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 17 package com.android.car.carlauncher; 18 19 import android.annotation.Nullable; 20 import android.content.ComponentName; 21 import android.content.Context; 22 import android.util.Log; 23 import android.view.LayoutInflater; 24 import android.view.View; 25 import android.view.ViewGroup; 26 27 import androidx.recyclerview.widget.RecyclerView; 28 29 import java.util.Collections; 30 import java.util.List; 31 32 /** 33 * The adapter that populates the grid view with apps. 34 */ 35 final class AppGridAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> { 36 public static final int RECENT_APPS_TYPE = 1; 37 public static final int APP_ITEM_TYPE = 2; 38 private static final long RECENT_APPS_ID = 0; 39 private static final String TAG = "AppGridAdapter"; 40 41 private final Context mContext; 42 private final int mColumnNumber; 43 private final LayoutInflater mInflater; 44 45 private List<AppMetaData> mApps; 46 private List<AppMetaData> mMostRecentApps; 47 private boolean mIsDistractionOptimizationRequired; 48 AppGridAdapter(Context context)49 AppGridAdapter(Context context) { 50 mContext = context; 51 mInflater = LayoutInflater.from(context); 52 mColumnNumber = 53 mContext.getResources().getInteger(R.integer.car_app_selector_column_number); 54 // Stable IDs improve performance and make rotary work better. 55 setHasStableIds(true); 56 } 57 setIsDistractionOptimizationRequired(boolean isDistractionOptimizationRequired)58 void setIsDistractionOptimizationRequired(boolean isDistractionOptimizationRequired) { 59 mIsDistractionOptimizationRequired = isDistractionOptimizationRequired; 60 sortAllApps(); 61 notifyDataSetChanged(); 62 } 63 setMostRecentApps(@ullable List<AppMetaData> mostRecentApps)64 void setMostRecentApps(@Nullable List<AppMetaData> mostRecentApps) { 65 mMostRecentApps = mostRecentApps; 66 notifyDataSetChanged(); 67 } 68 69 @Override getItemId(int position)70 public long getItemId(int position) { 71 if (position == 0 && hasRecentlyUsedApps()) { 72 return RECENT_APPS_ID; 73 } 74 if (mApps == null) { 75 Log.w(TAG, "apps list not set"); 76 return RecyclerView.NO_ID; 77 } 78 int index = hasRecentlyUsedApps() ? position - 1 : position; 79 if (index < 0 || index >= mApps.size()) { 80 Log.w(TAG, "index out of range"); 81 return RecyclerView.NO_ID; 82 } 83 ComponentName componentName = mApps.get(index).getComponentName(); 84 long id = componentName.getPackageName().hashCode(); 85 id <<= Integer.SIZE; 86 id |= componentName.getClassName().hashCode(); 87 return id; 88 } 89 setAllApps(@ullable List<AppMetaData> apps)90 void setAllApps(@Nullable List<AppMetaData> apps) { 91 mApps = apps; 92 sortAllApps(); 93 notifyDataSetChanged(); 94 } 95 getSpanSizeLookup(int position)96 public int getSpanSizeLookup(int position) { 97 if (position == 0 && hasRecentlyUsedApps()) { 98 return mColumnNumber; 99 } 100 return 1; 101 } 102 103 @Override getItemViewType(int position)104 public int getItemViewType(int position) { 105 if (position == 0 && hasRecentlyUsedApps()) { 106 return RECENT_APPS_TYPE; 107 } 108 return APP_ITEM_TYPE; 109 } 110 111 @Override onCreateViewHolder(ViewGroup parent, int viewType)112 public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { 113 if (viewType == RECENT_APPS_TYPE) { 114 View view = 115 mInflater.inflate(R.layout.recent_apps_row, parent, /* attachToRoot= */ false); 116 return new RecentAppsRowViewHolder(view, mContext); 117 } else { 118 View view = mInflater.inflate(R.layout.app_item, parent, /* attachToRoot= */ false); 119 return new AppItemViewHolder(view, mContext); 120 } 121 } 122 123 @Override onBindViewHolder(RecyclerView.ViewHolder holder, int position)124 public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { 125 switch (holder.getItemViewType()) { 126 case RECENT_APPS_TYPE: 127 ((RecentAppsRowViewHolder) holder).bind( 128 mMostRecentApps, mIsDistractionOptimizationRequired); 129 break; 130 case APP_ITEM_TYPE: 131 int index = hasRecentlyUsedApps() ? position - 1 : position; 132 AppMetaData app = mApps.get(index); 133 ((AppItemViewHolder) holder).bind(app, mIsDistractionOptimizationRequired); 134 break; 135 default: 136 } 137 } 138 139 @Override getItemCount()140 public int getItemCount() { 141 // If there are any most recently launched apps, add a "most recently used apps row item" 142 return (mApps == null ? 0 : mApps.size()) + (hasRecentlyUsedApps() ? 1 : 0); 143 } 144 hasRecentlyUsedApps()145 private boolean hasRecentlyUsedApps() { 146 return mMostRecentApps != null && mMostRecentApps.size() > 0; 147 } 148 sortAllApps()149 private void sortAllApps() { 150 if (mApps != null) { 151 Collections.sort(mApps, AppLauncherUtils.ALPHABETICAL_COMPARATOR); 152 } 153 } 154 }