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

Commit 7b81353e authored by Ned Burns's avatar Ned Burns
Browse files

Log when user taps on notifs

Add buffer logging to NotificationClicker and SBNActivityStarter to (a)
log when the user clicks on a notification and (b) the intent that we
fire in response, if any.

Bug: 112656837
Test: manual, atest
Change-Id: Ib9bdfbc184b58a7260e44e6cda48ba8016358e44
parent c1b97d73
Loading
Loading
Loading
Loading
+12 −0
Original line number Diff line number Diff line
@@ -61,6 +61,18 @@ public class LogModule {
        return buffer;
    }

    /** Provides a logging buffer for all logs related to the data layer of notifications. */
    @Provides
    @Singleton
    @NotifInteractionLog
    public static LogBuffer provideNotifInteractionLogBuffer(
            LogcatEchoTracker echoTracker,
            DumpManager dumpManager) {
        LogBuffer buffer = new LogBuffer("NotifInteractionLog", 50, 10, echoTracker);
        buffer.attach(dumpManager);
        return buffer;
    }

    /** Provides a logging buffer for all logs related to Quick Settings. */
    @Provides
    @Singleton
+36 −0
Original line number Diff line number Diff line
/*
 * 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.systemui.log.dagger;

import static java.lang.annotation.RetentionPolicy.RUNTIME;

import com.android.systemui.log.LogBuffer;

import java.lang.annotation.Documented;
import java.lang.annotation.Retention;

import javax.inject.Qualifier;

/**
 * A {@link LogBuffer} for messages related to the user interacting with notifications (e.g.
 * clicking on them).
 */
@Qualifier
@Documented
@Retention(RUNTIME)
public @interface NotifInteractionLog {
}
+43 −9
Original line number Diff line number Diff line
@@ -23,11 +23,14 @@ import android.view.View;

import com.android.systemui.DejankUtils;
import com.android.systemui.bubbles.BubbleController;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.phone.StatusBar;

import java.util.Optional;

import javax.inject.Inject;

