summaryrefslogtreecommitdiff
path: root/graphics/java
diff options
context:
space:
mode:
Diffstat (limited to 'graphics/java')
-rw-r--r--graphics/java/android/graphics/ImageDecoder.java446
-rw-r--r--graphics/java/android/graphics/Typeface.java2
-rw-r--r--graphics/java/android/graphics/drawable/Icon.java6
-rw-r--r--graphics/java/android/graphics/drawable/RippleBackground.java9
-rw-r--r--graphics/java/android/graphics/drawable/RippleDrawable.java12
5 files changed, 318 insertions, 157 deletions
diff --git a/graphics/java/android/graphics/ImageDecoder.java b/graphics/java/android/graphics/ImageDecoder.java
index 60416a720231..419e2b7e4818 100644
--- a/graphics/java/android/graphics/ImageDecoder.java
+++ b/graphics/java/android/graphics/ImageDecoder.java
@@ -16,29 +16,45 @@
package android.graphics;
+import static android.system.OsConstants.SEEK_SET;
+
import android.annotation.IntDef;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.annotation.RawRes;
+import android.content.ContentResolver;
+import android.content.res.AssetFileDescriptor;
import android.content.res.AssetManager;
import android.content.res.Resources;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.NinePatchDrawable;
+import android.net.Uri;
+import android.system.ErrnoException;
+import android.system.Os;
+
+import libcore.io.IoUtils;
+import dalvik.system.CloseGuard;
import java.nio.ByteBuffer;
+import java.io.FileDescriptor;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.lang.ArrayIndexOutOfBoundsException;
+import java.lang.AutoCloseable;
import java.lang.NullPointerException;
import java.lang.RuntimeException;
import java.lang.annotation.Retention;
import static java.lang.annotation.RetentionPolicy.SOURCE;
+import java.util.concurrent.atomic.AtomicBoolean;
/**
* Class for decoding images as {@link Bitmap}s or {@link Drawable}s.
* @hide
*/
-public final class ImageDecoder {
+public final class ImageDecoder implements AutoCloseable {
/**
* Source of the encoded image data.
*/
@@ -47,10 +63,7 @@ public final class ImageDecoder {
Resources getResources() { return null; }
/* @hide */
- void close() {}
-
- /* @hide */
- abstract ImageDecoder createImageDecoder();
+ abstract ImageDecoder createImageDecoder() throws IOException;
};
private static class ByteArraySource extends Source {
@@ -64,7 +77,7 @@ public final class ImageDecoder {
private final int mLength;
@Override
- public ImageDecoder createImageDecoder() {
+ public ImageDecoder createImageDecoder() throws IOException {
return nCreate(mData, mOffset, mLength);
}
}
@@ -76,7 +89,7 @@ public final class ImageDecoder {
private final ByteBuffer mBuffer;
@Override
- public ImageDecoder createImageDecoder() {
+ public ImageDecoder createImageDecoder() throws IOException {
if (!mBuffer.isDirect() && mBuffer.hasArray()) {
int offset = mBuffer.arrayOffset() + mBuffer.position();
int length = mBuffer.limit() - mBuffer.position();
@@ -86,61 +99,110 @@ public final class ImageDecoder {
}
}
- private static class ResourceSource extends Source {
- ResourceSource(Resources res, int resId)
- throws Resources.NotFoundException {
- // Test that the resource can be found.
- InputStream is = null;
+ private static class ContentResolverSource extends Source {
+ ContentResolverSource(ContentResolver resolver, Uri uri) {
+ mResolver = resolver;
+ mUri = uri;
+ }
+
+ private final ContentResolver mResolver;
+ private final Uri mUri;
+
+ @Override
+ public ImageDecoder createImageDecoder() throws IOException {
+ AssetFileDescriptor assetFd = null;
try {
- is = res.openRawResource(resId);
+ if (mUri.getScheme() == ContentResolver.SCHEME_CONTENT) {
+ assetFd = mResolver.openTypedAssetFileDescriptor(mUri,
+ "image/*", null);
+ } else {
+ assetFd = mResolver.openAssetFileDescriptor(mUri, "r");
+ }
+ } catch (FileNotFoundException e) {
+ // Some images cannot be opened as AssetFileDescriptors (e.g.
+ // bmp, ico). Open them as InputStreams.
+ InputStream is = mResolver.openInputStream(mUri);
+ if (is == null) {
+ throw new FileNotFoundException(mUri.toString());
+ }
+
+ return createFromStream(is);
+ }
+
+ final FileDescriptor fd = assetFd.getFileDescriptor();
+ final long offset = assetFd.getStartOffset();
+
+ ImageDecoder decoder = null;
+ try {
+ try {
+ Os.lseek(fd, offset, SEEK_SET);
+ decoder = nCreate(fd);
+ } catch (ErrnoException e) {
+ decoder = createFromStream(new FileInputStream(fd));
+ }
} finally {
- if (is != null) {
- try {
- is.close();
- } catch (IOException e) {
- }
+ if (decoder == null) {
+ IoUtils.closeQuietly(assetFd);
+ } else {
+ decoder.mAssetFd = assetFd;
}
}
+ return decoder;
+ }
+ }
+
+ private static ImageDecoder createFromStream(InputStream is) throws IOException {
+ // Arbitrary size matches BitmapFactory.
+ byte[] storage = new byte[16 * 1024];
+ ImageDecoder decoder = null;
+ try {
+ decoder = nCreate(is, storage);
+ } finally {
+ if (decoder == null) {
+ IoUtils.closeQuietly(is);
+ } else {
+ decoder.mInputStream = is;
+ decoder.mTempStorage = storage;
+ }
+ }
+
+ return decoder;
+ }
+ private static class ResourceSource extends Source {
+ ResourceSource(Resources res, int resId) {
mResources = res;
mResId = resId;
}
final Resources mResources;
final int mResId;
- // This is just stored here in order to keep the underlying Asset
- // alive. FIXME: Can I access the Asset (and keep it alive) without
- // this object?
- InputStream mInputStream;
@Override
public Resources getResources() { return mResources; }
@Override
- public ImageDecoder createImageDecoder() {
- // FIXME: Can I bypass creating the stream?
- try {
- mInputStream = mResources.openRawResource(mResId);
- } catch (Resources.NotFoundException e) {
- // This should never happen, since we already tested in the
- // constructor.
- }
- if (!(mInputStream instanceof AssetManager.AssetInputStream)) {
- // This should never happen.
- throw new RuntimeException("Resource is not an asset?");
- }
- long asset = ((AssetManager.AssetInputStream) mInputStream).getNativeAsset();
- return nCreate(asset);
- }
-
- @Override
- public void close() {
+ public ImageDecoder createImageDecoder() throws IOException {
+ // This is just used in order to access the underlying Asset and
+ // keep it alive. FIXME: Can we skip creating this object?
+ InputStream is = null;
+ ImageDecoder decoder = null;
try {
- mInputStream.close();
- } catch (IOException e) {
+ is = mResources.openRawResource(mResId);
+ if (!(is instanceof AssetManager.AssetInputStream)) {
+ // This should never happen.
+ throw new RuntimeException("Resource is not an asset?");
+ }
+ long asset = ((AssetManager.AssetInputStream) is).getNativeAsset();
+ decoder = nCreate(asset);
} finally {
- mInputStream = null;
+ if (decoder == null) {
+ IoUtils.closeQuietly(is);
+ } else {
+ decoder.mInputStream = is;
+ }
}
+ return decoder;
}
}
@@ -148,29 +210,52 @@ public final class ImageDecoder {
* Contains information about the encoded image.
*/
public static class ImageInfo {
+ /**
+ * Width of the image, without scaling or cropping.
+ */
public final int width;
+
+ /**
+ * Height of the image, without scaling or cropping.
+ */
public final int height;
- // TODO?: Add more info? mimetype, ninepatch etc?
- ImageInfo(int width, int height) {
- this.width = width;
- this.height = height;
+ /* @hide */
+ ImageDecoder decoder;
+
+ /* @hide */
+ ImageInfo(ImageDecoder decoder) {
+ this.width = decoder.mWidth;
+ this.height = decoder.mHeight;
+ this.decoder = decoder;
+ }
+
+ /**
+ * The mimeType of the image, if known.
+ */
+ public String getMimeType() {
+ return decoder.getMimeType();
}
};
/**
- * Used if the provided data is incomplete.
+ * Supplied to onPartialImage if the provided data is incomplete.
+ *
+ * Will never be thrown by ImageDecoder.
*
* There may be a partial image to display.
*/
- public class IncompleteException extends Exception {};
+ public static class IncompleteException extends IOException {};
/**
* Used if the provided data is corrupt.
*
- * There may be a partial image to display.
+ * May be thrown if there is nothing to display.
+ *
+ * If supplied to onPartialImage, there may be a correct partial image to
+ * display.
*/
- public class CorruptException extends Exception {};
+ public static class CorruptException extends IOException {};
/**
* Optional listener supplied to {@link #decodeDrawable} or
@@ -190,18 +275,21 @@ public final class ImageDecoder {
/**
* Optional listener supplied to the ImageDecoder.
*/
- public static interface OnExceptionListener {
+ public static interface OnPartialImageListener {
/**
- * Called when there is a problem in the stream or in the data.
- * FIXME: Or do not allow streams?
- * FIXME: Report how much of the image has been decoded?
+ * Called when there is only a partial image to display.
+ *
+ * If the input is incomplete or contains an error, this listener lets
+ * the client know that and allows them to optionally bypass the rest
+ * of the decode/creation process.
*
- * @param e Exception containing information about the error.
- * @return True to create and return a {@link Drawable}/
- * {@link Bitmap} with partial data. False to return
- * {@code null}. True is the default.
+ * @param e IOException containing information about the error that
+ * interrupted the decode.
+ * @return True (which is the default) to create and return a
+ * {@link Drawable}/{@link Bitmap} with partial data. False to
+ * abort the decode and throw the {@link java.io.IOException}.
*/
- public boolean onException(Exception e);
+ public boolean onPartialImage(IOException e);
};
// Fields
@@ -218,12 +306,18 @@ public final class ImageDecoder {
private boolean mAsAlphaMask = false;
private Rect mCropRect;
- private PostProcess mPostProcess;
- private OnExceptionListener mOnExceptionListener;
+ private PostProcess mPostProcess;
+ private OnPartialImageListener mOnPartialImageListener;
+ // Objects for interacting with the input.
+ private InputStream mInputStream;
+ private byte[] mTempStorage;
+ private AssetFileDescriptor mAssetFd;
+ private final AtomicBoolean mClosed = new AtomicBoolean();
+ private final CloseGuard mCloseGuard = CloseGuard.get();
/**
- * Private constructor called by JNI. {@link #recycle} must be
+ * Private constructor called by JNI. {@link #close} must be
* called after decoding to delete native resources.
*/
@SuppressWarnings("unused")
@@ -233,6 +327,20 @@ public final class ImageDecoder {
mHeight = height;
mDesiredWidth = width;
mDesiredHeight = height;
+ mCloseGuard.open("close");
+ }
+
+ @Override
+ protected void finalize() throws Throwable {
+ try {
+ if (mCloseGuard != null) {
+ mCloseGuard.warnIfOpen();
+ }
+
+ close();
+ } finally {
+ super.finalize();
+ }
}
/**
@@ -243,14 +351,28 @@ public final class ImageDecoder {
* // FIXME: Can be an @DrawableRes?
* @return a new Source object, which can be passed to
* {@link #decodeDrawable} or {@link #decodeBitmap}.
- * @throws Resources.NotFoundException if the asset does not exist.
*/
+ @NonNull
public static Source createSource(@NonNull Resources res, @RawRes int resId)
- throws Resources.NotFoundException {
+ {
return new ResourceSource(res, resId);
}
/**
+ * Create a new {@link Source} from a {@link android.net.Uri}.
+ *
+ * @param cr to retrieve from.
+ * @param uri of the image file.
+ * @return a new Source object, which can be passed to
+ * {@link #decodeDrawable} or {@link #decodeBitmap}.
+ */
+ @NonNull
+ public static Source createSource(@NonNull ContentResolver cr,
+ @NonNull Uri uri) {
+ return new ContentResolverSource(cr, uri);
+ }
+
+ /**
* Create a new {@link Source} from a byte array.
* @param data byte array of compressed image data.
* @param offset offset into data for where the decoder should begin
@@ -260,7 +382,6 @@ public final class ImageDecoder {
* @throws ArrayIndexOutOfBoundsException if offset and length are
* not within data.
*/
- // TODO: Overloads that don't use offset, length
public static Source createSource(@NonNull byte[] data, int offset,
int length) throws ArrayIndexOutOfBoundsException {
if (data == null) {
@@ -275,6 +396,13 @@ public final class ImageDecoder {
}
/**
+ * See {@link #createSource(byte[], int, int).
+ */
+ public static Source createSource(@NonNull byte[] data) {
+ return createSource(data, 0, data.length);
+ }
+
+ /**
* Create a new {@link Source} from a {@link java.nio.ByteBuffer}.
*
* The returned {@link Source} effectively takes ownership of the
@@ -307,7 +435,7 @@ public final class ImageDecoder {
+ "provided " + sampleSize);
}
if (mNativePtr == 0) {
- throw new IllegalStateException("ImageDecoder is recycled!");
+ throw new IllegalStateException("ImageDecoder is closed!");
}
return nGetSampledSize(mNativePtr, sampleSize);
@@ -433,13 +561,13 @@ public final class ImageDecoder {
}
/**
- * Set (replace) the {@link OnExceptionListener} on this object.
+ * Set (replace) the {@link OnPartialImageListener} on this object.
*
* Will be called if there is an error in the input. Without one, a
* partial {@link Bitmap} will be created.
*/
- public void setOnExceptionListener(OnExceptionListener l) {
- mOnExceptionListener = l;
+ public void setOnPartialImageListener(OnPartialImageListener l) {
+ mOnPartialImageListener = l;
}
/**
@@ -500,24 +628,26 @@ public final class ImageDecoder {
mAsAlphaMask = true;
}
- /**
- * Clean up resources.
- *
- * ImageDecoder has a private constructor, and will always be recycled
- * by decodeDrawable or decodeBitmap which creates it, so there is no
- * need for a finalizer.
- */
- private void recycle() {
- if (mNativePtr == 0) {
+ @Override
+ public void close() {
+ mCloseGuard.close();
+ if (!mClosed.compareAndSet(false, true)) {
return;
}
- nRecycle(mNativePtr);
+ nClose(mNativePtr);
mNativePtr = 0;
+
+ IoUtils.closeQuietly(mInputStream);
+ IoUtils.closeQuietly(mAssetFd);
+
+ mInputStream = null;
+ mAssetFd = null;
+ mTempStorage = null;
}
private void checkState() {
if (mNativePtr == 0) {
- throw new IllegalStateException("Cannot reuse ImageDecoder.Source!");
+ throw new IllegalStateException("Cannot use closed ImageDecoder!");
}
checkSubset(mDesiredWidth, mDesiredHeight, mCropRect);
@@ -547,48 +677,55 @@ public final class ImageDecoder {
}
/**
- * Create a {@link Drawable}.
+ * Create a {@link Drawable} from a {@code Source}.
+ *
+ * @param src representing the encoded image.
+ * @param listener for learning the {@link ImageInfo} and changing any
+ * default settings on the {@code ImageDecoder}. If not {@code null},
+ * this will be called on the same thread as {@code decodeDrawable}
+ * before that method returns.
+ * @return Drawable for displaying the image.
+ * @throws IOException if {@code src} is not found, is an unsupported
+ * format, or cannot be decoded for any reason.
*/
- public static Drawable decodeDrawable(Source src, OnHeaderDecodedListener listener) {
- ImageDecoder decoder = src.createImageDecoder();
- if (decoder == null) {
- return null;
- }
-
- if (listener != null) {
- ImageInfo info = new ImageInfo(decoder.mWidth, decoder.mHeight);
- listener.onHeaderDecoded(info, decoder);
- }
+ @NonNull
+ public static Drawable decodeDrawable(@NonNull Source src,
+ @Nullable OnHeaderDecodedListener listener) throws IOException {
+ try (ImageDecoder decoder = src.createImageDecoder()) {
+ if (listener != null) {
+ ImageInfo info = new ImageInfo(decoder);
+ try {
+ listener.onHeaderDecoded(info, decoder);
+ } finally {
+ info.decoder = null;
+ }
+ }
- decoder.checkState();
+ decoder.checkState();
- if (decoder.mRequireUnpremultiplied) {
- // Though this could be supported (ignored) for opaque images, it
- // seems better to always report this error.
- throw new IllegalStateException("Cannot decode a Drawable with" +
- " unpremultiplied pixels!");
- }
+ if (decoder.mRequireUnpremultiplied) {
+ // Though this could be supported (ignored) for opaque images,
+ // it seems better to always report this error.
+ throw new IllegalStateException("Cannot decode a Drawable " +
+ "with unpremultiplied pixels!");
+ }
- if (decoder.mMutable) {
- throw new IllegalStateException("Cannot decode a mutable Drawable!");
- }
+ if (decoder.mMutable) {
+ throw new IllegalStateException("Cannot decode a mutable " +
+ "Drawable!");
+ }
- try {
Bitmap bm = nDecodeBitmap(decoder.mNativePtr,
- decoder.mOnExceptionListener,
+ decoder.mOnPartialImageListener,
decoder.mPostProcess,
- decoder.mDesiredWidth, decoder.mDesiredHeight,
+ decoder.mDesiredWidth,
+ decoder.mDesiredHeight,
decoder.mCropRect,
- false, // decoder.mMutable
+ false, // mMutable
decoder.mAllocator,
- false, // decoder.mRequireUnpremultiplied
+ false, // mRequireUnpremultiplied
decoder.mPreferRamOverQuality,
- decoder.mAsAlphaMask
- );
- if (bm == null) {
- return null;
- }
-
+ decoder.mAsAlphaMask);
Resources res = src.getResources();
if (res == null) {
bm.setDensity(Bitmap.DENSITY_NONE);
@@ -606,60 +743,91 @@ public final class ImageDecoder {
// TODO: Handle animation.
return new BitmapDrawable(res, bm);
- } finally {
- decoder.recycle();
- src.close();
}
}
/**
- * Create a {@link Bitmap}.
+ * See {@link #decodeDrawable(Source, OnHeaderDecodedListener)}.
*/
- public static Bitmap decodeBitmap(Source src, OnHeaderDecodedListener listener) {
- ImageDecoder decoder = src.createImageDecoder();
- if (decoder == null) {
- return null;
- }
+ @NonNull
+ public static Drawable decodeDrawable(@NonNull Source src)
+ throws IOException {
+ return decodeDrawable(src, null);
+ }
- if (listener != null) {
- ImageInfo info = new ImageInfo(decoder.mWidth, decoder.mHeight);
- listener.onHeaderDecoded(info, decoder);
- }
+ /**
+ * Create a {@link Bitmap} from a {@code Source}.
+ *
+ * @param src representing the encoded image.
+ * @param listener for learning the {@link ImageInfo} and changing any
+ * default settings on the {@code ImageDecoder}. If not {@code null},
+ * this will be called on the same thread as {@code decodeBitmap}
+ * before that method returns.
+ * @return Bitmap containing the image.
+ * @throws IOException if {@code src} is not found, is an unsupported
+ * format, or cannot be decoded for any reason.
+ */
+ @NonNull
+ public static Bitmap decodeBitmap(@NonNull Source src,
+ @Nullable OnHeaderDecodedListener listener) throws IOException {
+ try (ImageDecoder decoder = src.createImageDecoder()) {
+ if (listener != null) {
+ ImageInfo info = new ImageInfo(decoder);
+ try {
+ listener.onHeaderDecoded(info, decoder);
+ } finally {
+ info.decoder = null;
+ }
+ }
- decoder.checkState();
+ decoder.checkState();
- try {
return nDecodeBitmap(decoder.mNativePtr,
- decoder.mOnExceptionListener,
+ decoder.mOnPartialImageListener,
decoder.mPostProcess,
- decoder.mDesiredWidth, decoder.mDesiredHeight,
+ decoder.mDesiredWidth,
+ decoder.mDesiredHeight,
decoder.mCropRect,
decoder.mMutable,
decoder.mAllocator,
decoder.mRequireUnpremultiplied,
decoder.mPreferRamOverQuality,
decoder.mAsAlphaMask);
- } finally {
- decoder.recycle();
- src.close();
}
}
- private static native ImageDecoder nCreate(long asset);
+ private String getMimeType() {
+ return nGetMimeType(mNativePtr);
+ }
+
+ /**
+ * See {@link #decodeBitmap(Source, OnHeaderDecodedListener)}.
+ */
+ @NonNull
+ public static Bitmap decodeBitmap(@NonNull Source src) throws IOException {
+ return decodeBitmap(src, null);
+ }
+
+ private static native ImageDecoder nCreate(long asset) throws IOException;
private static native ImageDecoder nCreate(ByteBuffer buffer,
int position,
- int limit);
+ int limit) throws IOException;
private static native ImageDecoder nCreate(byte[] data, int offset,
- int length);
+ int length) throws IOException;
+ private static native ImageDecoder nCreate(InputStream is, byte[] storage);
+ private static native ImageDecoder nCreate(FileDescriptor fd) throws IOException;
+ @NonNull
private static native Bitmap nDecodeBitmap(long nativePtr,
- OnExceptionListener listener,
+ OnPartialImageListener listener,
PostProcess postProcess,
int width, int height,
Rect cropRect, boolean mutable,
int allocator, boolean requireUnpremul,
- boolean preferRamOverQuality, boolean asAlphaMask);
+ boolean preferRamOverQuality, boolean asAlphaMask)
+ throws IOException;
private static native Point nGetSampledSize(long nativePtr,
int sampleSize);
private static native void nGetPadding(long nativePtr, Rect outRect);
- private static native void nRecycle(long nativePtr);
+ private static native void nClose(long nativePtr);
+ private static native String nGetMimeType(long nativePtr);
}
diff --git a/graphics/java/android/graphics/Typeface.java b/graphics/java/android/graphics/Typeface.java
index 3d65bd226faf..68b7ac287e98 100644
--- a/graphics/java/android/graphics/Typeface.java
+++ b/graphics/java/android/graphics/Typeface.java
@@ -429,7 +429,7 @@ public class Typeface {
}
/**
- * Sets an index of the font collection.
+ * Sets an index of the font collection. See {@link android.R.attr#ttcIndex}.
*
* Can not be used for Typeface source. build() method will return null for invalid index.
* @param ttcIndex An index of the font collection. If the font source is not font
diff --git a/graphics/java/android/graphics/drawable/Icon.java b/graphics/java/android/graphics/drawable/Icon.java
index c329918afc27..749b75941ef9 100644
--- a/graphics/java/android/graphics/drawable/Icon.java
+++ b/graphics/java/android/graphics/drawable/Icon.java
@@ -819,8 +819,10 @@ public final class Icon implements Parcelable {
if (bitmapWidth > maxWidth || bitmapHeight > maxHeight) {
float scale = Math.min((float) maxWidth / bitmapWidth,
(float) maxHeight / bitmapHeight);
- bitmap = Bitmap.createScaledBitmap(bitmap, (int) (scale * bitmapWidth),
- (int) (scale * bitmapHeight), true /* filter */);
+ bitmap = Bitmap.createScaledBitmap(bitmap,
+ Math.max(1, (int) (scale * bitmapWidth)),
+ Math.max(1, (int) (scale * bitmapHeight)),
+ true /* filter */);
}
return bitmap;
}
diff --git a/graphics/java/android/graphics/drawable/RippleBackground.java b/graphics/java/android/graphics/drawable/RippleBackground.java
index dea194e4ffde..4571553d4d4e 100644
--- a/graphics/java/android/graphics/drawable/RippleBackground.java
+++ b/graphics/java/android/graphics/drawable/RippleBackground.java
@@ -16,17 +16,12 @@
package android.graphics.drawable;
-import android.animation.Animator;
-import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.animation.TimeInterpolator;
import android.graphics.Canvas;
-import android.graphics.CanvasProperty;
import android.graphics.Paint;
import android.graphics.Rect;
import android.util.FloatProperty;
-import android.view.DisplayListCanvas;
-import android.view.RenderNodeAnimator;
import android.view.animation.LinearInterpolator;
/**
@@ -78,8 +73,8 @@ class RippleBackground extends RippleComponent {
private void onStateChanged(boolean animateChanged) {
float newOpacity = 0.0f;
- if (mHovered) newOpacity += 1.0f;
- if (mFocused) newOpacity += 1.0f;
+ if (mHovered) newOpacity += .25f;
+ if (mFocused) newOpacity += .75f;
if (mAnimator != null) {
mAnimator.cancel();
mAnimator = null;
diff --git a/graphics/java/android/graphics/drawable/RippleDrawable.java b/graphics/java/android/graphics/drawable/RippleDrawable.java
index 734cff542c51..b883656d784a 100644
--- a/graphics/java/android/graphics/drawable/RippleDrawable.java
+++ b/graphics/java/android/graphics/drawable/RippleDrawable.java
@@ -264,8 +264,8 @@ public class RippleDrawable extends LayerDrawable {
}
setRippleActive(enabled && pressed);
-
setBackgroundActive(hovered, focused);
+
return changed;
}
@@ -879,22 +879,18 @@ public class RippleDrawable extends LayerDrawable {
// Grab the color for the current state and cut the alpha channel in
// half so that the ripple and background together yield full alpha.
final int color = mState.mColor.getColorForState(getState(), Color.BLACK);
- final int halfAlpha = (Color.alpha(color) / 2) << 24;
final Paint p = mRipplePaint;
if (mMaskColorFilter != null) {
// The ripple timing depends on the paint's alpha value, so we need
// to push just the alpha channel into the paint and let the filter
// handle the full-alpha color.
- final int fullAlphaColor = color | (0xFF << 24);
- mMaskColorFilter.setColor(fullAlphaColor);
-
- p.setColor(halfAlpha);
+ mMaskColorFilter.setColor(color | 0xFF000000);
+ p.setColor(color & 0xFF000000);
p.setColorFilter(mMaskColorFilter);
p.setShader(mMaskShader);
} else {
- final int halfAlphaColor = (color & 0xFFFFFF) | halfAlpha;
- p.setColor(halfAlphaColor);
+ p.setColor(color);
p.setColorFilter(null);
p.setShader(null);
}