Android Open Source - HockeySDK-Android Attachment Downloader






From Project

Back to project page HockeySDK-Android.

License

The source code is released under:

Apache License

If you think the Android project HockeySDK-Android listed in this page is inappropriate, such as containing malicious code/tools or violating the copyright, please email info at java2s dot com, thanks.

Java Source Code

package net.hockeyapp.android.tasks;
/*w  ww . j  a v  a 2 s . co  m*/
import android.graphics.Bitmap;
import android.os.AsyncTask;
import android.os.Build;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import net.hockeyapp.android.Constants;
import net.hockeyapp.android.objects.FeedbackAttachment;
import net.hockeyapp.android.utils.AsyncTaskUtils;
import net.hockeyapp.android.utils.ImageUtils;
import net.hockeyapp.android.views.AttachmentView;

import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLConnection;
import java.util.LinkedList;
import java.util.Queue;

/**
 * <h3>Description</h3>
 * 
 * Singleton class to queue attachment downloads.
 * 
 * <h3>License</h3>
 * 
 * <pre>
 * Copyright (c) 2011-2014 Bit Stadium GmbH
 * 
 * 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:
 * 
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 * 
 * 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.
 * </pre>
 *
 * @author Patrick Eschenbach
 */
public class AttachmentDownloader {

  /**
   * AttachmentDownloaderHolder is loaded on the first execution of AttachmentDownloader.getInstance()
   * or the first access to FeedbackParserHolder.INSTANCE, not before.
   */
  private static class AttachmentDownloaderHolder {
    public static final AttachmentDownloader INSTANCE = new AttachmentDownloader();
  }

  public static AttachmentDownloader getInstance() {
    return AttachmentDownloaderHolder.INSTANCE;
  }

  private Queue<DownloadJob> queue;

  private boolean downloadRunning;

  private AttachmentDownloader() {
    this.queue = new LinkedList<DownloadJob>();
    this.downloadRunning = false;
  }

  public void download(FeedbackAttachment feedbackAttachment, AttachmentView attachmentView) {
    queue.add(new DownloadJob(feedbackAttachment, attachmentView));
    downloadNext();
  }

  private void downloadNext() {
    if (downloadRunning) {
      return;
    }

    DownloadJob downloadJob = queue.peek();
    if (downloadJob != null) {
      DownloadTask downloadTask = new DownloadTask(downloadJob, new Handler() {
        @Override
        public void handleMessage(Message msg) {
          final DownloadJob retryCandidate = queue.poll();
          if (!retryCandidate.isSuccess() && retryCandidate.consumeRetry()) {
            this.postDelayed(new Runnable() {
              @Override
              public void run() {
                queue.add(retryCandidate);
                downloadNext();
              }
            }, 3000);
          }
          downloadRunning = false;
          downloadNext();
        }
      });
      downloadRunning = true;
      AsyncTaskUtils.execute(downloadTask);
    }
  }

  /**
   * Holds everything needed for a download process.
   */
  private static class DownloadJob {

    private final FeedbackAttachment feedbackAttachment;
    private final AttachmentView attachmentView;
    private boolean success;
    private int remainingRetries;

    private DownloadJob(FeedbackAttachment feedbackAttachment, AttachmentView attachmentView) {
      this.feedbackAttachment = feedbackAttachment;
      this.attachmentView = attachmentView;
      this.success = false;
      this.remainingRetries = 2;
    }

    public FeedbackAttachment getFeedbackAttachment() {
      return feedbackAttachment;
    }

    public AttachmentView getAttachmentView() {
      return attachmentView;
    }

    public boolean isSuccess() { return success; }

    public void setSuccess(boolean success) { this.success = success; }

    public boolean hasRetry() {
      return remainingRetries > 0;
    }

    public boolean consumeRetry() {
      return --remainingRetries < 0 ? false : true;
    }
  }

  /**
   * The AsyncTask that downloads the image and the updates the view.
   */
  private static class DownloadTask extends AsyncTask<Void, Integer, Boolean> {

    private final DownloadJob downloadJob;

    private final Handler handler;

    private File dropFolder;

    private Bitmap bitmap;

    private int bitmapOrientation;

    public DownloadTask(DownloadJob downloadJob, Handler handler) {
      this.downloadJob = downloadJob;
      this.handler = handler;
      this.dropFolder = Constants.getHockeyAppStorageDir();
      this.bitmap = null;
      this.bitmapOrientation = ImageUtils.ORIENTATION_PORTRAIT; // default
    }

    @Override
    protected void onPreExecute() {
    }

    @Override
    protected Boolean doInBackground(Void... args) {
      FeedbackAttachment attachment = downloadJob.getFeedbackAttachment();

      if (attachment.isAvailableInCache()) {
        Log.e(Constants.TAG, "Cached...");
        loadImageThumbnail();
        return true;

      } else {
        Log.e(Constants.TAG, "Downloading...");
        boolean success = downloadAttachment(attachment.getUrl(), attachment.getCacheId());
        if (success) {
          loadImageThumbnail();
        }
        return success;
      }
    }

    @Override
    protected void onProgressUpdate(Integer... values) {
    }

    @Override
    protected void onPostExecute(Boolean success) {
      AttachmentView attachmentView = downloadJob.getAttachmentView();
      downloadJob.setSuccess(success);

      if (success) {
        attachmentView.setImage(bitmap, bitmapOrientation);

      } else {
        if (!downloadJob.hasRetry()) {
          attachmentView.signalImageLoadingError();
        }
      }

      handler.sendEmptyMessage(0);
    }

