Improve RemoteViews to simplify notification view hierarchy.
Test: manual
Change-Id: Iab1579a3e992a53f1e44ff7236511d1093de048f
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 587a7cc..4c5044d 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -6701,8 +6701,7 @@
customContent = customContent.clone();
if (p.mHeaderless) {
if (decorationType <= DevFlags.DECORATION_PARTIAL) {
- template.removeAllViewsExceptId(R.id.notification_top_line_container,
- R.id.notification_main_column);
+ template.removeFromParent(R.id.notification_top_line);
}
if (decorationType != DevFlags.DECORATION_FULL_COMPATIBLE) {
// Change the max content size from 60dp (the compatible size) to 48dp
diff --git a/core/java/android/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java
index 4a84851..5176b7e 100644
--- a/core/java/android/widget/RemoteViews.java
+++ b/core/java/android/widget/RemoteViews.java
@@ -73,6 +73,8 @@
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewGroup.MarginLayoutParams;
+import android.view.ViewManager;
+import android.view.ViewParent;
import android.view.ViewStub;
import android.widget.AdapterView.OnItemClickListener;
@@ -175,6 +177,7 @@
private static final int OVERRIDE_TEXT_COLORS_TAG = 20;
private static final int SET_RIPPLE_DRAWABLE_COLOR_TAG = 21;
private static final int SET_INT_TAG_TAG = 22;
+ private static final int REMOVE_FROM_PARENT_ACTION_TAG = 23;
/** @hide **/
@IntDef(prefix = "MARGIN_", value = {
@@ -1827,6 +1830,75 @@
}
/**
+ * Action to remove a view from its parent.
+ */
+ private class RemoveFromParentAction extends Action {
+
+ RemoveFromParentAction(@IdRes int viewId) {
+ this.viewId = viewId;
+ }
+
+ RemoveFromParentAction(Parcel parcel) {
+ viewId = parcel.readInt();
+ }
+
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(viewId);
+ }
+
+ @Override
+ public void apply(View root, ViewGroup rootParent, OnClickHandler handler) {
+ final View target = root.findViewById(viewId);
+
+ if (target == null || target == root) {
+ return;
+ }
+
+ ViewParent parent = target.getParent();
+ if (parent instanceof ViewManager) {
+ ((ViewManager) parent).removeView(target);
+ }
+ }
+
+ @Override
+ public Action initActionAsync(ViewTree root, ViewGroup rootParent, OnClickHandler handler) {
+ // In the async implementation, update the view tree so that subsequent calls to
+ // findViewById return the correct view.
+ root.createTree();
+ ViewTree target = root.findViewTreeById(viewId);
+
+ if (target == null || target == root) {
+ return ACTION_NOOP;
+ }
+
+ ViewTree parent = root.findViewTreeParentOf(target);
+ if (parent == null || !(parent.mRoot instanceof ViewManager)) {
+ return ACTION_NOOP;
+ }
+ final ViewManager parentVg = (ViewManager) parent.mRoot;
+
+ parent.mChildren.remove(target);
+ return new RuntimeAction() {
+ @Override
+ public void apply(View root, ViewGroup rootParent, OnClickHandler handler)
+ throws ActionException {
+ parentVg.removeView(target.mRoot);
+ }
+ };
+ }
+
+ @Override
+ public int getActionTag() {
+ return REMOVE_FROM_PARENT_ACTION_TAG;
+ }
+
+ @Override
+ public int mergeBehavior() {
+ return MERGE_APPEND;
+ }
+ }
+
+ /**
* Helper action to set compound drawables on a TextView. Supports relative
* (s/t/e/b) or cardinal (l/t/r/b) arrangement.
*/
@@ -2531,6 +2603,8 @@
return new SetRippleDrawableColor(parcel);
case SET_INT_TAG_TAG:
return new SetIntTagAction(parcel);
+ case REMOVE_FROM_PARENT_ACTION_TAG:
+ return new RemoveFromParentAction(parcel);
default:
throw new ActionException("Tag " + tag + " not found");
}
@@ -2669,6 +2743,18 @@
}
/**
+ * Removes the {@link View} specified by the {@code viewId} from its parent {@link ViewManager}.
+ * This will do nothing if the viewId specifies the root view of this RemoteViews.
+ *
+ * @param viewId The id of the {@link View} to remove from its parent.
+ *
+ * @hide
+ */
+ public void removeFromParent(@IdRes int viewId) {
+ addAction(new RemoveFromParentAction(viewId));
+ }
+
+ /**
* Equivalent to calling {@link AdapterViewAnimator#showNext()}
*
* @param viewId The id of the view on which to call {@link AdapterViewAnimator#showNext()}
@@ -4013,6 +4099,22 @@
return null;
}
+ public ViewTree findViewTreeParentOf(ViewTree child) {
+ if (mChildren == null) {
+ return null;
+ }
+ for (ViewTree tree : mChildren) {
+ if (tree == child) {
+ return this;
+ }
+ ViewTree result = tree.findViewTreeParentOf(child);
+ if (result != null) {
+ return result;
+ }
+ }
+ return null;
+ }
+
public void replaceView(View v) {
mRoot = v;
mChildren = null;
diff --git a/core/res/res/layout/notification_template_material_base.xml b/core/res/res/layout/notification_template_material_base.xml
index a045e15..41be36b 100644
--- a/core/res/res/layout/notification_template_material_base.xml
+++ b/core/res/res/layout/notification_template_material_base.xml
@@ -109,51 +109,38 @@
android:layout_weight="1"
/>
- <!--
- Because RemoteViews doesn't allow us to remove specific views, this container allows us
- to remove the NotificationTopLineView without removing other padding items.
- -->
- <FrameLayout
- android:id="@+id/notification_top_line_container"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
+ <!-- extends ViewGroup -->
+ <NotificationTopLineView
+ android:id="@+id/notification_top_line"
+ android:layout_width="wrap_content"
+ android:layout_height="@dimen/notification_headerless_line_height"
+ android:layout_marginEnd="@dimen/notification_heading_margin_end"
+ android:layout_marginStart="@dimen/notification_content_margin_start"
android:clipChildren="false"
+ android:theme="@style/Theme.DeviceDefault.Notification"
>
- <!-- extends ViewGroup -->
- <NotificationTopLineView
- android:id="@+id/notification_top_line"
+ <!--
+ NOTE: The notification_top_line_views layout contains the app_name_text.
+ In order to include the title view at the beginning, the Notification.Builder
+ has logic to hide that view whenever this title view is to be visible.
+ -->
+
+ <TextView
+ android:id="@+id/title"
android:layout_width="wrap_content"
- android:layout_height="@dimen/notification_headerless_line_height"
- android:layout_marginEnd="@dimen/notification_heading_margin_end"
- android:layout_marginStart="@dimen/notification_content_margin_start"
- android:clipChildren="false"
- android:theme="@style/Theme.DeviceDefault.Notification"
- >
+ android:layout_height="wrap_content"
+ android:layout_marginEnd="@dimen/notification_header_separating_margin"
+ android:ellipsize="marquee"
+ android:fadingEdge="horizontal"
+ android:singleLine="true"
+ android:textAlignment="viewStart"
+ android:textAppearance="@style/TextAppearance.DeviceDefault.Notification.Title"
+ />
- <!--
- NOTE: The notification_top_line_views layout contains the app_name_text.
- In order to include the title view at the beginning, the Notification.Builder
- has logic to hide that view whenever this title view is to be visible.
- -->
+ <include layout="@layout/notification_top_line_views" />
- <TextView
- android:id="@+id/title"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginEnd="@dimen/notification_header_separating_margin"
- android:ellipsize="marquee"
- android:fadingEdge="horizontal"
- android:singleLine="true"
- android:textAlignment="viewStart"
- android:textAppearance="@style/TextAppearance.DeviceDefault.Notification.Title"
- />
-
- <include layout="@layout/notification_top_line_views" />
-
- </NotificationTopLineView>
-
- </FrameLayout>
+ </NotificationTopLineView>
<LinearLayout
android:id="@+id/notification_main_column"
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index beb0059..9b06285 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -2876,7 +2876,6 @@
<java-symbol type="id" name="alternate_expand_target" />
<java-symbol type="id" name="notification_header" />
<java-symbol type="id" name="notification_top_line" />
- <java-symbol type="id" name="notification_top_line_container" />
<java-symbol type="id" name="notification_headerless_margin_extra_top" />
<java-symbol type="id" name="notification_headerless_margin_extra_bottom" />
<java-symbol type="id" name="time_divider" />