com.stroke.academy.common.updater.ApkDownloadUtil.java Source code

Java tutorial

Introduction

Here is the source code for com.stroke.academy.common.updater.ApkDownloadUtil.java

Source

/**
 * @(#)ApkDownloadUtil.java, Mar 7, 2014. Copyright 2014 Yodao, Inc. All rights
 * reserved. YODAO PROPRIETARY/CONFIDENTIAL. Use is
 * subject to license terms.
 */
package com.stroke.academy.common.updater;

import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.TaskStackBuilder;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.Handler;
import android.os.Message;
import android.support.v4.app.NotificationCompat;

import com.stroke.academy.AcademyApplication;
import com.stroke.academy.R;
import com.stroke.academy.common.constant.Consts;
import com.stroke.academy.common.util.Toaster;

import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.params.HttpConnectionParams;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InterruptedIOException;
import java.io.OutputStream;
import java.lang.ref.WeakReference;
import java.net.SocketException;
import java.net.UnknownHostException;

/**
 * apk
 * ??
 *    1.initAppDownloadInfo()??
 *    2.setDownloadListener ?
 *    3.startDownload 
 * @author emilyu
 */
public class ApkDownloadUtil {

    private boolean isDownloading = false;

    private String downloadUrl = null;

    private String appName = null;

    private String packageName = null;

    private DownloadHandler downloadHandler = null;

    private NotificationManager mNotifyManager = null;

    private NotificationCompat.Builder mBuilder = null;

    private DownloadThread downloadThread = null;

    private ApkDownloadListener downloadListener = null;

    private static ApkDownloadUtil apkDownloadUtil = null;

    public final static int PROGRESS_MSG = 1;

    public final static int DOWNLOAD_SUCCESS_MSG = 2;

    public final static int DOWNLOAD_FAIL_MSG = 3;

    public final static int DOWNLOAD_CANCEL_MSG = 4;

    private final static String APK_DOWNLOAD_DIR = Consts.TEMP_FILE_PATH;

    private final static String APK_DOWNLOAD_SUF = ".apk";

    private final static String APK_DOWNLOAD_TEMP = ".temp";

    private long mContentSize;

    private ApkDownloadUtil() {
    }

    public synchronized static ApkDownloadUtil getInstance() {
        if (apkDownloadUtil == null) {
            apkDownloadUtil = new ApkDownloadUtil();
        }

        return apkDownloadUtil;
    }

    /**
     * ???
     * @param appName
     * @param packageName
     * @param downloadUrl
     */
    public void initAppDownloadInfo(String appName, String packageName, String downloadUrl) {
        this.appName = appName;
        this.packageName = packageName;
        this.downloadUrl = downloadUrl;
        this.downloadHandler = new DownloadHandler(this);
    }

    /**
     * ?
     * @param downloadListener
     */
    public void setDownloadListener(ApkDownloadListener downloadListener) {
        this.downloadListener = downloadListener;
    }

    /**
     * ?
     * @param context
     * @param targetClass
     */
    private void showAppDownloadNotify(Context context, Class<?> parentClass, Class<?> targetClass) {
        mNotifyManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
        // show notify
        Intent notifyIntent = new Intent(context, targetClass);

        TaskStackBuilder stackBuilder = TaskStackBuilder.create(context);
        // Adds the back stack
        if (parentClass != null) {
            stackBuilder.addNextIntent(new Intent(context, parentClass));
        }
        // Adds the Intent to the top of the stack
        stackBuilder.addNextIntent(notifyIntent);
        // Gets a PendingIntent containing the entire back stack
        PendingIntent resultPendingIntent = stackBuilder.getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT);

