com.fanfou.app.opensource.service.DownloadService.java Source code

Java tutorial

Introduction

Here is the source code for com.fanfou.app.opensource.service.DownloadService.java

Source

/*******************************************************************************
 * Copyright 2011, 2012, 2013 fanfou.com, Xiaoke, Zhang
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *******************************************************************************/
package com.fanfou.app.opensource.service;

import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.protocol.HTTP;
import org.apache.http.util.EntityUtils;

import android.annotation.SuppressLint;
import android.app.AlarmManager;
import android.app.AlertDialog;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.net.Uri;
import android.os.Handler;
import android.os.Message;
import android.text.TextUtils;
import android.util.Log;
import android.webkit.MimeTypeMap;
import android.widget.RemoteViews;

import com.fanfou.app.opensource.AppContext;
import com.fanfou.app.opensource.NewVersionPage;
import com.fanfou.app.opensource.R;
import com.fanfou.app.opensource.http.SimpleClient;
import com.fanfou.app.opensource.update.AppVersionInfo;
import com.fanfou.app.opensource.util.CommonHelper;
import com.fanfou.app.opensource.util.IOHelper;

/**
 * @author mcxiaoke
 * @version 1.0 2011.09.04
 * @version 2.0 2011.10.31
 * @version 2.1 2011.11.24
 * @version 2.2 2011.11.25
 * @version 2.3 2011.11.28
 * @version 2.4 2011.12.02
 * @version 2.5 2011.12.19
 * @version 2.6 2011.12.30
 * @version 2.7 2012.01.05
 * @version 2.8 2012.01.16
 * 
 */
public class DownloadService extends BaseIntentService {
    @SuppressLint("HandlerLeak")
    private class DownloadHandler extends Handler {
        private static final long UPDATE_TIME = 1500;
        private long lastTime = 0;

        @Override
        public void handleMessage(final Message msg) {
            if (AppContext.DEBUG) {
                log("DownloadHandler what=" + msg.what + " progress=" + msg.arg1);
            }
            if (DownloadService.MSG_PROGRESS == msg.what) {
                final long now = System.currentTimeMillis();
                if ((now - this.lastTime) < DownloadHandler.UPDATE_TIME) {
                    return;
                }
                final int progress = msg.arg1;
                updateProgress(progress);
                this.lastTime = System.currentTimeMillis();
            } else if (DownloadService.MSG_SUCCESS == msg.what) {
                DownloadService.this.nm.cancel(DownloadService.NOTIFICATION_PROGRESS_ID);
                final String filePath = msg.getData().getString(Constants.EXTRA_FILENAME);
                CommonHelper.open(DownloadService.this, filePath);
            }
        }
    }

    private static final String TAG = DownloadService.class.getSimpleName();

    public static final String UPDATE_VERSION_FILE = "http://apps.fanfou.com/android/update.json";
    private static final int NOTIFICATION_PROGRESS_ID = -12345;
    public static final long AUTO_UPDATE_INTERVAL = 2 * 3600 * 1000L;
    private NotificationManager nm;
    private Notification notification;

    private Handler mHandler;
    public static final int TYPE_CHECK = 0;

    public static final int TYPE_DOWNLOAD = 1;

    private static final int MSG_PROGRESS = 0;

    private static final int MSG_SUCCESS = 1;

    public static AppVersionInfo fetchVersionInfo() {
        final SimpleClient client = new SimpleClient(AppContext.getAppContext());
        try {
            final HttpResponse response = client.get(DownloadService.UPDATE_VERSION_FILE);
            final int statusCode = response.getStatusLine().getStatusCode();
            if (AppContext.DEBUG) {
                Log.d(DownloadService.TAG, "statusCode=" + statusCode);
            }
            if (statusCode == 200) {
                final String content = EntityUtils.toString(response.getEntity(), HTTP.UTF_8);
                if (AppContext.DEBUG) {
                    Log.d(DownloadService.TAG, "response=" + content);
                }
                return AppVersionInfo.parse(content);
            }
        } catch (final IOException e) {
            if (AppContext.DEBUG) {
                e.printStackTrace();
            }
        } catch (final Exception e) {
            if (AppContext.DEBUG) {
                e.printStackTrace();
            }
        } finally {
        }
        return null;
    }