/**
 * Click handler for generic clicks on notifications. Clicks on specific areas (expansion caret,
 * app ops icon, etc) are handled elsewhere.
@@ -35,15 +38,19 @@ import java.util.Optional;
public final class NotificationClicker implements View.OnClickListener {
    private static final String TAG = "NotificationClicker";

    private final Optional<StatusBar> mStatusBar;
    private final BubbleController mBubbleController;
    private final NotificationClickerLogger mLogger;
    private final Optional<StatusBar> mStatusBar;
    private final NotificationActivityStarter mNotificationActivityStarter;

    public NotificationClicker(Optional<StatusBar> statusBar,
    private NotificationClicker(
            BubbleController bubbleController,
            NotificationClickerLogger logger,
            Optional<StatusBar> statusBar,
            NotificationActivityStarter notificationActivityStarter) {
        mStatusBar = statusBar;
        mBubbleController = bubbleController;
        mLogger = logger;
        mStatusBar = statusBar;
        mNotificationActivityStarter = notificationActivityStarter;
    }

@@ -58,25 +65,26 @@ public final class NotificationClicker implements View.OnClickListener {
                SystemClock.uptimeMillis(), v, "NOTIFICATION_CLICK"));

        final ExpandableNotificationRow row = (ExpandableNotificationRow) v;
        final StatusBarNotification sbn = row.getEntry().getSbn();
        if (sbn == null) {
            Log.e(TAG, "NotificationClicker called on an unclickable notification,");
            return;
        }
        final NotificationEntry entry = row.getEntry();
        mLogger.logOnClick(entry);

        // Check if the notification is displaying the menu, if so slide notification back
        if (isMenuVisible(row)) {
            mLogger.logMenuVisible(entry);
            row.animateTranslateNotification(0);
            return;
        } else if (row.isChildInGroup() && isMenuVisible(row.getNotificationParent())) {
            mLogger.logParentMenuVisible(entry);
            row.getNotificationParent().animateTranslateNotification(0);
            return;
        } else if (row.isSummaryWithChildren() && row.areChildrenExpanded()) {
            // We never want to open the app directly if the user clicks in between
            // the notifications.
            mLogger.logChildrenExpanded(entry);
            return;
        } else if (row.areGutsExposed()) {
            // ignore click if guts are exposed
            mLogger.logGutsExposed(entry);
            return;
        }

@@ -88,7 +96,7 @@ public final class NotificationClicker implements View.OnClickListener {
            mBubbleController.collapseStack();
        }

        mNotificationActivityStarter.onNotificationClicked(sbn, row);
        mNotificationActivityStarter.onNotificationClicked(entry.getSbn(), row);
    }

    private boolean isMenuVisible(ExpandableNotificationRow row) {
@@ -107,4 +115,30 @@ public final class NotificationClicker implements View.OnClickListener {
            row.setOnClickListener(null);
        }
    }

    /** Daggerized builder for NotificationClicker. */
    public static class Builder {
        private final BubbleController mBubbleController;
        private final NotificationClickerLogger mLogger;

        @Inject
        public Builder(
                BubbleController bubbleController,
                NotificationClickerLogger logger) {
            mBubbleController = bubbleController;
            mLogger = logger;
        }

        /** Builds an instance. */
        public NotificationClicker build(
                Optional<StatusBar> statusBar,
                NotificationActivityStarter notificationActivityStarter
        ) {
            return new NotificationClicker(
                    mBubbleController,
                    mLogger,
                    statusBar,
                    notificationActivityStarter);
        }
    }
}
+70 −0
Original line number Diff line number Diff line
/*
 * 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.systemui.statusbar.notification

import com.android.systemui.log.LogBuffer
import com.android.systemui.log.LogLevel
import com.android.systemui.log.dagger.NotifInteractionLog
import com.android.systemui.statusbar.notification.collection.NotificationEntry
import javax.inject.Inject

class NotificationClickerLogger @Inject constructor(
    @NotifInteractionLog private val buffer: LogBuffer
) {
    fun logOnClick(entry: NotificationEntry) {
        buffer.log(TAG, LogLevel.DEBUG, {
            str1 = entry.key
            str2 = entry.ranking.channel.id
        }, {
            "CLICK $str1 (channel=$str2)"
        })
    }

    fun logMenuVisible(entry: NotificationEntry) {
        buffer.log(TAG, LogLevel.DEBUG, {
            str1 = entry.key
        }, {
            "Ignoring click on $str1; menu is visible"
        })
    }

    fun logParentMenuVisible(entry: NotificationEntry) {
        buffer.log(TAG, LogLevel.DEBUG, {
            str1 = entry.key
        }, {
            "Ignoring click on $str1; parent menu is visible"
        })
    }

    fun logChildrenExpanded(entry: NotificationEntry) {
        buffer.log(TAG, LogLevel.DEBUG, {
            str1 = entry.key
        }, {
            "Ignoring click on $str1; children are expanded"
        })
    }

    fun logGutsExposed(entry: NotificationEntry) {
        buffer.log(TAG, LogLevel.DEBUG, {
            str1 = entry.key
        }, {
            "Ignoring click on $str1; guts are exposed"
        })
    }
}

private const val TAG = "NotificationClicker"
+3 −7
Original line number Diff line number Diff line
@@ -17,7 +17,6 @@
package com.android.systemui.statusbar.notification.init

import android.service.notification.StatusBarNotification
import com.android.systemui.bubbles.BubbleController
import com.android.systemui.plugins.statusbar.NotificationSwipeActionHelper.SnoozeOption
import com.android.systemui.statusbar.FeatureFlags
import com.android.systemui.statusbar.NotificationListener
@@ -62,12 +61,12 @@ class NotificationsControllerImpl @Inject constructor(
    private val deviceProvisionedController: DeviceProvisionedController,
    private val notificationRowBinder: NotificationRowBinderImpl,
    private val remoteInputUriController: RemoteInputUriController,
    private val bubbleController: BubbleController,
    private val groupManager: NotificationGroupManager,
    private val groupAlertTransferHelper: NotificationGroupAlertTransferHelper,
    private val headsUpManager: HeadsUpManager,
    private val headsUpController: HeadsUpController,
    private val headsUpViewBinder: HeadsUpViewBinder
    private val headsUpViewBinder: HeadsUpViewBinder,
    private val clickerBuilder: NotificationClicker.Builder
) : NotificationsController {

    override fun initialize(
@@ -87,10 +86,7 @@ class NotificationsControllerImpl @Inject constructor(
        listController.bind()

        notificationRowBinder.setNotificationClicker(
                NotificationClicker(
                        Optional.of(statusBar),
                        bubbleController,
                        notificationActivityStarter))
                clickerBuilder.build(Optional.of(statusBar), notificationActivityStarter))
        notificationRowBinder.setUpWithPresenter(
                presenter,
                listContainer,
Loading