165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane/* 265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane * Copyright (C) 2014 The Android Open Source Project 365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane * 465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane * Licensed under the Apache License, Version 2.0 (the "License"); 565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane * you may not use this file except in compliance with the License. 665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane * You may obtain a copy of the License at 765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane * 865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane * http://www.apache.org/licenses/LICENSE-2.0 965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane * 1065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane * Unless required by applicable law or agreed to in writing, software 1165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane * distributed under the License is distributed on an "AS IS" BASIS, 1265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane * See the License for the specific language governing permissions and 1465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane * limitations under the License. 1565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane */ 1665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 1765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lanepackage com.android.tv.settings.widget; 1865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 1965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Laneimport android.accounts.Account; 2065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Laneimport android.accounts.AccountManager; 2165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Laneimport android.content.Context; 2265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Laneimport android.content.Intent.ShortcutIconResource; 2365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Laneimport android.content.pm.PackageManager.NameNotFoundException; 2465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Laneimport android.content.res.Resources; 2565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Laneimport android.content.res.Resources.NotFoundException; 2665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Laneimport android.graphics.Bitmap; 2765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Laneimport android.graphics.BitmapFactory; 2865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Laneimport android.graphics.Canvas; 2965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Laneimport android.graphics.drawable.Drawable; 3065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Laneimport android.net.Uri; 3165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Laneimport android.os.AsyncTask; 3265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Laneimport android.util.Log; 3365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Laneimport android.util.TypedValue; 3465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Laneimport android.widget.ImageView; 3565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 3665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Laneimport com.android.tv.settings.util.AccountImageHelper; 3765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Laneimport com.android.tv.settings.util.ByteArrayPool; 3865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Laneimport com.android.tv.settings.util.CachedInputStream; 3965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Laneimport com.android.tv.settings.util.UriUtils; 4065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 4165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Laneimport java.io.BufferedInputStream; 4265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Laneimport java.io.IOException; 4365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Laneimport java.io.InputStream; 4465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Laneimport java.lang.ref.WeakReference; 4565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Laneimport java.net.URL; 4665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Laneimport java.net.URLConnection; 4765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 4865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane/** 4965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane * AsyncTask which loads a bitmap. 5065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane * <p> 5165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane * The source of this can be another package (via a resource), a URI (content provider), or 5265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane * a file path. 5365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane * 5465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane * @see BitmapWorkerOptions 5565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane */ 5665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lanepublic class BitmapWorkerTask extends AsyncTask<BitmapWorkerOptions, Void, Bitmap> { 5765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 5865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane private static final String TAG = "BitmapWorker"; 5965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane private static final String GOOGLE_ACCOUNT_TYPE = "com.google"; 6065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 6165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane private static final boolean DEBUG = false; 6265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 6365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane private static final int SOCKET_TIMEOUT = 10000; 6465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane private static final int READ_TIMEOUT = 10000; 6565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 666e995161147d9110d77ae1fe38b697e52891d3f2Tony Mantler private final WeakReference<ImageView> mImageView; 6765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane // a flag for if the bitmap is scaled from original source 6865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane protected boolean mScaled; 6965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 7065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane public BitmapWorkerTask(ImageView imageView) { 716e995161147d9110d77ae1fe38b697e52891d3f2Tony Mantler mImageView = new WeakReference<>(imageView); 7265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane mScaled = false; 7365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 7465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 7565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane @Override 7665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane protected Bitmap doInBackground(BitmapWorkerOptions... params) { 7765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 7865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane return retrieveBitmap(params[0]); 7965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 8065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 8165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane protected Bitmap retrieveBitmap(BitmapWorkerOptions workerOptions) { 8265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane try { 8365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane if (workerOptions.getIconResource() != null) { 8465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane return getBitmapFromResource(workerOptions.getContext(), 8565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane workerOptions.getIconResource(), 8665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane workerOptions); 8765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } else if (workerOptions.getResourceUri() != null) { 8865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane if (UriUtils.isAndroidResourceUri(workerOptions.getResourceUri()) 8965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane || UriUtils.isShortcutIconResourceUri(workerOptions.getResourceUri())) { 9065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane // Make an icon resource from this. 9165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane return getBitmapFromResource(workerOptions.getContext(), 9265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane UriUtils.getIconResource(workerOptions.getResourceUri()), 9365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane workerOptions); 9465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } else if (UriUtils.isWebUri(workerOptions.getResourceUri())) { 9565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane return getBitmapFromHttp(workerOptions); 9665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } else if (UriUtils.isContentUri(workerOptions.getResourceUri())) { 9765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane return getBitmapFromContent(workerOptions); 9865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } else if (UriUtils.isAccountImageUri(workerOptions.getResourceUri())) { 9965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane return getAccountImage(workerOptions); 10065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } else { 10165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane Log.e(TAG, "Error loading bitmap - unknown resource URI! " 10265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane + workerOptions.getResourceUri()); 10365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 10465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } else { 10565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane Log.e(TAG, "Error loading bitmap - no source!"); 10665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 10765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } catch (IOException e) { 10865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane Log.e(TAG, "Error loading url " + workerOptions.getResourceUri(), e); 10965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane return null; 11065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } catch (RuntimeException e) { 11165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane Log.e(TAG, "Critical Error loading url " + workerOptions.getResourceUri(), e); 11265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane return null; 11365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 11465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 11565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane return null; 11665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 11765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 11865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane @Override 11965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane protected void onPostExecute(Bitmap bitmap) { 1206e995161147d9110d77ae1fe38b697e52891d3f2Tony Mantler final ImageView imageView = mImageView.get(); 1216e995161147d9110d77ae1fe38b697e52891d3f2Tony Mantler if (imageView != null) { 1226e995161147d9110d77ae1fe38b697e52891d3f2Tony Mantler imageView.setImageBitmap(bitmap); 12365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 12465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 12565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 12665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane private Bitmap getBitmapFromResource(Context context, ShortcutIconResource iconResource, 12765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane BitmapWorkerOptions outputOptions) throws IOException { 12865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane if (DEBUG) { 12965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane Log.d(TAG, "Loading " + iconResource.toString()); 13065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 13165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane try { 13265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane Object drawable = loadDrawable(context, iconResource); 13365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane if (drawable instanceof InputStream) { 13465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane // Most of these are bitmaps, so resize properly. 13565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane return decodeBitmap((InputStream)drawable, outputOptions); 13665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } else if (drawable instanceof Drawable){ 13765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane return createIconBitmap((Drawable) drawable, outputOptions); 13865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } else { 13965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane Log.w(TAG, "getBitmapFromResource failed, unrecognized resource: " + drawable); 14065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane return null; 14165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 14265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } catch (NameNotFoundException e) { 14365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane Log.w(TAG, "Could not load package: " + iconResource.packageName + "! NameNotFound"); 14465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane return null; 14565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } catch (NotFoundException e) { 14665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane Log.w(TAG, "Could not load resource: " + iconResource.resourceName + "! NotFound"); 14765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane return null; 14865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 14965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 15065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 15165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane public final boolean isScaled() { 15265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane return mScaled; 15365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 15465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 15565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane /** 15665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane * Scales the bitmap if either of the dimensions is out of range. 15765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane */ 15865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane private Bitmap scaleBitmapIfNecessary(BitmapWorkerOptions outputOptions, Bitmap bitmap) { 15965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane if (bitmap == null) { 16065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane return null; 16165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 16265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 16365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane float heightScale = 1f; 16465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane { 16565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane if (bitmap.getHeight() > outputOptions.getHeight()) { 16665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane heightScale = (float) outputOptions.getHeight() / (float) bitmap.getHeight(); 16765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 16865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 16965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 17065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane float widthScale = 1f; 17165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane { 17265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane if (bitmap.getWidth() > outputOptions.getWidth()) { 17365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane widthScale = (float) outputOptions.getWidth() / (float) bitmap.getWidth(); 17465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 17565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 17665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane float scale = heightScale < widthScale ? heightScale : widthScale; 17765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane if (scale >= 1.0f) { 17865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane return bitmap; 17965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } else { 18065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane int width = (int) (bitmap.getWidth() * scale); 18165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane int height = (int) (bitmap.getHeight() * scale); 18265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane if (DEBUG) { 18365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane Log.d(TAG, "Scaling bitmap " + ((outputOptions.getResourceUri() != null) 18465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane ? outputOptions.getResourceUri().toString() 18565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane : outputOptions.getIconResource().toString()) + " from " 18665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane + bitmap.getWidth() + "x" + bitmap.getHeight() + " to " + width 18765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane + "x" + height + " scale " + scale); 18865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 18965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane Bitmap newBitmap = Bitmap.createScaledBitmap(bitmap, width, height, true); 19065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane mScaled = true; 19165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane return newBitmap; 19265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 19365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 19465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 19565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane private Bitmap decodeBitmap(InputStream in, BitmapWorkerOptions options) 19665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane throws IOException { 19765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane CachedInputStream bufferedStream = null; 19865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane BitmapFactory.Options bitmapOptions = null; 19965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane try { 20065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane bufferedStream = new CachedInputStream(in); 20165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane // Let the bufferedStream be able to mark unlimited bytes up to full stream length. 20265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane // The value that BitmapFactory uses (1024) is too small for detecting bounds 20365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane bufferedStream.setOverrideMarkLimit(Integer.MAX_VALUE); 20465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane bitmapOptions = new BitmapFactory.Options(); 20565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane bitmapOptions.inJustDecodeBounds = true; 20665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane if (options.getBitmapConfig() != null) { 20765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane bitmapOptions.inPreferredConfig = options.getBitmapConfig(); 20865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 20965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane bitmapOptions.inTempStorage = ByteArrayPool.get16KBPool().allocateChunk(); 21065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane bufferedStream.mark(Integer.MAX_VALUE); 21165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane BitmapFactory.decodeStream(bufferedStream, null, bitmapOptions); 21265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 21365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane float heightScale = 1f; 21465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane { 21565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane int height = options.getHeight(); 21665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane if (height > 0) { 21765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane heightScale = (float) bitmapOptions.outHeight / height; 21865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 21965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 22065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 22165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane float widthScale = 1f; 22265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane { 22365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane int width = options.getWidth(); 22465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane if (width > 0) { 22565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane widthScale = (float) bitmapOptions.outWidth / width; 22665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 22765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 22865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 22965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane float scale = heightScale > widthScale ? heightScale : widthScale; 23065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 23165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane if (DEBUG) { 23265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane Log.d("BitmapWorkerTask", "Source bitmap: (" + bitmapOptions.outWidth + "x" 23365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane + bitmapOptions.outHeight + "). Max size: (" + options.getWidth() + "x" 23465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane + options.getHeight() + "). Chosen scale: " + scale + " -> " 23565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane + (int) scale); 23665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 23765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 23865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane bitmapOptions.inJustDecodeBounds = false; 23965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane if (scale >= 2) { 24065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane bitmapOptions.inSampleSize = (int) scale; 24165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 24265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane // Reset buffer to original position and disable the overrideMarkLimit 24365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane bufferedStream.reset(); 24465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane bufferedStream.setOverrideMarkLimit(0); 24565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane return scaleBitmapIfNecessary(options, 24665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane BitmapFactory.decodeStream(bufferedStream, null, 24765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane bitmapOptions)); 24865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 24965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } finally { 25065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane if (bitmapOptions != null) { 25165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane ByteArrayPool.get16KBPool().releaseChunk(bitmapOptions.inTempStorage); 25265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 25365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane if (bufferedStream != null) { 25465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane bufferedStream.close(); 25565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 25665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 25765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 25865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 25965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane private Bitmap getBitmapFromHttp(BitmapWorkerOptions options) throws IOException { 26065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane URL url = new URL(options.getResourceUri().toString()); 26165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane if (DEBUG) { 26265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane Log.d(TAG, "Loading " + url); 26365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 26465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane try { 26565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane URLConnection connection = url.openConnection(); 26665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane connection.setConnectTimeout(SOCKET_TIMEOUT); 26765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane connection.setReadTimeout(READ_TIMEOUT); 26865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane InputStream in = new BufferedInputStream(connection.getInputStream()); 26965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane return decodeBitmap(in, options); 27065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } finally { 27165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane if (DEBUG) { 27265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane Log.d(TAG, "loading done "+url); 27365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 27465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 27565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 27665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 27765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane private Bitmap getBitmapFromContent(BitmapWorkerOptions options) throws IOException { 27865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane InputStream bitmapStream = 27965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane options.getContext().getContentResolver().openInputStream(options.getResourceUri()); 28065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane if (bitmapStream != null) { 28165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane return decodeBitmap(bitmapStream, options); 28265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } else { 28365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane Log.w(TAG, "Content provider returned a null InputStream when trying to " + 28465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane "open resource."); 28565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane return null; 28665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 28765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 28865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 28965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane /** 29065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane * load drawable for non-bitmap resource or InputStream for bitmap resource without 29165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane * caching Bitmap in Resources. So that caller can maintain a different caching 29265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane * storage with less memory used. 29365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane * @return either {@link Drawable} for xml and ColorDrawable <br> 29465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane * or {@link InputStream} for Bitmap resource 29565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane */ 29665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane private static Object loadDrawable(Context context, ShortcutIconResource r) 29765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane throws NameNotFoundException { 29865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane Resources resources = context.getPackageManager() 29965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane .getResourcesForApplication(r.packageName); 30065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane if (resources == null) { 30165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane return null; 30265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 30365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane final int id = resources.getIdentifier(r.resourceName, null, null); 30465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane if (id == 0) { 30565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane Log.e(TAG, "Couldn't get resource " + r.resourceName + " in resources of " 30665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane + r.packageName); 30765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane return null; 30865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 30965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane TypedValue value = new TypedValue(); 31065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane resources.getValue(id, value, true); 31165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane if ((value.type == TypedValue.TYPE_STRING && value.string.toString().endsWith(".xml")) || ( 31265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane value.type >= TypedValue.TYPE_FIRST_COLOR_INT 31365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane && value.type <= TypedValue.TYPE_LAST_COLOR_INT)) { 31465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane return resources.getDrawable(id); 31565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 31665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane return resources.openRawResource(id, value); 31765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 31865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 31965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane private static Bitmap createIconBitmap(Drawable drawable, BitmapWorkerOptions workerOptions) { 32065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane // Some drawables have an intrinsic width and height of -1. In that case 32165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane // size it to our output. 32265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane int width = drawable.getIntrinsicWidth(); 32365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane if (width == -1) { 32465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane width = workerOptions.getWidth(); 32565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 32665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane int height = drawable.getIntrinsicHeight(); 32765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane if (height == -1) { 32865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane height = workerOptions.getHeight(); 32965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 33065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); 33165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane Canvas canvas = new Canvas(bitmap); 33265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane drawable.setBounds(0, 0, drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight()); 33365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane drawable.draw(canvas); 33465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane return bitmap; 33565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 33665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 33765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane public static Drawable getDrawable(Context context, ShortcutIconResource iconResource) 33865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane throws NameNotFoundException { 33965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane Resources resources = 34065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane context.getPackageManager().getResourcesForApplication(iconResource.packageName); 34165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane int id = resources.getIdentifier(iconResource.resourceName, null, null); 34265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane if (id == 0) { 34365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane throw new NameNotFoundException(); 34465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 34565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane return resources.getDrawable(id); 34665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 34765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 34865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane private Bitmap getAccountImage(BitmapWorkerOptions options) { 34965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane String accountName = UriUtils.getAccountName(options.getResourceUri()); 35065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane Context context = options.getContext(); 35165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane 35265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane if (accountName != null && context != null) { 35365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane Account thisAccount = null; 35465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane for (Account account : AccountManager.get(context). 35565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane getAccountsByType(GOOGLE_ACCOUNT_TYPE)) { 35665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane if (account.name.equals(accountName)) { 35765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane thisAccount = account; 35865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane break; 35965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 36065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 36165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane if (thisAccount != null) { 36265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane String picUriString = AccountImageHelper.getAccountPictureUri(context, thisAccount); 36365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane if (picUriString != null) { 36465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane BitmapWorkerOptions.Builder optionBuilder = 36565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane new BitmapWorkerOptions.Builder(context) 36665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane .width(options.getWidth()) 36765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane .height(options.getHeight()) 36865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane .cacheFlag(options.getCacheFlag()) 36965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane .bitmapConfig(options.getBitmapConfig()) 37065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane .resource(Uri.parse(picUriString)); 37165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane return BitmapDownloader.getInstance(context) 37265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane .loadBitmapBlocking(optionBuilder.build()); 37365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 37465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane return null; 37565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 37665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 37765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane return null; 37865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane } 37965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane} 380