    public static Intent getNewVersionIntent(final Context context, final AppVersionInfo info) {
        final Intent intent = new Intent(context, NewVersionPage.class);
        intent.putExtra(Constants.EXTRA_DATA, info);
        return intent;
    }

    private final static PendingIntent getPendingIntent(final Context context) {
        final Intent intent = new Intent(context, DownloadService.class);
        intent.putExtra(Constants.EXTRA_TYPE, DownloadService.TYPE_CHECK);
        final PendingIntent pi = PendingIntent.getService(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
        return pi;
    }

    public static void notifyUpdate(final AppVersionInfo info, final Context context) {
        final String versionInfo = info.versionName;
        final NotificationManager nm = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
        final Notification notification = new Notification(R.drawable.ic_notify_icon,
                "?" + versionInfo, System.currentTimeMillis());

        final PendingIntent contentIntent = PendingIntent.getActivity(context, 0,
                DownloadService.getNewVersionIntent(context, info), 0);
        notification.setLatestEventInfo(context, "?" + versionInfo,
                "", contentIntent);
        notification.flags |= Notification.FLAG_AUTO_CANCEL;
        nm.notify(2, notification);

    }

    public static void showUpdateConfirmDialog(final Context context, final AppVersionInfo info) {
        final DialogInterface.OnClickListener downListener = new DialogInterface.OnClickListener() {

            @Override
            public void onClick(final DialogInterface dialog, final int which) {
                DownloadService.startDownload(context, info);
            }
        };
        final AlertDialog.Builder builder = new AlertDialog.Builder(context);
        builder.setTitle("???").setCancelable(true).setNegativeButton("??",
                null);
        builder.setPositiveButton("??", downListener);
        final StringBuffer sb = new StringBuffer();
        sb.append("").append(AppContext.appVersionName).append("(Build")
                .append(AppContext.appVersionCode).append(")");
        sb.append("\n").append(info.versionName).append("(Build").append(info.versionCode)
                .append(")");
        sb.append("\n").append(info.releaseDate);
        sb.append("\n").append(info.forceUpdate ? "???" : "?");
        sb.append("\n\n").append(info.changelog);
        builder.setMessage(sb.toString());
        final AlertDialog dialog = builder.create();
        dialog.show();

    }

    public static void startDownload(final Context context, final AppVersionInfo info) {
        final Intent intent = new Intent(context, DownloadService.class);
        intent.putExtra(Constants.EXTRA_TYPE, DownloadService.TYPE_DOWNLOAD);
        intent.putExtra(Constants.EXTRA_URL, info);
        context.startService(intent);
    }

    public static void unset(final Context context) {
        final AlarmManager am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
        am.cancel(DownloadService.getPendingIntent(context));
        if (AppContext.DEBUG) {
            Log.d(DownloadService.TAG, "unset");
        }
    }

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

    }

    private void check() {
        final AppVersionInfo info = DownloadService.fetchVersionInfo();
        if (AppContext.DEBUG) {
            Log.d(DownloadService.TAG, "check() VersionInfo=" + info);
            if (info != null) {
                DownloadService.notifyUpdate(info, this);
                return;
            }
        }
        if ((info != null) && (info.versionCode > AppContext.appVersionCode)) {
            DownloadService.notifyUpdate(info, this);
        }
    }

