package info.guardianproject.pixelknot; import android.app.Dialog; import android.content.ComponentName; import android.content.DialogInterface; import android.content.Intent; import android.content.pm.ResolveInfo; import android.graphics.Color; import android.graphics.drawable.ColorDrawable; import android.net.Uri; import android.os.Bundle; import android.support.annotation.Nullable; import android.support.design.widget.BottomSheetDialogFragment; import android.support.design.widget.CoordinatorLayout; import android.support.v7.app.AlertDialog; import android.support.v7.app.AppCompatActivity; import android.support.v7.widget.GridLayoutManager; import android.support.v7.widget.RecyclerView; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.CheckBox; import android.widget.ImageView; import android.widget.TextView; import java.util.ArrayList; import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Set; public class ShareChooserDialog extends BottomSheetDialogFragment { private RecyclerView mRecyclerView; private ArrayList<ResolveInfo> mTargets; private int mParentWidth; private final static Set<String> gSafeApps; static { // package names from appbrain.com HashSet<String> activities = new HashSet<>(); activities.add("com.twitter.android"); //, ActivityNames.TWITTER); activities.add("com.facebook.katana"); //, ActivityNames.FACEBOOK); activities.add("com.google.android.gm"); //, ActivityNames.GMAIL); activities.add("com.android.bluetooth"); //, ActivityNames.BLUETOOTH); activities.add("com.yahoo.mobile.client.android.flickr"); //, ActivityNames.FLICKR); activities.add("com.dropbox.android"); //, ActivityNames.DROPBOX); activities.add("com.bumptech.bumpga"); //, ActivityNames.BUMP); activities.add("com.google.android.apps.docs"); //, ActivityNames.DRIVE); activities.add("com.google.android.apps.plus"); //, ActivityNames.GOOGLE_PLUS); //activities.add("com.instagram.android"); //, ActivityNames.INSTAGRAM); activities.add("com.tumblr"); //, ActivityNames.TUMBLR); activities.add("org.wordpress.android"); //, ActivityNames.WORDPRESS); //activities.add("com.skype.raider"); //, ActivityNames.SKYPE); activities.add("com.google.android.email"); //, ActivityNames.EMAIL); activities.add("com.htc.android.mail"); //, ActivityNames.EMAIL); activities.add("com.android.email"); //, ActivityNames.EMAIL); gSafeApps = Collections.unmodifiableSet(activities); } public interface ShareChooserDialogListener { void onItemSelected(ResolveInfo ri); } private ShareChooserDialogListener mListener; public ShareChooserDialog() { super(); } private void setListener(ShareChooserDialogListener listener) { mListener = listener; } @Override public void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); Uri uri = Uri.parse(getArguments().getString("uri")); mParentWidth = getArguments().getInt("width", 640); Intent intent = new Intent(); intent.setAction(Intent.ACTION_SEND); intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); intent.putExtra(Intent.EXTRA_STREAM, uri); intent.setType("image/jpeg"); mTargets = new ArrayList<>(); List<ResolveInfo> resInfo = App.getInstance().getPackageManager().queryIntentActivities(intent, 0); if (resInfo != null && resInfo.size() > 0) { for (ResolveInfo resolveInfo : resInfo) { String packageName = resolveInfo.activityInfo.packageName; if (!packageName.equals(App.getInstance().getPackageName())) // Remove ourselves { mTargets.add(resolveInfo); } } } } @Override public Dialog onCreateDialog(Bundle savedInstanceState) { final Dialog dialog = super.onCreateDialog(savedInstanceState); dialog.setOnShowListener(new DialogInterface.OnShowListener() { @Override public void onShow(DialogInterface dialogINterface) { dialog.getWindow().setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT)); dialog.getWindow().setLayout( mParentWidth - UIHelpers.dpToPx(0, getContext()), // Set margins here! ViewGroup.LayoutParams.MATCH_PARENT); } }); return dialog; } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View v = inflater.inflate(R.layout.share_chooser, container, false); setupView(v); return v; } private void setupView(View v) { mRecyclerView = (RecyclerView)v.findViewById(R.id.recycler_view_apps); // Figure out how manby columns that fit in the given parent width. Give them 100dp. int appWidth = UIHelpers.dpToPx(80, getContext()); final int nCols = (mParentWidth - /* padding */ UIHelpers.dpToPx(8, getContext())) / appWidth; GridLayoutManager glm = new GridLayoutManager(getContext(), nCols); glm.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() { @Override public int getSpanSize(int position) { if (mRecyclerView.getAdapter() != null) { if (mRecyclerView.getAdapter().getItemViewType(position) == 1) { return nCols; } return 1; } return 0; } }); mRecyclerView.setLayoutManager(glm); class VH extends RecyclerView.ViewHolder { public final ImageView icon; public final TextView label; public VH(View itemView) { super(itemView); icon = (ImageView) itemView.findViewById(R.id.ivShare); label = (TextView) itemView.findViewById(R.id.tvShare); } } mRecyclerView.setAdapter(new RecyclerView.Adapter<VH>() { private ArrayList<Object> mIntents; RecyclerView.Adapter init(List<ResolveInfo> targetedShareIntents) { mIntents = new ArrayList<>(); ArrayList<ResolveInfo> safe = new ArrayList<>(); ArrayList<ResolveInfo> unsafe = new ArrayList<>(); for (ResolveInfo ri : targetedShareIntents) { if (gSafeApps.contains(ri.activityInfo.packageName)) { safe.add(ri); } else { unsafe.add(ri); } } if (safe.size() > 0) { mIntents.add(getString(R.string.chooser_share_safe)); mIntents.addAll(safe); } if (unsafe.size() > 0) { mIntents.add(getString(R.string.chooser_share_unsafe)); mIntents.addAll(unsafe); } return this; } @Override public int getItemViewType(int position) { if (mIntents.get(position) instanceof String) return 1; return 0; } @Override public VH onCreateViewHolder(ViewGroup parent, int viewType) { View view = LayoutInflater.from(parent.getContext()).inflate((viewType == 1) ? R.layout.share_header_item : R.layout.share_item, parent, false); return new VH(view); } @Override public void onBindViewHolder(VH holder, int position) { if (getItemViewType(position) == 1) { holder.label.setText((CharSequence)mIntents.get(position)); return; } final ResolveInfo ri = (ResolveInfo) mIntents.get(position); holder.icon.setImageDrawable(ri.loadIcon(App.getInstance().getPackageManager())); holder.label.setText(ri.loadLabel(App.getInstance().getPackageManager())); holder.itemView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { if (mListener != null) mListener.onItemSelected(ri); dismiss(); } }); } @Override public int getItemCount() { return mIntents.size(); } }.init(mTargets)); } public static void createChooser(CoordinatorLayout rootView, final AppCompatActivity parent, final int requestCode, final Uri uri) { ShareChooserDialog d = new ShareChooserDialog(); d.setListener(new ShareChooserDialog.ShareChooserDialogListener() { @Override public void onItemSelected(final ResolveInfo ri) { if (gSafeApps.contains(ri.activityInfo.packageName) || App.getInstance().getSettings().skipUnsafeShareInfo()) { startActivityForResolveInfo(ri); } else { // Show info dialog final AlertDialog.Builder alert = new AlertDialog.Builder(parent).setTitle(R.string.unsafe_share_title).setMessage(R.string.unsafe_share); final View view = LayoutInflater.from(parent).inflate(R.layout.dialog_unsafe_share, null, false); alert.setView(view); alert.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialogInterface, int i) { CheckBox cb = (CheckBox) view.findViewById(R.id.cbDontShowAgain); if (cb.isChecked()) { App.getInstance().getSettings().setSkipUnsafeShareInfo(true); } startActivityForResolveInfo(ri); } }); alert.show(); } } private void startActivityForResolveInfo(ResolveInfo ri) { Intent intent = new Intent(); intent.setAction(Intent.ACTION_SEND); intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); intent.putExtra(Intent.EXTRA_STREAM, uri); intent.setType("image/jpeg"); ComponentName name = new ComponentName(ri.activityInfo.applicationInfo.packageName, ri.activityInfo.name); intent.setComponent(name); parent.startActivityForResult(intent, requestCode); } }); Bundle args = new Bundle(); args.putString("uri", uri.toString()); args.putInt("width", rootView.getWidth()); d.setArguments(args); d.show(parent.getSupportFragmentManager(), "Share"); } }