Better overflow button

Overflow button as BadgedImageView
- BadgedImageView uses launcher’s icon factory to render overflow icon, which fixes the size and space inconsistencies between real bubbles and a bare ImageView
- BadgedImageView gives us access to the existing dot drawing logic, which we can later use to draw a dot on overflow button when overflow bubbles get updates
- Replace Bubble with BubbleViewProvider inside BadgedImageView so that BadgedImageView can access BubbleOverflow’s dot info

UI polish
- Set margins for overflow bubbles
- Set padding for overflow empty state
- Set overflow button and dot color to accent color from theme
- Render overflow button based on theme and dark mode; update on change

Bug: 149146374
Bug: 148878911
Test: manual - overflow button shape, icon color updates on theme change
Test: manual - overflow button color updates on dark mode change
Test: manual - overflow UI looks like mocks (specs not final)
Test: atest SystemUITests
Change-Id: I3d8829d56bce5c80936698a038438aff6db42d0f
This commit is contained in:
Lyn Han
2020-02-19 20:33:45 -08:00
parent 3cd75d77e2
commit cd4f87efbb
13 changed files with 180 additions and 75 deletions

View File

@@ -25,6 +25,7 @@
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/bubble_overflow_recycler"
android:layout_gravity="center_horizontal"
android:nestedScrollingEnabled="false"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
@@ -32,6 +33,8 @@
android:id="@+id/bubble_overflow_empty_state"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingLeft="@dimen/bubble_overflow_empty_state_padding"
android:paddingRight="@dimen/bubble_overflow_empty_state_padding"
android:orientation="vertical"
android:gravity="center">

View File

@@ -14,11 +14,9 @@
~ See the License for the specific language governing permissions and
~ limitations under the License
-->
<ImageView
<com.android.systemui.bubbles.BadgedImageView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/bubble_overflow_button"
android:layout_width="@dimen/individual_bubble_size"
android:layout_height="@dimen/individual_bubble_size"
android:src="@drawable/ic_bubble_overflow_button"
android:scaleType="center"
android:layout_gravity="end"/>
android:src="@drawable/ic_bubble_overflow_button"/>

View File

@@ -1128,8 +1128,10 @@
<dimen name="bubble_padding_top">16dp</dimen>
<!-- Size of individual bubbles. -->
<dimen name="individual_bubble_size">60dp</dimen>
<!-- Size of bubble bitmap. -->
<dimen name="bubble_bitmap_size">52dp</dimen>
<!-- Size of bubble icon bitmap. -->
<dimen name="bubble_icon_bitmap_size">52dp</dimen>
<dimen name="bubble_overflow_icon_bitmap_size">24dp</dimen>
<!-- Extra padding added to the touchable rect for bubbles so they are easier to grab. -->
<dimen name="bubble_touch_padding">12dp</dimen>
<!-- Size of the circle around the bubbles when they're in the dismiss target. -->
@@ -1141,6 +1143,12 @@
<dimen name="bubble_expanded_view_slop">8dp</dimen>
<!-- Default (and minimum) height of the expanded view shown when the bubble is expanded -->
<dimen name="bubble_expanded_default_height">180dp</dimen>
<!-- Default height of bubble overflow -->
<dimen name="bubble_overflow_height">380dp</dimen>
<!-- Bubble overflow padding when there are no bubbles -->
<dimen name="bubble_overflow_empty_state_padding">16dp</dimen>
<!-- Margin of overflow bubbles -->
<dimen name="bubble_overflow_margin">16dp</dimen>
<!-- Height of the triangle that points to the expanded bubble -->
<dimen name="bubble_pointer_height">4dp</dimen>
<!-- Width of the triangle that points to the expanded bubble -->

View File

