Java tutorial
/* * 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; } }); } } } }