fr.s13d.photobackup.media.PBMediaStore.java Source code

Java tutorial

Introduction

Here is the source code for fr.s13d.photobackup.media.PBMediaStore.java

Source

/**
 * Copyright (C) 2013-2016 Stphane Pchard.
 *
 * This file is part of PhotoBackup.
 *
 * PhotoBackup is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * PhotoBackup is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 */
package fr.s13d.photobackup.media;

import android.content.ContentResolver;
import android.content.Context;
import android.content.SharedPreferences;
import android.database.Cursor;
import android.database.MergeCursor;
import android.net.Uri;
import android.preference.PreferenceManager;
import android.provider.MediaStore;
import android.support.v4.util.ArrayMap;
import android.text.TextUtils;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;

import fr.s13d.photobackup.Log;
import fr.s13d.photobackup.PBApplication;
import fr.s13d.photobackup.PBConstants;
import fr.s13d.photobackup.interfaces.PBMediaStoreInterface;

import static android.preference.PreferenceManager.getDefaultSharedPreferences;

public class PBMediaStore {

    private static final String LOG_TAG = "PBMediaStore";
    private static List<PBMedia> mediaList;
    private static PBSyncMediaStoreTask syncTask;
    private static final SharedPreferences picturesPreferences = PBApplication.getApp()
            .getSharedPreferences(PBApplication.PB_MEDIAS_SHARED_PREFS, Context.MODE_PRIVATE);
    private final List<PBMediaStoreInterface> interfaces = new ArrayList<>();
    private static final Uri imagesUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
    private static final Uri videosUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
    private static final String DATE_ADDED_DESC = "date_added DESC";

    ////////////////
    // Life-cycle //
    ////////////////
    public void addInterface(PBMediaStoreInterface storeInterface) {
        interfaces.add(storeInterface);
    }

    public void removeInterface(PBMediaStoreInterface storeInterface) {
        interfaces.remove(storeInterface);
    }

    public void close() {
        if (syncTask != null) {
            syncTask.cancel(true);
        }
        setMediaListToNull();
    }

    /////////////
    // Queries //
    /////////////
    public PBMedia createMediaForLatestInStore(boolean backupVideos) {
        final ContentResolver cr = PBApplication.getApp().getContentResolver();
        final Cursor cursor = cr.query(backupVideos ? videosUri : imagesUri, null, null, null, DATE_ADDED_DESC);
        if (cursor == null || !cursor.moveToFirst()) {
            Log.d(LOG_TAG, "Media cursor is null or empty.");
            return null;
        }

        final int bucketId = cursor.getColumnIndex(MediaStore.Images.Media.BUCKET_ID);
        if (!backupVideos && !isBucketSelected(cursor.getString(bucketId))) {
            Log.d(LOG_TAG, "Media not in selected buckets.");
            return null;
        }

        final PBMedia media = new PBMedia(cursor);
        try {
            String stateString = picturesPreferences.getString(String.valueOf(media.getId()),
                    PBMedia.PBMediaState.WAITING.name());
            media.setState(PBMedia.PBMediaState.valueOf(stateString));
        } catch (Exception e) {
            Log.e(LOG_TAG, e);
        }
        closeCursor(cursor);

        return media;
    }

    Cursor getAllMediasCursor() {
        String where = null;
        final SharedPreferences prefs = getDefaultSharedPreferences(PBApplication.getApp());
        final Set<String> bucketIds = prefs.getStringSet(PBConstants.PREF_PICTURE_FOLDER_LIST, null);
        if (bucketIds != null && !bucketIds.isEmpty()) {
            final String bucketString = TextUtils.join(", ", bucketIds);
            where = "bucket_id in (" + bucketString + ")";
        }

        final boolean backupVideos = prefs.getBoolean(PBConstants.PREF_MEDIA_BACKUP_VIDEO, false);
        final String[] projection = new String[] { "_id", "_data", "date_added" };
        final ContentResolver cr = PBApplication.getApp().getContentResolver();
        final Cursor[] cursors = new Cursor[backupVideos ? 2 : 1];
        cursors[0] = cr.query(imagesUri, projection, where, null, DATE_ADDED_DESC);
        if (backupVideos) {
            cursors[1] = cr.query(videosUri, projection, where, null, DATE_ADDED_DESC);
        }
        if (cursors[0] == null) {
            Log.d(LOG_TAG, "Media cursor is null.");
            return null;
        }

        return new MergeCursor(cursors);
    }

