Another redesign of notification guts

- Separate out the blocking helper layout/logic a bit
more from the standard guts
- Colors! Larger text! big buttons! Persistent descriptions
of the behavior you're choosing
- No more special 'min' logic
- no more inline blocking
- placeholder text for what's shown when multiple channels are
involved
- both 'turn off notifications' and the settings gear currently
go to the same place

Test: atest
Bug: 127992400
Change-Id: I080335fab728c4ac269e093d09c2f6b5ffdaea5e
This commit is contained in:
Julia Reynolds
2019-04-03 11:00:17 -04:00
parent bbc42684cc
commit 52a2737b55
14 changed files with 598 additions and 848 deletions

View File

@@ -0,0 +1,40 @@
<!--
Copyright (C) 2019 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.
-->
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="@+id/back">
<shape android:shape="oval">
<solid
android:color="@color/GM2_green_500" />
<size
android:height="36dp"
android:width="36dp"/>
</shape>
</item>
<item
android:id="@+id/fore"
android:gravity="center">
<vector
android:width="32dp"
android:height="32dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="#FFFFFFFF"
android:pathData="M15,14.5c-1.38,0 -2.5,-1.12 -2.5,-2.5c0,-0.28 -0.22,-0.5 -0.5,-0.5s-0.5,0.22 -0.5,0.5c0,1.38 -1.12,2.5 -2.5,2.5S6.5,13.38 6.5,12c0,-0.28 -0.22,-0.5 -0.5,-0.5c-0.24,0 -0.46,0.18 -0.49,0.42C5.41,12.55 4.89,13 4.27,13H2v-2h1.71C4.1,10.11 5,9.5 6,9.5c1.38,0 2.5,1.12 2.5,2.5c0,0.28 0.22,0.5 0.5,0.5s0.5,-0.22 0.5,-0.5c0,-1.38 1.12,-2.5 2.5,-2.5s2.5,1.12 2.5,2.5c0,0.28 0.22,0.5 0.5,0.5s0.5,-0.22 0.5,-0.5c0,-1.38 1.12,-2.5 2.5,-2.5c1.02,0 1.91,0.6 2.29,1.5H22v2h-2.27c-0.62,0 -1.14,-0.45 -1.23,-1.08c-0.04,-0.24 -0.25,-0.42 -0.49,-0.42c-0.28,0 -0.5,0.22 -0.5,0.5C17.5,13.38 16.38,14.5 15,14.5z"/>
</vector>
</item>
</layer-list>

View File

@@ -0,0 +1,41 @@
<!--
Copyright (C) 2019 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.
-->
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="@+id/back">
<shape android:shape="oval">
<solid
android:color="@color/GM2_yellow_500" />
<size
android:height="36dp"
android:width="36dp"/>
</shape>
</item>
<item
android:id="@+id/fore"
android:gravity="center">
<vector
android:width="32dp"
android:height="32dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="#FFFFFFFF"
android:pathData="M8.98,16.65c-0.47,0 -0.91,-0.27 -1.12,-0.69l-1.93,-4.61L5.46,12.3c-0.21,0.43 -0.64,0.69 -1.12,0.69H2v-2h1.88l1,-2C5.1,8.56 5.52,8.3 6,8.3s0.9,0.26 1.12,0.69l1.73,4.14l2,-7c0.2,-0.46 0.65,-0.76 1.15,-0.76s0.95,0.3 1.15,0.76l0.04,0.12l1.96,6.88l1.7,-4.08c0.49,-0.98 1.84,-0.91 2.26,-0.06l1,2H22v2h-2.35c-0.47,0 -0.91,-0.27 -1.12,-0.7l-0.47,-0.95l-1.9,4.55c-0.25,0.5 -0.69,0.77 -1.18,0.75c-0.48,-0.01 -0.92,-0.31 -1.11,-0.76l-0.04,-0.12L12,9.37l-1.87,6.52c-0.19,0.45 -0.63,0.74 -1.11,0.76C9.01,16.65 9,16.65 8.98,16.65zM20.32,11.4L20.32,11.4C20.32,11.4 20.32,11.4 20.32,11.4z" />
</vector>
</item>
</layer-list>

View File

