Add logs to NotificationRoundnessManager

Log the state of NotificationRoundnessManager when we are updating the
corners of a Notification to gather more info for investigating a bug.

Bug: 242861679
Test: atest NotificationRoundnessManagerTest
Change-Id: I78ef916513f46390508259828476bb1ea3b368c7
This commit is contained in:
András Kurucz
2022-09-16 11:52:29 +00:00
parent 7b46b29bce
commit 9ad3eaf9c6
5 changed files with 205 additions and 3 deletions

View File

@@ -76,6 +76,14 @@ public class LogModule {
return factory.create("NotifInterruptLog", 100);
}
/** Provides a logging buffer for notification rendering events. */
@Provides
@SysUISingleton
@NotificationRenderLog
public static LogBuffer provideNotificationRenderLogBuffer(LogBufferFactory factory) {
return factory.create("NotifRenderLog", 100);
}
/** Provides a logging buffer for all logs for lockscreen to shade transition events. */
@Provides
@SysUISingleton

View File

@@ -0,0 +1,33 @@
/*
* Copyright (c) 2022 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 notification rendering logging. */
@Qualifier
@Documented
@Retention(RUNTIME)
public @interface NotificationRenderLog {
}

View File

@@ -0,0 +1,72 @@
/*
* Copyright (c) 2022 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.logging
import com.android.systemui.log.LogBuffer
import com.android.systemui.log.LogLevel.INFO
import com.android.systemui.log.dagger.NotificationRenderLog
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow
import com.android.systemui.statusbar.notification.row.ExpandableView
import com.android.systemui.statusbar.notification.stack.NotificationSection
import javax.inject.Inject
/** Handles logging for the {NotificationRoundnessManager}. */
class NotificationRoundnessLogger
@Inject
constructor(@NotificationRenderLog val buffer: LogBuffer) {
/** Called when the {NotificationRoundnessManager} updates the corners if the Notifications. */
fun onCornersUpdated(
view: ExpandableView?,
isFirstInSection: Boolean,
isLastInSection: Boolean,
topChanged: Boolean,
bottomChanged: Boolean
) {
buffer.log(
TAG_ROUNDNESS,
INFO,
{
str1 = (view as? ExpandableNotificationRow)?.entry?.key
bool1 = isFirstInSection
bool2 = isLastInSection
bool3 = topChanged
bool4 = bottomChanged
},
{
"onCornersUpdated: " +
"entry=$str1 isFirstInSection=$bool1 isLastInSection=$bool2 " +
"topChanged=$bool3 bottomChanged=$bool4"
}
)
}
/** Called when we update the {NotificationRoundnessManager} with new sections. */
fun onSectionCornersUpdated(sections: Array<NotificationSection?>, anyChanged: Boolean) {
buffer.log(
TAG_ROUNDNESS,
INFO,
{
int1 = sections.size
bool1 = anyChanged
},
{ "onSectionCornersUpdated: sections size=$int1 anyChanged=$bool1" }
)
}
}
private const val TAG_ROUNDNESS = "NotifRoundnessLogger"

View File

