Merge "Add screen for notification history"
This commit is contained in:
committed by
Android (Google) Code Review
commit
63bbda167f
@@ -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