/**
   * This method should be called in the prepare-methods of menus. It changes the visibility of the
   * menu items depending on a FeedItem's attributes.
   *
   * @param mi An instance of MenuInterface that the method uses to change a MenuItem's visibility
   * @param selectedItem The FeedItem for which the menu is supposed to be prepared
   * @param showExtendedMenu True if MenuItems that let the user share information about the
   *     FeedItem and visit its website should be set visible. This parameter should be set to false
   *     if the menu space is limited.
   * @param queueAccess Used for testing if the queue contains the selected item
   * @return Returns true if selectedItem is not null.
   */
  public static boolean onPrepareMenu(
      MenuInterface mi, FeedItem selectedItem, boolean showExtendedMenu, QueueAccess queueAccess) {
    if (selectedItem == null) {
      return false;
    }
    DownloadRequester requester = DownloadRequester.getInstance();
    boolean hasMedia = selectedItem.getMedia() != null;
    boolean downloaded = hasMedia && selectedItem.getMedia().isDownloaded();
    boolean downloading = hasMedia && requester.isDownloadingFile(selectedItem.getMedia());
    boolean notLoadedAndNotLoading = hasMedia && (!downloaded) && (!downloading);
    boolean isPlaying = hasMedia && selectedItem.getState() == FeedItem.State.PLAYING;

    FeedItem.State state = selectedItem.getState();

    if (!isPlaying) {
      mi.setItemVisibility(R.id.skip_episode_item, false);
    }
    if (!downloaded || isPlaying) {
      mi.setItemVisibility(R.id.play_item, false);
      mi.setItemVisibility(R.id.remove_item, false);
    }
    if (!notLoadedAndNotLoading) {
      mi.setItemVisibility(R.id.download_item, false);
    }
    if (!(notLoadedAndNotLoading | downloading) | isPlaying) {
      mi.setItemVisibility(R.id.stream_item, false);
    }
    if (!downloading) {
      mi.setItemVisibility(R.id.cancel_download_item, false);
    }

    boolean isInQueue = queueAccess.contains(selectedItem.getId());
    if (!isInQueue || isPlaying) {
      mi.setItemVisibility(R.id.remove_from_queue_item, false);
    }
    if (!(!isInQueue && selectedItem.getMedia() != null)) {
      mi.setItemVisibility(R.id.add_to_queue_item, false);
    }
    if (!showExtendedMenu || selectedItem.getLink() == null) {
      mi.setItemVisibility(R.id.share_link_item, false);
    }

    if (!AppConfig.DEBUG
        || !(state == FeedItem.State.IN_PROGRESS || state == FeedItem.State.READ)) {
      mi.setItemVisibility(R.id.mark_unread_item, false);
    }
    if (!(state == FeedItem.State.NEW || state == FeedItem.State.IN_PROGRESS)) {
      mi.setItemVisibility(R.id.mark_read_item, false);
    }

    if (!showExtendedMenu || selectedItem.getLink() == null) {
      mi.setItemVisibility(R.id.visit_website_item, false);
    }

    if (selectedItem.getPaymentLink() == null || !selectedItem.getFlattrStatus().flattrable()) {
      mi.setItemVisibility(R.id.support_item, false);
    }
    return true;
  }
    /**
     * Waits for completed requests. Once the first request has been taken, the method will wait
     * WAIT_TIMEOUT ms longer to collect more completed requests.
     *
     * @return Collected feeds or null if the method has been interrupted during the first waiting
     *     period.
     */
    private List<Feed> collectCompletedRequests() {
      List<Feed> results = new LinkedList<Feed>();
      DownloadRequester requester = DownloadRequester.getInstance();
      int tasks = 0;

      try {
        DownloadRequest request = completedRequests.take();
        parserService.submit(new FeedParserTask(request));
        tasks++;
      } catch (InterruptedException e) {
        return null;
      }

      tasks += pollCompletedDownloads();

      isCollectingRequests = true;

      if (requester.isDownloadingFeeds()) {
        // wait for completion of more downloads
        long startTime = System.currentTimeMillis();
        long currentTime = startTime;
        while (requester.isDownloadingFeeds() && (currentTime - startTime) < WAIT_TIMEOUT) {
          try {
            if (BuildConfig.DEBUG)
              Log.d(TAG, "Waiting for " + (startTime + WAIT_TIMEOUT - currentTime) + " ms");
            sleep(startTime + WAIT_TIMEOUT - currentTime);
          } catch (InterruptedException e) {
            if (BuildConfig.DEBUG) Log.d(TAG, "interrupted while waiting for more downloads");
            tasks += pollCompletedDownloads();
          } finally {
            currentTime = System.currentTimeMillis();
          }
        }

        tasks += pollCompletedDownloads();
      }

      isCollectingRequests = false;

      for (int i = 0; i < tasks; i++) {
        try {
          Feed f = parserService.take().get();
          if (f != null) {
            results.add(f);
          }
        } catch (InterruptedException e) {
          e.printStackTrace();

        } catch (ExecutionException e) {
          e.printStackTrace();
        }
      }

      return results;
    }
  /**
   * Updates the contents of the service's notifications. Should be called before
   * setupNotificationBuilders.
   */
  @SuppressLint("NewApi")
  private Notification updateNotifications() {
    String contentTitle = getString(R.string.download_notification_title);
    int numDownloads = requester.getNumberOfDownloads();
    String downloadsLeft;
    if (numDownloads > 0) {
      downloadsLeft = requester.getNumberOfDownloads() + getString(R.string.downloads_left);
    } else {
      downloadsLeft = getString(R.string.downloads_processing);
    }
    if (android.os.Build.VERSION.SDK_INT >= 16) {

      if (notificationBuilder != null) {

        StringBuilder bigText = new StringBuilder("");
        for (int i = 0; i < downloads.size(); i++) {
          Downloader downloader = downloads.get(i);
          final DownloadRequest request = downloader.getDownloadRequest();
          if (request.getFeedfileType() == Feed.FEEDFILETYPE_FEED) {
            if (request.getTitle() != null) {
              if (i > 0) {
                bigText.append("\n");
              }
              bigText.append("\u2022 " + request.getTitle());
            }
          } else if (request.getFeedfileType() == FeedMedia.FEEDFILETYPE_FEEDMEDIA) {
            if (request.getTitle() != null) {
              if (i > 0) {
                bigText.append("\n");
              }
              bigText.append(
                  "\u2022 " + request.getTitle() + " (" + request.getProgressPercent() + "%)");
            }
          }
        }
        notificationBuilder.setSummaryText(downloadsLeft);
        notificationBuilder.setBigContentTitle(contentTitle);
        if (bigText != null) {
          notificationBuilder.bigText(bigText.toString());
        }
        return notificationBuilder.build();
      }
    } else {
      if (notificationCompatBuilder != null) {
        notificationCompatBuilder.setContentTitle(contentTitle);
        notificationCompatBuilder.setContentText(downloadsLeft);
        return notificationCompatBuilder.build();
      }
    }
    return null;
  }
  public static boolean onMenuItemClicked(Context context, int menuItemId, FeedItem selectedItem)
      throws DownloadRequestException {
    DownloadRequester requester = DownloadRequester.getInstance();
    switch (menuItemId) {
      case R.id.skip_episode_item:
        context.sendBroadcast(new Intent(PlaybackService.ACTION_SKIP_CURRENT_EPISODE));
        break;
      case R.id.download_item:
        DBTasks.downloadFeedItems(context, selectedItem);
        break;
      case R.id.play_item:
        DBTasks.playMedia(context, selectedItem.getMedia(), true, true, false);
        break;
      case R.id.remove_item:
        DBWriter.deleteFeedMediaOfItem(context, selectedItem.getMedia().getId());
        break;
      case R.id.cancel_download_item:
        requester.cancelDownload(context, selectedItem.getMedia());
        break;
      case R.id.mark_read_item:
        DBWriter.markItemRead(context, selectedItem, true, true);
        break;
      case R.id.mark_unread_item:
        DBWriter.markItemRead(context, selectedItem, false, true);
        break;
      case R.id.add_to_queue_item:
        DBWriter.addQueueItem(context, selectedItem.getId());
        break;
      case R.id.remove_from_queue_item:
        DBWriter.removeQueueItem(context, selectedItem.getId(), true);
        break;
      case R.id.stream_item:
        DBTasks.playMedia(context, selectedItem.getMedia(), true, true, true);
        break;
      case R.id.visit_website_item:
        Uri uri = Uri.parse(selectedItem.getLink());
        context.startActivity(new Intent(Intent.ACTION_VIEW, uri));
        break;
      case R.id.support_item:
        DBTasks.flattrItemIfLoggedIn(context, selectedItem);
        break;
      case R.id.share_link_item:
        ShareUtils.shareFeedItemLink(context, selectedItem);
        break;
      default:
        return false;
    }
    // Refresh menu state

    return true;
  }
  public static boolean onMenuItemClicked(Context context, MenuItem item, FeedItem selectedItem)
      throws DownloadRequestException {
    DownloadRequester requester = DownloadRequester.getInstance();
    FeedManager manager = FeedManager.getInstance();
    switch (item.getItemId()) {
      case R.id.download_item:
        manager.downloadFeedItem(context, selectedItem);
        break;
      case R.id.play_item:
        manager.playMedia(context, selectedItem.getMedia(), true, true, false);
        break;
      case R.id.remove_item:
        manager.deleteFeedMedia(context, selectedItem.getMedia());
        break;
      case R.id.cancel_download_item:
        requester.cancelDownload(context, selectedItem.getMedia());
        break;
      case R.id.mark_read_item:
        manager.markItemRead(context, selectedItem, true, true);
        break;
      case R.id.mark_unread_item:
        manager.markItemRead(context, selectedItem, false, true);
        break;
      case R.id.add_to_queue_item:
        manager.addQueueItem(context, selectedItem);
        break;
      case R.id.remove_from_queue_item:
        manager.removeQueueItem(context, selectedItem);
        break;
      case R.id.stream_item:
        manager.playMedia(context, selectedItem.getMedia(), true, true, true);
        break;
      case R.id.visit_website_item:
        Uri uri = Uri.parse(selectedItem.getLink());
        context.startActivity(new Intent(Intent.ACTION_VIEW, uri));
        break;
      case R.id.support_item:
        new FlattrClickWorker(context, selectedItem.getPaymentLink()).executeAsync();
        break;
      case R.id.share_link_item:
        ShareUtils.shareFeedItemLink(context, selectedItem);
        break;
      default:
        return false;
    }
    // Refresh menu state

    return true;
  }
        @Override
        public void run() {
          if (BuildConfig.DEBUG) Log.d(TAG, "downloadCompletionThread was started");
          while (!isInterrupted()) {
            try {
              Downloader downloader = downloadExecutor.take().get();
              if (BuildConfig.DEBUG) Log.d(TAG, "Received 'Download Complete' - message.");
              removeDownload(downloader);
              DownloadStatus status = downloader.getResult();
              boolean successful = status.isSuccessful();

              final int type = status.getFeedfileType();
              if (successful) {
                if (type == Feed.FEEDFILETYPE_FEED) {
                  handleCompletedFeedDownload(downloader.getDownloadRequest());
                } else if (type == FeedImage.FEEDFILETYPE_FEEDIMAGE) {
                  handleCompletedImageDownload(status, downloader.getDownloadRequest());
                } else if (type == FeedMedia.FEEDFILETYPE_FEEDMEDIA) {
                  handleCompletedFeedMediaDownload(status, downloader.getDownloadRequest());
                }
              } else {
                numberOfDownloads.decrementAndGet();
                if (!status.isCancelled()) {
                  if (status.getReason() == DownloadError.ERROR_UNAUTHORIZED) {
                    postAuthenticationNotification(downloader.getDownloadRequest());
                  } else if (status.getReason() == DownloadError.ERROR_HTTP_DATA_ERROR
                      && Integer.valueOf(status.getReasonDetailed())
                          == HttpStatus.SC_REQUESTED_RANGE_NOT_SATISFIABLE) {

                    Log.d(TAG, "Requested invalid range, restarting download from the beginning");
                    FileUtils.deleteQuietly(
                        new File(downloader.getDownloadRequest().getDestination()));
                    DownloadRequester.getInstance()
                        .download(DownloadService.this, downloader.getDownloadRequest());
                  } else {
                    Log.e(TAG, "Download failed");
                    saveDownloadStatus(status);
                    handleFailedDownload(status, downloader.getDownloadRequest());
                  }
                }
                sendDownloadHandledIntent();
                queryDownloadsAsync();
              }
            } catch (InterruptedException e) {
              if (BuildConfig.DEBUG) Log.d(TAG, "DownloadCompletionThread was interrupted");
            } catch (ExecutionException e) {
              e.printStackTrace();
              numberOfDownloads.decrementAndGet();
            }
          }
          if (BuildConfig.DEBUG) Log.d(TAG, "End of downloadCompletionThread");
        }
  /** Check if there's something else to download, otherwise stop */
  void queryDownloads() {
    if (AppConfig.DEBUG) {
      Log.d(TAG, numberOfDownloads.get() + " downloads left");
    }

    if (numberOfDownloads.get() <= 0 && DownloadRequester.getInstance().hasNoDownloads()) {
      if (AppConfig.DEBUG)
        Log.d(TAG, "Number of downloads is " + numberOfDownloads.get() + ", attempting shutdown");
      stopSelf();
    } else {
      setupNotificationUpdater();
      startForeground(NOTIFICATION_ID, updateNotifications());
    }
  }
  public static boolean onPrepareMenu(Menu menu, FeedItem selectedItem) {
    FeedManager manager = FeedManager.getInstance();
    DownloadRequester requester = DownloadRequester.getInstance();
    boolean hasMedia = selectedItem.getMedia() != null;
    boolean downloaded = hasMedia && selectedItem.getMedia().isDownloaded();
    boolean downloading = hasMedia && requester.isDownloadingFile(selectedItem.getMedia());
    boolean notLoadedAndNotLoading = hasMedia && (!downloaded) && (!downloading);
    FeedItem.State state = selectedItem.getState();

    menu.findItem(R.id.play_item).setVisible(downloaded);
    menu.findItem(R.id.remove_item).setVisible(downloaded);
    menu.findItem(R.id.download_item).setVisible(notLoadedAndNotLoading);
    menu.findItem(R.id.stream_item).setVisible(notLoadedAndNotLoading | downloading);
    menu.findItem(R.id.cancel_download_item).setVisible(downloading);

    boolean isInQueue = manager.isInQueue(selectedItem);

    menu.findItem(R.id.remove_from_queue_item).setVisible(isInQueue);
    menu.findItem(R.id.add_to_queue_item).setVisible(!isInQueue && selectedItem.getMedia() != null);

    menu.findItem(R.id.share_link_item).setVisible(selectedItem.getLink() != null);

    menu.findItem(R.id.mark_unread_item)
        .setVisible(state == FeedItem.State.IN_PROGRESS || state == FeedItem.State.READ);
    menu.findItem(R.id.mark_read_item)
        .setVisible(state == FeedItem.State.NEW || state == FeedItem.State.IN_PROGRESS);

    if (selectedItem.getLink() != null) {
      menu.findItem(R.id.visit_website_item).setVisible(true);
    }

    if (selectedItem.getPaymentLink() != null) {
      menu.findItem(R.id.support_item).setVisible(true);
    }

    return true;
  }
