arun.com.chromer.shared.views.IntentPickerSheetView.java Source code

Java tutorial

Introduction

Here is the source code for arun.com.chromer.shared.views.IntentPickerSheetView.java

Source

/*
 * Lynket
 *
 * Copyright (C) 2019 Arunkumar
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package arun.com.chromer.shared.views;

import android.annotation.SuppressLint;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.graphics.drawable.Drawable;
import android.os.AsyncTask;
import android.os.Build;
import android.support.annotation.NonNull;
import android.support.annotation.StringRes;
import android.support.v4.view.ViewCompat;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.FrameLayout;
import android.widget.GridView;
import android.widget.ImageView;
import android.widget.TextView;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

import arun.com.chromer.util.Utils;
import flipboard.bottomsheet.commons.R;

@SuppressLint("ViewConstructor")
public class IntentPickerSheetView extends FrameLayout {

    private final Intent intent;
    private final GridView appGrid;
    @SuppressWarnings("FieldCanBeLocal")
    private final TextView titleView;
    private final List<ActivityInfo> mixins = new ArrayList<>();
    private Adapter adapter;
    private Filter filter = new FilterNone();
    private Comparator<ActivityInfo> sortMethod = new SortAlphabetically();
    private int columnWidthDp = 100;

    public IntentPickerSheetView(Context context, Intent intent, @StringRes int titleRes,
            OnIntentPickedListener listener) {
        this(context, intent, context.getString(titleRes), listener);
    }

    @SuppressWarnings("WeakerAccess")
    public IntentPickerSheetView(Context context, final Intent intent, final String title,
            final OnIntentPickedListener listener) {
        super(context);
        this.intent = intent;

        inflate(context, R.layout.grid_sheet_view, this);
        appGrid = findViewById(R.id.grid);
        titleView = findViewById(R.id.title);

        titleView.setText(title);
        appGrid.setOnItemClickListener(
                (parent, view, position, id) -> listener.onIntentPicked(adapter.getItem(position)));

        ViewCompat.setElevation(this, Utils.dpToPx(16));
    }

    @NonNull
    public static Filter selfPackageExcludeFilter(@NonNull final Context context) {
        return info -> !info.componentName.getPackageName().equalsIgnoreCase(context.getPackageName());
    }

    @Override
    protected void onDetachedFromWindow() {
        super.onDetachedFromWindow();
        for (ActivityInfo activityInfo : adapter.activityInfos) {
            if (activityInfo.iconLoadTask != null) {
                activityInfo.iconLoadTask.cancel(true);
                activityInfo.iconLoadTask = null;
            }
        }
    }

    public void setSortMethod(Comparator<ActivityInfo> sortMethod) {
        this.sortMethod = sortMethod;
    }

    public void setFilter(Filter filter) {
        this.filter = filter;
    }

    public void setColumnWidthDp(int columnWidthDp) {
        this.columnWidthDp = columnWidthDp;
    }

    public List<ActivityInfo> getMixins() {
        return this.mixins;
    }

    /**
     * Adds custom mixins to the resulting picker sheet
     *
     * @param infos Custom ActivityInfo classes to mix in
     */
    public void setMixins(@NonNull List<ActivityInfo> infos) {
        mixins.clear();
        mixins.addAll(infos);
    }

    @Override
    protected void onAttachedToWindow() {
        super.onAttachedToWindow();
        this.adapter = new Adapter(getContext(), intent, mixins);
        appGrid.setAdapter(this.adapter);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        int width = MeasureSpec.getSize(widthMeasureSpec);
        final float density = getResources().getDisplayMetrics().density;
        getResources().getDimensionPixelSize(R.dimen.bottomsheet_default_sheet_width);
        appGrid.setNumColumns((int) (width / (columnWidthDp * density)));
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        // Necessary for showing elevation on 5.0+
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            setOutlineProvider(new Utils.ShadowOutline(w, h));
        }
    }

    public interface Filter {
        boolean include(ActivityInfo info);
    }

    public interface OnIntentPickedListener {
        void onIntentPicked(ActivityInfo activityInfo);
    }

    /**
     * Represents an item in the picker grid
     */
    public static class ActivityInfo {
        public final String label;
        public final ComponentName componentName;
        public final ResolveInfo resolveInfo;
        public Drawable icon;
        public Object tag;
        private AsyncTask<Void, Void, Drawable> iconLoadTask;

        public ActivityInfo(Drawable icon, String label, Context context, Class<?> clazz) {
            this.icon = icon;
            resolveInfo = null;
            this.label = label;
            this.componentName = new ComponentName(context, clazz.getName());
        }

        public ActivityInfo(ResolveInfo resolveInfo, CharSequence label, ComponentName componentName) {
            this.resolveInfo = resolveInfo;
            this.label = label.toString();
            this.componentName = componentName;
        }

        public Intent getConcreteIntent(Intent intent) {
            Intent concreteIntent = new Intent(intent);
            concreteIntent.setComponent(componentName);
            return concreteIntent;
        }
    }

    private class SortAlphabetically implements Comparator<ActivityInfo> {
        @Override
        public int compare(ActivityInfo lhs, ActivityInfo rhs) {
            return lhs.label.compareTo(rhs.label);
        }
    }

    private class FilterNone implements Filter {
        @Override
        public boolean include(ActivityInfo info) {
            return true;
        }
    }

    private class Adapter extends BaseAdapter {

        final List<ActivityInfo> activityInfos;
        final LayoutInflater inflater;
        private final PackageManager packageManager;

        public Adapter(Context context, Intent intent, List<ActivityInfo> mixins) {
            inflater = LayoutInflater.from(context);
            packageManager = context.getPackageManager();
            @SuppressLint("InlinedApi")
            List<ResolveInfo> infos = packageManager.queryIntentActivities(intent, PackageManager.MATCH_ALL);
            activityInfos = new ArrayList<>(infos.size() + mixins.size());
            activityInfos.addAll(mixins);
            for (ResolveInfo info : infos) {
                ComponentName componentName = new ComponentName(info.activityInfo.packageName,
                        info.activityInfo.name);
                ActivityInfo activityInfo = new ActivityInfo(info, info.loadLabel(packageManager), componentName);
                if (filter.include(activityInfo)) {
                    activityInfos.add(activityInfo);
                }
            }
            Collections.sort(activityInfos, sortMethod);
        }

        @Override
        public int getCount() {
            return activityInfos.size();
        }

        @Override
        public ActivityInfo getItem(int position) {
            return activityInfos.get(position);
        }

        @Override
        public long getItemId(int position) {
            return activityInfos.get(position).componentName.hashCode();
        }

        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            final ViewHolder holder;

            if (convertView == null) {
                convertView = inflater.inflate(R.layout.sheet_grid_item, parent, false);
                holder = new ViewHolder(convertView);
                convertView.setTag(holder);
            } else {
                holder = (ViewHolder) convertView.getTag();
            }

            final ActivityInfo info = activityInfos.get(position);
            if (info.iconLoadTask != null) {
                info.iconLoadTask.cancel(true);
                info.iconLoadTask = null;
            }
            if (info.icon != null) {
                holder.icon.setImageDrawable(info.icon);
            } else {
                //noinspection deprecation
                holder.icon.setImageDrawable(getResources().getDrawable(R.color.divider_gray));
                info.iconLoadTask = new AsyncTask<Void, Void, Drawable>() {
                    @Override
                    protected Drawable doInBackground(@NonNull Void... params) {
                        return info.resolveInfo.loadIcon(packageManager);
                    }

                    @Override
                    protected void onPostExecute(@NonNull Drawable drawable) {
                        info.icon = drawable;
                        info.iconLoadTask = null;
                        holder.icon.setImageDrawable(drawable);
                    }
                };
                info.iconLoadTask.execute();
            }
            holder.label.setText(info.label);

            return convertView;
        }

        class ViewHolder {
            final ImageView icon;
            final TextView label;

            ViewHolder(View root) {
                icon = root.findViewById(R.id.icon);
                label = root.findViewById(R.id.label);
            }
        }

    }
}