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

Commit 363ab6af authored by Treehugger Robot's avatar Treehugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Add peekWhen() and pop() methods to TestLooperManager." into main

parents 7c1c7f3e db1a8279
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -34766,6 +34766,8 @@ package android.os {
    method public boolean hasMessages(android.os.Handler, Object, int);
    method public boolean hasMessages(android.os.Handler, Object, Runnable);
    method public android.os.Message next();
    method @FlaggedApi("android.os.message_queue_testability") @Nullable public Long peekWhen();
    method @FlaggedApi("android.os.message_queue_testability") @Nullable public android.os.Message pop();
    method public void recycle(android.os.Message);
    method public void release();
  }
+32 −3
Original line number Diff line number Diff line
@@ -14,6 +14,8 @@

package android.os;

import android.annotation.FlaggedApi;
import android.annotation.Nullable;
import android.util.ArraySet;

import java.util.concurrent.LinkedBlockingQueue;
@@ -93,9 +95,36 @@ public class TestLooperManager {
    }

    /**
     * Releases the looper to continue standard looping and processing of messages,
     * no further interactions with TestLooperManager will be allowed after
     * release() has been called.
     * Returns the next message that should be executed by this queue, and removes it from the
     * queue. If the queue is empty or no messages are deliverable, returns null.
     * This method never blocks.
     *
     * <p>Callers should always call {@link #recycle(Message)} on the message when all interactions
     * with it have completed.
     */
    @FlaggedApi(Flags.FLAG_MESSAGE_QUEUE_TESTABILITY)
    @Nullable
    public Message pop() {
        checkReleased();
        return mQueue.popForTest();
    }

    /**
     * Returns the values of {@link Message#when} of the next message that should be executed by
     * this queue. If the queue is empty or no messages are deliverable, returns null.
     * This method never blocks.
     */
    @FlaggedApi(Flags.FLAG_MESSAGE_QUEUE_TESTABILITY)
    @SuppressWarnings("AutoBoxing")  // box the primitive long, or return null to indicate no value
    @Nullable
    public Long peekWhen() {
        checkReleased();
        return mQueue.peekWhenForTest();
    }

    /**
     * Releases the looper to continue standard looping and processing of messages, no further
     * interactions with TestLooperManager will be allowed after release() has been called.
     */
    public void release() {
        synchronized (sHeldLoopers) {
+0 −91
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 android.os;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;

import android.platform.test.ravenwood.RavenwoodRule;

import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.platform.app.InstrumentationRegistry;

import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;

@RunWith(AndroidJUnit4.class)
public class TestLooperManagerTest {
    private static final String TAG = "TestLooperManagerTest";

    @Rule
    public final RavenwoodRule mRavenwood = new RavenwoodRule.Builder()
            .setProvideMainThread(true)
            .build();

    @Test
    public void testMainThread() throws Exception {
        doTest(Looper.getMainLooper());
    }

    @Test
    public void testCustomThread() throws Exception {
        final HandlerThread thread = new HandlerThread(TAG);
        thread.start();
        doTest(thread.getLooper());
    }

    private void doTest(Looper looper) throws Exception {
        final TestLooperManager tlm =
                InstrumentationRegistry.getInstrumentation().acquireLooperManager(looper);

        final Handler handler = new Handler(looper);
        final CountDownLatch latch = new CountDownLatch(1);

        assertFalse(tlm.hasMessages(handler, null, 42));

        handler.sendEmptyMessage(42);
        handler.post(() -> {
            latch.countDown();
        });
        assertTrue(tlm.hasMessages(handler, null, 42));
        assertFalse(latch.await(100, TimeUnit.MILLISECONDS));

        final Message first = tlm.next();
        assertEquals(42, first.what);
        assertNull(first.callback);
        tlm.execute(first);
        assertFalse(tlm.hasMessages(handler, null, 42));
        assertFalse(latch.await(100, TimeUnit.MILLISECONDS));
        tlm.recycle(first);

        final Message second = tlm.next();
        assertNotNull(second.callback);
        tlm.execute(second);
        assertFalse(tlm.hasMessages(handler, null, 42));
        assertTrue(latch.await(100, TimeUnit.MILLISECONDS));
        tlm.recycle(second);

        tlm.release();
    }
}