// It could be part of the AIDL Interface but at the moment no Activity uses it directly
  public void addIncompleteDownloads() {
    Log.i(AnkiDroidApp.TAG, "DownloadManagerService - Adding incomplete downloads:");

    File dir = new File(mDestination + "/tmp/");
    File[] fileList = dir.listFiles(new IncompleteDownloadsFilter());

    if (fileList != null) {
      for (File file : fileList) {
        String filename = file.getName();
        Log.i(AnkiDroidApp.TAG, "Filename = " + filename);

        // Personal decks
        if (filename.endsWith(".anki.tmp")) {
          Download download =
              new Download(filename.substring(0, filename.length() - ".anki.tmp".length()));
          download.setDownloaded(file.length());
          mPersonalDeckDownloads.add(download);
        }
        // Shared decks
        else if (filename.endsWith(".shared.zip.tmp")) {
          filename = filename.substring(0, filename.length() - ".shared.zip.tmp".length());
          int lastDotPosition = filename.lastIndexOf(".");
          String identifier = filename.substring(lastDotPosition + 1, filename.length());
          String title = filename.substring(0, lastDotPosition);

          SharedDeckDownload download = new SharedDeckDownload(Integer.parseInt(identifier), title);
          download.setDownloaded(file.length());
          mSharedDeckDownloads.add(download);
        }
        // Shared but not totally updated decks
        else if (filename.endsWith(".anki.updating")) {
          String title = filename.substring(0, filename.length() - ".anki.updating".length());
          SharedDeckDownload download = new SharedDeckDownload(title);

          SharedPreferences pref = PrefSettings.getSharedPrefs(getBaseContext());
          String pausedPref =
              "paused:" + mDestination + "/tmp/" + download.getTitle() + ".anki.updating";
          if (pref.getBoolean(pausedPref, false)) {
            download.setStatus(SharedDeckDownload.STATUS_PAUSED);
          } else {
            download.setStatus(SharedDeckDownload.STATUS_UPDATING);
          }
          mSharedDeckDownloads.add(download);
        }
      }
      notifyObservers();
    }
    // If no decks were added, stop the service
    stopIfFinished();
  }
 @Override
 protected void onPostExecute(Download download) {
   Log.i(AnkiDroidApp.TAG, "on post execute");
   if (download.getStatus() == Download.STATUS_COMPLETE) {
     showNotification(download.getTitle());
   } else if (download.getStatus() == Download.STATUS_ERROR) {
     // Error - Clean up
     Log.i(AnkiDroidApp.TAG, "deleting file");
     new File(mDestination + "/tmp/" + download.getTitle() + ".anki.tmp").delete();
     Log.e(AnkiDroidApp.TAG, "Error while downloading personal deck.");
   }
   mPersonalDeckDownloads.remove(download);
   notifyPersonalDeckObservers();
   stopIfFinished();
 }
    @Override
    protected Download doInBackground(Download... downloads) {
      Download download = downloads[0];

      URL url;
      RandomAccessFile file = null;
      InflaterInputStream iis = null;

      try {
        url = new URL(AnkiDroidProxy.SYNC_URL + "fulldown");
        HttpURLConnection connection = (HttpURLConnection) url.openConnection();

        connection.setDoInput(true);
        connection.setDoOutput(true);
        connection.setUseCaches(false);
        connection.setRequestMethod("POST");
        // FIXME: The connection always returns all bytes, regardless of what is indicated in range
        // property, so
        // resuming downloads of personal decks is not possible at the moment
        // Fix this when the connection is fixed on AnkiOnline
        // Log.i(AnkiDroidApp.TAG, "Range = " + download.getDownloaded());
        // connection.setRequestProperty("Range","bytes=" + download.getDownloaded() + "-");
        connection.setRequestProperty("Content-type", "application/x-www-form-urlencoded");

        connection.connect();

        long startTime = System.currentTimeMillis();

        DataOutputStream ds = new DataOutputStream(connection.getOutputStream());
        String data =
            "p="
                + URLEncoder.encode(mPassword, "UTF-8")
                + "&u="
                + URLEncoder.encode(mUsername, "UTF-8")
                + "&d="
                + URLEncoder.encode(download.getTitle(), "UTF-8");
        ds.writeBytes(data);
        Log.i(AnkiDroidApp.TAG, "Closing streams...");
        ds.flush();
        ds.close();

        // Make sure response code is in the 200 range.
        if (connection.getResponseCode() / 100 != 2) {
          download.setStatus(Download.STATUS_ERROR);
          publishProgress();
        } else {
          download.setStatus(Download.STATUS_DOWNLOADING);
          publishProgress();
        }

        Log.i(AnkiDroidApp.TAG, "Response code = " + connection.getResponseCode());

        // Check for valid content length.
        Log.i(AnkiDroidApp.TAG, "Connection length = " + connection.getContentLength());
        int contentLength = connection.getContentLength();
        if (contentLength < 1) {
          Log.i(AnkiDroidApp.TAG, "Content Length = -1");
          // download.setStatus(Download.ERROR);
        }

        // Set the size for this download if it hasn't been already set
        if (download.getSize() == -1 && contentLength != -1) {
          download.setSize(contentLength);
          Log.i(AnkiDroidApp.TAG, "File size = " + contentLength);
        }

        // Open file
        file =
            new RandomAccessFile(mDestination + "/tmp/" + download.getTitle() + ".anki.tmp", "rw");
        // FIXME: Uncomment next line when the connection is fixed on AnkiOnline (= when the
        // connection only
        // returns the bytes specified on the range property)
        // file.seek(download.getDownloaded());

        iis = new InflaterInputStream(connection.getInputStream());

        while (download.getStatus() == Download.STATUS_DOWNLOADING) {
          // Size buffer according to how much of the file is left to download
          Log.v(AnkiDroidApp.TAG, "Downloading... " + download.getDownloaded());
          byte[] buffer;
          // if (size - downloaded > MAX_BUFFER_SIZE) {
          buffer = new byte[MAX_BUFFER_SIZE];
          // } else {
          // buffer = new byte[size - downloaded];
          // }

          // Read from server into buffer.
          int read = iis.read(buffer);
          if (read == -1) {
            break;
          }

          // Write buffer to file.
          file.write(buffer, 0, read);
          download.setDownloaded(download.getDownloaded() + read);
          publishProgress();
        }

        if (download.getStatus() == Download.STATUS_DOWNLOADING) {
          // Change status to complete if this point was reached because downloading has finished
          download.setStatus(Download.STATUS_COMPLETE);
          new File(mDestination + "/tmp/" + download.getTitle() + ".anki.tmp")
              .renameTo(new File(mDestination + "/" + download.getTitle() + ".anki"));
          long finishTime = System.currentTimeMillis();
          Log.i(AnkiDroidApp.TAG, "Finished in " + ((finishTime - startTime) / 1000) + " seconds!");
          Log.i(AnkiDroidApp.TAG, "Downloaded = " + download.getDownloaded());
        } else if (download.getStatus() == Download.STATUS_CANCELLED) {
          // Cancelled download, clean up
          new File(mDestination + "/tmp/" + download.getTitle() + ".anki.tmp").delete();
          Log.i(AnkiDroidApp.TAG, "Download cancelled.");
        }
        publishProgress();
        connection.disconnect();
      } catch (Exception e) {
        e.printStackTrace();
        Log.i(AnkiDroidApp.TAG, "Exception Error = " + e.getMessage());
        download.setStatus(Download.STATUS_ERROR);
        publishProgress();
      } finally {
        Log.i(AnkiDroidApp.TAG, "finally");
        // Close file
        if (file != null) {
          try {
            Log.i(AnkiDroidApp.TAG, "closing file");
            file.close();
          } catch (Exception e) {
            Log.i(AnkiDroidApp.TAG, "exception closing file");
          }
        }

        // Close connection to server
        if (iis != null) {
          try {
            Log.i(AnkiDroidApp.TAG, "closing iis");
            iis.close();
            Log.i(AnkiDroidApp.TAG, "closed iis");
          } catch (Exception e) {
            Log.i(AnkiDroidApp.TAG, "exception closing iis: " + e.getMessage());
          }
        }
      }

      return download;
    }