diff --git a/twidere/src/main/java/org/mariotaku/twidere/activity/MediaViewerActivity.java b/twidere/src/main/java/org/mariotaku/twidere/activity/MediaViewerActivity.java index 79c55cfb0..9fa63e5f4 100644 --- a/twidere/src/main/java/org/mariotaku/twidere/activity/MediaViewerActivity.java +++ b/twidere/src/main/java/org/mariotaku/twidere/activity/MediaViewerActivity.java @@ -23,7 +23,6 @@ import android.content.Context; import android.content.Intent; import android.media.MediaPlayer; import android.net.Uri; -import android.os.AsyncTask; import android.os.Build; import android.os.Bundle; import android.os.Handler; @@ -103,6 +102,7 @@ public final class MediaViewerActivity extends BaseActivity implements Constants private static final int REQUEST_SHARE_MEDIA = 201; private static final int REQUEST_PERMISSION_SAVE_MEDIA = 202; + private static final int REQUEST_PERMISSION_SHARE_MEDIA = 203; @Inject FileCache mFileCache; @@ -110,8 +110,8 @@ public final class MediaViewerActivity extends BaseActivity implements Constants MediaDownloader mMediaDownloader; private ParcelableMedia[] mMedia; - private SaveFileTask mSaveFileTask; private int mSaveToStoragePosition = -1; + private int mShareMediaPosition = -1; private Helper mHelper; @@ -193,15 +193,7 @@ public final class MediaViewerActivity extends BaseActivity implements Constants } case R.id.share: { if (object instanceof CacheDownloadMediaViewerFragment) { - if (object instanceof VideoPageFragment) { - shareMedia(CacheProvider.Type.VIDEO); - } else if (object instanceof ImagePageFragment) { - shareMedia(CacheProvider.Type.IMAGE); - } else if (object instanceof GifPageFragment) { - shareMedia(CacheProvider.Type.IMAGE); - } else { - throw new UnsupportedOperationException("Unsupported fragment " + object); - } + requestAndShareMedia(currentItem); } else { final ParcelableMedia media = getMedia()[currentItem]; final Intent intent = new Intent(Intent.ACTION_SEND); @@ -243,6 +235,13 @@ public final class MediaViewerActivity extends BaseActivity implements Constants } return; } + case REQUEST_PERMISSION_SHARE_MEDIA: { + if (!PermissionUtils.hasPermission(permissions, grantResults, Manifest.permission.WRITE_EXTERNAL_STORAGE)) { + Toast.makeText(this, R.string.share_media_no_storage_permission_message, Toast.LENGTH_LONG).show(); + } + shareMedia(); + return; + } } super.onRequestPermissionsResult(requestCode, permissions, grantResults); } @@ -386,10 +385,43 @@ public final class MediaViewerActivity extends BaseActivity implements Constants intent.putExtra(Intent.EXTRA_TEXT, IntentUtils.getStatusShareText(this, status)); } - protected void shareMedia(@CacheProvider.Type final String type) { + protected void requestAndSaveToStorage(int position) { + mSaveToStoragePosition = position; + if (PermissionUtils.hasPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE)) { + saveToStorage(); + } else { + final String[] permissions; + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { + permissions = new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE, + Manifest.permission.READ_EXTERNAL_STORAGE}; + } else { + permissions = new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}; + } + ActivityCompat.requestPermissions(this, permissions, REQUEST_PERMISSION_SAVE_MEDIA); + } + } + + protected void requestAndShareMedia(int position) { + mShareMediaPosition = position; + if (PermissionUtils.hasPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE)) { + shareMedia(); + } else { + final String[] permissions; + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { + permissions = new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE, + Manifest.permission.READ_EXTERNAL_STORAGE}; + } else { + permissions = new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}; + } + ActivityCompat.requestPermissions(this, permissions, REQUEST_PERMISSION_SHARE_MEDIA); + } + } + + protected void shareMedia() { + if (mShareMediaPosition == -1) return; final ViewPager viewPager = findViewPager(); final PagerAdapter adapter = viewPager.getAdapter(); - final Object object = adapter.instantiateItem(viewPager, viewPager.getCurrentItem()); + final Object object = adapter.instantiateItem(viewPager, mShareMediaPosition); if (!(object instanceof CacheDownloadMediaViewerFragment)) return; CacheDownloadLoader.Result result = ((CacheDownloadMediaViewerFragment) object).getDownloadResult(); if (result == null || result.cacheUri == null) { @@ -397,6 +429,17 @@ public final class MediaViewerActivity extends BaseActivity implements Constants return; } final File destination = ShareProvider.getFilesDir(this); + if (destination == null) return; + String type; + if (object instanceof VideoPageFragment) { + type = CacheProvider.Type.VIDEO; + } else if (object instanceof ImagePageFragment) { + type = CacheProvider.Type.IMAGE; + } else if (object instanceof GifPageFragment) { + type = CacheProvider.Type.IMAGE; + } else { + throw new UnsupportedOperationException("Unsupported fragment " + object); + } final SaveFileTask task = new SaveFileTask(this, result.cacheUri, destination, new CacheProvider.CacheFileTypeCallback(this, type)) { private static final String PROGRESS_FRAGMENT_TAG = "progress"; @@ -455,24 +498,7 @@ public final class MediaViewerActivity extends BaseActivity implements Constants Toast.makeText(activity, R.string.error_occurred, Toast.LENGTH_SHORT).show(); } }; - task.execute(); - } - - - protected void requestAndSaveToStorage(int position) { - mSaveToStoragePosition = position; - if (PermissionUtils.hasPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE)) { - saveToStorage(); - } else { - final String[] permissions; - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { - permissions = new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE, - Manifest.permission.READ_EXTERNAL_STORAGE}; - } else { - permissions = new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}; - } - ActivityCompat.requestPermissions(this, permissions, REQUEST_PERMISSION_SAVE_MEDIA); - } + AsyncTaskUtils.executeTask(task); } protected void saveToStorage() { @@ -484,20 +510,20 @@ public final class MediaViewerActivity extends BaseActivity implements Constants final CacheDownloadMediaViewerFragment f = (CacheDownloadMediaViewerFragment) object; final CacheDownloadLoader.Result result = f.getDownloadResult(); if (result == null) return; - if (mSaveFileTask != null && mSaveFileTask.getStatus() == AsyncTask.Status.RUNNING) return; final Uri cacheUri = result.cacheUri; final boolean hasMedia = cacheUri != null; if (!hasMedia) return; + SaveFileTask task; if (f instanceof ImagePageFragment) { - mSaveFileTask = SaveMediaToGalleryTask.create(this, cacheUri, CacheProvider.Type.IMAGE); + task = SaveMediaToGalleryTask.create(this, cacheUri, CacheProvider.Type.IMAGE); } else if (f instanceof VideoPageFragment) { - mSaveFileTask = SaveMediaToGalleryTask.create(this, cacheUri, CacheProvider.Type.VIDEO); + task = SaveMediaToGalleryTask.create(this, cacheUri, CacheProvider.Type.VIDEO); } else if (f instanceof GifPageFragment) { - mSaveFileTask = SaveMediaToGalleryTask.create(this, cacheUri, CacheProvider.Type.IMAGE); + task = SaveMediaToGalleryTask.create(this, cacheUri, CacheProvider.Type.IMAGE); } else { throw new UnsupportedOperationException(); } - AsyncTaskUtils.executeTask(mSaveFileTask); + AsyncTaskUtils.executeTask(task); } public static class ImagePageFragment extends SubsampleImageViewerFragment { diff --git a/twidere/src/main/java/org/mariotaku/twidere/provider/ShareProvider.java b/twidere/src/main/java/org/mariotaku/twidere/provider/ShareProvider.java index 0fea6b77f..00179f957 100644 --- a/twidere/src/main/java/org/mariotaku/twidere/provider/ShareProvider.java +++ b/twidere/src/main/java/org/mariotaku/twidere/provider/ShareProvider.java @@ -1,10 +1,11 @@ package org.mariotaku.twidere.provider; -import android.annotation.SuppressLint; +import android.Manifest; import android.content.ContentProvider; import android.content.ContentResolver; import android.content.ContentValues; import android.content.Context; +import android.content.pm.PackageManager; import android.database.Cursor; import android.database.MatrixCursor; import android.net.Uri; @@ -12,6 +13,7 @@ import android.os.ParcelFileDescriptor; import android.provider.MediaStore.MediaColumns; import android.support.annotation.NonNull; import android.support.annotation.Nullable; +import android.support.v4.content.ContextCompat; import org.apache.commons.lang3.ArrayUtils; @@ -31,16 +33,12 @@ public class ShareProvider extends ContentProvider { return true; } - @SuppressLint("SetWorldReadable") @Nullable @Override public Cursor query(@NonNull Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) { try { final File file = getFile(uri); if (file == null) return null; - // Make world-readable intentionally since it will be deleted shortly - //noinspection ResultOfMethodCallIgnored - file.setReadable(true, false); if (projection == null) { projection = COLUMNS; } @@ -100,9 +98,16 @@ public class ShareProvider extends ContentProvider { @Nullable public static File getFilesDir(Context context) { - final File externalCacheDir = context.getExternalCacheDir(); - if (externalCacheDir == null) return null; - return new File(externalCacheDir, "shared_files"); + File cacheDir = context.getCacheDir(); + if (ContextCompat.checkSelfPermission(context, Manifest.permission.WRITE_EXTERNAL_STORAGE) == + PackageManager.PERMISSION_GRANTED) { + final File externalCacheDir = context.getExternalCacheDir(); + if (externalCacheDir != null && externalCacheDir.canWrite()) { + cacheDir = externalCacheDir; + } + } + if (cacheDir == null) return null; + return new File(cacheDir, "shared_files"); } @Nullable diff --git a/twidere/src/main/res/values/strings.xml b/twidere/src/main/res/values/strings.xml index ee089242f..4474b287e 100644 --- a/twidere/src/main/res/values/strings.xml +++ b/twidere/src/main/res/values/strings.xml @@ -724,6 +724,7 @@ Notifications will be grouped Notifications will be displayed separately Storage permission is needed to save media. + Some application requires storage permission to share media. Storage permission is needed to select file. %s mentioned you Can\'t load all replies. <a href=\"#dialog\";>Why?</a>