@@ -19,12 +19,19 @@ package com.android.systemui.statusbar.notification.stack;
import android.content.res.Resources;
import android.util.MathUtils;
import androidx.annotation.NonNull;
import com.android.systemui.Dumpable;
import com.android.systemui.R;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.statusbar.notification.NotificationSectionsFeatureManager;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.logging.NotificationRoundnessLogger;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.notification.row.ExpandableView;
import java.io.PrintWriter;
import java.util.HashSet;
import javax.inject.Inject;
@@ -33,12 +40,16 @@ import javax.inject.Inject;
* A class that manages the roundness for notification views
*/
@SysUISingleton
public class NotificationRoundnessManager {
public class NotificationRoundnessManager implements Dumpable {
private static final String TAG = "NotificationRoundnessManager";
private final ExpandableView[] mFirstInSectionViews;
private final ExpandableView[] mLastInSectionViews;
private final ExpandableView[] mTmpFirstInSectionViews;
private final ExpandableView[] mTmpLastInSectionViews;
private final NotificationRoundnessLogger mNotifLogger;
private final DumpManager mDumpManager;
private boolean mExpanded;
private HashSet<ExpandableView> mAnimatedChildren;
private Runnable mRoundingChangedCallback;
@@ -53,12 +64,31 @@ public class NotificationRoundnessManager {
@Inject
NotificationRoundnessManager(
NotificationSectionsFeatureManager sectionsFeatureManager) {
NotificationSectionsFeatureManager sectionsFeatureManager,
NotificationRoundnessLogger notifLogger,
DumpManager dumpManager) {
int numberOfSections = sectionsFeatureManager.getNumberOfBuckets();
mFirstInSectionViews = new ExpandableView[numberOfSections];
mLastInSectionViews = new ExpandableView[numberOfSections];
mTmpFirstInSectionViews = new ExpandableView[numberOfSections];
mTmpLastInSectionViews = new ExpandableView[numberOfSections];
mNotifLogger = notifLogger;
mDumpManager = dumpManager;
mDumpManager.registerDumpable(TAG, this);
}
@Override
public void dump(@NonNull PrintWriter pw, @NonNull String[] args) {
pw.println("mFirstInSectionViews: length=" + mFirstInSectionViews.length);
pw.println(dumpViews(mFirstInSectionViews));
pw.println("mLastInSectionViews: length=" + mLastInSectionViews.length);
pw.println(dumpViews(mFirstInSectionViews));
if (mTrackedHeadsUp != null) {
pw.println("trackedHeadsUp=" + mTrackedHeadsUp.getEntry());
}
pw.println("roundForPulsingViews=" + mRoundForPulsingViews);
pw.println("isClearAllInProgress=" + mIsClearAllInProgress);
}
public void updateView(ExpandableView view, boolean animate) {
@@ -95,6 +125,9 @@ public class NotificationRoundnessManager {
view.setFirstInSection(isFirstInSection);
view.setLastInSection(isLastInSection);
mNotifLogger.onCornersUpdated(view, isFirstInSection,
isLastInSection, topChanged, bottomChanged);
return (isFirstInSection || isLastInSection) && (topChanged || bottomChanged);
}
@@ -184,6 +217,7 @@ public class NotificationRoundnessManager {
if (isLastInSection(view) && !top) {
return 1.0f;
}
if (view == mTrackedHeadsUp) {
// If we're pushing up on a headsup the appear fraction is < 0 and it needs to still be
// rounded.
@@ -220,6 +254,8 @@ public class NotificationRoundnessManager {
if (anyChanged) {
mRoundingChangedCallback.run();
}
mNotifLogger.onSectionCornersUpdated(sections, anyChanged);
}
private boolean handleRemovedOldViews(NotificationSection[] sections,
@@ -296,4 +332,36 @@ public class NotificationRoundnessManager {
public void setShouldRoundPulsingViews(boolean shouldRoundPulsingViews) {
mRoundForPulsingViews = shouldRoundPulsingViews;
}
private String dumpViews(ExpandableView[] views) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < views.length; i++) {
if (views[i] == null) continue;
sb.append("\t")
.append("[").append(i).append("] ")
.append("isPinned=").append(views[i].isPinned()).append(" ")
.append("isFirstInSection=").append(views[i].isFirstInSection()).append(" ")
.append("isLastInSection=").append(views[i].isLastInSection()).append(" ");
if (views[i] instanceof ExpandableNotificationRow) {
sb.append("entry=");
dumpEntry(((ExpandableNotificationRow) views[i]).getEntry(), sb);
}
sb.append("\n");
}
return sb.toString();
}
private void dumpEntry(NotificationEntry entry, StringBuilder sb) {
sb.append("NotificationEntry{key=").append(entry.getKey()).append(" ");
if (entry.getSection() != null) {
sb.append(" section=")
.append(entry.getSection().getLabel());
}
sb.append("}");
}
}

View File

@@ -16,6 +16,8 @@
package com.android.systemui.statusbar.notification.stack;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.atLeast;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
@@ -32,8 +34,10 @@ import androidx.test.filters.SmallTest;
import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.statusbar.notification.NotificationSectionsFeatureManager;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.logging.NotificationRoundnessLogger;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.notification.row.ExpandableView;
import com.android.systemui.statusbar.notification.row.NotificationTestHelper;
@@ -57,6 +61,7 @@ public class NotificationRoundnessManagerTest extends SysuiTestCase {
private Runnable mRoundnessCallback = mock(Runnable.class);
private ExpandableNotificationRow mFirst;
private ExpandableNotificationRow mSecond;
private NotificationRoundnessLogger mLogger = mock(NotificationRoundnessLogger.class);
private float mSmallRadiusRatio;
@Before
@@ -66,7 +71,9 @@ public class NotificationRoundnessManagerTest extends SysuiTestCase {
mSmallRadiusRatio = resources.getDimension(R.dimen.notification_corner_radius_small)
/ resources.getDimension(R.dimen.notification_corner_radius);
mRoundnessManager = new NotificationRoundnessManager(
new NotificationSectionsFeatureManager(new DeviceConfigProxy(), mContext));
new NotificationSectionsFeatureManager(new DeviceConfigProxy(), mContext),
mLogger,
mock(DumpManager.class));
allowTestableLooperAsMainThread();
NotificationTestHelper testHelper = new NotificationTestHelper(
mContext,
@@ -337,6 +344,20 @@ public class NotificationRoundnessManagerTest extends SysuiTestCase {
Assert.assertTrue(mSecond.isLastInSection());
}
@Test
public void testLoggingOnRoundingUpdate() {
NotificationSection[] sections = new NotificationSection[]{
createSection(mFirst, mSecond),
createSection(null, null)
};
mRoundnessManager.updateRoundedChildren(sections);
verify(mLogger).onSectionCornersUpdated(sections, /*anyChanged=*/ true);
verify(mLogger, atLeast(1)).onCornersUpdated(eq(mFirst), anyBoolean(),
anyBoolean(), anyBoolean(), anyBoolean());
verify(mLogger, atLeast(1)).onCornersUpdated(eq(mSecond), anyBoolean(),
anyBoolean(), anyBoolean(), anyBoolean());
}
private NotificationSection createSection(ExpandableNotificationRow first,
ExpandableNotificationRow last) {
NotificationSection section = mock(NotificationSection.class);