Fields Summary |
---|
private static final String | TAG |
private static final boolean | DEBUG |
private static final int | FULL_ALPHA |
private static final int | DIM_ALPHA_ON_SOLID |
private static final int | CHANGE_BG_DELAY_MS |
private static final int | FADE_DURATION |
private static final boolean | USE_SEPARATE_WINDOWUsing a separate window for backgrounds can improve graphics performance by
leveraging hardware display layers.
TODO: support a leanback configuration option. |
private static final String | WINDOW_NAME |
private static final String | FRAGMENT_TAG |
private android.content.Context | mContext |
private android.os.Handler | mHandler |
private android.view.Window | mWindow |
private android.view.WindowManager | mWindowManager |
private android.view.View | mBgView |
private BackgroundContinuityService | mService |
private int | mThemeDrawableResourceId |
private int | mHeightPx |
private int | mWidthPx |
private android.graphics.drawable.Drawable | mBackgroundDrawable |
private int | mBackgroundColor |
private boolean | mAttached |
private android.graphics.drawable.LayerDrawable | mLayerDrawable |
private DrawableWrapper | mLayerWrapper |
private DrawableWrapper | mImageInWrapper |
private DrawableWrapper | mImageOutWrapper |
private DrawableWrapper | mColorWrapper |
private DrawableWrapper | mDimWrapper |
private android.graphics.drawable.Drawable | mThemeDrawable |
private ChangeBackgroundRunnable | mChangeRunnable |
private final Animator.AnimatorListener | mImageInListener |
Methods Summary |
---|
private void | applyBackgroundChanges()
if (!mAttached || mLayerWrapper == null) {
return;
}
if (DEBUG) Log.v(TAG, "applyBackgroundChanges drawable " + mBackgroundDrawable);
int dimAlpha = 0;
if (mImageOutWrapper != null && mImageOutWrapper.isAnimationPending()) {
if (DEBUG) Log.v(TAG, "mImageOutWrapper animation starting");
mImageOutWrapper.startAnimation();
mImageOutWrapper = null;
dimAlpha = DIM_ALPHA_ON_SOLID;
}
if (mImageInWrapper == null && mBackgroundDrawable != null) {
if (DEBUG) Log.v(TAG, "creating new imagein drawable");
mImageInWrapper = new DrawableWrapper(mBackgroundDrawable);
mLayerDrawable.setDrawableByLayerId(R.id.background_imagein, mBackgroundDrawable);
if (DEBUG) Log.v(TAG, "mImageInWrapper animation starting");
mImageInWrapper.setAlpha(0);
mImageInWrapper.fadeIn(FADE_DURATION, 0);
mImageInWrapper.startAnimation(mImageInListener);
dimAlpha = FULL_ALPHA;
}
if (mDimWrapper != null && dimAlpha != 0) {
if (DEBUG) Log.v(TAG, "dimwrapper animation starting to " + dimAlpha);
mDimWrapper.fade(FADE_DURATION, 0, dimAlpha);
mDimWrapper.startAnimation();
}
|
public void | attach(android.view.Window window)Make the background visible on the given Window.
if (USE_SEPARATE_WINDOW) {
attachBehindWindow(window);
} else {
attachToView(window.getDecorView());
}
|
private void | attachBehindWindow(android.view.Window window)
if (DEBUG) Log.v(TAG, "attachBehindWindow " + window);
mWindow = window;
mWindowManager = window.getWindowManager();
WindowManager.LayoutParams params = new WindowManager.LayoutParams(
// Media window sits behind the main application window
WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA,
// Avoid default to software format RGBA
WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED,
android.graphics.PixelFormat.TRANSLUCENT);
params.setTitle(WINDOW_NAME);
params.width = ViewGroup.LayoutParams.MATCH_PARENT;
params.height = ViewGroup.LayoutParams.MATCH_PARENT;
View backgroundView = LayoutInflater.from(mContext).inflate(
R.layout.lb_background_window, null);
mWindowManager.addView(backgroundView, params);
attachToView(backgroundView);
|
private void | attachToView(android.view.View sceneRoot)
mBgView = sceneRoot;
mAttached = true;
syncWithService();
|
private android.graphics.drawable.Drawable | createEmptyDrawable()
Bitmap bitmap = null;
return new BitmapDrawable(mContext.getResources(), bitmap);
|
private void | createFragment(android.app.Activity activity)
// Use a fragment to ensure the background manager gets detached properly.
BackgroundFragment fragment = (BackgroundFragment) activity.getFragmentManager()
.findFragmentByTag(FRAGMENT_TAG);
if (fragment == null) {
fragment = new BackgroundFragment();
activity.getFragmentManager().beginTransaction().add(fragment, FRAGMENT_TAG).commit();
} else {
if (fragment.getBackgroundManager() != null) {
throw new IllegalStateException("Created duplicated BackgroundManager for same " +
"activity, please use getInstance() instead");
}
}
fragment.setBackgroundManager(this);
|
private void | createSupportFragment(android.support.v4.app.FragmentActivity activity)
// Use a fragment to ensure the background manager gets detached properly.
BackgroundSupportFragment fragment = (BackgroundSupportFragment) activity
.getSupportFragmentManager().findFragmentByTag(FRAGMENT_TAG);
if (fragment == null) {
fragment = new BackgroundSupportFragment();
activity.getSupportFragmentManager().beginTransaction().add(fragment, FRAGMENT_TAG)
.commit();
} else {
if (fragment.getBackgroundManager() != null) {
throw new IllegalStateException("Created duplicated BackgroundManager for same " +
"activity, please use getInstance() instead");
}
}
fragment.setBackgroundManager(this);
|
void | detach()Release references to Drawables and put the BackgroundManager into the
detached state. Called when the associated Activity is destroyed.
if (DEBUG) Log.v(TAG, "detach " + this);
release();
if (mWindowManager != null && mBgView != null) {
mWindowManager.removeViewImmediate(mBgView);
}
mWindowManager = null;
mWindow = null;
mBgView = null;
mAttached = false;
if (mService != null) {
mService.unref();
mService = null;
}
|
public final int | getColor()Returns the current background color.
return mBackgroundColor;
|
public android.graphics.drawable.Drawable | getDrawable()Returns the current background {@link Drawable}.
return mBackgroundDrawable;
|
public static android.support.v17.leanback.app.BackgroundManager | getInstance(android.app.Activity activity)Get the BackgroundManager associated with the Activity.
The BackgroundManager will be created on-demand for each individual
Activity. Subsequent calls will return the same BackgroundManager created
for this Activity.
if (activity instanceof FragmentActivity) {
return getSupportInstance((FragmentActivity) activity);
}
BackgroundFragment fragment = (BackgroundFragment) activity.getFragmentManager()
.findFragmentByTag(FRAGMENT_TAG);
if (fragment != null) {
BackgroundManager manager = fragment.getBackgroundManager();
if (manager != null) {
return manager;
}
// manager is null: this is a fragment restored by FragmentManager,
// fall through to create a BackgroundManager attach to it.
}
return new BackgroundManager(activity, false);
|
private static android.support.v17.leanback.app.BackgroundManager | getSupportInstance(android.support.v4.app.FragmentActivity activity)
BackgroundSupportFragment fragment = (BackgroundSupportFragment) activity
.getSupportFragmentManager().findFragmentByTag(FRAGMENT_TAG);
if (fragment != null) {
BackgroundManager manager = fragment.getBackgroundManager();
if (manager != null) {
return manager;
}
// manager is null: this is a fragment restored by FragmentManager,
// fall through to create a BackgroundManager attach to it.
}
return new BackgroundManager(activity, true);
|
private android.graphics.drawable.Drawable | getThemeDrawable()
Drawable drawable = null;
if (mThemeDrawableResourceId != -1) {
drawable = mService.getThemeDrawable(mContext, mThemeDrawableResourceId);
}
if (drawable == null) {
drawable = createEmptyDrawable();
}
return drawable;
|
private void | lazyInit()
if (mLayerDrawable != null) {
return;
}
mLayerDrawable = (LayerDrawable) ContextCompat.getDrawable(mContext,
R.drawable.lb_background).mutate();
mBgView.setBackground(mLayerDrawable);
mLayerDrawable.setDrawableByLayerId(R.id.background_imageout, createEmptyDrawable());
mDimWrapper = new DrawableWrapper(
mLayerDrawable.findDrawableByLayerId(R.id.background_dim));
mLayerWrapper = new DrawableWrapper(mLayerDrawable);
mColorWrapper = new DrawableWrapper(
mLayerDrawable.findDrawableByLayerId(R.id.background_color));
|
void | onActivityResume()Synchronizes state when the owning Activity is resumed.
if (mService == null) {
return;
}
if (mLayerDrawable == null) {
if (DEBUG) Log.v(TAG, "onActivityResume " + this +
" released state, syncing with service");
syncWithService();
} else {
if (DEBUG) Log.v(TAG, "onActivityResume " + this + " updating service color "
+ mBackgroundColor + " drawable " + mBackgroundDrawable);
mService.setColor(mBackgroundColor);
mService.setDrawable(mBackgroundDrawable);
}
|
public void | release()Release references to Drawables. Typically called to reduce memory
overhead when not visible.
When an Activity is resumed, if the BackgroundManager has not been
released, the continuity service is updated from the BackgroundManager
state. If the BackgroundManager was released, the BackgroundManager
inherits the current state from the continuity service.
if (DEBUG) Log.v(TAG, "release " + this);
if (mLayerDrawable != null) {
mLayerDrawable.setDrawableByLayerId(R.id.background_imagein, createEmptyDrawable());
mLayerDrawable.setDrawableByLayerId(R.id.background_imageout, createEmptyDrawable());
mLayerDrawable = null;
}
mLayerWrapper = null;
mImageInWrapper = null;
mImageOutWrapper = null;
mColorWrapper = null;
mDimWrapper = null;
mThemeDrawable = null;
if (mChangeRunnable != null) {
mChangeRunnable.cancel();
mChangeRunnable = null;
}
releaseBackgroundBitmap();
|
private void | releaseBackgroundBitmap()
mBackgroundDrawable = null;
|
private boolean | sameDrawable(android.graphics.drawable.Drawable first, android.graphics.drawable.Drawable second)
if (first == null || second == null) {
return false;
}
if (first == second) {
return true;
}
if (first instanceof BitmapDrawable && second instanceof BitmapDrawable) {
if (((BitmapDrawable) first).getBitmap().sameAs(((BitmapDrawable) second).getBitmap())) {
return true;
}
}
return false;
|
public void | setBitmap(android.graphics.Bitmap bitmap)Set the given bitmap into the background. When using setBitmap to set the
background, the provided bitmap will be scaled and cropped to correctly
fit within the dimensions of the view. The timing for when this becomes
visible in the app is undefined and may take place after a small delay.
if (DEBUG) {
Log.v(TAG, "setBitmap " + bitmap);
}
if (bitmap == null) {
setDrawableInternal(null);
return;
}
if (bitmap.getWidth() <= 0 || bitmap.getHeight() <= 0) {
if (DEBUG) {
Log.v(TAG, "invalid bitmap width or height");
}
return;
}
Matrix matrix = null;
if ((bitmap.getWidth() != mWidthPx || bitmap.getHeight() != mHeightPx)) {
int dwidth = bitmap.getWidth();
int dheight = bitmap.getHeight();
float scale;
// Scale proportionately to fit width and height.
if (dwidth * mHeightPx > mWidthPx * dheight) {
scale = (float) mHeightPx / (float) dheight;
} else {
scale = (float) mWidthPx / (float) dwidth;
}
int subX = Math.min((int) (mWidthPx / scale), dwidth);
int dx = Math.max(0, (dwidth - subX) / 2);
matrix = new Matrix();
matrix.setScale(scale, scale);
matrix.preTranslate(-dx, 0);
if (DEBUG) Log.v(TAG, "original image size " + bitmap.getWidth() + "x" + bitmap.getHeight() +
" scale " + scale + " dx " + dx);
}
BitmapDrawable bitmapDrawable = new BitmapDrawable(mContext.getResources(), bitmap, matrix);
setDrawableInternal(bitmapDrawable);
|
public void | setColor(int color)Set the background to the given color. The timing for when this becomes
visible in the app is undefined and may take place after a small delay.
if (DEBUG) Log.v(TAG, "setColor " + Integer.toHexString(color));
mBackgroundColor = color;
mService.setColor(mBackgroundColor);
if (mColorWrapper != null) {
mColorWrapper.setColor(mBackgroundColor);
}
|
public void | setDrawable(android.graphics.drawable.Drawable drawable)Set the given drawable into the background. The provided Drawable will be
used unmodified as the background, without any scaling or cropping
applied to it. The timing for when this becomes visible in the app is
undefined and may take place after a small delay.
if (DEBUG) Log.v(TAG, "setBackgroundDrawable " + drawable);
setDrawableInternal(drawable);
|
private void | setDrawableInternal(android.graphics.drawable.Drawable drawable)
if (!mAttached) {
throw new IllegalStateException("Must attach before setting background drawable");
}
if (mChangeRunnable != null) {
if (sameDrawable(drawable, mChangeRunnable.mDrawable)) {
if (DEBUG) Log.v(TAG, "setting same drawable");
return;
}
mChangeRunnable.cancel();
}
mChangeRunnable = new ChangeBackgroundRunnable(drawable);
if (mImageInWrapper != null && mImageInWrapper.isAnimationStarted()) {
if (DEBUG) Log.v(TAG, "animation in progress");
} else {
mHandler.postDelayed(mChangeRunnable, CHANGE_BG_DELAY_MS);
}
|
private void | showWallpaper(boolean show)
if (mWindow == null) {
return;
}
WindowManager.LayoutParams layoutParams = mWindow.getAttributes();
if (show) {
if ((layoutParams.flags & WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER) != 0) {
return;
}
if (DEBUG) Log.v(TAG, "showing wallpaper");
layoutParams.flags |= WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
} else {
if ((layoutParams.flags & WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER) == 0) {
return;
}
if (DEBUG) Log.v(TAG, "hiding wallpaper");
layoutParams.flags &= ~WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
}
mWindow.setAttributes(layoutParams);
|
private void | syncWithService()
int color = mService.getColor();
Drawable drawable = mService.getDrawable();
if (DEBUG) Log.v(TAG, "syncWithService color " + Integer.toHexString(color)
+ " drawable " + drawable);
mBackgroundColor = color;
mBackgroundDrawable = drawable == null ? null :
drawable.getConstantState().newDrawable().mutate();
updateImmediate();
|
private void | updateImmediate()
lazyInit();
mColorWrapper.setColor(mBackgroundColor);
if (mDimWrapper != null) {
mDimWrapper.setAlpha(mBackgroundColor == Color.TRANSPARENT ? 0 : DIM_ALPHA_ON_SOLID);
}
showWallpaper(mBackgroundColor == Color.TRANSPARENT);
mThemeDrawable = getThemeDrawable();
mLayerDrawable.setDrawableByLayerId(R.id.background_theme, mThemeDrawable);
if (mBackgroundDrawable == null) {
mLayerDrawable.setDrawableByLayerId(R.id.background_imagein, createEmptyDrawable());
} else {
if (DEBUG) Log.v(TAG, "Background drawable is available");
mImageInWrapper = new DrawableWrapper(mBackgroundDrawable);
mLayerDrawable.setDrawableByLayerId(R.id.background_imagein, mBackgroundDrawable);
if (mDimWrapper != null) {
mDimWrapper.setAlpha(FULL_ALPHA);
}
}
|