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
17package com.googlecode.android_scripting;
18
19import android.app.ProgressDialog;
20import android.content.Context;
21import android.content.DialogInterface;
22import android.os.AsyncTask;
23
24
25import com.googlecode.android_scripting.exception.Sl4aException;
26
27import java.io.File;
28import java.io.FileNotFoundException;
29import java.io.FileOutputStream;
30import java.io.IOException;
31import java.io.OutputStream;
32import java.net.MalformedURLException;
33import java.net.URL;
34import java.net.URLConnection;
35
36/**
37 * AsyncTask for extracting ZIP files.
38 *
39 */
40public 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
52    private ProgressReportingOutputStream(File f) throws FileNotFoundException {
53      super(f);
54    }
55
56    @Override
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
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
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
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
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
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
139  protected void onCancelled() {
140    if (mDialog != null) {
141      mDialog.setTitle("Download cancelled.");
142    }
143  }
144
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