Adding AppsStore for handling various app updates
Change-Id: Ia2242ce583576ace0924ef7142793ba37f4adcb9
diff --git a/res/layout/all_apps.xml b/res/layout/all_apps.xml
index 8cf32bd..2ce6b8c 100644
--- a/res/layout/all_apps.xml
+++ b/res/layout/all_apps.xml
@@ -31,48 +31,7 @@
<include layout="@layout/all_apps_fast_scroller" />
- <com.android.launcher3.allapps.FloatingHeaderView
- android:id="@+id/all_apps_header"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:paddingTop="@dimen/all_apps_header_top_padding"
- android:clipToPadding="false"
- android:layout_below="@id/search_container_all_apps" >
-
- <include layout="@layout/predictions_view" android:id="@+id/header_content" />
-
- <com.android.launcher3.allapps.PersonalWorkSlidingTabStrip
- android:id="@+id/tabs"
- android:layout_width="match_parent"
- android:layout_height="@dimen/all_apps_header_tab_height"
- android:layout_marginLeft="@dimen/all_apps_tabs_side_padding"
- android:layout_marginRight="@dimen/all_apps_tabs_side_padding"
- android:layout_below="@id/header_content"
- android:orientation="horizontal">
- <Button
- android:id="@+id/tab_personal"
- android:layout_width="0dp"
- android:layout_height="match_parent"
- android:layout_weight="1"
- android:background="?android:attr/selectableItemBackground"
- android:fontFamily="sans-serif-medium"
- android:text="@string/all_apps_personal_tab"
- android:textAllCaps="true"
- android:textColor="@color/all_apps_tab_text"
- android:textSize="14sp"/>
- <Button
- android:id="@+id/tab_work"
- android:layout_width="0dp"
- android:layout_height="match_parent"
- android:layout_weight="1"
- android:background="?android:attr/selectableItemBackground"
- android:fontFamily="sans-serif-medium"
- android:text="@string/all_apps_work_tab"
- android:textAllCaps="true"
- android:textColor="@color/all_apps_work_tab_text"
- android:textSize="14sp"/>
- </com.android.launcher3.allapps.PersonalWorkSlidingTabStrip>
- </com.android.launcher3.allapps.FloatingHeaderView>
+ <include layout="@layout/all_apps_floating_header" />
<!-- Note: we are reusing/repurposing a system attribute for search layout, because of a
platform bug, which prevents using custom attributes in <include> tag -->
diff --git a/res/layout/all_apps_floating_header.xml b/res/layout/all_apps_floating_header.xml
new file mode 100644
index 0000000..166725d
--- /dev/null
+++ b/res/layout/all_apps_floating_header.xml
@@ -0,0 +1,58 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2018 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<com.android.launcher3.allapps.FloatingHeaderView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/all_apps_header"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_below="@id/search_container_all_apps"
+ android:clipToPadding="false"
+ android:paddingTop="@dimen/all_apps_header_top_padding"
+ android:orientation="vertical" >
+
+ <com.android.launcher3.allapps.PersonalWorkSlidingTabStrip
+ android:id="@+id/tabs"
+ android:layout_width="match_parent"
+ android:layout_height="@dimen/all_apps_header_tab_height"
+ android:layout_marginLeft="@dimen/all_apps_tabs_side_padding"
+ android:layout_marginRight="@dimen/all_apps_tabs_side_padding"
+ android:orientation="horizontal">
+
+ <Button
+ android:id="@+id/tab_personal"
+ android:layout_width="0dp"
+ android:layout_height="match_parent"
+ android:layout_weight="1"
+ android:background="?android:attr/selectableItemBackground"
+ android:fontFamily="sans-serif-medium"
+ android:text="@string/all_apps_personal_tab"
+ android:textAllCaps="true"
+ android:textColor="@color/all_apps_tab_text"
+ android:textSize="14sp" />
+
+ <Button
+ android:id="@+id/tab_work"
+ android:layout_width="0dp"
+ android:layout_height="match_parent"
+ android:layout_weight="1"
+ android:background="?android:attr/selectableItemBackground"
+ android:fontFamily="sans-serif-medium"
+ android:text="@string/all_apps_work_tab"
+ android:textAllCaps="true"
+ android:textColor="@color/all_apps_work_tab_text"
+ android:textSize="14sp" />
+ </com.android.launcher3.allapps.PersonalWorkSlidingTabStrip>
+</com.android.launcher3.allapps.FloatingHeaderView>
diff --git a/res/layout/predictions_view.xml b/res/layout/predictions_view.xml
deleted file mode 100644
index 280290c..0000000
--- a/res/layout/predictions_view.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2017 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<com.android.launcher3.allapps.PredictionRowView
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="wrap_content" />
\ No newline at end of file
diff --git a/src/com/android/launcher3/allapps/AllAppsContainerView.java b/src/com/android/launcher3/allapps/AllAppsContainerView.java
index 2e544ec..dc3de18 100644
--- a/src/com/android/launcher3/allapps/AllAppsContainerView.java
+++ b/src/com/android/launcher3/allapps/AllAppsContainerView.java
@@ -55,13 +55,11 @@
import com.android.launcher3.dragndrop.DragOptions;
import com.android.launcher3.keyboard.FocusedItemDecorator;
import com.android.launcher3.userevent.nano.LauncherLogProto.Target;
-import com.android.launcher3.util.ComponentKey;
import com.android.launcher3.util.ComponentKeyMapper;
import com.android.launcher3.util.ItemInfoMatcher;
import com.android.launcher3.util.PackageUserKey;
import com.android.launcher3.views.BottomUserEducationView;
-import java.util.HashMap;
import java.util.List;
import java.util.Set;
@@ -76,6 +74,7 @@
private final ClickShadowView mTouchFeedbackView;
private final ItemInfoMatcher mPersonalMatcher = ItemInfoMatcher.ofUser(Process.myUserHandle());
private final ItemInfoMatcher mWorkMatcher = ItemInfoMatcher.not(mPersonalMatcher);
+ private final AllAppsStore mAllAppsStore = new AllAppsStore();
private SearchUiManager mSearchUiManager;
private View mSearchContainer;
@@ -92,8 +91,6 @@
private boolean mHasPredictions = false;
private boolean mSearchModeWhileUsingTabs = false;
- private final HashMap<ComponentKey, AppInfo> mComponentToAppMap = new HashMap<>();
-
public AllAppsContainerView(Context context) {
this(context, null);
}
@@ -132,6 +129,10 @@
// TODO: Reimplement once fast scroller is fixed.
}
+ public AllAppsStore getAppsStore() {
+ return mAllAppsStore;
+ }
+
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
@@ -149,64 +150,29 @@
public void setApps(List<AppInfo> apps) {
boolean hasWorkProfileApp = hasWorkProfileApp(apps);
rebindAdapters(hasWorkProfileApp);
- mComponentToAppMap.clear();
- addOrUpdateApps(apps);
+ mAllAppsStore.setApps(apps);
}
/**
* Adds or updates existing apps in the list
*/
public void addOrUpdateApps(List<AppInfo> apps) {
- for (AppInfo app : apps) {
- mComponentToAppMap.put(app.toComponentKey(), app);
- }
- onAppsUpdated();
- mSearchUiManager.refreshSearchResult();
- mHeader.onAppsUpdated();
+ mAllAppsStore.addOrUpdateApps(apps);
}
/**
* Removes some apps from the list.
*/
public void removeApps(List<AppInfo> apps) {
- for (AppInfo app : apps) {
- mComponentToAppMap.remove(app.toComponentKey());
- }
- onAppsUpdated();
- mSearchUiManager.refreshSearchResult();
- }
-
- private void onAppsUpdated() {
- for (int i = 0; i < getNumOfAdapters(); i++) {
- mAH[i].appsList.onAppsUpdated();
- }
- }
-
- private int getNumOfAdapters() {
- return mUsingTabs ? mAH.length : 1;
+ mAllAppsStore.removeApps(apps);
}
public void updatePromiseAppProgress(PromiseAppInfo app) {
- for (int i = 0; i < mAH.length; i++) {
- updatePromiseAppProgress(app, mAH[i].recyclerView);
- }
- if (isHeaderVisible()) {
- updatePromiseAppProgress(app, mHeader.getPredictionRow());
- }
- }
-
- private void updatePromiseAppProgress(PromiseAppInfo app, ViewGroup parent) {
- if (parent == null) {
- return;
- }
- int childCount = parent.getChildCount();
- for (int i = 0; i < childCount; i++) {
- View child = parent.getChildAt(i);
- if (child instanceof BubbleTextView && child.getTag() == app) {
- BubbleTextView bubbleTextView = (BubbleTextView) child;
- bubbleTextView.applyProgressLevel(app.level);
+ mAllAppsStore.updateAllIcons((child) -> {
+ if (child.getTag() == app) {
+ child.applyProgressLevel(app.level);
}
- }
+ });
}
/**
@@ -358,34 +324,15 @@
}
public void updateIconBadges(Set<PackageUserKey> updatedBadges) {
- final PackageUserKey packageUserKey = new PackageUserKey(null, null);
- for (int j = 0; j < mAH.length; j++) {
- updateIconBadges(updatedBadges, packageUserKey, mAH[j].recyclerView);
- }
- if (mHeader != null) {
- updateIconBadges(updatedBadges, packageUserKey, mHeader.getPredictionRow());
- }
- }
-
- private void updateIconBadges(Set<PackageUserKey> updatedBadges, PackageUserKey packageUserKey,
- ViewGroup parent) {
- if (parent == null) {
- return;
- }
- final int n = parent.getChildCount();
- for (int i = 0; i < n; i++) {
- View child = parent.getChildAt(i);
- if (child instanceof PredictionRowView) {
- updateIconBadges(updatedBadges, packageUserKey, (PredictionRowView) child);
+ PackageUserKey tempKey = new PackageUserKey(null, null);
+ mAllAppsStore.updateAllIcons((child) -> {
+ if (child.getTag() instanceof ItemInfo) {
+ ItemInfo info = (ItemInfo) child.getTag();
+ if (tempKey.updateFromItemInfo(info) && updatedBadges.contains(tempKey)) {
+ child.applyBadgeState(info, true /* animate */);
+ }
}
- if (!(child instanceof BubbleTextView) || !(child.getTag() instanceof ItemInfo)) {
- continue;
- }
- ItemInfo info = (ItemInfo) child.getTag();
- if (packageUserKey.updateFromItemInfo(info) && updatedBadges.contains(packageUserKey)) {
- ((BubbleTextView) child).applyBadgeState(info, true /* animate */);
- }
- }
+ });
}
public SpringAnimationHandler getSpringAnimationHandler() {
@@ -403,6 +350,9 @@
replaceRVContainer(showTabs);
mUsingTabs = showTabs;
+ mAllAppsStore.unregisterIconContainer(mAH[AdapterHolder.MAIN].recyclerView);
+ mAllAppsStore.unregisterIconContainer(mAH[AdapterHolder.WORK].recyclerView);
+
if (mUsingTabs) {
mAH[AdapterHolder.MAIN].setup(mViewPager.getChildAt(0), mPersonalMatcher);
mAH[AdapterHolder.WORK].setup(mViewPager.getChildAt(1), mWorkMatcher);
@@ -419,6 +369,9 @@
}
}
+ mAllAppsStore.registerIconContainer(mAH[AdapterHolder.MAIN].recyclerView);
+ mAllAppsStore.registerIconContainer(mAH[AdapterHolder.WORK].recyclerView);
+
applyTouchDelegate();
}
@@ -492,9 +445,6 @@
}
public void setPredictedApps(List<ComponentKeyMapper<AppInfo>> apps) {
- if (isHeaderVisible()) {
- mHeader.getPredictionRow().setPredictedApps(apps);
- }
mAH[AdapterHolder.MAIN].appsList.setPredictedApps(apps);
boolean hasPredictions = !apps.isEmpty();
if (mHasPredictions != hasPredictions) {
@@ -506,7 +456,7 @@
}
public AppInfo findApp(ComponentKeyMapper<AppInfo> mapper) {
- return mapper.getItem(mComponentToAppMap);
+ return mAllAppsStore.getApp(mapper);
}
public AlphabeticalAppsList getApps() {
@@ -526,9 +476,9 @@
return;
}
mHeader.setVisibility(View.VISIBLE);
- mHeader.setup(mAH, mComponentToAppMap, mNumPredictedAppsPerRow);
+ mHeader.setup(mAH, mAH[AllAppsContainerView.AdapterHolder.WORK].recyclerView == null);
- int padding = mHeader.getPredictionRow().getExpectedHeight();
+ int padding = mHeader.getMaxTranslation();
if (mHasPredictions && !mUsingTabs) {
padding += mHeader.getPaddingTop() + mHeader.getPaddingBottom();
}
@@ -582,14 +532,6 @@
}
}
- public List<AppInfo> getPredictedApps() {
- if (isHeaderVisible()) {
- return mHeader.getPredictionRow().getPredictedApps();
- } else {
- return mAH[AdapterHolder.MAIN].appsList.getPredictedApps();
- }
- }
-
public boolean isHeaderVisible() {
return mHeader != null && mHeader.getVisibility() == View.VISIBLE;
}
@@ -604,7 +546,7 @@
public static final int MAIN = 0;
public static final int WORK = 1;
- final AllAppsGridAdapter adapter;
+ public final AllAppsGridAdapter adapter;
final LinearLayoutManager layoutManager;
final SpringAnimationHandler animationHandler;
final AlphabeticalAppsList appsList;
@@ -614,7 +556,7 @@
boolean verticalFadingEdge;
AdapterHolder(boolean isWork) {
- appsList = new AlphabeticalAppsList(mLauncher, mComponentToAppMap, isWork);
+ appsList = new AlphabeticalAppsList(mLauncher, mAllAppsStore, isWork);
adapter = new AllAppsGridAdapter(mLauncher, appsList, mLauncher,
AllAppsContainerView.this, true);
appsList.setAdapter(adapter);
@@ -649,11 +591,6 @@
? paddingTopForTabs : padding.top;
recyclerView.setPadding(padding.left, paddingTop, padding.right, padding.bottom);
}
- if (isHeaderVisible()) {
- PredictionRowView prv = mHeader.getPredictionRow();
- prv.setPadding(padding.left, prv.getPaddingTop() , padding.right,
- prv.getPaddingBottom());
- }
}
void applyNumsPerRow() {
@@ -663,10 +600,6 @@
}
adapter.setNumAppsPerRow(mNumAppsPerRow);
appsList.setNumAppsPerRow(mNumAppsPerRow, mNumPredictedAppsPerRow);
- if (isHeaderVisible()) {
- mHeader.getPredictionRow()
- .setNumAppsPerRow(mNumPredictedAppsPerRow);
- }
}
}
diff --git a/src/com/android/launcher3/allapps/AllAppsStore.java b/src/com/android/launcher3/allapps/AllAppsStore.java
new file mode 100644
index 0000000..17f1c89
--- /dev/null
+++ b/src/com/android/launcher3/allapps/AllAppsStore.java
@@ -0,0 +1,127 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.launcher3.allapps;
+
+import android.view.View;
+import android.view.ViewGroup;
+
+import com.android.launcher3.AppInfo;
+import com.android.launcher3.BubbleTextView;
+import com.android.launcher3.util.ComponentKey;
+import com.android.launcher3.util.ComponentKeyMapper;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+
+/**
+ * A utility class to maintain the collection of all apps.
+ */
+public class AllAppsStore {
+
+ private final HashMap<ComponentKey, AppInfo> mComponentToAppMap = new HashMap<>();
+ private final List<OnUpdateListener> mUpdateListeners = new ArrayList<>();
+ private final ArrayList<ViewGroup> mIconContainers = new ArrayList<>();
+
+ public Collection<AppInfo> getApps() {
+ return mComponentToAppMap.values();
+ }
+
+ /**
+ * Sets the current set of apps.
+ */
+ public void setApps(List<AppInfo> apps) {
+ mComponentToAppMap.clear();
+ addOrUpdateApps(apps);
+ }
+
+ public AppInfo getApp(ComponentKey key) {
+ return mComponentToAppMap.get(key);
+ }
+
+ public AppInfo getApp(ComponentKeyMapper<AppInfo> mapper) {
+ return mapper.getItem(mComponentToAppMap);
+ }
+
+ /**
+ * Adds or updates existing apps in the list
+ */
+ public void addOrUpdateApps(List<AppInfo> apps) {
+ for (AppInfo app : apps) {
+ mComponentToAppMap.put(app.toComponentKey(), app);
+ }
+ notifyUpdate();
+ }
+
+ /**
+ * Removes some apps from the list.
+ */
+ public void removeApps(List<AppInfo> apps) {
+ for (AppInfo app : apps) {
+ mComponentToAppMap.remove(app.toComponentKey());
+ }
+ notifyUpdate();
+ }
+
+
+ private void notifyUpdate() {
+ int count = mUpdateListeners.size();
+ for (int i = 0; i < count; i++) {
+ mUpdateListeners.get(i).onAppsUpdated();
+ }
+ }
+
+ public void addUpdateListener(OnUpdateListener listener) {
+ mUpdateListeners.add(listener);
+ }
+
+ public void removeUpdateListener(OnUpdateListener listener) {
+ mUpdateListeners.remove(listener);
+ }
+
+ public void registerIconContainer(ViewGroup container) {
+ if (container != null) {
+ mIconContainers.add(container);
+ }
+ }
+
+ public void unregisterIconContainer(ViewGroup container) {
+ mIconContainers.remove(container);
+ }
+
+ public void updateAllIcons(IconAction action) {
+ for (int i = mIconContainers.size() - 1; i >= 0; i--) {
+ ViewGroup parent = mIconContainers.get(i);
+ int childCount = parent.getChildCount();
+
+ for (int j = 0; j < childCount; j++) {
+ View child = parent.getChildAt(j);
+ if (child instanceof BubbleTextView) {
+ action.apply((BubbleTextView) child);
+ }
+ }
+ }
+ }
+
+ public interface OnUpdateListener {
+ void onAppsUpdated();
+ }
+
+ public interface IconAction {
+ void apply(BubbleTextView icon);
+ }
+}
diff --git a/src/com/android/launcher3/allapps/AlphabeticalAppsList.java b/src/com/android/launcher3/allapps/AlphabeticalAppsList.java
index 76828de..29b32b0 100644
--- a/src/com/android/launcher3/allapps/AlphabeticalAppsList.java
+++ b/src/com/android/launcher3/allapps/AlphabeticalAppsList.java
@@ -44,7 +44,7 @@
/**
* The alphabetically sorted list of applications.
*/
-public class AlphabeticalAppsList {
+public class AlphabeticalAppsList implements AllAppsStore.OnUpdateListener {
public static final String TAG = "AlphabeticalAppsList";
private static final boolean DEBUG = false;
@@ -153,7 +153,7 @@
// The set of apps from the system not including predictions
private final List<AppInfo> mApps = new ArrayList<>();
- private final HashMap<ComponentKey, AppInfo> mComponentToAppMap;
+ private final AllAppsStore mAllAppsStore;
// The set of filtered apps with the current filter
private final List<AppInfo> mFilteredApps = new ArrayList<>();
@@ -179,16 +179,13 @@
private int mNumAppRowsInAdapter;
private ItemInfoMatcher mItemFilter;
- public AlphabeticalAppsList(
- Context context,
- HashMap<ComponentKey,
- AppInfo> componentToAppMap,
- boolean isWork) {
- mComponentToAppMap = componentToAppMap;
+ public AlphabeticalAppsList(Context context, AllAppsStore appsStore, boolean isWork) {
+ mAllAppsStore = appsStore;
mLauncher = Launcher.getLauncher(context);
mIndexer = new AlphabeticIndexCompat(context);
mAppNameComparator = new AppInfoComparator(context);
mIsWork = isWork;
+ mAllAppsStore.addUpdateListener(this);
}
public void updateItemFilter(ItemInfoMatcher itemFilter) {
@@ -283,14 +280,14 @@
}
private List<AppInfo> processPredictedAppComponents(List<ComponentKeyMapper<AppInfo>> components) {
- if (mComponentToAppMap.isEmpty()) {
+ if (mAllAppsStore.getApps().isEmpty()) {
// Apps have not been bound yet.
return Collections.emptyList();
}
List<AppInfo> predictedApps = new ArrayList<>();
for (ComponentKeyMapper<AppInfo> mapper : components) {
- AppInfo info = mapper.getItem(mComponentToAppMap);
+ AppInfo info = mAllAppsStore.getApp(mapper);
if (info != null) {
predictedApps.add(info);
} else {
@@ -359,11 +356,12 @@
/**
* Updates internals when the set of apps are updated.
*/
- void onAppsUpdated() {
+ @Override
+ public void onAppsUpdated() {
// Sort the list of apps
mApps.clear();
- for (AppInfo app : mComponentToAppMap.values()) {
+ for (AppInfo app : mAllAppsStore.getApps()) {
if (mItemFilter == null || mItemFilter.matches(app, null) || hasFilter()) {
mApps.add(app);
}
@@ -580,7 +578,7 @@
}
ArrayList<AppInfo> result = new ArrayList<>();
for (ComponentKey key : mSearchResults) {
- AppInfo match = mComponentToAppMap.get(key);
+ AppInfo match = mAllAppsStore.getApp(key);
if (match != null) {
result.add(match);
}
diff --git a/src/com/android/launcher3/allapps/FloatingHeaderView.java b/src/com/android/launcher3/allapps/FloatingHeaderView.java
index 2391768..d8a9f63 100644
--- a/src/com/android/launcher3/allapps/FloatingHeaderView.java
+++ b/src/com/android/launcher3/allapps/FloatingHeaderView.java
@@ -15,7 +15,6 @@
*/
package com.android.launcher3.allapps;
-
import android.animation.ValueAnimator;
import android.content.Context;
import android.graphics.Point;
@@ -27,18 +26,14 @@
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
+import android.widget.LinearLayout;
import android.widget.RelativeLayout;
-import com.android.launcher3.AppInfo;
import com.android.launcher3.R;
-import com.android.launcher3.util.ComponentKey;
-import java.util.HashMap;
-
-public class FloatingHeaderView extends RelativeLayout implements
+public class FloatingHeaderView extends LinearLayout implements
ValueAnimator.AnimatorUpdateListener {
-
private final Rect mClip = new Rect(0, 0, Integer.MAX_VALUE, Integer.MAX_VALUE);
private final ValueAnimator mAnimator = ValueAnimator.ofInt(0, 0);
private final Point mTempOffset = new Point();
@@ -63,19 +58,18 @@
}
};
- private PredictionRowView mPredictionRow;
private ViewGroup mTabLayout;
private AllAppsRecyclerView mMainRV;
private AllAppsRecyclerView mWorkRV;
private AllAppsRecyclerView mCurrentRV;
private ViewGroup mParent;
- private boolean mTabsHidden;
private boolean mHeaderCollapsed;
- private int mMaxTranslation;
private int mSnappedScrolledY;
private int mTranslationY;
private boolean mForwardToRecyclerView;
+ protected int mMaxTranslation;
+
public FloatingHeaderView(@NonNull Context context) {
this(context, null);
}
@@ -88,17 +82,10 @@
protected void onFinishInflate() {
super.onFinishInflate();
mTabLayout = findViewById(R.id.tabs);
- mPredictionRow = findViewById(R.id.header_content);
}
- public void setup(AllAppsContainerView.AdapterHolder[] mAH,
- HashMap<ComponentKey, AppInfo> componentToAppMap, int numPredictedAppsPerRow) {
- mTabsHidden = mAH[AllAppsContainerView.AdapterHolder.WORK].recyclerView == null;
- mTabLayout.setVisibility(mTabsHidden ? View.GONE : View.VISIBLE);
- mPredictionRow.setup(mAH[AllAppsContainerView.AdapterHolder.MAIN].adapter,
- componentToAppMap, numPredictedAppsPerRow);
- mPredictionRow.setShowDivider(mTabsHidden);
- mMaxTranslation = mPredictionRow.getExpectedHeight();
+ public void setup(AllAppsContainerView.AdapterHolder[] mAH, boolean tabsHidden) {
+ mTabLayout.setVisibility(tabsHidden ? View.GONE : View.VISIBLE);
mMainRV = setupRV(mMainRV, mAH[AllAppsContainerView.AdapterHolder.MAIN].recyclerView);
mWorkRV = setupRV(mWorkRV, mAH[AllAppsContainerView.AdapterHolder.WORK].recyclerView);
mParent = (ViewGroup) mMainRV.getParent();
@@ -117,12 +104,12 @@
mCurrentRV = active ? mMainRV : mWorkRV;
}
- public PredictionRowView getPredictionRow() {
- return mPredictionRow;
+ public int getMaxTranslation() {
+ return mMaxTranslation;
}
private boolean canSnapAt(int currentScrollY) {
- return Math.abs(currentScrollY) <= mPredictionRow.getHeight();
+ return Math.abs(currentScrollY) <= mMaxTranslation;
}
private void moved(final int currentScrollY) {
@@ -149,16 +136,12 @@
}
}
- private void apply() {
+ protected void applyScroll(int uncappedY, int currentY) { }
+
+ protected void apply() {
int uncappedTranslationY = mTranslationY;
mTranslationY = Math.max(mTranslationY, -mMaxTranslation);
- if (mTranslationY != uncappedTranslationY) {
- // we hide it completely if already capped (for opening search anim)
- mPredictionRow.setVisibility(View.INVISIBLE);
- } else {
- mPredictionRow.setVisibility(View.VISIBLE);
- mPredictionRow.setTranslationY(uncappedTranslationY);
- }
+ applyScroll(uncappedTranslationY, mTranslationY);
mTabLayout.setTranslationY(mTranslationY);
mClip.top = mMaxTranslation + mTranslationY;
// clipping on a draw might cause additional redraw
@@ -218,10 +201,6 @@
p.x = getLeft() - mCurrentRV.getLeft() - mParent.getLeft();
p.y = getTop() - mCurrentRV.getTop() - mParent.getTop();
}
-
- public void onAppsUpdated() {
- mPredictionRow.onAppsUpdated();
- }
}
diff --git a/src/com/android/launcher3/allapps/PredictionRowView.java b/src/com/android/launcher3/allapps/PredictionRowView.java
deleted file mode 100644
index 267ef3c..0000000
--- a/src/com/android/launcher3/allapps/PredictionRowView.java
+++ /dev/null
@@ -1,245 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.launcher3.allapps;
-
-import android.content.Context;
-import android.graphics.Canvas;
-import android.graphics.Paint;
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
-import android.util.AttributeSet;
-import android.util.Log;
-import android.view.View;
-import android.widget.LinearLayout;
-
-import com.android.launcher3.AppInfo;
-import com.android.launcher3.BubbleTextView;
-import com.android.launcher3.ItemInfo;
-import com.android.launcher3.Launcher;
-import com.android.launcher3.R;
-import com.android.launcher3.config.FeatureFlags;
-import com.android.launcher3.logging.UserEventDispatcher;
-import com.android.launcher3.userevent.nano.LauncherLogProto;
-import com.android.launcher3.util.ComponentKey;
-import com.android.launcher3.util.ComponentKeyMapper;
-import com.android.launcher3.util.Themes;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.List;
-
-public class PredictionRowView extends LinearLayout implements
- UserEventDispatcher.LogContainerProvider {
-
- private static final String TAG = "PredictionRowView";
-
- private HashMap<ComponentKey, AppInfo> mComponentToAppMap;
- private int mNumPredictedAppsPerRow;
- // The set of predicted app component names
- private final List<ComponentKeyMapper<AppInfo>> mPredictedAppComponents = new ArrayList<>();
- // The set of predicted apps resolved from the component names and the current set of apps
- private final ArrayList<AppInfo> mPredictedApps = new ArrayList<>();
- private final Paint mPaint;
- // This adapter is only used to create an identical item w/ same behavior as in the all apps RV
- private AllAppsGridAdapter mAdapter;
- private boolean mShowDivider;
-
- public PredictionRowView(@NonNull Context context) {
- this(context, null);
- }
-
- public PredictionRowView(@NonNull Context context, @Nullable AttributeSet attrs) {
- super(context, attrs);
- setOrientation(LinearLayout.HORIZONTAL);
- setWillNotDraw(false);
- mPaint = new Paint();
- mPaint.setColor(Themes.getAttrColor(context, android.R.attr.colorControlHighlight));
- mPaint.setStrokeWidth(getResources().getDimensionPixelSize(R.dimen.all_apps_divider_height));
- }
-
- public void setup(AllAppsGridAdapter adapter, HashMap<ComponentKey, AppInfo> componentToAppMap,
- int numPredictedAppsPerRow) {
- mAdapter = adapter;
- mComponentToAppMap = componentToAppMap;
- mNumPredictedAppsPerRow = numPredictedAppsPerRow;
- setVisibility(mPredictedAppComponents.isEmpty() ? View.GONE : View.VISIBLE);
- }
-
- @Override
- protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- super.onMeasure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(getExpectedHeight(),
- MeasureSpec.EXACTLY));
- }
-
- public int getExpectedHeight() {
- int height = 0;
- if (!mPredictedAppComponents.isEmpty()) {
- height += Launcher.getLauncher(getContext())
- .getDeviceProfile().allAppsCellHeightPx;
- height += getPaddingTop() + getPaddingBottom();
- }
- return height;
- }
-
- public void setShowDivider(boolean showDivider) {
- mShowDivider = showDivider;
- int paddingBottom = showDivider ? getResources()
- .getDimensionPixelSize(R.dimen.all_apps_prediction_row_divider_height) : 0;
- setPadding(getPaddingLeft(), getPaddingTop(), getPaddingRight(), paddingBottom);
- }
-
- /**
- * Sets the number of apps per row.
- */
- public void setNumAppsPerRow(int numPredictedAppsPerRow) {
- if (mNumPredictedAppsPerRow != numPredictedAppsPerRow) {
- mNumPredictedAppsPerRow = numPredictedAppsPerRow;
- onPredictionsUpdated();
- }
- }
-
- /**
- * Returns the predicted apps.
- */
- public List<AppInfo> getPredictedApps() {
- return mPredictedApps;
- }
-
- /**
- * Sets the current set of predicted apps.
- *
- * This can be called before we get the full set of applications, we should merge the results
- * only in onPredictionsUpdated() which is idempotent.
- *
- * If the number of predicted apps is the same as the previous list of predicted apps,
- * we can optimize by swapping them in place.
- */
- public void setPredictedApps(List<ComponentKeyMapper<AppInfo>> apps) {
- mPredictedAppComponents.clear();
- mPredictedAppComponents.addAll(apps);
- mPredictedApps.clear();
- mPredictedApps.addAll(processPredictedAppComponents(mPredictedAppComponents));
- onPredictionsUpdated();
- }
-
- private void onPredictionsUpdated() {
- int childCountBefore = getChildCount();
- if (getChildCount() != mNumPredictedAppsPerRow) {
- while (getChildCount() > mNumPredictedAppsPerRow) {
- removeViewAt(0);
- }
- while (getChildCount() < mNumPredictedAppsPerRow) {
- AllAppsGridAdapter.ViewHolder holder = mAdapter
- .onCreateViewHolder(this, AllAppsGridAdapter.VIEW_TYPE_ICON);
- BubbleTextView icon = (BubbleTextView) holder.itemView;
- LinearLayout.LayoutParams params =
- new LayoutParams(0, icon.getLayoutParams().height);
- params.weight = 1;
- icon.setLayoutParams(params);
- addView(icon);
- }
- }
-
- for (int i = 0; i < getChildCount(); i++) {
- BubbleTextView icon = (BubbleTextView) getChildAt(i);
- icon.reset();
- if (mPredictedApps.size() > i) {
- icon.setVisibility(View.VISIBLE);
- icon.applyFromApplicationInfo(mPredictedApps.get(i));
- } else {
- icon.setVisibility(View.INVISIBLE);
- }
- }
-
- if (getChildCount() > 0 && childCountBefore == 0
- || getChildCount() == 0 && childCountBefore > 0) {
- // setting up header to adjust the height
- // only necessary if childcount switches from/to 0
- Launcher.getLauncher(getContext()).getAppsView().setupHeader();
- }
- }
-
- /**
- * Refreshes the app icons in the row view, while preserving the same set of predictions.
- */
- public void onAppsUpdated() {
- for (int i = 0; i < getChildCount(); i++) {
- View child = getChildAt(i);
- if (!(child instanceof BubbleTextView)) {
- continue;
- }
- if (i >= mPredictedApps.size()) {
- break;
- }
- BubbleTextView icon = (BubbleTextView) getChildAt(i);
- icon.reset();
- icon.applyFromApplicationInfo(mPredictedApps.get(i));
- }
- }
-
- private List<AppInfo> processPredictedAppComponents(
- List<ComponentKeyMapper<AppInfo>> components) {
- if (mComponentToAppMap.isEmpty()) {
- // Apps have not been bound yet.
- return Collections.emptyList();
- }
-
- List<AppInfo> predictedApps = new ArrayList<>();
- for (ComponentKeyMapper<AppInfo> mapper : components) {
- AppInfo info = mapper.getItem(mComponentToAppMap);
- if (info != null) {
- predictedApps.add(info);
- } else {
- if (FeatureFlags.IS_DOGFOOD_BUILD) {
- Log.e(TAG, "Predicted app not found: " + mapper);
- }
- }
- // Stop at the number of predicted apps
- if (predictedApps.size() == mNumPredictedAppsPerRow) {
- break;
- }
- }
- return predictedApps;
- }
-
- @Override
- protected void onDraw(Canvas canvas) {
- super.onDraw(canvas);
-
- if (mShowDivider) {
- int side = getResources().getDimensionPixelSize(R.dimen.dynamic_grid_edge_margin);
- int y = getHeight() - (getPaddingBottom() / 2);
- int x1 = getPaddingLeft() + side;
- int x2 = getWidth() - getPaddingRight() - side;
- canvas.drawLine(x1, y, x2, y, mPaint);
- }
- }
-
- @Override
- public void fillInLogContainerData(View v, ItemInfo info, LauncherLogProto.Target target,
- LauncherLogProto.Target targetParent) {
- for (int i = 0; i < mPredictedApps.size(); i++) {
- AppInfo appInfo = mPredictedApps.get(i);
- if (appInfo == info) {
- targetParent.containerType = LauncherLogProto.ContainerType.PREDICTION;
- target.predictedRank = i;
- break;
- }
- }
- }
-}
diff --git a/src/com/android/launcher3/allapps/SearchUiManager.java b/src/com/android/launcher3/allapps/SearchUiManager.java
index f562b6a..bb17ed5 100644
--- a/src/com/android/launcher3/allapps/SearchUiManager.java
+++ b/src/com/android/launcher3/allapps/SearchUiManager.java
@@ -35,12 +35,6 @@
@NonNull SpringAnimation getSpringForFling();
/**
- * Notifies the search manager that the apps-list has changed and the search UI should be
- * updated accordingly.
- */
- void refreshSearchResult();
-
- /**
* Notifies the search manager to close any active search session.
*/
void reset();
diff --git a/src/com/android/launcher3/allapps/search/AppsSearchContainerLayout.java b/src/com/android/launcher3/allapps/search/AppsSearchContainerLayout.java
index 6f07eeb..fca3e47 100644
--- a/src/com/android/launcher3/allapps/search/AppsSearchContainerLayout.java
+++ b/src/com/android/launcher3/allapps/search/AppsSearchContainerLayout.java
@@ -37,6 +37,7 @@
import com.android.launcher3.Launcher;
import com.android.launcher3.R;
import com.android.launcher3.allapps.AllAppsContainerView;
+import com.android.launcher3.allapps.AllAppsStore;
import com.android.launcher3.allapps.AlphabeticalAppsList;
import com.android.launcher3.allapps.SearchUiManager;
import com.android.launcher3.graphics.TintedDrawableSpan;
@@ -48,7 +49,8 @@
* Layout to contain the All-apps search UI.
*/
public class AppsSearchContainerLayout extends FrameLayout
- implements SearchUiManager, AllAppsSearchBarController.Callbacks {
+ implements SearchUiManager, AllAppsSearchBarController.Callbacks,
+ AllAppsStore.OnUpdateListener {
private final Launcher mLauncher;
private final int mMinHeight;
@@ -111,6 +113,18 @@
}
@Override
+ protected void onAttachedToWindow() {
+ super.onAttachedToWindow();
+ mLauncher.getAppsView().getAppsStore().addUpdateListener(this);
+ }
+
+ @Override
+ protected void onDetachedFromWindow() {
+ super.onDetachedFromWindow();
+ mLauncher.getAppsView().getAppsStore().removeUpdateListener(this);
+ }
+
+ @Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
if (!mLauncher.getDeviceProfile().isVerticalBarLayout()) {
getLayoutParams().height = mLauncher.getDragLayer().getInsets().top + mMinHeight;
@@ -134,7 +148,7 @@
}
@Override
- public void refreshSearchResult() {
+ public void onAppsUpdated() {
mSearchBarController.refreshSearchResult();
}
diff --git a/src/com/android/launcher3/util/ComponentKeyMapper.java b/src/com/android/launcher3/util/ComponentKeyMapper.java
index 916176a..a7f0d76 100644
--- a/src/com/android/launcher3/util/ComponentKeyMapper.java
+++ b/src/com/android/launcher3/util/ComponentKeyMapper.java
@@ -18,8 +18,6 @@
import android.support.annotation.Nullable;
-import java.util.ArrayList;
-import java.util.List;
import java.util.Map;
public class ComponentKeyMapper<T> {