Merge "Use Executor in AsyncSensorManager."
This commit is contained in:
@@ -25,16 +25,21 @@ import androidx.annotation.VisibleForTesting;
|
||||
*/
|
||||
public class Assert {
|
||||
private static final Looper sMainLooper = Looper.getMainLooper();
|
||||
private static Looper sTestLooper = null;
|
||||
private static Thread sTestThread = null;
|
||||
|
||||
@VisibleForTesting
|
||||
public static void setTestableLooper(Looper testLooper) {
|
||||
sTestLooper = testLooper;
|
||||
setTestThread(testLooper == null ? null : testLooper.getThread());
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
public static void setTestThread(Thread thread) {
|
||||
sTestThread = thread;
|
||||
}
|
||||
|
||||
public static void isMainThread() {
|
||||
if (!sMainLooper.isCurrentThread()
|
||||
&& (sTestLooper == null || !sTestLooper.isCurrentThread())) {
|
||||
&& (sTestThread == null || sTestThread != Thread.currentThread())) {
|
||||
throw new IllegalStateException("should be called from the main thread."
|
||||
+ " sMainLooper.threadName=" + sMainLooper.getThread().getName()
|
||||
+ " Thread.currentThread()=" + Thread.currentThread().getName());
|
||||
@@ -43,7 +48,7 @@ public class Assert {
|
||||
|
||||
public static void isNotMainThread() {
|
||||
if (sMainLooper.isCurrentThread()
|
||||
&& (sTestLooper == null || sTestLooper.isCurrentThread())) {
|
||||
&& (sTestThread == null || sTestThread == Thread.currentThread())) {
|
||||
throw new IllegalStateException("should not be called from the main thread.");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,6 +32,7 @@ import java.util.concurrent.Executors;
|
||||
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import dagger.Binds;
|
||||
import dagger.Module;
|
||||
import dagger.Provides;
|
||||
|
||||
@@ -199,4 +200,10 @@ public abstract class ConcurrencyModule {
|
||||
public static Executor provideUiBackgroundExecutor() {
|
||||
return Executors.newSingleThreadExecutor();
|
||||
}
|
||||
|
||||
/**
|
||||
* Binds {@link ThreadFactoryImpl} to {@link ThreadFactory}.
|
||||
*/
|
||||
@Binds
|
||||
public abstract ThreadFactory bindExecutorFactory(ThreadFactoryImpl impl);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* 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.util.concurrency;
|
||||
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
/**
|
||||
* Factory for building Executors running on a unique named thread.
|
||||
*
|
||||
* Use this when our generally available @Main, @Background, @UiBackground, @LongRunning, or
|
||||
* similar global qualifiers don't quite cut it. Note that the methods here create entirely new
|
||||
* threads; there are no singletons here. Use responsibly.
|
||||
*/
|
||||
public interface ThreadFactory {
|
||||
/**
|
||||
* Return an {@link java.util.concurrent.Executor} running on a named thread.
|
||||
*
|
||||
* The thread is implicitly started and may be left running indefinitely, depending on the
|
||||
* implementation. Assume this is the case and use responsibly.
|
||||
**/
|
||||
Executor buildExecutorOnNewThread(String threadName);
|
||||
|
||||
/**
|
||||
* Return an {@link DelayableExecutor} running on a named thread.
|
||||
*
|
||||
* The thread is implicitly started and may be left running indefinitely, depending on the
|
||||
* implementation. Assume this is the case and use responsibly.
|
||||
**/
|
||||
DelayableExecutor buildDelayableExecutorOnNewThread(String threadName);
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* 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.util.concurrency;
|
||||
|
||||
import android.os.HandlerThread;
|
||||
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
class ThreadFactoryImpl implements ThreadFactory {
|
||||
@Inject
|
||||
ThreadFactoryImpl() {}
|
||||
|
||||
public Executor buildExecutorOnNewThread(String threadName) {
|
||||
return buildDelayableExecutorOnNewThread(threadName);
|
||||
}
|
||||
|
||||
public DelayableExecutor buildDelayableExecutorOnNewThread(String threadName) {
|
||||
HandlerThread handlerThread = new HandlerThread(threadName);
|
||||
handlerThread.start();
|
||||
return new ExecutorImpl(handlerThread.getLooper());
|
||||
}
|
||||
}
|
||||
@@ -25,18 +25,18 @@ import android.hardware.SensorEventListener;
|
||||
import android.hardware.SensorManager;
|
||||
import android.hardware.TriggerEventListener;
|
||||
import android.os.Handler;
|
||||
import android.os.HandlerThread;
|
||||
import android.os.MemoryFile;
|
||||
import android.util.Log;
|
||||
|
||||
import com.android.internal.annotations.VisibleForTesting;
|
||||
import com.android.internal.util.Preconditions;
|
||||
import com.android.systemui.plugins.PluginListener;
|
||||
import com.android.systemui.plugins.SensorManagerPlugin;
|
||||
import com.android.systemui.shared.plugins.PluginManager;
|
||||
import com.android.systemui.util.concurrency.ThreadFactory;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
@@ -56,25 +56,14 @@ public class AsyncSensorManager extends SensorManager
|
||||
|
||||
private final SensorManager mInner;
|
||||
private final List<Sensor> mSensorCache;
|
||||
private final Handler mHandler;
|
||||
private final Executor mExecutor;
|
||||
private final List<SensorManagerPlugin> mPlugins;
|
||||
|
||||
@Inject
|
||||
public AsyncSensorManager(SensorManager sensorManager, PluginManager pluginManager) {
|
||||
this(sensorManager, pluginManager, null);
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
public AsyncSensorManager(
|
||||
SensorManager sensorManager, PluginManager pluginManager, Handler handler) {
|
||||
public AsyncSensorManager(SensorManager sensorManager, ThreadFactory threadFactory,
|
||||
PluginManager pluginManager) {
|
||||
mInner = sensorManager;
|
||||
if (handler == null) {
|
||||
HandlerThread handlerThread = new HandlerThread("async_sensor");
|
||||
handlerThread.start();
|
||||
mHandler = new Handler(handlerThread.getLooper());
|
||||
} else {
|
||||
mHandler = handler;
|
||||
}
|
||||
mExecutor = threadFactory.buildExecutorOnNewThread("async_sensor");
|
||||
mSensorCache = mInner.getSensorList(Sensor.TYPE_ALL);
|
||||
mPlugins = new ArrayList<>();
|
||||
if (pluginManager != null) {
|
||||
@@ -97,7 +86,7 @@ public class AsyncSensorManager extends SensorManager
|
||||
protected boolean registerListenerImpl(SensorEventListener listener,
|
||||
Sensor sensor, int delayUs, Handler handler, int maxReportLatencyUs,
|
||||
int reservedFlags) {
|
||||
mHandler.post(() -> {
|
||||
mExecutor.execute(() -> {
|
||||
if (!mInner.registerListener(listener, sensor, delayUs, maxReportLatencyUs, handler)) {
|
||||
Log.e(TAG, "Registering " + listener + " for " + sensor + " failed.");
|
||||
}
|
||||
@@ -129,12 +118,12 @@ public class AsyncSensorManager extends SensorManager
|
||||
@Override
|
||||
protected void registerDynamicSensorCallbackImpl(DynamicSensorCallback callback,
|
||||
Handler handler) {
|
||||
mHandler.post(() -> mInner.registerDynamicSensorCallback(callback, handler));
|
||||
mExecutor.execute(() -> mInner.registerDynamicSensorCallback(callback, handler));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void unregisterDynamicSensorCallbackImpl(DynamicSensorCallback callback) {
|
||||
mHandler.post(() -> mInner.unregisterDynamicSensorCallback(callback));
|
||||
mExecutor.execute(() -> mInner.unregisterDynamicSensorCallback(callback));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -145,7 +134,7 @@ public class AsyncSensorManager extends SensorManager
|
||||
if (sensor == null) {
|
||||
throw new IllegalArgumentException("sensor cannot be null");
|
||||
}
|
||||
mHandler.post(() -> {
|
||||
mExecutor.execute(() -> {
|
||||
if (!mInner.requestTriggerSensor(listener, sensor)) {
|
||||
Log.e(TAG, "Requesting " + listener + " for " + sensor + " failed.");
|
||||
}
|
||||
@@ -158,7 +147,7 @@ public class AsyncSensorManager extends SensorManager
|
||||
boolean disable) {
|
||||
Preconditions.checkArgument(disable);
|
||||
|
||||
mHandler.post(() -> {
|
||||
mExecutor.execute(() -> {
|
||||
if (!mInner.cancelTriggerSensor(listener, sensor)) {
|
||||
Log.e(TAG, "Canceling " + listener + " for " + sensor + " failed.");
|
||||
}
|
||||
@@ -178,7 +167,7 @@ public class AsyncSensorManager extends SensorManager
|
||||
Log.w(TAG, "No plugins registered");
|
||||
return false;
|
||||
}
|
||||
mHandler.post(() -> {
|
||||
mExecutor.execute(() -> {
|
||||
for (int i = 0; i < mPlugins.size(); i++) {
|
||||
mPlugins.get(i).registerListener(sensor, listener);
|
||||
}
|
||||
@@ -194,7 +183,7 @@ public class AsyncSensorManager extends SensorManager
|
||||
*/
|
||||
public void unregisterPluginListener(SensorManagerPlugin.Sensor sensor,
|
||||
SensorManagerPlugin.SensorEventListener listener) {
|
||||
mHandler.post(() -> {
|
||||
mExecutor.execute(() -> {
|
||||
for (int i = 0; i < mPlugins.size(); i++) {
|
||||
mPlugins.get(i).unregisterListener(sensor, listener);
|
||||
}
|
||||
@@ -214,14 +203,14 @@ public class AsyncSensorManager extends SensorManager
|
||||
|
||||
@Override
|
||||
protected boolean setOperationParameterImpl(SensorAdditionalInfo parameter) {
|
||||
mHandler.post(() -> mInner.setOperationParameter(parameter));
|
||||
mExecutor.execute(() -> mInner.setOperationParameter(parameter));
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void unregisterListenerImpl(SensorEventListener listener,
|
||||
Sensor sensor) {
|
||||
mHandler.post(() -> {
|
||||
mExecutor.execute(() -> {
|
||||
if (sensor == null) {
|
||||
mInner.unregisterListener(listener);
|
||||
} else {
|
||||
|
||||
@@ -30,9 +30,7 @@ import static org.mockito.Mockito.when;
|
||||
import android.app.AlarmManager;
|
||||
import android.hardware.Sensor;
|
||||
import android.hardware.display.AmbientDisplayConfiguration;
|
||||
import android.os.Handler;
|
||||
import android.testing.AndroidTestingRunner;
|
||||
import android.testing.TestableLooper;
|
||||
import android.testing.TestableLooper.RunWithLooper;
|
||||
import android.view.Display;
|
||||
|
||||
@@ -43,6 +41,7 @@ import com.android.systemui.broadcast.BroadcastDispatcher;
|
||||
import com.android.systemui.dock.DockManager;
|
||||
import com.android.systemui.statusbar.phone.DozeParameters;
|
||||
import com.android.systemui.util.concurrency.FakeExecutor;
|
||||
import com.android.systemui.util.concurrency.FakeThreadFactory;
|
||||
import com.android.systemui.util.sensors.AsyncSensorManager;
|
||||
import com.android.systemui.util.sensors.FakeProximitySensor;
|
||||
import com.android.systemui.util.sensors.FakeSensorManager;
|
||||
@@ -92,7 +91,7 @@ public class DozeTriggersTest extends SysuiTestCase {
|
||||
mTapSensor = mSensors.getFakeTapSensor().getSensor();
|
||||
WakeLock wakeLock = new WakeLockFake();
|
||||
AsyncSensorManager asyncSensorManager =
|
||||
new AsyncSensorManager(mSensors, null, new Handler());
|
||||
new AsyncSensorManager(mSensors, new FakeThreadFactory(mExecutor), null);
|
||||
|
||||
FakeThresholdSensor thresholdSensor = new FakeThresholdSensor();
|
||||
thresholdSensor.setLoaded(true);
|
||||
@@ -186,6 +185,6 @@ public class DozeTriggersTest extends SysuiTestCase {
|
||||
}
|
||||
|
||||
private void waitForSensorManager() {
|
||||
TestableLooper.get(this).processAllMessages();
|
||||
mExecutor.runAllReady();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* 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.util.concurrency;
|
||||
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
/**
|
||||
* Implementation of {@link ThreadFactory} that returns {@link FakeExecutor} where it can.
|
||||
*/
|
||||
public class FakeThreadFactory implements ThreadFactory {
|
||||
private final FakeExecutor mFakeExecutor;
|
||||
|
||||
public FakeThreadFactory(FakeExecutor fakeExecutor) {
|
||||
mFakeExecutor = fakeExecutor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Executor buildExecutorOnNewThread(String threadName) {
|
||||
return mFakeExecutor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DelayableExecutor buildDelayableExecutorOnNewThread(String threadName) {
|
||||
return mFakeExecutor;
|
||||
}
|
||||
}
|
||||
@@ -23,15 +23,16 @@ import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.verifyNoMoreInteractions;
|
||||
|
||||
import android.hardware.SensorEventListener;
|
||||
import android.os.Handler;
|
||||
import android.testing.AndroidTestingRunner;
|
||||
import android.testing.TestableLooper;
|
||||
|
||||
import androidx.test.filters.SmallTest;
|
||||
|
||||
import com.android.systemui.SysuiTestCase;
|
||||
import com.android.systemui.plugins.SensorManagerPlugin;
|
||||
import com.android.systemui.shared.plugins.PluginManager;
|
||||
import com.android.systemui.util.concurrency.FakeExecutor;
|
||||
import com.android.systemui.util.concurrency.FakeThreadFactory;
|
||||
import com.android.systemui.util.time.FakeSystemClock;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
@@ -39,20 +40,20 @@ import org.junit.runner.RunWith;
|
||||
|
||||
@SmallTest
|
||||
@RunWith(AndroidTestingRunner.class)
|
||||
@TestableLooper.RunWithLooper
|
||||
public class AsyncSensorManagerTest extends SysuiTestCase {
|
||||
|
||||
private AsyncSensorManager mAsyncSensorManager;
|
||||
private SensorEventListener mListener;
|
||||
private FakeSensorManager.FakeProximitySensor mSensor;
|
||||
private PluginManager mPluginManager;
|
||||
private FakeExecutor mFakeExecutor = new FakeExecutor(new FakeSystemClock());
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
mPluginManager = mock(PluginManager.class);
|
||||
FakeSensorManager fakeSensorManager = new FakeSensorManager(mContext);
|
||||
mAsyncSensorManager = new AsyncSensorManager(
|
||||
fakeSensorManager, mPluginManager, new Handler());
|
||||
fakeSensorManager, new FakeThreadFactory(mFakeExecutor), mPluginManager);
|
||||
mSensor = fakeSensorManager.getFakeProximitySensor();
|
||||
mListener = mock(SensorEventListener.class);
|
||||
}
|
||||
@@ -99,6 +100,6 @@ public class AsyncSensorManagerTest extends SysuiTestCase {
|
||||
}
|
||||
|
||||
public void waitUntilRequestsCompleted() {
|
||||
TestableLooper.get(this).processAllMessages();
|
||||
mFakeExecutor.runAllReady();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,12 +20,14 @@ import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import android.os.Handler;
|
||||
import android.test.suitebuilder.annotation.SmallTest;
|
||||
import android.testing.AndroidTestingRunner;
|
||||
import android.testing.TestableLooper;
|
||||
|
||||
import com.android.systemui.SysuiTestCase;
|
||||
import com.android.systemui.util.Assert;
|
||||
import com.android.systemui.util.concurrency.FakeExecutor;
|
||||
import com.android.systemui.util.concurrency.FakeThreadFactory;
|
||||
import com.android.systemui.util.time.FakeSystemClock;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
@@ -33,21 +35,20 @@ import org.junit.runner.RunWith;
|
||||
|
||||
@SmallTest
|
||||
@RunWith(AndroidTestingRunner.class)
|
||||
@TestableLooper.RunWithLooper
|
||||
public class ThresholdSensorImplTest extends SysuiTestCase {
|
||||
|
||||
private ThresholdSensorImpl mThresholdSensor;
|
||||
private FakeSensorManager mSensorManager;
|
||||
private AsyncSensorManager mAsyncSensorManager;
|
||||
private FakeSensorManager.FakeProximitySensor mFakeProximitySensor;
|
||||
private FakeExecutor mFakeExecutor = new FakeExecutor(new FakeSystemClock());
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
allowTestableLooperAsMainThread();
|
||||
mSensorManager = new FakeSensorManager(getContext());
|
||||
|
||||
mAsyncSensorManager = new AsyncSensorManager(
|
||||
mSensorManager, null, new Handler());
|
||||
mSensorManager, new FakeThreadFactory(mFakeExecutor), null);
|
||||
|
||||
mFakeProximitySensor = mSensorManager.getFakeProximitySensor();
|
||||
ThresholdSensorImpl.Builder thresholdSensorBuilder = new ThresholdSensorImpl.Builder(
|
||||
@@ -60,6 +61,7 @@ public class ThresholdSensorImplTest extends SysuiTestCase {
|
||||
|
||||
@Test
|
||||
public void testSingleListener() {
|
||||
Assert.setTestThread(Thread.currentThread());
|
||||
TestableListener listener = new TestableListener();
|
||||
|
||||
assertFalse(mThresholdSensor.isRegistered());
|
||||
@@ -81,6 +83,7 @@ public class ThresholdSensorImplTest extends SysuiTestCase {
|
||||
|
||||
@Test
|
||||
public void testMultiListener() {
|
||||
Assert.setTestThread(Thread.currentThread());
|
||||
TestableListener listenerA = new TestableListener();
|
||||
TestableListener listenerB = new TestableListener();
|
||||
|
||||
@@ -114,6 +117,7 @@ public class ThresholdSensorImplTest extends SysuiTestCase {
|
||||
|
||||
@Test
|
||||
public void testDuplicateListener() {
|
||||
Assert.setTestThread(Thread.currentThread());
|
||||
TestableListener listenerA = new TestableListener();
|
||||
|
||||
assertFalse(mThresholdSensor.isRegistered());
|
||||
@@ -138,6 +142,7 @@ public class ThresholdSensorImplTest extends SysuiTestCase {
|
||||
}
|
||||
@Test
|
||||
public void testUnregister() {
|
||||
Assert.setTestThread(Thread.currentThread());
|
||||
TestableListener listener = new TestableListener();
|
||||
|
||||
assertFalse(mThresholdSensor.isRegistered());
|
||||
@@ -157,6 +162,7 @@ public class ThresholdSensorImplTest extends SysuiTestCase {
|
||||
|
||||
@Test
|
||||
public void testPauseAndResume() {
|
||||
Assert.setTestThread(Thread.currentThread());
|
||||
TestableListener listener = new TestableListener();
|
||||
|
||||
assertFalse(mThresholdSensor.isRegistered());
|
||||
@@ -199,6 +205,7 @@ public class ThresholdSensorImplTest extends SysuiTestCase {
|
||||
|
||||
@Test
|
||||
public void testAlertListeners() {
|
||||
Assert.setTestThread(Thread.currentThread());
|
||||
TestableListener listenerA = new TestableListener();
|
||||
TestableListener listenerB = new TestableListener();
|
||||
|
||||
@@ -230,6 +237,7 @@ public class ThresholdSensorImplTest extends SysuiTestCase {
|
||||
|
||||
@Test
|
||||
public void testHysteresis() {
|
||||
Assert.setTestThread(Thread.currentThread());
|
||||
float lowValue = 10f;
|
||||
float highValue = 100f;
|
||||
FakeSensorManager.FakeGenericSensor sensor = mSensorManager.getFakeLightSensor();
|
||||
@@ -278,6 +286,7 @@ public class ThresholdSensorImplTest extends SysuiTestCase {
|
||||
|
||||
@Test
|
||||
public void testAlertAfterPause() {
|
||||
Assert.setTestThread(Thread.currentThread());
|
||||
TestableListener listener = new TestableListener();
|
||||
|
||||
mThresholdSensor.register(listener);
|
||||
@@ -307,7 +316,7 @@ public class ThresholdSensorImplTest extends SysuiTestCase {
|
||||
}
|
||||
|
||||
private void waitForSensorManager() {
|
||||
TestableLooper.get(this).processAllMessages();
|
||||
mFakeExecutor.runAllReady();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user