@@ -24,6 +24,7 @@
android:clipChildren="false"
android:clipToPadding="false"
android:orientation="vertical"
android:paddingStart="@*android:dimen/notification_content_margin_start"
android:background="@color/notification_guts_bg_color">
<!-- Package Info -->
@@ -31,7 +32,6 @@
android:id="@+id/header"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="@*android:dimen/notification_content_margin_start"
android:clipChildren="false"
android:clipToPadding="false">
<ImageView
@@ -44,7 +44,7 @@
android:id="@+id/pkgname"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Notification.Info"
style="@style/TextAppearance.NotificationInfo.Primary"
android:layout_marginStart="3dp"
android:layout_marginEnd="2dp"
android:singleLine="true"
@@ -54,7 +54,7 @@
android:id="@+id/pkg_divider"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Notification.Info"
style="@style/TextAppearance.NotificationInfo.Primary"
android:layout_marginStart="2dp"
android:layout_marginEnd="2dp"
android:text="@*android:string/notification_header_divider_symbol"
@@ -64,7 +64,7 @@
android:id="@+id/delegate_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Notification.Info"
style="@style/TextAppearance.NotificationInfo.Primary"
android:layout_marginStart="2dp"
android:layout_marginEnd="2dp"
android:ellipsize="end"
@@ -77,286 +77,284 @@
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_alignParentEnd="true"
android:paddingHorizontal="16dp"
android:orientation="horizontal">
<!-- Optional link to app. Only appears if the channel is not disabled and the app
asked for it -->
<ImageButton
android:id="@+id/app_settings"
android:layout_width="40dp"
android:layout_height="56dp"
android:layout_width="48dp"
android:layout_height="48dp"
android:layout_centerVertical="true"
android:paddingRight="16dp"
android:visibility="gone"
android:background="@drawable/ripple_drawable"
android:contentDescription="@string/notification_app_settings"
android:src="@drawable/ic_settings"
android:tint="?android:attr/colorAccent" />
android:src="@drawable/ic_info"
android:tint="@color/notification_guts_link_icon_tint" />
<!-- 24 dp icon with 16 dp padding all around to mirror notification content margins -->
<ImageButton
android:id="@+id/info"
android:layout_width="24dp"
android:layout_height="56dp"
android:layout_width="48dp"
android:layout_height="48dp"
android:layout_centerVertical="true"
android:background="@drawable/ripple_drawable"
android:contentDescription="@string/notification_more_settings"
android:src="@drawable/ic_info"
android:tint="?android:attr/colorAccent" />
android:src="@drawable/ic_settings"
android:tint="@color/notification_guts_link_icon_tint" />
</LinearLayout>
</RelativeLayout>
<!-- Channel Info Block -->
<LinearLayout
android:id="@+id/prompt"
android:id="@+id/channel_info"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="@dimen/notification_guts_button_spacing"
android:paddingEnd="@*android:dimen/notification_content_margin_end"
android:orientation="vertical">
<RelativeLayout
android:id="@+id/names"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="@+id/group_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
style="@style/TextAppearance.NotificationInfo.Primary"
android:layout_marginStart="2dp"
android:layout_marginEnd="2dp"
android:ellipsize="end"
android:maxLines="1"
android:layout_centerVertical="true" />
<TextView
android:id="@+id/pkg_group_divider"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
style="@style/TextAppearance.NotificationInfo.Primary"
android:layout_marginStart="2dp"
android:layout_marginEnd="2dp"
android:text="@*android:string/notification_header_divider_symbol"
android:layout_centerVertical="true"
android:layout_toEndOf="@id/group_name" />
<!-- Channel Name -->
<TextView
android:id="@+id/channel_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
style="@style/TextAppearance.NotificationInfo.Primary"
android:layout_toEndOf="@id/pkg_group_divider"/>
</RelativeLayout>
</LinearLayout>
<LinearLayout
android:id="@+id/blocking_helper"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="@dimen/notification_guts_button_spacing"
android:paddingEnd="@*android:dimen/notification_content_margin_end"
android:clipChildren="false"
android:clipToPadding="false"
android:orientation="vertical">
<!-- blocking helper text. no need for non-configurable check b/c controls won't be
activated in that case -->
<TextView
android:id="@+id/blocking_helper_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="2dp"
android:text="@string/inline_blocking_helper"
style="@*android:style/TextAppearance.DeviceDefault.Notification" />
<RelativeLayout
android:id="@+id/block_buttons"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/notification_guts_button_spacing">
<TextView
android:id="@+id/blocking_helper_turn_off_notifications"
android:text="@string/inline_turn_off_notifications"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_alignParentStart="true"
android:width="110dp"
android:paddingEnd="15dp"
android:breakStrategy="simple"
style="@style/TextAppearance.NotificationInfo.Button"/>
<TextView
android:id="@+id/deliver_silently"
android:text="@string/inline_deliver_silently_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_marginStart="@dimen/notification_guts_button_horizontal_spacing"
android:paddingEnd="15dp"
android:width="110dp"
android:breakStrategy="simple"
android:layout_toStartOf="@+id/keep_showing"
style="@style/TextAppearance.NotificationInfo.Button"/>
<TextView
android:id="@+id/keep_showing"
android:text="@string/inline_keep_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_marginStart="@dimen/notification_guts_button_horizontal_spacing"
android:width="110dp"
android:breakStrategy="simple"
android:layout_alignParentEnd="true"
style="@style/TextAppearance.NotificationInfo.Button"/>
</RelativeLayout>
</LinearLayout>
<LinearLayout
android:id="@+id/inline_controls"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="@dimen/notification_guts_button_spacing"
android:paddingEnd="@*android:dimen/notification_content_margin_end"
android:clipChildren="false"
android:clipToPadding="false"
android:orientation="vertical">
<!-- Channel Info Block -->
<LinearLayout
<!-- Non configurable app/channel text. appears instead of @+id/interruptiveness_settings-->
<TextView
android:id="@+id/non_configurable_text"
android:text="@string/notification_unblockable_desc"
android:visibility="gone"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="@dimen/notification_guts_option_vertical_padding"
style="@*android:style/TextAppearance.DeviceDefault.Notification" />
<!-- Non configurable multichannel text. appears instead of @+id/interruptiveness_settings-->
<TextView
android:id="@+id/non_configurable_multichannel_text"
android:text="@string/notification_multichannel_desc"
android:visibility="gone"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="@dimen/notification_guts_option_vertical_padding"
style="@*android:style/TextAppearance.DeviceDefault.Notification" />
<LinearLayout
android:id="@+id/interruptiveness_settings"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="@*android:dimen/notification_content_margin_start"
android:layout_marginEnd="@*android:dimen/notification_content_margin_start"
android:orientation="vertical">
<RelativeLayout
android:id="@+id/names"
<!-- Interruptive row -->
<LinearLayout
android:id="@+id/alert_row"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="@+id/group_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Notification.Title"
android:layout_marginStart="2dp"
android:layout_marginEnd="2dp"
android:ellipsize="end"
android:maxLines="1"
android:layout_centerVertical="true" />
<TextView
android:id="@+id/pkg_group_divider"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Notification.Title"
android:layout_marginStart="2dp"
android:layout_marginEnd="2dp"
android:text="@*android:string/notification_header_divider_symbol"
android:layout_centerVertical="true"
android:layout_toEndOf="@id/group_name" />
<!-- Channel Name -->
<TextView
android:id="@+id/channel_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
style="@*android:style/TextAppearance.DeviceDefault.Notification.Title"
android:layout_toEndOf="@id/pkg_group_divider"/>
</RelativeLayout>
<!-- Question prompt -->
<TextView
android:id="@+id/block_prompt"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
style="@*android:style/TextAppearance.DeviceDefault.Notification" />
android:paddingTop="@dimen/notification_guts_option_vertical_padding"
android:paddingBottom="@dimen/notification_guts_option_vertical_padding"
android:paddingStart="@dimen/notification_guts_option_horizontal_padding"
android:orientation="horizontal">
<ImageView
android:id="@+id/int_alert"
android:src="@drawable/ic_notification_interruptive"
android:background="@android:color/transparent"
android:layout_gravity="center"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:contentDescription="@string/inline_silent_button_alert"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingStart="@dimen/notification_guts_option_horizontal_padding"
android:paddingEnd="@dimen/notification_guts_option_horizontal_padding"
android:orientation="vertical">
<TextView
android:id="@+id/int_alert_label"
android:text="@string/inline_silent_button_alert"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ellipsize="end"
android:maxLines="1"
style="@style/TextAppearance.NotificationInfo.Primary"/>
<TextView
android:id="@+id/int_alert_summary"
android:text="@string/hint_text_alert"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ellipsize="end"
style="@style/TextAppearance.NotificationInfo.Secondary"/>
</LinearLayout>
</LinearLayout>
<!-- Gentle row -->
<LinearLayout
android:id="@+id/silent_row"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="@dimen/notification_guts_option_vertical_padding"
android:paddingBottom="@dimen/notification_guts_option_vertical_padding"
android:paddingStart="@dimen/notification_guts_option_horizontal_padding"
android:layout_marginTop="@dimen/notification_guts_option_vertical_margin"
android:orientation="horizontal">
<ImageView
android:id="@+id/int_silent"
android:src="@drawable/ic_notification_gentle"
android:layout_gravity="center"
android:layout_width="36dp"
android:layout_height="36dp"
android:background="@android:color/transparent"
android:contentDescription="@string/inline_silent_button_silent"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:paddingStart="@dimen/notification_guts_option_horizontal_padding"
android:paddingEnd="@dimen/notification_guts_option_horizontal_padding">
<TextView
android:id="@+id/int_silent_label"
android:text="@string/inline_silent_button_silent"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ellipsize="end"
android:maxLines="1"
style="@style/TextAppearance.NotificationInfo.Primary"/>
<TextView
android:id="@+id/int_silent_summary"
android:text="@string/hint_text_silent"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ellipsize="end"
style="@style/TextAppearance.NotificationInfo.Secondary"/>
</LinearLayout>
</LinearLayout>
</LinearLayout>
<!-- Settings and Done buttons -->
<RelativeLayout
android:id="@+id/block_or_minimize"
android:id="@+id/bottom_buttons"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/notification_guts_button_spacing"
android:layout_marginStart="@dimen/notification_guts_button_side_margin"
android:layout_marginEnd="@dimen/notification_guts_button_side_margin"
android:clipChildren="false"
android:clipToPadding="false">
android:paddingTop="@dimen/notification_guts_button_spacing"
android:paddingBottom="@dimen/notification_guts_button_spacing">
<TextView
android:id="@+id/turn_off_notifications"
android:text="@string/inline_turn_off_notifications"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_alignParentStart="true"
android:maxWidth="200dp"
style="@style/TextAppearance.NotificationInfo.Button"/>
<TextView
android:id="@+id/done"
android:text="@string/inline_ok_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:maxWidth="100dp"
style="@style/TextAppearance.NotificationInfo.Button"/>
<LinearLayout
android:id="@+id/block_buttons"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:maxWidth="125dp"
android:layout_alignParentEnd="true"
android:maxWidth="200dp"
android:orientation="horizontal">
<TextView
android:id="@+id/deliver_silently"
android:text="@string/inline_silent_button_silent"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_marginStart="@dimen/notification_guts_button_horizontal_spacing"
android:paddingRight="24dp"
android:maxWidth="125dp"
style="@style/TextAppearance.NotificationInfo.Button"/>
<TextView
android:id="@+id/block"
android:text="@string/inline_block_button"
android:minWidth="48dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:maxWidth="75dp"
android:layout_marginStart="@dimen/notification_guts_button_horizontal_spacing"
style="@style/TextAppearance.NotificationInfo.Button"/>
<TextView
android:id="@+id/minimize"
android:text="@string/inline_minimize_button"
android:minWidth="48dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:maxWidth="75dp"
android:layout_marginStart="@dimen/notification_guts_button_horizontal_spacing"
style="@style/TextAppearance.NotificationInfo.Button"/>
</LinearLayout>
style="@style/TextAppearance.NotificationInfo.Button"/>
</RelativeLayout>
<LinearLayout
android:id="@+id/interruptiveness_settings"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:visibility="gone">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="2dp"
android:layout_marginStart="@dimen/notification_guts_button_side_margin"
android:layout_marginEnd="@dimen/notification_guts_button_side_margin"
android:gravity="center"
android:orientation="horizontal">
<LinearLayout
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:gravity="center_horizontal"
android:orientation="vertical">
<FrameLayout
android:id="@+id/int_block_wrapper"
android:padding="4dp"
android:layout_width="48dp"
android:layout_height="48dp"
android:gravity="center">
<ImageButton
android:id="@+id/int_block"
android:background="@drawable/circle_white_40dp"
android:src="@drawable/ic_notification_block"
android:layout_gravity="center"
android:layout_width="40dp"
android:layout_height="40dp"
android:clickable="false"
android:contentDescription="@string/inline_block_button"
android:tint="@color/GM2_grey_400"
style="@style/TextAppearance.NotificationInfo.Button"/>
</FrameLayout>
<TextView
android:id="@+id/int_block_label"
android:text="@string/inline_block_button"
android:layout_gravity="center_horizontal"
android:gravity="center"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ellipsize="end"
android:maxLines="1"
style="@style/TextAppearance.NotificationInfo.ButtonLabel"/>
</LinearLayout>
<LinearLayout
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:gravity="center_horizontal"
android:orientation="vertical">
<FrameLayout
android:id="@+id/int_silent_wrapper"
android:padding="4dp"
android:layout_width="48dp"
android:layout_height="48dp"
android:gravity="center">
<ImageButton
android:id="@+id/int_silent"
android:background="@drawable/circle_white_40dp"
android:src="@drawable/ic_notifications_silence"
android:layout_gravity="center"
android:layout_width="40dp"
android:layout_height="40dp"
android:clickable="false"
android:contentDescription="@string/inline_silent_button_silent"
android:tint="@color/GM2_grey_400"
style="@style/TextAppearance.NotificationInfo.Button"/>
</FrameLayout>
<TextView
android:id="@+id/int_silent_label"
android:text="@string/inline_silent_button_silent"
android:layout_gravity="center_horizontal"
android:gravity="center"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ellipsize="end"
android:maxLines="1"
style="@style/TextAppearance.NotificationInfo.ButtonLabel"/>
</LinearLayout>
<LinearLayout
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:gravity="center_horizontal"
android:orientation="vertical">
<FrameLayout
android:id="@+id/int_alert_wrapper"
android:padding="4dp"
android:layout_width="48dp"
android:layout_height="48dp"
android:gravity="center">
<ImageButton
android:id="@+id/int_alert"
android:background="@drawable/circle_white_40dp"
android:src="@drawable/ic_notifications_alert"
android:layout_gravity="center"
android:layout_width="40dp"
android:layout_height="40dp"
android:contentDescription="@string/inline_silent_button_alert"
android:clickable="false"
android:tint="@color/GM2_grey_400"
style="@style/TextAppearance.NotificationInfo.Button"/>
</FrameLayout>
<TextView
android:id="@+id/int_alert_label"
android:text="@string/inline_silent_button_alert"
android:layout_gravity="center_horizontal"
android:gravity="center"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ellipsize="end"
android:maxLines="1"
style="@style/TextAppearance.NotificationInfo.ButtonLabel"/>
</LinearLayout>
</LinearLayout>
<TextView
android:id="@+id/hint_text"
android:layout_marginStart="@*android:dimen/notification_content_margin_start"
android:layout_marginEnd="@*android:dimen/notification_content_margin_start"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
style="@style/TextAppearance.NotificationInfo.HintText" />
<TextView
android:id="@+id/done_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="right"
android:paddingRight="24dp"
android:text="@string/inline_done_button"
style="@style/TextAppearance.NotificationInfo.Button" />
</LinearLayout>
</LinearLayout>
<com.android.systemui.statusbar.notification.row.NotificationUndoLayout

View File