    private boolean isBucketSelected(final String requestedBucketId) {
        Log.d(LOG_TAG, "Checking if bucket " + requestedBucketId + " is selected by user.");
        final SharedPreferences prefs = getDefaultSharedPreferences(PBApplication.getApp());
        final Set<String> bucketSet = prefs.getStringSet(PBConstants.PREF_PICTURE_FOLDER_LIST, null);
        return bucketSet != null && bucketSet.contains(requestedBucketId);
    }

    private void getBucketData(final ArrayMap<String, String> bucketNamesList, final String buckedId,
            final String buckedName) {

        // We want to group the images by bucket names. We abuse the
        // "WHERE" parameter to insert a "GROUP BY" clause into the SQL statement.
        // The template for "WHERE" parameter is like:
        //    SELECT ... FROM ... WHERE (%s)
        // and we make it look like:
        //    SELECT ... FROM ... WHERE (1) GROUP BY (2)
        // The "(1)" means true. The "(2)" means the second columns specified in projection.
        // Note that because there is a ")" in the template, we use "(2" to match it.
        final String[] projection = { buckedId, buckedName, "count(*) as media_count" };
        final String groupBy = "1) GROUP BY (2";
        final Cursor cursor = PBApplication.getApp().getContentResolver().query(imagesUri, projection, groupBy,
                null, "media_count desc");

        if (cursor != null && cursor.moveToFirst()) {
            String name;
            String id;
            String count;
            final int bucketIdColumn = cursor.getColumnIndex(buckedId);
            final int bucketNameColumn = cursor.getColumnIndex(buckedName);
            final int bucketCountColumn = cursor.getColumnIndex("media_count");
            do {
                id = cursor.getString(bucketIdColumn);
                name = cursor.getString(bucketNameColumn);
                count = cursor.getString(bucketCountColumn);
                bucketNamesList.put(id, name + " (" + count + ")");
            } while (cursor.moveToNext());
        }
        closeCursor(cursor);

        Log.d(LOG_TAG, bucketNamesList.toString());
    }

    /**
     * @return list of device media bucket names
     */
    public ArrayMap<String, String> getBucketData() {
        final ArrayMap<String, String> bucketNames = new ArrayMap<>();
        getBucketData(bucketNames, MediaStore.Images.ImageColumns.BUCKET_ID,
                MediaStore.Images.ImageColumns.BUCKET_DISPLAY_NAME);

        final SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(PBApplication.getApp());
        final boolean backupVideos = sp.getBoolean(PBConstants.PREF_MEDIA_BACKUP_VIDEO, false);
        if (backupVideos) {
            getBucketData(bucketNames, MediaStore.Video.VideoColumns.BUCKET_ID,
                    MediaStore.Video.VideoColumns.BUCKET_DISPLAY_NAME);
        }
        return bucketNames;
    }

    private void closeCursor(Cursor cursor) {
        if (cursor != null && !cursor.isClosed()) {
            cursor.close();
        }
    }

    /////////////////////////////////
    // Synchronize the media store //
    /////////////////////////////////
    public void sync() {
        if (syncTask != null) {
            syncTask.cancel(true);
        }

        setSyncTask(new PBSyncMediaStoreTask());
        syncTask.execute();
        Log.i(LOG_TAG, "Start SyncMediaStoreTask");
    }

    void onPostSync() {
        for (PBMediaStoreInterface storeInterface : interfaces) {
            storeInterface.onSyncMediaStoreTaskPostExecute();
        }
        Log.i(LOG_TAG, "Stop PBSyncMediaStoreTask");
    }

    //////////////////
    // Lazy loaders //
    //////////////////
    public List<PBMedia> getMediaList() {
        if (mediaList == null) {
            setMediaList(new ArrayList<PBMedia>());
        }
        return mediaList;
    }

    ////////////////////
    // Static setters //
    ////////////////////
    private static void setMediaListToNull() {
        mediaList = null;
    }

    private static void setSyncTask(PBSyncMediaStoreTask syncTask) {
        PBMediaStore.syncTask = syncTask;
    }

    private static void setMediaList(List<PBMedia> mediaList) {
        PBMediaStore.mediaList = mediaList;
    }
}