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

Commit ff561aa3 authored by Jeff DeCew's avatar Jeff DeCew Committed by Android (Google) Code Review
Browse files

Merge "Support running more tests without TestableLooper" into main

parents 294bbe3c c74bc460
Loading
Loading
Loading
Loading
+33 −0
Original line number Diff line number Diff line
@@ -37,6 +37,39 @@ public class Assert {
        sTestThread = thread;
    }

    /**
     * Run {@code mainThreadWork} synchronously, ensuring that {@link #isMainThread()} will return
     * {@code true} while it is running.
     * <ol>
     * <li>If {@link #isMainThread()} already passes, the work is simply run.
     * <li>If the test thread is {@code null}, it will be set, the work run, and then cleared.
     * <li>If the test thread is already set to a different thread, this call will fail the test to
     * avoid causing spurious errors on other thread
     * </ol>
     */
    @VisibleForTesting
    public static void runWithCurrentThreadAsMainThread(Runnable mainThreadWork) {
        if (sMainLooper.isCurrentThread()) {
            // Already on the main thread; just run
            mainThreadWork.run();
            return;
        }
        Thread currentThread = Thread.currentThread();
        Thread originalThread = sTestThread;
        if (originalThread == currentThread) {
            // test thread is already set; just run
            mainThreadWork.run();
            return;
        }
        if (originalThread != null) {
            throw new AssertionError("Can't run with current thread (" + currentThread
                    + ") as main thread; test thread is already set to " + originalThread);
        }
        sTestThread = currentThread;
        mainThreadWork.run();
        sTestThread = null;
    }

    public static void isMainThread() {
        if (!sMainLooper.isCurrentThread()
                && (sTestThread == null || sTestThread != Thread.currentThread())) {
+7 −0
Original line number Diff line number Diff line
@@ -74,6 +74,8 @@ import com.android.systemui.statusbar.notification.interruption.VisualInterrupti
import com.android.systemui.statusbar.notification.interruption.VisualInterruptionRefactor;
import com.android.systemui.statusbar.notification.logging.NotificationPanelLogger;
import com.android.systemui.statusbar.notification.logging.NotificationPanelLoggerImpl;
import com.android.systemui.statusbar.notification.row.NotificationEntryProcessorFactory;
import com.android.systemui.statusbar.notification.row.NotificationEntryProcessorFactoryLooperImpl;
import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
import com.android.systemui.statusbar.notification.row.OnUserInteractionCallback;
import com.android.systemui.statusbar.notification.row.ui.viewmodel.ActivatableNotificationViewModelModule;
@@ -232,6 +234,11 @@ public interface NotificationsModule {
    @Binds
    NotifInflater bindNotifInflater(NotifInflaterImpl notifInflaterImpl);

    /** */
    @Binds
    NotificationEntryProcessorFactory bindNotificationEntryProcessorFactory(
            NotificationEntryProcessorFactoryLooperImpl factoryImpl);

    /** */
    @Binds
    ConversationIconManager bindConversationIconManager(IconManager iconManager);
+5 −33
Original line number Diff line number Diff line
@@ -16,9 +16,6 @@

package com.android.systemui.statusbar.notification.row;

import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.widget.FrameLayout;
@@ -29,7 +26,6 @@ import androidx.annotation.Nullable;
import androidx.core.os.CancellationSignal;

import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.inflation.NotificationRowBinder;
import com.android.systemui.statusbar.notification.collection.notifcollection.CommonNotifCollection;
@@ -82,17 +78,17 @@ public final class NotifBindPipeline {
    private final Map<NotificationEntry, BindEntry> mBindEntries = new ArrayMap<>();
    private final NotifBindPipelineLogger mLogger;
    private final List<BindCallback> mScratchCallbacksList = new ArrayList<>();
    private final Handler mMainHandler;
    private final Processor<NotificationEntry> mStartProcessor;
    private BindStage mStage;

    @Inject
    NotifBindPipeline(
            CommonNotifCollection collection,
            NotifBindPipelineLogger logger,
            @Main Looper mainLooper) {
            NotificationEntryProcessorFactory processorFactory) {
        collection.addCollectionListener(mCollectionListener);
        mLogger = logger;
        mMainHandler = new NotifBindPipelineHandler(mainLooper);
        mStartProcessor = processorFactory.create(this::startPipeline);
    }

    /**
@@ -167,10 +163,7 @@ public final class NotifBindPipeline {
        // Abort any existing pipeline run
        mStage.abortStage(entry, bindEntry.row);

        if (!mMainHandler.hasMessages(START_PIPELINE_MSG, entry)) {
            Message msg = Message.obtain(mMainHandler, START_PIPELINE_MSG, entry);
            mMainHandler.sendMessage(msg);
        }
        mStartProcessor.request(entry);
    }

    /**
@@ -223,7 +216,7 @@ public final class NotifBindPipeline {
                mStage.abortStage(entry, row);
            }
            mStage.deleteStageParams(entry);
            mMainHandler.removeMessages(START_PIPELINE_MSG, entry);
            mStartProcessor.cancel(entry);
        }
    };

@@ -247,25 +240,4 @@ public final class NotifBindPipeline {
        public final Set<BindCallback> callbacks = new ArraySet<>();
        public boolean invalidated;
    }

    private static final int START_PIPELINE_MSG = 1;

    private class NotifBindPipelineHandler extends Handler {

        NotifBindPipelineHandler(Looper looper) {
            super(looper);
        }

        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case START_PIPELINE_MSG:
                    NotificationEntry entry = (NotificationEntry) msg.obj;
                    startPipeline(entry);
                    break;
                default:
                    throw new IllegalArgumentException("Unknown message type: " + msg.what);
            }
        }
    }
}
+25 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2024 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.row

import com.android.systemui.statusbar.notification.collection.NotificationEntry
import java.util.function.Consumer

/** an interface for [NotifBindPipeline] to build a main thread message processor */
interface NotificationEntryProcessorFactory {
    /** Creates a [Processor] that will call the given consumer */
    fun create(consumer: Consumer<NotificationEntry>): Processor<NotificationEntry>
}
+56 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2024 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.row

import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.statusbar.notification.collection.NotificationEntry
import com.android.systemui.util.concurrency.DelayableExecutor
import java.util.concurrent.ConcurrentHashMap
import java.util.function.Consumer
import javax.inject.Inject

class NotificationEntryProcessorFactoryExecutorImpl
@Inject
constructor(@Main private val mMainExecutor: DelayableExecutor) :
    NotificationEntryProcessorFactory {
    override fun create(consumer: Consumer<NotificationEntry>): Processor<NotificationEntry> {
        return ExecutorProcessor(mMainExecutor, consumer)
    }

    private class ExecutorProcessor(
        private val executor: DelayableExecutor,
        private val consumer: Consumer<NotificationEntry>,
    ) : Processor<NotificationEntry> {
        val cancellationsByEntry = ConcurrentHashMap<NotificationEntry, Runnable>()

        override fun request(obj: NotificationEntry) {
            cancellationsByEntry.computeIfAbsent(obj) { entry ->
                executor.executeDelayed({ processEntry(entry) }, 0L)
            }
        }

        private fun processEntry(entry: NotificationEntry) {
            val cancellation = cancellationsByEntry.remove(entry)
            if (cancellation != null) {
                consumer.accept(entry)
            }
        }

        override fun cancel(obj: NotificationEntry) {
            cancellationsByEntry.remove(obj)?.run()
        }
    }
}
Loading