Merge "Add a dummy launcher for CTS" into qt-dev
diff --git a/service/src/com/android/car/CarLocationService.java b/service/src/com/android/car/CarLocationService.java
index ad86741..43d4a46 100644
--- a/service/src/com/android/car/CarLocationService.java
+++ b/service/src/com/android/car/CarLocationService.java
@@ -125,6 +125,11 @@
}
});
break;
+ case CarPowerStateListener.SUSPEND_EXIT:
+ deleteCacheFile();
+ if (future != null) {
+ future.complete(null);
+ }
default:
// This service does not need to do any work for these events but should still
// notify the CarPowerManager that it may proceed.
@@ -153,7 +158,7 @@
boolean locationEnabled = locationManager.isLocationEnabled();
logd("isLocationEnabled(): " + locationEnabled);
if (!locationEnabled) {
- asyncOperation(() -> deleteCacheFile());
+ deleteCacheFile();
}
} else if (action == LocationManager.PROVIDERS_CHANGED_ACTION
&& shouldCheckLocationPermissions()) {
@@ -163,7 +168,7 @@
locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER);
logd("isProviderEnabled('gps'): " + gpsEnabled);
if (!gpsEnabled) {
- asyncOperation(() -> deleteCacheFile());
+ deleteCacheFile();
}
}
}
@@ -188,7 +193,6 @@
Location location = locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER);
if (location == null) {
logd("Not storing null location");
- deleteCacheFile();
} else {
logd("Storing location: " + location);
AtomicFile atomicFile = new AtomicFile(getLocationCacheFile());
@@ -250,6 +254,7 @@
long currentTime = System.currentTimeMillis();
if (location.getTime() + TTL_THIRTY_DAYS_MS < currentTime) {
logd("Location expired.");
+ deleteCacheFile();
} else {
location.setTime(currentTime);
long elapsedTime = SystemClock.elapsedRealtimeNanos();
@@ -297,7 +302,6 @@
}
}
reader.endObject();
- deleteCacheFile();
} catch (FileNotFoundException e) {
Log.d(TAG, "Location cache file not found.");
} catch (IOException e) {
diff --git a/service/src/com/android/car/CarMediaService.java b/service/src/com/android/car/CarMediaService.java
index bac93f9..5728bf2 100644
--- a/service/src/com/android/car/CarMediaService.java
+++ b/service/src/com/android/car/CarMediaService.java
@@ -477,7 +477,9 @@
// e.g. Assistant starts playback, user uses hardware button, etc.
mStartPlayback = false;
}
- mSharedPrefs.edit().putInt(PLAYBACK_STATE_KEY, state).apply();
+ if (mSharedPrefs != null) {
+ mSharedPrefs.edit().putInt(PLAYBACK_STATE_KEY, state).apply();
+ }
}
private void maybeRestartPlayback(PlaybackState state) {
diff --git a/service/src/com/android/car/ICarImpl.java b/service/src/com/android/car/ICarImpl.java
index 2f90d3d..244ee8b 100644
--- a/service/src/com/android/car/ICarImpl.java
+++ b/service/src/com/android/car/ICarImpl.java
@@ -449,7 +449,7 @@
+ " without permission " + android.Manifest.permission.DUMP);
return;
}
- if (args == null || args.length == 0) {
+ if (args == null || args.length == 0 || (args.length > 0 && "-a".equals(args[0]))) {
writer.println("*dump car service*");
writer.println("*FutureConfig, DEFAULT:" + FeatureConfiguration.DEFAULT);
@@ -702,19 +702,19 @@
switch (arg) {
case PARAM_ON_MODE:
mGarageModeService.forceStartGarageMode();
+ writer.println("Garage mode: " + mGarageModeService.isGarageModeActive());
break;
case PARAM_OFF_MODE:
mGarageModeService.stopAndResetGarageMode();
+ writer.println("Garage mode: " + mGarageModeService.isGarageModeActive());
break;
case PARAM_QUERY_MODE:
- // Nothing to do. Always query at the end anyway.
+ mGarageModeService.dump(writer);
break;
default:
writer.println("Unknown value. Valid argument: " + PARAM_ON_MODE + "|"
+ PARAM_OFF_MODE + "|" + PARAM_QUERY_MODE);
- return;
}
- writer.println("Garage mode: " + mGarageModeService.isGarageModeActive());
}
/**
diff --git a/service/src/com/android/car/garagemode/Controller.java b/service/src/com/android/car/garagemode/Controller.java
index 347ba73..d7235dd 100644
--- a/service/src/com/android/car/garagemode/Controller.java
+++ b/service/src/com/android/car/garagemode/Controller.java
@@ -28,6 +28,7 @@
import com.android.car.CarLocalServices;
import com.android.internal.annotations.VisibleForTesting;
+import java.util.List;
import java.util.concurrent.CompletableFuture;
/**
@@ -105,6 +106,13 @@
}
/**
+ * @return The names of the jobs that Garage Mode is waiting for
+ */
+ List<String> pendingGarageModeJobs() {
+ return mGarageMode.pendingJobs();
+ }
+
+ /**
* Wrapper method to send a broadcast
*
* @param i intent that contains broadcast data
diff --git a/service/src/com/android/car/garagemode/GarageMode.java b/service/src/com/android/car/garagemode/GarageMode.java
index b13045e..1165de5 100644
--- a/service/src/com/android/car/garagemode/GarageMode.java
+++ b/service/src/com/android/car/garagemode/GarageMode.java
@@ -63,6 +63,7 @@
private boolean mGarageModeActive;
private JobScheduler mJobScheduler;
+ private List<String> mPendingJobs = new ArrayList<>();
private Handler mHandler;
private Runnable mRunnable = new Runnable() {
@Override
@@ -129,6 +130,10 @@
return mGarageModeActive;
}
+ synchronized List<String> pendingJobs() {
+ return mPendingJobs;
+ }
+
void enterGarageMode(CompletableFuture<Void> future) {
LOG.d("Entering GarageMode");
synchronized (this) {
@@ -141,9 +146,7 @@
ArrayList<Integer> startedUsers =
CarLocalServices.getService(CarUserService.class).startAllBackgroundUsers();
synchronized (this) {
- for (Integer user : startedUsers) {
- mStartedBackgroundUsers.add(user);
- }
+ mStartedBackgroundUsers.addAll(startedUsers);
}
}
@@ -224,15 +227,22 @@
mHandler.removeCallbacks(mRunnable);
}
- private int numberOfJobsRunning() {
+ private synchronized int numberOfJobsRunning() {
List<JobInfo> startedJobs = mJobScheduler.getStartedJobs();
int count = 0;
+ List<String> currentPendingJobs = new ArrayList<>();
for (JobSnapshot snap : mJobScheduler.getAllJobSnapshots()) {
if (startedJobs.contains(snap.getJobInfo())
&& snap.getJobInfo().isRequireDeviceIdle()) {
+ currentPendingJobs.add(snap.getJobInfo().toString());
count++;
}
}
+ if (count > 0) {
+ // We have something pending, so update the list.
+ // (Otherwise, keep the old list.)
+ mPendingJobs = currentPendingJobs;
+ }
return count;
}
}
diff --git a/service/src/com/android/car/garagemode/GarageModeService.java b/service/src/com/android/car/garagemode/GarageModeService.java
index f28bb35..8527bc7 100644
--- a/service/src/com/android/car/garagemode/GarageModeService.java
+++ b/service/src/com/android/car/garagemode/GarageModeService.java
@@ -23,6 +23,7 @@
import com.android.internal.annotations.VisibleForTesting;
import java.io.PrintWriter;
+import java.util.List;
/**
* Main service container for car Garage Mode.
@@ -63,11 +64,24 @@
/**
* Dumps useful information about GarageMode
- * @param writer
+ * @param writer Where to dump the information
*/
@Override
public void dump(PrintWriter writer) {
- writer.println("GarageModeInProgress " + mController.isGarageModeActive());
+ boolean isActive = mController.isGarageModeActive();
+ writer.println("GarageModeInProgress " + isActive);
+ List<String> jobs = mController.pendingGarageModeJobs();
+ if (isActive) {
+ writer.println("GarageMode is currently waiting for " + jobs.size() + " jobs:");
+ } else {
+ writer.println("GarageMode was last waiting for " + jobs.size() + " jobs:");
+ }
+ // Dump the names of the jobs that GM is/was waiting for
+ int jobNumber = 1;
+ for (String job : jobs) {
+ writer.println(" " + jobNumber + ": " + job);
+ jobNumber++;
+ }
}
/**
diff --git a/service/src/com/android/car/hal/InputHalService.java b/service/src/com/android/car/hal/InputHalService.java
index f0993eb..d719510 100644
--- a/service/src/com/android/car/hal/InputHalService.java
+++ b/service/src/com/android/car/hal/InputHalService.java
@@ -140,12 +140,19 @@
KeyEvent.ACTION_DOWN : KeyEvent.ACTION_UP;
int code = v.value.int32Values.get(1);
int display = v.value.int32Values.get(2);
+ int indentsCount = v.value.int32Values.size() < 4 ? 1 : v.value.int32Values.get(3);
if (DBG) {
- Log.i(CarLog.TAG_INPUT, "hal event code:" + code + ", action:" + action +
- ", display:" + display);
+ Log.i(CarLog.TAG_INPUT, new StringBuilder()
+ .append("hal event code:").append(code)
+ .append(", action:").append(action)
+ .append(", display: ").append(display)
+ .append(", number of indents: ").append(indentsCount)
+ .toString());
}
-
- dispatchKeyEvent(listener, action, code, display);
+ while (indentsCount > 0) {
+ indentsCount--;
+ dispatchKeyEvent(listener, action, code, display);
+ }
}
}
diff --git a/service/src/com/android/car/trust/BleManager.java b/service/src/com/android/car/trust/BleManager.java
index fd319d6..24a3b79 100644
--- a/service/src/com/android/car/trust/BleManager.java
+++ b/service/src/com/android/car/trust/BleManager.java
@@ -225,6 +225,9 @@
if (Log.isLoggable(TAG, Log.DEBUG)) {
Log.d(TAG, "stopGattServer");
}
+ if (mBluetoothGatt != null) {
+ mBluetoothGatt.disconnect();
+ }
mGattServer.close();
mGattServer = null;
}
diff --git a/service/src/com/android/car/trust/CarTrustAgentEnrollmentService.java b/service/src/com/android/car/trust/CarTrustAgentEnrollmentService.java
index cb0f908..6743375 100644
--- a/service/src/com/android/car/trust/CarTrustAgentEnrollmentService.java
+++ b/service/src/com/android/car/trust/CarTrustAgentEnrollmentService.java
@@ -531,7 +531,7 @@
notifyEscrowTokenReceived(value);
break;
case ENROLLMENT_STATE_HANDLE:
- // TODO(danharms): React to ACK. Shut down server?
+ mCarTrustAgentBleManager.disconnectRemoteDevice();
break;
default:
// Should never get here
diff --git a/tests/carservice_unit_test/Android.mk b/tests/carservice_unit_test/Android.mk
index 3267fa6..6b715fc 100644
--- a/tests/carservice_unit_test/Android.mk
+++ b/tests/carservice_unit_test/Android.mk
@@ -57,8 +57,8 @@
frameworks-base-testutils \
truth-prebuilt
+# mockito-target-inline dependency
LOCAL_JNI_SHARED_LIBRARIES := \
- # mockito-target-inline dependency \
libdexmakerjvmtiagent \
include $(BUILD_PACKAGE)
diff --git a/tests/carservice_unit_test/src/com/android/car/CarLocationServiceTest.java b/tests/carservice_unit_test/src/com/android/car/CarLocationServiceTest.java
index f653709..4290354 100644
--- a/tests/carservice_unit_test/src/com/android/car/CarLocationServiceTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/CarLocationServiceTest.java
@@ -292,10 +292,10 @@
/**
* Test that the {@link CarLocationService} stores the {@link LocationManager}'s last known
- * location upon power state-changed SUSPEND events.
+ * location upon power state-changed SHUTDOWN_PREPARE events.
*/
@Test
- public void testStoresLocationUponStateChanged() throws Exception {
+ public void testStoresLocationUponShutdownPrepare() throws Exception {
long currentTime = System.currentTimeMillis();
long elapsedTime = SystemClock.elapsedRealtimeNanos();
Location timbuktu = new Location(LocationManager.GPS_PROVIDER);
@@ -367,12 +367,28 @@
mCarLocationService.init();
mCarLocationService.onReceive(mMockContext,
new Intent(LocationManager.MODE_CHANGED_ACTION));
- mLatch.await();
verify(mMockLocationManager, times(1)).isLocationEnabled();
assertFalse(getLocationCacheFile().exists());
}
/**
+ * Test that the {@link CarLocationService} deletes location_cache.json when the system resumes
+ * from suspend-to-ram.
+ */
+ @Test
+ public void testDeletesCacheFileUponSuspendExit() throws Exception {
+ when(mMockContext.getSystemService(Context.LOCATION_SERVICE))
+ .thenReturn(mMockLocationManager);
+ when(mMockLocationManager.isLocationEnabled()).thenReturn(false);
+ mCarLocationService.init();
+ CompletableFuture<Void> future = new CompletableFuture<>();
+ mCarLocationService.onStateChanged(CarPowerStateListener.SUSPEND_EXIT, future);
+ assertTrue(future.isDone());
+ verify(mMockLocationManager, times(0)).isLocationEnabled();
+ assertFalse(getLocationCacheFile().exists());
+ }
+
+ /**
* Test that the {@link CarLocationService} deletes location_cache.json when the GPS location
* provider is disabled.
*/
@@ -385,7 +401,6 @@
mCarLocationService.init();
mCarLocationService.onReceive(mMockContext,
new Intent(LocationManager.PROVIDERS_CHANGED_ACTION));
- mLatch.await();
verify(mMockLocationManager, times(1))
.isProviderEnabled(LocationManager.GPS_PROVIDER);
assertFalse(getLocationCacheFile().exists());
diff --git a/tests/carservice_unit_test/src/com/android/car/hal/InputHalServiceTest.java b/tests/carservice_unit_test/src/com/android/car/hal/InputHalServiceTest.java
index 32f8e1d..5cce922 100644
--- a/tests/carservice_unit_test/src/com/android/car/hal/InputHalServiceTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/hal/InputHalServiceTest.java
@@ -181,6 +181,28 @@
assertThat(event.getRepeatCount()).isEqualTo(0);
}
+ /**
+ * Test for handling rotary knob event.
+ */
+ @Test
+ public void handlesRepeatedKeyWithIndents() {
+ subscribeListener();
+ KeyEvent event = dispatchSingleEventWithIndents(KeyEvent.KEYCODE_VOLUME_UP, 5);
+ assertThat(event.getAction()).isEqualTo(KeyEvent.ACTION_DOWN);
+ assertThat(event.getKeyCode()).isEqualTo(KeyEvent.KEYCODE_VOLUME_UP);
+ assertThat(event.getEventTime()).isEqualTo(0L);
+ assertThat(event.getDownTime()).isEqualTo(0L);
+ assertThat(event.getRepeatCount()).isEqualTo(4);
+
+ when(mUptimeSupplier.getAsLong()).thenReturn(5L);
+ event = dispatchSingleEventWithIndents(KeyEvent.KEYCODE_VOLUME_UP, 5);
+ assertThat(event.getAction()).isEqualTo(KeyEvent.ACTION_DOWN);
+ assertThat(event.getKeyCode()).isEqualTo(KeyEvent.KEYCODE_VOLUME_UP);
+ assertThat(event.getEventTime()).isEqualTo(5L);
+ assertThat(event.getDownTime()).isEqualTo(5L);
+ assertThat(event.getRepeatCount()).isEqualTo(9);
+ }
+
@Test
public void handlesKeyUp_withoutKeyDown() {
subscribeListener();
@@ -237,4 +259,25 @@
reset(mInputListener);
return captor.getValue();
}
-}
+
+ private VehiclePropValue makeKeyPropValueWithIndents(int code, int indents) {
+ VehiclePropValue v = new VehiclePropValue();
+ v.prop = VehicleProperty.HW_KEY_INPUT;
+ // Only Key.down can have indents.
+ v.value.int32Values.add(VehicleHwKeyInputAction.ACTION_DOWN);
+ v.value.int32Values.add(code);
+ v.value.int32Values.add(DISPLAY);
+ v.value.int32Values.add(indents);
+ return v;
+ }
+
+ private KeyEvent dispatchSingleEventWithIndents(int code, int indents) {
+ ArgumentCaptor<KeyEvent> captor = ArgumentCaptor.forClass(KeyEvent.class);
+ reset(mInputListener);
+ mInputHalService.handleHalEvents(
+ ImmutableList.of(makeKeyPropValueWithIndents(code, indents)));
+ verify(mInputListener).onKeyEvent(captor.capture(), eq(DISPLAY));
+ reset(mInputListener);
+ return captor.getValue();
+ }
+}
\ No newline at end of file