diff options
Diffstat (limited to 'src/com')
13 files changed, 224 insertions, 57 deletions
diff --git a/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java b/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java index e09b38b668..468cb55cd3 100644 --- a/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java +++ b/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java @@ -352,7 +352,7 @@ public class LauncherPreviewRenderer extends ContextWrapper private void inflateAndAddWidgets(LauncherAppWidgetInfo info, WidgetsModel widgetsModel) { WidgetItem widgetItem = widgetsModel.getWidgetProviderInfoByProviderName( - info.providerName); + info.providerName, info.user); if (widgetItem == null) { return; } diff --git a/src/com/android/launcher3/icons/IconCache.java b/src/com/android/launcher3/icons/IconCache.java index 60d6e830c6..936eeb9220 100644 --- a/src/com/android/launcher3/icons/IconCache.java +++ b/src/com/android/launcher3/icons/IconCache.java @@ -18,6 +18,7 @@ package com.android.launcher3.icons; import static com.android.launcher3.util.Executors.MAIN_EXECUTOR; import static com.android.launcher3.util.Executors.MODEL_EXECUTOR; +import static com.android.launcher3.widget.WidgetSections.NO_CATEGORY; import static java.util.stream.Collectors.groupingBy; @@ -46,7 +47,6 @@ import androidx.annotation.NonNull; import com.android.launcher3.InvariantDeviceProfile; import com.android.launcher3.LauncherFiles; -import com.android.launcher3.R; import com.android.launcher3.Utilities; import com.android.launcher3.config.FeatureFlags; import com.android.launcher3.icons.ComponentWithLabel.ComponentCachingLogic; @@ -63,6 +63,8 @@ import com.android.launcher3.shortcuts.ShortcutKey; import com.android.launcher3.util.InstantAppResolver; import com.android.launcher3.util.PackageUserKey; import com.android.launcher3.util.Preconditions; +import com.android.launcher3.widget.WidgetSections; +import com.android.launcher3.widget.WidgetSections.WidgetSection; import java.util.Collections; import java.util.List; @@ -275,7 +277,8 @@ public class IconCache extends BaseIconCache { getTitleAndIcon(appInfo, false); return appInfo.bitmap; } else { - PackageItemInfo pkgInfo = new PackageItemInfo(shortcutInfo.getPackage()); + PackageItemInfo pkgInfo = new PackageItemInfo(shortcutInfo.getPackage(), + shortcutInfo.getUserHandle()); getTitleAndIconForApp(pkgInfo, false); return pkgInfo.bitmap; } @@ -409,8 +412,10 @@ public class IconCache extends BaseIconCache { CacheEntry entry = getEntryForPackageLocked( infoInOut.packageName, infoInOut.user, useLowResIcon); applyCacheEntry(entry, infoInOut); - if (infoInOut.category == PackageItemInfo.CONVERSATIONS) { - infoInOut.title = mContext.getString(R.string.widget_category_conversations); + if (infoInOut.widgetCategory != NO_CATEGORY) { + WidgetSection widgetSection = WidgetSections.getWidgetSections(mContext) + .get(infoInOut.widgetCategory); + infoInOut.title = mContext.getString(widgetSection.mSectionTitle); infoInOut.contentDescription = mPackageManager.getUserBadgedLabel( infoInOut.title, infoInOut.user); } diff --git a/src/com/android/launcher3/model/LoaderTask.java b/src/com/android/launcher3/model/LoaderTask.java index cb3af9d477..8a494ba539 100644 --- a/src/com/android/launcher3/model/LoaderTask.java +++ b/src/com/android/launcher3/model/LoaderTask.java @@ -804,8 +804,9 @@ public class LoaderTask implements Runnable { if (appWidgetInfo.restoreStatus != LauncherAppWidgetInfo.RESTORE_COMPLETED) { appWidgetInfo.pendingItemInfo = WidgetsModel.newPendingItemInfo( - appWidgetInfo.providerName); - appWidgetInfo.pendingItemInfo.user = appWidgetInfo.user; + mApp.getContext(), + appWidgetInfo.providerName, + appWidgetInfo.user); mIconCache.getTitleAndIconForApp( appWidgetInfo.pendingItemInfo, false); } diff --git a/src/com/android/launcher3/model/data/PackageItemInfo.java b/src/com/android/launcher3/model/data/PackageItemInfo.java index a81fe6a9d1..0055763cef 100644 --- a/src/com/android/launcher3/model/data/PackageItemInfo.java +++ b/src/com/android/launcher3/model/data/PackageItemInfo.java @@ -16,47 +16,41 @@ package com.android.launcher3.model.data; -import androidx.annotation.IntDef; +import static com.android.launcher3.widget.WidgetSections.NO_CATEGORY; + +import android.os.UserHandle; import com.android.launcher3.LauncherSettings; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; import java.util.Objects; /** * Represents a {@link Package} in the widget tray section. */ public class PackageItemInfo extends ItemInfoWithIcon { - @Retention(RetentionPolicy.SOURCE) - @IntDef({NO_CATEGORY, CONVERSATIONS}) - public @interface Category{} - /** The package is not categorized in the widget tray. */ - public static final int NO_CATEGORY = 0; - /** The package is categorized to conversations widget in the widget tray. */ - public static final int CONVERSATIONS = 1; - /** * Package name of the {@link PackageItemInfo}. */ public final String packageName; /** Represents a widget category shown in the widget tray section. */ - @Category public final int category; + public final int widgetCategory; - public PackageItemInfo(String packageName) { - this(packageName, NO_CATEGORY); + public PackageItemInfo(String packageName, UserHandle user) { + this(packageName, NO_CATEGORY, user); } - public PackageItemInfo(String packageName, @Category int category) { + public PackageItemInfo(String packageName, int widgetCategory, UserHandle user) { this.packageName = packageName; - this.category = category; + this.widgetCategory = widgetCategory; + this.user = user; this.itemType = LauncherSettings.Favorites.ITEM_TYPE_NON_ACTIONABLE; } public PackageItemInfo(PackageItemInfo copy) { this.packageName = copy.packageName; - this.category = copy.category; + this.widgetCategory = copy.widgetCategory; + this.user = copy.user; this.itemType = LauncherSettings.Favorites.ITEM_TYPE_NON_ACTIONABLE; } @@ -75,11 +69,13 @@ public class PackageItemInfo extends ItemInfoWithIcon { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; PackageItemInfo that = (PackageItemInfo) o; - return Objects.equals(packageName, that.packageName); + return Objects.equals(packageName, that.packageName) + && Objects.equals(user, that.user) + && widgetCategory == that.widgetCategory; } @Override public int hashCode() { - return Objects.hash(packageName, user); + return Objects.hash(packageName, user, widgetCategory); } } diff --git a/src/com/android/launcher3/util/PackageUserKey.java b/src/com/android/launcher3/util/PackageUserKey.java index 3a3b5a261e..92d97371e5 100644 --- a/src/com/android/launcher3/util/PackageUserKey.java +++ b/src/com/android/launcher3/util/PackageUserKey.java @@ -1,19 +1,24 @@ package com.android.launcher3.util; +import static com.android.launcher3.widget.WidgetSections.NO_CATEGORY; + import android.os.UserHandle; import android.service.notification.StatusBarNotification; +import android.text.TextUtils; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import com.android.launcher3.model.data.ItemInfo; +import com.android.launcher3.model.data.PackageItemInfo; -import java.util.Arrays; +import java.util.Objects; -/** Creates a hash key based on package name and user. */ +/** Creates a hash key based on package name, widget category, and user. */ public class PackageUserKey { public String mPackageName; + public int mWidgetCategory; public UserHandle mUser; private int mHashCode; @@ -27,14 +32,31 @@ public class PackageUserKey { return new PackageUserKey(notification.getPackageName(), notification.getUser()); } + /** Creates a {@link PackageUserKey} from {@link PackageItemInfo}. */ + public static PackageUserKey fromPackageItemInfo(PackageItemInfo info) { + if (TextUtils.isEmpty(info.packageName) && info.widgetCategory != NO_CATEGORY) { + return new PackageUserKey(info.widgetCategory, info.user); + } + return new PackageUserKey(info.packageName, info.user); + } + public PackageUserKey(String packageName, UserHandle user) { update(packageName, user); } + public PackageUserKey(int widgetCategory, UserHandle user) { + update(/* packageName= */ "", widgetCategory, user); + } + public void update(String packageName, UserHandle user) { + update(packageName, NO_CATEGORY, user); + } + + private void update(String packageName, int widgetCategory, UserHandle user) { mPackageName = packageName; + mWidgetCategory = widgetCategory; mUser = user; - mHashCode = Arrays.hashCode(new Object[] {packageName, user}); + mHashCode = Objects.hash(packageName, widgetCategory, user); } /** @@ -59,12 +81,14 @@ public class PackageUserKey { public boolean equals(Object obj) { if (!(obj instanceof PackageUserKey)) return false; PackageUserKey otherKey = (PackageUserKey) obj; - return mPackageName.equals(otherKey.mPackageName) && mUser.equals(otherKey.mUser); + return Objects.equals(mPackageName, otherKey.mPackageName) + && mWidgetCategory == otherKey.mWidgetCategory + && Objects.equals(mUser, otherKey.mUser); } @NonNull @Override public String toString() { - return mPackageName + "#" + mUser; + return mPackageName + "#" + mUser + ",category=" + mWidgetCategory; } } diff --git a/src/com/android/launcher3/widget/PendingAppWidgetHostView.java b/src/com/android/launcher3/widget/PendingAppWidgetHostView.java index b6bb6aa389..553ba13fe7 100644 --- a/src/com/android/launcher3/widget/PendingAppWidgetHostView.java +++ b/src/com/android/launcher3/widget/PendingAppWidgetHostView.java @@ -17,7 +17,7 @@ package com.android.launcher3.widget; import static com.android.launcher3.graphics.PreloadIconDrawable.newPendingIcon; -import static com.android.launcher3.model.data.PackageItemInfo.CONVERSATIONS; +import static com.android.launcher3.widget.WidgetSections.getWidgetSections; import android.content.Context; import android.graphics.Canvas; @@ -89,8 +89,8 @@ public class PendingAppWidgetHostView extends LauncherAppWidgetHostView setOnClickListener(ItemClickHandler.INSTANCE); if (info.pendingItemInfo == null) { - info.pendingItemInfo = new PackageItemInfo(info.providerName.getPackageName()); - info.pendingItemInfo.user = info.user; + info.pendingItemInfo = new PackageItemInfo(info.providerName.getPackageName(), + info.user); cache.updateIconInBackground(this, info.pendingItemInfo); } else { reapplyItemInfo(info.pendingItemInfo); @@ -338,10 +338,11 @@ public class PendingAppWidgetHostView extends LauncherAppWidgetHostView */ @Nullable private Drawable getWidgetCategoryIcon() { - switch (mInfo.pendingItemInfo.category) { - case CONVERSATIONS: - return getContext().getDrawable(R.drawable.ic_conversations_widget_category); + if (mInfo.pendingItemInfo.widgetCategory == WidgetSections.NO_CATEGORY) { + return null; } - return null; + Context context = getContext(); + return context.getDrawable(getWidgetSections(context).get( + mInfo.pendingItemInfo.widgetCategory).mSectionDrawable); } } diff --git a/src/com/android/launcher3/widget/WidgetSections.java b/src/com/android/launcher3/widget/WidgetSections.java new file mode 100644 index 0000000000..c45b09591f --- /dev/null +++ b/src/com/android/launcher3/widget/WidgetSections.java @@ -0,0 +1,134 @@ +/* + * Copyright (C) 2021 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.widget; + +import static android.content.res.Resources.ID_NULL; + +import android.content.ComponentName; +import android.content.Context; +import android.content.res.TypedArray; +import android.content.res.XmlResourceParser; +import android.util.ArrayMap; +import android.util.AttributeSet; +import android.util.SparseArray; +import android.util.Xml; + +import androidx.annotation.DrawableRes; +import androidx.annotation.StringRes; + +import com.android.launcher3.R; +import com.android.launcher3.util.IntSet; + +import org.xmlpull.v1.XmlPullParser; +import org.xmlpull.v1.XmlPullParserException; + +import java.io.IOException; +import java.util.Map; + +/** A helper class to parse widget sections (categories) resource overlay. */ +public final class WidgetSections { + /** The package is not categorized in the widget tray. */ + public static final int NO_CATEGORY = -1; + + private static final String TAG_SECTION_NAME = "section"; + private static final String TAG_WIDGET_NAME = "widget"; + + private static SparseArray<WidgetSection> sWidgetSections; + private static Map<ComponentName, IntSet> sWidgetsToCategories; + + /** Returns a list of widget sections that are shown in the widget picker. */ + public static synchronized SparseArray<WidgetSection> getWidgetSections(Context context) { + if (sWidgetSections != null) { + return sWidgetSections; + } + parseWidgetSectionsXml(context); + return sWidgetSections; + } + + /** Returns a map which maps app widget providers to app widget categories. */ + public static synchronized Map<ComponentName, IntSet> getWidgetsToCategory( + Context context) { + if (sWidgetsToCategories != null) { + return sWidgetsToCategories; + } + parseWidgetSectionsXml(context); + return sWidgetsToCategories; + } + + private static synchronized void parseWidgetSectionsXml(Context context) { + SparseArray<WidgetSection> widgetSections = new SparseArray(); + Map<ComponentName, IntSet> widgetsToCategories = new ArrayMap<>(); + try (XmlResourceParser parser = context.getResources().getXml(R.xml.widget_sections)) { + final int depth = parser.getDepth(); + int type; + while (((type = parser.next()) != XmlPullParser.END_TAG + || parser.getDepth() > depth) && type != XmlPullParser.END_DOCUMENT) { + if ((type == XmlPullParser.START_TAG) + && TAG_SECTION_NAME.equals(parser.getName())) { + AttributeSet sectionAttributes = Xml.asAttributeSet(parser); + WidgetSection section = new WidgetSection(context, sectionAttributes); + final int sectionDepth = parser.getDepth(); + while (((type = parser.next()) != XmlPullParser.END_TAG + || parser.getDepth() > sectionDepth) + && type != XmlPullParser.END_DOCUMENT) { + if ((type == XmlPullParser.START_TAG) + && TAG_WIDGET_NAME.equals(parser.getName())) { + TypedArray a = context.obtainStyledAttributes( + Xml.asAttributeSet(parser), R.styleable.WidgetSections); + ComponentName provider = ComponentName.unflattenFromString( + a.getString(R.styleable.WidgetSections_provider)); + boolean alsoKeepInApp = a.getBoolean( + R.styleable.WidgetSections_alsoKeepInApp, + /* defValue= */ false); + final IntSet categories; + if (widgetsToCategories.containsKey(provider)) { + categories = widgetsToCategories.get(provider); + } else { + categories = new IntSet(); + widgetsToCategories.put(provider, categories); + } + if (alsoKeepInApp) { + categories.add(NO_CATEGORY); + } + categories.add(section.mCategory); + } + } + widgetSections.put(section.mCategory, section); + } + } + sWidgetSections = widgetSections; + sWidgetsToCategories = widgetsToCategories; + } catch (IOException | XmlPullParserException e) { + throw new RuntimeException(e); + } + } + + /** A data class which contains a widget section's information. */ + public static final class WidgetSection { + public final int mCategory; + @StringRes + public final int mSectionTitle; + @DrawableRes + public final int mSectionDrawable; + + public WidgetSection(Context context, AttributeSet attrs) { + TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.WidgetSections); + mCategory = a.getInt(R.styleable.WidgetSections_category, NO_CATEGORY); + mSectionTitle = a.getResourceId(R.styleable.WidgetSections_sectionTitle, ID_NULL); + mSectionDrawable = a.getResourceId(R.styleable.WidgetSections_sectionDrawable, ID_NULL); + } + } +} diff --git a/src/com/android/launcher3/widget/model/WidgetListSpaceEntry.java b/src/com/android/launcher3/widget/model/WidgetListSpaceEntry.java index e62425f7d7..7f24905f88 100644 --- a/src/com/android/launcher3/widget/model/WidgetListSpaceEntry.java +++ b/src/com/android/launcher3/widget/model/WidgetListSpaceEntry.java @@ -16,6 +16,8 @@ package com.android.launcher3.widget.model; +import android.os.Process; + import com.android.launcher3.model.data.PackageItemInfo; import java.util.Collections; @@ -26,7 +28,9 @@ import java.util.Collections; public class WidgetListSpaceEntry extends WidgetsListBaseEntry { public WidgetListSpaceEntry() { - super(new PackageItemInfo(""), "", Collections.EMPTY_LIST); + super(new PackageItemInfo(/* packageName= */ "", Process.myUserHandle()), + /* titleSectionName= */ "", + Collections.EMPTY_LIST); mPkgItem.title = ""; } diff --git a/src/com/android/launcher3/widget/picker/OnHeaderClickListener.java b/src/com/android/launcher3/widget/picker/OnHeaderClickListener.java index 73727515c2..35f11bde47 100644 --- a/src/com/android/launcher3/widget/picker/OnHeaderClickListener.java +++ b/src/com/android/launcher3/widget/picker/OnHeaderClickListener.java @@ -24,5 +24,5 @@ public interface OnHeaderClickListener { /** * Calls when a header is clicked to show / hide widgets for a package. */ - void onHeaderClicked(boolean showWidgets, PackageUserKey packageUserKey); + void onHeaderClicked(boolean showWidgets, PackageUserKey key); } diff --git a/src/com/android/launcher3/widget/picker/WidgetsListAdapter.java b/src/com/android/launcher3/widget/picker/WidgetsListAdapter.java index d52134c81e..0e5a7d7ba9 100644 --- a/src/com/android/launcher3/widget/picker/WidgetsListAdapter.java +++ b/src/com/android/launcher3/widget/picker/WidgetsListAdapter.java @@ -98,7 +98,7 @@ public class WidgetsListAdapter extends Adapter<ViewHolder> implements OnHeaderC private Predicate<WidgetsListBaseEntry> mHeaderAndSelectedContentFilter = entry -> entry instanceof WidgetsListHeaderEntry || entry instanceof WidgetsListSearchHeaderEntry - || new PackageUserKey(entry.mPkgItem.packageName, entry.mPkgItem.user) + || PackageUserKey.fromPackageItemInfo(entry.mPkgItem) .equals(mWidgetsContentVisiblePackageUserKey); @Nullable private Predicate<WidgetsListBaseEntry> mFilter = null; @Nullable private RecyclerView mRecyclerView; @@ -252,10 +252,11 @@ public class WidgetsListAdapter extends Adapter<ViewHolder> implements OnHeaderC return entry instanceof WidgetsListBaseEntry.Header && matchesKey(entry, key); } - private static boolean matchesKey( - @NonNull WidgetsListBaseEntry entry, @Nullable PackageUserKey key) { + private static boolean matchesKey(@NonNull WidgetsListBaseEntry entry, + @Nullable PackageUserKey key) { if (key == null) return false; return entry.mPkgItem.packageName.equals(key.mPackageName) + && entry.mPkgItem.widgetCategory == key.mWidgetCategory && entry.mPkgItem.user.equals(key.mUser); } @@ -434,11 +435,10 @@ public class WidgetsListAdapter extends Adapter<ViewHolder> implements OnHeaderC .filter(entry -> entry instanceof WidgetsListHeaderEntry) .map(entry -> entry.mPkgItem) .collect(Collectors.toMap( - entry -> new PackageUserKey(entry.packageName, entry.user), + entry -> PackageUserKey.fromPackageItemInfo(entry), entry -> entry)); for (WidgetsListBaseEntry visibleEntry: mVisibleEntries) { - PackageUserKey key = new PackageUserKey(visibleEntry.mPkgItem.packageName, - visibleEntry.mPkgItem.user); + PackageUserKey key = PackageUserKey.fromPackageItemInfo(visibleEntry.mPkgItem); PackageItemInfo packageItemInfo = packagesInfo.get(key); if (packageItemInfo != null && !visibleEntry.mPkgItem.title.equals(packageItemInfo.title)) { diff --git a/src/com/android/launcher3/widget/picker/WidgetsListHeader.java b/src/com/android/launcher3/widget/picker/WidgetsListHeader.java index ebd2d1014c..932e06d57b 100644 --- a/src/com/android/launcher3/widget/picker/WidgetsListHeader.java +++ b/src/com/android/launcher3/widget/picker/WidgetsListHeader.java @@ -15,6 +15,8 @@ */ package com.android.launcher3.widget.picker; +import static com.android.launcher3.widget.WidgetSections.NO_CATEGORY; + import android.content.Context; import android.content.res.Resources; import android.content.res.TypedArray; @@ -41,6 +43,8 @@ import com.android.launcher3.model.data.ItemInfoWithIcon; import com.android.launcher3.model.data.PackageItemInfo; import com.android.launcher3.util.PluralMessageFormat; import com.android.launcher3.views.ActivityContext; +import com.android.launcher3.widget.WidgetSections; +import com.android.launcher3.widget.WidgetSections.WidgetSection; import com.android.launcher3.widget.model.WidgetsListHeaderEntry; import com.android.launcher3.widget.model.WidgetsListSearchHeaderEntry; @@ -173,12 +177,12 @@ public final class WidgetsListHeader extends LinearLayout implements ItemInfoUpd private void setIcon(PackageItemInfo info) { Drawable icon; - switch (info.category) { - case PackageItemInfo.CONVERSATIONS: - icon = getContext().getDrawable(R.drawable.ic_conversations_widget_category); - break; - default: - icon = info.newIcon(getContext()); + if (info.widgetCategory == NO_CATEGORY) { + icon = info.newIcon(getContext()); + } else { + WidgetSection widgetSection = WidgetSections.getWidgetSections(getContext()) + .get(info.widgetCategory); + icon = getContext().getDrawable(widgetSection.mSectionDrawable); } applyDrawables(icon); mIconDrawable = icon; diff --git a/src/com/android/launcher3/widget/picker/WidgetsListHeaderViewHolderBinder.java b/src/com/android/launcher3/widget/picker/WidgetsListHeaderViewHolderBinder.java index fadb637054..c6a72855c7 100644 --- a/src/com/android/launcher3/widget/picker/WidgetsListHeaderViewHolderBinder.java +++ b/src/com/android/launcher3/widget/picker/WidgetsListHeaderViewHolderBinder.java @@ -62,9 +62,7 @@ public final class WidgetsListHeaderViewHolderBinder implements (position & POSITION_LAST) != 0, /* isExpanded= */ data.isWidgetListShown())); widgetsListHeader.setOnExpandChangeListener(isExpanded -> - mOnHeaderClickListener.onHeaderClicked( - isExpanded, - new PackageUserKey(data.mPkgItem.packageName, data.mPkgItem.user) - )); + mOnHeaderClickListener.onHeaderClicked(isExpanded, + PackageUserKey.fromPackageItemInfo(data.mPkgItem))); } } diff --git a/src/com/android/launcher3/widget/picker/WidgetsListSearchHeaderViewHolderBinder.java b/src/com/android/launcher3/widget/picker/WidgetsListSearchHeaderViewHolderBinder.java index bff43c101b..2b27fc266a 100644 --- a/src/com/android/launcher3/widget/picker/WidgetsListSearchHeaderViewHolderBinder.java +++ b/src/com/android/launcher3/widget/picker/WidgetsListSearchHeaderViewHolderBinder.java @@ -64,6 +64,6 @@ public final class WidgetsListSearchHeaderViewHolderBinder implements /* isExpanded= */ data.isWidgetListShown())); widgetsListHeader.setOnExpandChangeListener(isExpanded -> mOnHeaderClickListener.onHeaderClicked(isExpanded, - new PackageUserKey(data.mPkgItem.packageName, data.mPkgItem.user))); + PackageUserKey.fromPackageItemInfo(data.mPkgItem))); } } |