Merge "Improve notification history"

This commit is contained in:
Julia Reynolds
2020-02-11 21:54:54 +00:00
committed by Android (Google) Code Review
9 changed files with 329 additions and 142 deletions

View File

@@ -0,0 +1,25 @@
<!--
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"
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
android:pathData="M13,3c-4.76,0 -8.64,3.69 -8.97,8.37L2.21,9.54 0.8,10.95 5,15.16l4.21,-4.21 -1.42,-1.41 -1.75,1.76C6.39,7.76 9.37,5 13,5c3.87,0 7,3.13 7,7s-3.13,7 -7,7c-1.93,0 -3.68,-0.79 -4.94,-2.06l-1.42,1.42C8.27,19.99 10.51,21 13,21c4.97,0 9,-4.03 9,-9s-4.03,-9 -9,-9zM4.71,12c-0.01,0.01 -0.01,0.02 -0.02,0.03L4.66,12h0.05zM14,7h-2v5.41l3.79,3.8 1.42,-1.42 -3.21,-3.2z"/>
</vector>

View File

@@ -19,60 +19,105 @@
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:layout_height="match_parent"
android:background="@*android:color/material_grey_50">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<!-- TODO: header switch -->
<include layout="@layout/styled_switch_bar"/>
<LinearLayout
android:id="@+id/history_off"
android:visibility="gone"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="164dp"
android:orientation="vertical">
<ImageView
android:id="@+id/history_image"
android:layout_width="67dp"
android:layout_height="67dp"
android:layout_gravity="center_horizontal"
android:contentDescription="@string/notification_history"
android:scaleType="fitCenter"
android:tint="?android:attr/colorControlNormal"
android:src="@drawable/ic_history" />
<TextView
android:id="@+id/history_off_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/history_image"
android:layout_marginTop="48dp"
android:layout_marginStart="48dp"
android:layout_marginEnd="48dp"
android:layout_gravity="center_horizontal"
android:textAppearance="?android:attr/textAppearanceMedium"
android:text="@string/notification_history_off_title_extended" />
<TextView
android:id="@+id/history_off_summary"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/history_off_title"
android:layout_marginStart="48dp"
android:layout_marginEnd="48dp"
android:layout_marginTop="16dp"
android:layout_gravity="center_horizontal"
android:textAlignment="center"
android:textAppearance="?android:attr/textAppearanceSmall"
android:text="@string/notification_history_summary" />
</LinearLayout>
<LinearLayout
android:id="@+id/history_on"
android:visibility="gone"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="16dp">
<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" />
android:layout_marginBottom="28dp">
<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:textAppearance="?android:attr/textAppearanceMedium"
android:paddingBottom="16dp" />
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/list_container"
android:layout_width="wrap_content"
android:layout_height="300dp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:clipChildren="true"
android:elevation="3dp"
android:background="@drawable/rounded_bg">
android:background="@drawable/rounded_bg"
settings:layout_constraintHeight_max="200dp"
settings:layout_constrainedHeight="true">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/notification_list"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_height="0dp"
android:clipChildren="true"
settings:layout_constraintHeight_max="300dp"
settings:layout_constrainedHeight="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>
</androidx.constraintlayout.widget.ConstraintLayout>
</LinearLayout>
<LinearLayout
@@ -80,46 +125,36 @@
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" />
android:layout_marginBottom="28dp">
<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:textAppearance="?android:attr/textAppearanceMedium"
android:paddingBottom="16dp" />
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/list_container"
android:layout_width="wrap_content"
android:layout_height="300dp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
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:layout_height="0dp"
android:clipChildren="true"
settings:layout_constraintHeight_max="300dp"
settings:layout_constrainedHeight="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>
</androidx.constraintlayout.widget.ConstraintLayout>
</LinearLayout>
<LinearLayout
@@ -127,25 +162,13 @@
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>
android:textAppearance="?android:attr/textAppearanceMedium"
android:paddingBottom="16dp" />
<LinearLayout
android:id="@+id/apps"
android:layout_width="match_parent"
@@ -156,6 +179,7 @@
<!-- app based recycler views added here -->
</LinearLayout>
</LinearLayout>
</LinearLayout>
</LinearLayout>
</ScrollView>

