diff --git a/packages/SystemUI/res/layout/bubble_expanded_view.xml b/packages/SystemUI/res/layout/bubble_expanded_view.xml
new file mode 100644
index 0000000000000..b2307e71e3ce5
--- /dev/null
+++ b/packages/SystemUI/res/layout/bubble_expanded_view.xml
@@ -0,0 +1,30 @@
+
+
+
+
+
+
+
+
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 8e0bfb65428e9..4b07b5f132904 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -991,4 +991,8 @@
24dp
400dp
+
+ 4dp
+
+ 6dp
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedViewContainer.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedViewContainer.java
new file mode 100644
index 0000000000000..e28d96b2def93
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedViewContainer.java
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2018 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 com.android.systemui.bubbles;
+
+import android.annotation.Nullable;
+import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.Color;
+import android.graphics.drawable.ShapeDrawable;
+import android.util.AttributeSet;
+import android.view.View;
+import android.widget.LinearLayout;
+
+import com.android.systemui.R;
+import com.android.systemui.recents.TriangleShape;
+
+/**
+ * Container for the expanded bubble view, handles rendering the caret and header of the view.
+ */
+public class BubbleExpandedViewContainer extends LinearLayout {
+
+ // The triangle pointing to the expanded view
+ private View mPointerView;
+ // The view that is being displayed for the expanded state
+ private View mExpandedView;
+
+ public BubbleExpandedViewContainer(Context context) {
+ this(context, null);
+ }
+
+ public BubbleExpandedViewContainer(Context context, AttributeSet attrs) {
+ this(context, attrs, 0);
+ }
+
+ public BubbleExpandedViewContainer(Context context, AttributeSet attrs, int defStyleAttr) {
+ this(context, attrs, defStyleAttr, 0);
+ }
+
+ public BubbleExpandedViewContainer(Context context, AttributeSet attrs, int defStyleAttr,
+ int defStyleRes) {
+ super(context, attrs, defStyleAttr, defStyleRes);
+ setOrientation(VERTICAL);
+ }
+
+ @Override
+ protected void onFinishInflate() {
+ super.onFinishInflate();
+
+ Resources res = getResources();
+ mPointerView = findViewById(R.id.pointer_view);
+ int width = res.getDimensionPixelSize(R.dimen.bubble_pointer_width);
+ int height = res.getDimensionPixelSize(R.dimen.bubble_pointer_height);
+ ShapeDrawable triangleDrawable = new ShapeDrawable(
+ TriangleShape.create(width, height, true /* pointUp */));
+ triangleDrawable.setTint(Color.WHITE); // TODO: dark mode
+ mPointerView.setBackground(triangleDrawable);
+ }
+
+ /**
+ * Set the x position that the tip of the triangle should point to.
+ */
+ public void setPointerPosition(int x) {
+ // Adjust for the pointer size
+ x -= (mPointerView.getWidth() / 2);
+ mPointerView.setTranslationX(x);
+ }
+
+ /**
+ * Set the view to display for the expanded state. Passing null will clear the view.
+ */
+ public void setExpandedView(View view) {
+ if (mExpandedView != null) {
+ removeView(mExpandedView);
+ }
+ mExpandedView = view;
+ if (mExpandedView != null) {
+ addView(mExpandedView);
+ }
+ }
+
+ /**
+ * @return the view containing the expanded content, can be null.
+ */
+ @Nullable
+ public View getExpandedView() {
+ return mExpandedView;
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
index e395c4c2765c8..dfd18b23a5e39 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
@@ -25,6 +25,7 @@ import android.content.Context;
import android.content.res.Resources;
import android.graphics.Point;
import android.graphics.RectF;
+import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
@@ -52,7 +53,7 @@ public class BubbleStackView extends FrameLayout implements BubbleTouchHandler.F
private Point mDisplaySize;
private FrameLayout mBubbleContainer;
- private FrameLayout mExpandedViewContainer;
+ private BubbleExpandedViewContainer mExpandedViewContainer;
private int mBubbleSize;
private int mBubblePadding;
@@ -111,7 +112,9 @@ public class BubbleStackView extends FrameLayout implements BubbleTouchHandler.F
int padding = res.getDimensionPixelSize(R.dimen.bubble_expanded_view_padding);
int elevation = res.getDimensionPixelSize(R.dimen.bubble_elevation);
- mExpandedViewContainer = new FrameLayout(context);
+ mExpandedViewContainer = (BubbleExpandedViewContainer)
+ LayoutInflater.from(context).inflate(R.layout.bubble_expanded_view,
+ this /* parent */, false /* attachToRoot */);
mExpandedViewContainer.setElevation(elevation);
mExpandedViewContainer.setPadding(padding, padding, padding, padding);
mExpandedViewContainer.setClipChildren(false);
@@ -390,16 +393,19 @@ public class BubbleStackView extends FrameLayout implements BubbleTouchHandler.F
ExpandableNotificationRow row = mExpandedBubble.getRowView();
if (!row.equals(mExpandedViewContainer.getChildAt(0))) {
// Different expanded view than what we have
- mExpandedViewContainer.removeAllViews();
+ mExpandedViewContainer.setExpandedView(null);
}
- mExpandedViewContainer.addView(row);
+ int pointerPosition = mExpandedBubble.getPosition().x
+ + (mExpandedBubble.getWidth() / 2);
+ mExpandedViewContainer.setPointerPosition(pointerPosition);
+ mExpandedViewContainer.setExpandedView(row);
}
}
private void applyCurrentState() {
mExpandedViewContainer.setVisibility(mIsExpanded ? VISIBLE : GONE);
if (!mIsExpanded) {
- mExpandedViewContainer.removeAllViews();
+ mExpandedViewContainer.setExpandedView(null);
} else {
mExpandedViewContainer.setTranslationY(mBubbleContainer.getHeight());
ExpandableNotificationRow row = mExpandedBubble.getRowView();