CultureQuestORG/SDP2023

View on GitHub
app/src/main/java/ch/epfl/culturequest/storage/LocalStorage.java

Summary

Maintainability
A
0 mins
Test Coverage
A
96%
package ch.epfl.culturequest.storage;

import static android.graphics.Bitmap.CompressFormat.JPEG;
import static androidx.test.core.app.ApplicationProvider.getApplicationContext;

import android.content.ContentResolver;
import android.content.ContentValues;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.net.Uri;
import android.os.Build;
import android.provider.MediaStore;

import java.io.IOException;
import java.io.OutputStream;

public class LocalStorage {
    private final ContentResolver resolver;
    private final Uri contentUri;

    public Uri lastlyStoredImageUri;

    public LocalStorage(ContentResolver resolver) {
        this.resolver = resolver;

        // Gets the Uri where the image will be stored (here we use the primary external storage
        // to be able to share the images with other apps and to have Read/Write access)
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
            contentUri = MediaStore.Images.Media.getContentUri(MediaStore.VOLUME_EXTERNAL_PRIMARY);
        } else {
            contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
        }
    }

    /**
     * Stores the given bitmap image in the shared folder: "/sdcard/Pictures".
     * This folder was chosen because it allows to share the image with other apps.
     * It creates a new entry in the MediaStore and adds the "pending_" prefix to the image name
     * if this image still needs to be sent to Google Lens.
     *
     * @param bitmap          the bitmap image to store
     * @param isWifiAvailable indicates if wifi is available or not
     * @throws IOException if the image could not be stored
     */
    public void storeImageLocally(Bitmap bitmap, boolean isWifiAvailable) throws IOException {
        // Creates a new entry in the MediaStore
        final ContentValues values = new ContentValues();
        // Sets the image type : here jpeg (Android default)
        values.put(MediaStore.Images.Media.MIME_TYPE, "image/jpeg");
        // The name if this image still needs to be processed or not (useful to highlight that this
        // image still needs to be sent to Google Lens when wifi is not available).
        if (isWifiAvailable) {
            values.put(MediaStore.Images.Media.DISPLAY_NAME, System.currentTimeMillis() + ".jpeg");
        } else {
            values.put(MediaStore.Images.Media.DISPLAY_NAME, "pending_" + System.currentTimeMillis()
                    + ".jpeg");
        }

        // Inserts the new entry in the MediaStore and returns its uri
        Uri uri = resolver.insert(contentUri, values);
        lastlyStoredImageUri = uri;
        // Opens the output stream to store the image
        try {
            writeImageToStream(uri, bitmap);
        } catch (IOException e) {
            // If an error occurs, deletes the unsuccessful entry in the MediaStore.
            if (uri != null) {
                resolver.delete(uri, null, null);
            }
            throw e;
        }
    }

    /**
     * Writes the given bitmap image to the given uri.
     *
     * @param uri    the uri where the image will be stored
     * @param bitmap the bitmap image to store
     * @throws IOException if the image could not be stored
     */
    private void writeImageToStream(Uri uri, Bitmap bitmap) throws IOException {
        // Opens the output stream to store the image
        try (final OutputStream stream = resolver.openOutputStream(uri)) {
            // Compresses the bitmap image and writes it to the output stream
            if (bitmap == null || !bitmap.compress(JPEG, 95, stream)) {
                throw new IOException("Failed to save image.");
            }
        }
    }

    /**
     * Counts the number of selected images in the shared storage.
     *
     * @param selection     the selection clause
     * @param selectionArgs the selection arguments
     * @return the number of selected images in the shared storage
     **/
    public int countSelectedImagesInLocalStorage(String selection, String[] selectionArgs) {
        // Counts the number of ready images (not pending) in the shared storage
        try (Cursor cursor = getApplicationContext().getContentResolver().query(
                contentUri,
                null,
                selection,
                selectionArgs,
                null)) {
            return cursor.getCount();
        }
    }

    /**
     * Deletes all the images in the shared storage.
     **/
    public void clearLocalStorage() {
        ContentResolver contentResolver = getApplicationContext().getContentResolver();
        contentResolver.delete(contentUri, null, null);
    }

}