View File

@@ -23,55 +23,76 @@
<RelativeLayout
android:id="@+id/app_header"
android:layout_height="48dp"
android:layout_width="match_parent">
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:paddingTop="12dp"
android:paddingBottom="12dp"
android:paddingStart="16dp">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal">
<ImageView
android:id="@+id/icon"
android:padding="6dp"
android:layout_centerVertical="true"
android:layout_height="36dp"
android:layout_width="36dp" />
android:layout_height="24dp"
android:layout_width="24dp"
android:layout_gravity="center_vertical"
android:scaleType="centerInside"/>
<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" />
android:layout_gravity="center_vertical"
android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Body1"
android:paddingStart="8dp" />
</LinearLayout>
<TextView
android:id="@+id/count"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:paddingStart="6dp"
android:layout_gravity="center_vertical"
android:fontFamily="sans-serif-medium"
android:paddingTop="8dp"
android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Body1"/>
</LinearLayout>
<ImageButton
android:id="@+id/expand"
android:layout_alignParentEnd="true"
android:layout_centerVertical="true"
android:layout_height="48dp"
android:layout_width="48dp"
android:background="@drawable/button_ripple_radius"
android:src="@*android:drawable/ic_expand_more"/>
</RelativeLayout>
<FrameLayout
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="?android:attr/listDivider"/>
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/list_container"
android:layout_width="match_parent"
android:clipChildren="true"
android:layout_height="300dp">
android:layout_height="wrap_content">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/notification_list"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_height="0dp"
android:clipChildren="true"
settings:layout_constraintHeight_max="300dp"
settings:layout_constrainedHeight="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" />
</androidx.constraintlayout.widget.ConstraintLayout>
</LinearLayout>

View File

@@ -40,8 +40,8 @@
android:layout_centerVertical="true"
android:ellipsize="end"
android:singleLine="true"
android:textAppearance="?android:attr/textAppearanceSmall"
android:textColor="@color/material_grey_900"
android:fontFamily="sans-serif-medium"
android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Body1"
android:textAlignment="viewStart"/>
<ImageView
@@ -78,16 +78,11 @@
android:layout_gravity="left|center_vertical"
android:ellipsize="end"
android:singleLine="true"
android:paddingTop="3dp"
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>

View File

@@ -133,10 +133,4 @@
/>
</LinearLayout>
<View
android:layout_width="match_parent"
android:layout_height="0.5dp"
android:layout_marginTop="17dp"
android:background="@color/material_grey_300" />
</LinearLayout>

View File

@@ -6189,6 +6189,12 @@
<string name="notification_history_snooze">Snoozed</string>
<string name="notification_history_dismiss">Recently dismissed</string>
<!-- app summary of notification app list screen [CHAR LIMIT=100] -->
<plurals name="notification_history_count">
<item quantity="one"><xliff:g id="number">%d</xliff:g> notification</item>
<item quantity="other"><xliff:g id="number">%d</xliff:g> notifications</item>
</plurals>
<!-- 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 &amp; vibrate</string>
@@ -8040,6 +8046,15 @@
<!-- Configure notifications: settings title [CHAR LIMIT=100] -->
<string name="notification_history">Notification history</string>
<!-- Configure notifications: settings title [CHAR LIMIT=100] -->
<string name="notification_history_turn_on">Turn on history</string>
<!-- Configure notifications: settings title [CHAR LIMIT=100] -->
<string name="notification_history_turn_off">Turn off history</string>
<!-- Notification history screen; summary when history is off [CHAR LIMIT=200] -->
<string name="notification_history_off_title_extended">Notification history is turned off</string>
<!-- Configure Notifications: setting title, whether the snooze menu is shown on notifications [CHAR LIMIT=80] -->
<string name="snooze_options_title">Allow notification snoozing</string>

View File