@@ -42,6 +42,10 @@
<!-- The color of the text inside a notification -->
<color name="notification_primary_text_color">@*android:color/notification_primary_text_color_dark</color>
<color name="notification_guts_selection_bg">#202124</color>
<color name="notification_guts_selection_border">#669DF6</color>
<color name="notification_guts_link_icon_tint">@color/GM2_grey_200</color>
<!-- The color of the background in the top part of QSCustomizer -->
<color name="qs_customize_background">@color/GM2_grey_900</color>

View File

@@ -88,6 +88,10 @@
<!-- The "inside" of a notification, reached via longpress -->
<color name="notification_guts_bg_color">@color/GM2_grey_50</color>
<color name="notification_guts_selection_bg">#FFFFFF</color>
<color name="notification_guts_selection_border">#4285F4</color>
<color name="notification_guts_link_icon_tint">@color/GM2_grey_900</color>
<color name="assist_orb_color">#ffffff</color>
<color name="keyguard_user_switcher_background_gradient_color">#77000000</color>
@@ -163,4 +167,7 @@
<color name="GM2_red_300">#F28B82</color>
<color name="GM2_red_500">#B71C1C</color>
<color name="GM2_yellow_500">#FFFBBC04</color>
<color name="GM2_green_500">#FF34A853</color>
</resources>

View File

@@ -171,7 +171,7 @@
<dimen name="notification_menu_icon_padding">20dp</dimen>
<!-- The vertical space around the buttons in the inline settings -->
<dimen name="notification_guts_button_spacing">6dp</dimen>
<dimen name="notification_guts_button_spacing">12dp</dimen>
<!-- Extra horizontal space for properly aligning guts buttons with the notification content -->
<dimen name="notification_guts_button_side_margin">8dp</dimen>
@@ -188,6 +188,18 @@
<!-- The height of the header in inline settings -->
<dimen name="notification_guts_header_height">24dp</dimen>
<!-- The text size of the header in inline settings -->
<dimen name="notification_guts_header_text_size">16sp</dimen>
<!-- The horizontal space between items in the alert selections in the inline settings -->
<dimen name="notification_guts_option_horizontal_padding">15dp</dimen>
<!-- The vertical space between items in the alert selections in the inline settings -->
<dimen name="notification_guts_option_vertical_padding">15dp</dimen>
<!-- The vertical space between the alert selections in the inline settings -->
<dimen name="notification_guts_option_vertical_margin">6dp</dimen>
<!-- The minimum height for the snackbar shown after the snooze option has been chosen. -->
<dimen name="snooze_snackbar_min_height">56dp</dimen>

View File

@@ -1599,7 +1599,7 @@
<string name="inline_done_button">Done</string>
<!-- Notification Inline controls: button to dismiss the blocking helper [CHAR_LIMIT=20] -->
<string name="inline_ok_button">OK</string>
<string name="inline_ok_button">Apply</string>
<!-- Notification Inline controls: continue receiving notifications prompt, channel level -->
<string name="inline_keep_showing">Keep showing these notifications?</string>
@@ -1620,17 +1620,20 @@
<string name="inline_minimize_button">Minimize</string>
<!-- Notification inline controls: button to show notifications silently, without alerting the user [CHAR_LIMIT=35] -->
<string name="inline_silent_button_silent">Show silently</string>
<string name="inline_silent_button_silent">Gentle</string>
<!-- Notification inline controls: button to continue showing notifications silently [CHAR_LIMIT=35] -->
<string name="inline_silent_button_stay_silent">Stay silent</string>
<!-- Notification inline controls: button to make notifications alert the user [CHAR_LIMIT=35] -->
<string name="inline_silent_button_alert">Alert</string>
<string name="inline_silent_button_alert">Interruptive</string>
<!-- Notification inline controls: button to continue alerting the user when notifications arrive [CHAR_LIMIT=35] -->
<string name="inline_silent_button_keep_alerting">Keep alerting</string>
<!-- Notification inline controls: button to show block screen [CHAR_LIMIT=35] -->
<string name="inline_turn_off_notifications">Turn off notifications</string>
<!-- Notification Inline controls: continue receiving notifications prompt, app level -->
<string name="inline_keep_showing_app">Keep showing notifications from this app?</string>
@@ -1641,11 +1644,14 @@
<string name="hint_text_silent">Silent notifications appear in the shade, but do not appear on the lock screen, present a banner, or play a sound.</string>
<!-- Hint text for alert button in the interruptiveness settings [CHAR_LIMIT=NONE]-->
<string name="hint_text_alert">Alerted notifications appear in the shade, on the lock screen, present a banner, and play a sound.</string>
<string name="hint_text_alert">These notifications will make a sound and show in the notification drawer, status bar, and lock screen</string>
<!-- Notification: Control panel: Label that displays when the app's notifications cannot be blocked. -->
<string name="notification_unblockable_desc">These notifications can\'t be turned off</string>
<!-- Notification: Control panel: label that displays when viewing settings for a group of notifications posted to multiple channels. -->
<string name="notification_multichannel_desc">This group of notifications cannot be configured here</string>
<!-- Notification: Control panel: Label for the app that posted this notification, if it's not the package that the notification was posted for -->
<string name="notification_delegate_header">via <xliff:g id="app_name" example="YouTube">%1$s</xliff:g></string>

View File

@@ -435,6 +435,7 @@
</style>
<style name="TextAppearance.NotificationInfo.Primary">
<item name="android:fontFamily">@*android:string/config_bodyFontFamilyMedium</item>
<item name="android:textSize">16sp</item>
<item name="android:alpha">0.87</item>
</style>
@@ -471,16 +472,12 @@
</style>
<style name="TextAppearance.NotificationInfo.Button">
<item name="android:fontFamily">@*android:string/config_bodyFontFamilyMedium</item>
<item name="android:textSize">14sp</item>
<item name="android:fontFamily">@*android:string/config_bodyFontFamily</item>
<item name="android:textSize">16sp</item>
<item name="android:textColor">?android:attr/colorAccent</item>
<item name="android:background">@drawable/btn_borderless_rect</item>
<item name="android:gravity">center</item>
<item name="android:focusable">true</item>
<item name="android:paddingTop">@dimen/notification_guts_button_vertical_padding</item>
<item name="android:paddingBottom">@dimen/notification_guts_button_vertical_padding</item>
<item name="android:paddingLeft">@dimen/notification_guts_button_horizontal_padding</item>
<item name="android:paddingRight">@dimen/notification_guts_button_horizontal_padding</item>
</style>
<style name="TextAppearance.HeadsUpStatusBarText"

View File

