aboutsummaryrefslogtreecommitdiff
path: root/experimental
diff options
context:
space:
mode:
authorAutomerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>2020-03-10 16:53:46 +0000
committerAutomerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>2020-03-10 16:53:46 +0000
commit86a2f2742ce0c481ff1992b0bd9d2e1ed7652213 (patch)
tree427d932f13615632bc6192d776647288948dfd92 /experimental
parent508b239bae8d5645ad9c30527e2798f7a83ffd27 (diff)
parent528aad0008c44648e53d9bbce54d96aca1539344 (diff)
downloadCar-86a2f2742ce0c481ff1992b0bd9d2e1ed7652213.tar.gz
Merge "Fix gaze service creation through intent" into rvc-dev am: 528aad0008
Change-Id: I9c3ba65419af8de50491f1fd8207183c93ee2b22
Diffstat (limited to 'experimental')
-rw-r--r--experimental/experimental_api/src/android/car/experimental/DriverAwarenessSupplierService.java4
-rw-r--r--experimental/service/src/com/android/experimentalcar/DriverDistractionExperimentalFeatureService.java14
-rw-r--r--experimental/service/src/com/android/experimentalcar/GazeDriverAwarenessSupplier.java34
-rw-r--r--experimental/service/src/com/android/experimentalcar/TouchDriverAwarenessSupplier.java4
-rw-r--r--experimental/tests/experimentalcarservice_unit_test/src/com/android/experimentalcar/DriverDistractionExperimentalFeatureServiceTest.java143
-rw-r--r--experimental/tests/experimentalcarservice_unit_test/src/com/android/experimentalcar/GazeDriverAwarenessSupplierTest.java21
6 files changed, 207 insertions, 13 deletions
diff --git a/experimental/experimental_api/src/android/car/experimental/DriverAwarenessSupplierService.java b/experimental/experimental_api/src/android/car/experimental/DriverAwarenessSupplierService.java
index df48d101ca..c904428374 100644
--- a/experimental/experimental_api/src/android/car/experimental/DriverAwarenessSupplierService.java
+++ b/experimental/experimental_api/src/android/car/experimental/DriverAwarenessSupplierService.java
@@ -24,6 +24,7 @@ import android.os.RemoteException;
import android.util.Log;
import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
/**
* The supplier for providing a stream of the driver's current situational awareness.
@@ -130,7 +131,8 @@ public abstract class DriverAwarenessSupplierService extends Service {
* The binder between this service and
* {@link com.android.experimentalcar.DriverDistractionExperimentalFeatureService}.
*/
- private class SupplierBinder extends IDriverAwarenessSupplier.Stub {
+ @VisibleForTesting
+ public class SupplierBinder extends IDriverAwarenessSupplier.Stub {
@Override
public void onReady() {
diff --git a/experimental/service/src/com/android/experimentalcar/DriverDistractionExperimentalFeatureService.java b/experimental/service/src/com/android/experimentalcar/DriverDistractionExperimentalFeatureService.java
index e6848a174f..83b64d1df9 100644
--- a/experimental/service/src/com/android/experimentalcar/DriverDistractionExperimentalFeatureService.java
+++ b/experimental/service/src/com/android/experimentalcar/DriverDistractionExperimentalFeatureService.java
@@ -40,6 +40,7 @@ import android.content.ServiceConnection;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.IBinder;
+import android.os.Looper;
import android.os.RemoteCallbackList;
import android.os.RemoteException;
import android.os.UserHandle;
@@ -189,6 +190,7 @@ public final class DriverDistractionExperimentalFeatureService extends
private final Context mContext;
private final ITimeSource mTimeSource;
+ private final Looper mLooper;
/**
* Create an instance of {@link DriverDistractionExperimentalFeatureService}.
@@ -201,6 +203,15 @@ public final class DriverDistractionExperimentalFeatureService extends
Context context,
ITimeSource timeSource,
ITimer timer) {
+ this(context, timeSource, timer, Looper.myLooper());
+ }
+
+ @VisibleForTesting
+ DriverDistractionExperimentalFeatureService(
+ Context context,
+ ITimeSource timeSource,
+ ITimer timer,
+ Looper looper) {
mContext = context;
mTimeSource = timeSource;
mExpiredDriverAwarenessTimer = timer;
@@ -211,6 +222,7 @@ public final class DriverDistractionExperimentalFeatureService extends
mClientDispatchHandlerThread = new HandlerThread(TAG);
mClientDispatchHandlerThread.start();
mClientDispatchHandler = new Handler(mClientDispatchHandlerThread.getLooper());
+ mLooper = looper;
}
@Override
@@ -220,7 +232,7 @@ public final class DriverDistractionExperimentalFeatureService extends
ComponentName touchComponent = new ComponentName(mContext,
TouchDriverAwarenessSupplier.class);
TouchDriverAwarenessSupplier touchSupplier = new TouchDriverAwarenessSupplier(mContext,
- new DriverAwarenessSupplierCallback(touchComponent));
+ new DriverAwarenessSupplierCallback(touchComponent), mLooper);
addDriverAwarenessSupplier(touchComponent, touchSupplier, /* priority= */ 0);
touchSupplier.onReady();
diff --git a/experimental/service/src/com/android/experimentalcar/GazeDriverAwarenessSupplier.java b/experimental/service/src/com/android/experimentalcar/GazeDriverAwarenessSupplier.java
index 7fbacbf5de..aeb31e7ef8 100644
--- a/experimental/service/src/com/android/experimentalcar/GazeDriverAwarenessSupplier.java
+++ b/experimental/service/src/com/android/experimentalcar/GazeDriverAwarenessSupplier.java
@@ -17,6 +17,7 @@
package com.android.experimentalcar;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.car.Car;
import android.car.experimental.DriverAwarenessEvent;
import android.car.experimental.DriverAwarenessSupplierService;
@@ -44,12 +45,17 @@ public class GazeDriverAwarenessSupplier extends DriverAwarenessSupplierService
/* Maximum allowable staleness before gaze data should be considered unreliable for attention
* monitoring, in milliseconds. */
- private static final long MAX_STALENESS_MILLIS = 500;
+ @VisibleForTesting
+ static final long MAX_STALENESS_MILLIS = 500;
- private final Context mContext;
private final Object mLock = new Object();
private final ITimeSource mTimeSource;
- private final GazeAttentionProcessor.Configuration mConfiguration;
+
+ @GuardedBy("mLock")
+ private GazeAttentionProcessor.Configuration mConfiguration;
+
+ @Nullable
+ private Context mContext;
@GuardedBy("mLock")
private Car mCar;
@@ -58,18 +64,27 @@ public class GazeDriverAwarenessSupplier extends DriverAwarenessSupplierService
private OccupantAwarenessManager mOasManager;
@GuardedBy("mLock")
- private final GazeAttentionProcessor mProcessor;
+ private GazeAttentionProcessor mProcessor;
- public GazeDriverAwarenessSupplier(Context context) {
- this(context, new SystemTimeSource());
+ /**
+ * Empty constructor allows system service creation.
+ */
+ public GazeDriverAwarenessSupplier() {
+ this(/* context= */ null, new SystemTimeSource());
}
@VisibleForTesting
GazeDriverAwarenessSupplier(Context context, ITimeSource timeSource) {
mContext = context;
mTimeSource = timeSource;
- mConfiguration = loadConfiguration();
- mProcessor = new GazeAttentionProcessor(mConfiguration);
+ }
+
+ @Override
+ public void onCreate() {
+ super.onCreate();
+ if (mContext == null) {
+ mContext = this;
+ }
}
/**
@@ -90,8 +105,9 @@ public class GazeDriverAwarenessSupplier extends DriverAwarenessSupplierService
@Override
public void onReady() {
synchronized (mLock) {
+ mConfiguration = loadConfiguration();
+ mProcessor = new GazeAttentionProcessor(mConfiguration);
mCar = Car.createCar(mContext);
-
if (mCar != null) {
if (mOasManager == null && mCar.isFeatureEnabled(Car.OCCUPANT_AWARENESS_SERVICE)) {
mOasManager =
diff --git a/experimental/service/src/com/android/experimentalcar/TouchDriverAwarenessSupplier.java b/experimental/service/src/com/android/experimentalcar/TouchDriverAwarenessSupplier.java
index 4ed17cda86..fa8bc34c70 100644
--- a/experimental/service/src/com/android/experimentalcar/TouchDriverAwarenessSupplier.java
+++ b/experimental/service/src/com/android/experimentalcar/TouchDriverAwarenessSupplier.java
@@ -84,9 +84,9 @@ public class TouchDriverAwarenessSupplier extends IDriverAwarenessSupplier.Stub
private InputEventReceiver mInputEventReceiver;
TouchDriverAwarenessSupplier(Context context,
- IDriverAwarenessSupplierCallback driverAwarenessSupplierCallback) {
+ IDriverAwarenessSupplierCallback driverAwarenessSupplierCallback, Looper looper) {
this(context, driverAwarenessSupplierCallback, Executors.newScheduledThreadPool(1),
- Looper.myLooper(), new SystemTimeSource());
+ looper, new SystemTimeSource());
}
@VisibleForTesting
diff --git a/experimental/tests/experimentalcarservice_unit_test/src/com/android/experimentalcar/DriverDistractionExperimentalFeatureServiceTest.java b/experimental/tests/experimentalcarservice_unit_test/src/com/android/experimentalcar/DriverDistractionExperimentalFeatureServiceTest.java
index bcdac80f42..4cc23882fd 100644
--- a/experimental/tests/experimentalcarservice_unit_test/src/com/android/experimentalcar/DriverDistractionExperimentalFeatureServiceTest.java
+++ b/experimental/tests/experimentalcarservice_unit_test/src/com/android/experimentalcar/DriverDistractionExperimentalFeatureServiceTest.java
@@ -20,6 +20,12 @@ import static com.android.experimentalcar.DriverDistractionExperimentalFeatureSe
import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.when;
+
import android.car.Car;
import android.car.VehiclePropertyIds;
import android.car.experimental.CarDriverDistractionManager;
@@ -30,25 +36,51 @@ import android.car.experimental.DriverDistractionChangeEvent;
import android.car.experimental.IDriverAwarenessSupplier;
import android.car.experimental.IDriverAwarenessSupplierCallback;
import android.car.hardware.CarPropertyValue;
+import android.content.ComponentName;
import android.content.Context;
+import android.content.ContextWrapper;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.content.res.Resources;
+import android.hardware.input.InputManager;
+import android.os.Handler;
+import android.os.IBinder;
import android.os.Looper;
import android.os.RemoteException;
+import android.os.UserHandle;
import android.util.Pair;
+import android.view.InputChannel;
+import android.view.InputMonitor;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.core.app.ApplicationProvider;
+import androidx.test.rule.ServiceTestRule;
+
+import com.android.internal.annotations.GuardedBy;
import org.junit.After;
import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;
+import java.util.ArrayList;
import java.util.Arrays;
+import java.util.List;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;
+import java.util.stream.Collectors;
@RunWith(MockitoJUnitRunner.class)
public class DriverDistractionExperimentalFeatureServiceTest {
+ private static final String TAG = "Car.DriverDistractionServiceTest";
+
+ private static final String SERVICE_BIND_GAZE_SUPPLIER =
+ "com.android.experimentalcar/.GazeDriverAwarenessSupplier";
+
private static final long INITIAL_TIME = 1000L;
private static final long PREFERRED_SUPPLIER_STALENESS = 10L;
@@ -98,6 +130,18 @@ public class DriverDistractionExperimentalFeatureServiceTest {
@Mock
private Context mContext;
+ @Mock
+ private InputManager mInputManager;
+
+ @Mock
+ private InputMonitor mInputMonitor;
+
+ @Mock
+ private IBinder mIBinder;
+
+ @Rule
+ public final ServiceTestRule serviceRule = new ServiceTestRule();
+
private DriverDistractionExperimentalFeatureService mService;
private CarDriverDistractionManager mManager;
private FakeTimeSource mTimeSource;
@@ -120,6 +164,58 @@ public class DriverDistractionExperimentalFeatureServiceTest {
}
@Test
+ public void testConfig_servicesCanBeBound() throws Exception {
+ Context realContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
+
+ // Get the actual suppliers defined in the config
+ String[] preferredDriverAwarenessSuppliers = realContext.getResources().getStringArray(
+ R.array.preferredDriverAwarenessSuppliers);
+
+ for (String supplierStringName : preferredDriverAwarenessSuppliers) {
+ ComponentName supplierComponent = ComponentName.unflattenFromString(supplierStringName);
+ Class<?> supplerClass = Class.forName(supplierComponent.getClassName());
+ Intent serviceIntent =
+ new Intent(ApplicationProvider.getApplicationContext(), supplerClass);
+
+ // Bind the service and grab a reference to the binder.
+ IBinder binder = serviceRule.bindService(serviceIntent);
+
+ assertThat(binder instanceof DriverAwarenessSupplierService.SupplierBinder).isTrue();
+ }
+ }
+
+ @Test
+ public void testInit_bindsToServicesInXmlConfig() throws Exception {
+ Context spyContext = spy(InstrumentationRegistry.getInstrumentation().getTargetContext());
+
+ // Mock the config to load a gaze supplier
+ Resources spyResources = spy(spyContext.getResources());
+ doReturn(spyResources).when(spyContext).getResources();
+ doReturn(new String[]{SERVICE_BIND_GAZE_SUPPLIER}).when(spyResources).getStringArray(
+ anyInt());
+
+ // Mock the InputManager that will be used by TouchDriverAwarenessSupplier
+ doReturn(mInputManager).when(spyContext).getSystemService(Context.INPUT_SERVICE);
+ when(mInputManager.monitorGestureInput(any(), anyInt())).thenReturn(mInputMonitor);
+ // InputChannel cannot be mocked because it passes to InputEventReceiver.
+ final InputChannel[] inputChannels = InputChannel.openInputChannelPair(TAG);
+ inputChannels[0].dispose();
+ when(mInputMonitor.getInputChannel()).thenReturn(inputChannels[1]);
+
+ // Create a special context that allows binders to succeed and keeps track of them. Doesn't
+ // actually start the intents / services.
+ ServiceLauncherContext serviceLauncherContext = new ServiceLauncherContext(spyContext);
+ mService = new DriverDistractionExperimentalFeatureService(serviceLauncherContext,
+ mTimeSource, mTimer, spyContext.getMainLooper());
+ mService.init();
+
+ serviceLauncherContext.assertBoundService(SERVICE_BIND_GAZE_SUPPLIER);
+
+ serviceLauncherContext.reset();
+ inputChannels[0].dispose();
+ }
+
+ @Test
public void testHandleDriverAwarenessEvent_updatesCurrentValue_withLatestEvent()
throws Exception {
mService.setDriverAwarenessSuppliers(Arrays.asList(
@@ -443,4 +539,51 @@ public class DriverDistractionExperimentalFeatureServiceTest {
supplier,
maxStaleness));
}
+
+
+ /** Overrides framework behavior to succeed on binding/starting processes. */
+ public class ServiceLauncherContext extends ContextWrapper {
+ private final Object mLock = new Object();
+
+ @GuardedBy("mLock")
+ private List<Intent> mBoundIntents = new ArrayList<>();
+
+ ServiceLauncherContext(Context base) {
+ super(base);
+ }
+
+ @Override
+ public boolean bindServiceAsUser(Intent service, ServiceConnection conn, int flags,
+ Handler handler, UserHandle user) {
+ synchronized (mLock) {
+ mBoundIntents.add(service);
+ }
+ conn.onServiceConnected(service.getComponent(), mIBinder);
+ return true;
+ }
+
+ @Override
+ public boolean bindServiceAsUser(Intent service, ServiceConnection conn,
+ int flags, UserHandle user) {
+ return bindServiceAsUser(service, conn, flags, null, user);
+ }
+
+ @Override
+ public void unbindService(ServiceConnection conn) {
+ // do nothing
+ }
+
+ void assertBoundService(String service) {
+ synchronized (mLock) {
+ assertThat(mBoundIntents.stream().map(Intent::getComponent).collect(
+ Collectors.toList())).contains(ComponentName.unflattenFromString(service));
+ }
+ }
+
+ void reset() {
+ synchronized (mLock) {
+ mBoundIntents.clear();
+ }
+ }
+ }
}
diff --git a/experimental/tests/experimentalcarservice_unit_test/src/com/android/experimentalcar/GazeDriverAwarenessSupplierTest.java b/experimental/tests/experimentalcarservice_unit_test/src/com/android/experimentalcar/GazeDriverAwarenessSupplierTest.java
index c1f7581ae8..042c40da37 100644
--- a/experimental/tests/experimentalcarservice_unit_test/src/com/android/experimentalcar/GazeDriverAwarenessSupplierTest.java
+++ b/experimental/tests/experimentalcarservice_unit_test/src/com/android/experimentalcar/GazeDriverAwarenessSupplierTest.java
@@ -16,6 +16,8 @@
package com.android.experimentalcar;
+import static com.google.common.truth.Truth.assertThat;
+
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
@@ -24,10 +26,15 @@ import android.car.experimental.DriverAwarenessEvent;
import android.car.occupantawareness.GazeDetection;
import android.car.occupantawareness.OccupantAwarenessDetection;
import android.content.Context;
+import android.content.Intent;
+import android.os.IBinder;
+import androidx.test.core.app.ApplicationProvider;
import androidx.test.platform.app.InstrumentationRegistry;
+import androidx.test.rule.ServiceTestRule;
import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.junit.MockitoJUnitRunner;
@@ -45,6 +52,9 @@ public class GazeDriverAwarenessSupplierTest {
private float mDecayRate;
private FakeTimeSource mTimeSource;
+ @Rule
+ public final ServiceTestRule serviceRule = new ServiceTestRule();
+
@Before
public void setUp() throws Exception {
mSpyContext = spy(InstrumentationRegistry.getInstrumentation().getTargetContext());
@@ -63,6 +73,17 @@ public class GazeDriverAwarenessSupplierTest {
}
@Test
+ public void testWithBoundService() throws Exception {
+ Intent serviceIntent =
+ new Intent(ApplicationProvider.getApplicationContext(),
+ GazeDriverAwarenessSupplier.class);
+
+ // Bind the service and grab a reference to the binder.
+ IBinder binder = serviceRule.bindService(serviceIntent);
+ assertThat(binder instanceof GazeDriverAwarenessSupplier.SupplierBinder).isTrue();
+ }
+
+ @Test
public void testonReady_initialCallbackIsGenerated() throws Exception {
// Supplier should return an initial callback after onReady().
mGazeSupplier.onReady();