@@ -16,15 +16,22 @@
package com.android.settings.notification.history;
import static android.provider.Settings.Secure.NOTIFICATION_HISTORY_ENABLED;
import android.app.Activity;
import android.app.ActivityManager;
import android.app.INotificationManager;
import android.content.ComponentName;
import android.content.ContentResolver;
import android.content.Context;
import android.content.pm.PackageManager;
import android.database.ContentObserver;
import android.net.Uri;
import android.os.Bundle;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.UserHandle;
import android.provider.Settings;
import android.service.notification.NotificationListenerService;
import android.service.notification.StatusBarNotification;
import android.util.Log;
@@ -36,11 +43,13 @@ import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.TextView;
import androidx.recyclerview.widget.DividerItemDecoration;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import com.android.settings.R;
import com.android.settings.notification.NotificationBackend;
import com.android.settings.widget.SwitchBar;
import java.util.Arrays;
@@ -48,9 +57,13 @@ public class NotificationHistoryActivity extends Activity {
private static String TAG = "NotifHistory";
private ViewGroup mHistoryOn;
private ViewGroup mHistoryOff;
private ViewGroup mTodayView;
private ViewGroup mSnoozeView;
private ViewGroup mDismissView;
private SettingsObserver mSettingsObserver = new SettingsObserver();
private HistoryLoader mHistoryLoader;
private INotificationManager mNm;
private PackageManager mPm;
@@ -77,9 +90,17 @@ public class NotificationHistoryActivity extends Activity {
ImageView icon = viewForPackage.findViewById(R.id.icon);
icon.setImageDrawable(nhp.icon);
TextView count = viewForPackage.findViewById(R.id.count);
count.setText(getResources().getQuantityString(R.plurals.notification_history_count,
nhp.notifications.size(), nhp.notifications.size()));
RecyclerView rv = viewForPackage.findViewById(R.id.notification_list);
rv.setLayoutManager(new LinearLayoutManager(this));
LinearLayoutManager lm = new LinearLayoutManager(this);
rv.setLayoutManager(lm);
rv.setAdapter(new NotificationHistoryAdapter());
DividerItemDecoration dividerItemDecoration = new DividerItemDecoration(
rv.getContext(), lm.getOrientation());
rv.addItemDecoration(dividerItemDecoration);
((NotificationHistoryAdapter) rv.getAdapter()).onRebuildComplete(nhp.notifications);
mTodayView.addView(viewForPackage);
}
@@ -92,6 +113,8 @@ public class NotificationHistoryActivity extends Activity {
mTodayView = findViewById(R.id.apps);
mSnoozeView = findViewById(R.id.snoozed_list);
mDismissView = findViewById(R.id.recently_dismissed_list);
mHistoryOff = findViewById(R.id.history_off);
mHistoryOn = findViewById(R.id.history_on);
}
@Override
@@ -111,6 +134,9 @@ public class NotificationHistoryActivity extends Activity {
} catch (RemoteException e) {
Log.e(TAG, "Cannot register listener", e);
}
mSettingsObserver.observe();
bindSwitch();
}
@Override
@@ -120,9 +146,87 @@ public class NotificationHistoryActivity extends Activity {
} catch (RemoteException e) {
Log.e(TAG, "Cannot unregister listener", e);
}
mSettingsObserver.stopObserving();
super.onPause();
}
private void bindSwitch() {
SwitchBar bar = findViewById(R.id.switch_bar);
if (bar != null) {
bar.setSwitchBarText(R.string.notification_history_turn_off,
R.string.notification_history_turn_on);
bar.show();
try {
bar.addOnSwitchChangeListener(mOnSwitchClickListener);
} catch (IllegalStateException e) {
// an exception is thrown if you try to add the listener twice
}
bar.setChecked(Settings.Secure.getInt(getContentResolver(),
NOTIFICATION_HISTORY_ENABLED, 0) == 1);
toggleViews(bar.isChecked());
}
}
private void toggleViews(boolean isChecked) {
if (isChecked) {
mHistoryOff.setVisibility(View.GONE);
mHistoryOn.setVisibility(View.VISIBLE);
} else {
mHistoryOn.setVisibility(View.GONE);
mHistoryOff.setVisibility(View.VISIBLE);
mTodayView.removeAllViews();
}
}
private void onHistoryEnabledChanged(boolean enabled) {
if (enabled) {
mHistoryLoader.load(mOnHistoryLoaderListener);
}
}
final class SettingsObserver extends ContentObserver {
private final Uri NOTIFICATION_HISTORY_URI
= Settings.Secure.getUriFor(Settings.Secure.NOTIFICATION_HISTORY_ENABLED);
SettingsObserver() {
super(null);
}
void observe() {
ContentResolver resolver = getContentResolver();
resolver.registerContentObserver(NOTIFICATION_HISTORY_URI,
false, this, UserHandle.USER_ALL);
}
void stopObserving() {
ContentResolver resolver = getContentResolver();
resolver.unregisterContentObserver(this);
}
@Override
public void onChange(boolean selfChange, Uri uri) {
update(uri);
}
public void update(Uri uri) {
ContentResolver resolver = getContentResolver();
if (uri == null || NOTIFICATION_HISTORY_URI.equals(uri)) {
boolean historyEnabled = Settings.Secure.getInt(resolver,
Settings.Secure.NOTIFICATION_HISTORY_ENABLED, 0)
!= 0;
onHistoryEnabledChanged(historyEnabled);
}
}
}
private final SwitchBar.OnSwitchChangeListener mOnSwitchClickListener =
(switchView, isChecked) -> {
Settings.Secure.putInt(getContentResolver(),
NOTIFICATION_HISTORY_ENABLED,
isChecked ? 1 : 0);
toggleViews(isChecked);
};
private final NotificationListenerService mListener = new NotificationListenerService() {
@Override
@@ -132,18 +236,26 @@ public class NotificationHistoryActivity extends Activity {
mSnoozeView.setVisibility(View.GONE);
} else {
RecyclerView rv = mSnoozeView.findViewById(R.id.notification_list);
rv.setLayoutManager(new LinearLayoutManager(NotificationHistoryActivity.this));
LinearLayoutManager lm = new LinearLayoutManager(NotificationHistoryActivity.this);
rv.setLayoutManager(lm);
rv.setAdapter(new NotificationSbnAdapter(NotificationHistoryActivity.this, mPm));
((NotificationSbnAdapter) rv.getAdapter()).onRebuildComplete(
Arrays.asList(snoozed));
DividerItemDecoration dividerItemDecoration = new DividerItemDecoration(
rv.getContext(), lm.getOrientation());
rv.addItemDecoration(dividerItemDecoration);
}
try {
StatusBarNotification[] dismissed = mNm.getHistoricalNotifications(
NotificationHistoryActivity.this.getPackageName(), 10);
NotificationHistoryActivity.this.getPackageName(), 10, false);
RecyclerView rv = mDismissView.findViewById(R.id.notification_list);
rv.setLayoutManager(new LinearLayoutManager(NotificationHistoryActivity.this));
LinearLayoutManager lm = new LinearLayoutManager(NotificationHistoryActivity.this);
rv.setLayoutManager(lm);
rv.setAdapter(new NotificationSbnAdapter(NotificationHistoryActivity.this, mPm));
DividerItemDecoration dividerItemDecoration = new DividerItemDecoration(
rv.getContext(), lm.getOrientation());
rv.addItemDecoration(dividerItemDecoration);
((NotificationSbnAdapter) rv.getAdapter()).onRebuildComplete(
Arrays.asList(dismissed));
mDismissView.setVisibility(View.VISIBLE);

View File

@@ -73,6 +73,7 @@ public class NotificationHistoryAdapter extends
public void onRebuildComplete(List<HistoricalNotification> notifications) {
mValues = notifications;
mValues.sort((o1, o2) -> Long.compare(o2.getPostedTimeMs(), o1.getPostedTimeMs()));
notifyDataSetChanged();
}
}

View File

@@ -375,7 +375,7 @@ public class NotificationStation extends SettingsPreferenceFragment {
StatusBarNotification[] active = mNoMan.getActiveNotifications(
mContext.getPackageName());
StatusBarNotification[] dismissed = mNoMan.getHistoricalNotifications(
mContext.getPackageName(), 50);
mContext.getPackageName(), 50, false);
List<HistoricalNotificationInfo> list
= new ArrayList<>(active.length + dismissed.length);