/* * Copyright (C) 2017 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.wallpaper.asset; import android.app.Activity; import android.content.Context; import android.content.pm.PackageManager; import android.content.res.AssetFileDescriptor; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Rect; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.Drawable; import android.net.Uri; import android.os.AsyncTask; import android.util.Log; import android.widget.ImageView; import com.bumptech.glide.Glide; import com.bumptech.glide.load.Key; import com.bumptech.glide.load.engine.DiskCacheStrategy; import com.bumptech.glide.load.resource.drawable.DrawableTransitionOptions; import com.bumptech.glide.request.RequestOptions; import java.io.IOException; import java.security.MessageDigest; /** * Asset wrapping a drawable for a live wallpaper thumbnail. */ public class LiveWallpaperThumbAsset extends Asset { private static final String TAG = "LiveWallpaperThumbAsset"; protected final Context mContext; protected final android.app.WallpaperInfo mInfo; // The content Uri of thumbnail protected Uri mUri; private BitmapDrawable mThumbnailDrawable; public LiveWallpaperThumbAsset(Context context, android.app.WallpaperInfo info) { mContext = context.getApplicationContext(); mInfo = info; } public LiveWallpaperThumbAsset(Context context, android.app.WallpaperInfo info, Uri uri) { this(context, info); mUri = uri; } @Override public void decodeBitmap(int targetWidth, int targetHeight, BitmapReceiver receiver) { // No scaling is needed, as the thumbnail is already a thumbnail. LoadThumbnailTask task = new LoadThumbnailTask(mContext, mInfo, receiver); task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); } @Override public void decodeBitmapRegion(Rect rect, int targetWidth, int targetHeight, BitmapReceiver receiver) { receiver.onBitmapDecoded(null); } @Override public void decodeRawDimensions(Activity unused, DimensionsReceiver receiver) { receiver.onDimensionsDecoded(null); } @Override public boolean supportsTiling() { return false; } @Override public void loadDrawable(Context context, ImageView imageView, int placeholderColor) { RequestOptions reqOptions; if (mUri != null) { reqOptions = RequestOptions.centerCropTransform().apply(RequestOptions .diskCacheStrategyOf(DiskCacheStrategy.NONE) .skipMemoryCache(true)) .placeholder(new ColorDrawable(placeholderColor)); } else { reqOptions = RequestOptions.centerCropTransform() .placeholder(new ColorDrawable(placeholderColor)); } Glide.with(context) .asDrawable() .load(LiveWallpaperThumbAsset.this) .apply(reqOptions) .transition(DrawableTransitionOptions.withCrossFade()) .into(imageView); } /** * Returns a Glide cache key. */ Key getKey() { return new LiveWallpaperThumbKey(mInfo); } /** * Returns the thumbnail drawable for the live wallpaper synchronously. Should not be called on * the main UI thread. */ protected Drawable getThumbnailDrawable() { if (mUri != null) { if (mThumbnailDrawable != null) { return mThumbnailDrawable; } try { AssetFileDescriptor assetFileDescriptor = mContext.getContentResolver().openAssetFileDescriptor(mUri, "r"); if (assetFileDescriptor != null) { mThumbnailDrawable = new BitmapDrawable(mContext.getResources(), BitmapFactory.decodeStream(assetFileDescriptor.createInputStream())); return mThumbnailDrawable; } } catch (IOException e) { Log.w(TAG, "Not found thumbnail from URI."); } } return mInfo.loadThumbnail(mContext.getPackageManager()); } /** * Glide caching key for resources from any arbitrary package. */ private static final class LiveWallpaperThumbKey implements Key { private android.app.WallpaperInfo mInfo; public LiveWallpaperThumbKey(android.app.WallpaperInfo info) { mInfo = info; } @Override public String toString() { return getCacheKey(); } @Override public int hashCode() { return getCacheKey().hashCode(); } @Override public boolean equals(Object object) { if (!(object instanceof LiveWallpaperThumbKey)) { return false; } LiveWallpaperThumbKey otherKey = (LiveWallpaperThumbKey) object; return getCacheKey().equals(otherKey.getCacheKey()); } @Override public void updateDiskCacheKey(MessageDigest messageDigest) { messageDigest.update(getCacheKey().getBytes(CHARSET)); } /** * Returns an inexpensively calculated {@link String} suitable for use as a disk cache key, * based on the live wallpaper's package name and service name, which is enough to uniquely * identify a live wallpaper. */ private String getCacheKey() { return "LiveWallpaperThumbKey{" + "packageName=" + mInfo.getPackageName() + "," + "serviceName=" + mInfo.getServiceName() + '}'; } } /** * AsyncTask subclass which loads the live wallpaper's thumbnail bitmap off the main UI thread. * Resolves with null if live wallpaper thumbnail is not a bitmap. */ private static class LoadThumbnailTask extends AsyncTask { private final PackageManager mPackageManager; private android.app.WallpaperInfo mInfo; private BitmapReceiver mReceiver; public LoadThumbnailTask(Context context, android.app.WallpaperInfo info, BitmapReceiver receiver) { mInfo = info; mReceiver = receiver; mPackageManager = context.getPackageManager(); } @Override protected Bitmap doInBackground(Void... unused) { Drawable thumb = mInfo.loadThumbnail(mPackageManager); // Live wallpaper components may or may not specify a thumbnail drawable. if (thumb != null && thumb instanceof BitmapDrawable) { return ((BitmapDrawable) thumb).getBitmap(); } // If no thumbnail was specified, return a null bitmap. return null; } @Override protected void onPostExecute(Bitmap bitmap) { mReceiver.onBitmapDecoded(bitmap); } } }