示例#9
0
    @Override
    protected Void doInBackground(Void... params) {
      File f = null;
      if (image.getFile_url() != null) {
        f = new File(image.getFile_url());
      }
      if (image.getFile_url() != null && f.exists()) {
        BitmapFactory.Options options = new BitmapFactory.Options();
        options.inJustDecodeBounds = true;
        BitmapFactory.decodeFile(image.getFile_url(), options);
        int sampleSize = calculateSampleSize(options.outWidth, options.outHeight);

        options.inJustDecodeBounds = false;
        options.inSampleSize = sampleSize;
        decodedBitmap = BitmapFactory.decodeFile(image.getFile_url(), options);
        if (decodedBitmap == null) {
          Log.i(
              TAG,
              "Bitmap could not be decoded in custom sample size. Trying default sample size (path was "
                  + image.getFile_url()
                  + ")");
          decodedBitmap = BitmapFactory.decodeFile(image.getFile_url());
        }
        if (decodedBitmap != null) {
          bitmap =
              Bitmap.createScaledBitmap(decodedBitmap, PREFERRED_LENGTH, PREFERRED_LENGTH, false);
          if (baseLength == LENGTH_BASE_COVER) {
            addBitmapToCoverCache(image.getId(), bitmap);
          } else if (baseLength == LENGTH_BASE_THUMBNAIL) {
            addBitmapToThumbnailCache(image.getId(), bitmap);
          }
        } else {
          Log.w(TAG, "Could not load bitmap. Using default image.");
          bitmap = BitmapFactory.decodeResource(target.getResources(), R.drawable.default_cover);
        }
        if (AppConfig.DEBUG) Log.d(TAG, "Finished loading bitmaps");
      } else {
        Log.e(TAG, "FeedImage has no valid file url. Using default image");
        bitmap = BitmapFactory.decodeResource(target.getResources(), R.drawable.default_cover);
        if (image.getFile_url() != null
            && !DownloadRequester.getInstance().isDownloadingFile(image)) {
          FeedManager.getInstance().notifyInvalidImageFile(PodcastApp.getInstance(), image);
        }
      }
      return null;
    }
