Java tutorial
/** * Copyright (c) 2017 Giovanni Terlingen * <p/> * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * <p/> * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * <p/> * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. **/ package com.giovanniterlingen.windesheim.controllers; import android.app.Activity; import android.app.DownloadManager; import android.content.ActivityNotFoundException; import android.content.Context; import android.content.Intent; import android.database.Cursor; import android.net.Uri; import android.os.AsyncTask; import android.os.Environment; import android.support.v4.content.FileProvider; import android.text.format.Formatter; import android.util.SparseArray; import com.giovanniterlingen.windesheim.ApplicationLoader; import com.giovanniterlingen.windesheim.NotificationCenter; import com.giovanniterlingen.windesheim.R; import com.giovanniterlingen.windesheim.models.Download; import com.giovanniterlingen.windesheim.view.NatschoolActivity; import java.io.File; import java.net.URI; /** * A schedule app for students and teachers of Windesheim * * @author Giovanni Terlingen * @author Thomas Visch */ public class DownloadController extends AsyncTask<String, Object, String> implements NotificationCenter.NotificationCenterDelegate { private final Activity activity; private final String url; private final int studyRouteId; private final int contentId; private final int adapterPosition; private DownloadManager downloadManager; private long currentDownloadId = -1; static final SparseArray<Download> activeDownloads = new SparseArray<>(); public DownloadController(Activity activity, String url, int studyRouteId, int contentId, int adapterPosition) { this.activity = activity; this.url = url; this.studyRouteId = studyRouteId; this.contentId = contentId; this.adapterPosition = adapterPosition; } @Override protected void onPreExecute() { super.onPreExecute(); NotificationCenter.getInstance().addObserver(this, NotificationCenter.downloadCancelled); NotificationCenter.getInstance().postNotificationName(NotificationCenter.downloadPending, studyRouteId, adapterPosition, contentId); } @Override protected String doInBackground(final String... strings) { try { activeDownloads.put(contentId, new Download()); int lastSlash = url.lastIndexOf('/'); String fileName = url.substring(lastSlash + 1); File directory = Environment.getExternalStoragePublicDirectory( ApplicationLoader.applicationContext.getResources().getString(R.string.app_name)); if (!directory.exists()) { directory.mkdirs(); } final String encodedUrl = new URI("https", "elo.windesheim.nl", url, null).toString(); downloadManager = (DownloadManager) activity.getSystemService(Context.DOWNLOAD_SERVICE); DownloadManager.Request request = new DownloadManager.Request(Uri.parse(encodedUrl)); request.addRequestHeader("Cookie", new CookieController().getNatSchoolCookie()).setTitle(fileName) .setDescription(activity.getResources().getString(R.string.downloading)) .setDestinationInExternalPublicDir(File.separator + ApplicationLoader.applicationContext.getResources().getString(R.string.app_name), fileName); currentDownloadId = downloadManager.enqueue(request); while (true) { if (isCancelled()) { return "cancelled"; } DownloadManager.Query query = new DownloadManager.Query(); query.setFilterById(currentDownloadId); Cursor cursor = downloadManager.query(query); if (cursor.getCount() == 0) { return "cancelled"; } cursor.moveToFirst(); int status = cursor.getInt(cursor.getColumnIndex(DownloadManager.COLUMN_STATUS)); if (status == DownloadManager.STATUS_SUCCESSFUL || status == DownloadManager.STATUS_FAILED) { break; } if (status == DownloadManager.STATUS_PAUSED || status == DownloadManager.STATUS_PENDING) { // paused, reset download state to pending activeDownloads.put(contentId, new Download()); NotificationCenter.getInstance().postNotificationName(NotificationCenter.downloadPending, studyRouteId, adapterPosition, contentId); Thread.sleep(100); continue; } long downloaded = cursor .getLong(cursor.getColumnIndex(DownloadManager.COLUMN_BYTES_DOWNLOADED_SO_FAR)); long total = cursor.getLong(cursor.getColumnIndex(DownloadManager.COLUMN_TOTAL_SIZE_BYTES)); cursor.close(); if (total > 0 && downloaded > 0) { int progress = (int) (downloaded * 100 / total); String s = Formatter.formatFileSize(activity, downloaded) + "/" + Formatter.formatFileSize(activity, total); activeDownloads.get(contentId).setProgress(progress); activeDownloads.get(contentId).setProgressString(s); publishProgress(progress, s); } Thread.sleep(100); } return new File(directory, fileName).getAbsolutePath(); } catch (SecurityException e) { return "permission"; } catch (Exception e) { return null; } } @Override protected void onProgressUpdate(Object... progress) { super.onProgressUpdate(progress); NotificationCenter.getInstance().postNotificationName(NotificationCenter.downloadUpdated, studyRouteId, adapterPosition, contentId, progress[0], progress[1]); } @Override protected void onCancelled(String s) { super.onCancelled(s); if (currentDownloadId > -1 && downloadManager != null) { downloadManager.remove(currentDownloadId); } onPostExecute("cancelled"); } @Override protected void onPostExecute(final String result) { activeDownloads.remove(contentId); NotificationCenter.getInstance().removeObserver(this, NotificationCenter.downloadCancelled); NotificationCenter.getInstance().postNotificationName(NotificationCenter.downloadFinished, studyRouteId, adapterPosition, contentId); if ("permission".equals(result)) { ((NatschoolActivity) activity).noPermission(); return; } if ("cancelled".equals(result)) { ((NatschoolActivity) activity).downloadCanceled(); return; } if (result != null) { Uri uri; Intent target = new Intent(Intent.ACTION_VIEW); if (android.os.Build.VERSION.SDK_INT >= 24) { uri = FileProvider.getUriForFile(activity, "com.giovanniterlingen.windesheim.provider", new File(result)); target.setFlags(Intent.FLAG_ACTIVITY_NO_HISTORY | Intent.FLAG_GRANT_READ_URI_PERMISSION); } else { uri = Uri.fromFile(new File(result)); target.setFlags(Intent.FLAG_ACTIVITY_NO_HISTORY); } String extension = android.webkit.MimeTypeMap.getFileExtensionFromUrl(uri.toString()); String mimetype = android.webkit.MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension); target.setDataAndType(uri, mimetype); try { activity.startActivity(target); } catch (ActivityNotFoundException e) { ((NatschoolActivity) activity).noSupportedApp(); } } } @Override public void didReceivedNotification(int id, Object... args) { if (id == NotificationCenter.downloadCancelled && (int) args[0] == contentId) { this.cancel(true); } } }