    private void loadImageThumbnail() {
      try {
        String filename = downloadJob.getFeedbackAttachment().getCacheId();
        AttachmentView attachmentView = downloadJob.getAttachmentView();

        bitmapOrientation = ImageUtils.determineOrientation(new File(dropFolder, filename));
        int width  = bitmapOrientation == ImageUtils.ORIENTATION_LANDSCAPE ?
            attachmentView.getWidthLandscape() : attachmentView.getWidthPortrait();
        int height = bitmapOrientation == ImageUtils.ORIENTATION_LANDSCAPE ?
            attachmentView.getMaxHeightLandscape() : attachmentView.getMaxHeightPortrait();

        bitmap = ImageUtils.decodeSampledBitmap(new File(dropFolder, filename), width, height);

      } catch(IOException e) {
        e.printStackTrace();
        bitmap = null;
      }
    }

    private boolean downloadAttachment(String urlString, String filename) {
      try {
        URL url = new URL(urlString);
        URLConnection connection = createConnection(url);
        connection.connect();

        int lengthOfFile = connection.getContentLength();
        String status = connection.getHeaderField("Status");

        if (status != null) {
          if (!status.startsWith("200")) {
            return false;
          }
        }

        File file = new File(dropFolder, filename);
        InputStream input = new BufferedInputStream(connection.getInputStream());
        OutputStream output = new FileOutputStream(file);

        byte data[] = new byte[1024];
        int count = 0;
        long total = 0;
        while ((count = input.read(data)) != -1) {
          total += count;
          publishProgress((int)(total * 100 / lengthOfFile));
          output.write(data, 0, count);
        }

        output.flush();
        output.close();
        input.close();
        return (total > 0);

      } catch (Exception e) {
        e.printStackTrace();
        return false;
      }
    }

    private URLConnection createConnection(URL url) throws IOException {
      HttpURLConnection connection = (HttpURLConnection) url.openConnection();
      connection.addRequestProperty("User-Agent", "HockeySDK/Android");
      connection.setInstanceFollowRedirects(true);
      /* connection bug workaround for SDK<=2.x */
      if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.GINGERBREAD) {
        connection.setRequestProperty("connection", "close");
      }
      return connection;
    }
  }
}




Java Source Code List

net.hockeyapp.android.Constants.java
net.hockeyapp.android.CrashManagerListener.java
net.hockeyapp.android.CrashManager.java
net.hockeyapp.android.ExceptionHandler.java
net.hockeyapp.android.ExpiryInfoActivity.java
net.hockeyapp.android.FeedbackActivityInterface.java
net.hockeyapp.android.FeedbackActivity.java
net.hockeyapp.android.FeedbackManagerListener.java
net.hockeyapp.android.FeedbackManager.java
net.hockeyapp.android.LocaleManager.java
net.hockeyapp.android.LoginActivity.java
net.hockeyapp.android.LoginManagerListener.java
net.hockeyapp.android.LoginManager.java
net.hockeyapp.android.PaintActivity.java
net.hockeyapp.android.StringListener.java
net.hockeyapp.android.Strings.java
net.hockeyapp.android.Tracking.java
net.hockeyapp.android.UpdateActivityInterface.java
net.hockeyapp.android.UpdateActivity.java
net.hockeyapp.android.UpdateFragment.java
net.hockeyapp.android.UpdateInfoListener.java
net.hockeyapp.android.UpdateManagerListener.java
net.hockeyapp.android.UpdateManager.java
net.hockeyapp.android.adapters.MessagesAdapter.java
net.hockeyapp.android.listeners.DownloadFileListener.java
net.hockeyapp.android.listeners.SendFeedbackListener.java
net.hockeyapp.android.objects.ErrorObject.java
net.hockeyapp.android.objects.FeedbackAttachment.java
net.hockeyapp.android.objects.FeedbackMessage.java
net.hockeyapp.android.objects.FeedbackResponse.java
net.hockeyapp.android.objects.Feedback.java
net.hockeyapp.android.tasks.AttachmentDownloader.java
net.hockeyapp.android.tasks.CheckUpdateTaskWithUI.java
net.hockeyapp.android.tasks.CheckUpdateTask.java
net.hockeyapp.android.tasks.DownloadFileTask.java
net.hockeyapp.android.tasks.GetFileSizeTask.java
net.hockeyapp.android.tasks.LoginTask.java
net.hockeyapp.android.tasks.ParseFeedbackTask.java
net.hockeyapp.android.tasks.SendFeedbackTask.java
net.hockeyapp.android.utils.AsyncTaskUtils.java
net.hockeyapp.android.utils.Base64.java
net.hockeyapp.android.utils.ConnectionManager.java
net.hockeyapp.android.utils.DeviceUtils.java
net.hockeyapp.android.utils.FeedbackParser.java
net.hockeyapp.android.utils.ImageUtils.java
net.hockeyapp.android.utils.PrefsUtil.java
net.hockeyapp.android.utils.SimpleMultipartEntity.java
net.hockeyapp.android.utils.UiThreadUtil.java
net.hockeyapp.android.utils.Util.java
net.hockeyapp.android.utils.VersionCache.java
net.hockeyapp.android.utils.VersionHelper.java
net.hockeyapp.android.utils.ViewHelper.java
net.hockeyapp.android.views.AttachmentListView.java
net.hockeyapp.android.views.AttachmentView.java
net.hockeyapp.android.views.ExpiryInfoView.java
net.hockeyapp.android.views.FeedbackMessageView.java
net.hockeyapp.android.views.FeedbackView.java
net.hockeyapp.android.views.LoginView.java
net.hockeyapp.android.views.PaintView.java
net.hockeyapp.android.views.UpdateView.java