com.github.notizklotz.derbunddownloader.download.IssueDownloadService.java Source code

Java tutorial

Introduction

Here is the source code for com.github.notizklotz.derbunddownloader.download.IssueDownloadService.java

Source

/*
 * Der Bund ePaper Downloader - App to download ePaper issues of the Der Bund newspaper
 * Copyright (C) 2013 Adrian Gygax
 *
 * 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 com.github.notizklotz.derbunddownloader.download;

import android.annotation.SuppressLint;
import android.app.DownloadManager;
import android.app.IntentService;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.net.Uri;
import android.net.wifi.WifiManager;
import android.os.Build;
import android.preference.PreferenceManager;
import android.util.Log;

import com.github.notizklotz.derbunddownloader.BuildConfig;
import com.github.notizklotz.derbunddownloader.R;
import com.github.notizklotz.derbunddownloader.common.LocalDate;
import com.github.notizklotz.derbunddownloader.issuesgrid.DownloadedIssuesActivity_;
import com.github.notizklotz.derbunddownloader.settings.Settings;
import com.squareup.picasso.Picasso;

import org.androidannotations.annotations.EIntentService;
import org.androidannotations.annotations.ServiceAction;
import org.androidannotations.annotations.SystemService;
import org.springframework.util.Assert;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.web.client.RestClientException;
import org.springframework.web.client.RestTemplate;

import java.io.File;
import java.util.concurrent.CountDownLatch;

@SuppressLint("Registered")
@EIntentService
public class IssueDownloadService extends IntentService {

    private static final String LOG_TAG = IssueDownloadService.class.getSimpleName();
    private static final int WIFI_RECHECK_WAIT_MILLIS = 5 * 1000;
    private static final int WIFI_CHECK_MAX_MILLIS = 30 * 1000;
    private static final String WORKER_THREAD_NAME = "IssueDownloadService";
    private static final String ISSUE_PDF_URL_TEMPLATE = "http://epaper.derbund.ch/getFile.php?ausgabe=%02d%02d%04d";
    private static final String ISSUE_THUMBNAIL_URL_TEMPLATE = "http://epaper.derbund.ch/jpg/%04d-BVBU-001-%02d%02d.pdf.jpg";
    private static final String ISSUE_TITLE_TEMPLATE = "Der Bund ePaper %02d.%02d.%04d";
    private static final String ISSUE_FILENAME_TEMPLATE = "Der Bund ePaper %02d.%02d.%04d.pdf";
    private static final String ISSUE_DESCRIPTION_TEMPLATE = "%02d.%02d.%04d";
    @SuppressWarnings("WeakerAccess")
    @SystemService
    ConnectivityManager connectivityManager;
    @SystemService
    WifiManager wifiManager;
    @SuppressWarnings("WeakerAccess")
    @SystemService
    DownloadManager downloadManager;
    private WifiManager.WifiLock myWifiLock;
    private Intent intent;
    private DownloadCompletedBroadcastReceiver receiver;

    public IssueDownloadService() {
        super(WORKER_THREAD_NAME);
    }

    private static String expandTemplateWithDate(String template, LocalDate localDate) {
        return String.format(template, localDate.getDay(), localDate.getMonth(), localDate.getYear());
    }

    public static Uri getThumbnailUriForPDFUri(Uri pdfUri) {
        String ddmmyyyy = pdfUri.getQueryParameter("ausgabe");

        int day = Integer.parseInt(ddmmyyyy.substring(0, 2));
        int month = Integer.parseInt(ddmmyyyy.substring(2, 4));
        int year = Integer.parseInt(ddmmyyyy.substring(4, 8));

        return Uri.parse(String.format(ISSUE_THUMBNAIL_URL_TEMPLATE, year, day, month));
    }

    @ServiceAction
    public void downloadIssue(int day, int month, int year) {
        Log.i(LOG_TAG, "Handling download intent");
        try {
            boolean connected;
            final boolean wifiOnly = Settings.isWifiOnly(getApplicationContext());
            if (wifiOnly) {
                connected = waitForWifiConnection();
                if (!connected) {
                    notifyUser(getText(R.string.download_wifi_connection_failed),
                            getText(R.string.download_wifi_connection_failed_text), R.drawable.ic_stat_newspaper);
                }
            } else {
                NetworkInfo activeNetworkInfo = connectivityManager.getActiveNetworkInfo();
                connected = activeNetworkInfo != null && activeNetworkInfo.isConnected();
                if (!connected) {
                    notifyUser(getText(R.string.download_connection_failed),
                            getText(R.string.download_connection_failed_text), R.drawable.ic_stat_newspaper);
                }
            }

            if (connected) {
                if (!checkUserAccount()) {
                    notifyUser(getText(R.string.download_login_failed),
                            getText(R.string.download_login_failed_text), R.drawable.ic_stat_newspaper);
                } else {
                    final LocalDate issueDate = new LocalDate(day, month, year);
                    fetchThumbnail(issueDate);

                    final CountDownLatch downloadDoneSignal = new CountDownLatch(1);
                    receiver = new DownloadCompletedBroadcastReceiver(downloadDoneSignal);
                    registerReceiver(receiver, new IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE));

                    try {
                        String title = startDownload(issueDate, wifiOnly);
                        downloadDoneSignal.await();
                        notifyUser(title, getString(R.string.download_completed), R.drawable.ic_stat_newspaper);
                    } catch (InterruptedException e) {
                        Log.wtf(LOG_TAG, "Interrupted while waiting for the downloadDoneSignal");
                    }
                }
            }
        } catch (Exception e) {
            notifyUser(getText(R.string.download_service_error),
                    getText(R.string.download_service_error_text) + " " + e.getMessage(),
                    R.drawable.ic_stat_newspaper);
        } finally {
            cleanup();
        }
    }

    private boolean waitForWifiConnection() {
        boolean connected = false;
        if (wifiManager != null) {
            //WIFI_MODE_FULL was not enough on Xperia Tablet Z Android 4.2 to reconnect to the AP if Wifi was enabled but connection
            //was lost
            myWifiLock = wifiManager.createWifiLock(WifiManager.WIFI_MODE_FULL_HIGH_PERF, "IssueDownloadWifilock");
            myWifiLock.setReferenceCounted(false);
            myWifiLock.acquire();

            //Wait for Wifi coming up
            long firstCheckMillis = System.currentTimeMillis();
            if (!wifiManager.isWifiEnabled()) {
                notifyUser(getText(R.string.download_connection_failed),
                        getText(R.string.download_connection_failed_no_wifi_text), R.drawable.ic_stat_newspaper);
            } else {
                do {
                    NetworkInfo networkInfo = connectivityManager.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
                    assert networkInfo != null;
                    connected = networkInfo.isConnected();

                    if (!connected) {
                        Log.d(LOG_TAG, "Wifi connection is not yet ready. Wait and recheck");

                        if (System.currentTimeMillis() - firstCheckMillis > WIFI_CHECK_MAX_MILLIS) {
                            break;
                        }

                        try {
                            Thread.sleep(WIFI_RECHECK_WAIT_MILLIS);
                        } catch (InterruptedException e) {
                            Log.wtf(LOG_TAG, "Interrupted while waiting for Wifi connection", e);
                        }
                    }
                } while (!connected);
            }
        }
        return connected;
    }

    private void cleanup() {
        if (myWifiLock != null) {
            if (myWifiLock.isHeld()) {
                myWifiLock.release();
            }
            myWifiLock = null;
        }

        if (receiver != null) {
            unregisterReceiver(receiver);
            receiver = null;
        }

        if (intent != null) {
            AutomaticIssueDownloadAlarmReceiver.completeWakefulIntent(intent);
            intent = null;
        }
    }

    @Override
    public void onDestroy() {
        cleanup();
        super.onDestroy();
    }

    @Override
    protected void onHandleIntent(Intent intent) {
        this.intent = intent;
    }

    private void notifyUser(CharSequence contentTitle, CharSequence contentText, int icon) {
        Notification.Builder mBuilder = new Notification.Builder(getApplicationContext()).setSmallIcon(icon)
                .setContentTitle(contentTitle).setContentText(contentText).setTicker(contentTitle)
                .setAutoCancel(true);

        //http://developer.android.com/guide/topics/ui/notifiers/notifications.html
        // The stack builder object will contain an artificial back stack for thestarted Activity.
        // This ensures that navigating backward from the Activity leads out of your application to the Home screen.
        mBuilder.setContentIntent(android.support.v4.app.TaskStackBuilder.create(getApplicationContext())
                .addParentStack(DownloadedIssuesActivity_.class)
                .addNextIntent(new Intent(getApplicationContext(), DownloadedIssuesActivity_.class))
                .getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT));

        NotificationManager mNotifyMgr = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
        //noinspection deprecation
        mNotifyMgr.notify(1, mBuilder.getNotification());
    }

    private void fetchThumbnail(LocalDate issueDate) {
        Uri uri = Uri.parse(String.format(ISSUE_THUMBNAIL_URL_TEMPLATE, issueDate.getYear(), issueDate.getDay(),
                issueDate.getMonth()));
        Picasso.with(this).load(uri).fetch();
    }

    private String startDownload(LocalDate issueDate, boolean wifiOnly) {
        final String title = expandTemplateWithDate(ISSUE_TITLE_TEMPLATE, issueDate);
        final String filename = expandTemplateWithDate(ISSUE_FILENAME_TEMPLATE, issueDate);
        if (BuildConfig.DEBUG) {
            File extFilesDir = getExternalFilesDir(null);
            File file = new File(extFilesDir, filename);
            Log.d(LOG_TAG, "Filename: " + file.toString());
            Log.d(LOG_TAG, "Can write? " + (extFilesDir != null && extFilesDir.canWrite()));
        }

        Uri issueUrl = Uri.parse(expandTemplateWithDate(ISSUE_PDF_URL_TEMPLATE, issueDate));
        DownloadManager.Request pdfDownloadRequest = new DownloadManager.Request(issueUrl).setTitle(title)
                .setDescription(expandTemplateWithDate(ISSUE_DESCRIPTION_TEMPLATE, issueDate))
                .setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE)
                .setDestinationInExternalFilesDir(this, null, filename);

        if (wifiOnly) {
            pdfDownloadRequest.setAllowedNetworkTypes(DownloadManager.Request.NETWORK_WIFI);
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
                pdfDownloadRequest.setAllowedOverMetered(false);
            }
        }
        downloadManager.enqueue(pdfDownloadRequest);

        return title;
    }

    private boolean checkUserAccount() {
        if (BuildConfig.DEBUG) {
            Log.d(LOG_TAG, "Checking user account validity");
        }

        try {
            final SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(this);
            final String username = sharedPref.getString(Settings.KEY_USERNAME, "");
            final String password = sharedPref.getString(Settings.KEY_PASSWORD, "");

            RestTemplate restTemplate = new RestTemplate(true);
            LinkedMultiValueMap<String, String> form = new LinkedMultiValueMap<String, String>();
            form.add("user", username);
            form.add("password", password);
            form.add("dologin", "1");
            form.add("t", "");

            String response = restTemplate.postForObject("http://epaper.derbund.ch", form, String.class);
            boolean loginSuccessful = response.contains("flashcontent");
            Log.d(LOG_TAG, "Login successful? " + loginSuccessful);
            return loginSuccessful;
        } catch (RestClientException e) {
            Log.e(LOG_TAG, "Error while trying to login", e);
            return false;
        }
    }

    private static class DownloadCompletedBroadcastReceiver extends BroadcastReceiver {

        private final CountDownLatch downloadDoneSignal;

        private DownloadCompletedBroadcastReceiver(CountDownLatch downloadDoneSignal) {
            Assert.notNull(downloadDoneSignal);
            this.downloadDoneSignal = downloadDoneSignal;
        }

        @Override
        public void onReceive(Context context, Intent intent) {
            downloadDoneSignal.countDown();
        }
    }
}