import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
import com.android.systemui.statusbar.phone.NotificationGroupManager;
import com.android.systemui.statusbar.phone.ShadeController;
-import com.android.systemui.statusbar.phone.UnlockMethodCache;
+import com.android.systemui.util.Assert;
import java.util.ArrayList;
import java.util.HashMap;
private NotificationPresenter mPresenter;
private NotificationListContainer mListContainer;
+ // Used to help track down re-entrant calls to our update methods, which will cause bugs.
+ private boolean mPerformingUpdate;
+
@Inject
public NotificationViewHierarchyManager(Context context,
NotificationLockscreenUserManager notificationLockscreenUserManager,
*/
//TODO: Rewrite this to focus on Entries, or some other data object instead of views
public void updateNotificationViews() {
+ Assert.isMainThread();
+ beginUpdate();
+
ArrayList<NotificationEntry> activeNotifications = mEntryManager.getNotificationData()
.getActiveNotifications();
ArrayList<ExpandableNotificationRow> toShow = new ArrayList<>(activeNotifications.size());
// clear the map again for the next usage
mTmpChildOrderMap.clear();
- updateRowStates();
+ updateRowStatesInternal();
mListContainer.onNotificationViewUpdateFinished();
+
+ endUpdate();
}
private void addNotificationChildrenAndSort() {
* Updates expanded, dimmed and locked states of notification rows.
*/
public void updateRowStates() {
+ Assert.isMainThread();
+ beginUpdate();
+ updateRowStatesInternal();
+ endUpdate();
+ }
+
+ private void updateRowStatesInternal() {
Trace.beginSection("NotificationViewHierarchyManager#updateRowStates");
final int N = mListContainer.getContainerChildCount();
public void onDynamicPrivacyChanged() {
updateNotificationViews();
}
+
+ private void beginUpdate() {
+ if (mPerformingUpdate) {
+ throw new IllegalStateException("Re-entrant code during update.");
+ }
+ mPerformingUpdate = true;
+ }
+
+ private void endUpdate() {
+ if (!mPerformingUpdate) {
+ throw new IllegalStateException("Manager state has become desynced.");
+ }
+ mPerformingUpdate = false;
+ }
}
import com.android.systemui.statusbar.policy.HeadsUpUtil;
import com.android.systemui.statusbar.policy.ScrollAdapter;
import com.android.systemui.tuner.TunerService;
+import com.android.systemui.util.Assert;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public void setChildTransferInProgress(boolean childTransferInProgress) {
+ Assert.isMainThread();
mChildTransferInProgress = childTransferInProgress;
}
@Override
@ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
public void changeViewPosition(ExpandableView child, int newIndex) {
+ Assert.isMainThread();
+ if (mChangePositionInProgress) {
+ throw new IllegalStateException("Reentrant call to changeViewPosition");
+ }
+
int currentIndex = indexOfChild(child);
if (currentIndex == -1) {
@Override
@ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public void removeContainerView(View v) {
+ Assert.isMainThread();
removeView(v);
}
@Override
@ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public void addContainerView(View v) {
+ Assert.isMainThread();
addView(v);
}
import android.metrics.LogMaker;
import android.provider.Settings;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
import android.view.View;
import androidx.test.annotation.UiThreadTest;
import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto;
* Tests for {@link NotificationStackScrollLayout}.
*/
@SmallTest
-@RunWith(AndroidJUnit4.class)
+@RunWith(AndroidTestingRunner.class)
+@TestableLooper.RunWithLooper
public class NotificationStackScrollLayoutTest extends SysuiTestCase {
private NotificationStackScrollLayout mStackScroller; // Normally test this
@Before
@UiThreadTest
public void setUp() throws Exception {
+ com.android.systemui.util.Assert.sMainLooper = TestableLooper.get(this).getLooper();
+
mOriginalInterruptionModelSetting = Settings.Secure.getInt(mContext.getContentResolver(),
NOTIFICATION_NEW_INTERRUPTION_MODEL, 0);
Settings.Secure.putInt(mContext.getContentResolver(),