@@ -85,11 +85,13 @@ public class NotificationBlockingHelperManager {
// - User sentiment is negative (DEBUG flag can bypass)
// - The notification shade is fully expanded (guarantees we're not touching a HUN).
// - The row is blockable (i.e. not non-blockable)
// - The dismissed row is a valid group (>1 or 0 children) or the only child in the group
// - The dismissed row is a valid group (>1 or 0 children from the same channel)
// or the only child in the group
if ((row.getEntry().userSentiment == USER_SENTIMENT_NEGATIVE || DEBUG)
&& mIsShadeExpanded
&& !row.getIsNonblockable()
&& (!row.isChildInGroup() || row.isOnlyChildInGroup())) {
&& ((!row.isChildInGroup() || row.isOnlyChildInGroup())
&& row.getNumUniqueChannels() <= 1)) {
// Dismiss any current blocking helper before continuing forward (only one can be shown
// at a given time).
dismissCurrentBlockingHelper();

View File

@@ -309,7 +309,6 @@ public class NotificationGutsManager implements Dumpable, NotificationLifetimeEx
mDeviceProvisionedController.isDeviceProvisioned(),
row.getIsNonblockable(),
isForBlockingHelper,
row.getEntry().userSentiment == USER_SENTIMENT_NEGATIVE,
row.getEntry().importance,
row.getEntry().isHighPriority());

View File

@@ -39,6 +39,7 @@ import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.graphics.Color;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.GradientDrawable;
import android.metrics.LogMaker;
import android.os.Handler;
import android.os.RemoteException;
@@ -82,9 +83,13 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G
public static final int ACTION_NONE = 0;
static final int ACTION_UNDO = 1;
// standard controls
static final int ACTION_TOGGLE_SILENT = 2;
// unused
static final int ACTION_BLOCK = 3;
// blocking helper
static final int ACTION_DELIVER_SILENTLY = 4;
// standard controls
private static final int ACTION_ALERT = 5;
private INotificationManager mINotificationManager;
@@ -99,7 +104,6 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G
private NotificationChannel mSingleNotificationChannel;
private int mStartingChannelImportance;
private boolean mWasShownHighPriority;
private int mNotificationBlockState = ACTION_NONE;
/**
* The last importance level chosen by the user. Null if the user has not chosen an importance
* level; non-null once the user takes an action which indicates an explicit preference.
@@ -109,13 +113,13 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G
private boolean mIsNonblockable;
private StatusBarNotification mSbn;
private AnimatorSet mExpandAnimation;
private boolean mIsForeground;
private boolean mIsDeviceProvisioned;
private CheckSaveListener mCheckSaveListener;
private OnSettingsClickListener mOnSettingsClickListener;
private OnAppSettingsClickListener mAppSettingsClickListener;
private NotificationGuts mGutsContainer;
private GradientDrawable mSelectedBackground;
/** Whether this view is being shown as part of the blocking helper. */
private boolean mIsForBlockingHelper;
@@ -125,40 +129,39 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G
*/
private String mExitReason = NotificationCounters.BLOCKING_HELPER_DISMISSED;
private OnClickListener mOnKeepShowing = v -> {
mExitReason = NotificationCounters.BLOCKING_HELPER_KEEP_SHOWING;
if (mIsForBlockingHelper) {
closeControls(v);
mMetricsLogger.write(getLogMaker().setCategory(
MetricsEvent.NOTIFICATION_BLOCKING_HELPER)
.setType(MetricsEvent.TYPE_ACTION)
.setSubtype(MetricsEvent.BLOCKING_HELPER_CLICK_STAY_SILENT));
}
};
// used by standard ui
private OnClickListener mOnAlert = v -> {
mExitReason = NotificationCounters.BLOCKING_HELPER_KEEP_SHOWING;
mChosenImportance = IMPORTANCE_DEFAULT;
updateButtonsAndHelpText(ACTION_ALERT);
updateButtons(ACTION_ALERT);
};
// used by standard ui
private OnClickListener mOnSilent = v -> {
mExitReason = NotificationCounters.BLOCKING_HELPER_DELIVER_SILENTLY;
mChosenImportance = IMPORTANCE_LOW;
updateButtons(ACTION_TOGGLE_SILENT);
};
// used by standard ui
private OnClickListener mOnDismissSettings = v -> {
closeControls(v);
};
// used by blocking helper
private OnClickListener mOnKeepShowing = v -> {
mExitReason = NotificationCounters.BLOCKING_HELPER_KEEP_SHOWING;
closeControls(v);
mMetricsLogger.write(getLogMaker().setCategory(
MetricsEvent.NOTIFICATION_BLOCKING_HELPER)
.setType(MetricsEvent.TYPE_ACTION)
.setSubtype(MetricsEvent.BLOCKING_HELPER_CLICK_STAY_SILENT));
};
// used by blocking helper
private OnClickListener mOnDeliverSilently = v -> {
handleSaveImportance(
ACTION_DELIVER_SILENTLY, MetricsEvent.BLOCKING_HELPER_CLICK_STAY_SILENT);
if (!mIsForBlockingHelper) {
updateButtonsAndHelpText(ACTION_DELIVER_SILENTLY);
}
};
private OnClickListener mOnStopOrMinimizeNotifications = v -> {
handleSaveImportance(ACTION_BLOCK, MetricsEvent.BLOCKING_HELPER_CLICK_BLOCKED);
if (!mIsForBlockingHelper) {
updateButtonsAndHelpText(ACTION_BLOCK);
}
};
private void handleSaveImportance(int action, int metricsSubtype) {
@@ -189,6 +192,7 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G
.setType(MetricsEvent.TYPE_DISMISS)
.setSubtype(MetricsEvent.BLOCKING_HELPER_CLICK_UNDO));
} else {
// TODO: this can't happen?
mMetricsLogger.write(importanceChangeLogMaker().setType(MetricsEvent.TYPE_DISMISS));
}
saveImportanceAndExitReason(ACTION_UNDO);
@@ -233,7 +237,7 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G
bindNotification(pm, iNotificationManager, pkg, notificationChannel,
numUniqueChannelsInRow, sbn, checkSaveListener, onSettingsClick,
onAppSettingsClick, isDeviceProvisioned, isNonblockable,
false /* isBlockingHelper */, false /* isUserSentimentNegative */,
false /* isBlockingHelper */,
importance, wasShownHighPriority);
}
@@ -250,7 +254,6 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G
boolean isDeviceProvisioned,
boolean isNonblockable,
boolean isForBlockingHelper,
boolean isUserSentimentNegative,
int importance,
boolean wasShownHighPriority)
throws RemoteException {
@@ -268,13 +271,20 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G
mStartingChannelImportance = mSingleNotificationChannel.getImportance();
mWasShownHighPriority = wasShownHighPriority;
mIsNonblockable = isNonblockable;
mIsForeground =
(mSbn.getNotification().flags & Notification.FLAG_FOREGROUND_SERVICE) != 0;
mIsForBlockingHelper = isForBlockingHelper;
mAppUid = mSbn.getUid();
mDelegatePkg = mSbn.getOpPkg();
mIsDeviceProvisioned = isDeviceProvisioned;
mSelectedBackground = new GradientDrawable();
mSelectedBackground.setShape(GradientDrawable.RECTANGLE);
mSelectedBackground.setColor(mContext.getColor(R.color.notification_guts_selection_bg));
final float cornerRadii = getResources().getDisplayMetrics().density * 8;
mSelectedBackground.setCornerRadii(new float[]{cornerRadii, cornerRadii, cornerRadii,
cornerRadii, cornerRadii, cornerRadii, cornerRadii, cornerRadii});
mSelectedBackground.setStroke((int) (getResources().getDisplayMetrics().density * 2),
mContext.getColor(R.color.notification_guts_selection_border));
int numTotalChannels = mINotificationManager.getNumNotificationChannelsForPackage(
pkg, mAppUid, false /* includeDeleted */);
if (mNumUniqueChannelsInRow == 0) {
@@ -288,13 +298,74 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G
}
bindHeader();
bindPrompt();
bindButtons();
bindChannelDetails();
if (mIsForBlockingHelper) {
bindBlockingHelper();
} else {
bindInlineControls();
}
mMetricsLogger.write(notificationControlsLogMaker());
}
private void bindHeader() throws RemoteException {
private void bindBlockingHelper() {
findViewById(R.id.inline_controls).setVisibility(GONE);
findViewById(R.id.blocking_helper).setVisibility(VISIBLE);
findViewById(R.id.undo).setOnClickListener(mOnUndo);
View turnOffButton = findViewById(R.id.blocking_helper_turn_off_notifications);
turnOffButton.setOnClickListener(getSettingsOnClickListener());
turnOffButton.setVisibility(turnOffButton.hasOnClickListeners() ? VISIBLE : GONE);
TextView keepShowing = findViewById(R.id.keep_showing);
keepShowing.setOnClickListener(mOnKeepShowing);
View deliverSilently = findViewById(R.id.deliver_silently);
deliverSilently.setOnClickListener(mOnDeliverSilently);
}
private void bindInlineControls() {
findViewById(R.id.inline_controls).setVisibility(VISIBLE);
findViewById(R.id.blocking_helper).setVisibility(GONE);
if (mIsNonblockable) {
findViewById(R.id.non_configurable_text).setVisibility(VISIBLE);
findViewById(R.id.non_configurable_multichannel_text).setVisibility(GONE);
findViewById(R.id.interruptiveness_settings).setVisibility(GONE);
} else if (mNumUniqueChannelsInRow > 1) {
findViewById(R.id.non_configurable_text).setVisibility(GONE);
findViewById(R.id.interruptiveness_settings).setVisibility(GONE);
findViewById(R.id.non_configurable_multichannel_text).setVisibility(VISIBLE);
} else {
findViewById(R.id.non_configurable_text).setVisibility(GONE);
findViewById(R.id.non_configurable_multichannel_text).setVisibility(GONE);
findViewById(R.id.interruptiveness_settings).setVisibility(VISIBLE);
}
View turnOffButton = findViewById(R.id.turn_off_notifications);
turnOffButton.setOnClickListener(getSettingsOnClickListener());
turnOffButton.setVisibility(turnOffButton.hasOnClickListeners() && !mIsNonblockable
? VISIBLE : GONE);
View done = findViewById(R.id.done);
done.setOnClickListener(mOnDismissSettings);
View silent = findViewById(R.id.silent_row);
View alert = findViewById(R.id.alert_row);
silent.setOnClickListener(mOnSilent);
alert.setOnClickListener(mOnAlert);
if (mWasShownHighPriority) {
updateButtons(ACTION_ALERT);
} else {
updateButtons(ACTION_TOGGLE_SILENT);
}
}
private void bindHeader() {
// Package name
Drawable pkgicon = null;
ApplicationInfo info;
@@ -319,31 +390,44 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G
// Delegate
bindDelegate();
// Settings button.
final View settingsButton = findViewById(R.id.info);
if (mAppUid >= 0 && mOnSettingsClickListener != null && mIsDeviceProvisioned) {
settingsButton.setVisibility(View.VISIBLE);
final int appUidF = mAppUid;
settingsButton.setOnClickListener(
(View view) -> {
logBlockingHelperCounter(
NotificationCounters.BLOCKING_HELPER_NOTIF_SETTINGS);
mOnSettingsClickListener.onClick(view,
mNumUniqueChannelsInRow > 1 ? null : mSingleNotificationChannel,
appUidF);
});
// Set up app settings link (i.e. Customize)
View settingsLinkView = findViewById(R.id.app_settings);
Intent settingsIntent = getAppSettingsIntent(mPm, mPackageName,
mSingleNotificationChannel,
mSbn.getId(), mSbn.getTag());
if (settingsIntent != null
&& !TextUtils.isEmpty(mSbn.getNotification().getSettingsText())) {
settingsLinkView.setVisibility(VISIBLE);
settingsLinkView.setOnClickListener((View view) -> {
mAppSettingsClickListener.onClick(view, settingsIntent);
});
} else {
settingsButton.setVisibility(View.GONE);
settingsLinkView.setVisibility(View.GONE);
}
// System Settings button.
final View settingsButton = findViewById(R.id.info);
settingsButton.setOnClickListener(getSettingsOnClickListener());
settingsButton.setVisibility(settingsButton.hasOnClickListeners() ? VISIBLE : GONE);
}
private void bindPrompt() throws RemoteException {
final TextView blockPrompt = findViewById(R.id.block_prompt);
private OnClickListener getSettingsOnClickListener() {
if (mAppUid >= 0 && mOnSettingsClickListener != null && mIsDeviceProvisioned) {
final int appUidF = mAppUid;
return ((View view) -> {
logBlockingHelperCounter(
NotificationCounters.BLOCKING_HELPER_NOTIF_SETTINGS);
mOnSettingsClickListener.onClick(view,
mNumUniqueChannelsInRow > 1 ? null : mSingleNotificationChannel,
appUidF);
});
}
return null;
}
private void bindChannelDetails() throws RemoteException {
bindName();
bindGroup();
if (mIsNonblockable) {
blockPrompt.setText(R.string.notification_unblockable_desc);
}
}
private void bindName() {
@@ -450,110 +534,17 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G
}
}
private void bindButtons() {
findViewById(R.id.undo).setOnClickListener(mOnUndo);
boolean showInterruptivenessSettings =
!mIsNonblockable
&& !mIsForeground
&& !mIsForBlockingHelper
&& NotificationUtils.useNewInterruptionModel(mContext);
if (showInterruptivenessSettings) {
findViewById(R.id.block_or_minimize).setVisibility(GONE);
findViewById(R.id.interruptiveness_settings).setVisibility(VISIBLE);
View done = findViewById(R.id.done_button);
done.setOnClickListener(mOnDismissSettings);
View block = findViewById(R.id.int_block_wrapper);
View silent = findViewById(R.id.int_silent_wrapper);
View alert = findViewById(R.id.int_alert_wrapper);
block.setOnClickListener(mOnStopOrMinimizeNotifications);
silent.setOnClickListener(mOnDeliverSilently);
alert.setOnClickListener(mOnAlert);
if (mNotificationBlockState != ACTION_NONE) {
updateButtonsAndHelpText(mNotificationBlockState);
} else if (mWasShownHighPriority) {
updateButtonsAndHelpText(ACTION_ALERT);
} else {
updateButtonsAndHelpText(ACTION_DELIVER_SILENTLY);
}
} else {
findViewById(R.id.block_or_minimize).setVisibility(VISIBLE);
findViewById(R.id.interruptiveness_settings).setVisibility(GONE);
View block = findViewById(R.id.block);
TextView done = findViewById(R.id.done);
View minimize = findViewById(R.id.minimize);
View deliverSilently = findViewById(R.id.deliver_silently);
block.setOnClickListener(mOnStopOrMinimizeNotifications);
done.setOnClickListener(mOnKeepShowing);
minimize.setOnClickListener(mOnStopOrMinimizeNotifications);
deliverSilently.setOnClickListener(mOnDeliverSilently);
if (mIsNonblockable) {
done.setText(android.R.string.ok);
block.setVisibility(GONE);
minimize.setVisibility(GONE);
deliverSilently.setVisibility(GONE);
} else if (mIsForeground) {
block.setVisibility(GONE);
minimize.setVisibility(VISIBLE);
} else {
block.setVisibility(VISIBLE);
minimize.setVisibility(GONE);
}
// Set up app settings link (i.e. Customize)
View settingsLinkView = findViewById(R.id.app_settings);
Intent settingsIntent = getAppSettingsIntent(mPm, mPackageName,
mSingleNotificationChannel,
mSbn.getId(), mSbn.getTag());
if (!mIsForBlockingHelper
&& settingsIntent != null
&& !TextUtils.isEmpty(mSbn.getNotification().getSettingsText())) {
settingsLinkView.setVisibility(VISIBLE);
settingsLinkView.setOnClickListener((View view) -> {
mAppSettingsClickListener.onClick(view, settingsIntent);
});
} else {
settingsLinkView.setVisibility(View.GONE);
}
}
}
private void updateButtonsAndHelpText(int blockState) {
mNotificationBlockState = blockState;
ImageView block = findViewById(R.id.int_block);
ImageView silent = findViewById(R.id.int_silent);
ImageView alert = findViewById(R.id.int_alert);
TextView hintText = findViewById(R.id.hint_text);
private void updateButtons(int blockState) {
View silent = findViewById(R.id.silent_row);
View alert = findViewById(R.id.alert_row);
switch (blockState) {
case ACTION_BLOCK:
block.setBackgroundResource(R.drawable.circle_blue_40dp);
block.setColorFilter(Color.WHITE);
silent.setBackgroundResource(R.drawable.circle_white_40dp);
silent.setColorFilter(getResources().getColor(R.color.GM2_grey_400));
alert.setBackgroundResource(R.drawable.circle_white_40dp);
alert.setColorFilter(getResources().getColor(R.color.GM2_grey_400));
hintText.setText(R.string.hint_text_block);
break;
case ACTION_DELIVER_SILENTLY:
silent.setBackgroundResource(R.drawable.circle_blue_40dp);
silent.setColorFilter(Color.WHITE);
block.setBackgroundResource(R.drawable.circle_white_40dp);
block.setColorFilter(getResources().getColor(R.color.GM2_grey_400));
alert.setBackgroundResource(R.drawable.circle_white_40dp);
alert.setColorFilter(getResources().getColor(R.color.GM2_grey_400));
hintText.setText(R.string.hint_text_silent);
case ACTION_TOGGLE_SILENT:
silent.setBackground(mSelectedBackground);
alert.setBackground(null);
break;
case ACTION_ALERT:
alert.setBackgroundResource(R.drawable.circle_blue_40dp);
alert.setColorFilter(Color.WHITE);
block.setBackgroundResource(R.drawable.circle_white_40dp);
block.setColorFilter(getResources().getColor(R.color.GM2_grey_400));
silent.setBackgroundResource(R.drawable.circle_white_40dp);
silent.setColorFilter(getResources().getColor(R.color.GM2_grey_400));
hintText.setText(R.string.hint_text_alert);
alert.setBackground(mSelectedBackground);
silent.setBackground(null);
break;
}
}
@@ -575,28 +566,20 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G
mChosenImportance = IMPORTANCE_DEFAULT;
}
break;
case ACTION_BLOCK:
mExitReason = NotificationCounters.BLOCKING_HELPER_STOP_NOTIFICATIONS;
if (mIsForeground) {
mChosenImportance = IMPORTANCE_MIN;
} else {
mChosenImportance = IMPORTANCE_NONE;
}
break;
default:
throw new IllegalArgumentException();
}
}
// only used for blocking helper
private void swapContent(@NotificationInfoAction int action, boolean animate) {
if (mExpandAnimation != null) {
mExpandAnimation.cancel();
}
View prompt = findViewById(R.id.prompt);
View blockingHelper = findViewById(R.id.blocking_helper);
ViewGroup confirmation = findViewById(R.id.confirmation);
TextView confirmationText = findViewById(R.id.confirmation_text);
View header = findViewById(R.id.header);
saveImportanceAndExitReason(action);
@@ -606,33 +589,20 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G
case ACTION_DELIVER_SILENTLY:
confirmationText.setText(R.string.notification_channel_silenced);
break;
case ACTION_TOGGLE_SILENT:
if (mWasShownHighPriority) {
confirmationText.setText(R.string.notification_channel_silenced);
} else {
confirmationText.setText(R.string.notification_channel_unsilenced);
}
break;
case ACTION_BLOCK:
if (mIsForeground) {
confirmationText.setText(R.string.notification_channel_minimized);
} else {
confirmationText.setText(R.string.notification_channel_disabled);
}
break;
default:
throw new IllegalArgumentException();
}
boolean isUndo = action == ACTION_UNDO;
prompt.setVisibility(isUndo ? VISIBLE : GONE);
blockingHelper.setVisibility(isUndo ? VISIBLE : GONE);
findViewById(R.id.channel_info).setVisibility(isUndo ? VISIBLE : GONE);
findViewById(R.id.header).setVisibility(isUndo ? VISIBLE : GONE);
confirmation.setVisibility(isUndo ? GONE : VISIBLE);
header.setVisibility(isUndo ? VISIBLE : GONE);
if (animate) {
ObjectAnimator promptAnim = ObjectAnimator.ofFloat(prompt, View.ALPHA,
prompt.getAlpha(), isUndo ? 1f : 0f);
ObjectAnimator promptAnim = ObjectAnimator.ofFloat(blockingHelper, View.ALPHA,
blockingHelper.getAlpha(), isUndo ? 1f : 0f);
promptAnim.setInterpolator(isUndo ? Interpolators.ALPHA_IN : Interpolators.ALPHA_OUT);
ObjectAnimator confirmAnim = ObjectAnimator.ofFloat(confirmation, View.ALPHA,
confirmation.getAlpha(), isUndo ? 0f : 1f);
@@ -652,7 +622,7 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G
@Override
public void onAnimationEnd(Animator animation) {
if (!mCancelled) {
prompt.setVisibility(isUndo ? VISIBLE : GONE);
blockingHelper.setVisibility(isUndo ? VISIBLE : GONE);
confirmation.setVisibility(isUndo ? GONE : VISIBLE);
}
}
@@ -674,15 +644,11 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G
}
mExitReason = NotificationCounters.BLOCKING_HELPER_DISMISSED;
View prompt = findViewById(R.id.prompt);
ViewGroup confirmation = findViewById(R.id.confirmation);
View header = findViewById(R.id.header);
prompt.setVisibility(VISIBLE);
prompt.setAlpha(1f);
confirmation.setVisibility(GONE);
confirmation.setAlpha(1f);
header.setVisibility(VISIBLE);
header.setAlpha(1f);
if (mIsForBlockingHelper) {
bindBlockingHelper();
} else {
bindInlineControls();
}
mMetricsLogger.write(notificationControlsLogMaker().setType(MetricsEvent.TYPE_CLOSE));
}
@@ -730,8 +696,8 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G
* commit the updated importance.
*
* <p><b>Note,</b> this will only get called once the view is dismissing. This means that the
* user does not have the ability to undo the action anymore. See {@link #swapContent(boolean)}
* for where undo is handled.
* user does not have the ability to undo the action anymore. See
* {@link #swapContent(boolean, boolean)} for where undo is handled.
*/
@VisibleForTesting
void closeControls(View v) {

View File

@@ -16,6 +16,7 @@
package com.android.systemui.statusbar.notification.row;
import static android.app.NotificationManager.IMPORTANCE_DEFAULT;
import static android.service.notification.NotificationListenerService.Ranking.USER_SENTIMENT_NEGATIVE;
import static android.service.notification.NotificationListenerService.Ranking.USER_SENTIMENT_NEUTRAL;
import static android.service.notification.NotificationListenerService.Ranking.USER_SENTIMENT_POSITIVE;
@@ -24,11 +25,13 @@ import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.app.NotificationChannel;
import android.content.Context;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
@@ -130,6 +133,21 @@ public class NotificationBlockingHelperManagerTest extends SysuiTestCase {
verify(mGutsManager).openGuts(row, 0, 0, mMenuItem);
}
@Test
public void testPerhapsShowBlockingHelper_notShownForMultiChannelGroup() throws Exception {
ExpandableNotificationRow groupRow = createBlockableGroupRowSpy(10);
int i = 0;
for (ExpandableNotificationRow childRow : groupRow.getNotificationChildren()) {
childRow.getEntry().channel =
new NotificationChannel(Integer.toString(i++), "", IMPORTANCE_DEFAULT);
}
groupRow.getEntry().userSentiment = USER_SENTIMENT_NEGATIVE;
assertFalse(mBlockingHelperManager.perhapsShowBlockingHelper(groupRow, mMenuRow));
verify(mGutsManager, never()).openGuts(groupRow, 0, 0, mMenuItem);
}
@Test
public void testPerhapsShowBlockingHelper_shownForLargeGroup() throws Exception {

View File

@@ -325,7 +325,6 @@ public class NotificationGutsManagerTest extends SysuiTestCase {
eq(false),
eq(false),
eq(true) /* isForBlockingHelper */,
eq(true) /* isUserSentimentNegative */,
eq(0),
eq(false) /* wasShownHighPriority */);
}
@@ -354,7 +353,6 @@ public class NotificationGutsManagerTest extends SysuiTestCase {
eq(false),
eq(false),
eq(false) /* isForBlockingHelper */,
eq(true) /* isUserSentimentNegative */,
eq(0),
eq(false) /* wasShownHighPriority */);
}
@@ -385,7 +383,6 @@ public class NotificationGutsManagerTest extends SysuiTestCase {
eq(false),
eq(false),
eq(true) /* isForBlockingHelper */,
eq(true) /* isUserSentimentNegative */,
eq(IMPORTANCE_DEFAULT),
eq(true) /* wasShownHighPriority */);
}
@@ -415,7 +412,6 @@ public class NotificationGutsManagerTest extends SysuiTestCase {
eq(true),
eq(false),
eq(false) /* isForBlockingHelper */,
eq(true) /* isUserSentimentNegative */,
eq(0),
eq(false) /* wasShownHighPriority */);
}
@@ -444,7 +440,6 @@ public class NotificationGutsManagerTest extends SysuiTestCase {
eq(false),
eq(false),
eq(true) /* isForBlockingHelper */,
eq(true) /* isUserSentimentNegative */,
eq(0),
eq(false) /* wasShownHighPriority */);
}

