chromium/chrome/browser/download/android/java/src/org/chromium/chrome/browser/download/MediaStoreHelper.java

// Copyright 2019 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

package org.chromium.chrome.browser.download;

import android.os.Build;
import android.provider.MediaStore;
import android.text.TextUtils;

import androidx.annotation.NonNull;

import org.chromium.base.ContextUtils;
import org.chromium.base.Log;
import org.chromium.base.task.AsyncTask;

import java.io.File;
import java.io.FileNotFoundException;

/** Includes helper methods to interact with Android media store. */
public class MediaStoreHelper {
    private static final String TAG = "MediaStoreHelper";

    private MediaStoreHelper() {}

    /**
     * Adds an image file on external SD card to media store to show in the Android gallery app.
     * The images on primary storage will automatically scanned by media store. On external SD card,
     * usually .nomedia file will block the media store scan request.
     * The media store will decode, compress the image and maintain a copy on disk.
     * Does nothing if the file is not an image or the file is not on external SD card.
     * @param filePath The file path of the image file.
     * @param mimeType The mime type of the image file.
     */
    public static void addImageToGalleryOnSDCard(String filePath, String mimeType) {
        // TODO(xingliu): Support Android Q when we have available device with SD card slot.
        if (TextUtils.isEmpty(filePath)
                || mimeType == null
                || !mimeType.startsWith("image/")
                || Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
            return;
        }

        DownloadDirectoryProvider.getInstance()
                .getAllDirectoriesOptions(
                        (dirs) -> {
                            for (DirectoryOption dir : dirs) {
                                // Scan the media file if it is on SD card.
                                if (dir.type
                                                == DirectoryOption.DownloadLocationDirectoryType
                                                        .ADDITIONAL
                                        && filePath.contains(dir.location)) {
                                    addImageOnBlockingThread(filePath);
                                    return;
                                }
                            }
                        });
    }

    /**
     * Adds the image to media store on a blocking thread.
     * @param filePath The file path of the image file.
     */
    private static void addImageOnBlockingThread(@NonNull String filePath) {
        new AsyncTask<Void>() {
            @Override
            protected Void doInBackground() {
                try {
                    // The media store will decode the image to bitmap, compress, and maintain a
                    // copy on disk.
                    File file = new File(filePath);
                    MediaStore.Images.Media.insertImage(
                            ContextUtils.getApplicationContext().getContentResolver(),
                            filePath,
                            file.getName(),
                            null);
                } catch (FileNotFoundException e) {
                    Log.e(TAG, "Cannot find image file to add to gallery.", e);
                }
                return null;
            }

            @Override
            protected void onPostExecute(Void aVoid) {}
        }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
    }
}