        mBuilder = new NotificationCompat.Builder(context);
        mBuilder.setContentTitle(appName).setSmallIcon(R.drawable.ic_launcher)
                .setContentIntent(resultPendingIntent);
        mBuilder.setProgress(100, 0, false);
        mNotifyManager.notify(appName.hashCode(), mBuilder.build());
    }

    /**
     * ?
     * @return
     */
    public boolean isDownloading() {
        return isDownloading;
    }

    /**
     * ?
     * @return
     */
    public DownloadThread getDownloadThread() {
        return downloadThread;
    }

    /**
     * 
     * @param context
     * @param targetClass
     * @return
     */
    public void startDownload(Context context, Class<?> parentClass, Class<?> targetClass, boolean isUpdate) {
        downloadThread = new DownloadThread(isUpdate);
        downloadThread.start();
        showAppDownloadNotify(context, parentClass, targetClass);
    }

    private void startDownload(boolean isUpdate) {
        downloadThread = null;
        downloadThread = new DownloadThread(isUpdate);
        downloadThread.start();
    }

    public boolean checkDownloading() {
        if (isDownloading) {
            Toaster.show(AcademyApplication.getInstance(), R.string.task_downloading);
            return true;
        }

        return false;
    }

    /**
     * ??
     * @param packageName
     */
    public void cancelDownload(String packageName) {
        if (packageName.equals(this.packageName) && downloadThread != null) {
            downloadThread.interrupt();
        }
    }

    public static void installBundledApps(File file) {
        Intent intent = new Intent(Intent.ACTION_VIEW);
        intent.setDataAndType(Uri.fromFile(file), "application/vnd.android.package-archive");
        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        AcademyApplication.getInstance().startActivity(intent);
    }

    /**
     * 
     *
     * @author emilyu
     *
     */
    private class DownloadThread extends Thread {
        public static final int TIME_OUT = 30000;

        //        private String filePath = null;

        private String filePathTemp = null;

        private String finaFilePath = null;

        private InputStream in = null;

        private OutputStream out = null;

        public DownloadThread(boolean isUpdate) {

            File dir = new File(APK_DOWNLOAD_DIR);
            if (!dir.exists()) {
                dir.mkdirs();
            }
            filePathTemp = APK_DOWNLOAD_DIR + packageName + APK_DOWNLOAD_TEMP;
            finaFilePath = APK_DOWNLOAD_DIR + packageName + APK_DOWNLOAD_SUF;
            //TODO 
            File file = new File(filePathTemp);
            if (file.exists())
                file.delete();
            if (isUpdate) {
                File desFile = new File(finaFilePath);
                if (desFile.exists()) {
                    desFile.delete();
                }
            }
        }

        @Override
        public void run() {
            isDownloading = true;
            try {
                downloadFile();
                isDownloading = false;
                defineFileName();
                downloadHandler.obtainMessage(DOWNLOAD_SUCCESS_MSG, finaFilePath).sendToTarget();
            } catch (InterruptedException e) {
                isDownloading = false;
                downloadHandler.sendEmptyMessage(DOWNLOAD_CANCEL_MSG);
            } catch (Exception e) {
                isDownloading = false;
                downloadHandler.obtainMessage(DOWNLOAD_FAIL_MSG, e).sendToTarget();
            }

        }

        private void defineFileName() {
            File file = new File(filePathTemp);
            if (file.exists()) {
                file.renameTo(new File(finaFilePath));
            }
        }

        private void downloadFile() throws Exception {

            HttpGet get = new HttpGet(downloadUrl);
            HttpClient client = new DefaultHttpClient();
            HttpConnectionParams.setConnectionTimeout(client.getParams(), TIME_OUT);
            HttpConnectionParams.setSoTimeout(client.getParams(), TIME_OUT);
            HttpResponse response = client.execute(get);

            int statusCode = response.getStatusLine().getStatusCode();
            if (statusCode != 200 && statusCode != 206) {
                throw new Exception(response.getStatusLine().toString());
            }
            mContentSize = response.getEntity().getContentLength();
            //??
            File file = new File(finaFilePath);
            if (file.exists() && file.length() == mContentSize) {
                downloadHandler.obtainMessage(DOWNLOAD_SUCCESS_MSG, finaFilePath).sendToTarget();
                return;
            }
            out = new FileOutputStream(filePathTemp, true);
            in = response.getEntity().getContent();

            byte buffer[] = new byte[1024 * 4];
            int downLength = 0;
            int position = in.read(buffer);
            long time = System.currentTimeMillis();

            while (position > 0 && isAlive()) {
                if (interrupted()) {
                    throw new InterruptedException();
                }
                downLength += position;
                out.write(buffer, 0, position);
                if (System.currentTimeMillis() - time > 500) {// 500ms?
                    time = System.currentTimeMillis();
                    downloadHandler
                            .obtainMessage(PROGRESS_MSG, (int) (((float) downLength) / mContentSize * 100), 0)
                            .sendToTarget();
                }
                position = in.read(buffer);
            }
            out.flush();
            out.close();

        }
    }

    /**
     * handler
     *
     * @author emilyu
     *
     */
    private static class DownloadHandler extends Handler {

        private WeakReference<ApkDownloadUtil> utilReference = null;

        public DownloadHandler(ApkDownloadUtil apkDownloadUtil) {
            utilReference = new WeakReference<ApkDownloadUtil>(apkDownloadUtil);
        }

        @Override
        public void handleMessage(Message msg) {
            ApkDownloadUtil apkDownloadUtil = utilReference.get();
            switch (msg.what) {
            case ApkDownloadUtil.PROGRESS_MSG:
                apkDownloadUtil.mBuilder.setProgress(100, msg.arg1, false);
                apkDownloadUtil.mNotifyManager.notify(apkDownloadUtil.appName.hashCode(),
                        apkDownloadUtil.mBuilder.build());
                if (apkDownloadUtil.downloadListener != null) {
                    apkDownloadUtil.downloadListener.onDownloadProgress(msg.arg1);
                }
                break;
            case ApkDownloadUtil.DOWNLOAD_SUCCESS_MSG:
                File src = new File((String) msg.obj);
                //??
                if (src.length() != apkDownloadUtil.mContentSize) {
                    apkDownloadUtil.startDownload(false);
                    Toaster.show(AcademyApplication.getInstance(), R.string.download_fail_and_restart);
                    return;
                }
                installBundledApps(new File((String) msg.obj));
                apkDownloadUtil.mNotifyManager.cancel(apkDownloadUtil.appName.hashCode());
                apkDownloadUtil.downloadThread = null;
                if (apkDownloadUtil.downloadListener != null) {
                    apkDownloadUtil.downloadListener.onDownloadSucess();
                }
                break;
            case ApkDownloadUtil.DOWNLOAD_FAIL_MSG:
                Exception e = (Exception) msg.obj;
                if (e instanceof InterruptedIOException || e instanceof SocketException
                        || e instanceof UnknownHostException) {
                    Toaster.show(AcademyApplication.getInstance(), R.string.download_fail_by_network);
                } else if (e instanceof IOException || e instanceof FileNotFoundException) {
                    Toaster.show(AcademyApplication.getInstance(), R.string.download_fail_by_sdcard);
                } else {
                    Toaster.show(AcademyApplication.getInstance(), R.string.download_fail_retry);
                }
                apkDownloadUtil.mNotifyManager.cancel(apkDownloadUtil.appName.hashCode());
                apkDownloadUtil.downloadThread = null;
                if (apkDownloadUtil.downloadListener != null) {
                    apkDownloadUtil.downloadListener.onDownloadFail();
                }
                break;
            case ApkDownloadUtil.DOWNLOAD_CANCEL_MSG:
                apkDownloadUtil.mNotifyManager.cancel(apkDownloadUtil.appName.hashCode());
                apkDownloadUtil.downloadThread = null;
                if (apkDownloadUtil.downloadListener != null) {
                    apkDownloadUtil.downloadListener.onDownloadCancel();
                }
                break;
            default:
                break;
            }
        }
    }

    public interface ApkDownloadListener {
        /**
         * ??
         */
        public void onDownloadSucess();

        /**
         * ?
         */
        public void onDownloadFail();

        /**
         * ???
         */
        public void onDownloadCancel();

        /**
         * @param position
         * ?
         */
        public void onDownloadProgress(int position);
    }
}