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" />
|
||||
</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"
|
||||
android:theme="@*android:style/Theme.DeviceDefault.Settings.Dialog.NoActionBar"
|
||||
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_padding">14dp</dimen>
|
||||
|
||||
<dimen name="notification_history_header_drawable_start">26dp</dimen>
|
||||
|
||||
<dimen name="zen_mode_button_padding_vertical">16dp</dimen>
|
||||
<dimen name="zen_schedule_rule_checkbox_padding">7dp</dimen>
|
||||
<dimen name="zen_schedule_day_margin">17dp</dimen>
|
||||
|
@@ -6163,6 +6163,11 @@
|
||||
<string name="admin_more_details">More details</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.
|
||||
[CHAR LIMIT=40] -->
|
||||
<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.NotificationChannel;
|
||||
import android.app.NotificationChannelGroup;
|
||||
import android.app.NotificationHistory;
|
||||
import android.app.role.RoleManager;
|
||||
import android.app.usage.IUsageStatsManager;
|
||||
import android.app.usage.UsageEvents;
|
||||
@@ -367,6 +368,15 @@ public class NotificationBackend {
|
||||
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) {
|
||||
long now = System.currentTimeMillis();
|
||||
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