diff --git a/RELEASE-NOTES.txt b/RELEASE-NOTES.txt index 8f2cc3b58..ce099d30d 100644 --- a/RELEASE-NOTES.txt +++ b/RELEASE-NOTES.txt @@ -1,5 +1,6 @@ 2.39 ----- +* Fixed the note share sheet missing installed apps (e.g. Gmail, WhatsApp) by launching the system share sheet [#1578](https://github.com/Automattic/simplenote-android/issues/1578) 2.38 ----- diff --git a/Simplenote/src/main/java/com/automattic/simplenote/NoteEditorFragment.java b/Simplenote/src/main/java/com/automattic/simplenote/NoteEditorFragment.java index d9afb3e7e..a3b45d2e5 100644 --- a/Simplenote/src/main/java/com/automattic/simplenote/NoteEditorFragment.java +++ b/Simplenote/src/main/java/com/automattic/simplenote/NoteEditorFragment.java @@ -1388,6 +1388,13 @@ public void onShareDismissed() { } + @Override + public void onShareOtherClicked() { + if (mNote != null) { + showShare(mNote.getContent()); + } + } + /** * History bottom sheet listeners */ diff --git a/Simplenote/src/main/java/com/automattic/simplenote/ShareBottomSheetDialog.java b/Simplenote/src/main/java/com/automattic/simplenote/ShareBottomSheetDialog.java index b7628c86f..5bd8acd1c 100644 --- a/Simplenote/src/main/java/com/automattic/simplenote/ShareBottomSheetDialog.java +++ b/Simplenote/src/main/java/com/automattic/simplenote/ShareBottomSheetDialog.java @@ -1,16 +1,10 @@ package com.automattic.simplenote; -import android.app.Activity; -import android.content.ComponentName; import android.content.DialogInterface; -import android.content.Intent; -import android.content.pm.ResolveInfo; -import android.graphics.drawable.Drawable; import android.os.Bundle; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; -import android.widget.FrameLayout; import android.widget.TextView; import android.widget.Toast; @@ -18,28 +12,14 @@ import androidx.annotation.Nullable; import androidx.fragment.app.Fragment; import androidx.fragment.app.FragmentManager; -import androidx.recyclerview.widget.GridLayoutManager; -import androidx.recyclerview.widget.RecyclerView; import com.automattic.simplenote.models.Note; -import com.automattic.simplenote.utils.IconResizer; import com.automattic.simplenote.utils.NetworkUtils; -import com.automattic.simplenote.utils.ShareButtonAdapter; -import com.google.android.material.bottomsheet.BottomSheetBehavior; -import com.google.android.material.bottomsheet.BottomSheetDialog; - -import java.util.ArrayList; -import java.util.List; public class ShareBottomSheetDialog extends BottomSheetDialogBase { public static final String TAG = ShareBottomSheetDialog.class.getSimpleName(); - private static final int SHARE_SHEET_COLUMN_COUNT = 3; - private Fragment mFragment; - private Intent mShareIntent; - private List mShareButtons; - private RecyclerView mRecyclerView; private ShareSheetListener mListener; private TextView mPublishButton; private TextView mUnpublishButton; @@ -63,6 +43,7 @@ public void onDismiss(DialogInterface dialog) { getDialog().setContentView(R.layout.bottom_sheet_share); TextView mCollaborateButton = getDialog().findViewById(R.id.share_collaborate_button); + TextView mShareOtherButton = getDialog().findViewById(R.id.share_other_button); mPublishButton = getDialog().findViewById(R.id.share_publish_button); mUnpublishButton = getDialog().findViewById(R.id.share_unpublish_button); mWordPressButton = getDialog().findViewById(R.id.share_wp_post); @@ -105,30 +86,11 @@ public void onClick(View v) { } }); - mRecyclerView = getDialog().findViewById(R.id.share_button_recycler_view); - mRecyclerView.setHasFixedSize(true); - mRecyclerView.setLayoutManager(new GridLayoutManager(mFragment.requireActivity(), SHARE_SHEET_COLUMN_COUNT)); - - mShareIntent = new Intent(Intent.ACTION_SEND); - mShareIntent.setType("text/plain"); - - mShareButtons = getShareButtons(mFragment.requireActivity(), mShareIntent); - } - - if (getDialog() != null) { - // Set peek height to half height of view (i.e. set STATE_HALF_EXPANDED) to show some of - // sharing options when bottom sheet is shown. - getDialog().setOnShowListener(new DialogInterface.OnShowListener() { + mShareOtherButton.setOnClickListener(new View.OnClickListener() { @Override - public void onShow(DialogInterface dialogInterface) { - BottomSheetDialog bottomSheetDialog = (BottomSheetDialog) dialogInterface; - FrameLayout bottomSheet = bottomSheetDialog.findViewById(com.google.android.material.R.id.design_bottom_sheet); - - if (bottomSheet != null) { - BottomSheetBehavior behavior = BottomSheetBehavior.from(bottomSheet); - behavior.setState(BottomSheetBehavior.STATE_HALF_EXPANDED); - behavior.setSkipCollapsed(true); - } + public void onClick(View v) { + mListener.onShareOtherClicked(); + dismiss(); } }); } @@ -147,41 +109,13 @@ public void show(FragmentManager manager, Note note) { mPublishButton.setVisibility(View.VISIBLE); mUnpublishButton.setVisibility(View.GONE); } - - mShareIntent.putExtra(Intent.EXTRA_TEXT, note.getContent()); - - final ShareButtonAdapter.ItemListener shareListener = new ShareButtonAdapter.ItemListener() { - @Override - public void onItemClick(ShareButtonAdapter.ShareButtonItem item) { - mShareIntent.setComponent(new ComponentName(item.getPackageName(), item.getActivityName())); - mFragment.requireActivity().startActivity(Intent.createChooser(mShareIntent, mFragment.getString(R.string.share))); - dismiss(); - } - }; - - mRecyclerView.setAdapter(new ShareButtonAdapter(mShareButtons, shareListener)); } } - @NonNull - private List getShareButtons(Activity activity, Intent intent) { - List shareButtons = new ArrayList<>(); - final List matches = activity.getPackageManager().queryIntentActivities(intent, 0); - IconResizer iconResizer = new IconResizer(requireContext()); - - for (ResolveInfo match : matches) { - final Drawable icon = iconResizer.createIconThumbnail(match.loadIcon(activity.getPackageManager())); - final CharSequence label = match.loadLabel(activity.getPackageManager()); - shareButtons.add(new ShareButtonAdapter.ShareButtonItem(icon, label, - match.activityInfo.packageName, match.activityInfo.name)); - } - - return shareButtons; - } - public interface ShareSheetListener { void onShareCollaborateClicked(); void onShareDismissed(); + void onShareOtherClicked(); void onSharePublishClicked(); void onShareUnpublishClicked(); void onWordPressPostClicked(); diff --git a/Simplenote/src/main/java/com/automattic/simplenote/utils/IconResizer.java b/Simplenote/src/main/java/com/automattic/simplenote/utils/IconResizer.java deleted file mode 100644 index c001356d8..000000000 --- a/Simplenote/src/main/java/com/automattic/simplenote/utils/IconResizer.java +++ /dev/null @@ -1,102 +0,0 @@ -package com.automattic.simplenote.utils; - -import android.content.Context; -import android.content.res.Resources; -import android.graphics.Bitmap; -import android.graphics.Canvas; -import android.graphics.Paint; -import android.graphics.PaintFlagsDrawFilter; -import android.graphics.PixelFormat; -import android.graphics.Rect; -import android.graphics.drawable.BitmapDrawable; -import android.graphics.drawable.Drawable; -import android.graphics.drawable.PaintDrawable; - -import com.automattic.simplenote.R; - -/** - * Utility class to resize icons to match default icon size. - */ -public class IconResizer { - - // Code is borrowed from com.android.launcher.Utilities. - private int mIconWidth = -1; - private int mIconHeight = -1; - private final Rect mOldBounds = new Rect(); - private Canvas mCanvas = new Canvas(); - private Context context; - - public IconResizer(Context context) { - this.context = context; - mCanvas.setDrawFilter(new PaintFlagsDrawFilter(Paint.DITHER_FLAG, - Paint.FILTER_BITMAP_FLAG)); - - final Resources resources = context.getResources(); - mIconWidth = mIconHeight = (int) resources.getDimension(R.dimen.share_icon_size); - } - - /** - * Returns a Drawable representing the thumbnail of the specified Drawable. - * The size of the thumbnail is defined by the dimension - * android.R.dimen.launcher_application_icon_size. - *

- * This method is not thread-safe and should be invoked on the UI thread only. - * - * @param icon The icon to get a thumbnail of. - * @return A thumbnail for the specified icon or the icon itself if the - * thumbnail could not be created. - */ - public Drawable createIconThumbnail(Drawable icon) { - int width = mIconWidth; - int height = mIconHeight; - final int iconWidth = icon.getIntrinsicWidth(); - final int iconHeight = icon.getIntrinsicHeight(); - if (icon instanceof PaintDrawable) { - PaintDrawable painter = (PaintDrawable) icon; - painter.setIntrinsicWidth(width); - painter.setIntrinsicHeight(height); - } - if (width > 0 && height > 0) { - if (width < iconWidth || height < iconHeight) { - final float ratio = (float) iconWidth / iconHeight; - if (iconWidth > iconHeight) { - height = (int) (width / ratio); - } else if (iconHeight > iconWidth) { - width = (int) (height * ratio); - } - final Bitmap.Config c = icon.getOpacity() != PixelFormat.OPAQUE ? - Bitmap.Config.ARGB_8888 : Bitmap.Config.RGB_565; - final Bitmap thumb = Bitmap.createBitmap(mIconWidth, mIconHeight, c); - final Canvas canvas = mCanvas; - canvas.setBitmap(thumb); - // Copy the old bounds to restore them later - // If we were to do oldBounds = icon.getBounds(), - // the call to setBounds() that follows would - // change the same instance and we would lose the - // old bounds - mOldBounds.set(icon.getBounds()); - final int x = (mIconWidth - width) / 2; - final int y = (mIconHeight - height) / 2; - icon.setBounds(x, y, x + width, y + height); - icon.draw(canvas); - icon.setBounds(mOldBounds); - icon = new BitmapDrawable(context.getResources(), thumb); - canvas.setBitmap(null); - } else if (iconWidth < width && iconHeight < height) { - final Bitmap.Config c = Bitmap.Config.ARGB_8888; - final Bitmap thumb = Bitmap.createBitmap(mIconWidth, mIconHeight, c); - final Canvas canvas = mCanvas; - canvas.setBitmap(thumb); - mOldBounds.set(icon.getBounds()); - final int x = (width - iconWidth) / 2; - final int y = (height - iconHeight) / 2; - icon.setBounds(x, y, x + iconWidth, y + iconHeight); - icon.draw(canvas); - icon.setBounds(mOldBounds); - icon = new BitmapDrawable(context.getResources(), thumb); - canvas.setBitmap(null); - } - } - return icon; - } -} diff --git a/Simplenote/src/main/java/com/automattic/simplenote/utils/ShareButtonAdapter.java b/Simplenote/src/main/java/com/automattic/simplenote/utils/ShareButtonAdapter.java deleted file mode 100644 index 559c0d2c4..000000000 --- a/Simplenote/src/main/java/com/automattic/simplenote/utils/ShareButtonAdapter.java +++ /dev/null @@ -1,104 +0,0 @@ -package com.automattic.simplenote.utils; - -import android.graphics.drawable.Drawable; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.TextView; - -import androidx.annotation.NonNull; -import androidx.recyclerview.widget.RecyclerView; - -import com.automattic.simplenote.R; - -import java.util.List; - -public class ShareButtonAdapter extends RecyclerView.Adapter { - - private List mItems; - private ItemListener mListener; - - public ShareButtonAdapter(List items, ItemListener listener) { - mItems = items; - mListener = listener; - } - - @NonNull - @Override - public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { - return new ViewHolder(LayoutInflater.from(parent.getContext()) - .inflate(R.layout.share_button_item, parent, false)); - } - - @Override - public void onBindViewHolder(@NonNull ViewHolder holder, int position) { - holder.setData(mItems.get(position)); - } - - @Override - public int getItemCount() { - return mItems.size(); - } - - public interface ItemListener { - void onItemClick(ShareButtonItem item); - } - - public static class ShareButtonItem { - - private Drawable mDrawableRes; - - private CharSequence mTitle; - private String mPackageName; - private String mActivityName; - - public ShareButtonItem(Drawable drawable, CharSequence title, - String packageName, String activityName) { - mDrawableRes = drawable; - mTitle = title; - mPackageName = packageName; - mActivityName = activityName; - } - - public Drawable getDrawable() { - return mDrawableRes; - } - - public CharSequence getTitle() { - return mTitle; - } - - public String getPackageName() { - return mPackageName; - } - - public String getActivityName() { - return mActivityName; - } - } - - public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener { - - public TextView button; - public ShareButtonItem item; - - public ViewHolder(View itemView) { - super(itemView); - itemView.setOnClickListener(this); - button = itemView.findViewById(R.id.share_button); - } - - public void setData(ShareButtonItem item) { - this.item = item; - button.setCompoundDrawablesWithIntrinsicBounds(null, item.getDrawable(), null, null); - button.setText(item.getTitle()); - } - - @Override - public void onClick(View v) { - if (mListener != null) { - mListener.onItemClick(item); - } - } - } -} \ No newline at end of file diff --git a/Simplenote/src/main/res/drawable/ic_share_other_48dp.xml b/Simplenote/src/main/res/drawable/ic_share_other_48dp.xml new file mode 100644 index 000000000..013a8d756 --- /dev/null +++ b/Simplenote/src/main/res/drawable/ic_share_other_48dp.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + diff --git a/Simplenote/src/main/res/layout/bottom_sheet_share.xml b/Simplenote/src/main/res/layout/bottom_sheet_share.xml index 6014df637..73ed2a50d 100644 --- a/Simplenote/src/main/res/layout/bottom_sheet_share.xml +++ b/Simplenote/src/main/res/layout/bottom_sheet_share.xml @@ -65,22 +65,19 @@ style="@style/Theme.Simplestyle.BottomSheetDialogText"> - - - - + + - - + diff --git a/Simplenote/src/main/res/layout/share_button_item.xml b/Simplenote/src/main/res/layout/share_button_item.xml deleted file mode 100644 index 313f9da86..000000000 --- a/Simplenote/src/main/res/layout/share_button_item.xml +++ /dev/null @@ -1,18 +0,0 @@ - - - - - - \ No newline at end of file