com.keithandthegirl.services.download.DownloadService.java Source code

Java tutorial

Introduction

Here is the source code for com.keithandthegirl.services.download.DownloadService.java

Source

/**
 *  This file is part of MythTV for Android
 * 
 *  MythTV for Android 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.
 *
 *  MythTV for Android 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 MythTV for Android.  If not, see <http://www.gnu.org/licenses/>.
 *   
 * This software can be found at <https://github.com/MythTV-Android/mythtv-for-android/>
 *
 */
package com.keithandthegirl.services.download;

import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.net.URL;
import java.net.URLConnection;
import java.text.DecimalFormat;
import java.util.Collections;

import org.springframework.http.ContentCodingType;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
import org.springframework.social.support.ClientHttpRequestFactorySelector;
import org.springframework.web.client.RestTemplate;

import android.annotation.TargetApi;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.os.Build;
import android.os.Environment;
import android.support.v4.app.FragmentActivity;
import android.util.FloatMath;
import android.util.Log;

import com.keithandthegirl.R;
import com.keithandthegirl.db.EpisodeConstants;
import com.keithandthegirl.services.KatgService;

/**
 * @author Daniel Frey
 *
 */
public class DownloadService extends KatgService {

    private static final String TAG = DownloadService.class.getSimpleName();
    private static DecimalFormat formatter = new DecimalFormat("###");

    public static enum Resource {
        MP3("mp3", "audio/mpeg"), MP4("mp4", "video/mp4"), M4V("m4v", "video/x-m4v"), JPG("jpg", "image/jpeg");

        private String extension;
        private String mimeType;

        Resource(String extension, String mimeType) {
            this.extension = extension;
            this.mimeType = mimeType;
        }

        /**
         * @return the extension
         */
        public String getExtension() {
            return extension;
        }

        /**
         * @return the mimeType
         */
        public String getMimeType() {
            return mimeType;
        }

        public static Resource findByExtension(String value) {

            for (Resource resource : Resource.values()) {
                if (resource.getExtension().equals(value)) {
                    return resource;
                }
            }

            return null;
        }

        public static Resource findByMimeType(String value) {

            for (Resource resource : Resource.values()) {
                if (resource.getMimeType().equals(value)) {
                    return resource;
                }
            }

            return null;
        }

    }

    private int result = FragmentActivity.RESULT_CANCELED;

    private NotificationManager mNotificationManager;
    private Notification mNotification;
    private PendingIntent mContentIntent;
    private CharSequence mContentTitle;
    private int notificationId;

    private RestTemplate template = new RestTemplate(true, ClientHttpRequestFactorySelector.getRequestFactory());
    private HttpEntity<?> entity;

    public DownloadService() {
        super("DownloadService");

        HttpHeaders requestHeaders = new HttpHeaders();
        requestHeaders.setAcceptEncoding(Collections.singletonList(ContentCodingType.GZIP));

        entity = new HttpEntity<Object>(requestHeaders);
    }

    /* (non-Javadoc)
     * @see android.app.IntentService#onHandleIntent(android.content.Intent)
     */
    @TargetApi(8)
    @Override
    protected void onHandleIntent(Intent requestIntent) {
        Log.v(TAG, "onHandleIntent : enter");

        mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);

        mOriginalRequestIntent = requestIntent;

        Resource resourceType = Resource.valueOf(requestIntent.getStringExtra(RESOURCE_TYPE_EXTRA));
        mCallback = requestIntent.getParcelableExtra(SERVICE_CALLBACK);

        Uri data = requestIntent.getData();
        String urlPath = requestIntent.getStringExtra("urlpath");
        String directory = requestIntent.getStringExtra("directory");

        String filename = data.getLastPathSegment();

