public BitmapWorkerTask(ImageView target, FeedImage image, int length) { super(); this.target = target; this.image = image; this.baseLength = length; this.PREFERRED_LENGTH = (int) (length * PodcastApp.getLogicalDensity()); }
@Override protected void onCreate(Bundle savedInstanceState) { setTheme(PodcastApp.getThemeResourceId()); super.onCreate(savedInstanceState); getSupportActionBar().setDisplayHomeAsUpEnabled(true); setContentView(R.layout.greader_import); lstvGoogleAccount = (ListView) findViewById(R.id.lstvGoogleAccount); butStart = (Button) findViewById(R.id.butStartImport); txtvNoGoogleAccount = (TextView) findViewById(R.id.txtvNoGoogleAccount); greader = new GoogleReader(this); if (greader.getGoogleAccountNames().length == 0) { txtvNoGoogleAccount.setVisibility(View.VISIBLE); butStart.setEnabled(false); return; } else { lstvGoogleAccount.setAdapter( new ArrayAdapter<String>( this, android.R.layout.simple_list_item_single_choice, greader.getGoogleAccountNames())); lstvGoogleAccount.setChoiceMode(ListView.CHOICE_MODE_SINGLE); butStart.setOnClickListener( new OnClickListener() { @Override public void onClick(View v) { int checkPosition = lstvGoogleAccount.getCheckedItemPosition(); if (checkPosition == -1) { return; } Log.d(TAG, "getSelectedItemPosition:" + lstvGoogleAccount.getCheckedItemPosition()); greader.setSelectedAccount(checkPosition); GoogleReaderImportWorker importWorker = new GoogleReaderImportWorker(GoogleReaderImportActivity.this, greader) { @Override protected void handleResult(ArrayList<OpmlElement> result) { if (result != null) { if (AppConfig.DEBUG) Log.d(TAG, "Parsing was successful"); OpmlImportHolder.setReadElements(result); startActivityForResult( new Intent( GoogleReaderImportActivity.this, OpmlFeedChooserActivity.class), 0); } else { if (AppConfig.DEBUG) Log.d(TAG, "Parser error occurred"); } } }; importWorker.executeAsync(); } }); } }
@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; }
/** Caches and loads FeedImage bitmaps in the background */ public class FeedImageLoader { private static final String TAG = "FeedImageLoader"; private static FeedImageLoader singleton; public static final int LENGTH_BASE_COVER = 200; public static final int LENGTH_BASE_THUMBNAIL = 100; /** * Stores references to loaded bitmaps. Bitmaps can be accessed by the id of the FeedImage the * bitmap belongs to. */ final int memClass = ((ActivityManager) PodcastApp.getInstance().getSystemService(Context.ACTIVITY_SERVICE)) .getMemoryClass(); // Use 1/8th of the available memory for this memory cache. final int coverCacheSize = 1024 * 1024 * memClass / 10; final int thumbnailCacheSize = 1024 * 1024 * memClass / 6; private LruCache<Long, Bitmap> coverCache; private LruCache<Long, Bitmap> thumbnailCache; private FeedImageLoader() { coverCache = new LruCache<Long, Bitmap>(coverCacheSize) { @SuppressLint("NewApi") @Override protected int sizeOf(Long key, Bitmap value) { if (Integer.valueOf(android.os.Build.VERSION.SDK_INT) >= 12) return value.getByteCount(); else return (value.getRowBytes() * value.getHeight()); } }; thumbnailCache = new LruCache<Long, Bitmap>(thumbnailCacheSize) { @SuppressLint("NewApi") @Override protected int sizeOf(Long key, Bitmap value) { if (Integer.valueOf(android.os.Build.VERSION.SDK_INT) >= 12) return value.getByteCount(); else return (value.getRowBytes() * value.getHeight()); } }; } public static FeedImageLoader getInstance() { if (singleton == null) { singleton = new FeedImageLoader(); } return singleton; } @SuppressLint("NewApi") public void loadCoverBitmap(FeedImage image, ImageView target) { if (image != null) { Bitmap bitmap = getBitmapFromCoverCache(image.getId()); if (bitmap != null) { target.setImageBitmap(bitmap); } else { target.setImageResource(R.drawable.default_cover); BitmapWorkerTask worker = new BitmapWorkerTask(target, image, LENGTH_BASE_COVER); if (android.os.Build.VERSION.SDK_INT > android.os.Build.VERSION_CODES.GINGERBREAD_MR1) { worker.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); } else { worker.execute(); } } } else { target.setImageResource(R.drawable.default_cover); } } @SuppressLint("NewApi") public void loadThumbnailBitmap(FeedImage image, ImageView target) { if (image != null) { Bitmap bitmap = getBitmapFromThumbnailCache(image.getId()); if (bitmap != null) { target.setImageBitmap(bitmap); } else { target.setImageResource(R.drawable.default_cover); BitmapWorkerTask worker = new BitmapWorkerTask(target, image, LENGTH_BASE_THUMBNAIL); if (android.os.Build.VERSION.SDK_INT > android.os.Build.VERSION_CODES.GINGERBREAD_MR1) { worker.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); } else { worker.execute(); } } } else { target.setImageResource(R.drawable.default_cover); } } public void wipeImageCache() { coverCache.evictAll(); thumbnailCache.evictAll(); } public boolean isInThumbnailCache(FeedImage image) { return thumbnailCache.get(image.getId()) != null; } public Bitmap getBitmapFromThumbnailCache(long id) { return thumbnailCache.get(id); } public void addBitmapToThumbnailCache(long id, Bitmap bitmap) { thumbnailCache.put(id, bitmap); } public boolean isInCoverCache(FeedImage image) { return coverCache.get(image.getId()) != null; } public Bitmap getBitmapFromCoverCache(long id) { return coverCache.get(id); } public void addBitmapToCoverCache(long id, Bitmap bitmap) { coverCache.put(id, bitmap); } class BitmapWorkerTask extends AsyncTask<Void, Void, Void> { private int PREFERRED_LENGTH; private static final String TAG = "BitmapWorkerTask"; private ImageView target; private Bitmap bitmap; private Bitmap decodedBitmap; private int baseLength; private FeedImage image; public BitmapWorkerTask(ImageView target, FeedImage image, int length) { super(); this.target = target; this.image = image; this.baseLength = length; this.PREFERRED_LENGTH = (int) (length * PodcastApp.getLogicalDensity()); } @Override protected void onPostExecute(Void result) { super.onPostExecute(result); // check if imageview is still supposed to display this image if (target.getTag() == null || target.getTag() == image) { target.setImageBitmap(bitmap); } else { if (AppConfig.DEBUG) Log.d(TAG, "Not displaying image"); } } @Override protected void onPreExecute() { super.onPreExecute(); } private int calculateSampleSize(int width, int height) { int max = Math.max(width, height); if (max < PREFERRED_LENGTH) { return 1; } else { // find first sample size where max / sampleSize < // PREFERRED_LENGTH for (int sampleSize = 1, power = 0; ; power++, sampleSize = (int) Math.pow(2, power)) { int newLength = max / sampleSize; if (newLength <= PREFERRED_LENGTH) { if (newLength > 0) { return sampleSize; } else { return sampleSize - 1; } } } } } @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; } } }
@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(); } }); }
@Override protected void download() { File destination = new File(request.getDestination()); final boolean fileExists = destination.exists(); if (request.isDeleteOnFailure() && fileExists) { Log.w(TAG, "File already exists"); if (request.getFeedfileType() != FeedImage.FEEDFILETYPE_FEEDIMAGE) { onFail(DownloadError.ERROR_FILE_EXISTS, null); return; } else { onSuccess(); return; } } HttpClient httpClient = AntennapodHttpClient.getHttpClient(); RandomAccessFile out = null; InputStream connection = null; try { HttpGet httpGet = new HttpGet(URIUtil.getURIFromRequestUrl(request.getSource())); // add authentication information String userInfo = httpGet.getURI().getUserInfo(); if (userInfo != null) { String[] parts = userInfo.split(":"); if (parts.length == 2) { httpGet.addHeader( BasicScheme.authenticate( new UsernamePasswordCredentials(parts[0], parts[1]), "UTF-8", false)); } } else if (!StringUtils.isEmpty(request.getUsername()) && request.getPassword() != null) { httpGet.addHeader( BasicScheme.authenticate( new UsernamePasswordCredentials(request.getUsername(), request.getPassword()), "UTF-8", false)); } // add range header if necessary if (fileExists) { request.setSoFar(destination.length()); httpGet.addHeader(new BasicHeader("Range", "bytes=" + request.getSoFar() + "-")); if (BuildConfig.DEBUG) Log.d(TAG, "Adding range header: " + request.getSoFar()); } HttpResponse response = httpClient.execute(httpGet); HttpEntity httpEntity = response.getEntity(); int responseCode = response.getStatusLine().getStatusCode(); Header contentEncodingHeader = response.getFirstHeader("Content-Encoding"); final boolean isGzip = contentEncodingHeader != null && contentEncodingHeader.getValue().equalsIgnoreCase("gzip"); if (BuildConfig.DEBUG) Log.d(TAG, "Response code is " + responseCode); if (responseCode / 100 != 2 || httpEntity == null) { final DownloadError error; final String details; if (responseCode == HttpURLConnection.HTTP_UNAUTHORIZED) { error = DownloadError.ERROR_UNAUTHORIZED; details = String.valueOf(responseCode); } else { error = DownloadError.ERROR_HTTP_DATA_ERROR; details = String.valueOf(responseCode); } onFail(error, details); return; } if (!StorageUtils.storageAvailable(PodcastApp.getInstance())) { onFail(DownloadError.ERROR_DEVICE_NOT_FOUND, null); return; } connection = new BufferedInputStream(AndroidHttpClient.getUngzippedContent(httpEntity)); Header[] contentRangeHeaders = (fileExists) ? response.getHeaders("Content-Range") : null; if (fileExists && responseCode == HttpStatus.SC_PARTIAL_CONTENT && contentRangeHeaders != null && contentRangeHeaders.length > 0) { String start = contentRangeHeaders[0] .getValue() .substring("bytes ".length(), contentRangeHeaders[0].getValue().indexOf("-")); request.setSoFar(Long.valueOf(start)); Log.d(TAG, "Starting download at position " + request.getSoFar()); out = new RandomAccessFile(destination, "rw"); out.seek(request.getSoFar()); } else { destination.delete(); destination.createNewFile(); out = new RandomAccessFile(destination, "rw"); } byte[] buffer = new byte[BUFFER_SIZE]; int count = 0; request.setStatusMsg(R.string.download_running); if (BuildConfig.DEBUG) Log.d(TAG, "Getting size of download"); request.setSize(httpEntity.getContentLength() + request.getSoFar()); if (BuildConfig.DEBUG) Log.d(TAG, "Size is " + request.getSize()); if (request.getSize() < 0) { request.setSize(DownloadStatus.SIZE_UNKNOWN); } long freeSpace = StorageUtils.getFreeSpaceAvailable(); if (BuildConfig.DEBUG) Log.d(TAG, "Free space is " + freeSpace); if (request.getSize() != DownloadStatus.SIZE_UNKNOWN && request.getSize() > freeSpace) { onFail(DownloadError.ERROR_NOT_ENOUGH_SPACE, null); return; } if (BuildConfig.DEBUG) Log.d(TAG, "Starting download"); while (!cancelled && (count = connection.read(buffer)) != -1) { out.write(buffer, 0, count); request.setSoFar(request.getSoFar() + count); request.setProgressPercent( (int) (((double) request.getSoFar() / (double) request.getSize()) * 100)); } if (cancelled) { onCancelled(); } else { // check if size specified in the response header is the same as the size of the // written file. This check cannot be made if compression was used if (!isGzip && request.getSize() != DownloadStatus.SIZE_UNKNOWN && request.getSoFar() != request.getSize()) { onFail( DownloadError.ERROR_IO_ERROR, "Download completed but size: " + request.getSoFar() + " does not equal expected size " + request.getSize()); return; } onSuccess(); } } catch (IllegalArgumentException e) { e.printStackTrace(); onFail(DownloadError.ERROR_MALFORMED_URL, e.getMessage()); } catch (SocketTimeoutException e) { e.printStackTrace(); onFail(DownloadError.ERROR_CONNECTION_ERROR, e.getMessage()); } catch (UnknownHostException e) { e.printStackTrace(); onFail(DownloadError.ERROR_UNKNOWN_HOST, e.getMessage()); } catch (IOException e) { e.printStackTrace(); onFail(DownloadError.ERROR_IO_ERROR, e.getMessage()); } catch (NullPointerException e) { // might be thrown by connection.getInputStream() e.printStackTrace(); onFail(DownloadError.ERROR_CONNECTION_ERROR, request.getSource()); } finally { IOUtils.closeQuietly(out); AntennapodHttpClient.cleanup(); } }