    private void download(final AppVersionInfo info) {
        if ((info == null) || TextUtils.isEmpty(info.downloadUrl)) {
            return;
        }
        showProgress();
        final String url = info.downloadUrl;
        final int versionCode = info.versionCode;
        if (AppContext.DEBUG) {
            Log.v(DownloadService.TAG, "download apk file url: " + url + " versionCode:" + versionCode);
        }
        InputStream is = null;
        BufferedOutputStream bos = null;
        final SimpleClient client = new SimpleClient(AppContext.getAppContext());
        boolean needDownload = true;
        final File file = new File(IOHelper.getDownloadDir(this), "fanfouapp_" + versionCode + ".apk");
        try {
            final HttpResponse response = client.get(url);
            final int statusCode = response.getStatusLine().getStatusCode();
            if (statusCode == 200) {
                final HttpEntity entity = response.getEntity();
                final long totalSize = entity.getContentLength();
                long download = 0;

                if (file.exists() && file.isFile() && (file.length() == totalSize)) {
                    needDownload = false;
                    download = totalSize;
                    if (AppContext.DEBUG) {
                        Log.v(DownloadService.TAG,
                                "download apk file is already exists: " + file.getAbsolutePath());
                    }
                }

                if (needDownload) {
                    is = entity.getContent();
                    bos = new BufferedOutputStream(new FileOutputStream(file));
                    final byte[] buffer = new byte[8196];
                    int read = -1;
                    while ((read = is.read(buffer)) != -1) {
                        bos.write(buffer, 0, read);
                        download += read;
                        final int progress = (int) ((100.0 * download) / totalSize);
                        sendProgressMessage(progress);
                        if (AppContext.DEBUG) {
                            log("progress=" + progress);
                        }
                    }
                    bos.flush();
                }
                if (download >= totalSize) {
                    sendSuccessMessage(file);
                }
            }
        } catch (final IOException e) {
            if (AppContext.DEBUG) {
                Log.e(DownloadService.TAG, "download error: " + e.getMessage());
                e.printStackTrace();
            }

        } finally {
            this.nm.cancel(DownloadService.NOTIFICATION_PROGRESS_ID);
            IOHelper.forceClose(is);
            IOHelper.forceClose(bos);
        }
    }

    @SuppressWarnings("unused")
    private PendingIntent getInstallPendingIntent(final String fileName) {
        final String mimeType = MimeTypeMap.getSingleton()
                .getMimeTypeFromExtension(CommonHelper.getExtension(fileName));
        if (mimeType != null) {
            final Intent intent = new Intent(Intent.ACTION_VIEW);
            intent.setDataAndType(Uri.fromFile(new File(fileName)), mimeType);
            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            final PendingIntent pi = PendingIntent.getActivity(this, 0, intent, 0);
            return pi;
        }
        return null;
    }

    private void log(final String message) {
        Log.d("DownloadService", message);
    }

    @Override
    public void onCreate() {
        super.onCreate();
        this.mHandler = new DownloadHandler();
    }

    @Override
    protected void onHandleIntent(final Intent intent) {
        this.nm = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
        final int type = intent.getIntExtra(Constants.EXTRA_TYPE, DownloadService.TYPE_CHECK);
        if (AppContext.DEBUG) {
            Log.d(DownloadService.TAG, "onHandleIntent type=" + type);
        }
        if (type == DownloadService.TYPE_CHECK) {
            check();
        } else if (type == DownloadService.TYPE_DOWNLOAD) {
            final AppVersionInfo info = intent.getParcelableExtra(Constants.EXTRA_URL);
            log("onHandleIntent TYPE_DOWNLOAD info=" + info);
            if ((info != null) && !TextUtils.isEmpty(info.downloadUrl)) {
                download(info);
            }
        }
    }

    private void sendProgressMessage(final int progress) {
        final Message message = new Message();
        message.what = DownloadService.MSG_PROGRESS;
        message.arg1 = progress;
        this.mHandler.sendMessage(message);
    }

    private void sendSuccessMessage(final File file) {
        final Message message = new Message();
        message.what = DownloadService.MSG_SUCCESS;
        message.getData().putString(Constants.EXTRA_FILENAME, file.getAbsolutePath());
        this.mHandler.sendMessage(message);
    }

    private void showProgress() {
        this.notification = new Notification(R.drawable.ic_notify_download, "?",
                System.currentTimeMillis());
        this.notification.flags |= Notification.FLAG_ONGOING_EVENT;
        this.notification.flags |= Notification.FLAG_AUTO_CANCEL;
        this.notification.contentIntent = PendingIntent.getActivity(this, 0, new Intent(), 0);
        final RemoteViews view = new RemoteViews(getPackageName(), R.layout.download_notification);
        view.setTextViewText(R.id.download_notification_text, "? 0%");
        view.setProgressBar(R.id.download_notification_progress, 100, 0, false);
        this.notification.contentView = view;
        this.nm.notify(DownloadService.NOTIFICATION_PROGRESS_ID, this.notification);
    }

    private void updateProgress(final int progress) {
        final RemoteViews view = new RemoteViews(getPackageName(), R.layout.download_notification);
        view.setTextViewText(R.id.download_notification_text, "? " + progress + "%");
        view.setInt(R.id.download_notification_progress, "setProgress", progress);
        this.notification.contentView = view;
        this.nm.notify(DownloadService.NOTIFICATION_PROGRESS_ID, this.notification);
    }

}