Add ripple to switches, radio buttons, check boxes, seek bars
BUG: 14231772
Change-Id: Ie40eac9f68815294460175965a999dd75f4144b5
diff --git a/core/java/android/widget/AbsSeekBar.java b/core/java/android/widget/AbsSeekBar.java
index 438a9da..8a30def 100644
--- a/core/java/android/widget/AbsSeekBar.java
+++ b/core/java/android/widget/AbsSeekBar.java
@@ -29,6 +29,8 @@
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityNodeInfo;
+import com.android.internal.R;
+
public abstract class AbsSeekBar extends ProgressBar {
private Drawable mThumb;
private int mThumbOffset;
@@ -289,28 +291,39 @@
*/
private void setThumbPos(int w, Drawable thumb, float scale, int gap) {
int available = w - mPaddingLeft - mPaddingRight;
- int thumbWidth = thumb.getIntrinsicWidth();
- int thumbHeight = thumb.getIntrinsicHeight();
+ final int thumbWidth = thumb.getIntrinsicWidth();
+ final int thumbHeight = thumb.getIntrinsicHeight();
available -= thumbWidth;
// The extra space for the thumb to move on the track
available += mThumbOffset * 2;
- int thumbPos = (int) (scale * available + 0.5f);
+ final int thumbPos = (int) (scale * available + 0.5f);
- int topBound, bottomBound;
+ final int top, bottom;
if (gap == Integer.MIN_VALUE) {
- Rect oldBounds = thumb.getBounds();
- topBound = oldBounds.top;
- bottomBound = oldBounds.bottom;
+ final Rect oldBounds = thumb.getBounds();
+ top = oldBounds.top;
+ bottom = oldBounds.bottom;
} else {
- topBound = gap;
- bottomBound = gap + thumbHeight;
+ top = gap;
+ bottom = gap + thumbHeight;
}
-
- // Canvas will be translated, so 0,0 is where we start drawing
+
final int left = (isLayoutRtl() && mMirrorForRtl) ? available - thumbPos : thumbPos;
- thumb.setBounds(left, topBound, left + thumbWidth, bottomBound);
+ final int right = left + thumbWidth;
+
+ final Drawable background = getBackground();
+ if (background.supportsHotspots()) {
+ final Rect bounds = mThumb.getBounds();
+ final int offsetX = mPaddingLeft - mThumbOffset;
+ final int offsetY = mPaddingTop;
+ background.setHotspotBounds(left + offsetX, bounds.top + offsetY,
+ right + offsetX, bounds.bottom + offsetY);
+ }
+
+ // Canvas will be translated, so 0,0 is where we start drawing
+ thumb.setBounds(left, top, right, bottom);
}
/**
@@ -328,6 +341,7 @@
@Override
protected synchronized void onDraw(Canvas canvas) {
super.onDraw(canvas);
+
if (mThumb != null) {
canvas.save();
// Translate the padding. For the x, we need to allow the thumb to
@@ -424,10 +438,24 @@
return true;
}
+ private void setHotspot(int id, float x, float y) {
+ final Drawable bg = getBackground();
+ if (bg != null && bg.supportsHotspots()) {
+ bg.setHotspot(id, x, y);
+ }
+ }
+
+ private void clearHotspot(int id) {
+ final Drawable bg = getBackground();
+ if (bg != null && bg.supportsHotspots()) {
+ bg.removeHotspot(id);
+ }
+ }
+
private void trackTouchEvent(MotionEvent event) {
final int width = getWidth();
final int available = width - mPaddingLeft - mPaddingRight;
- int x = (int)event.getX();
+ final int x = (int) event.getX();
float scale;
float progress = 0;
if (isLayoutRtl() && mMirrorForRtl) {
@@ -451,7 +479,8 @@
}
final int max = getMax();
progress += scale * max;
-
+
+ setHotspot(R.attr.state_pressed, x, (int) event.getY());
setProgress((int) progress, true);
}
@@ -477,6 +506,7 @@
* canceled.
*/
void onStopTrackingTouch() {
+ clearHotspot(R.attr.state_pressed);
mIsDragging = false;
}
diff --git a/core/java/android/widget/CompoundButton.java b/core/java/android/widget/CompoundButton.java
index 4298545..ddc8b05 100644
--- a/core/java/android/widget/CompoundButton.java
+++ b/core/java/android/widget/CompoundButton.java
@@ -261,15 +261,13 @@
@Override
protected void onDraw(Canvas canvas) {
- super.onDraw(canvas);
-
final Drawable buttonDrawable = mButtonDrawable;
if (buttonDrawable != null) {
final int verticalGravity = getGravity() & Gravity.VERTICAL_GRAVITY_MASK;
final int drawableHeight = buttonDrawable.getIntrinsicHeight();
final int drawableWidth = buttonDrawable.getIntrinsicWidth();
- int top = 0;
+ final int top;
switch (verticalGravity) {
case Gravity.BOTTOM:
top = getHeight() - drawableHeight;
@@ -277,12 +275,24 @@
case Gravity.CENTER_VERTICAL:
top = (getHeight() - drawableHeight) / 2;
break;
+ default:
+ top = 0;
}
- int bottom = top + drawableHeight;
- int left = isLayoutRtl() ? getWidth() - drawableWidth : 0;
- int right = isLayoutRtl() ? getWidth() : drawableWidth;
+ final int bottom = top + drawableHeight;
+ final int left = isLayoutRtl() ? getWidth() - drawableWidth : 0;
+ final int right = isLayoutRtl() ? getWidth() : drawableWidth;
buttonDrawable.setBounds(left, top, right, bottom);
+
+ final Drawable background = getBackground();
+ if (background.supportsHotspots()) {
+ background.setHotspotBounds(left, top, right, bottom);
+ }
+ }
+
+ super.onDraw(canvas);
+
+ if (buttonDrawable != null) {
buttonDrawable.draw(canvas);
}
}
diff --git a/core/java/android/widget/Switch.java b/core/java/android/widget/Switch.java
index 3d23e4d..d013e7b 100644
--- a/core/java/android/widget/Switch.java
+++ b/core/java/android/widget/Switch.java
@@ -773,8 +773,6 @@
@Override
protected void onDraw(Canvas canvas) {
- super.onDraw(canvas);
-
final Rect tempRect = mTempRect;
final Drawable trackDrawable = mTrackDrawable;
final Drawable thumbDrawable = mThumbDrawable;
@@ -785,16 +783,12 @@
final int switchRight = mSwitchRight;
final int switchBottom = mSwitchBottom;
trackDrawable.setBounds(switchLeft, switchTop, switchRight, switchBottom);
- trackDrawable.draw(canvas);
-
- final int saveCount = canvas.save();
-
trackDrawable.getPadding(tempRect);
+
final int switchInnerLeft = switchLeft + tempRect.left;
final int switchInnerTop = switchTop + tempRect.top;
final int switchInnerRight = switchRight - tempRect.right;
final int switchInnerBottom = switchBottom - tempRect.bottom;
- canvas.clipRect(switchInnerLeft, switchTop, switchInnerRight, switchBottom);
// Relies on mTempRect, MUST be called first!
final int thumbPos = getThumbOffset();
@@ -803,6 +797,18 @@
int thumbLeft = switchInnerLeft - tempRect.left + thumbPos;
int thumbRight = switchInnerLeft + thumbPos + mThumbWidth + tempRect.right;
thumbDrawable.setBounds(thumbLeft, switchTop, thumbRight, switchBottom);
+
+ final Drawable background = getBackground();
+ if (background.supportsHotspots()) {
+ background.setHotspotBounds(thumbLeft, switchTop, thumbRight, switchBottom);
+ }
+
+ super.onDraw(canvas);
+
+ trackDrawable.draw(canvas);
+
+ final int saveCount = canvas.save();
+ canvas.clipRect(switchInnerLeft, switchTop, switchInnerRight, switchBottom);
thumbDrawable.draw(canvas);
final int drawableState[] = getDrawableState();
diff --git a/core/res/res/drawable/btn_radio_quantum.xml b/core/res/res/drawable/btn_radio_quantum.xml
index 152e3d3..0f9ebce 100644
--- a/core/res/res/drawable/btn_radio_quantum.xml
+++ b/core/res/res/drawable/btn_radio_quantum.xml
@@ -15,18 +15,20 @@
-->
<selector xmlns:android="http://schemas.android.com/apk/res/android">
- <item android:state_checked="true" android:state_enabled="true" android:state_pressed="true">
- <bitmap android:src="@drawable/btn_radio_on_pressed_qntm_alpha"
- android:tint="?attr/colorControlActivated" />
+ <item android:state_enabled="false" android:state_checked="true">
+ <bitmap android:src="@drawable/btn_radio_on_qntm_alpha"
+ android:tint="?attr/colorControlNormal"
+ android:alpha="?attr/disabledAlpha" />
+ </item>
+ <item android:state_enabled="false">
+ <bitmap android:src="@drawable/btn_radio_off_qntm_alpha"
+ android:tint="?attr/colorControlNormal"
+ android:alpha="?attr/disabledAlpha" />
</item>
<item android:state_checked="true">
<bitmap android:src="@drawable/btn_radio_on_qntm_alpha"
android:tint="?attr/colorControlActivated" />
</item>
- <item android:state_enabled="true" android:state_pressed="true">
- <bitmap android:src="@drawable/btn_radio_off_pressed_qntm_alpha"
- android:tint="?attr/colorControlActivated" />
- </item>
<item>
<bitmap android:src="@drawable/btn_radio_off_qntm_alpha"
android:tint="?attr/colorControlNormal" />
diff --git a/core/res/res/drawable/scrubber_control_selector_quantum.xml b/core/res/res/drawable/scrubber_control_selector_quantum.xml
index e34f64a..ef3af0c 100644
--- a/core/res/res/drawable/scrubber_control_selector_quantum.xml
+++ b/core/res/res/drawable/scrubber_control_selector_quantum.xml
@@ -19,10 +19,6 @@
<bitmap android:src="@drawable/scrubber_control_off_qntm_alpha"
android:tint="?attr/colorControlNormal" />
</item>
- <item android:state_pressed="true">
- <bitmap android:src="@drawable/scrubber_control_on_pressed_qntm_alpha"
- android:tint="?attr/colorControlActivated" />
- </item>
<item>
<bitmap android:src="@drawable/scrubber_control_on_qntm_alpha"
android:tint="?attr/colorControlActivated" />
diff --git a/core/res/res/drawable/switch_inner_quantum.xml b/core/res/res/drawable/switch_inner_quantum.xml
index 915377e..856895e 100644
--- a/core/res/res/drawable/switch_inner_quantum.xml
+++ b/core/res/res/drawable/switch_inner_quantum.xml
@@ -15,18 +15,20 @@
-->
<selector xmlns:android="http://schemas.android.com/apk/res/android">
- <item android:state_checked="true" android:state_pressed="true">
+ <item android:state_enabled="false" android:state_checked="true">
<nine-patch android:src="@drawable/switch_on_qntm_alpha"
- android:tint="?attr/colorControlActivated" />
+ android:tint="?attr/colorControlNormal"
+ android:alpha="?attr/disabledAlpha" />
+ </item>
+ <item android:state_enabled="false">
+ <nine-patch android:src="@drawable/switch_off_qntm_alpha"
+ android:tint="?attr/colorControlNormal"
+ android:alpha="?attr/disabledAlpha" />
</item>
<item android:state_checked="true">
<nine-patch android:src="@drawable/switch_on_qntm_alpha"
android:tint="?attr/colorControlActivated" />
</item>
- <item android:state_pressed="true">
- <nine-patch android:src="@drawable/switch_off_qntm_alpha"
- android:tint="?attr/colorControlActivated" />
- </item>
<item>
<nine-patch android:src="@drawable/switch_off_qntm_alpha"
android:tint="?attr/colorControlNormal" />
diff --git a/core/res/res/values/styles_quantum.xml b/core/res/res/values/styles_quantum.xml
index bdc7ad0..0cbb655 100644
--- a/core/res/res/values/styles_quantum.xml
+++ b/core/res/res/values/styles_quantum.xml
@@ -485,11 +485,18 @@
</style>
<style name="Widget.Quantum.CompoundButton" parent="Widget.CompoundButton"/>
- <style name="Widget.Quantum.CompoundButton.CheckBox" parent="Widget.CompoundButton.CheckBox"/>
- <style name="Widget.Quantum.CompoundButton.RadioButton" parent="Widget.CompoundButton.RadioButton"/>
+
+ <style name="Widget.Quantum.CompoundButton.CheckBox" parent="Widget.CompoundButton.CheckBox">
+ <item name="background">?attr/selectableItemBackground</item>
+ </style>
+
+ <style name="Widget.Quantum.CompoundButton.RadioButton" parent="Widget.CompoundButton.RadioButton">
+ <item name="background">?attr/selectableItemBackground</item>
+ </style>
<style name="Widget.Quantum.CompoundButton.Star" parent="Widget.CompoundButton.Star">
<item name="button">@drawable/btn_star_quantum</item>
+ <item name="background">?attr/selectableItemBackground</item>
</style>
<style name="Widget.Quantum.CompoundButton.Switch">
@@ -501,6 +508,7 @@
<item name="thumbTextPadding">12dip</item>
<item name="switchMinWidth">72dip</item>
<item name="switchPadding">16dip</item>
+ <item name="background">?attr/selectableItemBackground</item>
</style>
<style name="Widget.Quantum.EditText" parent="Widget.EditText"/>
@@ -619,6 +627,7 @@
<item name="paddingStart">16dip</item>
<item name="paddingEnd">16dip</item>
<item name="mirrorForRtl">true</item>
+ <item name="background">?attr/selectableItemBackground</item>
</style>
<style name="Widget.Quantum.RatingBar" parent="Widget.RatingBar">
@@ -846,7 +855,15 @@
<item name="popupBackground">?attr/colorBackground</item>
</style>
+ <style name="Widget.Quantum.Light.CompoundButton" parent="Widget.Quantum.CompoundButton"/>
<style name="Widget.Quantum.Light.CompoundButton.CheckBox" parent="Widget.Quantum.CompoundButton.CheckBox"/>
+ <style name="Widget.Quantum.Light.CompoundButton.RadioButton" parent="Widget.Quantum.CompoundButton.RadioButton"/>
+ <style name="Widget.Quantum.Light.CompoundButton.Star" parent="Widget.Quantum.CompoundButton.Star"/>
+
+ <style name="Widget.Quantum.Light.CompoundButton.Switch" parent="Widget.Quantum.CompoundButton.Switch">
+ <item name="switchTextAppearance">@style/TextAppearance.Quantum.Light.Widget.Switch</item>
+ </style>
+
<style name="Widget.Quantum.Light.ListView.DropDown" parent="Widget.Quantum.ListView.DropDown"/>
<style name="Widget.Quantum.Light.EditText" parent="Widget.Quantum.EditText"/>
<style name="Widget.Quantum.Light.ExpandableListView" parent="Widget.Quantum.ExpandableListView"/>
@@ -916,7 +933,6 @@
<item name="maxHeight">16dip</item>
</style>
- <style name="Widget.Quantum.Light.CompoundButton.RadioButton" parent="Widget.Quantum.CompoundButton.RadioButton"/>
<style name="Widget.Quantum.Light.ScrollView" parent="Widget.Quantum.ScrollView"/>
<style name="Widget.Quantum.Light.HorizontalScrollView" parent="Widget.Quantum.HorizontalScrollView"/>
@@ -932,7 +948,6 @@
<style name="Widget.Quantum.Light.Spinner.DropDown" parent="Widget.Quantum.Spinner.DropDown"/>
<style name="Widget.Quantum.Light.Spinner.DropDown.ActionBar" parent="Widget.Quantum.Spinner.DropDown.ActionBar"/>
- <style name="Widget.Quantum.Light.CompoundButton.Star" parent="Widget.Quantum.CompoundButton.Star"/>
<style name="Widget.Quantum.Light.TabWidget" parent="Widget.Quantum.TabWidget"/>
<style name="Widget.Quantum.Light.WebTextView" parent="Widget.Quantum.WebTextView"/>
<style name="Widget.Quantum.Light.WebView" parent="Widget.Quantum.WebView"/>
@@ -989,10 +1004,6 @@
<item name="backgroundSplit">?attr/colorPrimary</item>
</style>
- <style name="Widget.Quantum.Light.CompoundButton.Switch" parent="Widget.Quantum.CompoundButton.Switch">
- <item name="switchTextAppearance">@style/TextAppearance.Quantum.Light.Widget.Switch</item>
- </style>
-
<style name="Widget.Quantum.Light.FastScroll" parent="Widget.Quantum.FastScroll"/>
<style name="Widget.Quantum.Light.MediaRouteButton" parent="Widget.Quantum.MediaRouteButton">
diff --git a/graphics/java/android/graphics/drawable/Drawable.java b/graphics/java/android/graphics/drawable/Drawable.java
index 21cd5db..74d1219 100644
--- a/graphics/java/android/graphics/drawable/Drawable.java
+++ b/graphics/java/android/graphics/drawable/Drawable.java
@@ -518,9 +518,16 @@
public void removeHotspot(int key) {}
/**
- * Removes all hotspots from the drawable.
+ * Immediately removes all hotspots from the drawable.
*/
public void clearHotspots() {}
+
+ /**
+ * Sets the bounds to which hotspots are constrained.
+ *
+ * @hide until we finalize these APIs
+ */
+ public void setHotspotBounds(int left, int top, int right, int bottom) {}
/**
* Whether this drawable requests projection.
diff --git a/graphics/java/android/graphics/drawable/LayerDrawable.java b/graphics/java/android/graphics/drawable/LayerDrawable.java
index b366987..639d719 100644
--- a/graphics/java/android/graphics/drawable/LayerDrawable.java
+++ b/graphics/java/android/graphics/drawable/LayerDrawable.java
@@ -290,6 +290,26 @@
return false;
}
+
+ /**
+ * @hide
+ */
+ @Override
+ public boolean isProjected() {
+ if (super.isProjected()) {
+ return true;
+ }
+
+ final ChildDrawable[] layers = mLayerState.mChildren;
+ final int N = mLayerState.mNum;
+ for (int i = 0; i < N; i++) {
+ if (layers[i].mDrawable.isProjected()) {
+ return true;
+ }
+ }
+
+ return false;
+ }
/**
* Add a new layer to this drawable. The new layer is identified by an id.
diff --git a/graphics/java/android/graphics/drawable/Ripple.java b/graphics/java/android/graphics/drawable/Ripple.java
index 796da50..e3f57e9 100644
--- a/graphics/java/android/graphics/drawable/Ripple.java
+++ b/graphics/java/android/graphics/drawable/Ripple.java
@@ -139,8 +139,8 @@
public boolean draw(Canvas c, Paint p) {
final Rect bounds = mBounds;
final Rect padding = mPadding;
- final float dX = Math.max(mX, bounds.right - mX);
- final float dY = Math.max(mY, bounds.bottom - mY);
+ final float dX = Math.max(mX - bounds.left, bounds.right - mX);
+ final float dY = Math.max(mY - bounds.top, bounds.bottom - mY);
final int maxRadius = (int) Math.ceil(Math.sqrt(dX * dX + dY * dY));
final float enterState = mEnterState;
diff --git a/graphics/java/android/graphics/drawable/TouchFeedbackDrawable.java b/graphics/java/android/graphics/drawable/TouchFeedbackDrawable.java
index 813d755c..1958cfe 100644
--- a/graphics/java/android/graphics/drawable/TouchFeedbackDrawable.java
+++ b/graphics/java/android/graphics/drawable/TouchFeedbackDrawable.java
@@ -53,6 +53,9 @@
private final Rect mTempRect = new Rect();
private final Rect mPaddingRect = new Rect();
+ /** Current ripple effect bounds, used to constrain ripple effects. */
+ private final Rect mHotspotBounds = new Rect();
+
/** Current drawing bounds, used to compute dirty region. */
private final Rect mDrawingBounds = new Rect();
@@ -83,6 +86,9 @@
/** Whether the animation runnable has been posted. */
private boolean mAnimating;
+ /** Whether bounds are being overridden. */
+ private boolean mOverrideBounds;
+
TouchFeedbackDrawable() {
this(new TouchFeedbackState(null, null, null), null, null);
}
@@ -114,9 +120,22 @@
@Override
protected void onBoundsChange(Rect bounds) {
super.onBoundsChange(bounds);
+
+ if (!mOverrideBounds) {
+ mHotspotBounds.set(bounds);
+ }
+ onHotspotBoundsChange();
+ }
+
+ private void onHotspotBoundsChange() {
+ final int x = mHotspotBounds.centerX();
+ final int y = mHotspotBounds.centerY();
final int N = mActiveRipplesCount;
for (int i = 0; i < N; i++) {
+ if (mState.mPinned) {
+ mActiveRipples[i].move(x, y);
+ }
mActiveRipples[i].onBoundsChanged();
}
}
@@ -292,10 +311,10 @@
final Ripple ripple = mTouchedRipples.get(id);
if (ripple == null) {
- final Rect bounds = getBounds();
final Rect padding = mPaddingRect;
getPadding(padding);
+ final Rect bounds = mHotspotBounds;
if (mState.mPinned) {
x = bounds.exactCenterX();
y = bounds.exactCenterY();
@@ -308,7 +327,12 @@
mActiveRipples[mActiveRipplesCount++] = newRipple;
mTouchedRipples.put(id, newRipple);
- } else if (!mState.mPinned) {
+ } else if (mState.mPinned) {
+ final Rect bounds = mHotspotBounds;
+ x = bounds.exactCenterX();
+ y = bounds.exactCenterY();
+ ripple.move(x, y);
+ } else {
ripple.move(x, y);
}
@@ -338,6 +362,7 @@
final int n = mTouchedRipples.size();
for (int i = 0; i < n; i++) {
+ // TODO: Use a fast exit, maybe just fade out?
mTouchedRipples.valueAt(i).animate().exit();
}
@@ -348,6 +373,16 @@
}
/**
+ * @hide
+ */
+ @Override
+ public void setHotspotBounds(int left, int top, int right, int bottom) {
+ mOverrideBounds = true;
+ mHotspotBounds.set(left, top, right, bottom);
+ onHotspotBoundsChange();
+ }
+
+ /**
* Schedules the next animation, if necessary.
*/
private void scheduleAnimation() {