diff options
Diffstat (limited to 'src/com/android/launcher3/AppDrawerListAdapter.java')
-rw-r--r-- | src/com/android/launcher3/AppDrawerListAdapter.java | 350 |
1 files changed, 150 insertions, 200 deletions
diff --git a/src/com/android/launcher3/AppDrawerListAdapter.java b/src/com/android/launcher3/AppDrawerListAdapter.java index 3639e11f4..c68f52f7a 100644 --- a/src/com/android/launcher3/AppDrawerListAdapter.java +++ b/src/com/android/launcher3/AppDrawerListAdapter.java @@ -33,7 +33,6 @@ import android.view.View; import android.view.ViewGroup; import android.view.animation.DecelerateInterpolator; import android.view.animation.Interpolator; -import android.widget.FrameLayout; import android.widget.LinearLayout; import android.widget.SectionIndexer; import com.android.launcher3.locale.LocaleSetManager; @@ -53,6 +52,9 @@ import java.util.List; public class AppDrawerListAdapter extends RecyclerView.Adapter<AppDrawerListAdapter.ViewHolder> implements View.OnLongClickListener, DragSource, SectionIndexer { + public static final String REMOTE_HEADER = "☆"; + public static final String REMOTE_SCRUBBER = "★"; + private static final String TAG = AppDrawerListAdapter.class.getSimpleName(); private static final String NUMERIC_OR_SPECIAL_HEADER = "#"; @@ -71,6 +73,34 @@ public class AppDrawerListAdapter extends RecyclerView.Adapter<AppDrawerListAdap } } + private static class Bucket { + private int index; + private String startString; + + public Bucket(int index, String startString) { + this.index = index; + this.startString = startString; + } + } + + private static Bucket getBucketForApp(AppInfo app) { + if (app.hasFlag(AppInfo.REMOTE_APP_FLAG)) { + return new Bucket(Integer.MIN_VALUE, REMOTE_HEADER); + } else { + LocaleUtils localeUtils = LocaleUtils.getInstance(); + int index = localeUtils.getBucketIndex(app.title.toString()); + String start = localeUtils.getBucketLabel(index); + if (TextUtils.isEmpty(start)) { + start = NUMERIC_OR_SPECIAL_HEADER; + index = localeUtils.getBucketIndex(start); + } + return new Bucket(index, start); + } + } + + private final RemoteFolderManager mRemoteFolderManager; + + private HashSet<AppInfo> mAllApps; private ArrayList<AppItemIndexedInfo> mHeaderList; private LayoutInflater mLayoutInflater; @@ -113,8 +143,11 @@ public class AppDrawerListAdapter extends RecyclerView.Adapter<AppDrawerListAdap } public static class ViewHolder extends RecyclerView.ViewHolder { - public AutoFitTextView mTextView; - public ViewGroup mLayout; + public static int TYPE_NORMAL = 0; + public static int TYPE_CUSTOM = 1; + + public AutoFitTextView mHeaderTextView; + public ViewGroup mIconLayout; public View mContainerView; public View mFadingBackgroundBackView; public View mFadingBackgroundFrontView; @@ -123,9 +156,9 @@ public class AppDrawerListAdapter extends RecyclerView.Adapter<AppDrawerListAdap mContainerView = itemView; mFadingBackgroundBackView = itemView.findViewById(R.id.fading_background_back); mFadingBackgroundFrontView = itemView.findViewById(R.id.fading_background_front); - mTextView = (AutoFitTextView) itemView.findViewById(R.id.drawer_item_title); - mTextView.bringToFront(); - mLayout = (ViewGroup) itemView.findViewById(R.id.drawer_item_flow); + mHeaderTextView = (AutoFitTextView) itemView.findViewById(R.id.drawer_item_title); + mHeaderTextView.bringToFront(); + mIconLayout = (ViewGroup) itemView.findViewById(R.id.drawer_item_flow); } } @@ -180,14 +213,14 @@ public class AppDrawerListAdapter extends RecyclerView.Adapter<AppDrawerListAdap public void add(ViewHolder holder) { mViewHolderSet.add(holder); - holder.mTextView.addOnLayoutChangeListener(mLayoutChangeListener); + holder.mHeaderTextView.addOnLayoutChangeListener(mLayoutChangeListener); createAnimationHook(holder); } public void remove(ViewHolder holder) { mViewHolderSet.remove(holder); - holder.mTextView.removeOnLayoutChangeListener(mLayoutChangeListener); + holder.mHeaderTextView.removeOnLayoutChangeListener(mLayoutChangeListener); } public void onScrollStateChanged(RecyclerView recyclerView, int newState) { @@ -252,8 +285,8 @@ public class AppDrawerListAdapter extends RecyclerView.Adapter<AppDrawerListAdap } public void createAnimationHook(final ViewHolder holder) { - holder.mTextView.animate().cancel(); - holder.mTextView.animate() + holder.mHeaderTextView.animate().cancel(); + holder.mHeaderTextView.animate() .setUpdateListener(new ItemAnimator(holder, mItemAnimatorSet)) .setListener(new AnimatorListenerAdapter() { @Override @@ -325,8 +358,8 @@ public class AppDrawerListAdapter extends RecyclerView.Adapter<AppDrawerListAdap // Scale header text letters final float targetScale = (MAX_SCALE - MIN_SCALE) * percentage + MIN_SCALE; - holder.mTextView.setScaleX(targetScale); - holder.mTextView.setScaleY(targetScale); + holder.mHeaderTextView.setScaleX(targetScale); + holder.mHeaderTextView.setScaleY(targetScale); // Perform animation if (getSectionForPosition(holder.getPosition()) == mSectionTarget) { @@ -370,8 +403,11 @@ public class AppDrawerListAdapter extends RecyclerView.Adapter<AppDrawerListAdap public AppDrawerListAdapter(Launcher launcher) { mLauncher = launcher; mHeaderList = new ArrayList<AppItemIndexedInfo>(); + mAllApps = new HashSet<AppInfo>(); mLayoutInflater = LayoutInflater.from(launcher); + mRemoteFolderManager = mLauncher.getRemoteFolderManager(); + mLocaleSetManager = new LocaleSetManager(mLauncher); mLocaleSetManager.updateLocaleSet(mLocaleSetManager.getSystemLocaleSet()); mItemAnimatorSet = new ItemAnimatorSet(launcher); @@ -388,7 +424,6 @@ public class AppDrawerListAdapter extends RecyclerView.Adapter<AppDrawerListAdap mItemAnimatorSet.onScrolled(recyclerView, dx, dy); } - public void setDragging(boolean dragging) { mItemAnimatorSet.setDragging(dragging); } @@ -400,6 +435,13 @@ public class AppDrawerListAdapter extends RecyclerView.Adapter<AppDrawerListAdap mItemAnimatorSet.setSectionTarget(sectionIndex); } + /** + * @return the number of columns shown in the app drawer + */ + public int getNumColumns() { + return mNumColumns; + } + private void initParams() { mDeviceProfile = LauncherAppState.getInstance().getDynamicGrid().getDeviceProfile(); @@ -407,7 +449,7 @@ public class AppDrawerListAdapter extends RecyclerView.Adapter<AppDrawerListAdap // set aside the space needed for the container character int neededWidth = mLauncher.getResources() - .getDimensionPixelSize(R.dimen.app_drawer_char_width); + .getDimensionPixelSize(R.dimen.drawer_header_text_char_width); int availableWidth = mDeviceProfile.availableWidthPx - neededWidth; mNumColumns = (int) Math.floor(availableWidth / iconWidth); int leftOverPx = availableWidth % iconWidth; @@ -432,79 +474,67 @@ public class AppDrawerListAdapter extends RecyclerView.Adapter<AppDrawerListAdap /** * Create and populate mHeaderList (buckets for app sorting) - * @param info */ - public void populateByCharacter(ArrayList<AppInfo> info) { - if (info == null || info.size() <= 0) { - Collections.sort(mHeaderList); - return; - } + public void populateByCharacter() { + mHeaderList.clear(); // Create a clone of AppInfo ArrayList to preserve data - ArrayList<AppInfo> tempInfo = (ArrayList<AppInfo>) info.clone(); + HashSet<AppInfo> appsToProcess = (HashSet<AppInfo>) mAllApps.clone(); + while (!appsToProcess.isEmpty()) { + ArrayList<AppInfo> matchingApps = new ArrayList<AppInfo>(); - ArrayList<AppInfo> appInfos = new ArrayList<AppInfo>(); + AppInfo app = appsToProcess.iterator().next(); + Bucket bucket = getBucketForApp(app); - // get next app - AppInfo app = tempInfo.get(0); + // Find other apps that fall into the same bucket + for (Iterator<AppInfo> iter = appsToProcess.iterator(); iter.hasNext(); ) { + AppInfo otherApp = iter.next(); + Bucket otherBucket = getBucketForApp(otherApp); - // get starting character - LocaleUtils localeUtils = LocaleUtils.getInstance(); - int bucketIndex = localeUtils.getBucketIndex(app.title.toString()); - String startString - = localeUtils.getBucketLabel(bucketIndex); - if (TextUtils.isEmpty(startString)) { - startString = NUMERIC_OR_SPECIAL_HEADER; - bucketIndex = localeUtils.getBucketIndex(startString); - } - - // now iterate through - for (AppInfo info1 : tempInfo) { - int newBucketIndex = localeUtils.getBucketIndex(info1.title.toString()); + if (bucket.index == otherBucket.index) { + matchingApps.add(otherApp); - String newChar - = localeUtils.getBucketLabel(newBucketIndex); - if (TextUtils.isEmpty(newChar)) { - newChar = NUMERIC_OR_SPECIAL_HEADER; - } - // if same character - if (newChar.equals(startString)) { - // add it - appInfos.add(info1); + // This app doesn't need to be processed again for other strings + iter.remove(); + } } - } - - Collections.sort(appInfos, LauncherModel.getAppNameComparator()); - for (int i = 0; i < appInfos.size(); i += mNumColumns) { - int endIndex = (int) Math.min(i + mNumColumns, appInfos.size()); - ArrayList<AppInfo> subList = new ArrayList<AppInfo>(appInfos.subList(i, endIndex)); - AppItemIndexedInfo indexInfo; - indexInfo = new AppItemIndexedInfo(startString, bucketIndex, subList, i != 0); - mHeaderList.add(indexInfo); + // Sort so they display in alphabetical order + Collections.sort(matchingApps, LauncherModel.getAppNameComparator()); + + // Split app list by number of columns and add rows to header list + for (int i = 0; i < matchingApps.size(); i += mNumColumns) { + int endIndex = Math.min(i + mNumColumns, matchingApps.size()); + ArrayList<AppInfo> subList = + new ArrayList<AppInfo>(matchingApps.subList(i, endIndex)); + AppItemIndexedInfo indexedInfo = + new AppItemIndexedInfo(bucket.startString, bucket.index, subList, i != 0); + mHeaderList.add(indexedInfo); + } } - for (AppInfo remove : appInfos) { - // remove from mApps - tempInfo.remove(remove); - } - populateByCharacter(tempInfo); + Collections.sort(mHeaderList); } - public void setApps(ArrayList<AppInfo> list) { + public void setApps(List<AppInfo> list) { if (!LauncherAppState.isDisableAllApps()) { initParams(); filterProtectedApps(list); + mAllApps.clear(); + mAllApps.addAll(list); - mHeaderList.clear(); - populateByCharacter(list); - populateSectionHeaders(); - mLauncher.updateScrubber(); - this.notifyDataSetChanged(); + processApps(); } } + private void processApps() { + populateByCharacter(); + populateSectionHeaders(); + mLauncher.updateScrubber(); + this.notifyDataSetChanged(); + } + private void populateSectionHeaders() { if (mSectionHeaders == null || mSectionHeaders.size() != mHeaderList.size()) { mSectionHeaders = new LinkedHashMap<>(); @@ -521,128 +551,30 @@ public class AppDrawerListAdapter extends RecyclerView.Adapter<AppDrawerListAdap } public void reset() { - ArrayList<AppInfo> infos = getAllApps(); - mLauncher.mAppDrawer.getLayoutManager().removeAllViews(); - setApps(infos); - } - - private ArrayList<AppInfo> getAllApps() { - ArrayList<AppInfo> indexedInfos = new ArrayList<AppInfo>(); - - for (int j = 0; j < mHeaderList.size(); ++j) { - AppItemIndexedInfo indexedInfo = mHeaderList.get(j); - for (AppInfo info : indexedInfo.mInfo) { - indexedInfos.add(info); - } - } - return indexedInfos; - } - - public void updateApps(ArrayList<AppInfo> list) { - // We remove and re-add the updated applications list because it's properties may have - // changed (ie. the title), and this will ensure that the items will be in their proper - // place in the list. - if (!LauncherAppState.isDisableAllApps()) { - removeAppsWithoutInvalidate(list); - addAppsWithoutInvalidate(list); - reset(); - } + processApps(); } - - public void addApps(ArrayList<AppInfo> list) { + public void updateApps(List<AppInfo> list) { if (!LauncherAppState.isDisableAllApps()) { - addAppsWithoutInvalidate(list); + mAllApps.removeAll(list); + mAllApps.addAll(list); reset(); } } - private void addAppsWithoutInvalidate(ArrayList<AppInfo> list) { - // We add it in place, in alphabetical order - LocaleUtils localeUtils = LocaleUtils.getInstance(); - - int count = list.size(); - for (int i = 0; i < count; ++i) { - AppInfo info = list.get(i); - boolean found = false; - AppItemIndexedInfo lastInfoForSection = null; - int bucketIndex = localeUtils.getBucketIndex(info.title.toString()); - String start = localeUtils.getBucketLabel(bucketIndex); - if (TextUtils.isEmpty(start)) { - start = NUMERIC_OR_SPECIAL_HEADER; - bucketIndex = localeUtils.getBucketIndex(start); - } - for (int j = 0; j < mHeaderList.size(); ++j) { - AppItemIndexedInfo indexedInfo = mHeaderList.get(j); - if (start.equals(indexedInfo.mStartString)) { - Collections.sort(indexedInfo.mInfo, LauncherModel.getAppNameComparator()); - int index = - Collections.binarySearch(indexedInfo.mInfo, - info, LauncherModel.getAppNameComparator()); - if (index >= 0) { - found = true; - break; - } else { - lastInfoForSection = indexedInfo; - } - } - } - if (!found) { - if (lastInfoForSection != null) { - lastInfoForSection.mInfo.add(info); - } else { - // we need to create a new section - ArrayList<AppInfo> newInfos = new ArrayList<AppInfo>(); - newInfos.add(info); - AppItemIndexedInfo newInfo = - new AppItemIndexedInfo(start, bucketIndex, newInfos, false); - mHeaderList.add(newInfo); - Collections.sort(mHeaderList); - } - } - } + public void addApps(List<AppInfo> list) { + updateApps(list); } - public void removeApps(ArrayList<AppInfo> appInfos) { + public void removeApps(List<AppInfo> appInfos) { if (!LauncherAppState.isDisableAllApps()) { - removeAppsWithoutInvalidate(appInfos); - //recreate everything + mAllApps.removeAll(appInfos); reset(); } } - private void removeAppsWithoutInvalidate(ArrayList<AppInfo> list) { - // loop through all the apps and remove apps that have the same component - int length = list.size(); - for (int i = 0; i < length; ++i) { - AppInfo info = list.get(i); - for (int j = 0; j < mHeaderList.size(); ++j) { - AppItemIndexedInfo indexedInfo = mHeaderList.get(j); - ArrayList<AppInfo> clonedIndexedInfoApps = - (ArrayList<AppInfo>) indexedInfo.mInfo.clone(); - int index = - findAppByComponent(clonedIndexedInfoApps, info); - if (index > -1) { - indexedInfo.mInfo.remove(info); - } - } - } - } - - private int findAppByComponent(List<AppInfo> list, AppInfo item) { - ComponentName removeComponent = item.intent.getComponent(); - int length = list.size(); - for (int i = 0; i < length; ++i) { - AppInfo info = list.get(i); - if (info.intent.getComponent().equals(removeComponent)) { - return i; - } - } - return -1; - } - /* * AllAppsView implementation */ @@ -655,28 +587,34 @@ public class AppDrawerListAdapter extends RecyclerView.Adapter<AppDrawerListAdap View v = LayoutInflater.from(parent.getContext()). inflate(R.layout.app_drawer_item, parent, false); ViewHolder holder = new ViewHolder(v); - ViewGroup.LayoutParams params = holder.mTextView.getLayoutParams(); - - // set the margin parameter to account for the text size of the icons so that the text view - // is based on the icon size only - if (params instanceof ViewGroup.MarginLayoutParams) { - ViewGroup.MarginLayoutParams marginParams = (ViewGroup.MarginLayoutParams) params; - marginParams.setMargins(marginParams.leftMargin, marginParams.topMargin, - marginParams.rightMargin, marginParams.bottomMargin); - holder.mTextView.setLayoutParams(marginParams); - } for (int i = 0; i < mNumColumns; i++) { AppDrawerIconView icon = (AppDrawerIconView) mLayoutInflater.inflate( - R.layout.drawer_icon, holder.mLayout, false); + R.layout.drawer_icon, holder.mIconLayout, false); icon.setOnClickListener(mLauncher); icon.setOnLongClickListener(this); - holder.mLayout.addView(icon); + holder.mIconLayout.addView(icon); + + icon.mIcon.setPadding(mDeviceProfile.iconDrawablePaddingPx, + mDeviceProfile.iconDrawablePaddingPx, + mDeviceProfile.iconDrawablePaddingPx, + mDeviceProfile.iconDrawablePaddingPx); + } + + if (viewType == ViewHolder.TYPE_CUSTOM) { + mRemoteFolderManager.onCreateViewHolder(holder); } + return holder; } @Override + public int getItemViewType(int position) { + return mHeaderList.get(position).isRemote() ? + ViewHolder.TYPE_CUSTOM : ViewHolder.TYPE_NORMAL; + } + + @Override public void onViewAttachedToWindow(ViewHolder holder) { super.onViewAttachedToWindow(holder); @@ -704,23 +642,24 @@ public class AppDrawerListAdapter extends RecyclerView.Adapter<AppDrawerListAdap @Override public void onBindViewHolder(ViewHolder holder, int position) { AppItemIndexedInfo indexedInfo = mHeaderList.get(position); - holder.mTextView.setVisibility(indexedInfo.isChild ? View.INVISIBLE : View.VISIBLE); + + if (indexedInfo.isRemote()) { + mRemoteFolderManager.onBindViewHolder(holder, indexedInfo); + } + + holder.mHeaderTextView.setVisibility(indexedInfo.isChild ? View.INVISIBLE : View.VISIBLE); if (!indexedInfo.isChild) { - if (indexedInfo.mStartString.equals(NUMERIC_OR_SPECIAL_HEADER)) { - holder.mTextView.setText(NUMERIC_OR_SPECIAL_HEADER); - } else { - holder.mTextView.setText(String.valueOf(indexedInfo.mStartString)); - } + holder.mHeaderTextView.setText(indexedInfo.mStartString); } - holder.mTextView.setPivotX(0); - holder.mTextView.setPivotY(holder.mTextView.getHeight() / 2); + holder.mHeaderTextView.setPivotX(0); + holder.mHeaderTextView.setPivotY(holder.mHeaderTextView.getHeight() / 2); final int size = indexedInfo.mInfo.size(); - int childSize = holder.mLayout.getChildCount(); + int childSize = holder.mIconLayout.getChildCount(); for (int i = 0; i < childSize; i++) { - AppDrawerIconView icon = (AppDrawerIconView) holder.mLayout.getChildAt(i); + AppDrawerIconView icon = (AppDrawerIconView) holder.mIconLayout.getChildAt(i); icon.setLayoutParams(mIconParams); int extraStart = mExtraPadding; int extraEnd = mExtraPadding; @@ -742,13 +681,16 @@ public class AppDrawerListAdapter extends RecyclerView.Adapter<AppDrawerListAdap icon.setVisibility(View.VISIBLE); AppInfo info = indexedInfo.mInfo.get(i); icon.setTag(info); - Drawable d = Utilities.createIconDrawable(info.iconBitmap); + + Drawable d; + if (info.customDrawable != null) { + d = info.customDrawable; + } else { + d = Utilities.createIconDrawable(info.iconBitmap); + } d.setBounds(mIconRect); icon.mIcon.setImageDrawable(d); - icon.mIcon.setPadding(mDeviceProfile.iconDrawablePaddingPx, - mDeviceProfile.iconDrawablePaddingPx, - mDeviceProfile.iconDrawablePaddingPx, - mDeviceProfile.iconDrawablePaddingPx); + icon.mLabel.setText(info.title); icon.mLabel.setVisibility(mHideIconLabels ? View.INVISIBLE : View.VISIBLE); } @@ -877,6 +819,14 @@ public class AppDrawerListAdapter extends RecyclerView.Adapter<AppDrawerListAdap } return 0; } + + public boolean isRemote() { + return mStartString == REMOTE_HEADER; + } + + public ArrayList<AppInfo> getInfo() { + return mInfo; + } } @Override @@ -916,7 +866,7 @@ public class AppDrawerListAdapter extends RecyclerView.Adapter<AppDrawerListAdap return index; } - private void filterProtectedApps(ArrayList<AppInfo> list) { + private void filterProtectedApps(List<AppInfo> list) { updateProtectedAppsList(mLauncher); Iterator<AppInfo> iterator = list.iterator(); |