示例#10
0
  @SuppressLint("NewApi")
  @Override
  public void onCreate() {
    if (AppConfig.DEBUG) Log.d(TAG, "Service started");
    isRunning = true;
    handler = new Handler();
    completedDownloads = Collections.synchronizedList(new ArrayList<DownloadStatus>());
    downloads = new ArrayList<Downloader>();
    numberOfDownloads = new AtomicInteger(0);

    IntentFilter cancelDownloadReceiverFilter = new IntentFilter();
    cancelDownloadReceiverFilter.addAction(ACTION_CANCEL_ALL_DOWNLOADS);
    cancelDownloadReceiverFilter.addAction(ACTION_CANCEL_DOWNLOAD);
    registerReceiver(cancelDownloadReceiver, cancelDownloadReceiverFilter);
    syncExecutor =
        Executors.newSingleThreadExecutor(
            new ThreadFactory() {

              @Override
              public Thread newThread(Runnable r) {
                Thread t = new Thread(r);
                t.setPriority(Thread.MIN_PRIORITY);
                return t;
              }
            });
    downloadExecutor =
        new ExecutorCompletionService<Downloader>(
            Executors.newFixedThreadPool(
                NUM_PARALLEL_DOWNLOADS,
                new ThreadFactory() {

                  @Override
                  public Thread newThread(Runnable r) {
                    Thread t = new Thread(r);
                    t.setPriority(Thread.MIN_PRIORITY);
                    return t;
                  }
                }));
    schedExecutor =
        new ScheduledThreadPoolExecutor(
            SCHED_EX_POOL_SIZE,
            new ThreadFactory() {

              @Override
              public Thread newThread(Runnable r) {
                Thread t = new Thread(r);
                t.setPriority(Thread.MIN_PRIORITY);
                return t;
              }
            },
            new RejectedExecutionHandler() {

              @Override
              public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
                Log.w(TAG, "SchedEx rejected submission of new task");
              }
            });
    downloadCompletionThread.start();
    setupNotificationBuilders();
    requester = DownloadRequester.getInstance();
  }
