diff options
Diffstat (limited to 'src/com/android/launcher3/widget')
4 files changed, 202 insertions, 22 deletions
diff --git a/src/com/android/launcher3/widget/WidgetListRowEntry.java b/src/com/android/launcher3/widget/WidgetListRowEntry.java index 3e89eeb9b..335b8c759 100644 --- a/src/com/android/launcher3/widget/WidgetListRowEntry.java +++ b/src/com/android/launcher3/widget/WidgetListRowEntry.java @@ -41,4 +41,8 @@ public class WidgetListRowEntry { this.widgets = items; } + @Override + public String toString() { + return pkgItem.packageName + ":" + widgets.size(); + } } diff --git a/src/com/android/launcher3/widget/WidgetsContainerView.java b/src/com/android/launcher3/widget/WidgetsContainerView.java index 14a9d17ed..acec3dd3b 100644 --- a/src/com/android/launcher3/widget/WidgetsContainerView.java +++ b/src/com/android/launcher3/widget/WidgetsContainerView.java @@ -17,10 +17,12 @@ package com.android.launcher3.widget; import android.content.Context; +import android.content.pm.LauncherApps; import android.graphics.Point; import android.support.v7.widget.LinearLayoutManager; import android.util.AttributeSet; import android.util.Log; +import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.Toast; @@ -31,8 +33,10 @@ import com.android.launcher3.DragSource; import com.android.launcher3.DropTarget.DragObject; import com.android.launcher3.ItemInfo; import com.android.launcher3.Launcher; +import com.android.launcher3.LauncherAppState; import com.android.launcher3.R; import com.android.launcher3.Utilities; +import com.android.launcher3.compat.AlphabeticIndexCompat; import com.android.launcher3.dragndrop.DragOptions; import com.android.launcher3.folder.Folder; import com.android.launcher3.model.PackageItemInfo; @@ -74,7 +78,11 @@ public class WidgetsContainerView extends BaseContainerView public WidgetsContainerView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); mLauncher = Launcher.getLauncher(context); - mAdapter = new WidgetsListAdapter(this, this, context); + LauncherAppState apps = LauncherAppState.getInstance(context); + mAdapter = new WidgetsListAdapter(context, LayoutInflater.from(context), + apps.getWidgetCache(), new AlphabeticIndexCompat(context), this, this, + new WidgetsDiffReporter(apps.getIconCache())); + mAdapter.setNotifyListener(); if (LOGD) { Log.d(TAG, "WidgetsContainerView constructor"); } @@ -232,7 +240,6 @@ public class WidgetsContainerView extends BaseContainerView */ public void setWidgets(MultiHashMap<PackageItemInfo, WidgetItem> model) { mAdapter.setWidgets(model); - mAdapter.notifyDataSetChanged(); View loader = getContentView().findViewById(R.id.loader); if (loader != null) { diff --git a/src/com/android/launcher3/widget/WidgetsDiffReporter.java b/src/com/android/launcher3/widget/WidgetsDiffReporter.java new file mode 100644 index 000000000..52deec32b --- /dev/null +++ b/src/com/android/launcher3/widget/WidgetsDiffReporter.java @@ -0,0 +1,141 @@ +/* + * 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.widget; + +import android.util.Log; + +import com.android.launcher3.IconCache; +import com.android.launcher3.model.PackageItemInfo; +import com.android.launcher3.widget.WidgetsListAdapter.WidgetListRowEntryComparator; + +import java.util.ArrayList; +import java.util.Iterator; + +/** + * Do diff on widget's tray list items and call the {@link NotifyListener} methods accordingly. + */ +public class WidgetsDiffReporter { + private final boolean DEBUG = false; + private final String TAG = "WidgetsDiffReporter"; + private final IconCache mIconCache; + private NotifyListener mListener; + + public interface NotifyListener { + void notifyDataSetChanged(); + void notifyItemChanged(int index); + void notifyItemInserted(int index); + void notifyItemRemoved(int index); + } + + public WidgetsDiffReporter(IconCache iconCache) { + mIconCache = iconCache; + } + + public void setListener(NotifyListener listener) { + mListener = listener; + } + + public void process(ArrayList<WidgetListRowEntry> currentEntries, + ArrayList<WidgetListRowEntry> newEntries, WidgetListRowEntryComparator comparator) { + if (DEBUG) { + Log.d(TAG, "process oldEntries#=" + currentEntries.size() + + " newEntries#=" + newEntries.size()); + } + if (currentEntries.size() == 0 && newEntries.size() > 0) { + currentEntries.addAll(newEntries); + mListener.notifyDataSetChanged(); + return; + } + ArrayList<WidgetListRowEntry> orgEntries = + (ArrayList<WidgetListRowEntry>) currentEntries.clone(); + Iterator<WidgetListRowEntry> orgIter = orgEntries.iterator(); + Iterator<WidgetListRowEntry> newIter = newEntries.iterator(); + + WidgetListRowEntry orgRowEntry = orgIter.next(); + WidgetListRowEntry newRowEntry = newIter.next(); + + do { + int diff = comparePackageName(orgRowEntry, newRowEntry, comparator); + if (DEBUG) { + Log.d(TAG, String.format("diff=%d orgRowEntry (%s) newRowEntry (%s)", + diff, orgRowEntry != null? orgRowEntry.toString() : null, + newRowEntry != null? newRowEntry.toString() : null)); + } + int index = -1; + if (diff < 0) { + index = currentEntries.indexOf(orgRowEntry); + mListener.notifyItemRemoved(index); + if (DEBUG) { + Log.d(TAG, String.format("notifyItemRemoved called (%d)%s", index, + orgRowEntry.titleSectionName)); + } + currentEntries.remove(index); + orgRowEntry = orgIter.hasNext() ? orgIter.next() : null; + } else if (diff > 0) { + index = orgRowEntry != null? currentEntries.indexOf(orgRowEntry): + currentEntries.size(); + currentEntries.add(index, newRowEntry); + if (DEBUG) { + Log.d(TAG, String.format("notifyItemInserted called (%d)%s", index, + newRowEntry.titleSectionName)); + } + newRowEntry = newIter.hasNext() ? newIter.next() : null; + mListener.notifyItemInserted(index); + + } else { + // same package name but, + // did the icon, title, etc, change? + // or did the widget size and desc, span, etc change? + if (!isSamePackageItemInfo(orgRowEntry.pkgItem, newRowEntry.pkgItem) || + !orgRowEntry.widgets.equals(newRowEntry.widgets)) { + index = currentEntries.indexOf(orgRowEntry); + currentEntries.set(index, newRowEntry); + mListener.notifyItemChanged(index); + if (DEBUG) { + Log.d(TAG, String.format("notifyItemChanged called (%d)%s", index, + newRowEntry.titleSectionName)); + } + } + orgRowEntry = orgIter.hasNext() ? orgIter.next() : null; + newRowEntry = newIter.hasNext() ? newIter.next() : null; + } + } while(orgRowEntry != null || newRowEntry != null); + } + + /** + * Compare package name using the same comparator as in {@link WidgetsListAdapter}. + * Also handle null row pointers. + */ + private int comparePackageName(WidgetListRowEntry curRow, WidgetListRowEntry newRow, + WidgetListRowEntryComparator comparator) { + if (curRow == null && newRow == null) { + throw new IllegalStateException("Cannot compare PackageItemInfo if both rows are null."); + } + + if (curRow == null && newRow != null) { + return 1; // new row needs to be inserted + } else if (curRow != null && newRow == null) { + return -1; // old row needs to be deleted + } + return comparator.compare(curRow, newRow); + } + + private boolean isSamePackageItemInfo(PackageItemInfo curInfo, PackageItemInfo newInfo) { + return curInfo.iconBitmap.equals(newInfo.iconBitmap) && + !mIconCache.isDefaultIcon(curInfo.iconBitmap, curInfo.user); + } +} diff --git a/src/com/android/launcher3/widget/WidgetsListAdapter.java b/src/com/android/launcher3/widget/WidgetsListAdapter.java index a1eb0ab12..6b1800c67 100644 --- a/src/com/android/launcher3/widget/WidgetsListAdapter.java +++ b/src/com/android/launcher3/widget/WidgetsListAdapter.java @@ -21,9 +21,10 @@ import android.support.v7.widget.RecyclerView.Adapter; import android.util.Log; import android.view.LayoutInflater; import android.view.View; +import android.view.View.OnClickListener; +import android.view.View.OnLongClickListener; import android.view.ViewGroup; -import com.android.launcher3.LauncherAppState; import com.android.launcher3.R; import com.android.launcher3.WidgetPreviewLoader; import com.android.launcher3.compat.AlphabeticIndexCompat; @@ -55,40 +56,67 @@ public class WidgetsListAdapter extends Adapter<WidgetsRowViewHolder> { private final WidgetPreviewLoader mWidgetPreviewLoader; private final LayoutInflater mLayoutInflater; - - private final View.OnClickListener mIconClickListener; - private final View.OnLongClickListener mIconLongClickListener; - - private final ArrayList<WidgetListRowEntry> mEntries = new ArrayList<>(); private final AlphabeticIndexCompat mIndexer; + private final OnClickListener mIconClickListener; + private final OnLongClickListener mIconLongClickListener; private final int mIndent; - - public WidgetsListAdapter(View.OnClickListener iconClickListener, - View.OnLongClickListener iconLongClickListener, - Context context) { - mLayoutInflater = LayoutInflater.from(context); - mWidgetPreviewLoader = LauncherAppState.getInstance(context).getWidgetCache(); - - mIndexer = new AlphabeticIndexCompat(context); - + private ArrayList<WidgetListRowEntry> mEntries = new ArrayList<>(); + private final WidgetsDiffReporter mDiffReporter; + + public WidgetsListAdapter(Context context, LayoutInflater layoutInflater, + WidgetPreviewLoader widgetPreviewLoader, AlphabeticIndexCompat indexCompat, + OnClickListener iconClickListener, OnLongClickListener iconLongClickListener, + WidgetsDiffReporter diffReporter) { + mLayoutInflater = layoutInflater; + mWidgetPreviewLoader = widgetPreviewLoader; + mIndexer = indexCompat; mIconClickListener = iconClickListener; mIconLongClickListener = iconLongClickListener; mIndent = context.getResources().getDimensionPixelSize(R.dimen.widget_section_indent); + mDiffReporter = diffReporter; } + public void setNotifyListener() { + mDiffReporter.setListener(new WidgetsDiffReporter.NotifyListener() { + @Override + public void notifyDataSetChanged() { + WidgetsListAdapter.this.notifyDataSetChanged(); + } + + @Override + public void notifyItemChanged(int index) { + WidgetsListAdapter.this.notifyItemChanged(index); + } + + @Override + public void notifyItemInserted(int index) { + WidgetsListAdapter.this.notifyItemInserted(index); + } + + @Override + public void notifyItemRemoved(int index) { + WidgetsListAdapter.this.notifyItemRemoved(index); + } + }); + } + + /** + * Update the widget list. + */ public void setWidgets(MultiHashMap<PackageItemInfo, WidgetItem> widgets) { - mEntries.clear(); - WidgetItemComparator widgetComparator = new WidgetItemComparator(); + ArrayList<WidgetListRowEntry> tempEntries = new ArrayList<>(); + WidgetItemComparator widgetComparator = new WidgetItemComparator(); for (Map.Entry<PackageItemInfo, ArrayList<WidgetItem>> entry : widgets.entrySet()) { WidgetListRowEntry row = new WidgetListRowEntry(entry.getKey(), entry.getValue()); row.titleSectionName = mIndexer.computeSectionName(row.pkgItem.title); Collections.sort(row.widgets, widgetComparator); - mEntries.add(row); + tempEntries.add(row); } - - Collections.sort(mEntries, new WidgetListRowEntryComparator()); + WidgetListRowEntryComparator rowComparator = new WidgetListRowEntryComparator(); + Collections.sort(tempEntries, rowComparator); + mDiffReporter.process(mEntries, tempEntries, rowComparator); } @Override |