summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--packages/SystemUI/plugin/src/com/android/systemui/plugins/statusbar/NotificationMenuRowProvider.java74
-rw-r--r--packages/SystemUI/res/drawable/ic_snooze.xml12
-rw-r--r--packages/SystemUI/res/layout/notification_guts.xml123
-rw-r--r--packages/SystemUI/res/layout/notification_info.xml146
-rw-r--r--packages/SystemUI/res/layout/notification_menu_row.xml (renamed from packages/SystemUI/res/layout/notification_settings_icon_row.xml)20
-rw-r--r--packages/SystemUI/res/layout/notification_snooze.xml65
-rw-r--r--packages/SystemUI/res/layout/status_bar_notification_row.xml8
-rw-r--r--packages/SystemUI/res/values/colors.xml4
-rw-r--r--packages/SystemUI/res/values/dimens.xml17
-rw-r--r--packages/SystemUI/res/values/strings.xml22
-rw-r--r--packages/SystemUI/res/values/styles.xml14
-rw-r--r--packages/SystemUI/src/com/android/systemui/SwipeHelper.java16
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java111
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java86
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/NotificationGuts.java259
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/NotificationInfo.java319
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/NotificationMenuRow.java392
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/NotificationSettingsIconRow.java300
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/NotificationSnooze.java176
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java13
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java50
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationGutsTest.java88
22 files changed, 1501 insertions, 814 deletions
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/statusbar/NotificationMenuRowProvider.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/statusbar/NotificationMenuRowProvider.java
new file mode 100644
index 000000000000..c0a48a873780
--- /dev/null
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/statusbar/NotificationMenuRowProvider.java
@@ -0,0 +1,74 @@
+
+package com.android.systemui.plugins.statusbar;
+
+import android.content.Context;
+import android.graphics.drawable.Drawable;
+import android.service.notification.StatusBarNotification;
+import android.view.View;
+
+import java.util.ArrayList;
+
+import com.android.systemui.plugins.Plugin;
+
+public interface NotificationMenuRowProvider extends Plugin {
+
+ public static final String ACTION = "com.android.systemui.action.PLUGIN_NOTIFICATION_MENU_ROW";
+
+ public static final int VERSION = 1;
+
+ /**
+ * Returns a list of items to populate the menu 'behind' a notification.
+ */
+ public ArrayList<MenuItem> getMenuItems(Context context);
+
+ public interface OnMenuClickListener {
+ public void onMenuClicked(View row, int x, int y, MenuItem menu);
+
+ public void onMenuReset(View row);
+ }
+
+ public interface GutsInteractionListener {
+ public void onInteraction(View view);
+
+ public void closeGuts(View view);
+ }
+
+ public interface GutsContent {
+ public void setInteractionListener(GutsInteractionListener listener);
+
+ public View getContentView();
+
+ public boolean handleCloseControls();
+ }
+
+ public interface SnoozeGutsContent extends GutsContent {
+ public void setSnoozeListener(SnoozeListener listener);
+
+ public void setStatusBarNotification(StatusBarNotification sbn);
+ }
+
+ public interface SnoozeListener {
+ public void snoozeNotification(StatusBarNotification sbn, long snoozeUntil);
+ }
+
+ public static class MenuItem {
+ public Drawable icon;
+ public String menuDescription;
+ public View menuView;
+ public GutsContent gutsContent;
+
+ public MenuItem(Drawable i, String s, GutsContent content) {
+ icon = i;
+ menuDescription = s;
+ gutsContent = content;
+ }
+
+ public View getGutsView() {
+ return gutsContent.getContentView();
+ }
+
+ public boolean onTouch(View v, int x, int y) {
+ return false;
+ }
+ }
+}
diff --git a/packages/SystemUI/res/drawable/ic_snooze.xml b/packages/SystemUI/res/drawable/ic_snooze.xml
new file mode 100644
index 000000000000..b0b03a99f4a5
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_snooze.xml
@@ -0,0 +1,12 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
+ <path
+ android:pathData="M11.99,2C6.47,2 2,6.48 2,12s4.47,10 9.99,10C17.52,22 22,17.52 22,12S17.52,2 11.99,2zM12,20c-4.42,0 -8,-3.58 -8,-8s3.58,-8 8,-8 8,3.58 8,8 -3.58,8 -8,8z"
+ android:fillColor="#757575"/>
+ <path
+ android:pathData="M12.5,7H11v6l5.25,3.15 0.75,-1.23 -4.5,-2.67z"
+ android:fillColor="#757575"/>
+</vector>
diff --git a/packages/SystemUI/res/layout/notification_guts.xml b/packages/SystemUI/res/layout/notification_guts.xml
index 3948dc4b8771..9d8ef83ab7e6 100644
--- a/packages/SystemUI/res/layout/notification_guts.xml
+++ b/packages/SystemUI/res/layout/notification_guts.xml
@@ -23,125 +23,4 @@
android:visibility="gone"
android:clickable="true"
android:gravity="top|start"
- android:orientation="vertical"
- android:paddingStart="@*android:dimen/notification_content_margin_start"
- android:paddingEnd="8dp"
- android:background="@color/notification_guts_bg_color"
- android:theme="@*android:style/Theme.DeviceDefault.Light">
-
- <!-- header -->
- <RelativeLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:paddingTop="20dp"
- android:paddingEnd="8dp"
- android:paddingBottom="15dp"
- android:id="@+id/notification_guts_header">
- <TextView
- android:id="@+id/pkgname"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_alignParentStart="true"
- style="@style/TextAppearance.NotificationGuts.Secondary" />
- <TextView
- android:id="@+id/channel_name"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_alignParentStart="true"
- android:layout_below="@id/pkgname"
- style="@style/TextAppearance.NotificationGuts.Header" />
- <Switch
- android:id="@+id/channel_enabled_switch"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_alignParentRight="true"
- android:layout_centerVertical="true"
- android:background="@null" />
- </RelativeLayout>
- <!-- Importance radio buttons -->
- <LinearLayout
- android:id="@+id/importance"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="horizontal">
- <RadioGroup
- android:id="@+id/importance_buttons"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:paddingEnd="@*android:dimen/notification_content_margin_end">
- <RadioButton
- android:id="@+id/high_importance"
- android:layout_width="wrap_content"
- android:layout_height="@dimen/notification_inline_importance_height"
- style="@style/TextAppearance.NotificationGuts.Radio"
- android:buttonTint="@color/notification_guts_buttons" />
- <RadioButton
- android:id="@+id/default_importance"
- android:layout_width="wrap_content"
- android:layout_height="@dimen/notification_inline_importance_height"
- style="@style/TextAppearance.NotificationGuts.Radio"
- android:buttonTint="@color/notification_guts_buttons" />
- <RadioButton
- android:id="@+id/low_importance"
- android:layout_width="wrap_content"
- android:layout_height="@dimen/notification_inline_importance_height"
- style="@style/TextAppearance.NotificationGuts.Radio"
- android:buttonTint="@color/notification_guts_buttons" />
- <RadioButton
- android:id="@+id/min_importance"
- android:layout_width="wrap_content"
- android:layout_height="@dimen/notification_inline_importance_height"
- style="@style/TextAppearance.NotificationGuts.Radio"
- android:buttonTint="@color/notification_guts_buttons" />
- </RadioGroup>
- <LinearLayout
- android:id="@+id/importance_buttons_text"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="vertical">
- <include layout="@layout/notification_guts_importance_text"/>
- <include layout="@layout/notification_guts_importance_text"/>
- <include layout="@layout/notification_guts_importance_text"/>
- <include layout="@layout/notification_guts_importance_text"/>
- </LinearLayout>
- </LinearLayout>
- <!-- Channel Disabled Text -->
- <TextView
- android:id="@+id/channel_disabled"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:text="@string/notification_channel_disabled"
- style="@style/TextAppearance.NotificationGuts.Secondary" />
- <!-- Settings and Done buttons -->
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:gravity="end"
- android:paddingTop="16dp"
- android:paddingBottom="8dp" >
-
- <TextView
- android:id="@+id/more_settings"
- android:text="@string/notification_more_settings"
- android:layout_width="wrap_content"
- android:layout_height="36dp"
- style="@style/TextAppearance.NotificationGuts.Button"
- android:background="@drawable/btn_borderless_rect"
- android:gravity="center"
- android:paddingEnd="8dp"
- android:paddingStart="8dp"
- android:focusable="true" />
-
- <TextView
- android:id="@+id/done"
- android:text="@string/notification_done"
- android:layout_width="wrap_content"
- android:layout_height="36dp"
- style="@style/TextAppearance.NotificationGuts.Button"
- android:background="@drawable/btn_borderless_rect"
- android:gravity="center"
- android:layout_marginStart="8dp"
- android:layout_marginEnd="8dp"
- android:focusable="true"/>
- </LinearLayout>
-</com.android.systemui.statusbar.NotificationGuts>
+ android:theme="@*android:style/Theme.DeviceDefault.Light"/>
diff --git a/packages/SystemUI/res/layout/notification_info.xml b/packages/SystemUI/res/layout/notification_info.xml
new file mode 100644
index 000000000000..9770eccfd2c1
--- /dev/null
+++ b/packages/SystemUI/res/layout/notification_info.xml
@@ -0,0 +1,146 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2017, 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.
+-->
+
+<com.android.systemui.statusbar.NotificationInfo
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:id="@+id/notification_guts"
+ android:clickable="true"
+ android:gravity="top|start"
+ android:orientation="vertical"
+ android:paddingStart="@*android:dimen/notification_content_margin_start"
+ android:paddingEnd="8dp"
+ android:background="@color/notification_guts_bg_color"
+ android:theme="@*android:style/Theme.DeviceDefault.Light">
+
+ <!-- header -->
+ <RelativeLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingTop="20dp"
+ android:paddingEnd="8dp"
+ android:paddingBottom="15dp"
+ android:id="@+id/notification_guts_header">
+ <TextView
+ android:id="@+id/pkgname"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentStart="true"
+ style="@style/TextAppearance.NotificationGuts.Secondary" />
+ <TextView
+ android:id="@+id/channel_name"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentStart="true"
+ android:layout_below="@id/pkgname"
+ style="@style/TextAppearance.NotificationGuts.Header" />
+ <Switch
+ android:id="@+id/channel_enabled_switch"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentRight="true"
+ android:layout_centerVertical="true"
+ android:background="@null" />
+ </RelativeLayout>
+ <!-- Importance radio buttons -->
+ <LinearLayout
+ android:id="@+id/importance"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal">
+ <RadioGroup
+ android:id="@+id/importance_buttons"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:paddingEnd="@*android:dimen/notification_content_margin_end">
+ <RadioButton
+ android:id="@+id/high_importance"
+ android:layout_width="wrap_content"
+ android:layout_height="@dimen/notification_inline_importance_height"
+ style="@style/TextAppearance.NotificationGuts.Radio"
+ android:buttonTint="@color/notification_guts_buttons" />
+ <RadioButton
+ android:id="@+id/default_importance"
+ android:layout_width="wrap_content"
+ android:layout_height="@dimen/notification_inline_importance_height"
+ style="@style/TextAppearance.NotificationGuts.Radio"
+ android:buttonTint="@color/notification_guts_buttons" />
+ <RadioButton
+ android:id="@+id/low_importance"
+ android:layout_width="wrap_content"
+ android:layout_height="@dimen/notification_inline_importance_height"
+ style="@style/TextAppearance.NotificationGuts.Radio"
+ android:buttonTint="@color/notification_guts_buttons" />
+ <RadioButton
+ android:id="@+id/min_importance"
+ android:layout_width="wrap_content"
+ android:layout_height="@dimen/notification_inline_importance_height"
+ style="@style/TextAppearance.NotificationGuts.Radio"
+ android:buttonTint="@color/notification_guts_buttons" />
+ </RadioGroup>
+ <LinearLayout
+ android:id="@+id/importance_buttons_text"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical">
+ <include layout="@layout/notification_guts_importance_text"/>
+ <include layout="@layout/notification_guts_importance_text"/>
+ <include layout="@layout/notification_guts_importance_text"/>
+ <include layout="@layout/notification_guts_importance_text"/>
+ </LinearLayout>
+ </LinearLayout>
+ <!-- Channel Disabled Text -->
+ <TextView
+ android:id="@+id/channel_disabled"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:text="@string/notification_channel_disabled"
+ style="@style/TextAppearance.NotificationGuts.Secondary" />
+ <!-- Settings and Done buttons -->
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:gravity="end"
+ android:paddingTop="16dp"
+ android:paddingBottom="8dp" >
+
+ <TextView
+ android:id="@+id/more_settings"
+ android:text="@string/notification_more_settings"
+ android:layout_width="wrap_content"
+ android:layout_height="36dp"
+ style="@style/TextAppearance.NotificationGuts.Button"
+ android:background="@drawable/btn_borderless_rect"
+ android:gravity="center"
+ android:paddingEnd="8dp"
+ android:paddingStart="8dp"
+ android:focusable="true" />
+
+ <TextView
+ android:id="@+id/done"
+ android:text="@string/notification_done"
+ android:layout_width="wrap_content"
+ android:layout_height="36dp"
+ style="@style/TextAppearance.NotificationGuts.Button"
+ android:background="@drawable/btn_borderless_rect"
+ android:gravity="center"
+ android:layout_marginStart="8dp"
+ android:layout_marginEnd="8dp"
+ android:focusable="true"/>
+ </LinearLayout>
+</com.android.systemui.statusbar.NotificationInfo>
diff --git a/packages/SystemUI/res/layout/notification_settings_icon_row.xml b/packages/SystemUI/res/layout/notification_menu_row.xml
index da3461b906fa..12bcf8176561 100644
--- a/packages/SystemUI/res/layout/notification_settings_icon_row.xml
+++ b/packages/SystemUI/res/layout/notification_menu_row.xml
@@ -14,23 +14,9 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<com.android.systemui.statusbar.NotificationSettingsIconRow
+<com.android.systemui.statusbar.NotificationMenuRow
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:systemui="http://schemas.android.com/apk/res-auto"
- android:layout_width="wrap_content"
+ android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:visibility="invisible"
- >
-
- <com.android.systemui.statusbar.AlphaOptimizedImageView
- android:id="@+id/gear_icon"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:padding="@dimen/notification_gear_padding"
- android:src="@drawable/ic_settings"
- android:tint="@color/notification_gear_color"
- android:alpha="0"
- android:background="?android:attr/selectableItemBackgroundBorderless"
- />
-
-</com.android.systemui.statusbar.NotificationSettingsIconRow> \ No newline at end of file
+ android:visibility="invisible"/> \ No newline at end of file
diff --git a/packages/SystemUI/res/layout/notification_snooze.xml b/packages/SystemUI/res/layout/notification_snooze.xml
new file mode 100644
index 000000000000..5bd64defd2d1
--- /dev/null
+++ b/packages/SystemUI/res/layout/notification_snooze.xml
@@ -0,0 +1,65 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2017, 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.
+-->
+
+<com.android.systemui.statusbar.NotificationSnooze
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:minHeight="@dimen/snooze_snackbar_min_height"
+ android:id="@+id/notification_snooze"
+ android:clickable="true"
+ android:gravity="center_vertical"
+ android:orientation="horizontal"
+ android:paddingStart="24dp"
+ android:paddingEnd="24dp"
+ android:background="@color/snooze_snackbar_bg">
+
+ <TextView
+ android:id="@+id/snooze_option_default"
+ style="@style/TextAppearance.SnoozeSnackBar"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:gravity="center_vertical"
+ android:drawableTint="@android:color/white"
+ android:drawableEnd="@drawable/notification_expand_more"/>
+
+ <android.widget.Space
+ android:layout_width="0dp"
+ android:layout_height="0dp"
+ android:layout_weight="1"
+ />
+
+ <TextView
+ android:id="@+id/undo"
+ style="@style/TextAppearance.SnoozeSnackBar.Button"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:layout_marginEnd="8dp"
+ android:layout_marginStart="8dp"
+ android:background="@drawable/btn_borderless_rect"
+ android:layout_gravity="end"
+ android:text="@string/snooze_undo" />
+
+ <LinearLayout
+ android:id="@+id/snooze_options"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingTop="8dp"
+ android:paddingBottom="8dp"
+ android:orientation="vertical"/>
+
+</com.android.systemui.statusbar.NotificationSnooze>
diff --git a/packages/SystemUI/res/layout/status_bar_notification_row.xml b/packages/SystemUI/res/layout/status_bar_notification_row.xml
index e456984c5f36..d62cc184889c 100644
--- a/packages/SystemUI/res/layout/status_bar_notification_row.xml
+++ b/packages/SystemUI/res/layout/status_bar_notification_row.xml
@@ -24,10 +24,10 @@
>
<ViewStub
- android:layout="@layout/notification_settings_icon_row"
- android:id="@+id/settings_icon_row_stub"
- android:inflatedId="@+id/notification_settings_icon_row"
- android:layout_width="wrap_content"
+ android:layout="@layout/notification_menu_row"
+ android:id="@+id/menu_row_stub"
+ android:inflatedId="@+id/notification_menu_row"
+ android:layout_width="match_parent"
android:layout_height="match_parent"
/>
diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml
index 30408143e30d..1ec611a43b56 100644
--- a/packages/SystemUI/res/values/colors.xml
+++ b/packages/SystemUI/res/values/colors.xml
@@ -103,6 +103,10 @@
<color name="notification_guts_icon_tint">#8a000000</color>
<color name="notification_guts_disabled_icon_tint">#4d000000</color>
+ <!-- Colors of the snooze menu reached via snooze icon behind a notification -->
+ <color name="snooze_snackbar_bg">#FF4A4A4A</color>
+ <color name="snooze_snackbar_text">#FFA6BAFF</color>
+
<color name="assist_orb_color">#ffffff</color>
<color name="keyguard_user_switcher_background_gradient_color">#77000000</color>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 79529a7abcbc..ddcc4baf8350 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -106,11 +106,20 @@
<!-- Minimum layouted height of a notification in the statusbar-->
<dimen name="min_notification_layout_height">48dp</dimen>
- <!-- Width of the space containing the gear icon behind a notification -->
- <dimen name="notification_gear_width">64dp</dimen>
+ <!-- Size of the space to place a notification menu item -->
+ <dimen name="notification_menu_icon_size">64dp</dimen>
- <!-- The space around the gear icon displayed behind a notification -->
- <dimen name="notification_gear_padding">20dp</dimen>
+ <!-- The space around a notification menu item -->
+ <dimen name="notification_menu_icon_padding">20dp</dimen>
+
+ <!-- The minimum height for the snackbar shown after the snooze option has been chosen. -->
+ <dimen name="snooze_snackbar_min_height">48dp</dimen>
+
+ <!-- The text size of options in the snooze menu. -->
+ <dimen name="snooze_option_text_size">14sp</dimen>
+
+ <!-- The padding around options int the snooze menu. -->
+ <dimen name="snooze_option_padding">8dp</dimen>
<!-- size at which Notification icons will be drawn in the status bar -->
<dimen name="status_bar_icon_drawing_size">17dp</dimen>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 422431e7b31a..b05cc009a2fa 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -1375,8 +1375,26 @@
<!-- Notification: Control panel: Label for button that dismisses control panel. [CHAR LIMIT=NONE] -->
<string name="notification_done">Done</string>
- <!-- Notification: Gear: Content description for the gear. [CHAR LIMIT=NONE] -->
- <string name="notification_gear_accessibility"><xliff:g id="app_name" example="YouTube">%1$s</xliff:g> notification controls</string>
+ <!-- Notification: Menu row: Content description for menu items. [CHAR LIMIT=NONE] -->
+ <string name="notification_menu_accessibility"><xliff:g id="app_name" example="YouTube">%1$s</xliff:g> <xliff:g id="menu_description" example="notification controls">%2$s</xliff:g></string>
+
+ <!-- Notification: Menu row: Content description for the gear menu item. [CHAR LIMIT=NONE] -->
+ <string name="notification_menu_gear_description">notification controls</string>
+
+ <!-- Notification: Menu row: Content description for the snooze icon. [CHAR LIMIT=NONE] -->
+ <string name="notification_menu_snooze_description">notification snooze options</string>
+
+ <!-- Notification: Menu row: Snooze options: 15 minute option. [CHAR LIMIT=50]-->
+ <string name="snooze_option_15_min">15 minutes</string>
+ <!-- Notification: Menu row: Snooze options: 30 minute option. [CHAR LIMIT=50]-->
+ <string name="snooze_option_30_min">30 minutes</string>
+ <!-- Notification: Menu row: Snooze options: 1 hour option. [CHAR LIMIT=50]-->
+ <string name="snooze_option_1_hour">1 hour</string>
+ <!-- Notification: Menu row: Snooze undo button label. [CHAR LIMIT=50]-->
+ <string name="snooze_undo">UNDO</string>
+
+ <!-- Notification: Menu row: Snooze: message indicating how long the notification was snoozed for. [CHAR LIMIT=100]-->
+ <string name="snoozed_for_time">Snoozed for <xliff:g id="time_amount" example="15 minutes">%1$s</xliff:g></string>
<!-- Title of the battery settings detail panel [CHAR LIMIT=20] -->
<string name="battery_panel_title">Battery usage</string>
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index 6535a81d076b..c5a5518226d9 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -383,6 +383,20 @@
<item name="android:textColor">?android:attr/colorAccent</item>
</style>
+ <style name="TextAppearance.SnoozeSnackBar">
+ <item name="android:textSize">14sp</item>
+ <item name="android:fontFamily">roboto-regular</item>
+ <item name="android:textColor">@android:color/white</item>
+ </style>
+
+ <style name="TextAppearance.SnoozeSnackBar.Button">
+ <item name="android:textSize">14sp</item>
+ <item name="android:textAllCaps">true</item>
+ <item name="android:fontFamily">sans-serif-medium</item>
+ <item name="android:gravity">center</item>
+ <item name="android:textColor">@color/snooze_snackbar_text</item>
+ </style>
+
<style name="edit_theme" parent="@*android:style/Theme.DeviceDefault.QuickSettings">
<item name="android:colorBackground">?android:attr/colorSecondary</item>
</style>
diff --git a/packages/SystemUI/src/com/android/systemui/SwipeHelper.java b/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
index 5c50b5ce47d9..a95713fb017e 100644
--- a/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
@@ -32,7 +32,9 @@ import android.view.ViewConfiguration;
import android.view.accessibility.AccessibilityEvent;
import com.android.systemui.classifier.FalsingManager;
+import com.android.systemui.plugins.statusbar.NotificationMenuRowProvider.MenuItem;
import com.android.systemui.statusbar.FlingAnimationUtils;
+import com.android.systemui.statusbar.NotificationMenuRow;
import java.util.HashMap;
@@ -85,10 +87,12 @@ public class SwipeHelper implements Gefingerpoken {
private int mFalsingThreshold;
private boolean mTouchAboveFalsingThreshold;
private boolean mDisableHwLayers;
+ private Context mContext;
private HashMap<View, Animator> mDismissPendingMap = new HashMap<>();
public SwipeHelper(int swipeDirection, Callback callback, Context context) {
+ mContext = context;
mCallback = callback;
mHandler = new Handler();
mSwipeDirection = swipeDirection;
@@ -249,6 +253,7 @@ public class SwipeHelper implements Gefingerpoken {
}
}
+ @Override
public boolean onInterceptTouchEvent(final MotionEvent ev) {
final int action = ev.getAction();
@@ -280,7 +285,8 @@ public class SwipeHelper implements Gefingerpoken {
mCurrView.getLocationOnScreen(mTmpPos);
final int x = (int) ev.getRawX() - mTmpPos[0];
final int y = (int) ev.getRawY() - mTmpPos[1];
- mLongPressListener.onLongPress(mCurrView, x, y);
+ mLongPressListener.onLongPress(mCurrView, x, y,
+ NotificationMenuRow.getLongpressMenuItem(mContext));
}
}
};
@@ -379,6 +385,7 @@ public class SwipeHelper implements Gefingerpoken {
animView.setLayerType(View.LAYER_TYPE_HARDWARE, null);
}
AnimatorUpdateListener updateListener = new AnimatorUpdateListener() {
+ @Override
public void onAnimationUpdate(ValueAnimator animation) {
onTranslationUpdate(animView, (float) animation.getAnimatedValue(), canBeDismissed);
}
@@ -401,10 +408,12 @@ public class SwipeHelper implements Gefingerpoken {
anim.addListener(new AnimatorListenerAdapter() {
private boolean mCancelled;
+ @Override
public void onAnimationCancel(Animator animation) {
mCancelled = true;
}
+ @Override
public void onAnimationEnd(Animator animation) {
updateSwipeProgressFromOffset(animView, canBeDismissed);
mDismissPendingMap.remove(animView);
@@ -435,6 +444,7 @@ public class SwipeHelper implements Gefingerpoken {
public void snapChild(final View animView, final float targetLeft, float velocity) {
final boolean canBeDismissed = mCallback.canChildBeDismissed(animView);
AnimatorUpdateListener updateListener = new AnimatorUpdateListener() {
+ @Override
public void onAnimationUpdate(ValueAnimator animation) {
onTranslationUpdate(animView, (float) animation.getAnimatedValue(), canBeDismissed);
}
@@ -447,6 +457,7 @@ public class SwipeHelper implements Gefingerpoken {
int duration = SNAP_ANIM_LEN;
anim.setDuration(duration);
anim.addListener(new AnimatorListenerAdapter() {
+ @Override
public void onAnimationEnd(Animator animator) {
mSnappingChild = false;
updateSwipeProgressFromOffset(animView, canBeDismissed);
@@ -522,6 +533,7 @@ public class SwipeHelper implements Gefingerpoken {
}
}
+ @Override
public boolean onTouchEvent(MotionEvent ev) {
if (mLongPressSent) {
return true;
@@ -690,6 +702,6 @@ public class SwipeHelper implements Gefingerpoken {
* Equivalent to {@link View.OnLongClickListener#onLongClick(View)} with coordinates
* @return whether the longpress was handled
*/
- boolean onLongPress(View v, int x, int y);
+ boolean onLongPress(View v, int x, int y, MenuItem item);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
index 926f610d8850..f0de6961658d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
@@ -101,6 +101,10 @@ import com.android.systemui.RecentsComponent;
import com.android.systemui.SwipeHelper;
import com.android.systemui.SystemUI;
import com.android.systemui.assist.AssistManager;
+import com.android.systemui.plugins.statusbar.NotificationMenuRowProvider;
+import com.android.systemui.plugins.statusbar.NotificationMenuRowProvider.MenuItem;
+import com.android.systemui.plugins.statusbar.NotificationMenuRowProvider.SnoozeGutsContent;
+import com.android.systemui.plugins.statusbar.NotificationMenuRowProvider.SnoozeListener;
import com.android.systemui.recents.Recents;
import com.android.systemui.statusbar.NotificationData.Entry;
import com.android.systemui.statusbar.notification.VisualStabilityManager;
@@ -247,6 +251,7 @@ public abstract class BaseStatusBar extends SystemUI implements
// which notification is currently being longpress-examined by the user
private NotificationGuts mNotificationGutsExposed;
+ private MenuItem mGutsMenuItem;
private KeyboardShortcuts mKeyboardShortcuts;
@@ -702,6 +707,7 @@ public abstract class BaseStatusBar extends SystemUI implements
}
}
+ @Override
public void start() {
mWindowManager = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);
mWindowManagerService = WindowManagerGlobal.getWindowManagerService();
@@ -967,7 +973,7 @@ public abstract class BaseStatusBar extends SystemUI implements
entry.row.reInflateViews();
if (exposedGuts) {
mNotificationGutsExposed = entry.row.getGuts();
- bindGuts(entry.row);
+ bindGuts(entry.row, mGutsMenuItem);
}
inflateViews(entry, mStackScroller);
}
@@ -1032,6 +1038,7 @@ public abstract class BaseStatusBar extends SystemUI implements
@Override
public boolean onDismiss() {
AsyncTask.execute(new Runnable() {
+ @Override
public void run() {
TaskStackBuilder.create(mContext)
.addNextIntentWithParentStack(intent)
@@ -1045,11 +1052,18 @@ public abstract class BaseStatusBar extends SystemUI implements
}, false /* afterKeyguardGone */);
}
- private void bindGuts(final ExpandableNotificationRow row) {
+ protected void setNotificationSnoozed(StatusBarNotification sbn, long snoozeUntil) {
+ mNotificationListener.snoozeNotification(sbn.getKey(), snoozeUntil);
+ }
+
+ public SnoozeListener getSnoozeListener() {
+ return null;
+ }
+
+ private void bindGuts(final ExpandableNotificationRow row, MenuItem item) {
row.inflateGuts();
+ row.setGutsView(item);
final StatusBarNotification sbn = row.getStatusBarNotification();
- final NotificationChannel channel = row.getEntry().channel;
- PackageManager pmUser = getPackageManagerForUser(mContext, sbn.getUser().getIdentifier());
row.setTag(sbn.getPackageName());
final NotificationGuts guts = row.getGuts();
guts.setClosedListener((NotificationGuts g) -> {
@@ -1059,43 +1073,53 @@ public abstract class BaseStatusBar extends SystemUI implements
mNotificationGutsExposed = null;
});
- final INotificationManager iNotificationManager = INotificationManager.Stub.asInterface(
- ServiceManager.getService(Context.NOTIFICATION_SERVICE));
-
- final String pkg = sbn.getPackageName();
- final NotificationGuts.OnSettingsClickListener onSettingsClick =
- (View v, int appUid) -> {
- MetricsLogger.action(mContext, MetricsEvent.ACTION_NOTE_INFO);
- guts.resetFalsingCheck();
- startAppNotificationSettingsActivity(pkg, appUid);
- };
- final View.OnClickListener onDoneClick =
- (View v) -> {
- // If the user has security enabled, show challenge if the setting is changed.
- if (guts.hasImportanceChanged()
- && isLockscreenPublicMode(sbn.getUser().getIdentifier())
- && (mState == StatusBarState.KEYGUARD
- || mState == StatusBarState.SHADE_LOCKED)) {
- OnDismissAction dismissAction = new OnDismissAction() {
- @Override
- public boolean onDismiss() {
- closeControls(row, guts, v);
- return true;
- }
- };
- onLockedNotificationImportanceChange(dismissAction);
- } else {
- closeControls(row, guts, v);
- }
- };
- guts.bindNotification(pmUser, iNotificationManager, sbn, channel,
- onSettingsClick, onDoneClick, mNonBlockablePkgs);
+ if (item.gutsContent instanceof SnoozeGutsContent) {
+ ((SnoozeGutsContent) item.gutsContent).setSnoozeListener(getSnoozeListener());
+ ((SnoozeGutsContent) item.gutsContent).setStatusBarNotification(sbn);
+ }
+
+ if (item.gutsContent instanceof NotificationInfo) {
+ final NotificationChannel channel = row.getEntry().channel;
+ PackageManager pmUser = getPackageManagerForUser(mContext,
+ sbn.getUser().getIdentifier());
+ final INotificationManager iNotificationManager = INotificationManager.Stub.asInterface(
+ ServiceManager.getService(Context.NOTIFICATION_SERVICE));
+ final String pkg = sbn.getPackageName();
+ NotificationInfo info = (NotificationInfo) item.gutsContent;
+ final NotificationInfo.OnSettingsClickListener onSettingsClick = (View v,
+ int appUid) -> {
+ MetricsLogger.action(mContext, MetricsEvent.ACTION_NOTE_INFO);
+ guts.resetFalsingCheck();
+ startAppNotificationSettingsActivity(pkg, appUid);
+ };
+ final View.OnClickListener onDoneClick = (View v) -> {
+ // If the user has security enabled, show challenge if the setting is changed.
+ if (info.hasImportanceChanged()
+ && isLockscreenPublicMode(sbn.getUser().getIdentifier())
+ && (mState == StatusBarState.KEYGUARD
+ || mState == StatusBarState.SHADE_LOCKED)) {
+ OnDismissAction dismissAction = new OnDismissAction() {
+ @Override
+ public boolean onDismiss() {
+ saveAndCloseNotificationMenu(info, row, guts, v);
+ return true;
+ }
+ };
+ onLockedNotificationImportanceChange(dismissAction);
+ } else {
+ saveAndCloseNotificationMenu(info, row, guts, v);
+ }
+ };
+ info.bindNotification(pmUser, iNotificationManager, sbn, channel, onSettingsClick,
+ onDoneClick,
+ mNonBlockablePkgs);
+ }
}
- private void closeControls(
+ private void saveAndCloseNotificationMenu(NotificationInfo info,
ExpandableNotificationRow row, NotificationGuts guts, View done) {
guts.resetFalsingCheck();
-
+ info.saveImportance();
int[] rowLocation = new int[2];
int[] doneLocation = new int[2];
row.getLocationOnScreen(rowLocation);
@@ -1111,7 +1135,8 @@ public abstract class BaseStatusBar extends SystemUI implements
protected SwipeHelper.LongPressListener getNotificationLongClicker() {
return new SwipeHelper.LongPressListener() {
@Override
- public boolean onLongPress(View v, final int x, final int y) {
+ public boolean onLongPress(View v, final int x, final int y,
+ MenuItem item) {
if (!(v instanceof ExpandableNotificationRow)) {
return false;
}
@@ -1121,10 +1146,10 @@ public abstract class BaseStatusBar extends SystemUI implements
}
final ExpandableNotificationRow row = (ExpandableNotificationRow) v;
- bindGuts(row);
+ bindGuts(row, item);
+ NotificationGuts guts = row.getGuts();
// Assume we are a status_bar_notification_row
- final NotificationGuts guts = row.getGuts();
if (guts == null) {
// This view has no guts. Examples are the more card or the dismiss all view
return false;
@@ -1142,6 +1167,7 @@ public abstract class BaseStatusBar extends SystemUI implements
guts.setVisibility(View.INVISIBLE);
// Post to ensure the the guts are properly laid out.
guts.post(new Runnable() {
+ @Override
public void run() {
if (row.getWindowToken() == null) {
Log.e(TAG, "Trying to show notification guts, but not attached to "
@@ -1172,6 +1198,7 @@ public abstract class BaseStatusBar extends SystemUI implements
row.closeRemoteInput();
mStackScroller.onHeightChanged(row, true /* needsAnimation */);
mNotificationGutsExposed = guts;
+ mGutsMenuItem = item;
}
});
return true;
@@ -1483,6 +1510,7 @@ public abstract class BaseStatusBar extends SystemUI implements
}
protected class H extends Handler {
+ @Override
public void handleMessage(Message m) {
switch (m.what) {
case MSG_SHOW_RECENT_APPS:
@@ -1754,6 +1782,7 @@ public abstract class BaseStatusBar extends SystemUI implements
&& PreviewInflater.wouldLaunchResolverActivity(mContext, intent.getIntent(),
mCurrentUserId);
dismissKeyguardThenExecute(new OnDismissAction() {
+ @Override
public boolean onDismiss() {
new Thread() {
@Override
@@ -1804,6 +1833,7 @@ public abstract class BaseStatusBar extends SystemUI implements
private final class NotificationClicker implements View.OnClickListener {
private final int[] mTmpInt2 = new int[2];
+ @Override
public void onClick(final View v) {
if (!(v instanceof ExpandableNotificationRow)) {
Log.e(TAG, "NotificationClicker called on a view that is not a notification row.");
@@ -1847,6 +1877,7 @@ public abstract class BaseStatusBar extends SystemUI implements
&& PreviewInflater.wouldLaunchResolverActivity(mContext, intent.getIntent(),
mCurrentUserId);
dismissKeyguardThenExecute(new OnDismissAction() {
+ @Override
public boolean onDismiss() {
if (mHeadsUpManager != null && mHeadsUpManager.isHeadsUp(notificationKey)) {
// Release the HUN notification to the shade.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
index 013554c16f9a..f56d29d123c4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
@@ -51,6 +51,7 @@ import com.android.internal.widget.CachingIconView;
import com.android.systemui.Interpolators;
import com.android.systemui.R;
import com.android.systemui.classifier.FalsingManager;
+import com.android.systemui.plugins.statusbar.NotificationMenuRowProvider.MenuItem;
import com.android.systemui.statusbar.notification.HybridNotificationView;
import com.android.systemui.statusbar.notification.NotificationUtils;
import com.android.systemui.statusbar.notification.VisualStabilityManager;
@@ -120,7 +121,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
private int mNotificationColor;
private ExpansionLogger mLogger;
private String mLoggingKey;
- private NotificationSettingsIconRow mSettingsIconRow;
+ private NotificationMenuRow mMenuRow;
private NotificationGuts mGuts;
private NotificationData.Entry mEntry;
private StatusBarNotification mStatusBarNotification;
@@ -132,7 +133,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
private boolean mChildrenExpanded;
private boolean mIsSummaryWithChildren;
private NotificationChildrenContainer mChildrenContainer;
- private ViewStub mSettingsIconRowStub;
+ private ViewStub mMenuRowStub;
private ViewStub mGutsStub;
private boolean mIsSystemChildExpanded;
private boolean mIsPinned;
@@ -205,6 +206,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
private Runnable mOnDismissRunnable;
private boolean mIsLowPriority;
+ @Override
public boolean isGroupExpansionChanging() {
if (isChildInGroup()) {
return mNotificationParent.isGroupExpansionChanging();
@@ -386,8 +388,8 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
public void setAppName(String appName) {
mAppName = appName;
- if (mSettingsIconRow != null) {
- mSettingsIconRow.setAppName(mAppName);
+ if (mMenuRow != null) {
+ mMenuRow.setAppName(mAppName);
}
}
@@ -418,6 +420,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
row.setIsChildInGroup(false, null);
}
+ @Override
public boolean isChildInGroup() {
return mNotificationParent != null;
}
@@ -455,7 +458,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
@Override
protected boolean handleSlideBack() {
- if (mSettingsIconRow != null && mSettingsIconRow.isVisible()) {
+ if (mMenuRow != null && mMenuRow.isVisible()) {
animateTranslateNotification(0 /* targetLeft */);
return true;
}
@@ -679,6 +682,13 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
mHeadsUpManager = headsUpManager;
}
+ public void setGutsView(MenuItem item) {
+ if (mGuts != null) {
+ item.gutsContent.setInteractionListener(mGuts);
+ mGuts.setGutsContent(item.gutsContent);
+ }
+ }
+
public void reInflateViews() {
initDimens();
if (mIsSummaryWithChildren) {
@@ -695,16 +705,16 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
mGuts.setVisibility(oldGuts.getVisibility());
addView(mGuts, index);
}
- if (mSettingsIconRow != null) {
- View oldSettings = mSettingsIconRow;
- int settingsIndex = indexOfChild(oldSettings);
- removeView(oldSettings);
- mSettingsIconRow = (NotificationSettingsIconRow) LayoutInflater.from(mContext).inflate(
- R.layout.notification_settings_icon_row, this, false);
- mSettingsIconRow.setNotificationRowParent(ExpandableNotificationRow.this);
- mSettingsIconRow.setAppName(mAppName);
- mSettingsIconRow.setVisibility(oldSettings.getVisibility());
- addView(mSettingsIconRow, settingsIndex);
+ if (mMenuRow != null) {
+ View oldMenu = mMenuRow;
+ int menuIndex = indexOfChild(oldMenu);
+ removeView(oldMenu);
+ mMenuRow = (NotificationMenuRow) LayoutInflater.from(mContext).inflate(
+ R.layout.notification_menu_row, this, false);
+ mMenuRow.setNotificationRowParent(ExpandableNotificationRow.this);
+ mMenuRow.setAppName(mAppName);
+ mMenuRow.setVisibility(oldMenu.getVisibility());
+ addView(mMenuRow, menuIndex);
}
for (NotificationContentView l : mLayouts) {
@@ -1033,21 +1043,19 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
super.onFinishInflate();
mPublicLayout = (NotificationContentView) findViewById(R.id.expandedPublic);
mPrivateLayout = (NotificationContentView) findViewById(R.id.expanded);
-
mLayouts = new NotificationContentView[] {mPrivateLayout, mPublicLayout};
for (NotificationContentView l : mLayouts) {
l.setExpandClickListener(mExpandClickListener);
l.setContainingNotification(this);
}
-
- mSettingsIconRowStub = (ViewStub) findViewById(R.id.settings_icon_row_stub);
- mSettingsIconRowStub.setOnInflateListener(new ViewStub.OnInflateListener() {
+ mMenuRowStub = (ViewStub) findViewById(R.id.menu_row_stub);
+ mMenuRowStub.setOnInflateListener(new ViewStub.OnInflateListener() {
@Override
public void onInflate(ViewStub stub, View inflated) {
- mSettingsIconRow = (NotificationSettingsIconRow) inflated;
- mSettingsIconRow.setNotificationRowParent(ExpandableNotificationRow.this);
- mSettingsIconRow.setAppName(mAppName);
+ mMenuRow = (NotificationMenuRow) inflated;
+ mMenuRow.setNotificationRowParent(ExpandableNotificationRow.this);
+ mMenuRow.setAppName(mAppName);
}
});
mGutsStub = (ViewStub) findViewById(R.id.notification_guts_stub);
@@ -1079,7 +1087,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
mTranslateableViews.add(getChildAt(i));
}
// Remove views that don't translate
- mTranslateableViews.remove(mSettingsIconRowStub);
+ mTranslateableViews.remove(mMenuRowStub);
mTranslateableViews.remove(mChildrenContainerStub);
mTranslateableViews.remove(mGutsStub);
}
@@ -1094,8 +1102,8 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
}
}
invalidateOutline();
- if (mSettingsIconRow != null) {
- mSettingsIconRow.resetState();
+ if (mMenuRow != null) {
+ mMenuRow.resetState(true /* notify */);
}
}
@@ -1122,8 +1130,8 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
}
}
invalidateOutline();
- if (mSettingsIconRow != null) {
- mSettingsIconRow.updateSettingsIcons(translationX, getMeasuredWidth());
+ if (mMenuRow != null) {
+ mMenuRow.updateMenuAlpha(translationX, getMeasuredWidth());
}
}
@@ -1160,8 +1168,8 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
@Override
public void onAnimationEnd(Animator anim) {
- if (!cancelled && mSettingsIconRow != null && leftTarget == 0) {
- mSettingsIconRow.resetState();
+ if (!cancelled && mMenuRow != null && leftTarget == 0) {
+ mMenuRow.resetState(true /* notify */);
mTranslateAnim = null;
}
}
@@ -1171,17 +1179,17 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
}
public float getSpaceForGear() {
- if (mSettingsIconRow != null) {
- return mSettingsIconRow.getSpaceForGear();
+ if (mMenuRow != null) {
+ return mMenuRow.getSpaceForMenu();
}
return 0;
}
- public NotificationSettingsIconRow getSettingsRow() {
- if (mSettingsIconRow == null) {
- mSettingsIconRowStub.inflate();
+ public NotificationMenuRow getSettingsRow() {
+ if (mMenuRow == null) {
+ mMenuRowStub.inflate();
}
- return mSettingsIconRow;
+ return mMenuRow;
}
public void inflateGuts() {
@@ -1404,6 +1412,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
}
}
+ @Override
public boolean isGroupExpanded() {
return mGroupManager.isGroupExpanded(mStatusBarNotification);
}
@@ -1457,8 +1466,8 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
updateMaxHeights();
- if (mSettingsIconRow != null) {
- mSettingsIconRow.updateVerticalLocation();
+ if (mMenuRow != null) {
+ mMenuRow.updateVerticalLocation();
}
updateContentShiftHeight();
}
@@ -1505,6 +1514,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
mSensitiveHiddenInGeneral = hideSensitive;
}
+ @Override
public void setHideSensitiveForIntrinsicHeight(boolean hideSensitive) {
mHideSensitiveForIntrinsicHeight = hideSensitive;
if (mIsSummaryWithChildren) {
@@ -1517,6 +1527,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
}
}
+ @Override
public void setHideSensitive(boolean hideSensitive, boolean animated, long delay,
long duration) {
boolean oldShowingPublic = mShowingPublic;
@@ -1581,6 +1592,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
}
}
+ @Override
public boolean mustStayOnScreen() {
return mIsHeadsUp;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGuts.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGuts.java
index 83104e685e22..f6056ddab093 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGuts.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGuts.java
@@ -40,6 +40,7 @@ import android.view.View;
import android.view.ViewAnimationUtils;
import android.view.ViewGroup;
import android.widget.CompoundButton;
+import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.RadioButton;
@@ -53,6 +54,8 @@ import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.settingslib.Utils;
import com.android.systemui.Interpolators;
import com.android.systemui.R;
+import com.android.systemui.plugins.statusbar.NotificationMenuRowProvider;
+import com.android.systemui.plugins.statusbar.NotificationMenuRowProvider.GutsContent;
import com.android.systemui.statusbar.stack.StackStateAnimator;
import java.util.Set;
@@ -60,7 +63,8 @@ import java.util.Set;
/**
* The guts of a notification revealed when performing a long press.
*/
-public class NotificationGuts extends LinearLayout {
+public class NotificationGuts extends FrameLayout
+ implements NotificationMenuRowProvider.GutsInteractionListener {
private static final String TAG = "NotificationGuts";
private static final long CLOSE_GUTS_DELAY = 8000;
@@ -69,24 +73,14 @@ public class NotificationGuts extends LinearLayout {
private int mClipBottomAmount;
private int mActualHeight;
private boolean mExposed;
- private INotificationManager mINotificationManager;
- private int mStartingUserImportance;
- private StatusBarNotification mStatusBarNotification;
- private NotificationChannel mNotificationChannel;
-
- private View mImportanceGroup;
- private View mChannelDisabled;
- private Switch mChannelEnabledSwitch;
- private RadioButton mMinImportanceButton;
- private RadioButton mLowImportanceButton;
- private RadioButton mDefaultImportanceButton;
- private RadioButton mHighImportanceButton;
private Handler mHandler;
private Runnable mFalsingCheck;
private boolean mNeedsFalsingProtection;
private OnGutsClosedListener mListener;
+ private GutsContent mGutsContent;
+
public interface OnGutsClosedListener {
public void onGutsClosed(NotificationGuts guts);
}
@@ -103,11 +97,22 @@ public class NotificationGuts extends LinearLayout {
}
}
};
- final TypedArray ta =
- context.obtainStyledAttributes(attrs, com.android.internal.R.styleable.Theme, 0, 0);
+ final TypedArray ta = context.obtainStyledAttributes(attrs,
+ com.android.internal.R.styleable.Theme, 0, 0);
ta.recycle();
}
+ public NotificationGuts(Context context) {
+ this(context, null);
+
+ }
+
+ public void setGutsContent(GutsContent content) {
+ mGutsContent = content;
+ removeAllViews();
+ addView(mGutsContent.getContentView());
+ }
+
public void resetFalsingCheck() {
mHandler.removeCallbacks(mFalsingCheck);
if (mNeedsFalsingProtection && mExposed) {
@@ -165,213 +170,23 @@ public class NotificationGuts extends LinearLayout {
void onClick(View v, int appUid);
}
- void bindNotification(final PackageManager pm, final INotificationManager iNotificationManager,
- final StatusBarNotification sbn, final NotificationChannel channel,
- OnSettingsClickListener onSettingsClick,
- OnClickListener onDoneClick, final Set<String> nonBlockablePkgs) {
- mINotificationManager = iNotificationManager;
- mNotificationChannel = channel;
- mStatusBarNotification = sbn;
- mStartingUserImportance = channel.getImportance();
-
- final String pkg = sbn.getPackageName();
- int appUid = -1;
- String appname = pkg;
- Drawable pkgicon = null;
- try {
- final ApplicationInfo info = pm.getApplicationInfo(pkg,
- PackageManager.MATCH_UNINSTALLED_PACKAGES
- | PackageManager.MATCH_DISABLED_COMPONENTS
- | PackageManager.MATCH_DIRECT_BOOT_UNAWARE
- | PackageManager.MATCH_DIRECT_BOOT_AWARE);
- if (info != null) {
- appUid = info.uid;
- appname = String.valueOf(pm.getApplicationLabel(info));
- pkgicon = pm.getApplicationIcon(info);
- }
- } catch (PackageManager.NameNotFoundException e) {
- // app is gone, just show package name and generic icon
- pkgicon = pm.getDefaultActivityIcon();
- }
-
- // If this is the placeholder channel, don't use our channel-specific text.
- String appNameText;
- CharSequence channelNameText;
- if (channel.getId().equals(NotificationChannel.DEFAULT_CHANNEL_ID)) {
- appNameText = appname;
- channelNameText = mContext.getString(R.string.notification_header_default_channel);
- } else {
- appNameText = mContext.getString(R.string.notification_importance_header_app, appname);
- channelNameText = channel.getName();
- }
- ((TextView) findViewById(R.id.pkgname)).setText(appNameText);
- ((TextView) findViewById(R.id.channel_name)).setText(channelNameText);
-
- // Settings button.
- final TextView settingsButton = (TextView) findViewById(R.id.more_settings);
- if (appUid >= 0 && onSettingsClick != null) {
- final int appUidF = appUid;
- settingsButton.setOnClickListener(
- (View view) -> { onSettingsClick.onClick(view, appUidF); });
- settingsButton.setText(R.string.notification_more_settings);
- } else {
- settingsButton.setVisibility(View.GONE);
- }
-
- // Done button.
- final TextView doneButton = (TextView) findViewById(R.id.done);
- doneButton.setText(R.string.notification_done);
- doneButton.setOnClickListener(onDoneClick);
-
- boolean nonBlockable = false;
- try {
- final PackageInfo info = pm.getPackageInfo(pkg, PackageManager.GET_SIGNATURES);
- nonBlockable = Utils.isSystemPackage(getResources(), pm, info);
- } catch (PackageManager.NameNotFoundException e) {
- // unlikely.
- }
- if (nonBlockablePkgs != null) {
- nonBlockable |= nonBlockablePkgs.contains(pkg);
- }
-
- final View importanceButtons = findViewById(R.id.importance_buttons);
- bindToggles(importanceButtons, mStartingUserImportance, nonBlockable);
-
- // Importance Text (hardcoded to 4 importance levels)
- final ViewGroup importanceTextGroup =
- (ViewGroup) findViewById(R.id.importance_buttons_text);
- final int size = importanceTextGroup.getChildCount();
- for (int i = 0; i < size; i++) {
- int importanceNameResId = 0;
- int importanceDescResId = 0;
- switch (i) {
- case 0:
- importanceNameResId = R.string.high_importance;
- importanceDescResId = R.string.notification_importance_high;
- break;
- case 1:
- importanceNameResId = R.string.default_importance;
- importanceDescResId = R.string.notification_importance_default;
- break;
- case 2:
- importanceNameResId = R.string.low_importance;
- importanceDescResId = R.string.notification_importance_low;
- break;
- case 3:
- importanceNameResId = R.string.min_importance;
- importanceDescResId = R.string.notification_importance_min;
- break;
- default:
- Log.e(TAG, "Too many importance groups in this layout.");
- break;
- }
- final ViewGroup importanceChildGroup = (ViewGroup) importanceTextGroup.getChildAt(i);
- ((TextView) importanceChildGroup.getChildAt(0)).setText(importanceNameResId);
- ((TextView) importanceChildGroup.getChildAt(1)).setText(importanceDescResId);
- }
-
- // Top-level importance group
- mImportanceGroup = findViewById(R.id.importance);
- mChannelDisabled = findViewById(R.id.channel_disabled);
- updateImportanceGroup();
- }
-
- public boolean hasImportanceChanged() {
- return mStartingUserImportance != getSelectedImportance();
- }
-
- private void saveImportance() {
- int selectedImportance = getSelectedImportance();
- if (selectedImportance == mStartingUserImportance) {
- return;
- }
- MetricsLogger.action(mContext, MetricsEvent.ACTION_SAVE_IMPORTANCE,
- selectedImportance - mStartingUserImportance);
- mNotificationChannel.setImportance(selectedImportance);
- try {
- mINotificationManager.updateNotificationChannelForPackage(
- mStatusBarNotification.getPackageName(), mStatusBarNotification.getUid(),
- mNotificationChannel);
- } catch (RemoteException e) {
- // :(
- }
- }
-
- private int getSelectedImportance() {
- if (!mChannelEnabledSwitch.isChecked()) {
- return NotificationManager.IMPORTANCE_NONE;
- } else if (mMinImportanceButton.isChecked()) {
- return NotificationManager.IMPORTANCE_MIN;
- } else if (mLowImportanceButton.isChecked()) {
- return NotificationManager.IMPORTANCE_LOW;
- } else if (mDefaultImportanceButton.isChecked()) {
- return NotificationManager.IMPORTANCE_DEFAULT;
- } else if (mHighImportanceButton.isChecked()) {
- return NotificationManager.IMPORTANCE_HIGH;
- } else {
- return NotificationManager.IMPORTANCE_UNSPECIFIED;
- }
- }
-
- private void bindToggles(final View importanceButtons, final int importance,
- final boolean nonBlockable) {
- // Enabled Switch
- mChannelEnabledSwitch = (Switch) findViewById(R.id.channel_enabled_switch);
- mChannelEnabledSwitch.setChecked(importance != NotificationManager.IMPORTANCE_NONE);
- mChannelEnabledSwitch.setVisibility(nonBlockable ? View.INVISIBLE : View.VISIBLE);
-
- // Importance Buttons
- mMinImportanceButton = (RadioButton) importanceButtons.findViewById(R.id.min_importance);
- mLowImportanceButton = (RadioButton) importanceButtons.findViewById(R.id.low_importance);
- mDefaultImportanceButton =
- (RadioButton) importanceButtons.findViewById(R.id.default_importance);
- mHighImportanceButton = (RadioButton) importanceButtons.findViewById(R.id.high_importance);
-
- // Set to current importance setting
- switch (importance) {
- case NotificationManager.IMPORTANCE_UNSPECIFIED:
- case NotificationManager.IMPORTANCE_NONE:
- break;
- case NotificationManager.IMPORTANCE_MIN:
- mMinImportanceButton.setChecked(true);
- break;
- case NotificationManager.IMPORTANCE_LOW:
- mLowImportanceButton.setChecked(true);
- break;
- case NotificationManager.IMPORTANCE_DEFAULT:
- mDefaultImportanceButton.setChecked(true);
- break;
- case NotificationManager.IMPORTANCE_HIGH:
- case NotificationManager.IMPORTANCE_MAX:
- mHighImportanceButton.setChecked(true);
- break;
- }
-
- // Callback when checked.
- mChannelEnabledSwitch.setOnCheckedChangeListener((buttonView, isChecked) -> {
- resetFalsingCheck();
- updateImportanceGroup();
- });
- ((RadioGroup) importanceButtons).setOnCheckedChangeListener(
- (buttonView, isChecked) -> { resetFalsingCheck(); });
- }
-
- private void updateImportanceGroup() {
- final boolean disabled = getSelectedImportance() == NotificationManager.IMPORTANCE_NONE;
- mImportanceGroup.setVisibility(disabled ? View.GONE : View.VISIBLE);
- mChannelDisabled.setVisibility(disabled ? View.VISIBLE : View.GONE);
- }
-
public void closeControls(int x, int y, boolean saveImportance) {
- if (saveImportance) {
- saveImportance();
- }
if (getWindowToken() == null) {
if (mListener != null) {
mListener.onGutsClosed(this);
}
return;
}
+ if (mGutsContent == null || !mGutsContent.handleCloseControls()) {
+ animateClose(x, y);
+ }
+ setExposed(false, mNeedsFalsingProtection);
+ if (mListener != null) {
+ mListener.onGutsClosed(this);
+ }
+ }
+
+ private void animateClose(int x, int y) {
if (x == -1 || y == -1) {
x = (getLeft() + getRight()) / 2;
y = (getTop() + getHeight() / 2);
@@ -391,10 +206,6 @@ public class NotificationGuts extends LinearLayout {
}
});
a.start();
- setExposed(false, mNeedsFalsingProtection);
- if (mListener != null) {
- mListener.onGutsClosed(this);
- }
}
public void setActualHeight(int actualHeight) {
@@ -439,4 +250,14 @@ public class NotificationGuts extends LinearLayout {
public boolean isExposed() {
return mExposed;
}
+
+ @Override
+ public void onInteraction(View view) {
+ resetFalsingCheck();
+ }
+
+ @Override
+ public void closeGuts(View view) {
+ closeControls(-1 /* x */, -1 /* y */, true /* notify */);
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationInfo.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationInfo.java
new file mode 100644
index 000000000000..098984639a99
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationInfo.java
@@ -0,0 +1,319 @@
+package com.android.systemui.statusbar;
+
+/*
+ * Copyright (C) 2017 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
+ */
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.app.INotificationManager;
+import android.app.NotificationChannel;
+import android.app.NotificationManager;
+import android.content.Context;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.content.res.ColorStateList;
+import android.content.res.TypedArray;
+import android.graphics.Canvas;
+import android.graphics.drawable.Drawable;
+import android.os.Handler;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.service.notification.NotificationListenerService;
+import android.service.notification.StatusBarNotification;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.View;
+import android.view.ViewAnimationUtils;
+import android.view.ViewGroup;
+import android.view.View.OnClickListener;
+import android.widget.CompoundButton;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.RadioButton;
+import android.widget.RadioGroup;
+import android.widget.SeekBar;
+import android.widget.Switch;
+import android.widget.TextView;
+
+import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+import com.android.settingslib.Utils;
+import com.android.systemui.Interpolators;
+import com.android.systemui.R;
+import com.android.systemui.plugins.statusbar.NotificationMenuRowProvider.GutsContent;
+import com.android.systemui.plugins.statusbar.NotificationMenuRowProvider.GutsInteractionListener;
+import com.android.systemui.statusbar.NotificationGuts.OnSettingsClickListener;
+import com.android.systemui.statusbar.stack.StackStateAnimator;
+
+import java.util.Set;
+
+/**
+ * The guts of a notification revealed when performing a long press.
+ */
+public class NotificationInfo extends LinearLayout implements GutsContent {
+ private static final String TAG = "InfoGuts";
+
+ private INotificationManager mINotificationManager;
+ private int mStartingUserImportance;
+ private StatusBarNotification mStatusBarNotification;
+ private NotificationChannel mNotificationChannel;
+
+ private ImageView mAutoButton;
+ private TextView mImportanceSummary;
+ private TextView mImportanceTitle;
+ private boolean mAuto;
+
+ private View mImportanceGroup;
+ private View mChannelDisabled;
+ private Switch mChannelEnabledSwitch;
+ private RadioButton mMinImportanceButton;
+ private RadioButton mLowImportanceButton;
+ private RadioButton mDefaultImportanceButton;
+ private RadioButton mHighImportanceButton;
+
+ private GutsInteractionListener mGutsInteractionListener;
+
+ public NotificationInfo(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ interface OnSettingsClickListener {
+ void onClick(View v, int appUid);
+ }
+
+ void bindNotification(final PackageManager pm, final INotificationManager iNotificationManager,
+ final StatusBarNotification sbn, final NotificationChannel channel,
+ OnSettingsClickListener onSettingsClick,
+ OnClickListener onDoneClick, final Set<String> nonBlockablePkgs) {
+ mINotificationManager = iNotificationManager;
+ mNotificationChannel = channel;
+ mStatusBarNotification = sbn;
+ mStartingUserImportance = channel.getImportance();
+
+ final String pkg = sbn.getPackageName();
+ int appUid = -1;
+ String appname = pkg;
+ Drawable pkgicon = null;
+ try {
+ final ApplicationInfo info = pm.getApplicationInfo(pkg,
+ PackageManager.MATCH_UNINSTALLED_PACKAGES
+ | PackageManager.MATCH_DISABLED_COMPONENTS
+ | PackageManager.MATCH_DIRECT_BOOT_UNAWARE
+ | PackageManager.MATCH_DIRECT_BOOT_AWARE);
+ if (info != null) {
+ appUid = info.uid;
+ appname = String.valueOf(pm.getApplicationLabel(info));
+ pkgicon = pm.getApplicationIcon(info);
+ }
+ } catch (PackageManager.NameNotFoundException e) {
+ // app is gone, just show package name and generic icon
+ pkgicon = pm.getDefaultActivityIcon();
+ }
+
+ // If this is the placeholder channel, don't use our channel-specific text.
+ String appNameText;
+ CharSequence channelNameText;
+ if (channel.getId().equals(NotificationChannel.DEFAULT_CHANNEL_ID)) {
+ appNameText = appname;
+ channelNameText = mContext.getString(R.string.notification_header_default_channel);
+ } else {
+ appNameText = mContext.getString(R.string.notification_importance_header_app, appname);
+ channelNameText = channel.getName();
+ }
+ ((TextView) findViewById(R.id.pkgname)).setText(appNameText);
+ ((TextView) findViewById(R.id.channel_name)).setText(channelNameText);
+
+ // Settings button.
+ final TextView settingsButton = (TextView) findViewById(R.id.more_settings);
+ if (appUid >= 0 && onSettingsClick != null) {
+ final int appUidF = appUid;
+ settingsButton.setOnClickListener(
+ (View view) -> {
+ onSettingsClick.onClick(view, appUidF);
+ });
+ settingsButton.setText(R.string.notification_more_settings);
+ } else {
+ settingsButton.setVisibility(View.GONE);
+ }
+
+ // Done button.
+ final TextView doneButton = (TextView) findViewById(R.id.done);
+ doneButton.setText(R.string.notification_done);
+ doneButton.setOnClickListener(onDoneClick);
+
+ boolean nonBlockable = false;
+ try {
+ final PackageInfo info = pm.getPackageInfo(pkg, PackageManager.GET_SIGNATURES);
+ nonBlockable = Utils.isSystemPackage(getResources(), pm, info);
+ } catch (PackageManager.NameNotFoundException e) {
+ // unlikely.
+ }
+ if (nonBlockablePkgs != null) {
+ nonBlockable |= nonBlockablePkgs.contains(pkg);
+ }
+
+ final View importanceButtons = findViewById(R.id.importance_buttons);
+ bindToggles(importanceButtons, mStartingUserImportance, nonBlockable);
+
+ // Importance Text (hardcoded to 4 importance levels)
+ final ViewGroup importanceTextGroup = (ViewGroup) findViewById(
+ R.id.importance_buttons_text);
+ final int size = importanceTextGroup.getChildCount();
+ for (int i = 0; i < size; i++) {
+ int importanceNameResId = 0;
+ int importanceDescResId = 0;
+ switch (i) {
+ case 0:
+ importanceNameResId = R.string.high_importance;
+ importanceDescResId = R.string.notification_importance_high;
+ break;
+ case 1:
+ importanceNameResId = R.string.default_importance;
+ importanceDescResId = R.string.notification_importance_default;
+ break;
+ case 2:
+ importanceNameResId = R.string.low_importance;
+ importanceDescResId = R.string.notification_importance_low;
+ break;
+ case 3:
+ importanceNameResId = R.string.min_importance;
+ importanceDescResId = R.string.notification_importance_min;
+ break;
+ default:
+ Log.e(TAG, "Too many importance groups in this layout.");
+ break;
+ }
+ final ViewGroup importanceChildGroup = (ViewGroup) importanceTextGroup.getChildAt(i);
+ ((TextView) importanceChildGroup.getChildAt(0)).setText(importanceNameResId);
+ ((TextView) importanceChildGroup.getChildAt(1)).setText(importanceDescResId);
+ }
+
+ // Top-level importance group
+ mImportanceGroup = findViewById(R.id.importance);
+ mChannelDisabled = findViewById(R.id.channel_disabled);
+ updateImportanceGroup();
+ }
+
+ public boolean hasImportanceChanged() {
+ return mStartingUserImportance != getSelectedImportance();
+ }
+
+ public void saveImportance() {
+ int selectedImportance = getSelectedImportance();
+ if (selectedImportance == mStartingUserImportance) {
+ return;
+ }
+ MetricsLogger.action(mContext, MetricsEvent.ACTION_SAVE_IMPORTANCE,
+ selectedImportance - mStartingUserImportance);
+ mNotificationChannel.setImportance(selectedImportance);
+ try {
+ mINotificationManager.updateNotificationChannelForPackage(
+ mStatusBarNotification.getPackageName(), mStatusBarNotification.getUid(),
+ mNotificationChannel);
+ } catch (RemoteException e) {
+ // :(
+ }
+ }
+
+ private int getSelectedImportance() {
+ if (!mChannelEnabledSwitch.isChecked()) {
+ return NotificationManager.IMPORTANCE_NONE;
+ } else if (mMinImportanceButton.isChecked()) {
+ return NotificationManager.IMPORTANCE_MIN;
+ } else if (mLowImportanceButton.isChecked()) {
+ return NotificationManager.IMPORTANCE_LOW;
+ } else if (mDefaultImportanceButton.isChecked()) {
+ return NotificationManager.IMPORTANCE_DEFAULT;
+ } else if (mHighImportanceButton.isChecked()) {
+ return NotificationManager.IMPORTANCE_HIGH;
+ } else {
+ return NotificationManager.IMPORTANCE_UNSPECIFIED;
+ }
+ }
+
+ private void bindToggles(final View importanceButtons, final int importance,
+ final boolean nonBlockable) {
+ // Enabled Switch
+ mChannelEnabledSwitch = (Switch) findViewById(R.id.channel_enabled_switch);
+ mChannelEnabledSwitch.setChecked(importance != NotificationManager.IMPORTANCE_NONE);
+ mChannelEnabledSwitch.setVisibility(nonBlockable ? View.INVISIBLE : View.VISIBLE);
+
+ // Importance Buttons
+ mMinImportanceButton = (RadioButton) importanceButtons.findViewById(R.id.min_importance);
+ mLowImportanceButton = (RadioButton) importanceButtons.findViewById(R.id.low_importance);
+ mDefaultImportanceButton = (RadioButton) importanceButtons
+ .findViewById(R.id.default_importance);
+ mHighImportanceButton = (RadioButton) importanceButtons.findViewById(R.id.high_importance);
+
+ // Set to current importance setting
+ switch (importance) {
+ case NotificationManager.IMPORTANCE_UNSPECIFIED:
+ case NotificationManager.IMPORTANCE_NONE:
+ break;
+ case NotificationManager.IMPORTANCE_MIN:
+ mMinImportanceButton.setChecked(true);
+ break;
+ case NotificationManager.IMPORTANCE_LOW:
+ mLowImportanceButton.setChecked(true);
+ break;
+ case NotificationManager.IMPORTANCE_DEFAULT:
+ mDefaultImportanceButton.setChecked(true);
+ break;
+ case NotificationManager.IMPORTANCE_HIGH:
+ case NotificationManager.IMPORTANCE_MAX:
+ mHighImportanceButton.setChecked(true);
+ break;
+ }
+
+ // Callback when checked.
+ mChannelEnabledSwitch.setOnCheckedChangeListener((buttonView, isChecked) -> {
+ mGutsInteractionListener.onInteraction(NotificationInfo.this);
+ updateImportanceGroup();
+ });
+ ((RadioGroup) importanceButtons).setOnCheckedChangeListener(
+ (buttonView, isChecked) -> {
+ mGutsInteractionListener.onInteraction(NotificationInfo.this);
+ });
+ }
+
+ private void updateImportanceGroup() {
+ final boolean disabled = getSelectedImportance() == NotificationManager.IMPORTANCE_NONE;
+ mImportanceGroup.setVisibility(disabled ? View.GONE : View.VISIBLE);
+ mChannelDisabled.setVisibility(disabled ? View.VISIBLE : View.GONE);
+ }
+
+ public void closeControls() {
+ if (mGutsInteractionListener != null) {
+ mGutsInteractionListener.closeGuts(this);
+ }
+ }
+
+ @Override
+ public void setInteractionListener(GutsInteractionListener listener) {
+ mGutsInteractionListener = listener;
+ }
+
+ @Override
+ public View getContentView() {
+ return this;
+ }
+
+ @Override
+ public boolean handleCloseControls() {
+ return false;
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMenuRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMenuRow.java
new file mode 100644
index 000000000000..fad63dd4f700
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMenuRow.java
@@ -0,0 +1,392 @@
+/*
+ * Copyright (C) 2016 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.statusbar;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ValueAnimator;
+import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.drawable.Drawable;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.FrameLayout;
+
+import java.util.ArrayList;
+
+import com.android.systemui.Interpolators;
+import com.android.systemui.R;
+import com.android.systemui.plugins.PluginListener;
+import com.android.systemui.plugins.PluginManager;
+import com.android.systemui.plugins.statusbar.NotificationMenuRowProvider;
+import com.android.systemui.plugins.statusbar.NotificationMenuRowProvider.MenuItem;
+import com.android.systemui.plugins.statusbar.NotificationMenuRowProvider.OnMenuClickListener;
+
+public class NotificationMenuRow extends FrameLayout
+ implements PluginListener<NotificationMenuRowProvider>, View.OnClickListener {
+
+ private static final int ICON_ALPHA_ANIM_DURATION = 200;
+
+ private ExpandableNotificationRow mParent;
+ private OnMenuClickListener mListener;
+ private NotificationMenuRowProvider mMenuProvider;
+ private ArrayList<MenuItem> mMenuItems = new ArrayList<>();
+
+ private ValueAnimator mFadeAnimator;
+ private boolean mMenuFadedIn = false;
+ private boolean mAnimating = false;
+ private boolean mOnLeft = true;
+ private boolean mDismissing = false;
+ private boolean mSnapping = false;
+ private boolean mIconsPlaced = false;
+
+ private int[] mIconLocation = new int[2];
+ private int[] mParentLocation = new int[2];
+
+ private float mHorizSpaceForIcon;
+ private int mVertSpaceForIcons;
+
+ private int mIconPadding;
+ private int mIconTint;
+
+ private float mAlpha = 0f;
+
+ public NotificationMenuRow(Context context) {
+ this(context, null);
+ }
+
+ public NotificationMenuRow(Context context, AttributeSet attrs) {
+ this(context, attrs, 0);
+ }
+
+ public NotificationMenuRow(Context context, AttributeSet attrs, int defStyleAttr) {
+ this(context, attrs, defStyleAttr, 0);
+ }
+
+ public NotificationMenuRow(Context context, AttributeSet attrs, int defStyleAttr,
+ int defStyleRes) {
+ super(context, attrs);
+ PluginManager.getInstance(getContext()).addPluginListener(
+ NotificationMenuRowProvider.ACTION, this,
+ NotificationMenuRowProvider.VERSION, false /* Allow multiple */);
+ mMenuItems.addAll(getDefaultNotificationMenuItems());
+ }
+
+ @Override
+ protected void onFinishInflate() {
+ super.onFinishInflate();
+ final Resources res = getResources();
+ mHorizSpaceForIcon = res.getDimensionPixelSize(R.dimen.notification_menu_icon_size);
+ mVertSpaceForIcons = res.getDimensionPixelSize(R.dimen.notification_min_height);
+ mIconPadding = res.getDimensionPixelSize(R.dimen.notification_menu_icon_padding);
+ mIconTint = res.getColor(R.color.notification_gear_color);
+ updateMenu(false /* notify */);
+ }
+
+ public static MenuItem getLongpressMenuItem(Context context) {
+ Resources res = context.getResources();
+ Drawable settingsIcon = res.getDrawable(R.drawable.ic_settings);
+ String settingsDescription = res.getString(R.string.notification_menu_gear_description);
+ NotificationInfo settingsContent = (NotificationInfo) LayoutInflater.from(context).inflate(
+ R.layout.notification_info, null, false);
+ MenuItem settings = new MenuItem(settingsIcon, settingsDescription, settingsContent);
+ return settings;
+ }
+
+ public ArrayList<MenuItem> getDefaultNotificationMenuItems() {
+ ArrayList<MenuItem> items = new ArrayList<MenuItem>();
+ Resources res = getResources();
+
+ Drawable snoozeIcon = res.getDrawable(R.drawable.ic_snooze);
+ NotificationSnooze content = (NotificationSnooze) LayoutInflater.from(mContext)
+ .inflate(R.layout.notification_snooze, null, false);
+ String snoozeDescription = res.getString(R.string.notification_menu_snooze_description);
+ MenuItem snooze = new MenuItem(snoozeIcon, snoozeDescription, content);
+ items.add(snooze);
+
+ Drawable settingsIcon = res.getDrawable(R.drawable.ic_settings);
+ String settingsDescription = res.getString(R.string.notification_menu_gear_description);
+ NotificationInfo settingsContent = (NotificationInfo) LayoutInflater.from(mContext).inflate(
+ R.layout.notification_info, null, false);
+ MenuItem settings = new MenuItem(settingsIcon, settingsDescription, settingsContent);
+ items.add(settings);
+ return items;
+ }
+
+ private void updateMenu(boolean notify) {
+ removeAllViews();
+ mMenuItems.clear();
+ if (mMenuProvider != null) {
+ mMenuItems.addAll(mMenuProvider.getMenuItems(getContext()));
+ }
+ mMenuItems.addAll(getDefaultNotificationMenuItems());
+ for (int i = 0; i < mMenuItems.size(); i++) {
+ final View v = createMenuView(mMenuItems.get(i));
+ mMenuItems.get(i).menuView = v;
+ }
+ resetState(notify);
+ }
+
+ private View createMenuView(MenuItem item) {
+ AlphaOptimizedImageView iv = new AlphaOptimizedImageView(getContext());
+ addView(iv);
+ iv.setPadding(mIconPadding, mIconPadding, mIconPadding, mIconPadding);
+ iv.setImageDrawable(item.icon);
+ iv.setOnClickListener(this);
+ iv.setColorFilter(mIconTint);
+ iv.setAlpha(mAlpha);
+ FrameLayout.LayoutParams lp = (LayoutParams) iv.getLayoutParams();
+ lp.width = (int) mHorizSpaceForIcon;
+ lp.height = (int) mHorizSpaceForIcon;
+ return iv;
+ }
+
+ public void resetState(boolean notify) {
+ setMenuAlpha(0f);
+ mIconsPlaced = false;
+ mMenuFadedIn = false;
+ mAnimating = false;
+ mSnapping = false;
+ mDismissing = false;
+ setMenuLocation(mOnLeft ? 1 : -1 /* on left */);
+ if (mListener != null && notify) {
+ mListener.onMenuReset(mParent);
+ }
+ }
+
+ public void setMenuClickListener(OnMenuClickListener listener) {
+ mListener = listener;
+ }
+
+ public void setNotificationRowParent(ExpandableNotificationRow parent) {
+ mParent = parent;
+ setMenuLocation(mOnLeft ? 1 : -1);
+ }
+
+ public void setAppName(String appName) {
+ Resources res = getResources();
+ final int count = mMenuItems.size();
+ for (int i = 0; i < count; i++) {
+ MenuItem item = mMenuItems.get(i);
+ String description = String.format(
+ res.getString(R.string.notification_menu_accessibility),
+ appName, item.menuDescription);
+ item.menuView.setContentDescription(description);
+ }
+ }
+
+ public ExpandableNotificationRow getNotificationParent() {
+ return mParent;
+ }
+
+ public void setMenuAlpha(float alpha) {
+ mAlpha = alpha;
+ if (alpha == 0) {
+ mMenuFadedIn = false; // Can fade in again once it's gone.
+ setVisibility(View.INVISIBLE);
+ } else {
+ setVisibility(View.VISIBLE);
+ }
+ final int count = getChildCount();
+ for (int i = 0; i < count; i++) {
+ getChildAt(i).setAlpha(mAlpha);
+ }
+ }
+
+ /**
+ * Returns whether the menu is displayed on the left side of the view or not.
+ */
+ public boolean isMenuOnLeft() {
+ return mOnLeft;
+ }
+
+ /**
+ * Returns the horizontal space in pixels required to display the menu.
+ */
+ public float getSpaceForMenu() {
+ return mHorizSpaceForIcon * getChildCount();
+ }
+
+ /**
+ * Indicates whether the menu is visible at 1 alpha. Does not indicate if entire view is
+ * visible.
+ */
+ public boolean isVisible() {
+ return mAlpha > 0;
+ }
+
+ public void cancelFadeAnimator() {
+ if (mFadeAnimator != null) {
+ mFadeAnimator.cancel();
+ }
+ }
+
+ public void updateMenuAlpha(final float transX, final float size) {
+ if (mAnimating || !mMenuFadedIn) {
+ // Don't adjust when animating, or if the menu hasn't been shown yet.
+ return;
+ }
+
+ final float fadeThreshold = size * 0.3f;
+ final float absTrans = Math.abs(transX);
+ float desiredAlpha = 0;
+
+ if (absTrans == 0) {
+ desiredAlpha = 0;
+ } else if (absTrans <= fadeThreshold) {
+ desiredAlpha = 1;
+ } else {
+ desiredAlpha = 1 - ((absTrans - fadeThreshold) / (size - fadeThreshold));
+ }
+ setMenuAlpha(desiredAlpha);
+ }
+
+ public void fadeInMenu(final boolean fromLeft, final float transX,
+ final float notiThreshold) {
+ if (mDismissing || mAnimating) {
+ return;
+ }
+ if (isMenuLocationChange(transX)) {
+ setMenuAlpha(0f);
+ }
+ setMenuLocation((int) transX);
+ mFadeAnimator = ValueAnimator.ofFloat(mAlpha, 1);
+ mFadeAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
+ @Override
+ public void onAnimationUpdate(ValueAnimator animation) {
+ final float absTrans = Math.abs(transX);
+
+ boolean pastGear = (fromLeft && transX <= notiThreshold)
+ || (!fromLeft && absTrans <= notiThreshold);
+ if (pastGear && !mMenuFadedIn) {
+ setMenuAlpha((float) animation.getAnimatedValue());
+ }
+ }
+ });
+ mFadeAnimator.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationStart(Animator animation) {
+ mAnimating = true;
+ }
+
+ @Override
+ public void onAnimationCancel(Animator animation) {
+ // TODO should animate back to 0f from current alpha
+ setMenuAlpha(0f);
+ }
+
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ mAnimating = false;
+ mMenuFadedIn = mAlpha == 1;
+ }
+ });
+ mFadeAnimator.setInterpolator(Interpolators.ALPHA_IN);
+ mFadeAnimator.setDuration(ICON_ALPHA_ANIM_DURATION);
+ mFadeAnimator.start();
+ }
+
+ public void updateVerticalLocation() {
+ if (mParent == null || mMenuItems.size() == 0) {
+ return;
+ }
+ int parentHeight = mParent.getCollapsedHeight();
+ float translationY;
+ if (parentHeight < mVertSpaceForIcons) {
+ translationY = (parentHeight / 2) - (mHorizSpaceForIcon / 2);
+ } else {
+ translationY = (mVertSpaceForIcons - mHorizSpaceForIcon) / 2;
+ }
+ setTranslationY(translationY);
+ }
+
+ @Override
+ public void onRtlPropertiesChanged(int layoutDirection) {
+ mIconsPlaced = false;
+ setMenuLocation(mOnLeft ? 1 : -1);
+ }
+
+ public void setMenuLocation(int translation) {
+ boolean onLeft = translation > 0;
+ if ((mIconsPlaced && onLeft == mOnLeft) || mSnapping || mParent == null) {
+ // Do nothing
+ return;
+ }
+ final boolean isRtl = mParent.isLayoutRtl();
+ final int count = getChildCount();
+ final int width = getWidth();
+ for (int i = 0; i < count; i++) {
+ final View v = getChildAt(i);
+ final float left = isRtl
+ ? -(width - mHorizSpaceForIcon * (i + 1))
+ : i * mHorizSpaceForIcon;
+ final float right = isRtl
+ ? -i * mHorizSpaceForIcon
+ : width - (mHorizSpaceForIcon * (i + 1));
+ v.setTranslationX(onLeft ? left : right);
+ }
+ mOnLeft = onLeft;
+ mIconsPlaced = true;
+ }
+
+ public boolean isMenuLocationChange(float translation) {
+ boolean onLeft = translation > mIconPadding;
+ boolean onRight = translation < -mIconPadding;
+ if ((mOnLeft && onRight) || (!mOnLeft && onLeft)) {
+ return true;
+ }
+ return false;
+ }
+
+ public void setDismissing() {
+ mDismissing = true;
+ }
+
+ public void setSnapping(boolean snapping) {
+ mSnapping = snapping;
+ }
+
+ @Override
+ public void onClick(View v) {
+ if (mListener == null) {
+ // Nothing to do
+ return;
+ }
+ v.getLocationOnScreen(mIconLocation);
+ mParent.getLocationOnScreen(mParentLocation);
+ final int centerX = (int) (mHorizSpaceForIcon / 2);
+ final int centerY = (int) (v.getTranslationY() * 2 + v.getHeight()) / 2;
+ final int x = mIconLocation[0] - mParentLocation[0] + centerX;
+ final int y = mIconLocation[1] - mParentLocation[1] + centerY;
+ final int index = indexOfChild(v);
+ mListener.onMenuClicked(mParent, x, y, mMenuItems.get(index));
+ }
+
+ @Override
+ public void onPluginConnected(NotificationMenuRowProvider plugin, Context pluginContext) {
+ mMenuProvider = plugin;
+ updateMenu(false /* notify */);
+ }
+
+ @Override
+ public void onPluginDisconnected(NotificationMenuRowProvider plugin) {
+ mMenuProvider = null;
+ updateMenu(false /* notify */);
+ }
+} \ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationSettingsIconRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationSettingsIconRow.java
deleted file mode 100644
index 431564723992..000000000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationSettingsIconRow.java
+++ /dev/null
@@ -1,300 +0,0 @@
-/*
- * Copyright (C) 2016 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.statusbar;
-
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
-import android.animation.ValueAnimator;
-import android.content.Context;
-import android.content.res.Resources;
-import android.util.AttributeSet;
-import android.view.View;
-import android.widget.FrameLayout;
-
-import com.android.systemui.Interpolators;
-import com.android.systemui.R;
-
-public class NotificationSettingsIconRow extends FrameLayout implements View.OnClickListener {
-
- private static final int GEAR_ALPHA_ANIM_DURATION = 200;
-
- public interface SettingsIconRowListener {
- /**
- * Called when the gear behind a notification is touched.
- */
- public void onGearTouched(ExpandableNotificationRow row, int x, int y);
-
- /**
- * Called when a notification is slid back over the gear.
- */
- public void onSettingsIconRowReset(ExpandableNotificationRow row);
- }
-
- private ExpandableNotificationRow mParent;
- private AlphaOptimizedImageView mGearIcon;
- private float mHorizSpaceForGear;
- private SettingsIconRowListener mListener;
-
- private ValueAnimator mFadeAnimator;
- private boolean mSettingsFadedIn = false;
- private boolean mAnimating = false;
- private boolean mOnLeft = true;
- private boolean mDismissing = false;
- private boolean mSnapping = false;
- private boolean mIconPlaced = false;
-
- private int[] mGearLocation = new int[2];
- private int[] mParentLocation = new int[2];
- private int mVertSpaceForGear;
-
- public NotificationSettingsIconRow(Context context) {
- this(context, null);
- }
-
- public NotificationSettingsIconRow(Context context, AttributeSet attrs) {
- this(context, attrs, 0);
- }
-
- public NotificationSettingsIconRow(Context context, AttributeSet attrs, int defStyleAttr) {
- this(context, attrs, defStyleAttr, 0);
- }
-
- public NotificationSettingsIconRow(Context context, AttributeSet attrs, int defStyleAttr,
- int defStyleRes) {
- super(context, attrs);
- }
-
- @Override
- protected void onFinishInflate() {
- super.onFinishInflate();
- mGearIcon = (AlphaOptimizedImageView) findViewById(R.id.gear_icon);
- mGearIcon.setOnClickListener(this);
- setOnClickListener(this);
- mHorizSpaceForGear =
- getResources().getDimensionPixelOffset(R.dimen.notification_gear_width);
- mVertSpaceForGear = getResources().getDimensionPixelOffset(R.dimen.notification_min_height);
- resetState();
- }
-
- public void resetState() {
- setGearAlpha(0f);
- mIconPlaced = false;
- mSettingsFadedIn = false;
- mAnimating = false;
- mSnapping = false;
- mDismissing = false;
- setIconLocation(true /* on left */);
- if (mListener != null) {
- mListener.onSettingsIconRowReset(mParent);
- }
- }
-
- public void setGearListener(SettingsIconRowListener listener) {
- mListener = listener;
- }
-
- public void setNotificationRowParent(ExpandableNotificationRow parent) {
- mParent = parent;
- setIconLocation(mOnLeft);
- }
-
- public void setAppName(String appName) {
- Resources res = getResources();
- String description = String.format(res.getString(R.string.notification_gear_accessibility),
- appName);
- mGearIcon.setContentDescription(description);
- }
-
- public ExpandableNotificationRow getNotificationParent() {
- return mParent;
- }
-
- public void setGearAlpha(float alpha) {
- if (alpha == 0) {
- mSettingsFadedIn = false; // Can fade in again once it's gone.
- setVisibility(View.INVISIBLE);
- } else {
- setVisibility(View.VISIBLE);
- }
- mGearIcon.setAlpha(alpha);
- }
-
- /**
- * Returns whether the icon is on the left side of the view or not.
- */
- public boolean isIconOnLeft() {
- return mOnLeft;
- }
-
- /**
- * Returns the horizontal space in pixels required to display the gear behind a notification.
- */
- public float getSpaceForGear() {
- return mHorizSpaceForGear;
- }
-
- /**
- * Indicates whether the gear is visible at 1 alpha. Does not indicate
- * if entire view is visible.
- */
- public boolean isVisible() {
- return mGearIcon.getAlpha() > 0;
- }
-
- public void cancelFadeAnimator() {
- if (mFadeAnimator != null) {
- mFadeAnimator.cancel();
- }
- }
-
- public void updateSettingsIcons(final float transX, final float size) {
- if (mAnimating || !mSettingsFadedIn) {
- // Don't adjust when animating, or if the gear hasn't been shown yet.
- return;
- }
-
- final float fadeThreshold = size * 0.3f;
- final float absTrans = Math.abs(transX);
- float desiredAlpha = 0;
-
- if (absTrans == 0) {
- desiredAlpha = 0;
- } else if (absTrans <= fadeThreshold) {
- desiredAlpha = 1;
- } else {
- desiredAlpha = 1 - ((absTrans - fadeThreshold) / (size - fadeThreshold));
- }
- setGearAlpha(desiredAlpha);
- }
-
- public void fadeInSettings(final boolean fromLeft, final float transX,
- final float notiThreshold) {
- if (mDismissing || mAnimating) {
- return;
- }
- if (isIconLocationChange(transX)) {
- setGearAlpha(0f);
- }
- setIconLocation(transX > 0 /* fromLeft */);
- mFadeAnimator = ValueAnimator.ofFloat(mGearIcon.getAlpha(), 1);
- mFadeAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
- @Override
- public void onAnimationUpdate(ValueAnimator animation) {
- final float absTrans = Math.abs(transX);
-
- boolean pastGear = (fromLeft && transX <= notiThreshold)
- || (!fromLeft && absTrans <= notiThreshold);
- if (pastGear && !mSettingsFadedIn) {
- setGearAlpha((float) animation.getAnimatedValue());
- }
- }
- });
- mFadeAnimator.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationStart(Animator animation) {
- mAnimating = true;
- }
-
- @Override
- public void onAnimationCancel(Animator animation) {
- // TODO should animate back to 0f from current alpha
- mGearIcon.setAlpha(0f);
- }
-
- @Override
- public void onAnimationEnd(Animator animation) {
- mAnimating = false;
- mSettingsFadedIn = mGearIcon.getAlpha() == 1;
- }
- });
- mFadeAnimator.setInterpolator(Interpolators.ALPHA_IN);
- mFadeAnimator.setDuration(GEAR_ALPHA_ANIM_DURATION);
- mFadeAnimator.start();
- }
-
- public void updateVerticalLocation() {
- if (mParent == null) {
- return;
- }
- int parentHeight = mParent.getCollapsedHeight();
- if (parentHeight < mVertSpaceForGear) {
- mGearIcon.setTranslationY((parentHeight / 2) - (mGearIcon.getHeight() / 2));
- } else {
- mGearIcon.setTranslationY((mVertSpaceForGear - mGearIcon.getHeight()) / 2);
- }
- }
-
- @Override
- public void onRtlPropertiesChanged(int layoutDirection) {
- setIconLocation(mOnLeft);
- }
-
- public void setIconLocation(boolean onLeft) {
- if ((mIconPlaced && onLeft == mOnLeft) || mSnapping || mParent == null
- || mGearIcon.getWidth() == 0) {
- // Do nothing
- return;
- }
- final boolean isRtl = mParent.isLayoutRtl();
- final float left = isRtl
- ? -(mParent.getWidth() - mHorizSpaceForGear)
- : 0;
- final float right = isRtl
- ? 0
- : mParent.getWidth() - mHorizSpaceForGear;
- final float centerX = ((mHorizSpaceForGear - mGearIcon.getWidth()) / 2);
- setTranslationX(onLeft ? left + centerX : right + centerX);
- mOnLeft = onLeft;
- mIconPlaced = true;
- }
-
- public boolean isIconLocationChange(float translation) {
- boolean onLeft = translation > mGearIcon.getPaddingStart();
- boolean onRight = translation < -mGearIcon.getPaddingStart();
- if ((mOnLeft && onRight) || (!mOnLeft && onLeft)) {
- return true;
- }
- return false;
- }
-
- public void setDismissing() {
- mDismissing = true;
- }
-
- public void setSnapping(boolean snapping) {
- mSnapping = snapping;
- }
-
- @Override
- public void onClick(View v) {
- if (v.getId() == R.id.gear_icon) {
- if (mListener != null) {
- mGearIcon.getLocationOnScreen(mGearLocation);
- mParent.getLocationOnScreen(mParentLocation);
-
- final int centerX = (int) (mHorizSpaceForGear / 2);
- final int centerY =
- (int) (mGearIcon.getTranslationY() * 2 + mGearIcon.getHeight())/ 2;
- final int x = mGearLocation[0] - mParentLocation[0] + centerX;
- final int y = mGearLocation[1] - mParentLocation[1] + centerY;
- mListener.onGearTouched(mParent, x, y);
- }
- } else {
- // Do nothing when the background is touched.
- }
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationSnooze.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationSnooze.java
new file mode 100644
index 000000000000..670d73efcbee
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationSnooze.java
@@ -0,0 +1,176 @@
+package com.android.systemui.statusbar;
+/*
+ * Copyright (C) 2017 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
+ */
+
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.concurrent.TimeUnit;
+
+import com.android.systemui.plugins.statusbar.NotificationMenuRowProvider;
+import com.android.systemui.plugins.statusbar.NotificationMenuRowProvider.GutsInteractionListener;
+import com.android.systemui.plugins.statusbar.NotificationMenuRowProvider.SnoozeListener;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.Color;
+import android.service.notification.StatusBarNotification;
+import android.util.AttributeSet;
+import android.util.TypedValue;
+import android.view.ContextThemeWrapper;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.RadioGroup;
+import android.widget.RadioGroup.OnCheckedChangeListener;
+import android.widget.TextView;
+import android.widget.Toast;
+import com.android.systemui.R;
+
+public class NotificationSnooze extends LinearLayout
+ implements NotificationMenuRowProvider.SnoozeGutsContent, View.OnClickListener {
+
+ private GutsInteractionListener mGutsInteractionListener;
+ private SnoozeListener mSnoozeListener;
+ private StatusBarNotification mSbn;
+
+ private TextView mSelectedOption;
+ private TextView mUndo;
+ private ViewGroup mSnoozeOptionView;
+
+ private long mTimeToSnooze;
+
+ // Default is the first option in this list
+ private static final int[] SNOOZE_OPTIONS = {
+ R.string.snooze_option_15_min, R.string.snooze_option_30_min,
+ R.string.snooze_option_1_hour
+ };
+
+ public NotificationSnooze(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ @Override
+ protected void onFinishInflate() {
+ super.onFinishInflate();
+ // Create the different options based on list
+ createOptionViews();
+
+ // Snackbar
+ mSelectedOption = (TextView) findViewById(R.id.snooze_option_default);
+ mSelectedOption.setOnClickListener(this);
+ mUndo = (TextView) findViewById(R.id.undo);
+ mUndo.setOnClickListener(this);
+
+ // Default to first option in list
+ setTimeToSnooze(SNOOZE_OPTIONS[0]);
+ }
+
+ private void createOptionViews() {
+ mSnoozeOptionView = (ViewGroup) findViewById(R.id.snooze_options);
+ mSnoozeOptionView.setVisibility(View.GONE);
+ final Resources res = getResources();
+ final int textSize = res.getDimensionPixelSize(R.dimen.snooze_option_text_size);
+ final int p = res.getDimensionPixelSize(R.dimen.snooze_option_padding);
+ for (int i = 0; i < SNOOZE_OPTIONS.length; i++) {
+ TextView tv = new TextView(getContext());
+ tv.setTextColor(Color.WHITE);
+ tv.setTextSize(TypedValue.COMPLEX_UNIT_PX, textSize);
+ tv.setPadding(p, p, p, p);
+ mSnoozeOptionView.addView(tv);
+ tv.setText(SNOOZE_OPTIONS[i]);
+ tv.setTag(SNOOZE_OPTIONS[i]);
+ tv.setOnClickListener(this);
+ }
+ }
+
+ private void showSnoozeOptions(boolean show) {
+ mSelectedOption.setVisibility(show ? View.GONE : View.VISIBLE);
+ mUndo.setVisibility(show ? View.GONE : View.VISIBLE);
+ mSnoozeOptionView.setVisibility(show ? View.VISIBLE : View.GONE);
+ }
+
+ private void setTimeToSnooze(int optionId) {
+ long snoozeUntilMillis = Calendar.getInstance().getTimeInMillis();
+ switch (optionId) {
+ case R.string.snooze_option_15_min:
+ snoozeUntilMillis += TimeUnit.MINUTES.toMillis(15);
+ break;
+ case R.string.snooze_option_30_min:
+ snoozeUntilMillis += TimeUnit.MINUTES.toMillis(30);
+ break;
+ case R.string.snooze_option_1_hour:
+ snoozeUntilMillis += TimeUnit.MINUTES.toMillis(60);
+ break;
+ }
+ mTimeToSnooze = snoozeUntilMillis;
+ final Resources res = getResources();
+ String selectedString = String.format(
+ res.getString(R.string.snoozed_for_time), res.getString(optionId));
+ mSelectedOption.setText(selectedString);
+ showSnoozeOptions(false);
+ }
+
+ @Override
+ public void onClick(View v) {
+ if (mGutsInteractionListener != null) {
+ mGutsInteractionListener.onInteraction(this);
+ }
+ final int id = v.getId();
+ final Integer tag = (Integer) v.getTag();
+ if (tag != null) {
+ // From the option list
+ setTimeToSnooze(tag);
+ } else if (id == R.id.snooze_option_default) {
+ // Show more snooze options
+ showSnoozeOptions(true);
+ } else if (id == R.id.undo) {
+ mTimeToSnooze = -1;
+ mGutsInteractionListener.closeGuts(this);
+ }
+ }
+
+ @Override
+ public View getContentView() {
+ return this;
+ }
+
+ @Override
+ public void setStatusBarNotification(StatusBarNotification sbn) {
+ mSbn = sbn;
+ }
+
+ @Override
+ public void setInteractionListener(GutsInteractionListener listener) {
+ mGutsInteractionListener = listener;
+ }
+
+ @Override
+ public void setSnoozeListener(SnoozeListener listener) {
+ mSnoozeListener = listener;
+ }
+
+ @Override
+ public boolean handleCloseControls() {
+ // When snooze is closed (i.e. there was interaction outside of the notification)
+ // then we commit the snooze action.
+ if (mSnoozeListener != null && mTimeToSnooze != -1) {
+ mSnoozeListener.snoozeNotification(mSbn, mTimeToSnooze);
+ return true;
+ }
+ return false;
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
index 8dcc693a6c14..7d824772b26d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -141,6 +141,7 @@ import com.android.systemui.keyguard.KeyguardViewMediator;
import com.android.systemui.plugins.qs.QS;
import com.android.systemui.ActivityStarter;
import com.android.systemui.plugins.qs.QS.BaseStatusBarHeader;
+import com.android.systemui.plugins.statusbar.NotificationMenuRowProvider.SnoozeListener;
import com.android.systemui.qs.QSFragment;
import com.android.systemui.qs.QSPanel;
import com.android.systemui.recents.ScreenPinningRequest;
@@ -205,7 +206,7 @@ import java.util.Map;
public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
DragDownHelper.DragDownCallback, ActivityStarter, OnUnlockMethodChangedListener,
- OnHeadsUpChangedListener, VisualStabilityManager.Callback {
+ OnHeadsUpChangedListener, VisualStabilityManager.Callback, SnoozeListener {
static final String TAG = "PhoneStatusBar";
public static final boolean DEBUG = BaseStatusBar.DEBUG;
public static final boolean SPEW = false;
@@ -4858,4 +4859,14 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
}
}
+
+ @Override
+ public SnoozeListener getSnoozeListener() {
+ return this;
+ }
+
+ @Override
+ public void snoozeNotification(StatusBarNotification sbn, long snoozeUntil) {
+ setNotificationSnoozed(sbn, snoozeUntil);
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
index 395e8f2a1d56..b5ec398ffdd7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
@@ -63,14 +63,15 @@ import com.android.systemui.Interpolators;
import com.android.systemui.R;
import com.android.systemui.SwipeHelper;
import com.android.systemui.classifier.FalsingManager;
+import com.android.systemui.plugins.statusbar.NotificationMenuRowProvider;
+import com.android.systemui.plugins.statusbar.NotificationMenuRowProvider.MenuItem;
import com.android.systemui.statusbar.ActivatableNotificationView;
import com.android.systemui.statusbar.DismissView;
import com.android.systemui.statusbar.EmptyShadeView;
import com.android.systemui.statusbar.ExpandableNotificationRow;
import com.android.systemui.statusbar.ExpandableView;
import com.android.systemui.statusbar.NotificationGuts;
-import com.android.systemui.statusbar.NotificationSettingsIconRow;
-import com.android.systemui.statusbar.NotificationSettingsIconRow.SettingsIconRowListener;
+import com.android.systemui.statusbar.NotificationMenuRow;
import com.android.systemui.statusbar.NotificationShelf;
import com.android.systemui.statusbar.StackScrollerDecorView;
import com.android.systemui.statusbar.StatusBarState;
@@ -94,7 +95,8 @@ import java.util.HashSet;
public class NotificationStackScrollLayout extends ViewGroup
implements SwipeHelper.Callback, ExpandHelper.Callback, ScrollAdapter,
ExpandableView.OnHeightChangedListener, NotificationGroupManager.OnGroupChangeListener,
- SettingsIconRowListener, ScrollContainer, VisibilityLocationProvider {
+ NotificationMenuRowProvider.OnMenuClickListener, ScrollContainer,
+ VisibilityLocationProvider {
public static final float BACKGROUND_ALPHA_DIMMED = 0.7f;
private static final String TAG = "StackScroller";
@@ -224,7 +226,7 @@ public class NotificationStackScrollLayout extends ViewGroup
private int mMaxScrollAfterExpand;
private SwipeHelper.LongPressListener mLongPressListener;
- private NotificationSettingsIconRow mCurrIconRow;
+ private NotificationMenuRow mCurrIconRow;
private View mTranslatingParentView;
private View mGearExposedView;
@@ -399,16 +401,20 @@ public class NotificationStackScrollLayout extends ViewGroup
}
@Override
- public void onGearTouched(ExpandableNotificationRow row, int x, int y) {
- if (mLongPressListener != null) {
+ public void onMenuClicked(View view, int x, int y, MenuItem item) {
+ if (mLongPressListener == null) {
+ return;
+ }
+ if (view instanceof ExpandableNotificationRow) {
+ ExpandableNotificationRow row = (ExpandableNotificationRow) view;
MetricsLogger.action(mContext, MetricsEvent.ACTION_TOUCH_GEAR,
row.getStatusBarNotification().getPackageName());
- mLongPressListener.onLongPress(row, x, y);
}
+ mLongPressListener.onLongPress(view, x, y, item);
}
@Override
- public void onSettingsIconRowReset(ExpandableNotificationRow row) {
+ public void onMenuReset(View row) {
if (mTranslatingParentView != null && row == mTranslatingParentView) {
mSwipeHelper.setSnappedToGear(false);
mGearExposedView = null;
@@ -425,7 +431,7 @@ public class NotificationStackScrollLayout extends ViewGroup
if (DEBUG) {
int y = mTopPadding;
canvas.drawLine(0, y, getWidth(), y, mDebugPaint);
- y = (int) getLayoutHeight();
+ y = getLayoutHeight();
canvas.drawLine(0, y, getWidth(), y, mDebugPaint);
y = getHeight() - getEmptyBottomMargin();
canvas.drawLine(0, y, getWidth(), y, mDebugPaint);
@@ -911,7 +917,7 @@ public class NotificationStackScrollLayout extends ViewGroup
mDragAnimPendingChildren.remove(animView);
}
if (mCurrIconRow != null && targetLeft == 0) {
- mCurrIconRow.resetState();
+ mCurrIconRow.resetState(true /* notify */);
mCurrIconRow = null;
}
}
@@ -4121,7 +4127,7 @@ public class NotificationStackScrollLayout extends ViewGroup
if (currView instanceof ExpandableNotificationRow) {
// Set the listener for the current row's gear
mCurrIconRow = ((ExpandableNotificationRow) currView).getSettingsRow();
- mCurrIconRow.setGearListener(NotificationStackScrollLayout.this);
+ mCurrIconRow.setMenuClickListener(NotificationStackScrollLayout.this);
}
}
@@ -4133,9 +4139,9 @@ public class NotificationStackScrollLayout extends ViewGroup
mCurrIconRow.setSnapping(false); // If we're moving, we're not snapping.
// If the gear is visible and the movement is towards it it's not a location change.
- boolean onLeft = mGearSnappedTo ? mGearSnappedOnLeft : mCurrIconRow.isIconOnLeft();
+ boolean onLeft = mGearSnappedTo ? mGearSnappedOnLeft : mCurrIconRow.isMenuOnLeft();
boolean locationChange = isTowardsGear(translation, onLeft)
- ? false : mCurrIconRow.isIconLocationChange(translation);
+ ? false : mCurrIconRow.isMenuLocationChange(translation);
if (locationChange) {
// Don't consider it "snapped" if location has changed.
setSnappedToGear(false);
@@ -4146,8 +4152,8 @@ public class NotificationStackScrollLayout extends ViewGroup
mCheckForDrag = null;
} else {
// Check scheduled, reset alpha and update location; check will fade it in
- mCurrIconRow.setGearAlpha(0f);
- mCurrIconRow.setIconLocation(translation > 0 /* onLeft */);
+ mCurrIconRow.setMenuAlpha(0f);
+ mCurrIconRow.setMenuLocation((int) translation);
}
}
}
@@ -4198,14 +4204,14 @@ public class NotificationStackScrollLayout extends ViewGroup
return false; // Let SwipeHelper handle it.
}
- boolean gestureTowardsGear = isTowardsGear(velocity, mCurrIconRow.isIconOnLeft());
+ boolean gestureTowardsGear = isTowardsGear(velocity, mCurrIconRow.isMenuOnLeft());
boolean gestureFastEnough = Math.abs(velocity) > getEscapeVelocity();
final double timeForGesture = ev.getEventTime() - ev.getDownTime();
final boolean showGearForSlowOnGoing = !canChildBeDismissed(animView)
&& timeForGesture >= SWIPE_GEAR_TIMING;
if (mGearSnappedTo && mCurrIconRow.isVisible()) {
- if (mGearSnappedOnLeft == mCurrIconRow.isIconOnLeft()) {
+ if (mGearSnappedOnLeft == mCurrIconRow.isMenuOnLeft()) {
boolean coveringGear =
Math.abs(getTranslation(animView)) <= getSpaceForGear(animView) * 0.6f;
if (gestureTowardsGear || coveringGear) {
@@ -4249,7 +4255,7 @@ public class NotificationStackScrollLayout extends ViewGroup
private void snapToGear(View animView, float velocity) {
final float snapBackThreshold = getSpaceForGear(animView);
- final float target = mCurrIconRow.isIconOnLeft() ? snapBackThreshold
+ final float target = mCurrIconRow.isMenuOnLeft() ? snapBackThreshold
: -snapBackThreshold;
mGearExposedView = mTranslatingParentView;
if (animView instanceof ExpandableNotificationRow) {
@@ -4280,7 +4286,7 @@ public class NotificationStackScrollLayout extends ViewGroup
final float multiplier = canChildBeDismissed(animView) ? 0.4f : 0.2f;
final float snapBackThreshold = getSpaceForGear(animView) * multiplier;
final float translation = getTranslation(animView);
- return !swipedFarEnough() && mCurrIconRow.isVisible() && (mCurrIconRow.isIconOnLeft()
+ return !swipedFarEnough() && mCurrIconRow.isVisible() && (mCurrIconRow.isMenuOnLeft()
? translation > snapBackThreshold
: translation < -snapBackThreshold);
}
@@ -4349,7 +4355,7 @@ public class NotificationStackScrollLayout extends ViewGroup
* Indicates the the gear has been snapped to.
*/
private void setSnappedToGear(boolean snapped) {
- mGearSnappedOnLeft = (mCurrIconRow != null) ? mCurrIconRow.isIconOnLeft() : false;
+ mGearSnappedOnLeft = (mCurrIconRow != null) ? mCurrIconRow.isMenuOnLeft() : false;
mGearSnappedTo = snapped && mCurrIconRow != null;
}
@@ -4389,11 +4395,11 @@ public class NotificationStackScrollLayout extends ViewGroup
final float bounceBackToGearWidth = getSpaceForGear(mTranslatingParentView);
final float notiThreshold = getSize(mTranslatingParentView) * 0.4f;
if ((mCurrIconRow != null && (!mCurrIconRow.isVisible()
- || mCurrIconRow.isIconLocationChange(translation)))
+ || mCurrIconRow.isMenuLocationChange(translation)))
&& absTransX >= bounceBackToGearWidth * 0.4
&& absTransX < notiThreshold) {
// Fade in the gear
- mCurrIconRow.fadeInSettings(translation > 0 /* fromLeft */, translation,
+ mCurrIconRow.fadeInMenu(translation > 0 /* fromLeft */, translation,
notiThreshold);
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationGutsTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationGutsTest.java
index cac0806e0f15..166fcb1e8a6a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationGutsTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationGutsTest.java
@@ -63,7 +63,7 @@ public class NotificationGutsTest {
private static final String TEST_CHANNEL = "test_channel";
private static final String TEST_CHANNEL_NAME = "TEST CHANNEL NAME";
- private NotificationGuts mNotificationGuts;
+ private NotificationInfo mNotificationInfo;
private final INotificationManager mMockINotificationManager = mock(INotificationManager.class);
private final PackageManager mMockPackageManager = mock(PackageManager.class);
private NotificationChannel mNotificationChannel;
@@ -76,7 +76,7 @@ public class NotificationGutsTest {
// Inflate the layout
final LayoutInflater layoutInflater =
LayoutInflater.from(InstrumentationRegistry.getTargetContext());
- mNotificationGuts = (NotificationGuts) layoutInflater.inflate(R.layout.notification_guts,
+ mNotificationInfo = (NotificationInfo) layoutInflater.inflate(R.layout.notification_info,
null);
// PackageManager must return a packageInfo and applicationInfo.
@@ -98,18 +98,18 @@ public class NotificationGutsTest {
@UiThreadTest
public void testBindNotification_SetsTextApplicationName() throws Exception {
when(mMockPackageManager.getApplicationLabel(any())).thenReturn("App Name");
- mNotificationGuts.bindNotification(mMockPackageManager, mMockINotificationManager,
+ mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
mMockStatusBarNotification, mNotificationChannel, null, null, null);
- final TextView textView = (TextView) mNotificationGuts.findViewById(R.id.pkgname);
+ final TextView textView = (TextView) mNotificationInfo.findViewById(R.id.pkgname);
assertTrue(textView.getText().toString().contains("App Name"));
}
@Test
@UiThreadTest
public void testBindNotification_SetsTextChannelName() throws Exception {
- mNotificationGuts.bindNotification(mMockPackageManager, mMockINotificationManager,
+ mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
mMockStatusBarNotification, mNotificationChannel, null, null, null);
- final TextView textView = (TextView) mNotificationGuts.findViewById(R.id.channel_name);
+ final TextView textView = (TextView) mNotificationInfo.findViewById(R.id.channel_name);
assertEquals(TEST_CHANNEL_NAME, textView.getText());
}
@@ -117,12 +117,12 @@ public class NotificationGutsTest {
@UiThreadTest
public void testBindNotification_SetsOnClickListenerForSettings() throws Exception {
final CountDownLatch latch = new CountDownLatch(1);
- mNotificationGuts.bindNotification(mMockPackageManager, mMockINotificationManager,
+ mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
mMockStatusBarNotification, mNotificationChannel,
(View v, int appUid) -> { latch.countDown(); }, null, null);
- final TextView settingsButton =
- (TextView) mNotificationGuts.findViewById(R.id.more_settings);
+ final TextView settingsButton =
+ (TextView) mNotificationInfo.findViewById(R.id.more_settings);
settingsButton.performClick();
// Verify that listener was triggered.
assertEquals(0, latch.getCount());
@@ -132,12 +132,12 @@ public class NotificationGutsTest {
@UiThreadTest
public void testBindNotification_SetsOnClickListenerForDone() throws Exception {
final CountDownLatch latch = new CountDownLatch(1);
- mNotificationGuts.bindNotification(mMockPackageManager, mMockINotificationManager,
+ mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
mMockStatusBarNotification, mNotificationChannel, null,
(View v) -> { latch.countDown(); },
null);
- final TextView doneButton = (TextView) mNotificationGuts.findViewById(R.id.done);
+ final TextView doneButton = (TextView) mNotificationInfo.findViewById(R.id.done);
doneButton.performClick();
// Verify that listener was triggered.
assertEquals(0, latch.getCount());
@@ -146,38 +146,38 @@ public class NotificationGutsTest {
@Test
@UiThreadTest
public void testHasImportanceChanged_DefaultsToFalse() throws Exception {
- mNotificationGuts.bindNotification(mMockPackageManager, mMockINotificationManager,
+ mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
mMockStatusBarNotification, mNotificationChannel, null, null, null);
- assertFalse(mNotificationGuts.hasImportanceChanged());
+ assertFalse(mNotificationInfo.hasImportanceChanged());
}
@Test
@UiThreadTest
public void testHasImportanceChanged_ReturnsTrueAfterButtonChecked() throws Exception {
mNotificationChannel.setImportance(NotificationManager.IMPORTANCE_LOW);
- mNotificationGuts.bindNotification(mMockPackageManager, mMockINotificationManager,
+ mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
mMockStatusBarNotification, mNotificationChannel, null, null, null);
// Find the high button and check it.
- RadioButton highButton = (RadioButton) mNotificationGuts.findViewById(R.id.high_importance);
+ RadioButton highButton = (RadioButton) mNotificationInfo.findViewById(R.id.high_importance);
highButton.setChecked(true);
- assertTrue(mNotificationGuts.hasImportanceChanged());
+ assertTrue(mNotificationInfo.hasImportanceChanged());
}
@Test
@UiThreadTest
public void testImportanceButtonCheckedBasedOnInitialImportance() throws Exception {
mNotificationChannel.setImportance(NotificationManager.IMPORTANCE_HIGH);
- mNotificationGuts.bindNotification(mMockPackageManager, mMockINotificationManager,
+ mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
mMockStatusBarNotification, mNotificationChannel, null, null, null);
- RadioButton highButton = (RadioButton) mNotificationGuts.findViewById(R.id.high_importance);
+ RadioButton highButton = (RadioButton) mNotificationInfo.findViewById(R.id.high_importance);
assertTrue(highButton.isChecked());
}
@Test
@UiThreadTest
public void testBindNotification_DoesNotUpdateNotificationChannel() throws Exception {
- mNotificationGuts.bindNotification(mMockPackageManager, mMockINotificationManager,
+ mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
mMockStatusBarNotification, mNotificationChannel, null, null, null);
verify(mMockINotificationManager, never()).updateNotificationChannelForPackage(
anyString(), anyInt(), any());
@@ -187,10 +187,10 @@ public class NotificationGutsTest {
@UiThreadTest
public void testDoesNotUpdateNotificationChannelAfterImportanceChanged() throws Exception {
mNotificationChannel.setImportance(NotificationManager.IMPORTANCE_LOW);
- mNotificationGuts.bindNotification(mMockPackageManager, mMockINotificationManager,
+ mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
mMockStatusBarNotification, mNotificationChannel, null, null, null);
- RadioButton highButton = (RadioButton) mNotificationGuts.findViewById(R.id.high_importance);
+ RadioButton highButton = (RadioButton) mNotificationInfo.findViewById(R.id.high_importance);
highButton.setChecked(true);
verify(mMockINotificationManager, never()).updateNotificationChannelForPackage(
anyString(), anyInt(), any());
@@ -199,10 +199,10 @@ public class NotificationGutsTest {
@Test
@UiThreadTest
public void testCloseControls_DoesNotUpdateNotificationChannelIfUnchanged() throws Exception {
- mNotificationGuts.bindNotification(mMockPackageManager, mMockINotificationManager,
+ mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
mMockStatusBarNotification, mNotificationChannel, null, null, null);
- mNotificationGuts.closeControls(-1, -1, true);
+ mNotificationInfo.closeControls();
verify(mMockINotificationManager, never()).updateNotificationChannelForPackage(
anyString(), anyInt(), any());
}
@@ -211,10 +211,10 @@ public class NotificationGutsTest {
@UiThreadTest
public void testCloseControls_DoesNotUpdateNotificationChannelIfUnspecified() throws Exception {
mNotificationChannel.setImportance(NotificationManager.IMPORTANCE_UNSPECIFIED);
- mNotificationGuts.bindNotification(mMockPackageManager, mMockINotificationManager,
+ mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
mMockStatusBarNotification, mNotificationChannel, null, null, null);
- mNotificationGuts.closeControls(-1, -1, true);
+ mNotificationInfo.closeControls();
verify(mMockINotificationManager, never()).updateNotificationChannelForPackage(
anyString(), anyInt(), any());
}
@@ -223,12 +223,12 @@ public class NotificationGutsTest {
@UiThreadTest
public void testCloseControls_CallsUpdateNotificationChannelIfChanged() throws Exception {
mNotificationChannel.setImportance(NotificationManager.IMPORTANCE_LOW);
- mNotificationGuts.bindNotification(mMockPackageManager, mMockINotificationManager,
+ mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
mMockStatusBarNotification, mNotificationChannel, null, null, null);
- RadioButton highButton = (RadioButton) mNotificationGuts.findViewById(R.id.high_importance);
+ RadioButton highButton = (RadioButton) mNotificationInfo.findViewById(R.id.high_importance);
highButton.setChecked(true);
- mNotificationGuts.closeControls(-1, -1, true);
+ mNotificationInfo.closeControls();
verify(mMockINotificationManager, times(1)).updateNotificationChannelForPackage(
eq(TEST_PACKAGE_NAME), anyInt(), eq(mNotificationChannel));
assertEquals(NotificationManager.IMPORTANCE_HIGH, mNotificationChannel.getImportance());
@@ -238,12 +238,12 @@ public class NotificationGutsTest {
@UiThreadTest
public void testCloseControls_DoesNotUpdateNotificationChannelIfSaveFalse() throws Exception {
mNotificationChannel.setImportance(NotificationManager.IMPORTANCE_LOW);
- mNotificationGuts.bindNotification(mMockPackageManager, mMockINotificationManager,
+ mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
mMockStatusBarNotification, mNotificationChannel, null, null, null);
- RadioButton highButton = (RadioButton) mNotificationGuts.findViewById(R.id.high_importance);
+ RadioButton highButton = (RadioButton) mNotificationInfo.findViewById(R.id.high_importance);
highButton.setChecked(true);
- mNotificationGuts.closeControls(-1, -1, false);
+ mNotificationInfo.closeControls();
verify(mMockINotificationManager, never()).updateNotificationChannelForPackage(
anyString(), anyInt(), any());
}
@@ -252,10 +252,10 @@ public class NotificationGutsTest {
@UiThreadTest
public void testEnabledSwitchOnByDefault() throws Exception {
mNotificationChannel.setImportance(NotificationManager.IMPORTANCE_LOW);
- mNotificationGuts.bindNotification(mMockPackageManager, mMockINotificationManager,
+ mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
mMockStatusBarNotification, mNotificationChannel, null, null, null);
- Switch enabledSwitch = (Switch) mNotificationGuts.findViewById(R.id.channel_enabled_switch);
+ Switch enabledSwitch = (Switch) mNotificationInfo.findViewById(R.id.channel_enabled_switch);
assertTrue(enabledSwitch.isChecked());
}
@@ -263,10 +263,10 @@ public class NotificationGutsTest {
@UiThreadTest
public void testEnabledSwitchVisibleByDefault() throws Exception {
mNotificationChannel.setImportance(NotificationManager.IMPORTANCE_LOW);
- mNotificationGuts.bindNotification(mMockPackageManager, mMockINotificationManager,
+ mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
mMockStatusBarNotification, mNotificationChannel, null, null, null);
- Switch enabledSwitch = (Switch) mNotificationGuts.findViewById(R.id.channel_enabled_switch);
+ Switch enabledSwitch = (Switch) mNotificationInfo.findViewById(R.id.channel_enabled_switch);
assertEquals(View.VISIBLE, enabledSwitch.getVisibility());
}
@@ -274,11 +274,11 @@ public class NotificationGutsTest {
@UiThreadTest
public void testEnabledSwitchInvisibleIfNonBlockable() throws Exception {
mNotificationChannel.setImportance(NotificationManager.IMPORTANCE_LOW);
- mNotificationGuts.bindNotification(mMockPackageManager, mMockINotificationManager,
+ mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
mMockStatusBarNotification, mNotificationChannel, null, null,
Collections.singleton(TEST_PACKAGE_NAME));
- Switch enabledSwitch = (Switch) mNotificationGuts.findViewById(R.id.channel_enabled_switch);
+ Switch enabledSwitch = (Switch) mNotificationInfo.findViewById(R.id.channel_enabled_switch);
assertEquals(View.INVISIBLE, enabledSwitch.getVisibility());
}
@@ -286,13 +286,13 @@ public class NotificationGutsTest {
@UiThreadTest
public void testEnabledSwitchChangedCallsUpdateNotificationChannel() throws Exception {
mNotificationChannel.setImportance(NotificationManager.IMPORTANCE_LOW);
- mNotificationGuts.bindNotification(mMockPackageManager, mMockINotificationManager,
+ mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
mMockStatusBarNotification, mNotificationChannel, null, null,
Collections.singleton(TEST_PACKAGE_NAME));
- Switch enabledSwitch = (Switch) mNotificationGuts.findViewById(R.id.channel_enabled_switch);
+ Switch enabledSwitch = (Switch) mNotificationInfo.findViewById(R.id.channel_enabled_switch);
enabledSwitch.setChecked(false);
- mNotificationGuts.closeControls(-1, -1, true);
+ mNotificationInfo.closeControls();
verify(mMockINotificationManager, times(1)).updateNotificationChannelForPackage(
eq(TEST_PACKAGE_NAME), anyInt(), eq(mNotificationChannel));
}
@@ -301,14 +301,14 @@ public class NotificationGutsTest {
@UiThreadTest
public void testEnabledSwitchOverridesOtherButtons() throws Exception {
mNotificationChannel.setImportance(NotificationManager.IMPORTANCE_LOW);
- mNotificationGuts.bindNotification(mMockPackageManager, mMockINotificationManager,
+ mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
mMockStatusBarNotification, mNotificationChannel, null, null, null);
- Switch enabledSwitch = (Switch) mNotificationGuts.findViewById(R.id.channel_enabled_switch);
- RadioButton lowButton = (RadioButton) mNotificationGuts.findViewById(R.id.low_importance);
+ Switch enabledSwitch = (Switch) mNotificationInfo.findViewById(R.id.channel_enabled_switch);
+ RadioButton lowButton = (RadioButton) mNotificationInfo.findViewById(R.id.low_importance);
lowButton.setChecked(true);
enabledSwitch.setChecked(false);
- mNotificationGuts.closeControls(-1, -1, true);
+ mNotificationInfo.closeControls();
assertEquals(NotificationManager.IMPORTANCE_NONE, mNotificationChannel.getImportance());
}
}