package net.typeblog.shelter.ui; import android.graphics.Bitmap; import android.graphics.drawable.Drawable; import android.os.Handler; import android.os.Looper; import android.os.RemoteException; import android.support.annotation.NonNull; import android.support.v7.widget.RecyclerView; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.ImageView; import android.widget.TextView; import net.typeblog.shelter.R; import net.typeblog.shelter.services.ILoadIconCallback; import net.typeblog.shelter.services.IShelterService; import net.typeblog.shelter.util.ApplicationInfoWrapper; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; public class AppListAdapter extends RecyclerView.Adapter { class ViewHolder extends RecyclerView.ViewHolder { private ViewGroup mView; private ImageView mIcon; private TextView mTitle; private TextView mPackage; int mIndex = -1; ViewHolder(ViewGroup view) { super(view); mView = view; mIcon = view.findViewById(R.id.list_app_icon); mTitle = view.findViewById(R.id.list_app_title); mPackage = view.findViewById(R.id.list_app_package); view.setOnClickListener((v) -> onClick()); } void onClick() { if (mIndex == -1) return; // Show available operations via the Fragment // pass the full info to it, since we can't be sure // the index won't change if (mContextMenuHandler != null) { mContextMenuHandler.showContextMenu(mList.get(mIndex), mView); } } void setIndex(final int index) { mIndex = index; if (mIndex >= 0) { ApplicationInfoWrapper info = mList.get(mIndex); mPackage.setText(info.getPackageName()); if (info.isHidden()) { String label = String.format(mLabelDisabled, info.getLabel()); mTitle.setText(label); mView.setBackgroundResource(R.color.disabledAppBackground); } else { mTitle.setText(info.getLabel()); mView.setBackground(null); } // Load the application icon from cache // or populate the cache through the service if (mIconCache.containsKey(info.getPackageName())) { mIcon.setImageBitmap(mIconCache.get(info.getPackageName())); } else { mIcon.setImageDrawable(mDefaultIcon); try { mService.loadIcon(info, new ILoadIconCallback.Stub() { @Override public void callback(Bitmap icon) { if (index == mIndex) { mHandler.post(() -> mIcon.setImageBitmap(icon)); } synchronized (AppListAdapter.class) { mIconCache.put(info.getPackageName(), icon); } } }); } catch (RemoteException e) { // Do Nothing } } } } } interface ContextMenuHandler { void showContextMenu(ApplicationInfoWrapper info, View view); } private List mList = new ArrayList<>(); private IShelterService mService; private Drawable mDefaultIcon; private String mLabelDisabled; private Map mIconCache = new HashMap<>(); private ContextMenuHandler mContextMenuHandler = null; private Handler mHandler = new Handler(Looper.getMainLooper()); AppListAdapter(IShelterService service, Drawable defaultIcon) { mService = service; mDefaultIcon = defaultIcon; } void setContextMenuHandler(ContextMenuHandler handler) { mContextMenuHandler = handler; } void setData(List apps) { mList.clear(); mIconCache.clear(); mList.addAll(apps); notifyDataSetChanged(); } @Override public int getItemCount() { return mList.size(); } @NonNull @Override public ViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int i) { if (mLabelDisabled == null) { mLabelDisabled = viewGroup.getContext().getString(R.string.list_item_disabled); } LayoutInflater inflater = viewGroup.getContext().getSystemService(LayoutInflater.class); ViewGroup view = (ViewGroup) inflater.inflate(R.layout.app_list_item, viewGroup, false); ViewHolder vh = new ViewHolder(view); vh.setIndex(i); return vh; } @Override public void onBindViewHolder(@NonNull ViewHolder viewHolder, int i) { viewHolder.setIndex(i); } @Override public void onViewRecycled(@NonNull ViewHolder holder) { super.onViewRecycled(holder); holder.setIndex(-1); } }