示例#11
0
  @Override
  protected void onCreate(Bundle savedInstanceState) {
    setTheme(PodcastApp.getThemeResourceId());
    super.onCreate(savedInstanceState);
    getSupportActionBar().setDisplayHomeAsUpEnabled(true);
    StorageUtils.checkStorageAvailability(this);
    setContentView(R.layout.addfeed);

    requester = DownloadRequester.getInstance();
    progDialog = new ProgressDialog(this);

    etxtFeedurl = (EditText) findViewById(R.id.etxtFeedurl);
    butBrowseMiroGuide = (Button) findViewById(R.id.butBrowseMiroguide);
    butOpmlImport = (Button) findViewById(R.id.butOpmlImport);
    butGreaderImport = (Button) findViewById(R.id.butGreaderImport);
    butConfirm = (Button) findViewById(R.id.butConfirm);
    butCancel = (Button) findViewById(R.id.butCancel);

    butBrowseMiroGuide.setOnClickListener(
        new OnClickListener() {

          @Override
          public void onClick(View v) {
            startActivity(new Intent(AddFeedActivity.this, MiroGuideMainActivity.class));
          }
        });

    butOpmlImport.setOnClickListener(
        new OnClickListener() {

          @Override
          public void onClick(View v) {
            startActivity(new Intent(AddFeedActivity.this, OpmlImportFromPathActivity.class));
          }
        });

    butGreaderImport.setOnClickListener(
        new OnClickListener() {

          @Override
          public void onClick(View v) {
            startActivity(new Intent(AddFeedActivity.this, GoogleReaderImportActivity.class));
          }
        });

    butConfirm.setOnClickListener(
        new View.OnClickListener() {
          @Override
          public void onClick(View v) {
            addNewFeed();
          }
        });

    butCancel.setOnClickListener(
        new View.OnClickListener() {
          @Override
          public void onClick(View v) {
            setResult(RESULT_CANCELED);
            finish();
          }
        });
  }