org.gateshipone.odyssey.artworkdatabase.BulkDownloadService.java Source code

Java tutorial

Introduction

Here is the source code for org.gateshipone.odyssey.artworkdatabase.BulkDownloadService.java

Source

/*
 * Copyright (C) 2016  Hendrik Borghorst & Frederik Luetkes
 *
 * This program 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.
 *
 * This program 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 org.gateshipone.odyssey.artworkdatabase;

import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.os.Bundle;
import android.os.IBinder;
import android.os.PowerManager;
import android.support.annotation.Nullable;
import android.support.v4.app.NotificationCompat;
import android.util.Log;

import com.android.volley.Request;
import com.android.volley.RequestQueue;

import org.gateshipone.odyssey.R;
import org.gateshipone.odyssey.artworkdatabase.network.LimitingRequestQueue;

public class BulkDownloadService extends Service implements ArtworkManager.BulkLoadingProgressCallback {
    private static final String TAG = BulkDownloadService.class.getSimpleName();

    private static final int NOTIFICATION_ID = 84;

    public static final String ACTION_CANCEL_BULKDOWNLOAD = "org.gateshipone.odyssey.bulkdownload.cancel";
    public static final String ACTION_START_BULKDOWNLOAD = "org.gateshipone.odyssey.bulkdownload.start";

    public static final String BUNDLE_KEY_ARTIST_PROVIDER = "org.gateshipone.odyssey.artist_provider";
    public static final String BUNDLE_KEY_ALBUM_PROVIDER = "org.gateshipone.odyssey.album_provider";
    public static final String BUNDLE_KEY_WIFI_ONLY = "org.gateshipone.odyssey.wifi_only";

    private NotificationManager mNotificationManager;
    private NotificationCompat.Builder mBuilder;

    private int mRemainingArtists;
    private int mRemainingAlbums;

    private int mSumImageDownloads;

    private ActionReceiver mBroadcastReceiver;

    private PowerManager.WakeLock mWakelock;

    private ConnectionStateReceiver mConnectionStateChangeReceiver;

    private boolean mWifiOnly;

    /**
     * Called when the service is created because it is requested by an activity
     */
    @Override
    public void onCreate() {
        super.onCreate();
        mNotificationManager = (NotificationManager) this.getSystemService(Context.NOTIFICATION_SERVICE);

        mConnectionStateChangeReceiver = new ConnectionStateReceiver();
        IntentFilter filter = new IntentFilter();
        filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
        registerReceiver(mConnectionStateChangeReceiver, filter);
    }

    @Override
    public void onDestroy() {
        unregisterReceiver(mBroadcastReceiver);
        unregisterReceiver(mConnectionStateChangeReceiver);
        Log.v(TAG, "Calling super.onDestroy()");
        super.onDestroy();
        Log.v(TAG, "Called super.onDestroy()");
    }

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        if (intent != null && intent.getAction().equals(ACTION_START_BULKDOWNLOAD)) {
            Log.v(TAG, "Starting bulk download in service with thread id: " + Thread.currentThread().getId());

            // reset counter
            mRemainingArtists = 0;
            mRemainingAlbums = 0;
            mSumImageDownloads = 0;

            String artistProvider = getString(R.string.pref_artwork_provider_artist_default);
            String albumProvider = getString(R.string.pref_artwork_provider_album_default);
            mWifiOnly = true;

            // read setting from extras
            Bundle extras = intent.getExtras();
            if (extras != null) {
                artistProvider = extras.getString(BUNDLE_KEY_ARTIST_PROVIDER,
                        getString(R.string.pref_artwork_provider_artist_default));
                albumProvider = extras.getString(BUNDLE_KEY_ALBUM_PROVIDER,
                        getString(R.string.pref_artwork_provider_album_default));
                mWifiOnly = intent.getBooleanExtra(BUNDLE_KEY_WIFI_ONLY, true);
            }

            if (artistProvider.equals(getString(R.string.pref_artwork_provider_none_key))
                    && albumProvider.equals(getString(R.string.pref_artwork_provider_none_key))) {
                return START_NOT_STICKY;
            }

            if (!isDownloadAllowed(this)) {
                return START_NOT_STICKY;
            }

            PowerManager powerManager = (PowerManager) getSystemService(POWER_SERVICE);
            mWakelock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "Odyssey_BulkDownloader");

            // FIXME do some timeout checking. e.g. 5 minutes no new image then cancel the process
            mWakelock.acquire();

            ArtworkManager artworkManager = ArtworkManager.getInstance(getApplicationContext());
            artworkManager.initialize(artistProvider, albumProvider, mWifiOnly);
            artworkManager.bulkLoadImages(this, getApplicationContext());
        }
        return START_STICKY;
    }

    private void runAsForeground() {
        if (mBroadcastReceiver == null) {
            mBroadcastReceiver = new ActionReceiver();

            // Create a filter to only handle certain actions
            IntentFilter intentFilter = new IntentFilter();

            intentFilter.addAction(ACTION_CANCEL_BULKDOWNLOAD);

            registerReceiver(mBroadcastReceiver, intentFilter);
        }

        mBuilder = new NotificationCompat.Builder(this)
                .setContentTitle(getString(R.string.downloader_notification_title))
                .setStyle(new NotificationCompat.BigTextStyle()
                        .bigText(getString(R.string.downloader_notification_remaining_images) + ' '
                                + String.valueOf(mSumImageDownloads - (mRemainingArtists + mRemainingAlbums)) + '/'
                                + String.valueOf(mSumImageDownloads)))
                .setProgress(mSumImageDownloads, mSumImageDownloads - (mRemainingArtists + mRemainingAlbums), false)
                .setSmallIcon(R.drawable.odyssey_notification);

        mBuilder.setOngoing(true);

        // Cancel action
        Intent nextIntent = new Intent(BulkDownloadService.ACTION_CANCEL_BULKDOWNLOAD);
        PendingIntent nextPendingIntent = PendingIntent.getBroadcast(getApplicationContext(), 1, nextIntent,
                PendingIntent.FLAG_UPDATE_CURRENT);
        android.support.v7.app.NotificationCompat.Action cancelAction = new android.support.v7.app.NotificationCompat.Action.Builder(
                R.drawable.ic_close_24dp, getString(R.string.dialog_action_cancel), nextPendingIntent).build();

        mBuilder.addAction(cancelAction);

        Notification notification = mBuilder.build();
        startForeground(NOTIFICATION_ID, notification);
        mNotificationManager.notify(NOTIFICATION_ID, notification);

    }

    @Override
    public void startAlbumLoading(int albumCount) {
        Log.v(TAG, "Albumloading started with: " + albumCount + " albums");
        mSumImageDownloads += albumCount;
        mRemainingAlbums = albumCount;
        runAsForeground();
    }

    @Override
    public void startArtistLoading(int artistCount) {
        Log.v(TAG, "Artistloading started with: " + artistCount + " artists");
        mSumImageDownloads += artistCount;
        mRemainingArtists = artistCount;
        runAsForeground();
    }

    @Override
    public void albumsRemaining(int remainingAlbums) {
        Log.v(TAG, "AlbumsRemaining: " + remainingAlbums + " artists");
        mRemainingAlbums = remainingAlbums;
        updateNotification();
    }

    @Override
    public void artistsRemaining(int remainingArtists) {
        Log.v(TAG, "ArtistsRemaining: " + remainingArtists + " artists");
        mRemainingArtists = remainingArtists;
        updateNotification();
    }

    @Override
    public void finishedLoading() {
        mNotificationManager.cancel(NOTIFICATION_ID);
        stopForeground(true);
        stopSelf();
        if (mWakelock.isHeld()) {
            mWakelock.release();
        }
    }

    private void updateNotification() {
        if ((mSumImageDownloads - (mRemainingArtists + mRemainingAlbums)) % 10 == 0) {
            mBuilder.setProgress(mSumImageDownloads, mSumImageDownloads - (mRemainingArtists + mRemainingAlbums),
                    false);
            mBuilder.setStyle(new NotificationCompat.BigTextStyle()
                    .bigText(getString(R.string.downloader_notification_remaining_images) + ' '
                            + String.valueOf(mSumImageDownloads - (mRemainingArtists + mRemainingAlbums)) + '/'
                            + String.valueOf(mSumImageDownloads)));
            mNotificationManager.notify(NOTIFICATION_ID, mBuilder.build());
        }
    }

    /**
     * Checks the current network state if an artwork download is allowed.
     *
     * @param context The current context to resolve the networkinfo
     * @return true if a download is allowed else false
     */
    private boolean isDownloadAllowed(final Context context) {
        ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);

        NetworkInfo networkInfo = cm.getActiveNetworkInfo();

        if (networkInfo == null) {
            return false;
        } else {
            boolean isWifi = cm.getActiveNetworkInfo().getType() == ConnectivityManager.TYPE_WIFI
                    || cm.getActiveNetworkInfo().getType() == ConnectivityManager.TYPE_ETHERNET;

            return !(mWifiOnly && !isWifi);
        }
    }

    private class ActionReceiver extends BroadcastReceiver {

        @Override
        public void onReceive(Context context, Intent intent) {
            Log.e(TAG, "Broadcast requested");
            if (intent.getAction().equals(ACTION_CANCEL_BULKDOWNLOAD)) {
                Log.e(TAG, "Cancel requested");
                ArtworkManager.getInstance(getApplicationContext()).cancelAllRequests(getApplicationContext());
                mNotificationManager.cancel(NOTIFICATION_ID);
                stopForeground(true);
                stopSelf();
            }
        }
    }

    private class ConnectionStateReceiver extends BroadcastReceiver {

        @Override
        public void onReceive(Context context, Intent intent) {
            if (!isDownloadAllowed(context)) {
                // Cancel all downloads
                Log.v(TAG, "Cancel all downloads because of connection change");
                LimitingRequestQueue.getInstance(BulkDownloadService.this)
                        .cancelAll(new RequestQueue.RequestFilter() {
                            @Override
                            public boolean apply(Request<?> request) {
                                return true;
                            }
                        });
            }

        }
    }
}