Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 7f43530a authored by Will Brockman's avatar Will Brockman
Browse files

Statsd UiEvent logging for notification history.

Events logged:
Notif history on/off/open/close
Notif click (recent/snoozed/older)
Notif delete (older)
Notif package history open/close

Additional background: There are 3 notif history sections: snoozed
notifs, recently dismissed notifs, and older notifs. In the snoozed &
recent sections we still know the notif SBN, so actions on those
events are logged with instance ID. The older-notifs section is
grouped by package, and we no longer know the instance ID.

This change depends on change 11692386 in frameworks/base, which adds
UiEventLogger support for the RankingSelected atom.

Bug: 155061525
Test: Manual (statsd testdrive)
Change-Id: If267fca97c40c1bbd8dfa785814c85927ab36c91
parent db6309ca
Loading
Loading
Loading
Loading
+76 −9
Original line number Diff line number Diff line
@@ -26,7 +26,6 @@ import android.app.ActivityManager;
import android.app.INotificationManager;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.res.TypedArray;
import android.graphics.Outline;
@@ -49,10 +48,12 @@ 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.internal.logging.UiEvent;
import com.android.internal.logging.UiEventLogger;
import com.android.internal.logging.UiEventLoggerImpl;
import com.android.settings.R;
import com.android.settings.notification.NotificationBackend;
import com.android.settings.widget.SwitchBar;
@@ -82,6 +83,48 @@ public class NotificationHistoryActivity extends Activity {
    private PackageManager mPm;
    private CountDownLatch mCountdownLatch;
    private Future mCountdownFuture;
    private UiEventLogger mUiEventLogger = new UiEventLoggerImpl();

    enum NotificationHistoryEvent implements UiEventLogger.UiEventEnum {
        @UiEvent(doc = "User turned on notification history")
        NOTIFICATION_HISTORY_ON(504),

        @UiEvent(doc = "User turned off notification history")
        NOTIFICATION_HISTORY_OFF(505),

        @UiEvent(doc = "User opened notification history page")
        NOTIFICATION_HISTORY_OPEN(506),

        @UiEvent(doc = "User closed notification history page")
        NOTIFICATION_HISTORY_CLOSE(507),

        @UiEvent(doc = "User clicked on a notification history item in recently dismissed section")
        NOTIFICATION_HISTORY_RECENT_ITEM_CLICK(508),

        @UiEvent(doc = "User clicked on a notification history item in snoozed section")
        NOTIFICATION_HISTORY_SNOOZED_ITEM_CLICK(509),

        @UiEvent(doc = "User clicked to expand the notification history of a package (app)")
        NOTIFICATION_HISTORY_PACKAGE_HISTORY_OPEN(510),

        @UiEvent(doc = "User clicked to close the notification history of a package (app)")
        NOTIFICATION_HISTORY_PACKAGE_HISTORY_CLOSE(511),

        @UiEvent(doc = "User clicked on a notification history item in an expanded by-app section")
        NOTIFICATION_HISTORY_OLDER_ITEM_CLICK(512),

        @UiEvent(doc = "User dismissed a notification history item in an expanded by-app section")
        NOTIFICATION_HISTORY_OLDER_ITEM_DELETE(513);

        private int mId;
        NotificationHistoryEvent(int id) {
            mId = id;
        }
        @Override
        public int getId() {
            return mId;
        }
    }

    private HistoryLoader.OnHistoryLoaderListener mOnHistoryLoaderListener = notifications -> {
        findViewById(R.id.today_list).setVisibility(
@@ -105,7 +148,8 @@ public class NotificationHistoryActivity extends Activity {
            }
        });
        // for each package, new header and recycler view
        for (NotificationHistoryPackage nhp : notifications) {
        for (int i = 0, notificationsSize = notifications.size(); i < notificationsSize; i++) {
            NotificationHistoryPackage nhp = notifications.get(i);
            View viewForPackage = LayoutInflater.from(this)
                    .inflate(R.layout.notification_history_app_layout, null);

@@ -115,6 +159,7 @@ public class NotificationHistoryActivity extends Activity {
            expand.setContentDescription(container.getVisibility() == View.VISIBLE
                    ? getString(R.string.condition_expand_hide)
                    : getString(R.string.condition_expand_show));
            int finalI = i;
            expand.setOnClickListener(v -> {
                container.setVisibility(container.getVisibility() == View.VISIBLE
                        ? View.GONE : View.VISIBLE);
@@ -125,6 +170,11 @@ public class NotificationHistoryActivity extends Activity {
                        ? getString(R.string.condition_expand_hide)
                        : getString(R.string.condition_expand_show));
                expand.sendAccessibilityEvent(TYPE_VIEW_ACCESSIBILITY_FOCUSED);
                mUiEventLogger.logWithPosition(
                        (container.getVisibility() == View.VISIBLE)
                            ? NotificationHistoryEvent.NOTIFICATION_HISTORY_PACKAGE_HISTORY_OPEN
                            : NotificationHistoryEvent.NOTIFICATION_HISTORY_PACKAGE_HISTORY_CLOSE,
                        nhp.uid, nhp.pkgName, finalI);
            });

            TextView label = viewForPackage.findViewById(R.id.label);
@@ -148,7 +198,7 @@ public class NotificationHistoryActivity extends Activity {
                        if (newCount == 0) {
                            viewForPackage.setVisibility(View.GONE);
                        }
                    }));
                    }, mUiEventLogger));
            ((NotificationHistoryAdapter) rv.getAdapter()).onRebuildComplete(
                    new ArrayList<>(nhp.notifications));

