HypoAlarm/GlowPadBackport/src/main/java/net/sebastianopoggi/ui/GlowPadBackport/TargetDrawable.java

342 lines
11 KiB
Java

/*
* Copyright (C) 2011 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 net.sebastianopoggi.ui.GlowPadBackport;
import android.content.res.Resources;
import android.graphics.Canvas;
import android.graphics.ColorFilter;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.StateListDrawable;
import android.util.Log;
import java.lang.reflect.Method;
public class TargetDrawable {
private static final String TAG = "TargetDrawable";
private static final boolean DEBUG = false;
public static final int[] STATE_ACTIVE =
{android.R.attr.state_enabled, android.R.attr.state_active};
public static final int[] STATE_INACTIVE =
{android.R.attr.state_enabled, -android.R.attr.state_active};
public static final int[] STATE_FOCUSED =
{android.R.attr.state_enabled, -android.R.attr.state_active,
android.R.attr.state_focused};
// We're using Reflection to access these private APIs on older Android versions
static Method mGetStateDrawableIndex, mGetStateCount, mGetStateDrawable;
static {
// In this static block we initialize all reflected methods (so that we can work around
// the @hide annotations for those Android Framework methods). This is not ideal, but
// there's not much we can do about that either.
try {
mGetStateCount = StateListDrawable.class.getDeclaredMethod("getStateCount");
mGetStateCount.setAccessible(true);
}
catch (NoSuchMethodException e) {
Log.e(TAG, "Couldn't access the StateListDrawable#getStateCount() method. " +
"Some stuff might break!", e);
}
try {
mGetStateDrawable = StateListDrawable.class.getDeclaredMethod("getStateDrawable", int.class);
mGetStateDrawable.setAccessible(true);
}
catch (NoSuchMethodException e) {
Log.e(TAG, "Couldn't access the StateListDrawable#getStateDrawable(int) method. " +
"Some stuff might break!", e);
}
try {
mGetStateDrawableIndex = StateListDrawable.class.getDeclaredMethod("getStateDrawableIndex", int[].class);
mGetStateDrawableIndex.setAccessible(true);
}
catch (NoSuchMethodException e) {
Log.e(TAG, "Couldn't access the StateListDrawable#mGetStateDrawableIndex(int[]) method. " +
"Some stuff might break!", e);
}
}
private float mTranslationX = 0.0f;
private float mTranslationY = 0.0f;
private float mPositionX = 0.0f;
private float mPositionY = 0.0f;
private float mScaleX = 1.0f;
private float mScaleY = 1.0f;
private float mAlpha = 1.0f;
private Drawable mDrawable;
private boolean mEnabled = true;
private final int mResourceId;
/* package */ static class DrawableWithAlpha extends Drawable {
private float mAlpha = 1.0f;
private Drawable mRealDrawable;
public DrawableWithAlpha(Drawable realDrawable) {
mRealDrawable = realDrawable;
}
public void setAlphaFloat(float alpha) {
mAlpha = alpha;
}
public int getAlphaFloat() {
return (int) (mAlpha * 255);
}
public void draw(Canvas canvas) {
mRealDrawable.setAlpha(Math.round(mAlpha * 255f));
mRealDrawable.draw(canvas);
}
@Override
public void setAlpha(int alpha) {
mRealDrawable.setAlpha(alpha);
}
@Override
public int getAlpha() {
return mRealDrawable.getAlpha();
}
@Override
public void setColorFilter(ColorFilter cf) {
mRealDrawable.setColorFilter(cf);
}
@Override
public int getOpacity() {
return mRealDrawable.getOpacity();
}
}
public TargetDrawable(Resources res, int resId) {
mResourceId = resId;
setDrawable(res, resId);
}
public void setDrawable(Resources res, int resId) {
// Note we explicitly don't set mResourceId to resId since we allow the drawable to be
// swapped at runtime and want to re-use the existing resource id for identification.
Drawable drawable = resId == 0 ? null : res.getDrawable(resId);
// Mutate the drawable so we can animate shared drawable properties.
mDrawable = drawable != null ? drawable.mutate() : null;
resizeDrawables();
setState(STATE_INACTIVE);
}
public TargetDrawable(TargetDrawable other) {
mResourceId = other.mResourceId;
// Mutate the drawable so we can animate shared drawable properties.
mDrawable = other.mDrawable != null ? other.mDrawable.mutate() : null;
resizeDrawables();
setState(STATE_INACTIVE);
}
public void setState(int[] state) {
if (mDrawable instanceof StateListDrawable) {
StateListDrawable d = (StateListDrawable) mDrawable;
d.setState(state);
}
}
public boolean hasState(int[] state) {
if (mDrawable instanceof StateListDrawable) {
StateListDrawable d = (StateListDrawable) mDrawable;
// TODO: this doesn't seem to work
try {
return (Integer) mGetStateDrawableIndex.invoke(d, state) != -1;
}
catch (Exception e) {
Log.w(TAG, "StateListDrawable#getStateDrawableIndex(int[]) call failed!", e);
}
}
return false;
}
/**
* Returns true if the drawable is a StateListDrawable and is in the focused state.
*
* @return Returns true if the drawable is a StateListDrawable and is in the focused state
*/
public boolean isActive() {
if (mDrawable instanceof StateListDrawable) {
StateListDrawable d = (StateListDrawable) mDrawable;
int[] states = d.getState();
for (int i = 0; i < states.length; i++) {
if (states[i] == android.R.attr.state_focused) {
return true;
}
}
}
return false;
}
/**
* Returns true if this target is enabled. Typically an enabled target contains a valid
* drawable in a valid state. Currently all targets with valid drawables are valid.
*
* @return Returns true if the target is enabled, false otherwise
*/
public boolean isEnabled() {
return mDrawable != null && mEnabled;
}
/**
* Makes drawables in a StateListDrawable all the same dimensions.
* If not a StateListDrawable, then justs sets the bounds to the intrinsic size of the
* drawable.
*/
private void resizeDrawables() {
if (mDrawable instanceof StateListDrawable) {
StateListDrawable d = (StateListDrawable) mDrawable;
int maxWidth = 0;
int maxHeight = 0;
Integer stateCount = 0;
try {
stateCount = (Integer) mGetStateCount.invoke(d);
}
catch (Exception e) {
Log.w(TAG, "StateListDrawable#getStateCount() call failed!", e);
}
for (int i = 0; i < stateCount; i++) {
Drawable childDrawable;
try {
childDrawable = (Drawable) mGetStateDrawable.invoke(d, i);
}
catch (Exception e) {
Log.w(TAG, "StateListDrawable#getStateDrawable(int) call failed!", e);
continue;
}
maxWidth = Math.max(maxWidth, childDrawable.getIntrinsicWidth());
maxHeight = Math.max(maxHeight, childDrawable.getIntrinsicHeight());
}
if (DEBUG) {
Log.v(TAG, "union of childDrawable rects " + d + " to: "
+ maxWidth + "x" + maxHeight);
}
d.setBounds(0, 0, maxWidth, maxHeight);
for (int i = 0; i < stateCount; i++) {
Drawable childDrawable;
try {
childDrawable = (Drawable) mGetStateDrawable.invoke(d, i);
}
catch (Exception e) {
Log.w(TAG, "StateListDrawable#getStateDrawable(int) call failed!", e);
continue;
}
if (DEBUG) {
Log.v(TAG, "sizing drawable " + childDrawable + " to: "
+ maxWidth + "x" + maxHeight);
}
childDrawable.setBounds(0, 0, maxWidth, maxHeight);
}
}
else if (mDrawable != null) {
mDrawable.setBounds(0, 0,
mDrawable.getIntrinsicWidth(), mDrawable.getIntrinsicHeight());
}
}
public void setX(float x) {
mTranslationX = x;
}
public void setY(float y) {
mTranslationY = y;
}
public void setScaleX(float x) {
mScaleX = x;
}
public void setScaleY(float y) {
mScaleY = y;
}
public void setAlpha(float alpha) {
mAlpha = alpha;
}
public float getX() {
return mTranslationX;
}
public float getY() {
return mTranslationY;
}
public float getScaleX() {
return mScaleX;
}
public float getScaleY() {
return mScaleY;
}
public float getAlpha() {
return mAlpha;
}
public void setPositionX(float x) {
mPositionX = x;
}
public void setPositionY(float y) {
mPositionY = y;
}
public float getPositionX() {
return mPositionX;
}
public float getPositionY() {
return mPositionY;
}
public int getWidth() {
return mDrawable != null ? mDrawable.getIntrinsicWidth() : 0;
}
public int getHeight() {
return mDrawable != null ? mDrawable.getIntrinsicHeight() : 0;
}
public void draw(Canvas canvas) {
if (mDrawable == null || !mEnabled) {
return;
}
canvas.save(Canvas.MATRIX_SAVE_FLAG);
canvas.scale(mScaleX, mScaleY, mPositionX, mPositionY);
canvas.translate(mTranslationX + mPositionX, mTranslationY + mPositionY);
canvas.translate(-0.5f * getWidth(), -0.5f * getHeight());
mDrawable.setAlpha(Math.round(mAlpha * 255f));
mDrawable.draw(canvas);
canvas.restore();
}
public void setEnabled(boolean enabled) {
mEnabled = enabled;
}
public int getResourceId() {
return mResourceId;
}
}