Merge "Add screen for notification history"
This commit is contained in:
committed by
Android (Google) Code Review
commit
63bbda167f
@@ -1193,6 +1193,15 @@
|
|||||||
android:value="com.android.settings.notification.history.NotificationStation" />
|
android:value="com.android.settings.notification.history.NotificationStation" />
|
||||||
</activity>
|
</activity>
|
||||||
|
|
||||||
|
<activity
|
||||||
|
android:name=".notification.history.NotificationHistoryActivity"
|
||||||
|
android:label="@string/notification_history_title">
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.intent.action.MAIN" />
|
||||||
|
<category android:name="android.intent.category.DEFAULT" />
|
||||||
|
</intent-filter>
|
||||||
|
</activity>
|
||||||
|
|
||||||
<activity android:name=".notification.zen.ZenModeVoiceActivity"
|
<activity android:name=".notification.zen.ZenModeVoiceActivity"
|
||||||
android:theme="@*android:style/Theme.DeviceDefault.Settings.Dialog.NoActionBar"
|
android:theme="@*android:style/Theme.DeviceDefault.Settings.Dialog.NoActionBar"
|
||||||
android:label="@string/zen_mode_settings_title">
|
android:label="@string/zen_mode_settings_title">
|
||||||
|
26
res/drawable/ic_clear.xml
Normal file
26
res/drawable/ic_clear.xml
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!--
|
||||||
|
Copyright (C) 2020 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.
|
||||||
|
-->
|
||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:viewportWidth="24"
|
||||||
|
android:viewportHeight="24"
|
||||||
|
android:width="24dp"
|
||||||
|
android:height="24dp">
|
||||||
|
<path
|
||||||
|
android:pathData="M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12Z"
|
||||||
|
android:fillColor="#FFFFFF" />
|
||||||
|
</vector>
|
||||||
|
|
24
res/drawable/ic_snooze.xml
Normal file
24
res/drawable/ic_snooze.xml
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
<!--
|
||||||
|
Copyright (C) 2020 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
|
||||||
|
-->
|
||||||
|
<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:fillColor="@android:color/white"
|
||||||
|
android:pathData="M9,11h3.63L9,15.2L9,17h6v-2h-3.63L15,10.8L15,9L9,9v2zM16.056,3.346l1.282,-1.535 4.607,3.85 -1.28,1.54zM3.336,7.19l-1.28,-1.536L6.662,1.81l1.28,1.536zM12,6c3.86,0 7,3.14 7,7s-3.14,7 -7,7 -7,-3.14 -7,-7 3.14,-7 7,-7m0,-2c-4.97,0 -9,4.03 -9,9s4.03,9 9,9 9,-4.03 9,-9 -4.03,-9 -9,-9z"/>
|
||||||
|
</vector>
|
24
res/drawable/ic_today.xml
Normal file
24
res/drawable/ic_today.xml
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
<!--
|
||||||
|
Copyright (C) 2020 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.
|
||||||
|
-->
|
||||||
|
<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:fillColor="@android:color/white"
|
||||||
|
android:pathData="M19,3h-1L18,1h-2v2L8,3L8,1L6,1v2L5,3c-1.11,0 -2,0.9 -2,2v14c0,1.1 0.89,2 2,2h14c1.1,0 2,-0.9 2,-2L21,5c0,-1.1 -0.9,-2 -2,-2zM19,19L5,19L5,8h14v11zM9,9.5c-1.38,0 -2.5,1.12 -2.5,2.5s1.12,2.5 2.5,2.5 2.5,-1.12 2.5,-2.5S10.38,9.5 9,9.5z"/>
|
||||||
|
</vector>
|
26
res/drawable/rounded_bg.xml
Normal file
26
res/drawable/rounded_bg.xml
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!--
|
||||||
|
Copyright (C) 2020 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.
|
||||||
|
-->
|
||||||
|
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:shape="rectangle">
|
||||||
|
<solid android:color="?android:attr/colorBackgroundFloating" />
|
||||||
|
<corners
|
||||||
|
android:bottomLeftRadius="?android:attr/dialogCornerRadius"
|
||||||
|
android:topLeftRadius="?android:attr/dialogCornerRadius"
|
||||||
|
android:bottomRightRadius="?android:attr/dialogCornerRadius"
|
||||||
|
android:topRightRadius="?android:attr/dialogCornerRadius"
|
||||||
|
/>
|
||||||
|
</shape>
|
161
res/layout/notification_history.xml
Normal file
161
res/layout/notification_history.xml
Normal file
@@ -0,0 +1,161 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Copyright (C) 2020 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.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<ScrollView
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:settings="http://schemas.android.com/apk/res-auto"
|
||||||
|
android:id="@+id/scroll"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:padding="16dp"
|
||||||
|
android:background="@*android:color/material_grey_50">
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<!-- TODO: header switch -->
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/snoozed_list"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:layout_marginBottom="10dp">
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/snooze_header"
|
||||||
|
android:layout_height="48dp"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:gravity="center_vertical"
|
||||||
|
android:orientation="horizontal">
|
||||||
|
<ImageView
|
||||||
|
android:src="@drawable/ic_snooze"
|
||||||
|
android:tint="?android:attr/textColorPrimary"
|
||||||
|
android:padding="6dp"
|
||||||
|
android:layout_height="36dp"
|
||||||
|
android:layout_width="36dp" />
|
||||||
|
<TextView
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:text="@string/notification_history_snooze"
|
||||||
|
android:textColor="?android:attr/textColorPrimary"
|
||||||
|
android:paddingStart="@dimen/notification_history_header_drawable_start" />
|
||||||
|
</LinearLayout>
|
||||||
|
<FrameLayout
|
||||||
|
android:id="@+id/list_container"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="300dp"
|
||||||
|
android:clipChildren="true"
|
||||||
|
android:elevation="3dp"
|
||||||
|
android:background="@drawable/rounded_bg">
|
||||||
|
|
||||||
|
<androidx.recyclerview.widget.RecyclerView
|
||||||
|
android:id="@+id/notification_list"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:clipChildren="true"
|
||||||
|
settings:fastScrollEnabled="true"
|
||||||
|
settings:fastScrollHorizontalThumbDrawable="@drawable/thumb_drawable"
|
||||||
|
settings:fastScrollHorizontalTrackDrawable="@drawable/line_drawable"
|
||||||
|
settings:fastScrollVerticalThumbDrawable="@drawable/thumb_drawable"
|
||||||
|
settings:fastScrollVerticalTrackDrawable="@drawable/line_drawable"/>
|
||||||
|
|
||||||
|
</FrameLayout>
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/recently_dismissed_list"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:layout_marginBottom="10dp">
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/dismissed_header"
|
||||||
|
android:layout_height="48dp"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:gravity="center_vertical"
|
||||||
|
android:orientation="horizontal">
|
||||||
|
<ImageView
|
||||||
|
android:src="@drawable/ic_clear"
|
||||||
|
android:tint="?android:attr/textColorPrimary"
|
||||||
|
android:padding="6dp"
|
||||||
|
android:layout_height="36dp"
|
||||||
|
android:layout_width="36dp" />
|
||||||
|
<TextView
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:text="@string/notification_history_dismiss"
|
||||||
|
android:textColor="?android:attr/textColorPrimary"
|
||||||
|
android:paddingStart="@dimen/notification_history_header_drawable_start" />
|
||||||
|
</LinearLayout>
|
||||||
|
<FrameLayout
|
||||||
|
android:id="@+id/list_container"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="300dp"
|
||||||
|
android:elevation="3dp"
|
||||||
|
android:clipChildren="true"
|
||||||
|
android:background="@drawable/rounded_bg">
|
||||||
|
|
||||||
|
<androidx.recyclerview.widget.RecyclerView
|
||||||
|
android:id="@+id/notification_list"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:clipChildren="true"
|
||||||
|
settings:fastScrollEnabled="true"
|
||||||
|
settings:fastScrollHorizontalThumbDrawable="@drawable/thumb_drawable"
|
||||||
|
settings:fastScrollHorizontalTrackDrawable="@drawable/line_drawable"
|
||||||
|
settings:fastScrollVerticalThumbDrawable="@drawable/thumb_drawable"
|
||||||
|
settings:fastScrollVerticalTrackDrawable="@drawable/line_drawable"/>
|
||||||
|
|
||||||
|
</FrameLayout>
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/today_list"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical">
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/app_header"
|
||||||
|
android:layout_height="48dp"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:gravity="center_vertical"
|
||||||
|
android:orientation="horizontal">
|
||||||
|
<ImageView
|
||||||
|
android:src="@drawable/ic_today"
|
||||||
|
android:tint="?android:attr/textColorPrimary"
|
||||||
|
android:padding="6dp"
|
||||||
|
android:layout_height="36dp"
|
||||||
|
android:layout_width="36dp" />
|
||||||
|
<TextView
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:text="@string/notification_history_today"
|
||||||
|
android:textColor="?android:attr/textColorPrimary"
|
||||||
|
android:paddingStart="@dimen/notification_history_header_drawable_start" />
|
||||||
|
</LinearLayout>
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/apps"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:elevation="3dp"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:background="@drawable/rounded_bg">
|
||||||
|
<!-- app based recycler views added here -->
|
||||||
|
</LinearLayout>
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
</ScrollView>
|
77
res/layout/notification_history_app_layout.xml
Normal file
77
res/layout/notification_history_app_layout.xml
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Copyright (C) 2020 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.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:settings="http://schemas.android.com/apk/res-auto"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<RelativeLayout
|
||||||
|
android:id="@+id/app_header"
|
||||||
|
android:layout_height="48dp"
|
||||||
|
android:layout_width="match_parent">
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/icon"
|
||||||
|
android:padding="6dp"
|
||||||
|
android:layout_centerVertical="true"
|
||||||
|
android:layout_height="36dp"
|
||||||
|
android:layout_width="36dp" />
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/label"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_centerVertical="true"
|
||||||
|
|
||||||
|
android:textColor="@color/material_grey_900"
|
||||||
|
android:layout_toEndOf="@id/icon"
|
||||||
|
android:paddingStart="@dimen/notification_history_header_drawable_start" />
|
||||||
|
<ImageButton
|
||||||
|
android:id="@+id/expand"
|
||||||
|
android:layout_alignParentEnd="true"
|
||||||
|
android:layout_centerVertical="true"
|
||||||
|
android:layout_height="48dp"
|
||||||
|
android:layout_width="48dp"
|
||||||
|
android:src="@*android:drawable/ic_expand_more"/>
|
||||||
|
</RelativeLayout>
|
||||||
|
|
||||||
|
<FrameLayout
|
||||||
|
android:id="@+id/list_container"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:clipChildren="true"
|
||||||
|
android:layout_height="300dp">
|
||||||
|
|
||||||
|
<androidx.recyclerview.widget.RecyclerView
|
||||||
|
android:id="@+id/notification_list"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:clipChildren="true"
|
||||||
|
settings:fastScrollEnabled="true"
|
||||||
|
settings:fastScrollHorizontalThumbDrawable="@drawable/thumb_drawable"
|
||||||
|
settings:fastScrollHorizontalTrackDrawable="@drawable/line_drawable"
|
||||||
|
settings:fastScrollVerticalThumbDrawable="@drawable/thumb_drawable"
|
||||||
|
settings:fastScrollVerticalTrackDrawable="@drawable/line_drawable"/>
|
||||||
|
|
||||||
|
</FrameLayout>
|
||||||
|
|
||||||
|
<View
|
||||||
|
android:id="@+id/divider"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="0.5dp"
|
||||||
|
android:background="@color/material_grey_300" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
93
res/layout/notification_history_log_row.xml
Normal file
93
res/layout/notification_history_log_row.xml
Normal file
@@ -0,0 +1,93 @@
|
|||||||
|
<!--
|
||||||
|
Copyright (C) 2020 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.
|
||||||
|
-->
|
||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:paddingBottom="6dp"
|
||||||
|
android:paddingTop="6dp"
|
||||||
|
android:paddingStart="?android:attr/listPreferredItemPaddingStart"
|
||||||
|
android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:background="?android:attr/selectableItemBackground">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:layout_marginBottom="6dp">
|
||||||
|
<RelativeLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="@*android:dimen/status_bar_icon_size"
|
||||||
|
android:gravity="center_vertical">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/title"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_centerVertical="true"
|
||||||
|
android:ellipsize="end"
|
||||||
|
android:singleLine="true"
|
||||||
|
android:textAppearance="?android:attr/textAppearanceSmall"
|
||||||
|
android:textColor="@color/material_grey_900"
|
||||||
|
android:textAlignment="viewStart"/>
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/alerted_icon"
|
||||||
|
android:layout_width="@*android:dimen/status_bar_icon_size"
|
||||||
|
android:layout_height="@*android:dimen/status_bar_icon_size"
|
||||||
|
android:layout_centerVertical="true"
|
||||||
|
android:layout_marginStart="6dp"
|
||||||
|
android:paddingTop="1dp"
|
||||||
|
android:scaleType="fitCenter"
|
||||||
|
android:visibility="gone"
|
||||||
|
android:layout_toEndOf="@id/title"
|
||||||
|
android:tint="?android:attr/textColorSecondary"
|
||||||
|
android:src="@drawable/ic_notifications_alert"/>
|
||||||
|
|
||||||
|
<DateTimeView
|
||||||
|
android:id="@+id/timestamp"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_alignParentEnd="true"
|
||||||
|
android:layout_centerVertical="true"
|
||||||
|
android:ellipsize="end"
|
||||||
|
android:singleLine="true"
|
||||||
|
android:textColor="?android:attr/textColorPrimary"
|
||||||
|
android:textAppearance="?android:attr/textAppearanceSmall"
|
||||||
|
android:textAlignment="viewEnd"
|
||||||
|
/>
|
||||||
|
</RelativeLayout>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/text"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="left|center_vertical"
|
||||||
|
android:ellipsize="end"
|
||||||
|
android:singleLine="true"
|
||||||
|
android:textColor="?android:attr/textColorPrimary"
|
||||||
|
android:textAppearance="?android:attr/textAppearanceSmall"
|
||||||
|
android:textAlignment="viewStart" />
|
||||||
|
|
||||||
|
<View
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="0.5dp"
|
||||||
|
android:layout_marginTop="17dp"
|
||||||
|
android:background="@color/material_grey_300" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</LinearLayout>
|
142
res/layout/notification_sbn_log_row.xml
Normal file
142
res/layout/notification_sbn_log_row.xml
Normal file
@@ -0,0 +1,142 @@
|
|||||||
|
<!--
|
||||||
|
Copyright (C) 2020 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.
|
||||||
|
-->
|
||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:paddingBottom="6dp"
|
||||||
|
android:paddingTop="6dp"
|
||||||
|
android:paddingStart="?android:attr/listPreferredItemPaddingStart"
|
||||||
|
android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:background="?android:attr/selectableItemBackground"
|
||||||
|
>
|
||||||
|
|
||||||
|
<RelativeLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
>
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/icon"
|
||||||
|
android:layout_width="@*android:dimen/status_bar_icon_size"
|
||||||
|
android:layout_height="@*android:dimen/status_bar_icon_size"
|
||||||
|
android:layout_centerVertical="true"
|
||||||
|
android:layout_toEndOf="@+id/pkgicon"
|
||||||
|
android:layout_marginStart="0dp"
|
||||||
|
android:layout_marginEnd="8dp"
|
||||||
|
android:contentDescription="@null"
|
||||||
|
android:adjustViewBounds="true"
|
||||||
|
android:tint="?android:attr/textColorPrimary"
|
||||||
|
android:maxHeight="@*android:dimen/status_bar_icon_size"
|
||||||
|
android:maxWidth="@*android:dimen/status_bar_icon_size"
|
||||||
|
android:scaleType="fitCenter" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/pkgname"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_centerVertical="true"
|
||||||
|
android:layout_toEndOf="@id/icon"
|
||||||
|
android:ellipsize="end"
|
||||||
|
android:singleLine="true"
|
||||||
|
android:textColor="?android:attr/textColorPrimary"
|
||||||
|
android:textAppearance="?android:attr/textAppearanceSmall"
|
||||||
|
android:textStyle="bold"
|
||||||
|
android:textAlignment="viewStart" />
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/alerted_icon"
|
||||||
|
android:layout_width="@*android:dimen/status_bar_icon_size"
|
||||||
|
android:layout_height="@*android:dimen/status_bar_icon_size"
|
||||||
|
android:layout_centerVertical="true"
|
||||||
|
android:layout_marginStart="6dp"
|
||||||
|
android:paddingTop="1dp"
|
||||||
|
android:scaleType="fitCenter"
|
||||||
|
android:visibility="gone"
|
||||||
|
android:layout_toEndOf="@id/pkgname"
|
||||||
|
android:tint="?android:attr/textColorSecondary"
|
||||||
|
android:src="@drawable/ic_notifications_alert"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/profile_badge"
|
||||||
|
android:layout_width="@*android:dimen/status_bar_icon_size"
|
||||||
|
android:layout_height="@*android:dimen/status_bar_icon_size"
|
||||||
|
android:layout_centerVertical="true"
|
||||||
|
android:layout_marginEnd="6dp"
|
||||||
|
android:paddingTop="1dp"
|
||||||
|
android:scaleType="fitCenter"
|
||||||
|
android:visibility="gone"
|
||||||
|
android:layout_toStartOf="@id/timestamp"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<DateTimeView
|
||||||
|
android:id="@+id/timestamp"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:paddingTop="13dp"
|
||||||
|
android:paddingBottom="13dp"
|
||||||
|
android:layout_alignBottom="@android:id/widget_frame"
|
||||||
|
android:layout_alignParentEnd="true"
|
||||||
|
android:layout_alignTop="@android:id/widget_frame"
|
||||||
|
android:layout_centerVertical="true"
|
||||||
|
android:ellipsize="end"
|
||||||
|
android:singleLine="true"
|
||||||
|
android:textColor="?android:attr/textColorPrimary"
|
||||||
|
android:textAppearance="?android:attr/textAppearanceSmall"
|
||||||
|
android:textAlignment="viewEnd"
|
||||||
|
/>
|
||||||
|
</RelativeLayout>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:layout_marginStart="30dp"
|
||||||
|
android:layout_marginBottom="6dp"
|
||||||
|
>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/title"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="left|center_vertical"
|
||||||
|
android:ellipsize="end"
|
||||||
|
android:singleLine="true"
|
||||||
|
android:textColor="?android:attr/textColorPrimary"
|
||||||
|
android:textAlignment="viewStart"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/text"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="left|center_vertical"
|
||||||
|
android:ellipsize="end"
|
||||||
|
android:singleLine="true"
|
||||||
|
android:textColor="?android:attr/textColorPrimary"
|
||||||
|
android:textAppearance="?android:attr/textAppearanceSmall"
|
||||||
|
android:textAlignment="viewStart"
|
||||||
|
/>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<View
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="0.5dp"
|
||||||
|
android:layout_marginTop="17dp"
|
||||||
|
android:background="@color/material_grey_300" />
|
||||||
|
</LinearLayout>
|
@@ -81,6 +81,8 @@
|
|||||||
<dimen name="notification_importance_button_text">16sp</dimen>
|
<dimen name="notification_importance_button_text">16sp</dimen>
|
||||||
<dimen name="notification_importance_button_padding">14dp</dimen>
|
<dimen name="notification_importance_button_padding">14dp</dimen>
|
||||||
|
|
||||||
|
<dimen name="notification_history_header_drawable_start">26dp</dimen>
|
||||||
|
|
||||||
<dimen name="zen_mode_button_padding_vertical">16dp</dimen>
|
<dimen name="zen_mode_button_padding_vertical">16dp</dimen>
|
||||||
<dimen name="zen_schedule_rule_checkbox_padding">7dp</dimen>
|
<dimen name="zen_schedule_rule_checkbox_padding">7dp</dimen>
|
||||||
<dimen name="zen_schedule_day_margin">17dp</dimen>
|
<dimen name="zen_schedule_day_margin">17dp</dimen>
|
||||||
|
@@ -6163,6 +6163,11 @@
|
|||||||
<string name="admin_more_details">More details</string>
|
<string name="admin_more_details">More details</string>
|
||||||
<string name="notification_log_title">Notification log</string>
|
<string name="notification_log_title">Notification log</string>
|
||||||
|
|
||||||
|
<string name="notification_history_title">Notification history</string>
|
||||||
|
<string name="notification_history_today">Today</string>
|
||||||
|
<string name="notification_history_snooze">Snoozed</string>
|
||||||
|
<string name="notification_history_dismiss">Recently dismissed</string>
|
||||||
|
|
||||||
<!-- Category title for phone call's ringtone and vibration settings in the Sound Setting.
|
<!-- Category title for phone call's ringtone and vibration settings in the Sound Setting.
|
||||||
[CHAR LIMIT=40] -->
|
[CHAR LIMIT=40] -->
|
||||||
<string name="sound_category_call_ringtone_vibrate_title">Call ringtone & vibrate</string>
|
<string name="sound_category_call_ringtone_vibrate_title">Call ringtone & vibrate</string>
|
||||||
|
@@ -21,6 +21,7 @@ import static android.app.NotificationManager.IMPORTANCE_UNSPECIFIED;
|
|||||||
import android.app.INotificationManager;
|
import android.app.INotificationManager;
|
||||||
import android.app.NotificationChannel;
|
import android.app.NotificationChannel;
|
||||||
import android.app.NotificationChannelGroup;
|
import android.app.NotificationChannelGroup;
|
||||||
|
import android.app.NotificationHistory;
|
||||||
import android.app.role.RoleManager;
|
import android.app.role.RoleManager;
|
||||||
import android.app.usage.IUsageStatsManager;
|
import android.app.usage.IUsageStatsManager;
|
||||||
import android.app.usage.UsageEvents;
|
import android.app.usage.UsageEvents;
|
||||||
@@ -367,6 +368,15 @@ public class NotificationBackend {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public NotificationHistory getNotificationHistory(String pkg) {
|
||||||
|
try {
|
||||||
|
return sINM.getNotificationHistory(pkg);
|
||||||
|
} catch (Exception e) {
|
||||||
|
Log.w(TAG, "Error calling NoMan", e);
|
||||||
|
}
|
||||||
|
return new NotificationHistory();
|
||||||
|
}
|
||||||
|
|
||||||
protected void recordAggregatedUsageEvents(Context context, AppRow appRow) {
|
protected void recordAggregatedUsageEvents(Context context, AppRow appRow) {
|
||||||
long now = System.currentTimeMillis();
|
long now = System.currentTimeMillis();
|
||||||
long startTime = now - (DateUtils.DAY_IN_MILLIS * DAYS_TO_CHECK);
|
long startTime = now - (DateUtils.DAY_IN_MILLIS * DAYS_TO_CHECK);
|
||||||
|
@@ -0,0 +1,93 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2020 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.settings.notification.history;
|
||||||
|
|
||||||
|
import android.app.NotificationHistory;
|
||||||
|
import android.app.NotificationHistory.HistoricalNotification;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.pm.ApplicationInfo;
|
||||||
|
import android.content.pm.PackageManager;
|
||||||
|
import android.os.UserHandle;
|
||||||
|
|
||||||
|
import com.android.settings.notification.NotificationBackend;
|
||||||
|
import com.android.settingslib.utils.ThreadUtils;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public class HistoryLoader {
|
||||||
|
private final Context mContext;
|
||||||
|
private final NotificationBackend mBackend;
|
||||||
|
private final PackageManager mPm;
|
||||||
|
|
||||||
|
public HistoryLoader(Context context, NotificationBackend backend, PackageManager pm) {
|
||||||
|
mContext = context;
|
||||||
|
mBackend = backend;
|
||||||
|
mPm = pm;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void load(OnHistoryLoaderListener listener) {
|
||||||
|
ThreadUtils.postOnBackgroundThread(() -> {
|
||||||
|
Map<String, NotificationHistoryPackage> historicalNotifications = new HashMap<>();
|
||||||
|
NotificationHistory history =
|
||||||
|
mBackend.getNotificationHistory(mContext.getPackageName());
|
||||||
|
|
||||||
|
while (history.hasNextNotification()) {
|
||||||
|
HistoricalNotification hn = history.getNextNotification();
|
||||||
|
|
||||||
|
String key = hn.getPackage() + "|" + hn.getUid();
|
||||||
|
NotificationHistoryPackage hnsForPackage = historicalNotifications.getOrDefault(
|
||||||
|
key,
|
||||||
|
new NotificationHistoryPackage(hn.getPackage(), hn.getUid()));
|
||||||
|
hnsForPackage.notifications.add(hn);
|
||||||
|
historicalNotifications.put(key, hnsForPackage);
|
||||||
|
}
|
||||||
|
List<NotificationHistoryPackage> packages =
|
||||||
|
new ArrayList<>(historicalNotifications.values());
|
||||||
|
Collections.sort(packages,
|
||||||
|
(o1, o2) -> -1 * Long.compare(o1.getMostRecent(), o2.getMostRecent()));
|
||||||
|
for (NotificationHistoryPackage nhp : packages) {
|
||||||
|
ApplicationInfo info;
|
||||||
|
try {
|
||||||
|
info = mPm.getApplicationInfoAsUser(
|
||||||
|
nhp.pkgName,
|
||||||
|
PackageManager.MATCH_UNINSTALLED_PACKAGES
|
||||||
|
| PackageManager.MATCH_DISABLED_COMPONENTS
|
||||||
|
| PackageManager.MATCH_DIRECT_BOOT_UNAWARE
|
||||||
|
| PackageManager.MATCH_DIRECT_BOOT_AWARE,
|
||||||
|
UserHandle.getUserId(nhp.uid));
|
||||||
|
if (info != null) {
|
||||||
|
nhp.label = String.valueOf(mPm.getApplicationLabel(info));
|
||||||
|
nhp.icon = mPm.getUserBadgedIcon(mPm.getApplicationIcon(info),
|
||||||
|
UserHandle.of(UserHandle.getUserId(nhp.uid)));
|
||||||
|
}
|
||||||
|
} catch (PackageManager.NameNotFoundException e) {
|
||||||
|
// app is gone, just show package name and generic icon
|
||||||
|
nhp.icon = mPm.getDefaultActivityIcon();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ThreadUtils.postOnMainThread(() -> listener.onHistoryLoaded(packages));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
interface OnHistoryLoaderListener {
|
||||||
|
void onHistoryLoaded(List<NotificationHistoryPackage> notificationsByPackage);
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,156 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2020 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.settings.notification.history;
|
||||||
|
|
||||||
|
import android.app.Activity;
|
||||||
|
import android.app.ActivityManager;
|
||||||
|
import android.app.INotificationManager;
|
||||||
|
import android.content.ComponentName;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.pm.PackageManager;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.os.RemoteException;
|
||||||
|
import android.os.ServiceManager;
|
||||||
|
import android.service.notification.NotificationListenerService;
|
||||||
|
import android.service.notification.StatusBarNotification;
|
||||||
|
import android.util.Log;
|
||||||
|
import android.util.Slog;
|
||||||
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
import android.widget.ImageButton;
|
||||||
|
import android.widget.ImageView;
|
||||||
|
import android.widget.TextView;
|
||||||
|
|
||||||
|
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||||
|
import androidx.recyclerview.widget.RecyclerView;
|
||||||
|
|
||||||
|
import com.android.settings.R;
|
||||||
|
import com.android.settings.notification.NotificationBackend;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
public class NotificationHistoryActivity extends Activity {
|
||||||
|
|
||||||
|
private static String TAG = "NotifHistory";
|
||||||
|
|
||||||
|
private ViewGroup mTodayView;
|
||||||
|
private ViewGroup mSnoozeView;
|
||||||
|
private ViewGroup mDismissView;
|
||||||
|
private HistoryLoader mHistoryLoader;
|
||||||
|
private INotificationManager mNm;
|
||||||
|
private PackageManager mPm;
|
||||||
|
|
||||||
|
private HistoryLoader.OnHistoryLoaderListener mOnHistoryLoaderListener = notifications -> {
|
||||||
|
// for each package, new header and recycler view
|
||||||
|
for (NotificationHistoryPackage nhp : notifications) {
|
||||||
|
View viewForPackage = LayoutInflater.from(this)
|
||||||
|
.inflate(R.layout.notification_history_app_layout, null);
|
||||||
|
|
||||||
|
final View container = viewForPackage.findViewById(R.id.list_container);
|
||||||
|
container.setVisibility(View.GONE);
|
||||||
|
ImageButton expand = viewForPackage.findViewById(R.id.expand);
|
||||||
|
expand.setOnClickListener(v -> {
|
||||||
|
container.setVisibility(container.getVisibility() == View.VISIBLE
|
||||||
|
? View.GONE : View.VISIBLE);
|
||||||
|
expand.setImageResource(container.getVisibility() == View.VISIBLE
|
||||||
|
? R.drawable.ic_expand_less
|
||||||
|
: com.android.internal.R.drawable.ic_expand_more);
|
||||||
|
});
|
||||||
|
|
||||||
|
TextView label = viewForPackage.findViewById(R.id.label);
|
||||||
|
label.setText(nhp.label != null ? nhp.label : nhp.pkgName);
|
||||||
|
ImageView icon = viewForPackage.findViewById(R.id.icon);
|
||||||
|
icon.setImageDrawable(nhp.icon);
|
||||||
|
|
||||||
|
RecyclerView rv = viewForPackage.findViewById(R.id.notification_list);
|
||||||
|
rv.setLayoutManager(new LinearLayoutManager(this));
|
||||||
|
rv.setAdapter(new NotificationHistoryAdapter());
|
||||||
|
((NotificationHistoryAdapter) rv.getAdapter()).onRebuildComplete(nhp.notifications);
|
||||||
|
mTodayView.addView(viewForPackage);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
|
setContentView(R.layout.notification_history);
|
||||||
|
mTodayView = findViewById(R.id.apps);
|
||||||
|
mSnoozeView = findViewById(R.id.snoozed_list);
|
||||||
|
mDismissView = findViewById(R.id.recently_dismissed_list);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onResume() {
|
||||||
|
super.onResume();
|
||||||
|
|
||||||
|
mPm = getPackageManager();
|
||||||
|
|
||||||
|
mHistoryLoader = new HistoryLoader(this, new NotificationBackend(), mPm);
|
||||||
|
mHistoryLoader.load(mOnHistoryLoaderListener);
|
||||||
|
|
||||||
|
mNm = INotificationManager.Stub.asInterface(
|
||||||
|
ServiceManager.getService(Context.NOTIFICATION_SERVICE));
|
||||||
|
try {
|
||||||
|
mListener.registerAsSystemService(this, new ComponentName(getPackageName(),
|
||||||
|
this.getClass().getCanonicalName()), ActivityManager.getCurrentUser());
|
||||||
|
} catch (RemoteException e) {
|
||||||
|
Log.e(TAG, "Cannot register listener", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onPause() {
|
||||||
|
try {
|
||||||
|
mListener.unregisterAsSystemService();
|
||||||
|
} catch (RemoteException e) {
|
||||||
|
Log.e(TAG, "Cannot unregister listener", e);
|
||||||
|
}
|
||||||
|
super.onPause();
|
||||||
|
}
|
||||||
|
|
||||||
|
private final NotificationListenerService mListener = new NotificationListenerService() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onListenerConnected() {
|
||||||
|
StatusBarNotification[] snoozed = getSnoozedNotifications();
|
||||||
|
if (snoozed == null || snoozed.length == 0) {
|
||||||
|
mSnoozeView.setVisibility(View.GONE);
|
||||||
|
} else {
|
||||||
|
RecyclerView rv = mSnoozeView.findViewById(R.id.notification_list);
|
||||||
|
rv.setLayoutManager(new LinearLayoutManager(NotificationHistoryActivity.this));
|
||||||
|
rv.setAdapter(new NotificationSbnAdapter(NotificationHistoryActivity.this, mPm));
|
||||||
|
((NotificationSbnAdapter) rv.getAdapter()).onRebuildComplete(
|
||||||
|
Arrays.asList(snoozed));
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
StatusBarNotification[] dismissed = mNm.getHistoricalNotifications(
|
||||||
|
NotificationHistoryActivity.this.getPackageName(), 10);
|
||||||
|
RecyclerView rv = mDismissView.findViewById(R.id.notification_list);
|
||||||
|
rv.setLayoutManager(new LinearLayoutManager(NotificationHistoryActivity.this));
|
||||||
|
rv.setAdapter(new NotificationSbnAdapter(NotificationHistoryActivity.this, mPm));
|
||||||
|
((NotificationSbnAdapter) rv.getAdapter()).onRebuildComplete(
|
||||||
|
Arrays.asList(dismissed));
|
||||||
|
mDismissView.setVisibility(View.VISIBLE);
|
||||||
|
} catch (Exception e) {
|
||||||
|
Slog.e(TAG, "Cannot load recently dismissed", e);
|
||||||
|
mDismissView.setVisibility(View.GONE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
@@ -0,0 +1,78 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2020 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.settings.notification.history;
|
||||||
|
|
||||||
|
import android.app.NotificationHistory;
|
||||||
|
import android.app.NotificationHistory.HistoricalNotification;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.graphics.drawable.Drawable;
|
||||||
|
import android.os.UserHandle;
|
||||||
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.recyclerview.widget.RecyclerView;
|
||||||
|
|
||||||
|
import com.android.settings.R;
|
||||||
|
import com.android.settings.notification.NotificationBackend;
|
||||||
|
import com.android.settingslib.utils.ThreadUtils;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Comparator;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.TreeMap;
|
||||||
|
|
||||||
|
public class NotificationHistoryAdapter extends
|
||||||
|
RecyclerView.Adapter<NotificationHistoryViewHolder> {
|
||||||
|
|
||||||
|
private List<HistoricalNotification> mValues;
|
||||||
|
|
||||||
|
public NotificationHistoryAdapter() {
|
||||||
|
mValues = new ArrayList<>();
|
||||||
|
setHasStableIds(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public NotificationHistoryViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
|
||||||
|
View view = LayoutInflater.from(parent.getContext())
|
||||||
|
.inflate(R.layout.notification_history_log_row, parent, false);
|
||||||
|
return new NotificationHistoryViewHolder(view);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onBindViewHolder(final @NonNull NotificationHistoryViewHolder holder,
|
||||||
|
int position) {
|
||||||
|
final HistoricalNotification hn = mValues.get(position);
|
||||||
|
holder.setTitle(hn.getTitle());
|
||||||
|
holder.setSummary(hn.getText());
|
||||||
|
holder.setPostedTime(hn.getPostedTimeMs());
|
||||||
|
holder.addOnClick(hn.getPackage(), hn.getUserId(), hn.getChannelId());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getItemCount() {
|
||||||
|
return mValues.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onRebuildComplete(List<HistoricalNotification> notifications) {
|
||||||
|
mValues = notifications;
|
||||||
|
notifyDataSetChanged();
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,62 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2020 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.settings.notification.history;
|
||||||
|
|
||||||
|
import android.app.NotificationHistory;
|
||||||
|
import android.graphics.drawable.Drawable;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
public class NotificationHistoryPackage {
|
||||||
|
String pkgName;
|
||||||
|
int uid;
|
||||||
|
List<NotificationHistory.HistoricalNotification> notifications;
|
||||||
|
CharSequence label;
|
||||||
|
Drawable icon;
|
||||||
|
|
||||||
|
public NotificationHistoryPackage(String pkgName, int uid) {
|
||||||
|
this.pkgName = pkgName;
|
||||||
|
this.uid = uid;
|
||||||
|
notifications = new ArrayList<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getMostRecent() {
|
||||||
|
if (notifications.isEmpty()) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return notifications.get(0).getPostedTimeMs();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if (this == o) return true;
|
||||||
|
if (o == null || getClass() != o.getClass()) return false;
|
||||||
|
NotificationHistoryPackage that = (NotificationHistoryPackage) o;
|
||||||
|
return uid == that.uid &&
|
||||||
|
Objects.equals(pkgName, that.pkgName) &&
|
||||||
|
Objects.equals(notifications, that.notifications) &&
|
||||||
|
Objects.equals(label, that.label) &&
|
||||||
|
Objects.equals(icon, that.icon);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return Objects.hash(pkgName, uid, notifications, label, icon);
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,70 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2020 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.settings.notification.history;
|
||||||
|
|
||||||
|
import static android.provider.Settings.EXTRA_APP_PACKAGE;
|
||||||
|
import static android.provider.Settings.EXTRA_CHANNEL_ID;
|
||||||
|
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.os.UserHandle;
|
||||||
|
import android.provider.Settings;
|
||||||
|
import android.view.View;
|
||||||
|
import android.widget.DateTimeView;
|
||||||
|
import android.widget.TextView;
|
||||||
|
|
||||||
|
import androidx.recyclerview.widget.RecyclerView;
|
||||||
|
|
||||||
|
import com.android.settings.R;
|
||||||
|
|
||||||
|
public class NotificationHistoryViewHolder extends RecyclerView.ViewHolder {
|
||||||
|
|
||||||
|
private final DateTimeView mTime;
|
||||||
|
private final TextView mTitle;
|
||||||
|
private final TextView mSummary;
|
||||||
|
|
||||||
|
NotificationHistoryViewHolder(View itemView) {
|
||||||
|
super(itemView);
|
||||||
|
mTime = itemView.findViewById(R.id.timestamp);
|
||||||
|
mTime.setShowRelativeTime(true);
|
||||||
|
mTitle = itemView.findViewById(R.id.title);
|
||||||
|
mSummary = itemView.findViewById(R.id.text);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setSummary(CharSequence summary) {
|
||||||
|
mSummary.setText(summary);
|
||||||
|
mSummary.setVisibility(summary != null ? View.VISIBLE : View.GONE);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setTitle(CharSequence title) {
|
||||||
|
mTitle.setText(title);
|
||||||
|
mTitle.setVisibility(title != null ? View.VISIBLE : View.GONE);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setPostedTime(long postedTime) {
|
||||||
|
mTime.setTime(postedTime);
|
||||||
|
}
|
||||||
|
|
||||||
|
void addOnClick(String pkg, int userId, String channelId) {
|
||||||
|
itemView.setOnClickListener(v -> {
|
||||||
|
Intent intent = new Intent(Settings.ACTION_CHANNEL_NOTIFICATION_SETTINGS)
|
||||||
|
.putExtra(EXTRA_APP_PACKAGE, pkg)
|
||||||
|
.putExtra(EXTRA_CHANNEL_ID, channelId);
|
||||||
|
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||||
|
itemView.getContext().startActivityAsUser(intent, UserHandle.of(userId));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,152 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2020 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.settings.notification.history;
|
||||||
|
|
||||||
|
import static android.content.pm.PackageManager.*;
|
||||||
|
|
||||||
|
import android.app.Notification;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.pm.ApplicationInfo;
|
||||||
|
import android.content.pm.PackageManager;
|
||||||
|
import android.graphics.PorterDuff;
|
||||||
|
import android.graphics.drawable.Drawable;
|
||||||
|
import android.os.UserHandle;
|
||||||
|
import android.service.notification.StatusBarNotification;
|
||||||
|
import android.text.TextUtils;
|
||||||
|
import android.util.Log;
|
||||||
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.recyclerview.widget.RecyclerView;
|
||||||
|
|
||||||
|
import com.android.settings.R;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public class NotificationSbnAdapter extends
|
||||||
|
RecyclerView.Adapter<NotificationSbnViewHolder> {
|
||||||
|
|
||||||
|
private static final String TAG = "SbnAdapter";
|
||||||
|
private List<StatusBarNotification> mValues;
|
||||||
|
private Map<Integer, Drawable> mUserBadgeCache;
|
||||||
|
private final Context mContext;
|
||||||
|
private PackageManager mPm;
|
||||||
|
|
||||||
|
public NotificationSbnAdapter(Context context, PackageManager pm) {
|
||||||
|
mContext = context;
|
||||||
|
mPm = pm;
|
||||||
|
mUserBadgeCache = new HashMap<>();
|
||||||
|
mValues = new ArrayList<>();
|
||||||
|
setHasStableIds(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public NotificationSbnViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
|
||||||
|
View view = LayoutInflater.from(parent.getContext())
|
||||||
|
.inflate(R.layout.notification_sbn_log_row, parent, false);
|
||||||
|
return new NotificationSbnViewHolder(view);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onBindViewHolder(final @NonNull NotificationSbnViewHolder holder,
|
||||||
|
int position) {
|
||||||
|
final StatusBarNotification sbn = mValues.get(position);
|
||||||
|
holder.setIcon(loadIcon(sbn));
|
||||||
|
holder.setPackageName(loadPackageName(sbn.getPackageName()).toString());
|
||||||
|
holder.setTitle(getTitleString(sbn.getNotification()));
|
||||||
|
holder.setSummary(getTextString(mContext, sbn.getNotification()));
|
||||||
|
holder.setPostedTime(sbn.getPostTime());
|
||||||
|
if (!mUserBadgeCache.containsKey(sbn.getUserId())) {
|
||||||
|
Drawable profile = mContext.getPackageManager().getUserBadgeForDensity(
|
||||||
|
UserHandle.of(sbn.getUserId()), -1);
|
||||||
|
mUserBadgeCache.put(sbn.getUserId(), profile);
|
||||||
|
}
|
||||||
|
holder.setProfileBadge(mUserBadgeCache.get(sbn.getUserId()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getItemCount() {
|
||||||
|
return mValues.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onRebuildComplete(List<StatusBarNotification> notifications) {
|
||||||
|
mValues = notifications;
|
||||||
|
notifyDataSetChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
private @NonNull CharSequence loadPackageName(String pkg) {
|
||||||
|
try {
|
||||||
|
ApplicationInfo info = mPm.getApplicationInfo(pkg,
|
||||||
|
MATCH_ANY_USER);
|
||||||
|
if (info != null) return mPm.getApplicationLabel(info);
|
||||||
|
} catch (NameNotFoundException e) {
|
||||||
|
Log.e(TAG, "Cannot load package name", e);
|
||||||
|
}
|
||||||
|
return pkg;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String getTitleString(Notification n) {
|
||||||
|
CharSequence title = null;
|
||||||
|
if (n.extras != null) {
|
||||||
|
title = n.extras.getCharSequence(Notification.EXTRA_TITLE);
|
||||||
|
}
|
||||||
|
return title == null? null : String.valueOf(title);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the appropriate substring for this notification based on the style of notification.
|
||||||
|
*/
|
||||||
|
private static String getTextString(Context appContext, Notification n) {
|
||||||
|
CharSequence text = null;
|
||||||
|
if (n.extras != null) {
|
||||||
|
text = n.extras.getCharSequence(Notification.EXTRA_TEXT);
|
||||||
|
|
||||||
|
Notification.Builder nb = Notification.Builder.recoverBuilder(appContext, n);
|
||||||
|
|
||||||
|
if (nb.getStyle() instanceof Notification.BigTextStyle) {
|
||||||
|
text = ((Notification.BigTextStyle) nb.getStyle()).getBigText();
|
||||||
|
} else if (nb.getStyle() instanceof Notification.MessagingStyle) {
|
||||||
|
Notification.MessagingStyle ms = (Notification.MessagingStyle) nb.getStyle();
|
||||||
|
final List<Notification.MessagingStyle.Message> messages = ms.getMessages();
|
||||||
|
if (messages != null && messages.size() > 0) {
|
||||||
|
text = messages.get(messages.size() - 1).getText();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (TextUtils.isEmpty(text)) {
|
||||||
|
text = n.extras.getCharSequence(Notification.EXTRA_TEXT);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return text == null ? null : String.valueOf(text);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Drawable loadIcon(StatusBarNotification sbn) {
|
||||||
|
Drawable draw = sbn.getNotification().getSmallIcon().loadDrawableAsUser(
|
||||||
|
sbn.getPackageContext(mContext), sbn.getUserId());
|
||||||
|
if (draw == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
draw.mutate();
|
||||||
|
draw.setColorFilter(sbn.getNotification().color, PorterDuff.Mode.SRC_ATOP);
|
||||||
|
return draw;
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,77 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2020 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.settings.notification.history;
|
||||||
|
|
||||||
|
import android.graphics.drawable.Drawable;
|
||||||
|
import android.graphics.drawable.Icon;
|
||||||
|
import android.text.TextUtils;
|
||||||
|
import android.view.View;
|
||||||
|
import android.widget.DateTimeView;
|
||||||
|
import android.widget.ImageView;
|
||||||
|
import android.widget.TextView;
|
||||||
|
|
||||||
|
import androidx.recyclerview.widget.RecyclerView;
|
||||||
|
|
||||||
|
import com.android.settings.R;
|
||||||
|
|
||||||
|
public class NotificationSbnViewHolder extends RecyclerView.ViewHolder {
|
||||||
|
|
||||||
|
private final TextView mPkgName;
|
||||||
|
private final ImageView mIcon;
|
||||||
|
private final DateTimeView mTime;
|
||||||
|
private final TextView mTitle;
|
||||||
|
private final TextView mSummary;
|
||||||
|
private final ImageView mProfileBadge;
|
||||||
|
|
||||||
|
NotificationSbnViewHolder(View itemView) {
|
||||||
|
super(itemView);
|
||||||
|
mPkgName = itemView.findViewById(R.id.pkgname);
|
||||||
|
mIcon = itemView.findViewById(R.id.icon);
|
||||||
|
mTime = itemView.findViewById(R.id.timestamp);
|
||||||
|
mTitle = itemView.findViewById(R.id.title);
|
||||||
|
mSummary = itemView.findViewById(R.id.text);
|
||||||
|
mProfileBadge = itemView.findViewById(R.id.profile_badge);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setSummary(CharSequence summary) {
|
||||||
|
mSummary.setVisibility(TextUtils.isEmpty(summary) ? View.GONE : View.VISIBLE);
|
||||||
|
mSummary.setText(summary);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setTitle(CharSequence title) {
|
||||||
|
if (title == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
mTitle.setText(title);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setIcon(Drawable icon) {
|
||||||
|
mIcon.setImageDrawable(icon);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setPackageName(String pkg) {
|
||||||
|
mPkgName.setText(pkg);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setPostedTime(long postedTime) {
|
||||||
|
mTime.setTime(postedTime);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setProfileBadge(Drawable badge) {
|
||||||
|
mProfileBadge.setImageDrawable(badge);
|
||||||
|
}
|
||||||
|
}
|
Reference in New Issue
Block a user