@@ -217,6 +267,8 @@ public class NotificationHistoryActivity extends Activity {
                }
            });
        });

        mUiEventLogger.log(NotificationHistoryEvent.NOTIFICATION_HISTORY_OPEN);
    }

    @Override
@@ -226,6 +278,7 @@ public class NotificationHistoryActivity extends Activity {
        } catch (RemoteException e) {
            Log.e(TAG, "Cannot unregister listener", e);
        }
        mUiEventLogger.log(NotificationHistoryEvent.NOTIFICATION_HISTORY_CLOSE);
        super.onPause();
    }

@@ -273,9 +326,21 @@ public class NotificationHistoryActivity extends Activity {

    private final SwitchBar.OnSwitchChangeListener mOnSwitchClickListener =
            (switchView, isChecked) -> {
                int oldState = 0;
                try {
                    oldState = Settings.Secure.getInt(getContentResolver(),
                            NOTIFICATION_HISTORY_ENABLED);
                } catch (Settings.SettingNotFoundException ignored) {
                }
                final int newState = isChecked ? 1 : 0;
                if (oldState != newState) {
                    Settings.Secure.putInt(getContentResolver(),
                        NOTIFICATION_HISTORY_ENABLED,
                        isChecked ? 1 : 0);
                            NOTIFICATION_HISTORY_ENABLED, newState);
                    mUiEventLogger.log(isChecked ? NotificationHistoryEvent.NOTIFICATION_HISTORY_ON
                            : NotificationHistoryEvent.NOTIFICATION_HISTORY_OFF);
                    Log.d(TAG, "onSwitchChange history to " + isChecked);
                }
                // Reset UI visibility to ensure it matches real state.
                mHistoryOn.setVisibility(View.GONE);
                if (isChecked) {
                    mHistoryEmpty.setVisibility(View.VISIBLE);
@@ -308,7 +373,8 @@ public class NotificationHistoryActivity extends Activity {
            LinearLayoutManager lm = new LinearLayoutManager(NotificationHistoryActivity.this);
            mSnoozedRv.setLayoutManager(lm);
            mSnoozedRv.setAdapter(
                    new NotificationSbnAdapter(NotificationHistoryActivity.this, mPm, mUm));
                    new NotificationSbnAdapter(NotificationHistoryActivity.this, mPm, mUm,
                            true, mUiEventLogger));
            mSnoozedRv.setNestedScrollingEnabled(false);

            if (snoozed == null || snoozed.length == 0) {
@@ -323,7 +389,8 @@ public class NotificationHistoryActivity extends Activity {
                new LinearLayoutManager(NotificationHistoryActivity.this);
            mDismissedRv.setLayoutManager(dismissLm);
            mDismissedRv.setAdapter(
                new NotificationSbnAdapter(NotificationHistoryActivity.this, mPm, mUm));
                    new NotificationSbnAdapter(NotificationHistoryActivity.this, mPm, mUm,
                            false , mUiEventLogger));
            mDismissedRv.setNestedScrollingEnabled(false);

            if (dismissed == null || dismissed.length == 0) {
+10 −2
Original line number Diff line number Diff line
@@ -36,6 +36,7 @@ import android.view.accessibility.AccessibilityNodeInfo;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;

import com.android.internal.logging.UiEventLogger;
import com.android.settings.R;

import java.util.ArrayList;
@@ -50,15 +51,17 @@ public class NotificationHistoryAdapter extends
    private INotificationManager mNm;
    private List<HistoricalNotification> mValues;
    private OnItemDeletedListener mListener;

    private UiEventLogger mUiEventLogger;
    public NotificationHistoryAdapter(INotificationManager nm,
            NotificationHistoryRecyclerView listView,
            OnItemDeletedListener listener) {
            OnItemDeletedListener listener,
            UiEventLogger uiEventLogger) {
        mValues = new ArrayList<>();
        setHasStableIds(true);
        listView.setOnItemSwipeDeleteListener(this);
        mNm = nm;
        mListener = listener;
        mUiEventLogger = uiEventLogger;
    }

    @Override
@@ -76,6 +79,8 @@ public class NotificationHistoryAdapter extends
        holder.setSummary(hn.getText());
        holder.setPostedTime(hn.getPostedTimeMs());
        holder.itemView.setOnClickListener(v -> {
            mUiEventLogger.logWithPosition(NotificationHistoryActivity.NotificationHistoryEvent
                    .NOTIFICATION_HISTORY_OLDER_ITEM_CLICK, hn.getUid(), hn.getPackage(), position);
            Intent intent =  new Intent(Settings.ACTION_CHANNEL_NOTIFICATION_SETTINGS)
                    .putExtra(EXTRA_APP_PACKAGE, hn.getPackage())
                    .putExtra(EXTRA_CHANNEL_ID, hn.getChannelId())
@@ -136,6 +141,9 @@ public class NotificationHistoryAdapter extends
            } catch (RemoteException e) {
                Slog.e(TAG, "Failed to delete item", e);
            }
            mUiEventLogger.logWithPosition(NotificationHistoryActivity.NotificationHistoryEvent
                        .NOTIFICATION_HISTORY_OLDER_ITEM_DELETE, hn.getUid(), hn.getPackage(),
                    position);
        }
        mListener.onItemDeleted(mValues.size());
        notifyItemRemoved(position);
+11 −4
Original line number Diff line number Diff line
@@ -49,11 +49,11 @@ import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;

import com.android.internal.logging.UiEventLogger;
import com.android.internal.util.ContrastColorUtil;
import com.android.settings.R;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -70,8 +70,11 @@ public class NotificationSbnAdapter extends
    private boolean mInNightMode;
    private @UserIdInt int mCurrentUser;
    private List<Integer> mEnabledProfiles = new ArrayList<>();
    private boolean mIsSnoozed;
    private UiEventLogger mUiEventLogger;

    public NotificationSbnAdapter(Context context, PackageManager pm, UserManager um) {
    public NotificationSbnAdapter(Context context, PackageManager pm, UserManager um,
            boolean isSnoozed, UiEventLogger uiEventLogger) {
        mContext = context;
        mPm = pm;
        mUserBadgeCache = new HashMap<>();
@@ -89,6 +92,9 @@ public class NotificationSbnAdapter extends
            }
        }
        setHasStableIds(true);
        // If true, this is the panel for snoozed notifs, otherwise the one for dismissed notifs.
        mIsSnoozed = isSnoozed;
        mUiEventLogger = uiEventLogger;
    }

    @Override
@@ -116,8 +122,9 @@ public class NotificationSbnAdapter extends
                mUserBadgeCache.put(userId, profile);
            }
            holder.setProfileBadge(mUserBadgeCache.get(userId));
            holder.addOnClick(sbn.getPackageName(), sbn.getUserId(),
                    sbn.getNotification().contentIntent);
            holder.addOnClick(position, sbn.getPackageName(), sbn.getUid(), sbn.getUserId(),
                    sbn.getNotification().contentIntent, sbn.getInstanceId(), mIsSnoozed,
                    mUiEventLogger);
            holder.itemView.setOnLongClickListener(v -> {
                Intent intent =  new Intent(Settings.ACTION_CHANNEL_NOTIFICATION_SETTINGS)
                        .putExtra(EXTRA_APP_PACKAGE, sbn.getPackageName())
+12 −2
Original line number Diff line number Diff line
@@ -20,7 +20,6 @@ import android.app.PendingIntent;
import android.content.ActivityNotFoundException;
import android.content.Intent;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.os.UserHandle;
import android.text.TextUtils;
import android.util.Slog;
@@ -34,6 +33,8 @@ import androidx.core.view.ViewCompat;
import androidx.core.view.accessibility.AccessibilityNodeInfoCompat;
import androidx.recyclerview.widget.RecyclerView;

import com.android.internal.logging.InstanceId;
import com.android.internal.logging.UiEventLogger;
import com.android.settings.R;

public class NotificationSbnViewHolder extends RecyclerView.ViewHolder {
@@ -91,13 +92,22 @@ public class NotificationSbnViewHolder extends RecyclerView.ViewHolder {
        mDivider.setVisibility(visible ? View.VISIBLE : View.GONE);
    }

    void addOnClick(String pkg, int userId, PendingIntent pi) {
    void addOnClick(int position, String pkg, int uid, int userId, PendingIntent pi,
            InstanceId instanceId,
            boolean isSnoozed, UiEventLogger uiEventLogger) {
        Intent appIntent = itemView.getContext().getPackageManager()
                .getLaunchIntentForPackage(pkg);
        boolean isPendingIntentValid = pi != null && PendingIntent.getActivity(
                itemView.getContext(), 0, pi.getIntent(), PendingIntent.FLAG_NO_CREATE) != null;
        if (isPendingIntentValid || appIntent != null) {
            itemView.setOnClickListener(v -> {
                uiEventLogger.logWithInstanceIdAndPosition(
                        isSnoozed
                                ? NotificationHistoryActivity.NotificationHistoryEvent
                                .NOTIFICATION_HISTORY_SNOOZED_ITEM_CLICK
                                : NotificationHistoryActivity.NotificationHistoryEvent
                                .NOTIFICATION_HISTORY_RECENT_ITEM_CLICK,
                        uid, pkg, instanceId, position);
                if (pi != null) {
                    try {
                        pi.send();