[go: nahoru, domu]

blob: 3703bd43013e81a93b11d0582bfc8fb5e2bd9cce [file] [log] [blame]
/*
* Copyright (C) 2015 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.example.android.leanback;
import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.os.Handler;
import android.util.Log;
import android.view.View;
import androidx.core.content.ContextCompat;
import androidx.leanback.app.BackgroundManager;
/**
* App uses BackgroundHelper for each Activity, it wraps BackgroundManager and provides:
* 1. AsyncTask to load bitmap in background thread.
* 2. Using a BitmapCache to cache loaded bitmaps.
*/
public class BackgroundHelper {
private static final String TAG = "BackgroundHelper";
private static final boolean DEBUG = false;
private static final boolean ENABLED = true;
// Background delay serves to avoid kicking off expensive bitmap loading
// in case multiple backgrounds are set in quick succession.
private static final int SET_BACKGROUND_DELAY_MS = 100;
/**
* An very simple example of BitmapCache.
*/
public static class BitmapCache {
Bitmap mLastBitmap;
Object mLastToken;
// Singleton BitmapCache shared by multiple activities/backgroundHelper.
static BitmapCache sInstance = new BitmapCache();
private BitmapCache() {
}
/**
* Get cached bitmap by token, returns null if missing cache.
*/
public Bitmap getCache(Object token) {
if (token == null ? mLastToken == null : token.equals(mLastToken)) {
if (DEBUG) Log.v(TAG, "hitCache token:" + token + " " + mLastBitmap);
return mLastBitmap;
}
return null;
}
/**
* Add cached bitmap.
*/
public void putCache(Object token, Bitmap bitmap) {
if (DEBUG) Log.v(TAG, "putCache token:" + token + " " + bitmap);
mLastToken = token;
mLastBitmap = bitmap;
}
/**
* Add singleton of BitmapCache shared across activities.
*/
public static BitmapCache getInstance() {
return sInstance;
}
}
/**
* Callback class to perform task after bitmap is loaded.
*/
public abstract static class BitmapLoadCallback {
/**
* Called when Bitmap is loaded.
*/
public abstract void onBitmapLoaded(Bitmap bitmap);
}
static class Request {
Object mImageToken;
Bitmap mResult;
Request(Object imageToken) {
mImageToken = imageToken;
}
}
public BackgroundHelper(Activity activity) {
if (DEBUG && !ENABLED) Log.v(TAG, "BackgroundHelper: disabled");
mActivity = activity;
}
class LoadBackgroundRunnable implements Runnable {
Request mRequest;
LoadBackgroundRunnable(Object imageToken) {
mRequest = new Request(imageToken);
}
@Override
public void run() {
if (DEBUG) Log.v(TAG, "Executing task");
new LoadBitmapIntoBackgroundManagerTask().execute(mRequest);
mRunnable = null;
}
}
@SuppressWarnings("deprecation") /* AsyncTask */
class LoadBitmapTaskBase extends android.os.AsyncTask<Request, Object, Request> {
@Override
protected Request doInBackground(Request... params) {
boolean cancelled = isCancelled();
if (DEBUG) Log.v(TAG, "doInBackground cancelled " + cancelled);
Request request = params[0];
if (!cancelled) {
request.mResult = loadBitmap(request.mImageToken);
}
return request;
}
@Override
protected void onPostExecute(Request request) {
if (DEBUG) Log.v(TAG, "onPostExecute");
BitmapCache.getInstance().putCache(request.mImageToken, request.mResult);
}
@Override
protected void onCancelled(Request request) {
if (DEBUG) Log.v(TAG, "onCancelled");
}
private Bitmap loadBitmap(Object imageToken) {
if (imageToken instanceof Integer) {
final int resourceId = (Integer) imageToken;
if (DEBUG) Log.v(TAG, "load resourceId " + resourceId);
Drawable drawable = ContextCompat.getDrawable(mActivity, resourceId);
if (drawable instanceof BitmapDrawable) {
return ((BitmapDrawable) drawable).getBitmap();
}
}
return null;
}
}
class LoadBitmapIntoBackgroundManagerTask extends LoadBitmapTaskBase {
@Override
protected void onPostExecute(Request request) {
super.onPostExecute(request);
mBackgroundManager.setBitmap(request.mResult);
}
}
class LoadBitmapCallbackTask extends LoadBitmapTaskBase {
BitmapLoadCallback mCallback;
LoadBitmapCallbackTask(BitmapLoadCallback callback) {
mCallback = callback;
}
@Override
protected void onPostExecute(Request request) {
super.onPostExecute(request);
if (mCallback != null) {
mCallback.onBitmapLoaded(request.mResult);
}
}
}
final Activity mActivity;
BackgroundManager mBackgroundManager;
LoadBackgroundRunnable mRunnable;
// Allocate a dedicated handler because there may be no view available
// when setBackground is invoked.
static Handler sHandler = new Handler();
void createBackgroundManagerIfNeeded() {
if (mBackgroundManager == null) {
mBackgroundManager = BackgroundManager.getInstance(mActivity);
}
}
/**
* Attach BackgroundManager to activity window.
*/
public void attachToWindow() {
if (!ENABLED) {
return;
}
if (DEBUG) Log.v(TAG, "attachToWindow " + mActivity);
createBackgroundManagerIfNeeded();
mBackgroundManager.attach(mActivity.getWindow());
}
/**
* Attach BackgroundManager to a view inside activity.
*/
public void attachToView(View backgroundView) {
if (!ENABLED) {
return;
}
if (DEBUG) Log.v(TAG, "attachToView " + mActivity + " " + backgroundView);
createBackgroundManagerIfNeeded();
mBackgroundManager.attachToView(backgroundView);
}
/**
* Sets a background bitmap. It will look up the cache first if missing, an AsyncTask will
* will be launched to load the bitmap.
*/
public void setBackground(Object imageToken) {
if (!ENABLED) {
return;
}
if (DEBUG) Log.v(TAG, "set imageToken " + imageToken + " to " + mActivity);
createBackgroundManagerIfNeeded();
if (imageToken == null) {
mBackgroundManager.setDrawable(null);
return;
}
Bitmap cachedBitmap = BitmapCache.getInstance().getCache(imageToken);
if (cachedBitmap != null) {
mBackgroundManager.setBitmap(cachedBitmap);
return;
}
if (mRunnable != null) {
sHandler.removeCallbacks(mRunnable);
}
mRunnable = new LoadBackgroundRunnable(imageToken);
sHandler.postDelayed(mRunnable, SET_BACKGROUND_DELAY_MS);
}
/**
* Clear Drawable.
*/
public void clearDrawable() {
if (!ENABLED) {
return;
}
if (DEBUG) Log.v(TAG, "clearDrawable to " + mActivity);
createBackgroundManagerIfNeeded();
mBackgroundManager.clearDrawable();
}
/**
* Directly sets a Drawable as background.
*/
public void setDrawable(Drawable drawable) {
if (!ENABLED) {
return;
}
if (DEBUG) Log.v(TAG, "setDrawable " + drawable + " to " + mActivity);
createBackgroundManagerIfNeeded();
mBackgroundManager.setDrawable(drawable);
}
/**
* Load bitmap in background and pass result to BitmapLoadCallback.
*/
public void loadBitmap(Object imageToken, BitmapLoadCallback callback) {
Bitmap cachedBitmap = BitmapCache.getInstance().getCache(imageToken);
if (cachedBitmap != null) {
if (callback != null) {
callback.onBitmapLoaded(cachedBitmap);
return;
}
}
new LoadBitmapCallbackTask(callback).execute(new Request(imageToken));
}
}