View File

@@ -313,107 +313,19 @@ public class NotificationInfoTest extends SysuiTestCase {
}
@Test
public void testBindNotification_BlockButton() throws Exception {
public void testBindNotification_BlockLink_BlockingHelper() throws Exception {
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false,
IMPORTANCE_DEFAULT, true);
final View block = mNotificationInfo.findViewById(R.id.int_block);
final View minimize = mNotificationInfo.findViewById(R.id.block_or_minimize);
assertEquals(VISIBLE, block.getVisibility());
assertEquals(GONE, minimize.getVisibility());
}
@Test
public void testBindNotification_BlockButton_BlockingHelper() throws Exception {
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false,
true /* isBlockingHelper */, false, IMPORTANCE_DEFAULT, true);
final View block = mNotificationInfo.findViewById(R.id.block);
TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, mock(
NotificationInfo.OnSettingsClickListener.class), null, true, false,
true /* isBlockingHelper */, IMPORTANCE_DEFAULT, true);
final View block =
mNotificationInfo.findViewById(R.id.blocking_helper_turn_off_notifications);
final View interruptivenessSettings = mNotificationInfo.findViewById(
R.id.interruptiveness_settings);
R.id.inline_controls);
assertEquals(VISIBLE, block.getVisibility());
assertEquals(GONE, interruptivenessSettings.getVisibility());
}
@Test
public void testBindNotification_SilenceButton_CurrentlyAlerting() throws Exception {
mNotificationChannel.setImportance(IMPORTANCE_DEFAULT);
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false,
IMPORTANCE_DEFAULT, true);
final TextView silent = mNotificationInfo.findViewById(R.id.int_silent_label);
assertEquals(VISIBLE, silent.getVisibility());
assertEquals(
mContext.getString(R.string.inline_silent_button_silent), silent.getText());
}
@Test
public void testBindNotification_verifyButtonTexts() throws Exception {
mNotificationChannel.setImportance(IMPORTANCE_LOW);
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false,
IMPORTANCE_LOW, false);
final TextView block = mNotificationInfo.findViewById(R.id.int_block_label);
final TextView alert = mNotificationInfo.findViewById(R.id.int_alert_label);
final TextView silent = mNotificationInfo.findViewById(R.id.int_silent_label);
assertEquals(VISIBLE, silent.getVisibility());
assertEquals(VISIBLE, block.getVisibility());
assertEquals(VISIBLE, alert.getVisibility());
assertEquals(
mContext.getString(R.string.inline_silent_button_silent),
silent.getText());
assertEquals(
mContext.getString(R.string.inline_silent_button_alert), alert.getText());
assertEquals(
mContext.getString(R.string.inline_block_button), block.getText());
}
@Test
public void testBindNotification_verifyHintTextForSilent() throws Exception {
mNotificationChannel.setImportance(IMPORTANCE_LOW);
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false,
IMPORTANCE_LOW, false);
TextView hintText = mNotificationInfo.findViewById(R.id.hint_text);
assertEquals(mContext.getString(R.string.hint_text_silent), hintText.getText());
}
@Test
public void testBindNotification_verifyHintTextForBlock() throws Exception {
mNotificationChannel.setImportance(IMPORTANCE_LOW);
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false,
IMPORTANCE_LOW, false);
View blockWrapper = mNotificationInfo.findViewById(R.id.int_block_wrapper);
blockWrapper.performClick();
TextView hintText = mNotificationInfo.findViewById(R.id.hint_text);
assertEquals(mContext.getString(R.string.hint_text_block), hintText.getText());
}
@Test
public void testBindNotification_verifyHintTextForAlert() throws Exception {
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false,
IMPORTANCE_DEFAULT, true);
TextView hintText = mNotificationInfo.findViewById(R.id.hint_text);
assertEquals(mContext.getString(R.string.hint_text_alert), hintText.getText());
}
@Test
public void testBindNotification_MinButton() throws Exception {
mSbn.getNotification().flags = Notification.FLAG_FOREGROUND_SERVICE;
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false,
IMPORTANCE_DEFAULT, true);
final View block = mNotificationInfo.findViewById(R.id.block);
final View interruptivenessSettings = mNotificationInfo.findViewById(
R.id.interruptiveness_settings);
final View minimize = mNotificationInfo.findViewById(R.id.minimize);
assertEquals(GONE, block.getVisibility());
assertEquals(GONE, interruptivenessSettings.getVisibility());
assertEquals(VISIBLE, minimize.getVisibility());
}
@Test
public void testBindNotification_SetsOnClickListenerForSettings() throws Exception {
final CountDownLatch latch = new CountDownLatch(1);
@@ -484,7 +396,7 @@ public class NotificationInfoTest extends SysuiTestCase {
TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn,
null, null, null,
false, true,
true, true,
true,
IMPORTANCE_DEFAULT, true);
verify(mMetricsLogger).write(argThat(logMaker ->
logMaker.getCategory() == MetricsEvent.ACTION_NOTE_CONTROLS
@@ -499,7 +411,7 @@ public class NotificationInfoTest extends SysuiTestCase {
TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn,
null, null, null,
false, true,
true, true,
true,
IMPORTANCE_DEFAULT, true);
mNotificationInfo.logBlockingHelperCounter("HowCanNotifsBeRealIfAppsArent");
verify(mMetricsLogger).count(eq("HowCanNotifsBeRealIfAppsArent"), eq(1));
@@ -526,7 +438,7 @@ public class NotificationInfoTest extends SysuiTestCase {
throws Exception {
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
TEST_PACKAGE_NAME, mNotificationChannel, MULTIPLE_CHANNEL_COUNT, mSbn, null, null,
null, true, true, IMPORTANCE_DEFAULT, true);
null, true, false, IMPORTANCE_DEFAULT, true);
final TextView channelNameView =
mNotificationInfo.findViewById(R.id.channel_name);
assertEquals(GONE, channelNameView.getVisibility());
@@ -537,20 +449,24 @@ public class NotificationInfoTest extends SysuiTestCase {
public void testStopInvisibleIfBundleFromDifferentChannels() throws Exception {
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
TEST_PACKAGE_NAME, mNotificationChannel, MULTIPLE_CHANNEL_COUNT, mSbn, null, null,
null, true, true, IMPORTANCE_DEFAULT, true);
final TextView blockView = mNotificationInfo.findViewById(R.id.block);
assertEquals(GONE, blockView.getVisibility());
null, true, false, IMPORTANCE_DEFAULT, true);
assertEquals(GONE, mNotificationInfo.findViewById(
R.id.interruptiveness_settings).getVisibility());
assertEquals(VISIBLE, mNotificationInfo.findViewById(
R.id.non_configurable_multichannel_text).getVisibility());
}
@Test
public void testbindNotification_UnblockableTextVisibleWhenAppUnblockable() throws Exception {
public void testBindNotification_whenAppUnblockable() throws Exception {
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, true,
IMPORTANCE_DEFAULT, true);
final TextView view = mNotificationInfo.findViewById(R.id.block_prompt);
final TextView view = mNotificationInfo.findViewById(R.id.non_configurable_text);
assertEquals(View.VISIBLE, view.getVisibility());
assertEquals(mContext.getString(R.string.notification_unblockable_desc),
view.getText());
assertEquals(GONE,
mNotificationInfo.findViewById(R.id.interruptiveness_settings).getVisibility());
}
@Test
@@ -568,23 +484,9 @@ public class NotificationInfoTest extends SysuiTestCase {
mNotificationChannel.setImportance(IMPORTANCE_LOW);
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false,
IMPORTANCE_DEFAULT, false);
IMPORTANCE_LOW, false);
mNotificationInfo.findViewById(R.id.int_block).performClick();
mTestableLooper.processAllMessages();
verify(mMockINotificationManager, never()).updateNotificationChannelForPackage(
anyString(), eq(TEST_UID), any());
}
@Test
public void testDoesNotUpdateNotificationChannelAfterImportanceChangedMin()
throws Exception {
mNotificationChannel.setImportance(IMPORTANCE_LOW);
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false,
IMPORTANCE_DEFAULT, false);
mNotificationInfo.findViewById(R.id.minimize).performClick();
mNotificationInfo.findViewById(R.id.alert_row).performClick();
mTestableLooper.processAllMessages();
verify(mMockINotificationManager, never()).updateNotificationChannelForPackage(
anyString(), eq(TEST_UID), any());
@@ -598,21 +500,7 @@ public class NotificationInfoTest extends SysuiTestCase {
TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false,
IMPORTANCE_DEFAULT, true);
mNotificationInfo.findViewById(R.id.int_silent).performClick();
mTestableLooper.processAllMessages();
verify(mMockINotificationManager, never()).updateNotificationChannelForPackage(
anyString(), eq(TEST_UID), any());
}
@Test
public void testDoesNotUpdateNotificationChannelAfterImportanceChangedUnSilenced()
throws Exception {
mNotificationChannel.setImportance(IMPORTANCE_LOW);
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false,
IMPORTANCE_DEFAULT, false);
mNotificationInfo.findViewById(R.id.int_alert).performClick();
mNotificationInfo.findViewById(R.id.silent_row).performClick();
mTestableLooper.processAllMessages();
verify(mMockINotificationManager, never()).updateNotificationChannelForPackage(
anyString(), eq(TEST_UID), any());
@@ -649,76 +537,6 @@ public class NotificationInfoTest extends SysuiTestCase {
assertEquals(IMPORTANCE_UNSPECIFIED, mNotificationChannel.getImportance());
}
@Test
public void testHandleCloseControls_setsNotificationsDisabledForMultipleChannelNotifications()
throws Exception {
mNotificationChannel.setImportance(IMPORTANCE_LOW);
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
TEST_PACKAGE_NAME, mNotificationChannel /* notificationChannel */,
10 /* numUniqueChannelsInRow */, mSbn, null /* checkSaveListener */,
null /* onSettingsClick */, null /* onAppSettingsClick */,
true, false /* isNonblockable */, IMPORTANCE_DEFAULT, false
);
mNotificationInfo.findViewById(R.id.int_block_wrapper).performClick();
mNotificationInfo.findViewById(R.id.done_button).performClick();
mNotificationInfo.handleCloseControls(true, false);
mTestableLooper.processAllMessages();
verify(mMockINotificationManager, times(1))
.setNotificationsEnabledWithImportanceLockForPackage(
anyString(), eq(TEST_UID), eq(false));
}
@Test
public void testHandleCloseControls_keepsNotificationsEnabledForMultipleChannelNotifications()
throws Exception {
mNotificationChannel.setImportance(IMPORTANCE_LOW);
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
TEST_PACKAGE_NAME, mNotificationChannel /* notificationChannel */,
10 /* numUniqueChannelsInRow */, mSbn, null /* checkSaveListener */,
null /* onSettingsClick */, null /* onAppSettingsClick */,
true, false /* isNonblockable */, IMPORTANCE_DEFAULT, false
);
mNotificationInfo.findViewById(R.id.int_block_wrapper).performClick();
mNotificationInfo.findViewById(R.id.done_button).performClick();
mNotificationInfo.handleCloseControls(true, false);
mTestableLooper.processAllMessages();
verify(mMockINotificationManager, times(1))
.setNotificationsEnabledWithImportanceLockForPackage(
anyString(), eq(TEST_UID), eq(false));
}
@Test
public void testCloseControls_blockingHelperSavesImportanceForMultipleChannelNotifications()
throws Exception {
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
TEST_PACKAGE_NAME, mNotificationChannel /* notificationChannel */,
10 /* numUniqueChannelsInRow */, mSbn, null /* checkSaveListener */,
null /* onSettingsClick */, null /* onAppSettingsClick */,
true /* provisioned */,
false /* isNonblockable */, true /* isForBlockingHelper */,
true /* isUserSentimentNegative */, IMPORTANCE_DEFAULT, true);
NotificationGuts guts = spy(new NotificationGuts(mContext, null));
when(guts.getWindowToken()).thenReturn(mock(IBinder.class));
doNothing().when(guts).animateClose(anyInt(), anyInt(), anyBoolean());
doNothing().when(guts).setExposed(anyBoolean(), anyBoolean());
guts.setGutsContent(mNotificationInfo);
mNotificationInfo.setGutsParent(guts);
mNotificationInfo.findViewById(R.id.done).performClick();
verify(mBlockingHelperManager).dismissCurrentBlockingHelper();
mTestableLooper.processAllMessages();
verify(mMockINotificationManager, times(1))
.setNotificationsEnabledWithImportanceLockForPackage(
anyString(), eq(TEST_UID), eq(true));
}
@Test
public void testCloseControls_nonNullCheckSaveListenerDoesntDelayKeepShowing_BlockingHelper()
throws Exception {
@@ -729,7 +547,7 @@ public class NotificationInfoTest extends SysuiTestCase {
10 /* numUniqueChannelsInRow */, mSbn, listener /* checkSaveListener */,
null /* onSettingsClick */, null /* onAppSettingsClick */, true /* provisioned */,
false /* isNonblockable */, true /* isForBlockingHelper */,
true /* isUserSentimentNegative */, IMPORTANCE_DEFAULT, true);
IMPORTANCE_DEFAULT, true);
NotificationGuts guts = spy(new NotificationGuts(mContext, null));
when(guts.getWindowToken()).thenReturn(mock(IBinder.class));
@@ -738,7 +556,7 @@ public class NotificationInfoTest extends SysuiTestCase {
guts.setGutsContent(mNotificationInfo);
mNotificationInfo.setGutsParent(guts);
mNotificationInfo.findViewById(R.id.done).performClick();
mNotificationInfo.findViewById(R.id.keep_showing).performClick();
verify(mBlockingHelperManager).dismissCurrentBlockingHelper();
mTestableLooper.processAllMessages();
@@ -757,8 +575,7 @@ public class NotificationInfoTest extends SysuiTestCase {
10 /* numUniqueChannelsInRow */, mSbn, listener /* checkSaveListener */,
null /* onSettingsClick */, null /* onAppSettingsClick */,
false /* isNonblockable */, true /* isForBlockingHelper */,
true, true /* isUserSentimentNegative */, /* isNoisy */
IMPORTANCE_DEFAULT, true);
true, IMPORTANCE_DEFAULT, true);
mNotificationInfo.handleCloseControls(true /* save */, false /* force */);
@@ -777,9 +594,9 @@ public class NotificationInfoTest extends SysuiTestCase {
null /* onSettingsClick */, null /* onAppSettingsClick */,
true /* provisioned */,
false /* isNonblockable */, true /* isForBlockingHelper */,
true /* isUserSentimentNegative */, IMPORTANCE_DEFAULT, true);
IMPORTANCE_DEFAULT, true);
mNotificationInfo.findViewById(R.id.block).performClick();
mNotificationInfo.findViewById(R.id.deliver_silently).performClick();
mTestableLooper.processAllMessages();
verify(listener).checkSave(any(Runnable.class), eq(mSbn));
}
@@ -799,7 +616,6 @@ public class NotificationInfoTest extends SysuiTestCase {
false /* isNonblockable */,
true /* isForBlockingHelper */,
true,
false /* isUserSentimentNegative */,
IMPORTANCE_DEFAULT, true);
NotificationGuts guts = mock(NotificationGuts.class);
doCallRealMethod().when(guts).closeControls(anyInt(), anyInt(), anyBoolean(), anyBoolean());
@@ -810,129 +626,6 @@ public class NotificationInfoTest extends SysuiTestCase {
verify(mBlockingHelperManager).dismissCurrentBlockingHelper();
}
@Test
public void testNonBlockableAppDoesNotBecomeBlocked() throws Exception {
mNotificationChannel.setImportance(IMPORTANCE_LOW);
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, true,
true, false, IMPORTANCE_DEFAULT, false);
mNotificationInfo.findViewById(R.id.block).performClick();
waitForUndoButton();
mTestableLooper.processAllMessages();
verify(mMockINotificationManager, never()).updateNotificationChannelForPackage(
anyString(), eq(TEST_UID), any());
}
@Test
public void testBlockChangedCallsUpdateNotificationChannel_notBlockingHelper()
throws Exception {
mNotificationChannel.setImportance(IMPORTANCE_LOW);
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn,
null, null, null,
true, false,
IMPORTANCE_DEFAULT, false);
mNotificationInfo.findViewById(R.id.int_block_wrapper).performClick();
mNotificationInfo.findViewById(R.id.done_button).performClick();
mNotificationInfo.handleCloseControls(true, false);
ArgumentCaptor<LogMaker> logMakerCaptor = ArgumentCaptor.forClass(LogMaker.class);
verify(mMetricsLogger, times(2)).write(logMakerCaptor.capture());
assertEquals(MetricsProto.MetricsEvent.TYPE_ACTION,
logMakerCaptor.getValue().getType());
assertEquals(IMPORTANCE_NONE - IMPORTANCE_LOW,
logMakerCaptor.getValue().getSubtype());
mTestableLooper.processAllMessages();
ArgumentCaptor<NotificationChannel> updated =
ArgumentCaptor.forClass(NotificationChannel.class);
verify(mMockINotificationManager, times(1)).updateNotificationChannelForPackage(
anyString(), eq(TEST_UID), updated.capture());
assertTrue((updated.getValue().getUserLockedFields()
& USER_LOCKED_IMPORTANCE) != 0);
assertEquals(IMPORTANCE_NONE, updated.getValue().getImportance());
}
@Test
public void testBlockChangedCallsUpdateNotificationChannel_blockingHelper() throws Exception {
mNotificationChannel.setImportance(IMPORTANCE_LOW);
mNotificationInfo.bindNotification(
mMockPackageManager,
mMockINotificationManager,
TEST_PACKAGE_NAME,
mNotificationChannel,
1 /* numChannels */,
mSbn,
null /* checkSaveListener */,
null /* onSettingsClick */,
null /* onAppSettingsClick */,
true /*provisioned */,
false /* isNonblockable */,
true /* isForBlockingHelper */,
true /* isUserSentimentNegative */,
IMPORTANCE_DEFAULT,
false);
mNotificationInfo.findViewById(R.id.block).performClick();
waitForUndoButton();
mNotificationInfo.handleCloseControls(true, false);
ArgumentCaptor<LogMaker> logMakerCaptor = ArgumentCaptor.forClass(LogMaker.class);
verify(mMetricsLogger, times(3)).write(logMakerCaptor.capture());
assertEquals(MetricsProto.MetricsEvent.TYPE_ACTION,
logMakerCaptor.getValue().getType());
assertEquals(IMPORTANCE_NONE - IMPORTANCE_LOW,
logMakerCaptor.getValue().getSubtype());
mTestableLooper.processAllMessages();
ArgumentCaptor<NotificationChannel> updated =
ArgumentCaptor.forClass(NotificationChannel.class);
verify(mMockINotificationManager, times(1)).updateNotificationChannelForPackage(
anyString(), eq(TEST_UID), updated.capture());
assertTrue((updated.getValue().getUserLockedFields()
& USER_LOCKED_IMPORTANCE) != 0);
assertEquals(IMPORTANCE_NONE, updated.getValue().getImportance());
}
@Test
public void testNonBlockableAppDoesNotBecomeMin() throws Exception {
mNotificationChannel.setImportance(IMPORTANCE_LOW);
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, true,
true, false, IMPORTANCE_DEFAULT, false);
mNotificationInfo.findViewById(R.id.minimize).performClick();
waitForUndoButton();
mTestableLooper.processAllMessages();
verify(mMockINotificationManager, never()).updateNotificationChannelForPackage(
anyString(), eq(TEST_UID), any());
}
@Test
public void testMinChangedCallsUpdateNotificationChannel() throws Exception {
mNotificationChannel.setImportance(IMPORTANCE_LOW);
mSbn.getNotification().flags = Notification.FLAG_FOREGROUND_SERVICE;
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false,
true, false, IMPORTANCE_DEFAULT, false);
mNotificationInfo.findViewById(R.id.minimize).performClick();
waitForUndoButton();
mNotificationInfo.handleCloseControls(true, false);
mTestableLooper.processAllMessages();
ArgumentCaptor<NotificationChannel> updated =
ArgumentCaptor.forClass(NotificationChannel.class);
verify(mMockINotificationManager, times(1)).updateNotificationChannelForPackage(
anyString(), eq(TEST_UID), updated.capture());
assertTrue((updated.getValue().getUserLockedFields()
& USER_LOCKED_IMPORTANCE) != 0);
assertEquals(IMPORTANCE_MIN, updated.getValue().getImportance());
}
@Test
public void testSilentlyChangedCallsUpdateNotificationChannel_blockingHelper()
throws Exception {
@@ -950,7 +643,6 @@ public class NotificationInfoTest extends SysuiTestCase {
true /*provisioned */,
false /* isNonblockable */,
true /* isForBlockingHelper */,
true /* isUserSentimentNegative */,
IMPORTANCE_DEFAULT,
false);
@@ -969,12 +661,13 @@ public class NotificationInfoTest extends SysuiTestCase {
}
@Test
public void testKeepUpdatesNotificationChannel() throws Exception {
public void testKeepUpdatesNotificationChannel_blockingHelper() throws Exception {
mNotificationChannel.setImportance(IMPORTANCE_LOW);
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false,
IMPORTANCE_DEFAULT, false);
TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, true,
IMPORTANCE_LOW, false);
mNotificationInfo.findViewById(R.id.keep_showing).performClick();
mNotificationInfo.handleCloseControls(true, false);
mTestableLooper.processAllMessages();
@@ -986,6 +679,24 @@ public class NotificationInfoTest extends SysuiTestCase {
assertEquals(IMPORTANCE_LOW, mNotificationChannel.getImportance());
}
@Test
public void testNoActionsUpdatesNotificationChannel_blockingHelper() throws Exception {
mNotificationChannel.setImportance(IMPORTANCE_DEFAULT);
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, true,
IMPORTANCE_DEFAULT, false);
mNotificationInfo.handleCloseControls(true, false);
mTestableLooper.processAllMessages();
ArgumentCaptor<NotificationChannel> updated =
ArgumentCaptor.forClass(NotificationChannel.class);
verify(mMockINotificationManager, times(1)).updateNotificationChannelForPackage(
anyString(), eq(TEST_UID), updated.capture());
assertTrue(0 != (mNotificationChannel.getUserLockedFields() & USER_LOCKED_IMPORTANCE));
assertEquals(IMPORTANCE_DEFAULT, mNotificationChannel.getImportance());
}
@Test
public void testSilenceCallsUpdateNotificationChannel() throws Exception {
mNotificationChannel.setImportance(IMPORTANCE_DEFAULT);
@@ -993,8 +704,8 @@ public class NotificationInfoTest extends SysuiTestCase {
TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false,
IMPORTANCE_DEFAULT, true);
mNotificationInfo.findViewById(R.id.int_silent_wrapper).performClick();
mNotificationInfo.findViewById(R.id.done_button).performClick();
mNotificationInfo.findViewById(R.id.silent_row).performClick();
mNotificationInfo.findViewById(R.id.done).performClick();
mNotificationInfo.handleCloseControls(true, false);
mTestableLooper.processAllMessages();
@@ -1014,8 +725,8 @@ public class NotificationInfoTest extends SysuiTestCase {
TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false,
IMPORTANCE_DEFAULT, false);
mNotificationInfo.findViewById(R.id.int_alert_wrapper).performClick();
mNotificationInfo.findViewById(R.id.done_button).performClick();
mNotificationInfo.findViewById(R.id.alert_row).performClick();
mNotificationInfo.findViewById(R.id.done).performClick();
mNotificationInfo.handleCloseControls(true, false);
mTestableLooper.processAllMessages();
@@ -1036,8 +747,8 @@ public class NotificationInfoTest extends SysuiTestCase {
TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false,
IMPORTANCE_DEFAULT, true);
mNotificationInfo.findViewById(R.id.int_silent_wrapper).performClick();
mNotificationInfo.findViewById(R.id.done_button).performClick();
mNotificationInfo.findViewById(R.id.silent_row).performClick();
mNotificationInfo.findViewById(R.id.done).performClick();
mNotificationInfo.handleCloseControls(true, false);
mTestableLooper.processAllMessages();
@@ -1058,8 +769,8 @@ public class NotificationInfoTest extends SysuiTestCase {
TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false,
IMPORTANCE_LOW, false);
mNotificationInfo.findViewById(R.id.int_alert_wrapper).performClick();
mNotificationInfo.findViewById(R.id.done_button).performClick();
mNotificationInfo.findViewById(R.id.alert_row).performClick();
mNotificationInfo.findViewById(R.id.done).performClick();
mNotificationInfo.handleCloseControls(true, false);
mTestableLooper.processAllMessages();
@@ -1072,31 +783,15 @@ public class NotificationInfoTest extends SysuiTestCase {
assertEquals(IMPORTANCE_DEFAULT, updated.getValue().getImportance());
}
@Test
public void testCloseControlsDoesNotUpdateMinIfSaveIsFalse() throws Exception {
mNotificationChannel.setImportance(IMPORTANCE_LOW);
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, true,
true, false, IMPORTANCE_DEFAULT, false);
mNotificationInfo.findViewById(R.id.minimize).performClick();
waitForUndoButton();
mNotificationInfo.handleCloseControls(false, false);
mTestableLooper.processAllMessages();
verify(mMockINotificationManager, never()).updateNotificationChannelForPackage(
eq(TEST_PACKAGE_NAME), eq(TEST_UID), eq(mNotificationChannel));
}
@Test
public void testCloseControlsDoesNotUpdateIfSaveIsFalse() throws Exception {
mNotificationChannel.setImportance(IMPORTANCE_LOW);
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false,
IMPORTANCE_DEFAULT, false);
IMPORTANCE_LOW, false);
mNotificationInfo.findViewById(R.id.int_block_wrapper).performClick();
mNotificationInfo.findViewById(R.id.done_button).performClick();
mNotificationInfo.findViewById(R.id.alert_row).performClick();
mNotificationInfo.findViewById(R.id.done).performClick();
mNotificationInfo.handleCloseControls(false, false);
mTestableLooper.processAllMessages();
@@ -1104,22 +799,6 @@ public class NotificationInfoTest extends SysuiTestCase {
eq(TEST_PACKAGE_NAME), eq(TEST_UID), eq(mNotificationChannel));
}
@Test
public void testBlockDoesNothingIfCheckSaveListenerIsNoOp() throws Exception {
mNotificationChannel.setImportance(IMPORTANCE_LOW);
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn,
(Runnable saveImportance, StatusBarNotification sbn) -> {
}, null, null, true, true, IMPORTANCE_DEFAULT, false);
mNotificationInfo.findViewById(R.id.int_block_wrapper).performClick();
mTestableLooper.processAllMessages();
mNotificationInfo.handleCloseControls(true, false);
verify(mMockINotificationManager, never()).updateNotificationChannelForPackage(
eq(TEST_PACKAGE_NAME), eq(TEST_UID), eq(mNotificationChannel));
}
@Test
public void testCloseControlsUpdatesWhenCheckSaveListenerUsesCallback() throws Exception {
mNotificationChannel.setImportance(IMPORTANCE_LOW);
@@ -1127,11 +806,11 @@ public class NotificationInfoTest extends SysuiTestCase {
TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn,
(Runnable saveImportance, StatusBarNotification sbn) -> {
saveImportance.run();
}, null, null, true, false, IMPORTANCE_DEFAULT, false
}, null, null, true, false, IMPORTANCE_LOW, false
);
mNotificationInfo.findViewById(R.id.int_block_wrapper).performClick();
mNotificationInfo.findViewById(R.id.done_button).performClick();
mNotificationInfo.findViewById(R.id.alert_row).performClick();
mNotificationInfo.findViewById(R.id.done).performClick();
mTestableLooper.processAllMessages();
verify(mMockINotificationManager, never()).updateNotificationChannelForPackage(
eq(TEST_PACKAGE_NAME), eq(TEST_UID), eq(mNotificationChannel));
@@ -1147,18 +826,4 @@ public class NotificationInfoTest extends SysuiTestCase {
public void testWillBeRemovedReturnsFalseBeforeBind() throws Exception {
assertFalse(mNotificationInfo.willBeRemoved());
}
@Test
public void testUndoText_min() throws Exception {
mSbn.getNotification().flags = Notification.FLAG_FOREGROUND_SERVICE;
mNotificationChannel.setImportance(IMPORTANCE_LOW);
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, true,
true, false, IMPORTANCE_DEFAULT, false);
mNotificationInfo.findViewById(R.id.minimize).performClick();
waitForUndoButton();
TextView confirmationText = mNotificationInfo.findViewById(R.id.confirmation_text);
assertTrue(confirmationText.getText().toString().contains("minimized"));
}
}