com.adamrosenfield.wordswithcrosses.versions.GingerbreadUtil.java Source code

Java tutorial

Introduction

Here is the source code for com.adamrosenfield.wordswithcrosses.versions.GingerbreadUtil.java

Source

/**
 * This file is part of Words With Crosses.
 *
 * Copyright (C) 2009-2010 Robert Cooper
 * Copyright (C) 2013 Adam Rosenfield
 *
 * 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.adamrosenfield.wordswithcrosses.versions;

import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.ConcurrentSkipListMap;

import android.annotation.TargetApi;
import android.app.DownloadManager;
import android.app.DownloadManager.Request;
import android.content.Context;
import android.net.Uri;

import com.adamrosenfield.wordswithcrosses.WordsWithCrossesApplication;
import com.adamrosenfield.wordswithcrosses.net.AbstractDownloader;
import com.adamrosenfield.wordswithcrosses.net.HTTPException;

import org.apache.http.protocol.HttpContext;

@TargetApi(9)
public class GingerbreadUtil extends DefaultUtil {

    private static final boolean USE_DOWNLOAD_MANAGER = false;

    private static class DownloadingFile {
        public boolean completed = false;
        public boolean succeeded = false;
        public int status = -1;
    }

    private static final ConcurrentMap<Long, DownloadingFile> waitingDownloads = new ConcurrentSkipListMap<>();

    private static final Map<Long, DownloadingFile> completedDownloads = new HashMap<>();

    @Override
    @SuppressWarnings("unused") // Ignore dead code warning
    public void downloadFile(URL url, Map<String, String> headers, File destination, boolean notification,
            String title, HttpContext httpContext) throws IOException {
        // The DownloadManager can sometimes be buggy and can cause spurious
        // errors, see
        // http://code.google.com/p/android/issues/detail?id=18462
        // Since puzzle files are very small (a few KB), we don't need to use
        // any of the useful features the DownloadManager provides, such as
        // resuming interrupted downloads and resuming downloads across
        // system reboots.  So for now, just use the ordinary
        // DefaultHttpClient.
        //
        // Also, pre-ICS download managers don't support HTTPS.
        if (!USE_DOWNLOAD_MANAGER || "https".equals(url.getProtocol()) && android.os.Build.VERSION.SDK_INT < 15) {
            super.downloadFile(url, headers, destination, notification, title, httpContext);
            return;
        }

        DownloadManager mgr = (DownloadManager) context.getSystemService(Context.DOWNLOAD_SERVICE);

        Request request = new Request(Uri.parse(url.toString()));
        File tempFile = new File(WordsWithCrossesApplication.TEMP_DIR, destination.getName());

        request.setDestinationUri(Uri.fromFile(tempFile));

        for (Entry<String, String> entry : headers.entrySet()) {
            request.addRequestHeader(entry.getKey(), entry.getValue());
        }

        request.setMimeType("application/x-crossword");

        setNotificationVisibility(request, notification);

        request.setTitle(title);
        long id = mgr.enqueue(request);
        Long idObj = id;

        String scrubbedUrl = AbstractDownloader.scrubUrl(url);
        LOG.info("Downloading " + scrubbedUrl + " ==> " + tempFile + " (id=" + id + ")");

        // If the request completed really fast, we're done
        DownloadingFile downloadingFile;
        boolean completed = false;
        boolean succeeded = false;
        int status = -1;
        synchronized (completedDownloads) {
            downloadingFile = completedDownloads.remove(idObj);
            if (downloadingFile != null) {
                completed = true;
                succeeded = downloadingFile.succeeded;
                status = downloadingFile.status;
            } else {
                downloadingFile = new DownloadingFile();
                waitingDownloads.put(idObj, downloadingFile);
            }
        }

        // Wait for the request to complete, if it hasn't completed already
        if (!completed) {
            try {
                synchronized (downloadingFile) {
                    if (!downloadingFile.completed) {
                        downloadingFile.wait();
                    }
                    succeeded = downloadingFile.succeeded;
                    status = downloadingFile.status;
                }
            } catch (InterruptedException e) {
                LOG.warning("Download interrupted: " + scrubbedUrl);
                throw new IOException("Download interrupted");
            }
        }

        LOG.info("Download " + (succeeded ? "succeeded" : "failed") + ": " + scrubbedUrl);

        if (succeeded) {
            if (!destination.equals(tempFile) && !tempFile.renameTo(destination)) {
                LOG.warning("Failed to rename " + tempFile + " to " + destination);
                throw new IOException("Failed to rename " + tempFile + " to " + destination);
            }
        } else {
            throw new HTTPException(status);
        }
    }

    @Override
    public void onFileDownloaded(long id, boolean succeeded, int status) {
        Long idObj = id;
        synchronized (completedDownloads) {
            DownloadingFile downloadingFile = waitingDownloads.remove(idObj);
            if (downloadingFile != null) {
                synchronized (downloadingFile) {
                    downloadingFile.completed = true;
                    downloadingFile.succeeded = succeeded;
                    downloadingFile.status = status;
                    downloadingFile.notifyAll();
                }
            } else {
                LOG.info("No thread is waiting on download for id=" + id);
                downloadingFile = new DownloadingFile();
                downloadingFile.completed = true;
                downloadingFile.succeeded = succeeded;
                downloadingFile.status = status;
                completedDownloads.put(idObj, downloadingFile);
            }
        }
    }

    protected void setNotificationVisibility(Request reqest, boolean notification) {
    }
}