@@ -17,7 +17,6 @@ package com.android.systemui.bubbles;
import android.annotation.Nullable;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Path;
import android.graphics.Rect;
@@ -50,9 +49,9 @@ public class BadgedImageView extends ImageView {
// Flyout gets shown before the dot
private int mCurrentDotState = DOT_STATE_SUPPRESSED_FOR_FLYOUT;
private Bubble mBubble;
private BubbleViewProvider mBubble;
private int mIconBitmapSize;
private int mBubbleBitmapSize;
private DotRenderer mDotRenderer;
private DotRenderer.DrawParams mDrawParams;
private boolean mOnLeft;
@@ -78,18 +77,18 @@ public class BadgedImageView extends ImageView {
public BadgedImageView(Context context, AttributeSet attrs, int defStyleAttr,
int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
mIconBitmapSize = getResources().getDimensionPixelSize(R.dimen.bubble_icon_bitmap_size);
mBubbleBitmapSize = getResources().getDimensionPixelSize(R.dimen.bubble_bitmap_size);
mDrawParams = new DotRenderer.DrawParams();
Path iconPath = PathParser.createPathFromPathData(
getResources().getString(com.android.internal.R.string.config_icon_mask));
mDotRenderer = new DotRenderer(mIconBitmapSize, iconPath, DEFAULT_PATH_SIZE);
mDotRenderer = new DotRenderer(mBubbleBitmapSize, iconPath, DEFAULT_PATH_SIZE);
}
/**
* Updates the view with provided info.
*/
public void update(Bubble bubble) {
public void update(BubbleViewProvider bubble) {
mBubble = bubble;
setImageBitmap(bubble.getBadgedImage());
setDotState(DOT_STATE_SUPPRESSED_FOR_FLYOUT);
@@ -147,7 +146,7 @@ public class BadgedImageView extends ImageView {
* @param iconPath The new icon path to use when calculating dot position.
*/
void drawDot(Path iconPath) {
mDotRenderer = new DotRenderer(mIconBitmapSize, iconPath, DEFAULT_PATH_SIZE);
mDotRenderer = new DotRenderer(mBubbleBitmapSize, iconPath, DEFAULT_PATH_SIZE);
invalidate();
}

View File

@@ -95,6 +95,7 @@ class Bubble implements BubbleViewProvider {
private int mDotColor;
private Path mDotPath;
public static String groupId(NotificationEntry entry) {
UserHandle user = entry.getSbn().getUser();
return user.getIdentifier() + "|" + entry.getSbn().getPackageName();
@@ -111,6 +112,7 @@ class Bubble implements BubbleViewProvider {
mSuppressionListener = listener;
}
@Override
public String getKey() {
return mKey;
}
@@ -127,14 +129,17 @@ class Bubble implements BubbleViewProvider {
return mEntry.getSbn().getPackageName();
}
@Override
public Bitmap getBadgedImage() {
return mBadgedImage;
}
@Override
public int getDotColor() {
return mDotColor;
}
@Override
public Path getDotPath() {
return mDotPath;
}
@@ -150,10 +155,12 @@ class Bubble implements BubbleViewProvider {
}
@Nullable
@Override
public BadgedImageView getIconView() {
return mIconView;
}
@Override
@Nullable
public BubbleExpandedView getExpandedView() {
return mExpandedView;
@@ -240,6 +247,7 @@ class Bubble implements BubbleViewProvider {
* Note that this contents visibility doesn't affect visibility at {@link android.view.View},
* and setting {@code false} actually means rendering the expanded view in transparent.
*/
@Override
public void setContentVisibility(boolean visibility) {
if (mExpandedView != null) {
mExpandedView.setContentVisibility(visibility);
@@ -333,7 +341,8 @@ class Bubble implements BubbleViewProvider {
/**
* Whether the bubble for this notification should show a dot indicating updated content.
*/
boolean showDot() {
@Override
public boolean showDot() {
return mShowBubbleUpdateDot
&& !mEntry.shouldSuppressNotificationDot()
&& !shouldSuppressNotification();
@@ -484,6 +493,7 @@ class Bubble implements BubbleViewProvider {
return Objects.hash(mKey);
}
@Override
public void logUIEvent(int bubbleCount, int action, float normalX, float normalY, int index) {
if (this.getEntry() == null
|| this.getEntry().getSbn() == null) {

View File

@@ -94,6 +94,7 @@ public class BubbleExpandedView extends LinearLayout implements View.OnClickList
private Point mDisplaySize;
private int mMinHeight;
private int mOverflowHeight;
private int mSettingsIconHeight;
private int mPointerWidth;
private int mPointerHeight;
@@ -218,6 +219,7 @@ public class BubbleExpandedView extends LinearLayout implements View.OnClickList
mWindowManager.getDefaultDisplay().getRealSize(mDisplaySize);
Resources res = getResources();
mMinHeight = res.getDimensionPixelSize(R.dimen.bubble_expanded_default_height);
mOverflowHeight = res.getDimensionPixelSize(R.dimen.bubble_overflow_height);
mPointerMargin = res.getDimensionPixelSize(R.dimen.bubble_pointer_margin);
mExpandedViewTouchSlop = res.getDimensionPixelSize(R.dimen.bubble_expanded_view_slop);
}
@@ -420,20 +422,19 @@ public class BubbleExpandedView extends LinearLayout implements View.OnClickList
return true;
}
// TODO(138116789) Fix overflow height.
void updateHeight() {
if (DEBUG_BUBBLE_EXPANDED_VIEW) {
Log.d(TAG, "updateHeight: bubble=" + getBubbleKey());
}
if (usingActivityView()) {
float desiredHeight = mMinHeight;
float desiredHeight = mOverflowHeight;
if (!mIsOverflow) {
desiredHeight = Math.max(mBubble.getDesiredHeight(mContext), mMinHeight);
}
float height = Math.min(desiredHeight, getMaxExpandedHeight());
height = Math.max(height, mMinHeight);
height = Math.max(height, mIsOverflow? mOverflowHeight : mMinHeight);
LayoutParams lp = (LayoutParams) mActivityView.getLayoutParams();
mNeedsNewHeight = lp.height != height;
mNeedsNewHeight = lp.height != height;
if (!mKeyboardVisible) {
// If the keyboard is visible... don't adjust the height because that will cause
// a configuration change and the keyboard will be lost.

View File

@@ -58,7 +58,7 @@ public class BubbleFlyoutView extends FrameLayout {
private final int mFlyoutSpaceFromBubble;
private final int mPointerSize;
private final int mBubbleSize;
private final int mBubbleIconBitmapSize;
private final int mBubbleBitmapSize;
private final float mBubbleIconTopPadding;
private final int mFlyoutElevation;
@@ -156,13 +156,13 @@ public class BubbleFlyoutView extends FrameLayout {
mPointerSize = res.getDimensionPixelSize(R.dimen.bubble_flyout_pointer_size);
mBubbleSize = res.getDimensionPixelSize(R.dimen.individual_bubble_size);
mBubbleIconBitmapSize = res.getDimensionPixelSize(R.dimen.bubble_icon_bitmap_size);
mBubbleIconTopPadding = (mBubbleSize - mBubbleIconBitmapSize) / 2f;
mBubbleBitmapSize = res.getDimensionPixelSize(R.dimen.bubble_bitmap_size);
mBubbleIconTopPadding = (mBubbleSize - mBubbleBitmapSize) / 2f;
mBubbleElevation = res.getDimensionPixelSize(R.dimen.bubble_elevation);
mFlyoutElevation = res.getDimensionPixelSize(R.dimen.bubble_flyout_elevation);
mOriginalDotSize = SIZE_PERCENTAGE * mBubbleIconBitmapSize;
mOriginalDotSize = SIZE_PERCENTAGE * mBubbleBitmapSize;
mNewDotRadius = (DOT_SCALE * mOriginalDotSize) / 2f;
mNewDotSize = mNewDotRadius * 2f;

View File

@@ -17,18 +17,23 @@
package com.android.systemui.bubbles;
import static android.view.View.GONE;
import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
import static com.android.systemui.bubbles.BadgedImageView.DEFAULT_PATH_SIZE;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Path;
import android.graphics.drawable.AdaptiveIconDrawable;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.InsetDrawable;
import android.util.PathParser;
import android.util.TypedValue;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;
import android.widget.ImageView;
import com.android.systemui.R;
@@ -37,15 +42,24 @@ import com.android.systemui.R;
* Class for showing aged out bubbles.
*/
public class BubbleOverflow implements BubbleViewProvider {
public static final String KEY = "Overflow";
private ImageView mOverflowBtn;
private BadgedImageView mOverflowBtn;
private BubbleExpandedView mOverflowExpandedView;
private LayoutInflater mInflater;
private Context mContext;
private Bitmap mIcon;
private Path mPath;
private int mBitmapSize;
private int mIconBitmapSize;
private int mDotColor;
public BubbleOverflow(Context context) {
mContext = context;
mInflater = LayoutInflater.from(context);
mBitmapSize = mContext.getResources().getDimensionPixelSize(R.dimen.bubble_bitmap_size);
mIconBitmapSize = mContext.getResources().getDimensionPixelSize(
R.dimen.bubble_overflow_icon_bitmap_size);
}
public void setUpOverflow(ViewGroup parentViewGroup) {
@@ -54,12 +68,49 @@ public class BubbleOverflow implements BubbleViewProvider {
false /* attachToRoot */);
mOverflowExpandedView.setOverflow(true);
mOverflowBtn = (ImageView) mInflater.inflate(R.layout.bubble_overflow_button,
updateIcon(mContext, parentViewGroup);
}
// TODO(b/149146374) Propagate theme change to bubbles in overflow.
void updateIcon(Context context, ViewGroup parentViewGroup) {
mInflater = LayoutInflater.from(context);
mOverflowBtn = (BadgedImageView) mInflater.inflate(R.layout.bubble_overflow_button,
parentViewGroup /* root */,
false /* attachToRoot */);
setOverflowBtnTheme();
TypedArray ta = mContext.obtainStyledAttributes(
new int[]{android.R.attr.colorBackgroundFloating});
int bgColor = ta.getColor(0, Color.WHITE /* default */);
ta.recycle();
TypedValue typedValue = new TypedValue();
context.getTheme().resolveAttribute(android.R.attr.colorAccent, typedValue, true);
int colorAccent = mContext.getColor(typedValue.resourceId);
mOverflowBtn.getDrawable().setTint(colorAccent);
mDotColor = colorAccent;
ColorDrawable bg = new ColorDrawable(bgColor);
InsetDrawable fg = new InsetDrawable(mOverflowBtn.getDrawable(),
mBitmapSize - mIconBitmapSize /* inset */);
AdaptiveIconDrawable adaptiveIconDrawable = new AdaptiveIconDrawable(bg, fg);
BubbleIconFactory iconFactory = new BubbleIconFactory(context);
mIcon = iconFactory.createBadgedIconBitmap(adaptiveIconDrawable,
null /* user */,
true /* shrinkNonAdaptiveIcons */).icon;
float scale = iconFactory.getNormalizer().getScale(mOverflowBtn.getDrawable(),
null /* outBounds */, null /* path */, null /* outMaskShape */);
float radius = DEFAULT_PATH_SIZE / 2f;
mPath = PathParser.createPathFromPathData(
context.getResources().getString(com.android.internal.R.string.config_icon_mask));
Matrix matrix = new Matrix();
matrix.setScale(scale /* x scale */, scale /* y scale */, radius /* pivot x */,
radius /* pivot y */);
mPath.transform(matrix);
mOverflowBtn.setVisibility(GONE);
mOverflowBtn.update(this);
}
ImageView getBtn() {
@@ -70,38 +121,49 @@ public class BubbleOverflow implements BubbleViewProvider {
mOverflowBtn.setVisibility(visible);
}
// TODO(b/149146374) Propagate theme change to bubbles in overflow.
void setOverflowBtnTheme() {
TypedArray ta = mContext.obtainStyledAttributes(
new int[]{android.R.attr.colorBackgroundFloating});
int bgColor = ta.getColor(0, Color.WHITE /* default */);
ta.recycle();
InsetDrawable fg = new InsetDrawable(mOverflowBtn.getDrawable(), 28);
ColorDrawable bg = new ColorDrawable(bgColor);
AdaptiveIconDrawable adaptiveIcon = new AdaptiveIconDrawable(bg, fg);
mOverflowBtn.setImageDrawable(adaptiveIcon);
}
@Override
public BubbleExpandedView getExpandedView() {
return mOverflowExpandedView;
}
@Override
public int getDotColor() {
return mDotColor;
}
@Override
public Bitmap getBadgedImage() {
return mIcon;
}
@Override
public boolean showDot() {
return false;
}
@Override
public Path getDotPath() {
return mPath;
}
@Override
public void setContentVisibility(boolean visible) {
mOverflowExpandedView.setContentVisibility(visible);
}
@Override
public void logUIEvent(int bubbleCount, int action, float normalX, float normalY,
int index) {
// TODO(b/149133814) Log overflow UI events.
}
@Override
public View getIconView() {
return mOverflowBtn;
}
@Override
public String getKey() {
return BubbleOverflowActivity.KEY;
return BubbleOverflow.KEY;
}
}

View File

@@ -29,7 +29,6 @@ import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import android.widget.TextView;
import androidx.recyclerview.widget.GridLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
@@ -47,7 +46,6 @@ import javax.inject.Inject;
* Must be public to be accessible to androidx...AppComponentFactory
*/
public class BubbleOverflowActivity extends Activity {
public static final String KEY = "Overflow";
private static final String TAG = TAG_WITH_CLASS_NAME ? "BubbleOverflowActivity" : TAG_BUBBLES;
private LinearLayout mEmptyState;
@@ -55,7 +53,6 @@ public class BubbleOverflowActivity extends Activity {
private BubbleOverflowAdapter mAdapter;
private RecyclerView mRecyclerView;
private List<Bubble> mOverflowBubbles = new ArrayList<>();
private int mMaxBubbles;
@Inject
public BubbleOverflowActivity(BubbleController controller) {
@@ -68,17 +65,16 @@ public class BubbleOverflowActivity extends Activity {
setContentView(R.layout.bubble_overflow_activity);
setBackgroundColor();
mMaxBubbles = getResources().getInteger(R.integer.bubbles_max_rendered);
mEmptyState = findViewById(R.id.bubble_overflow_empty_state);
mRecyclerView = findViewById(R.id.bubble_overflow_recycler);
mRecyclerView.setLayoutManager(
new GridLayoutManager(getApplicationContext(),
getResources().getInteger(R.integer.bubbles_overflow_columns)));
int bubbleMargin = getResources().getDimensionPixelSize(R.dimen.bubble_overflow_margin);
mAdapter = new BubbleOverflowAdapter(mOverflowBubbles,
mBubbleController::promoteBubbleFromOverflow);
mBubbleController::promoteBubbleFromOverflow, bubbleMargin);
mRecyclerView.setAdapter(mAdapter);
onDataChanged(mBubbleController.getOverflowBubbles());
mBubbleController.setOverflowCallback(() -> {
onDataChanged(mBubbleController.getOverflowBubbles());
@@ -95,11 +91,7 @@ public class BubbleOverflowActivity extends Activity {
void onDataChanged(List<Bubble> bubbles) {
mOverflowBubbles.clear();
if (bubbles.size() > mMaxBubbles) {
mOverflowBubbles.addAll(bubbles.subList(mMaxBubbles, bubbles.size()));
} else {
mOverflowBubbles.addAll(bubbles);
}
mOverflowBubbles.addAll(bubbles);
mAdapter.notifyDataSetChanged();
if (mOverflowBubbles.isEmpty()) {
@@ -147,10 +139,13 @@ public class BubbleOverflowActivity extends Activity {
class BubbleOverflowAdapter extends RecyclerView.Adapter<BubbleOverflowAdapter.ViewHolder> {
private Consumer<Bubble> mPromoteBubbleFromOverflow;
private List<Bubble> mBubbles;
private int mBubbleMargin;
public BubbleOverflowAdapter(List<Bubble> list, Consumer<Bubble> promoteBubble) {
public BubbleOverflowAdapter(List<Bubble> list, Consumer<Bubble> promoteBubble,
int bubbleMargin) {
mBubbles = list;
mPromoteBubbleFromOverflow = promoteBubble;
mBubbleMargin = bubbleMargin;
}
@Override
@@ -158,6 +153,12 @@ class BubbleOverflowAdapter extends RecyclerView.Adapter<BubbleOverflowAdapter.V
int viewType) {
BadgedImageView view = (BadgedImageView) LayoutInflater.from(parent.getContext())
.inflate(R.layout.bubble_view, parent, false);
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.WRAP_CONTENT,
LinearLayout.LayoutParams.WRAP_CONTENT
);
params.setMargins(mBubbleMargin, mBubbleMargin, mBubbleMargin, mBubbleMargin);
view.setLayoutParams(params);
return new ViewHolder(view);
}

View File

@@ -408,13 +408,7 @@ public class BubbleStackView extends FrameLayout {
setFocusable(true);
mBubbleContainer.bringToFront();
mBubbleOverflow = new BubbleOverflow(mContext);
if (BubbleExperimentConfig.allowBubbleOverflow(mContext)) {
mBubbleOverflow.setUpOverflow(this);
mBubbleContainer.addView(mBubbleOverflow.getBtn(), 0,
new FrameLayout.LayoutParams(WRAP_CONTENT, WRAP_CONTENT));
}
setUpOverflow();
setOnApplyWindowInsetsListener((View view, WindowInsets insets) -> {
if (!mIsExpanded || mIsExpansionAnimating) {
@@ -523,14 +517,29 @@ public class BubbleStackView extends FrameLayout {
addView(mFlyout, new FrameLayout.LayoutParams(WRAP_CONTENT, WRAP_CONTENT));
}
private void setUpOverflow() {
if (!BubbleExperimentConfig.allowBubbleOverflow(mContext)) {
return;
}
int overflowBtnIndex = 0;
if (mBubbleOverflow == null) {
mBubbleOverflow = new BubbleOverflow(mContext);
mBubbleOverflow.setUpOverflow(this);
} else {
mBubbleContainer.removeView(mBubbleOverflow.getBtn());
mBubbleOverflow.updateIcon(mContext, this);
overflowBtnIndex = mBubbleContainer.getChildCount() - 1;
}
mBubbleContainer.addView(mBubbleOverflow.getBtn(), overflowBtnIndex,
new FrameLayout.LayoutParams(WRAP_CONTENT, WRAP_CONTENT));
}
/**
* Handle theme changes.
*/
public void onThemeChanged() {
setUpFlyout();
if (BubbleExperimentConfig.allowBubbleOverflow(mContext)) {
mBubbleOverflow.setOverflowBtnTheme();
}
setUpOverflow();
}
/** Respond to the phone being rotated by repositioning the stack and hiding any flyouts. */
@@ -724,7 +733,7 @@ public class BubbleStackView extends FrameLayout {
if (mExpandedBubble == null
|| (BubbleExperimentConfig.allowBubbleOverflow(mContext)
&& mExpandedBubble.getIconView() == mBubbleOverflow.getBtn()
&& mExpandedBubble.getKey() == BubbleOverflowActivity.KEY)) {
&& mExpandedBubble.getKey() == BubbleOverflow.KEY)) {
return null;
}
return (Bubble) mExpandedBubble;
@@ -1649,7 +1658,7 @@ public class BubbleStackView extends FrameLayout {
* is between 0 and the bubble count minus 1.
*/
int getBubbleIndex(@Nullable BubbleViewProvider provider) {
if (provider == null || provider.getKey() == BubbleOverflowActivity.KEY) {
if (provider == null || provider.getKey() == BubbleOverflow.KEY) {
return 0;
}
Bubble b = (Bubble) provider;

View File

@@ -100,9 +100,6 @@ class BubbleTouchHandler implements View.OnTouchListener {
&& !(mTouchedView instanceof BubbleStackView)
&& !(mTouchedView instanceof BubbleFlyoutView)) {
if (mTouchedView.getId() == R.id.bubble_overflow_button) {
mStack.showOverflow();
}
// Not touching anything touchable, but we shouldn't collapse (e.g. touching edge
// of expanded view).
resetForNextGesture();
@@ -225,9 +222,12 @@ class BubbleTouchHandler implements View.OnTouchListener {
mBubbleData.setExpanded(!mBubbleData.isExpanded());
} else {
final String key = ((BadgedImageView) mTouchedView).getKey();
mBubbleData.setSelectedBubble(mBubbleData.getBubbleWithKey(key));
if (key == BubbleOverflow.KEY) {
mStack.showOverflow();
} else {
mBubbleData.setSelectedBubble(mBubbleData.getBubbleWithKey(key));
}
}
resetForNextGesture();
break;
}

View File

@@ -16,6 +16,8 @@
package com.android.systemui.bubbles;
import android.graphics.Bitmap;
import android.graphics.Path;
import android.view.View;
/**
@@ -23,8 +25,20 @@ import android.view.View;
*/
interface BubbleViewProvider {
BubbleExpandedView getExpandedView();
void setContentVisibility(boolean visible);
View getIconView();
void logUIEvent(int bubbleCount, int action, float normalX, float normalY, int index);
String getKey();
Bitmap getBadgedImage();
int getDotColor();
Path getDotPath();
boolean showDot();
}

View File

@@ -147,7 +147,7 @@ public class StackAnimationController extends
/** Horizontal offset of bubbles in the stack. */
private float mStackOffset;
/** Diameter of the bubble icon. */
private int mBubbleIconBitmapSize;
private int mBubbleBitmapSize;
/** Width of the bubble (icon and padding). */
private int mBubbleSize;
/**
@@ -194,7 +194,7 @@ public class StackAnimationController extends
return false;
}
float stackCenter = mStackPosition.x + mBubbleIconBitmapSize / 2;
float stackCenter = mStackPosition.x + mBubbleBitmapSize / 2;
float screenCenter = mLayout.getWidth() / 2;
return stackCenter < screenCenter;
}
@@ -227,7 +227,7 @@ public class StackAnimationController extends
* @return The X value that the stack will end up at after the fling/spring.
*/
public float flingStackThenSpringToEdge(float x, float velX, float velY) {
final boolean stackOnLeftSide = x - mBubbleIconBitmapSize / 2 < mLayout.getWidth() / 2;
final boolean stackOnLeftSide = x - mBubbleBitmapSize / 2 < mLayout.getWidth() / 2;
final boolean stackShouldFlingLeft = stackOnLeftSide
? velX < ESCAPE_VELOCITY
@@ -542,7 +542,7 @@ public class StackAnimationController extends
new SpringForce()
.setDampingRatio(SpringForce.DAMPING_RATIO_LOW_BOUNCY)
.setStiffness(SpringForce.STIFFNESS_MEDIUM),
velX, mLayout.getWidth() / 2f - mBubbleIconBitmapSize / 2f);
velX, mLayout.getWidth() / 2f - mBubbleBitmapSize / 2f);
springFirstBubbleWithStackFollowing(
DynamicAnimation.TRANSLATION_Y,
@@ -705,7 +705,7 @@ public class StackAnimationController extends
Resources res = layout.getResources();
mStackOffset = res.getDimensionPixelSize(R.dimen.bubble_stack_offset);
mBubbleSize = res.getDimensionPixelSize(R.dimen.individual_bubble_size);
mBubbleIconBitmapSize = res.getDimensionPixelSize(R.dimen.bubble_icon_bitmap_size);
mBubbleBitmapSize = res.getDimensionPixelSize(R.dimen.bubble_bitmap_size);
mBubblePaddingTop = res.getDimensionPixelSize(R.dimen.bubble_padding_top);
mBubbleOffscreen = res.getDimensionPixelSize(R.dimen.bubble_stack_offscreen);
mStackStartingVerticalOffset =