1 /*
2  * Copyright (C) 2017 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.googlecode.android_scripting;
18 
19 import android.app.ProgressDialog;
20 import android.content.Context;
21 import android.content.DialogInterface;
22 import android.os.AsyncTask;
23 
24 
25 import com.googlecode.android_scripting.exception.Sl4aException;
26 
27 import java.io.File;
28 import java.io.FileNotFoundException;
29 import java.io.FileOutputStream;
30 import java.io.IOException;
31 import java.io.OutputStream;
32 import java.net.MalformedURLException;
33 import java.net.URL;
34 import java.net.URLConnection;
35 
36 /**
37  * AsyncTask for extracting ZIP files.
38  *
39  */
40 public class UrlDownloaderTask extends AsyncTask<Void, Integer, Long> {
41 
42   private final URL mUrl;
43   private final File mFile;
44   private final ProgressDialog mDialog;
45 
46   private Throwable mException;
47   private OutputStream mProgressReportingOutputStream;
48 
49   private final class ProgressReportingOutputStream extends FileOutputStream {
50     private int mProgress = 0;
51 
ProgressReportingOutputStream(File f)52     private ProgressReportingOutputStream(File f) throws FileNotFoundException {
53       super(f);
54     }
55 
56     @Override
write(byte[] buffer, int offset, int count)57     public void write(byte[] buffer, int offset, int count) throws IOException {
58       super.write(buffer, offset, count);
59       mProgress += count;
60       publishProgress(mProgress);
61     }
62   }
63 
UrlDownloaderTask(String url, String out, Context context)64   public UrlDownloaderTask(String url, String out, Context context) throws MalformedURLException {
65     super();
66     if (context != null) {
67       mDialog = new ProgressDialog(context);
68     } else {
69       mDialog = null;
70     }
71     mUrl = new URL(url);
72     String fileName = new File(mUrl.getFile()).getName();
73     mFile = new File(out, fileName);
74   }
75 
76   @Override
onPreExecute()77   protected void onPreExecute() {
78     Log.v("Downloading " + mUrl);
79     if (mDialog != null) {
80       mDialog.setTitle("Downloading");
81       mDialog.setMessage(mFile.getName());
82       // mDialog.setIndeterminate(true);
83       mDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
84       mDialog.setOnCancelListener(new DialogInterface.OnCancelListener() {
85         @Override
86         public void onCancel(DialogInterface dialog) {
87           cancel(true);
88         }
89       });
90       mDialog.show();
91     }
92   }
93 
94   @Override
doInBackground(Void... params)95   protected Long doInBackground(Void... params) {
96     try {
97       return download();
98     } catch (Exception e) {
99       if (mFile.exists()) {
100         // Clean up bad downloads.
101         mFile.delete();
102       }
103       mException = e;
104       return null;
105     }
106   }
107 
108   @Override
onProgressUpdate(Integer... progress)109   protected void onProgressUpdate(Integer... progress) {
110     if (mDialog == null) {
111       return;
112     }
113     if (progress.length > 1) {
114       int contentLength = progress[1];
115       if (contentLength == -1) {
116         mDialog.setIndeterminate(true);
117       } else {
118         mDialog.setMax(contentLength);
119       }
120     } else {
121       mDialog.setProgress(progress[0].intValue());
122     }
123   }
124 
125   @Override
onPostExecute(Long result)126   protected void onPostExecute(Long result) {
127     if (mDialog != null && mDialog.isShowing()) {
128       mDialog.dismiss();
129     }
130     if (isCancelled()) {
131       return;
132     }
133     if (mException != null) {
134       Log.e("Download failed.", mException);
135     }
136   }
137 
138   @Override
onCancelled()139   protected void onCancelled() {
140     if (mDialog != null) {
141       mDialog.setTitle("Download cancelled.");
142     }
143   }
144 
download()145   private long download() throws Exception {
146     URLConnection connection = null;
147     try {
148       connection = mUrl.openConnection();
149     } catch (IOException e) {
150       throw new Sl4aException("Cannot open URL: " + mUrl, e);
151     }
152 
153     int contentLength = connection.getContentLength();
154 
155     if (mFile.exists() && contentLength == mFile.length()) {
156       Log.v("Output file already exists. Skipping download.");
157       return 0l;
158     }
159 
160     try {
161       mProgressReportingOutputStream = new ProgressReportingOutputStream(mFile);
162     } catch (FileNotFoundException e) {
163       throw new Sl4aException(e);
164     }
165 
166     publishProgress(0, contentLength);
167 
168     int bytesCopied = IoUtils.copy(connection.getInputStream(), mProgressReportingOutputStream);
169     if (bytesCopied != contentLength && contentLength != -1) {
170       throw new IOException("Download incomplete: " + bytesCopied + " != " + contentLength);
171     }
172     mProgressReportingOutputStream.close();
173     Log.v("Download completed successfully.");
174     return bytesCopied;
175   }
176 }
177