        File root;
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.FROYO) {
            switch (resourceType) {
            case MP3:
                root = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PODCASTS);

                break;
            case MP4:
                root = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MOVIES);

                break;
            case M4V:
                root = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MOVIES);

                break;
            case JPG:
                root = getExternalCacheDir();
                filename = requestIntent.getLongExtra("id", -1) + ".jpg";

                break;
            default:
                root = getExternalCacheDir();

                break;
            }
        } else {
            root = Environment.getExternalStorageDirectory();
        }

        File outputDir = new File(root, directory);
        outputDir.mkdirs();

        File output = new File(outputDir, filename);
        if (output.exists()) {
            result = FragmentActivity.RESULT_OK;

            mCallback.send(result, getOriginalIntentBundle());

            Log.v(TAG, "onHandleIntent : exit, image exists");
            return;
        }

        switch (resourceType) {
        case MP3:
            Log.v(TAG, "onHandleIntent : saving mp3");

            savePodcast(requestIntent.getLongExtra("id", -1), requestIntent.getStringExtra("title"), urlPath,
                    output);
            mCallback.send(result, getOriginalIntentBundle());

            break;

        case MP4:
            Log.v(TAG, "onHandleIntent : saving mp4");

            savePodcast(requestIntent.getLongExtra("id", -1), requestIntent.getStringExtra("title"), urlPath,
                    output);
            mCallback.send(result, getOriginalIntentBundle());

            break;

        case M4V:
            Log.v(TAG, "onHandleIntent : saving m4v");

            savePodcast(requestIntent.getLongExtra("id", -1), requestIntent.getStringExtra("title"), urlPath,
                    output);
            mCallback.send(result, getOriginalIntentBundle());

            break;

        case JPG:
            Log.v(TAG, "onHandleIntent : saving jpg");

            saveBitmap(requestIntent.getStringExtra("filename"), urlPath, output);
            mCallback.send(result, getOriginalIntentBundle());

            break;
        default:
            Log.w(TAG, "onHandleIntent : unknown extension '" + resourceType.getExtension() + "'");

            mCallback.send(REQUEST_INVALID, getOriginalIntentBundle());
            break;
        }

        Log.v(TAG, "onHandleIntent : exit");
    }

    // internal helpers

    private void saveBitmap(String filename, String urlPath, File output) {
        Log.v(TAG, "saveBitmap : enter");

        try {
            ResponseEntity<byte[]> responseEntity = template.exchange(urlPath, HttpMethod.GET, entity,
                    byte[].class);
            switch (responseEntity.getStatusCode()) {
            case OK:
                Log.v(TAG, "saveBitmap : file downloaded");

                byte[] bytes = responseEntity.getBody();
                Bitmap bitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.length);

                FileOutputStream fos = new FileOutputStream(output);
                bitmap.compress(Bitmap.CompressFormat.JPEG, 100, fos);
                fos.flush();
                fos.close();

                result = FragmentActivity.RESULT_OK;

                break;
            default:
                Log.v(TAG, "saveBitmap : file not downloaded");

                break;
            }
        } catch (Exception e) {
            Log.e(TAG, "saveBitmap : exit, error", e);
        }

        Log.v(TAG, "saveBitmap : exit");
    }

    private void savePodcast(Long id, String title, String urlPath, File output) {
        Log.v(TAG, "savePodcast : enter");

        sendNotification("Downloading Episode: " + title);

        URL url;
        URLConnection con;
        InputStream is;
        FileOutputStream fos;
        byte[] buffer = new byte[4096];

        try {
            url = new URL(urlPath);
            con = url.openConnection();
            is = con.getInputStream();
            fos = new FileOutputStream(output);

            boolean notified = false;
            int length = con.getContentLength();
            int total = 0, read = -1;
            while ((read = is.read(buffer)) != -1) {
                fos.write(buffer, 0, read);

                total += read;

                int percent = (int) FloatMath.ceil(((100 * (float) total) / (float) length));
                //Log.v( TAG, "savePodcast : download percent=" + percent + "%" );
                if (percent % 5 == 0 && !notified) {
                    progressUpdate(percent);
                    notified = true;
                } else {
                    notified = false;
                }
            }
            is.close();
            fos.close();

            result = FragmentActivity.RESULT_OK;

            ContentValues values = new ContentValues();
            values.put(EpisodeConstants.FIELD_FILE, output.getAbsolutePath());

            getContentResolver().update(ContentUris.withAppendedId(EpisodeConstants.CONTENT_URI, id), values, null,
                    null);

        } catch (Exception e) {
            Log.e(TAG, "savePodcast : error", e);
        } finally {
            completed();
        }

        Log.v(TAG, "savePodcast : exit");
    }

    @SuppressWarnings("deprecation")
    private void sendNotification(String description) {

        mContentTitle = description;

        long when = System.currentTimeMillis();
        notificationId = (int) when;

        mNotification = new Notification(android.R.drawable.stat_sys_download,
                getResources().getString(R.string.app_name), when);

        Intent notificationIntent = new Intent();
        mContentIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0);

        mNotification.setLatestEventInfo(this, getResources().getString(R.string.app_name), mContentTitle,
                mContentIntent);

        mNotification.flags = Notification.FLAG_ONGOING_EVENT;

        mNotificationManager.notify(notificationId, mNotification);

    }

    @SuppressWarnings("deprecation")
    public void progressUpdate(double percentageComplete) {

        CharSequence contentText = formatter.format(percentageComplete) + "% complete";

        mNotification.setLatestEventInfo(this, mContentTitle, contentText, mContentIntent);
        mNotificationManager.notify(notificationId, mNotification);
    }

    public void completed() {
        mNotificationManager.cancel(notificationId);
    }

}