Merge "Script to automatically generate vhal_consts_ for use in the emulator"
diff --git a/car-lib/src/android/car/vms/VmsLayer.java b/car-lib/src/android/car/vms/VmsLayer.java
index 702daec..afd0ae7 100644
--- a/car-lib/src/android/car/vms/VmsLayer.java
+++ b/car-lib/src/android/car/vms/VmsLayer.java
@@ -24,8 +24,10 @@
/**
* A VMS Layer which can be subscribed to by VMS clients.
- * Consists of the layer ID and the layer version.
+ * Consists of the layer ID and the layer major version.
*
+ * This class does not contain the minor version since all minor version are backward and forward
+ * compatible and should not be used for routing messages.
* @hide
*/
@FutureFeature
diff --git a/car-lib/src/android/car/vms/VmsLayerDependency.java b/car-lib/src/android/car/vms/VmsLayerDependency.java
index bb588eb..e14c7ec 100644
--- a/car-lib/src/android/car/vms/VmsLayerDependency.java
+++ b/car-lib/src/android/car/vms/VmsLayerDependency.java
@@ -80,6 +80,10 @@
}
};
+ public String toString() {
+ return "VmsLayerDependency{ Layer: " + mLayer + " Dependency: " + mDependency + "}";
+ }
+
@Override
public void writeToParcel(Parcel out, int flags) {
out.writeParcelable(mLayer, flags);
diff --git a/car-lib/src/android/car/vms/VmsLayersOffering.java b/car-lib/src/android/car/vms/VmsLayersOffering.java
index 12b3dd3..51a0b99 100644
--- a/car-lib/src/android/car/vms/VmsLayersOffering.java
+++ b/car-lib/src/android/car/vms/VmsLayersOffering.java
@@ -55,6 +55,11 @@
};
@Override
+ public String toString() {
+ return "VmsLayersOffering{" + mDependencies+ "}";
+ }
+
+ @Override
public void writeToParcel(Parcel out, int flags) {
out.writeParcelableList(mDependencies, flags);
}
diff --git a/car-lib/src/android/car/vms/VmsPublisherClientService.java b/car-lib/src/android/car/vms/VmsPublisherClientService.java
index 2743ff1..85fd2c2 100644
--- a/car-lib/src/android/car/vms/VmsPublisherClientService.java
+++ b/car-lib/src/android/car/vms/VmsPublisherClientService.java
@@ -106,6 +106,41 @@
if (DBG) {
Log.d(TAG, "Publishing for layer : " + layer);
}
+
+ IBinder token = getTokenForPublisherServiceThreadSafe();
+
+ try {
+ mVmsPublisherService.publish(token, layer, payload);
+ return true;
+ } catch (RemoteException e) {
+ Log.e(TAG, "unable to publish message: " + payload, e);
+ }
+ return false;
+ }
+
+ /**
+ * Uses the VmsPublisherService binder to set the layers offering.
+ *
+ * @param offering the layers that the publisher may publish.
+ * @return if the call to VmsPublisherService.setLayersOffering was successful.
+ */
+ public final boolean setLayersOffering(VmsLayersOffering offering) {
+ if (DBG) {
+ Log.d(TAG, "Setting layers offering : " + offering);
+ }
+
+ IBinder token = getTokenForPublisherServiceThreadSafe();
+
+ try {
+ mVmsPublisherService.setLayersOffering(token, offering);
+ return true;
+ } catch (RemoteException e) {
+ Log.e(TAG, "unable to set layers offering: " + offering, e);
+ }
+ return false;
+ }
+
+ private IBinder getTokenForPublisherServiceThreadSafe() {
if (mVmsPublisherService == null) {
throw new IllegalStateException("VmsPublisherService not set.");
}
@@ -117,13 +152,7 @@
if (token == null) {
throw new IllegalStateException("VmsPublisherService does not have a valid token.");
}
- try {
- mVmsPublisherService.publish(token, layer, payload);
- return true;
- } catch (RemoteException e) {
- Log.e(TAG, "unable to publish message: " + payload, e);
- }
- return false;
+ return token;
}
/**
diff --git a/car-lib/src/android/car/vms/VmsSubscriberManager.java b/car-lib/src/android/car/vms/VmsSubscriberManager.java
index 7c37b2d..640948a 100644
--- a/car-lib/src/android/car/vms/VmsSubscriberManager.java
+++ b/car-lib/src/android/car/vms/VmsSubscriberManager.java
@@ -162,8 +162,7 @@
* @param layer the layer to subscribe to.
* @throws IllegalStateException if the listener was not set via {@link #setListener}.
*/
- public void subscribe(VmsLayer layer)
- throws CarNotConnectedException {
+ public void subscribe(VmsLayer layer) throws CarNotConnectedException {
if (DBG) {
Log.d(TAG, "Subscribing to layer: " + layer);
}
@@ -186,8 +185,7 @@
}
}
- public void subscribeAll()
- throws CarNotConnectedException {
+ public void subscribeAll() throws CarNotConnectedException {
if (DBG) {
Log.d(TAG, "Subscribing passively to all data messages");
}
@@ -239,7 +237,7 @@
}
}
- public void unsubscribeAll() throws CarNotConnectedException {
+ public void unsubscribeAll() {
if (DBG) {
Log.d(TAG, "Unsubscribing passively from all data messages");
}
@@ -248,17 +246,17 @@
listener = mListener;
}
if (listener == null) {
- Log.w(TAG, "subscribe: listener was not set, " +
+ Log.w(TAG, "unsubscribeAll: listener was not set, " +
"setListener must be called first.");
throw new IllegalStateException("Listener was not set.");
}
try {
mVmsSubscriberService.removeVmsSubscriberClientPassiveListener(mIListener);
} catch (RemoteException e) {
- Log.e(TAG, "Could not connect: ", e);
- throw new CarNotConnectedException(e);
+ Log.e(TAG, "Failed to unregister subscriber ", e);
+ // ignore
} catch (IllegalStateException ex) {
- Car.checkCarNotConnectedExceptionFromCarService(ex);
+ Car.hideCarNotConnectedExceptionFromCarService(ex);
}
}
diff --git a/car-usb-handler/res/values/strings.xml b/car-usb-handler/res/values/strings.xml
index 2242648..be1e7a2 100644
--- a/car-usb-handler/res/values/strings.xml
+++ b/car-usb-handler/res/values/strings.xml
@@ -26,4 +26,5 @@
<string name="usb_pref_delete_yes">Yes</string>
<string name="usb_pref_delete_cancel">Cancel</string>
<string name="usb_resolving_handlers">Getting supported handlers</string>
+ <string name="usb_unknown_device">Unknown USB device</string>
</resources>
diff --git a/car-usb-handler/src/android/car/usb/handler/UsbDeviceSettings.java b/car-usb-handler/src/android/car/usb/handler/UsbDeviceSettings.java
index 5084414..288f598 100644
--- a/car-usb-handler/src/android/car/usb/handler/UsbDeviceSettings.java
+++ b/car-usb-handler/src/android/car/usb/handler/UsbDeviceSettings.java
@@ -17,7 +17,6 @@
import android.content.ComponentName;
import android.hardware.usb.UsbDevice;
-import com.android.internal.util.Preconditions;
/**
* Settings for USB device.
@@ -34,8 +33,6 @@
private boolean mDefaultHandler;
UsbDeviceSettings(String serialNumber, int vid, int pid) {
- Preconditions.checkNotNull(serialNumber);
-
mSerialNumber = serialNumber;
mVid = vid;
mPid = pid;
@@ -96,7 +93,15 @@
* Checks if setting matches {@code UsbDevice}.
*/
public boolean matchesDevice(UsbDevice device) {
- return getSerialNumber().equals(device.getSerialNumber());
+ String deviceSerial = device.getSerialNumber();
+ if (AoapInterface.isDeviceInAoapMode(device)) {
+ return mAoap && deviceSerial.equals(mSerialNumber);
+ } else if (deviceSerial == null) {
+ return mVid == device.getVendorId() && mPid == device.getProductId();
+ } else {
+ return mVid == device.getVendorId() && mPid == device.getProductId()
+ && deviceSerial.equals(mSerialNumber);
+ }
}
/**
diff --git a/car-usb-handler/src/android/car/usb/handler/UsbHostController.java b/car-usb-handler/src/android/car/usb/handler/UsbHostController.java
index b705928..5c61a98 100644
--- a/car-usb-handler/src/android/car/usb/handler/UsbHostController.java
+++ b/car-usb-handler/src/android/car/usb/handler/UsbHostController.java
@@ -68,10 +68,10 @@
public void onReceive(Context context, Intent intent) {
if (UsbManager.ACTION_USB_DEVICE_DETACHED.equals(intent.getAction())) {
UsbDevice device = intent.<UsbDevice>getParcelableExtra(UsbManager.EXTRA_DEVICE);
- unsetActiveDeviceIfSerialMatch(device);
+ unsetActiveDeviceIfMatch(device);
} else if (UsbManager.ACTION_USB_DEVICE_ATTACHED.equals(intent.getAction())) {
UsbDevice device = intent.<UsbDevice>getParcelableExtra(UsbManager.EXTRA_DEVICE);
- setActiveDeviceIfSerialMatch(device);
+ setActiveDeviceIfMatch(device);
}
}
};
@@ -79,9 +79,6 @@
@GuardedBy("this")
private UsbDevice mActiveDevice;
- @GuardedBy("this")
- private String mProcessingDeviceSerial;
-
public UsbHostController(Context context, UsbHostControllerCallbacks callbacks) {
mContext = context;
mCallback = callbacks;
@@ -96,17 +93,17 @@
}
- private synchronized void setActiveDeviceIfSerialMatch(UsbDevice device) {
- if (device != null && device.getSerialNumber() != null
- && device.getSerialNumber().equals(mProcessingDeviceSerial)) {
+ private synchronized void setActiveDeviceIfMatch(UsbDevice device) {
+ if (mActiveDevice != null && device != null
+ && UsbUtil.isDevicesMatching(device, mActiveDevice)) {
mActiveDevice = device;
}
}
- private synchronized void unsetActiveDeviceIfSerialMatch(UsbDevice device) {
+ private synchronized void unsetActiveDeviceIfMatch(UsbDevice device) {
mHandler.requestDeviceRemoved();
- if (mActiveDevice != null && mActiveDevice.getSerialNumber() != null
- && mActiveDevice.getSerialNumber().equals(device.getSerialNumber())) {
+ if (mActiveDevice != null && device != null
+ && UsbUtil.isDevicesMatching(device, mActiveDevice)) {
mActiveDevice = null;
}
}
@@ -114,7 +111,6 @@
private synchronized boolean startDeviceProcessingIfNull(UsbDevice device) {
if (mActiveDevice == null) {
mActiveDevice = device;
- mProcessingDeviceSerial = device.getSerialNumber();
return true;
}
return false;
@@ -122,7 +118,6 @@
private synchronized void stopDeviceProcessing() {
mActiveDevice = null;
- mProcessingDeviceSerial = null;
}
private synchronized UsbDevice getActiveDevice() {
@@ -131,8 +126,22 @@
private boolean deviceMatchedActiveDevice(UsbDevice device) {
UsbDevice activeDevice = getActiveDevice();
- return activeDevice != null && activeDevice.getSerialNumber() != null
- && activeDevice.getSerialNumber().equals(device.getSerialNumber());
+ return activeDevice != null && UsbUtil.isDevicesMatching(activeDevice, device);
+ }
+
+ private String generateTitle() {
+ String manufacturer = mActiveDevice.getManufacturerName();
+ String product = mActiveDevice.getProductName();
+ if (manufacturer == null && product == null) {
+ return mContext.getString(R.string.usb_unknown_device);
+ }
+ if (manufacturer != null && product != null) {
+ return manufacturer + " " + product;
+ }
+ if (manufacturer != null) {
+ return manufacturer;
+ }
+ return product;
}
/**
@@ -147,7 +156,7 @@
mCallback.optionsUpdated(mEmptyList);
mCallback.processingStateChanged(true);
- UsbDeviceSettings settings = mUsbSettingsStorage.getSettings(device.getSerialNumber());
+ UsbDeviceSettings settings = mUsbSettingsStorage.getSettings(device);
if (settings != null && mUsbResolver.dispatch(
mActiveDevice, settings.getHandler(), settings.getAoap())) {
if (LOCAL_LOGV) {
@@ -156,7 +165,7 @@
}
return;
}
- mCallback.titleChanged(device.getManufacturerName() + " " + device.getProductName());
+ mCallback.titleChanged(generateTitle());
mUsbResolver.resolve(device);
}
diff --git a/car-usb-handler/src/android/car/usb/handler/UsbSettingsStorage.java b/car-usb-handler/src/android/car/usb/handler/UsbSettingsStorage.java
index 157c92f..1b251f8 100644
--- a/car-usb-handler/src/android/car/usb/handler/UsbSettingsStorage.java
+++ b/car-usb-handler/src/android/car/usb/handler/UsbSettingsStorage.java
@@ -22,6 +22,7 @@
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
+import android.hardware.usb.UsbDevice;
import android.util.Log;
import java.util.ArrayList;
import java.util.List;
@@ -47,26 +48,43 @@
mDbHelper = new UsbSettingsDbHelper(context);
}
+ private Cursor queryFor(SQLiteDatabase db, UsbDevice device) {
+ String serial = device.getSerialNumber();
+ String selection;
+ String[] selectionArgs;
+ if (AoapInterface.isDeviceInAoapMode(device)) {
+ selection = COLUMN_SERIAL + " = ? AND " + COLUMN_AOAP + " = 1";
+ selectionArgs = new String[] {serial};
+ } else if (serial == null) {
+ selection = COLUMN_SERIAL + " IS NULL AND "
+ + COLUMN_VID + " = ? AND " + COLUMN_PID + " = ?";
+ selectionArgs = new String[] {
+ Integer.toString(device.getVendorId()),
+ Integer.toString(device.getProductId())};
+ } else {
+ selection =
+ COLUMN_SERIAL + " = ? AND " + COLUMN_VID + " = ? AND " + COLUMN_PID + " = ?";
+ selectionArgs = new String[] {
+ device.getSerialNumber(),
+ Integer.toString(device.getVendorId()),
+ Integer.toString(device.getProductId())};
+ }
+ return db.query(TABLE_USB_SETTINGS, null, selection, selectionArgs, null, null, null);
+ }
+
/**
* Returns settings for {@serialNumber} or null if it doesn't exist.
*/
@Nullable
- public UsbDeviceSettings getSettings(String serialNumber) {
+ public UsbDeviceSettings getSettings(UsbDevice device) {
try (SQLiteDatabase db = mDbHelper.getReadableDatabase();
- Cursor resultCursor = db.query(
- TABLE_USB_SETTINGS,
- null,
- COLUMN_SERIAL + " = ?",
- new String[]{serialNumber},
- null,
- null,
- null)) {
+ Cursor resultCursor = queryFor(db, device)) {
if (resultCursor.getCount() > 1) {
- throw new RuntimeException("Querying for serial number: " + serialNumber
+ throw new RuntimeException("Querying for device: " + device
+ " returned " + resultCursor.getCount() + " results");
}
if (resultCursor.getCount() == 0) {
- Log.w(TAG, "Usb setting missing for device serial: " + serialNumber);
+ Log.w(TAG, "Usb setting missing for device: " + device);
return null;
}
List<UsbDeviceSettings> settings = constructSettings(resultCursor);
@@ -168,7 +186,7 @@
private static class UsbSettingsDbHelper extends SQLiteOpenHelper {
- private static final int DATABASE_VERSION = 1;
+ private static final int DATABASE_VERSION = 2;
private static final String DATABASE_NAME = "usb_devices.db";
UsbSettingsDbHelper(Context context) {
@@ -177,20 +195,47 @@
@Override
public void onCreate(SQLiteDatabase db) {
- db.execSQL("CREATE TABLE " + TABLE_USB_SETTINGS + " ("
+ createTable(db, TABLE_USB_SETTINGS);
+ createSerialIndex(db);
+ }
+
+ private void createTable(SQLiteDatabase db, String tableName) {
+ db.execSQL("CREATE TABLE " + tableName + " ("
+ COLUMN_SERIAL + " TEXT,"
+ COLUMN_VID + " INTEGER,"
+ COLUMN_PID + " INTEGER,"
+ COLUMN_NAME + " TEXT, "
+ COLUMN_HANDLER + " TEXT,"
+ COLUMN_AOAP + " INTEGER,"
- + COLUMN_DEFAULT_HANDLER + " INTEGER," + "PRIMARY KEY (" + COLUMN_SERIAL
+ + COLUMN_DEFAULT_HANDLER + " INTEGER,"
+ + "PRIMARY KEY (" + COLUMN_SERIAL + ", " + COLUMN_VID + ", " + COLUMN_PID
+ "))");
}
+ private void createSerialIndex(SQLiteDatabase db) {
+ db.execSQL("CREATE INDEX " + TABLE_USB_SETTINGS + "_" + COLUMN_SERIAL + " ON "
+ + TABLE_USB_SETTINGS + "(" + COLUMN_SERIAL + ")");
+ }
+
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
- // Do nothing at this point. Not required for v1 database.
+ for (; oldVersion != newVersion; oldVersion++) {
+ switch (oldVersion) {
+ case 1:
+ String tempTableName = "temp_" + TABLE_USB_SETTINGS;
+ createTable(db, tempTableName);
+ db.execSQL("INSERT INTO " + tempTableName
+ + " SELECT * FROM " + TABLE_USB_SETTINGS);
+ db.execSQL("DROP TABLE " + TABLE_USB_SETTINGS);
+ db.execSQL("ALTER TABLE " + tempTableName + " RENAME TO "
+ + TABLE_USB_SETTINGS);
+ createSerialIndex(db);
+ break;
+ default:
+ throw new IllegalArgumentException(
+ "Unknown database version " + oldVersion);
+ }
+ }
}
}
}
diff --git a/evs/app/EvsStateControl.cpp b/evs/app/EvsStateControl.cpp
index abed1e5..ec29e39 100644
--- a/evs/app/EvsStateControl.cpp
+++ b/evs/app/EvsStateControl.cpp
@@ -21,7 +21,7 @@
#include <stdio.h>
#include <string.h>
-#include <android/log.h>
+#include <log/log.h>
// TODO: Seems like it'd be nice if the Vehicle HAL provided such helpers (but how & where?)
diff --git a/obd2-lib/src/com/android/car/obd2/Obd2Connection.java b/obd2-lib/src/com/android/car/obd2/Obd2Connection.java
index bfdb9c0..577b798 100644
--- a/obd2-lib/src/com/android/car/obd2/Obd2Connection.java
+++ b/obd2-lib/src/com/android/car/obd2/Obd2Connection.java
@@ -72,6 +72,10 @@
return true;
}
+ public boolean isConnected() {
+ return mConnection.isConnected();
+ }
+
static int toDigitValue(char c) {
if ((c >= '0') && (c <= '9')) return c - '0';
switch (c) {
diff --git a/obd2-lib/src/com/android/car/obd2/Obd2LiveFrameGenerator.java b/obd2-lib/src/com/android/car/obd2/Obd2LiveFrameGenerator.java
index 121b54a..3fffd22 100644
--- a/obd2-lib/src/com/android/car/obd2/Obd2LiveFrameGenerator.java
+++ b/obd2-lib/src/com/android/car/obd2/Obd2LiveFrameGenerator.java
@@ -56,6 +56,16 @@
mFloatCommands.add(
Obd2Command.getLiveFrameCommand(
Obd2Command.getFloatCommand(pid))));
+ Log.i(
+ TAG,
+ String.format(
+ "connectionPids = %s\napiIntegerPids=%s\napiFloatPids = %s\n"
+ + "mIntegerCommands = %s\nmFloatCommands = %s\n",
+ connectionPids,
+ apiIntegerPids,
+ apiFloatPids,
+ mIntegerCommands,
+ mFloatCommands));
}
public JsonWriter generate(JsonWriter jsonWriter) throws IOException {
diff --git a/service/src/com/android/car/ICarImpl.java b/service/src/com/android/car/ICarImpl.java
index eae070c..55f93ca 100644
--- a/service/src/com/android/car/ICarImpl.java
+++ b/service/src/com/android/car/ICarImpl.java
@@ -47,16 +47,6 @@
public static final String INTERNAL_SYSTEM_ACTIVITY_MONITORING_SERVICE =
"system_activity_monitoring";
- // load jni for all services here
- static {
- try {
- System.loadLibrary("jni_car_service");
- } catch (UnsatisfiedLinkError ex) {
- // Unable to load native library when loaded from the testing framework.
- Log.e(CarLog.TAG_SERVICE, "Failed to load jni_car_service library: " + ex.getMessage());
- }
- }
-
private final Context mContext;
private final VehicleHal mHal;
diff --git a/service/src/com/android/car/VmsLayersAvailability.java b/service/src/com/android/car/VmsLayersAvailability.java
index 5f5ac30..d6e89f2 100644
--- a/service/src/com/android/car/VmsLayersAvailability.java
+++ b/service/src/com/android/car/VmsLayersAvailability.java
@@ -83,7 +83,7 @@
/**
* Returns a collection of all the layers which may be published.
*/
- public Collection<VmsLayer> getAvailableLayers() {
+ public Set<VmsLayer> getAvailableLayers() {
synchronized (mLock) {
return mAvailableLayers;
}
@@ -93,7 +93,7 @@
* Returns a collection of all the layers which publishers could have published if the
* dependencies were satisfied.
*/
- public Collection<VmsLayer> getUnavailableLayers() {
+ public Set<VmsLayer> getUnavailableLayers() {
synchronized (mLock) {
return mUnavailableLayers;
}
diff --git a/service/src/com/android/car/VmsPublisherService.java b/service/src/com/android/car/VmsPublisherService.java
index 8f7fba3..8bb0167 100644
--- a/service/src/com/android/car/VmsPublisherService.java
+++ b/service/src/com/android/car/VmsPublisherService.java
@@ -56,7 +56,6 @@
private final Context mContext;
private final VmsHalService mHal;
private final VmsPublisherManager mPublisherManager;
- private final Map<IBinder, VmsLayersOffering> mRawOffering = new HashMap<>();
public VmsPublisherService(Context context, VmsHalService hal) {
mContext = context;
@@ -96,12 +95,7 @@
@Override
public void setLayersOffering(IBinder token, VmsLayersOffering offering) {
- // Store the raw dependencies
- mRawOffering.put(token, offering);
-
- //TODO(asafro): Calculate the new available layers
-
- //TODO(asafro): Notify the subscribers that there is a change in availability
+ mHal.setPublisherLayersOffering(token, offering);
}
// Implements IVmsPublisherService interface.
diff --git a/service/src/com/android/car/VmsRouting.java b/service/src/com/android/car/VmsRouting.java
index fc2cbac..2829cc0 100644
--- a/service/src/com/android/car/VmsRouting.java
+++ b/service/src/com/android/car/VmsRouting.java
@@ -20,16 +20,14 @@
import android.car.vms.IVmsSubscriberClient;
import android.car.vms.VmsLayer;
import android.car.vms.VmsSubscriptionState;
-
+import com.android.internal.annotations.GuardedBy;
import java.util.ArrayList;
-import java.util.HashSet;
import java.util.HashMap;
+import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
-import com.android.internal.annotations.GuardedBy;
-
/**
* Manages all the VMS subscriptions:
* + Subscriptions to data messages of individual layer + version.
@@ -62,6 +60,7 @@
* @param layer the layer subscribing to.
*/
public void addSubscription(IVmsSubscriberClient listener, VmsLayer layer) {
+ //TODO(b/36902947): revise if need to sync, and return value.
synchronized (mLock) {
++mSequenceNumber;
// Get or create the list of listeners for layer and version.
@@ -142,8 +141,8 @@
}
/**
- * Returns all the listeners for a layer and version. This include the subscribers which
- * explicitly subscribed to this layer and version and the promiscuous subscribers.
+ * Returns a list with all the listeners for a layer and version. This include the subscribers
+ * which explicitly subscribed to this layer and version and the promiscuous subscribers.
*
* @param layer to get listeners to.
* @return a list of the listeners.
@@ -162,6 +161,21 @@
}
/**
+ * Returns a list with all the listeners.
+ */
+ public Set<IVmsSubscriberClient> getAllListeners() {
+ Set<IVmsSubscriberClient> listeners = new HashSet<>();
+ synchronized (mLock) {
+ for (VmsLayer layer : mLayerSubscriptions.keySet()) {
+ listeners.addAll(mLayerSubscriptions.get(layer));
+ }
+ // Add the promiscuous subscribers.
+ listeners.addAll(mPromiscuousSubscribers);
+ }
+ return listeners;
+ }
+
+ /**
* Checks if a listener is subscribed to any messages.
* @param listener that may have subscription.
* @return true if the listener uis subscribed to messages.
diff --git a/service/src/com/android/car/VmsSubscriberService.java b/service/src/com/android/car/VmsSubscriberService.java
index 97ed27f..eabb0a6 100644
--- a/service/src/com/android/car/VmsSubscriberService.java
+++ b/service/src/com/android/car/VmsSubscriberService.java
@@ -269,18 +269,13 @@
// Implements VmsHalSubscriberListener interface
@Override
- public void onChange(VmsLayer layer, byte[] payload) {
+ public void onDataMessage(VmsLayer layer, byte[] payload) {
if(DBG) {
Log.d(TAG, "Publishing a message for layer: " + layer);
}
Set<IVmsSubscriberClient> listeners = mHal.getListeners(layer);
- // If there are no listeners we're done.
- if ((listeners == null)) {
- return;
- }
-
for (IVmsSubscriberClient subscriber : listeners) {
try {
subscriber.onVmsMessageReceived(layer, payload);
@@ -290,6 +285,24 @@
Log.e(TAG, "onVmsMessageReceived calling failed: ", e);
}
}
+ }
+ @Override
+ public void onLayersAvaiabilityChange(List<VmsLayer> availableLayers) {
+ if(DBG) {
+ Log.d(TAG, "Publishing layers availability change: " + availableLayers);
+ }
+
+ Set<IVmsSubscriberClient> listeners = mHal.getAllListeners();
+
+ for (IVmsSubscriberClient subscriber : listeners) {
+ try {
+ subscriber.onLayersAvailabilityChange(availableLayers);
+ } catch (RemoteException e) {
+ // If we could not send a record, its likely the connection snapped. Let the binder
+ // death handle the situation.
+ Log.e(TAG, "onLayersAvailabilityChange calling failed: ", e);
+ }
+ }
}
}
diff --git a/service/src/com/android/car/hal/DiagnosticHalService.java b/service/src/com/android/car/hal/DiagnosticHalService.java
index 84e3678..48bc7e9 100644
--- a/service/src/com/android/car/hal/DiagnosticHalService.java
+++ b/service/src/com/android/car/hal/DiagnosticHalService.java
@@ -114,8 +114,41 @@
}
@Override
+ public synchronized void init() {
+ for (int i = 0; i < mVehiclePropertyToConfig.size(); ++i) {
+ int propertyId = mVehiclePropertyToConfig.keyAt(i);
+ switch (propertyId) {
+ case VehicleProperty.OBD2_LIVE_FRAME:
+ case VehicleProperty.OBD2_FREEZE_FRAME:
+ case VehicleProperty.OBD2_FREEZE_FRAME_INFO:
+ Log.i(CarLog.TAG_DIAGNOSTIC,
+ String.format("subscribing to property 0x%x", propertyId));
+ mHal.subscribeProperty(this, propertyId);
+ break;
+ default:
+ break;
+ }
+ }
+ super.init();
+ }
+
+ @Override
public synchronized void release() {
super.release();
+ for (int i = 0; i < mVehiclePropertyToConfig.size(); ++i) {
+ int propertyId = mVehiclePropertyToConfig.keyAt(i);
+ switch (propertyId) {
+ case VehicleProperty.OBD2_LIVE_FRAME:
+ case VehicleProperty.OBD2_FREEZE_FRAME:
+ case VehicleProperty.OBD2_FREEZE_FRAME_INFO:
+ Log.i(CarLog.TAG_DIAGNOSTIC,
+ String.format("unsubscribing from property 0x%x", propertyId));
+ mHal.unsubscribeProperty(this, propertyId);
+ break;
+ default:
+ break;
+ }
+ }
mDiagnosticCapabilities.clear();
}
diff --git a/service/src/com/android/car/hal/VmsHalService.java b/service/src/com/android/car/hal/VmsHalService.java
index c23f36a..8a36117 100644
--- a/service/src/com/android/car/hal/VmsHalService.java
+++ b/service/src/com/android/car/hal/VmsHalService.java
@@ -22,24 +22,32 @@
import android.car.annotation.FutureFeature;
import android.car.vms.IVmsSubscriberClient;
import android.car.vms.VmsLayer;
+import android.car.vms.VmsLayerDependency;
+import android.car.vms.VmsLayersOffering;
import android.car.vms.VmsSubscriptionState;
import android.hardware.automotive.vehicle.V2_0.VehiclePropConfig;
import android.hardware.automotive.vehicle.V2_0.VehiclePropValue;
import android.hardware.automotive.vehicle.V2_1.VehicleProperty;
-import android.hardware.automotive.vehicle.V2_1.VmsMessageIntegerValuesIndex;
+import android.hardware.automotive.vehicle.V2_1.VmsBaseMessageIntegerValuesIndex;
import android.hardware.automotive.vehicle.V2_1.VmsMessageType;
-import android.os.SystemClock;
+import android.hardware.automotive.vehicle.V2_1.VmsOfferingMessageIntegerValuesIndex;
+import android.hardware.automotive.vehicle.V2_1.VmsSimpleMessageIntegerValuesIndex;
+import android.os.Binder;
+import android.os.IBinder;
import android.util.Log;
import com.android.car.CarLog;
+import com.android.car.VmsLayersAvailability;
import com.android.car.VmsRouting;
import com.android.internal.annotations.GuardedBy;
import java.io.PrintWriter;
import java.util.ArrayList;
-import java.util.Arrays;
import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
+import java.util.Map;
import java.util.Set;
import java.util.concurrent.CopyOnWriteArrayList;
@@ -49,25 +57,27 @@
*/
@FutureFeature
public class VmsHalService extends HalServiceBase {
+
private static final boolean DBG = true;
private static final int HAL_PROPERTY_ID = VehicleProperty.VEHICLE_MAP_SERVICE;
private static final String TAG = "VmsHalService";
- private static final Set<Integer> SUPPORTED_MESSAGE_TYPES =
- new HashSet<Integer>(
- Arrays.asList(
- VmsMessageType.SUBSCRIBE,
- VmsMessageType.UNSUBSCRIBE,
- VmsMessageType.DATA));
private boolean mIsSupported = false;
private CopyOnWriteArrayList<VmsHalPublisherListener> mPublisherListeners =
new CopyOnWriteArrayList<>();
private CopyOnWriteArrayList<VmsHalSubscriberListener> mSubscriberListeners =
new CopyOnWriteArrayList<>();
+
+ private final IBinder mHalPublisherToken = new Binder();
private final VehicleHal mVehicleHal;
- @GuardedBy("mLock")
- private VmsRouting mRouting = new VmsRouting();
- private final Object mLock = new Object();
+
+ private final Object mRoutingLock = new Object();
+ private final VmsRouting mRouting = new VmsRouting();
+ private final Object mAvailabilityLock = new Object();
+ @GuardedBy("mAvailabilityLock")
+ private final Map<IBinder, VmsLayersOffering> mOfferings = new HashMap<>();
+ @GuardedBy("mAvailabilityLock")
+ private final VmsLayersAvailability mAvailableLayers = new VmsLayersAvailability();
/**
* The VmsPublisherService implements this interface to receive data from the HAL.
@@ -80,7 +90,11 @@
* The VmsSubscriberService implements this interface to receive data from the HAL.
*/
public interface VmsHalSubscriberListener {
- void onChange(VmsLayer layer, byte[] payload);
+ // Notify listener on a data Message.
+ void onDataMessage(VmsLayer layer, byte[] payload);
+
+ // Notify listener on a change in available layers.
+ void onLayersAvaiabilityChange(List<VmsLayer> availableLayers);
}
/**
@@ -110,22 +124,22 @@
}
public void addSubscription(IVmsSubscriberClient listener, VmsLayer layer) {
- synchronized (mLock) {
+ boolean firstSubscriptionForLayer = false;
+ synchronized (mRoutingLock) {
// Check if publishers need to be notified about this change in subscriptions.
- boolean firstSubscriptionForLayer = !mRouting.hasLayerSubscriptions(layer);
+ firstSubscriptionForLayer = !mRouting.hasLayerSubscriptions(layer);
// Add the listeners subscription to the layer
mRouting.addSubscription(listener, layer);
-
- // Notify the publishers
- if (firstSubscriptionForLayer) {
- notifyPublishers(layer, true);
- }
+ }
+ if (firstSubscriptionForLayer) {
+ notifyPublishers(layer, true);
}
}
public void removeSubscription(IVmsSubscriberClient listener, VmsLayer layer) {
- synchronized (mLock) {
+ boolean layerHasSubscribers = true;
+ synchronized (mRoutingLock) {
if (!mRouting.hasLayerSubscriptions(layer)) {
Log.i(TAG, "Trying to remove a layer with no subscription: " + layer);
return;
@@ -135,67 +149,72 @@
mRouting.removeSubscription(listener, layer);
// Check if publishers need to be notified about this change in subscriptions.
- boolean layerHasSubscribers = mRouting.hasLayerSubscriptions(layer);
-
- // Notify the publishers
- if (!layerHasSubscribers) {
- notifyPublishers(layer, false);
- }
+ layerHasSubscribers = mRouting.hasLayerSubscriptions(layer);
+ }
+ if (!layerHasSubscribers) {
+ notifyPublishers(layer, false);
}
}
public void addSubscription(IVmsSubscriberClient listener) {
- synchronized (mLock) {
+ synchronized (mRoutingLock) {
mRouting.addSubscription(listener);
}
}
public void removeSubscription(IVmsSubscriberClient listener) {
- synchronized (mLock) {
+ synchronized (mRoutingLock) {
mRouting.removeSubscription(listener);
}
}
public void removeDeadListener(IVmsSubscriberClient listener) {
- synchronized (mLock) {
+ synchronized (mRoutingLock) {
mRouting.removeDeadListener(listener);
}
}
public Set<IVmsSubscriberClient> getListeners(VmsLayer layer) {
- synchronized (mLock) {
+ synchronized (mRoutingLock) {
return mRouting.getListeners(layer);
}
}
+ public Set<IVmsSubscriberClient> getAllListeners() {
+ synchronized (mRoutingLock) {
+ return mRouting.getAllListeners();
+ }
+ }
+
public boolean isHalSubscribed(VmsLayer layer) {
- synchronized (mLock) {
+ synchronized (mRoutingLock) {
return mRouting.isHalSubscribed(layer);
}
}
public VmsSubscriptionState getSubscriptionState() {
- synchronized (mLock) {
+ synchronized (mRoutingLock) {
return mRouting.getSubscriptionState();
}
}
public void addHalSubscription(VmsLayer layer) {
- synchronized (mLock) {
+ boolean firstSubscriptionForLayer = true;
+ synchronized (mRoutingLock) {
// Check if publishers need to be notified about this change in subscriptions.
- boolean firstSubscriptionForLayer = !mRouting.hasLayerSubscriptions(layer);
+ firstSubscriptionForLayer = !mRouting.hasLayerSubscriptions(layer);
// Add the listeners subscription to the layer
mRouting.addHalSubscription(layer);
-
- if (firstSubscriptionForLayer) {
- notifyPublishers(layer, true);
- }
+ }
+ if (firstSubscriptionForLayer) {
+ notifyPublishers(layer, true);
}
}
public void removeHalSubscription(VmsLayer layer) {
- synchronized (mLock) {
+ boolean layerHasSubscribers = true;
+ synchronized (mRoutingLock) {
if (!mRouting.hasLayerSubscriptions(layer)) {
Log.i(TAG, "Trying to remove a layer with no subscription: " + layer);
return;
@@ -205,21 +224,35 @@
mRouting.removeHalSubscription(layer);
// Check if publishers need to be notified about this change in subscriptions.
- boolean layerHasSubscribers = mRouting.hasLayerSubscriptions(layer);
-
- // Notify the publishers
- if (!layerHasSubscribers) {
- notifyPublishers(layer, false);
- }
+ layerHasSubscribers = mRouting.hasLayerSubscriptions(layer);
+ }
+ if (!layerHasSubscribers) {
+ notifyPublishers(layer, false);
}
}
public boolean containsListener(IVmsSubscriberClient listener) {
- synchronized (mLock) {
+ synchronized (mRoutingLock) {
return mRouting.containsListener(listener);
}
}
+ public void setPublisherLayersOffering(IBinder publisherToken, VmsLayersOffering offering){
+ Set<VmsLayer> availableLayers = Collections.EMPTY_SET;
+ synchronized (mAvailabilityLock) {
+ updateOffering(publisherToken, offering);
+ availableLayers = mAvailableLayers.getAvailableLayers();
+ }
+ notifySubscribers(availableLayers);
+ }
+
+ public Set<VmsLayer> getAvailableLayers() {
+ //TODO(b/36872877): wrap available layers in VmsAvailabilityState similar to VmsSubscriptionState.
+ synchronized (mAvailabilityLock) {
+ return mAvailableLayers.getAvailableLayers();
+ }
+ }
+
/**
* Notify all the publishers and the HAL on subscription changes regardless of who triggered
* the change.
@@ -227,18 +260,31 @@
* @param layer layer which is being subscribed to or unsubscribed from.
* @param hasSubscribers indicates if the notification is for subscription or unsubscription.
*/
- public void notifyPublishers(VmsLayer layer, boolean hasSubscribers) {
- synchronized (mLock) {
- // notify the HAL
- setSubscriptionRequest(layer, hasSubscribers);
+ private void notifyPublishers(VmsLayer layer, boolean hasSubscribers) {
+ // notify the HAL
+ setSubscriptionRequest(layer, hasSubscribers);
- // Notify the App publishers
- for (VmsHalPublisherListener listener : mPublisherListeners) {
- // Besides the list of layers, also a timestamp is provided to the clients.
- // They should ignore any notification with a timestamp that is older than the most
- // recent timestamp they have seen.
- listener.onChange(getSubscriptionState());
- }
+ // Notify the App publishers
+ for (VmsHalPublisherListener listener : mPublisherListeners) {
+ // Besides the list of layers, also a timestamp is provided to the clients.
+ // They should ignore any notification with a timestamp that is older than the most
+ // recent timestamp they have seen.
+ listener.onChange(getSubscriptionState());
+ }
+ }
+
+ /**
+ * Notify all the subscribers and the HAL on layers availability change.
+ *
+ * @param availableLayers the layers which publishers claim they made publish.
+ */
+ private void notifySubscribers(Set<VmsLayer> availableLayers) {
+ // notify the HAL
+ setAvailableLayers(availableLayers);
+
+ // Notify the App subscribers
+ for (VmsHalSubscriberListener listener : mSubscriberListeners) {
+ listener.onLayersAvaiabilityChange(new ArrayList<>(availableLayers));
}
}
@@ -288,42 +334,128 @@
}
for (VehiclePropValue v : values) {
ArrayList<Integer> vec = v.value.int32Values;
- int messageType = vec.get(VmsMessageIntegerValuesIndex.VMS_MESSAGE_TYPE);
- int layerId = vec.get(VmsMessageIntegerValuesIndex.VMS_LAYER_ID);
- int layerVersion = vec.get(VmsMessageIntegerValuesIndex.VMS_LAYER_VERSION);
-
- // Check if message type is supported.
- if (!SUPPORTED_MESSAGE_TYPES.contains(messageType)) {
- throw new IllegalArgumentException("Unexpected message type. " +
- "Expecting: " + SUPPORTED_MESSAGE_TYPES +
- ". Got: " + messageType);
-
- }
+ int messageType = vec.get(VmsBaseMessageIntegerValuesIndex.VMS_MESSAGE_TYPE);
if (DBG) {
- Log.d(TAG,
- "Received message for Type: " + messageType +
- " Layer Id: " + layerId +
- "Version: " + layerVersion);
+ Log.d(TAG, "Handling VMS message type: " + messageType);
}
- // This is a data message intended for subscribers.
- if (messageType == VmsMessageType.DATA) {
- // Get the payload.
- byte[] payload = toByteArray(v.value.bytes);
-
- // Send the message.
- for (VmsHalSubscriberListener listener : mSubscriberListeners) {
- listener.onChange(new VmsLayer(layerId, layerVersion), payload);
- }
- } else if (messageType == VmsMessageType.SUBSCRIBE) {
- addHalSubscription(new VmsLayer(layerId, layerVersion));
- } else {
- // messageType == VmsMessageType.UNSUBSCRIBE
- removeHalSubscription(new VmsLayer(layerId, layerVersion));
+ switch(messageType) {
+ case VmsMessageType.DATA:
+ handleDataEvent(vec, toByteArray(v.value.bytes));
+ break;
+ case VmsMessageType.SUBSCRIBE:
+ handleSubscribeEvent(vec);
+ break;
+ case VmsMessageType.UNSUBSCRIBE:
+ handleUnsubscribeEvent(vec);
+ break;
+ case VmsMessageType.OFFERING:
+ handleOfferingEvent(vec);
+ break;
+ case VmsMessageType.AVAILABILITY:
+ handleAvailabilityEvent();
+ break;
+ default:
+ throw new IllegalArgumentException("Unexpected message type: " + messageType);
}
}
}
+ private void handleDataEvent(List<Integer> integerValues, byte[] payload) {
+ int layerId = integerValues.get(VmsSimpleMessageIntegerValuesIndex.VMS_LAYER_ID);
+ int layerVersion = integerValues.get(VmsSimpleMessageIntegerValuesIndex.VMS_LAYER_VERSION);
+ if (DBG) {
+ Log.d(TAG,
+ "Handling a data event for Layer Id: " + layerId +
+ " Version: " + layerVersion);
+ }
+
+ // Send the message.
+ for (VmsHalSubscriberListener listener : mSubscriberListeners) {
+ listener.onDataMessage(new VmsLayer(layerId, layerVersion), payload);
+ }
+ }
+
+ private void handleSubscribeEvent(List<Integer> integerValues) {
+ int layerId = integerValues.get(VmsSimpleMessageIntegerValuesIndex.VMS_LAYER_ID);
+ int layerVersion = integerValues.get(VmsSimpleMessageIntegerValuesIndex.VMS_LAYER_VERSION);
+ if (DBG) {
+ Log.d(TAG,
+ "Handling a subscribe event for Layer Id: " + layerId +
+ " Version: " + layerVersion);
+ }
+ addHalSubscription(new VmsLayer(layerId, layerVersion));
+ }
+
+ private void handleUnsubscribeEvent(List<Integer> integerValues) {
+ int layerId = integerValues.get(VmsSimpleMessageIntegerValuesIndex.VMS_LAYER_ID);
+ int layerVersion = integerValues.get(VmsSimpleMessageIntegerValuesIndex.VMS_LAYER_VERSION);
+ if (DBG) {
+ Log.d(TAG,
+ "Handling an unsubscribe event for Layer Id: " + layerId +
+ " Version: " + layerVersion);
+ }
+ removeHalSubscription(new VmsLayer(layerId, layerVersion));
+ }
+
+ private void handleOfferingEvent(List<Integer> integerValues) {
+ int numLayersDependencies =
+ integerValues.get(VmsOfferingMessageIntegerValuesIndex.VMS_NUMBER_OF_LAYERS_DEPENDENCIES);
+ int idx = VmsOfferingMessageIntegerValuesIndex.FIRST_DEPENDENCIES_INDEX;
+
+ List<VmsLayerDependency> offeredLayers = new ArrayList<>();
+
+ // An offering is layerId, LayerVersion, NumDeps, <LayerId, LayerVersion> X NumDeps.
+ for (int i = 0; i < numLayersDependencies; i++) {
+ int layerId = integerValues.get(idx++);
+ int layerVersion = integerValues.get(idx++);
+ VmsLayer offeredLayer = new VmsLayer(layerId, layerVersion);
+
+ int numDependenciesForLayer = integerValues.get(idx++);
+ if (numDependenciesForLayer == 0) {
+ offeredLayers.add(new VmsLayerDependency(offeredLayer));
+ } else {
+ Set<VmsLayer> dependencies = new HashSet<>();
+
+ for (int j = 0; j < numDependenciesForLayer; j++) {
+ int dependantLayerId = integerValues.get(idx++);
+ int dependantLayerVersion = integerValues.get(idx++);
+
+ VmsLayer dependantLayer = new VmsLayer(dependantLayerId, dependantLayerVersion);
+ dependencies.add(dependantLayer);
+ }
+ offeredLayers.add(new VmsLayerDependency(offeredLayer, dependencies));
+ }
+ }
+ // Store the HAL offering.
+ VmsLayersOffering offering = new VmsLayersOffering(offeredLayers);
+ synchronized (mAvailabilityLock) {
+ updateOffering(mHalPublisherToken, offering);
+ }
+ }
+
+ private void handleAvailabilityEvent() {
+ synchronized (mAvailabilityLock) {
+ Collection<VmsLayer> availableLayers = mAvailableLayers.getAvailableLayers();
+ VehiclePropValue vehiclePropertyValue = toVehiclePropValue(
+ VmsMessageType.AVAILABILITY, availableLayers);
+ setPropertyValue(vehiclePropertyValue);
+ }
+ }
+
+ private void updateOffering(IBinder publisherToken, VmsLayersOffering offering) {
+ Set<VmsLayer> availableLayers = Collections.EMPTY_SET;
+ synchronized (mAvailabilityLock) {
+ mOfferings.put(publisherToken, offering);
+
+ // Update layers availability.
+ mAvailableLayers.setPublishersOffering(mOfferings.values());
+
+ availableLayers = mAvailableLayers.getAvailableLayers();
+ }
+ notifySubscribers(availableLayers);
+ }
+
@Override
public void dump(PrintWriter writer) {
writer.println(TAG);
@@ -339,14 +471,21 @@
*/
public boolean setSubscriptionRequest(VmsLayer layer, boolean hasSubscribers) {
VehiclePropValue vehiclePropertyValue = toVehiclePropValue(
- hasSubscribers ? VmsMessageType.SUBSCRIBE : VmsMessageType.UNSUBSCRIBE, layer);
+ hasSubscribers ? VmsMessageType.SUBSCRIBE : VmsMessageType.UNSUBSCRIBE, layer);
return setPropertyValue(vehiclePropertyValue);
}
public boolean setDataMessage(VmsLayer layer, byte[] payload) {
VehiclePropValue vehiclePropertyValue = toVehiclePropValue(VmsMessageType.DATA,
- layer,
- payload);
+ layer,
+ payload);
+ return setPropertyValue(vehiclePropertyValue);
+ }
+
+ public boolean setAvailableLayers(Collection<VmsLayer> availableLayers) {
+ VehiclePropValue vehiclePropertyValue = toVehiclePropValue(VmsMessageType.AVAILABILITY,
+ availableLayers);
+
return setPropertyValue(vehiclePropertyValue);
}
@@ -361,13 +500,20 @@
}
/** Creates a {@link VehiclePropValue} */
- private static VehiclePropValue toVehiclePropValue(int messageType, VmsLayer layer) {
+ private static VehiclePropValue toVehiclePropValue(int messageType) {
VehiclePropValue vehicleProp = new VehiclePropValue();
vehicleProp.prop = HAL_PROPERTY_ID;
vehicleProp.areaId = VehicleAreaType.VEHICLE_AREA_TYPE_NONE;
VehiclePropValue.RawValue v = vehicleProp.value;
v.int32Values.add(messageType);
+ return vehicleProp;
+ }
+
+ /** Creates a {@link VehiclePropValue} */
+ private static VehiclePropValue toVehiclePropValue(int messageType, VmsLayer layer) {
+ VehiclePropValue vehicleProp = toVehiclePropValue(messageType);
+ VehiclePropValue.RawValue v = vehicleProp.value;
v.int32Values.add(layer.getId());
v.int32Values.add(layer.getVersion());
return vehicleProp;
@@ -375,8 +521,8 @@
/** Creates a {@link VehiclePropValue} with payload */
private static VehiclePropValue toVehiclePropValue(int messageType,
- VmsLayer layer,
- byte[] payload) {
+ VmsLayer layer,
+ byte[] payload) {
VehiclePropValue vehicleProp = toVehiclePropValue(messageType, layer);
VehiclePropValue.RawValue v = vehicleProp.value;
v.bytes.ensureCapacity(payload.length);
@@ -385,4 +531,18 @@
}
return vehicleProp;
}
-}
\ No newline at end of file
+
+ /** Creates a {@link VehiclePropValue} with payload */
+ private static VehiclePropValue toVehiclePropValue(int messageType,
+ Collection<VmsLayer> layers) {
+ VehiclePropValue vehicleProp = toVehiclePropValue(messageType);
+ VehiclePropValue.RawValue v = vehicleProp.value;
+ int numLayers = layers.size();
+ v.int32Values.add(numLayers);
+ for (VmsLayer layer : layers) {
+ v.int32Values.add(layer.getId());
+ v.int32Values.add(layer.getVersion());
+ }
+ return vehicleProp;
+ }
+}
diff --git a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/KitchenSinkActivity.java b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/KitchenSinkActivity.java
index ae4a0aa..98bfc21 100644
--- a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/KitchenSinkActivity.java
+++ b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/KitchenSinkActivity.java
@@ -197,8 +197,7 @@
};
public DrawerAdapter() {
- super(KitchenSinkActivity.this, true /* showDisabledOnListOnEmpty */,
- true /* smallLayout */);
+ super(KitchenSinkActivity.this, true /* showDisabledOnListOnEmpty */);
setTitle(getString(R.string.app_title));
}
diff --git a/tests/carservice_test/src/com/android/car/test/VmsPublisherClientMockService.java b/tests/carservice_test/src/com/android/car/test/VmsPublisherClientMockService.java
index fbea6d2..cc73421 100644
--- a/tests/carservice_test/src/com/android/car/test/VmsPublisherClientMockService.java
+++ b/tests/carservice_test/src/com/android/car/test/VmsPublisherClientMockService.java
@@ -18,8 +18,12 @@
import android.car.annotation.FutureFeature;
import android.car.vms.VmsLayer;
+import android.car.vms.VmsLayerDependency;
+import android.car.vms.VmsLayersOffering;
import android.car.vms.VmsPublisherClientService;
import android.car.vms.VmsSubscriptionState;
+import java.util.List;
+import java.util.ArrayList;
/**
* This service is launched during the tests in VmsPublisherSubscriberTest. It publishes a property
@@ -36,12 +40,14 @@
public void onVmsSubscriptionChange(VmsSubscriptionState subscriptionState) {
// Case when the publisher finished initialization before the subscription request.
publishIfNeeded(subscriptionState);
+ declareOffering(subscriptionState);
}
@Override
public void onVmsPublisherServiceReady() {
// Case when the subscription request was sent before the publisher was ready.
- publishIfNeeded(getSubscriptions());
+ VmsSubscriptionState subscriptionState = getSubscriptions();
+ publishIfNeeded(subscriptionState);
}
private void publishIfNeeded(VmsSubscriptionState subscriptionState) {
@@ -51,4 +57,13 @@
}
}
}
+
+ private void declareOffering(VmsSubscriptionState subscriptionState) {
+ List<VmsLayerDependency> dependencies = new ArrayList<>();
+ for( VmsLayer layer : subscriptionState.getLayers()) {
+ dependencies.add(new VmsLayerDependency(layer));
+ }
+ VmsLayersOffering offering = new VmsLayersOffering(dependencies);
+ setLayersOffering(offering);
+ }
}
diff --git a/tests/carservice_test/src/com/android/car/test/VmsPublisherClientServiceTest.java b/tests/carservice_test/src/com/android/car/test/VmsPublisherClientServiceTest.java
index aa1431e..c22f63a 100644
--- a/tests/carservice_test/src/com/android/car/test/VmsPublisherClientServiceTest.java
+++ b/tests/carservice_test/src/com/android/car/test/VmsPublisherClientServiceTest.java
@@ -28,7 +28,8 @@
import android.hardware.automotive.vehicle.V2_0.VehiclePropertyAccess;
import android.hardware.automotive.vehicle.V2_0.VehiclePropertyChangeMode;
import android.hardware.automotive.vehicle.V2_1.VehicleProperty;
-import android.hardware.automotive.vehicle.V2_1.VmsMessageIntegerValuesIndex;
+import android.hardware.automotive.vehicle.V2_1.VmsBaseMessageIntegerValuesIndex;
+import android.hardware.automotive.vehicle.V2_1.VmsSimpleMessageIntegerValuesIndex;
import android.hardware.automotive.vehicle.V2_1.VmsMessageType;
import android.test.suitebuilder.annotation.MediumTest;
import android.util.Log;
@@ -139,9 +140,9 @@
// the semaphore will not be released.
assertTrue(mHalHandlerSemaphore.tryAcquire(2L, TimeUnit.SECONDS));
VehiclePropValue.RawValue rawValue = mHalHandler.getValue().value;
- int messageType = rawValue.int32Values.get(VmsMessageIntegerValuesIndex.VMS_MESSAGE_TYPE);
- int layerId = rawValue.int32Values.get(VmsMessageIntegerValuesIndex.VMS_LAYER_ID);
- int layerVersion = rawValue.int32Values.get(VmsMessageIntegerValuesIndex.VMS_LAYER_VERSION);
+ int messageType = rawValue.int32Values.get(VmsSimpleMessageIntegerValuesIndex.VMS_MESSAGE_TYPE);
+ int layerId = rawValue.int32Values.get(VmsSimpleMessageIntegerValuesIndex.VMS_LAYER_ID);
+ int layerVersion = rawValue.int32Values.get(VmsSimpleMessageIntegerValuesIndex.VMS_LAYER_VERSION);
byte[] payload = new byte[rawValue.bytes.size()];
for (int i = 0; i < rawValue.bytes.size(); ++i) {
payload[i] = rawValue.bytes.get(i);
@@ -161,7 +162,7 @@
// If this is the data message release the semaphone so the test can continue.
ArrayList<Integer> int32Values = value.value.int32Values;
- if (int32Values.get(VmsMessageIntegerValuesIndex.VMS_MESSAGE_TYPE) ==
+ if (int32Values.get(VmsBaseMessageIntegerValuesIndex.VMS_MESSAGE_TYPE) ==
VmsMessageType.DATA) {
mHalHandlerSemaphore.release();
}
diff --git a/tests/carservice_test/src/com/android/car/test/VmsPublisherSubscriberTest.java b/tests/carservice_test/src/com/android/car/test/VmsPublisherSubscriberTest.java
index e86b3fa..20fa0b6 100644
--- a/tests/carservice_test/src/com/android/car/test/VmsPublisherSubscriberTest.java
+++ b/tests/carservice_test/src/com/android/car/test/VmsPublisherSubscriberTest.java
@@ -32,7 +32,9 @@
import com.android.car.vehiclehal.test.MockedVehicleHal;
+import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Collections;
import java.util.List;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;
@@ -45,10 +47,12 @@
public static final VmsLayer LAYER = new VmsLayer(LAYER_ID, LAYER_VERSION);
public static final byte[] PAYLOAD = new byte[]{2, 3, 5, 7, 11, 13, 17};
+ private static final List<VmsLayer> AVAILABLE_LAYERS = new ArrayList<>(Arrays.asList(LAYER));
private HalHandler mHalHandler;
// Used to block until a value is propagated to the TestListener.onVmsMessageReceived.
private Semaphore mSubscriberSemaphore;
+ private Semaphore mAvailabilitySemaphore;
@Override
protected synchronized void configureMockedHal() {
@@ -92,6 +96,7 @@
if (!VmsTestUtils.canRunTest(TAG)) return;
super.setUp();
mSubscriberSemaphore = new Semaphore(0);
+ mAvailabilitySemaphore = new Semaphore(0);
}
@Override
@@ -121,12 +126,30 @@
assertTrue(Arrays.equals(PAYLOAD, listener.getPayload()));
}
+ /**
+ * The Mock service offers all the subscribed layers as available layers, so in this
+ * test the listener subscribes to a layer and verifies that it gets the notification that it
+ * is available.
+ */
+ public void testAvailability() throws Exception {
+ if (!VmsTestUtils.canRunTest(TAG)) return;
+ VmsSubscriberManager vmsSubscriberManager = (VmsSubscriberManager) getCar().getCarManager(
+ Car.VMS_SUBSCRIBER_SERVICE);
+ TestListener listener = new TestListener();
+ vmsSubscriberManager.setListener(listener);
+ vmsSubscriberManager.subscribe(LAYER);
+
+ assertTrue(mAvailabilitySemaphore.tryAcquire(2L, TimeUnit.SECONDS));
+ assertEquals(AVAILABLE_LAYERS, listener.getAvailalbeLayers());
+ }
+
private class HalHandler implements MockedVehicleHal.VehicleHalPropertyHandler {
}
private class TestListener implements VmsSubscriberManager.VmsSubscriberClientListener {
private VmsLayer mLayer;
private byte[] mPayload;
+ private List<VmsLayer> mAvailableLayers;
@Override
public void onVmsMessageReceived(VmsLayer layer, byte[] payload) {
@@ -139,9 +162,9 @@
@Override
public void onLayersAvailabilityChange(List<VmsLayer> availableLayers) {
- //TODO(asafro): test availability changes on publisher update when logic is implemented.
- // for that need to add Offering support in VmsPublisherClientService
- // and update VmsPublisherClientMockService
+ assertEquals(AVAILABLE_LAYERS, availableLayers);
+ mAvailableLayers = availableLayers;
+ mAvailabilitySemaphore.release();
}
@Override
@@ -156,5 +179,9 @@
public byte[] getPayload() {
return mPayload;
}
+
+ public List<VmsLayer> getAvailalbeLayers() {
+ return mAvailableLayers;
+ }
}
}
diff --git a/tests/carservice_test/src/com/android/car/test/VmsSubscriberManagerTest.java b/tests/carservice_test/src/com/android/car/test/VmsSubscriberManagerTest.java
index 79cddad..063d5cf 100644
--- a/tests/carservice_test/src/com/android/car/test/VmsSubscriberManagerTest.java
+++ b/tests/carservice_test/src/com/android/car/test/VmsSubscriberManagerTest.java
@@ -32,6 +32,7 @@
import android.util.Log;
import com.android.car.vehiclehal.VehiclePropValueBuilder;
import com.android.car.vehiclehal.test.MockedVehicleHal.VehicleHalPropertyHandler;
+import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.Semaphore;
@@ -46,6 +47,20 @@
private static final VmsLayer SUBSCRIPTION_LAYER = new VmsLayer(SUBSCRIPTION_LAYER_ID,
SUBSCRIPTION_LAYER_VERSION);
+ private static final int SUBSCRIPTION_DEPENDANT_LAYER_ID_1 = 4;
+ private static final int SUBSCRIPTION_DEPENDANT_LAYER_VERSION_1 = 5;
+ private static final VmsLayer SUBSCRIPTION_DEPENDANT_LAYER_1 =
+ new VmsLayer(SUBSCRIPTION_DEPENDANT_LAYER_ID_1, SUBSCRIPTION_DEPENDANT_LAYER_VERSION_1);
+
+ private static final int SUBSCRIPTION_DEPENDANT_LAYER_ID_2 = 6;
+ private static final int SUBSCRIPTION_DEPENDANT_LAYER_VERSION_2 = 7;
+ private static final VmsLayer SUBSCRIPTION_DEPENDANT_LAYER_2 =
+ new VmsLayer(SUBSCRIPTION_DEPENDANT_LAYER_ID_2, SUBSCRIPTION_DEPENDANT_LAYER_VERSION_2);
+
+ private static final int SUBSCRIPTION_UNSUPPORTED_LAYER_ID = 100;
+ private static final int SUBSCRIPTION_UNSUPPORTED_LAYER_VERSION = 200;
+
+
private HalHandler mHalHandler;
// Used to block until the HAL property is updated in HalHandler.onPropertySet.
private Semaphore mHalHandlerSemaphore;
@@ -132,6 +147,120 @@
assertTrue(Arrays.equals(expectedPayload, listener.getPayload()));
}
+
+ // Test injecting a value in the HAL and verifying it propagates to a subscriber.
+ public void testSimpleAvailableLayers() throws Exception {
+ if (!VmsTestUtils.canRunTest(TAG)) return;
+ VmsSubscriberManager vmsSubscriberManager = (VmsSubscriberManager) getCar().getCarManager(
+ Car.VMS_SUBSCRIBER_SERVICE);
+ TestListener listener = new TestListener();
+ vmsSubscriberManager.setListener(listener);
+ vmsSubscriberManager.subscribe(SUBSCRIPTION_LAYER);
+
+ // Inject a value and wait for its callback in TestListener.onLayersAvailabilityChange.
+ VehiclePropValue v = VehiclePropValueBuilder.newBuilder(VehicleProperty.VEHICLE_MAP_SERVICE)
+ .setAreaId(VehicleAreaType.VEHICLE_AREA_TYPE_NONE)
+ .setTimestamp(SystemClock.elapsedRealtimeNanos())
+ .build();
+ /*
+ Offering:
+ Layer | Dependency
+ ====================
+ (2, 3) | {}
+
+ Expected availability:
+ {(2, 3)}
+ */
+ v.value.int32Values.addAll(
+ Arrays.asList(
+ VmsMessageType.OFFERING, // MessageType
+ 1, // Number of offered layers
+
+ SUBSCRIPTION_LAYER_ID,
+ SUBSCRIPTION_LAYER_VERSION,
+ 0 // number of dependencies for layer
+ )
+ );
+
+ assertEquals(0, mSubscriberSemaphore.availablePermits());
+
+ List<VmsLayer> expectedAvailableLayers = new ArrayList<>(Arrays.asList(SUBSCRIPTION_LAYER));
+
+ getMockedVehicleHal().injectEvent(v);
+ assertTrue(mSubscriberSemaphore.tryAcquire(2L, TimeUnit.SECONDS));
+ assertEquals(expectedAvailableLayers, listener.getAvailableLayers());
+ }
+
+ // Test injecting a value in the HAL and verifying it propagates to a subscriber.
+ public void testComplexAvailableLayers() throws Exception {
+ if (!VmsTestUtils.canRunTest(TAG)) return;
+ VmsSubscriberManager vmsSubscriberManager = (VmsSubscriberManager) getCar().getCarManager(
+ Car.VMS_SUBSCRIBER_SERVICE);
+ TestListener listener = new TestListener();
+ vmsSubscriberManager.setListener(listener);
+ vmsSubscriberManager.subscribe(SUBSCRIPTION_LAYER);
+
+ // Inject a value and wait for its callback in TestListener.onLayersAvailabilityChange.
+ VehiclePropValue v = VehiclePropValueBuilder.newBuilder(VehicleProperty.VEHICLE_MAP_SERVICE)
+ .setAreaId(VehicleAreaType.VEHICLE_AREA_TYPE_NONE)
+ .setTimestamp(SystemClock.elapsedRealtimeNanos())
+ .build();
+ /*
+ Offering:
+ Layer | Dependency
+ ====================
+ (2, 3) | {}
+ (4, 5) | {(2, 3)}
+ (6, 7) | {(2, 3), (4, 5)}
+ (6, 7) | {(100, 200)}
+
+ Expected availability:
+ {(2, 3), (4, 5), (6, 7)}
+ */
+
+ v.value.int32Values.addAll(
+ Arrays.asList(
+ VmsMessageType.OFFERING, // MessageType
+ 4, // Number of offered layers
+
+ SUBSCRIPTION_LAYER_ID,
+ SUBSCRIPTION_LAYER_VERSION,
+ 0, // number of dependencies for layer
+
+ SUBSCRIPTION_DEPENDANT_LAYER_ID_1,
+ SUBSCRIPTION_DEPENDANT_LAYER_VERSION_1,
+ 1, // number of dependencies for layer
+ SUBSCRIPTION_LAYER_ID,
+ SUBSCRIPTION_LAYER_VERSION,
+
+ SUBSCRIPTION_DEPENDANT_LAYER_ID_2,
+ SUBSCRIPTION_DEPENDANT_LAYER_VERSION_2,
+ 2, // number of dependencies for layer
+ SUBSCRIPTION_LAYER_ID,
+ SUBSCRIPTION_LAYER_VERSION,
+ SUBSCRIPTION_DEPENDANT_LAYER_ID_1,
+ SUBSCRIPTION_DEPENDANT_LAYER_VERSION_1,
+
+ SUBSCRIPTION_DEPENDANT_LAYER_ID_2,
+ SUBSCRIPTION_DEPENDANT_LAYER_VERSION_2,
+ 1, // number of dependencies for layer
+ SUBSCRIPTION_UNSUPPORTED_LAYER_ID,
+ SUBSCRIPTION_UNSUPPORTED_LAYER_VERSION
+ )
+ );
+
+ assertEquals(0, mSubscriberSemaphore.availablePermits());
+
+ List<VmsLayer> expectedAvailableLayers =
+ new ArrayList<>(Arrays.asList(SUBSCRIPTION_LAYER,
+ SUBSCRIPTION_DEPENDANT_LAYER_1,
+ SUBSCRIPTION_DEPENDANT_LAYER_2));
+
+ getMockedVehicleHal().injectEvent(v);
+ assertTrue(mSubscriberSemaphore.tryAcquire(2L, TimeUnit.SECONDS));
+ assertEquals(expectedAvailableLayers, listener.getAvailableLayers());
+ }
+
private class HalHandler implements VehicleHalPropertyHandler {
private VehiclePropValue mValue;
@@ -165,6 +294,7 @@
private class TestListener implements VmsSubscriberClientListener{
private VmsLayer mLayer;
private byte[] mPayload;
+ private List<VmsLayer> mAvailableLayers = new ArrayList<>();
@Override
public void onVmsMessageReceived(VmsLayer layer, byte[] payload) {
@@ -177,6 +307,8 @@
@Override
public void onLayersAvailabilityChange(List<VmsLayer> availableLayers) {
Log.d(TAG, "onLayersAvailabilityChange: Layers: " + availableLayers);
+ mAvailableLayers.addAll(availableLayers);
+ mSubscriberSemaphore.release();
}
@Override
@@ -191,5 +323,9 @@
public byte[] getPayload() {
return mPayload;
}
+
+ public List<VmsLayer> getAvailableLayers() {
+ return mAvailableLayers;
+ }
}
}
diff --git a/tests/carservice_unit_test/src/com/android/car/CarPowerManagementServiceTest.java b/tests/carservice_unit_test/src/com/android/car/CarPowerManagementServiceTest.java
index c092566..78f13e3 100644
--- a/tests/carservice_unit_test/src/com/android/car/CarPowerManagementServiceTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/CarPowerManagementServiceTest.java
@@ -17,6 +17,7 @@
package com.android.car;
import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.SmallTest;
import android.util.Log;
import com.android.car.CarPowerManagementService.PowerEventProcessingHandler;
@@ -27,6 +28,7 @@
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;
+@SmallTest
public class CarPowerManagementServiceTest extends AndroidTestCase {
private static final String TAG = CarPowerManagementServiceTest.class.getSimpleName();
private static final long WAIT_TIMEOUT_MS = 2000;
diff --git a/tests/carservice_unit_test/src/com/android/car/CrashTrackerTest.java b/tests/carservice_unit_test/src/com/android/car/CrashTrackerTest.java
index 1ac320f..0737b9b 100644
--- a/tests/carservice_unit_test/src/com/android/car/CrashTrackerTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/CrashTrackerTest.java
@@ -17,10 +17,12 @@
import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.SmallTest;
import android.util.MutableBoolean;
import com.android.car.CarService.CrashTracker;
+@SmallTest
public class CrashTrackerTest extends AndroidTestCase {
public void testCrashingTooManyTimes() throws InterruptedException {
diff --git a/tests/carservice_unit_test/src/com/android/car/VmsLayersAvailabilityTest.java b/tests/carservice_unit_test/src/com/android/car/VmsLayersAvailabilityTest.java
index 07a0122..d6fd68d 100644
--- a/tests/carservice_unit_test/src/com/android/car/VmsLayersAvailabilityTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/VmsLayersAvailabilityTest.java
@@ -20,11 +20,14 @@
import android.car.vms.VmsLayerDependency;
import android.car.vms.VmsLayersOffering;
import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.SmallTest;
+
import java.util.Arrays;
+import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
-
+@SmallTest
public class VmsLayersAvailabilityTest extends AndroidTestCase {
private static final VmsLayer LAYER_X = new VmsLayer(1, 2);
@@ -62,6 +65,15 @@
super.setUp();
}
+ public void testNoOffering() {
+ assertTrue(mLayersAvailability.getAvailableLayers().isEmpty());
+ }
+
+ public void testEmptyOffering() {
+ mLayersAvailability.setPublishersOffering(Collections.EMPTY_LIST);
+ assertTrue(mLayersAvailability.getAvailableLayers().isEmpty());
+ }
+
public void testSingleLayerNoDeps() throws Exception {
Set<VmsLayer> expectedAvailableLayers = new HashSet<>();
expectedAvailableLayers.add(LAYER_X);
diff --git a/tests/carservice_unit_test/src/com/android/car/VmsRoutingTest.java b/tests/carservice_unit_test/src/com/android/car/VmsRoutingTest.java
index 4ca7096..0ff1c85 100644
--- a/tests/carservice_unit_test/src/com/android/car/VmsRoutingTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/VmsRoutingTest.java
@@ -20,11 +20,13 @@
import android.car.vms.VmsLayer;
import android.car.vms.VmsSubscriptionState;
import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.SmallTest;
+
import java.util.HashSet;
import java.util.List;
import java.util.Set;
-
+@SmallTest
public class VmsRoutingTest extends AndroidTestCase {
private static VmsLayer LAYER_WITH_SUBSCRIPTION_1= new VmsLayer(1, 2);
private static VmsLayer LAYER_WITH_SUBSCRIPTION_2= new VmsLayer(1, 3);
diff --git a/tests/obd2_app/Android.mk b/tests/obd2_app/Android.mk
new file mode 100644
index 0000000..7e1e22f
--- /dev/null
+++ b/tests/obd2_app/Android.mk
@@ -0,0 +1,40 @@
+# Copyright (C) 2017 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.
+#
+#
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
+
+LOCAL_PACKAGE_NAME := Obd2App
+
+LOCAL_AAPT_FLAGS := --auto-add-overlay
+
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_PROGUARD_ENABLED := disabled
+
+LOCAL_DEX_PREOPT := false
+
+LOCAL_STATIC_JAVA_LIBRARIES += \
+ com.android.car.obd2 \
+
+LOCAL_JAVA_VERSION := 1.8
+
+include $(BUILD_PACKAGE)
diff --git a/tests/obd2_app/AndroidManifest.xml b/tests/obd2_app/AndroidManifest.xml
new file mode 100644
index 0000000..184d939
--- /dev/null
+++ b/tests/obd2_app/AndroidManifest.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!-- Copyright (C) 2017 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
+
+
+ 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.
+-->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.google.android.car.obd2app">
+
+ <uses-permission android:name="android.permission.BLUETOOTH"/>
+ <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
+ <application
+ android:allowBackup="true"
+ android:debuggable="true"
+ android:icon="@mipmap/ic_launcher"
+ android:label="@string/app_name"
+ android:supportsRtl="true"
+ android:theme="@style/AppTheme">
+ <activity android:name=".MainActivity">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+ <activity android:name=".SettingsActivity"/>
+ </application>
+
+</manifest>
diff --git a/tests/obd2_app/res/drawable/ic_info_black_24dp.xml b/tests/obd2_app/res/drawable/ic_info_black_24dp.xml
new file mode 100644
index 0000000..b9139d1
--- /dev/null
+++ b/tests/obd2_app/res/drawable/ic_info_black_24dp.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2017 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:height="24dp"
+ android:viewportHeight="24.0"
+ android:viewportWidth="24.0"
+ android:width="24dp">
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zm1,15h-2v-6h2v6zm0,-8h-2V7h2v2z"/>
+</vector>
diff --git a/tests/obd2_app/res/drawable/ic_notifications_black_24dp.xml b/tests/obd2_app/res/drawable/ic_notifications_black_24dp.xml
new file mode 100644
index 0000000..486956c
--- /dev/null
+++ b/tests/obd2_app/res/drawable/ic_notifications_black_24dp.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2017 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:height="24dp"
+ android:viewportHeight="24.0"
+ android:viewportWidth="24.0"
+ android:width="24dp">
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M11.5,22c1.1,0 2,-0.9 2,-2h-4c0,1.1 0.9,2 2,2zm6.5,-6v-5.5c0,-3.07 -2.13,-5.64 -5,-6.32V3.5c0,-0.83 -0.67,-1.5 -1.5,-1.5S10,2.67 10,3.5v0.68c-2.87,0.68 -5,3.25 -5,6.32V16l-2,2v1h17v-1l-2,-2z"/>
+</vector>
diff --git a/tests/obd2_app/res/drawable/ic_sync_black_24dp.xml b/tests/obd2_app/res/drawable/ic_sync_black_24dp.xml
new file mode 100644
index 0000000..8511efa
--- /dev/null
+++ b/tests/obd2_app/res/drawable/ic_sync_black_24dp.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2017 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:height="24dp"
+ android:viewportHeight="24.0"
+ android:viewportWidth="24.0"
+ android:width="24dp">
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M12 4V1L8 5l4 4V6c3.31 0 6 2.69 6 6 0 1.01,-.25 1.97,-.7 2.8l1.46 1.46C19.54 15.03 20 13.57 20 12c0,-4.42,-3.58,-8,-8,-8zm0 14c-3.31 0,-6,-2.69,-6,-6 0,-1.01.25,-1.97.7,-2.8L5.24 7.74C4.46 8.97 4 10.43 4 12c0 4.42 3.58 8 8 8v3l4,-4,-4,-4v3z"/>
+</vector>
\ No newline at end of file
diff --git a/tests/obd2_app/res/layout/activity_main.xml b/tests/obd2_app/res/layout/activity_main.xml
new file mode 100644
index 0000000..29d7bd2
--- /dev/null
+++ b/tests/obd2_app/res/layout/activity_main.xml
@@ -0,0 +1,52 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2017 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.
+-->
+<RelativeLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:id="@+id/activity_main"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:paddingTop="@dimen/activity_vertical_margin"
+ android:paddingBottom="@dimen/activity_vertical_margin"
+ android:paddingLeft="@dimen/activity_horizontal_margin"
+ android:paddingRight="@dimen/activity_horizontal_margin"
+ tools:context="com.google.android.car.obd2app.MainActivity">
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentTop="true"
+ android:layout_alignParentStart="true"
+ android:id="@+id/statusBar"
+ android:layout_alignParentEnd="true"
+ android:text="Nothing to say"
+ android:minLines="10"/>
+ <Button
+ android:text="Connect"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentBottom="true"
+ android:layout_alignParentEnd="true"
+ android:id="@+id/connection"/>
+ <Button
+ android:text="Settings"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:id="@+id/settings"
+ android:layout_alignParentBottom="true"
+ android:layout_alignParentStart="true"
+ android:onClick="doSettings"/>
+</RelativeLayout>
diff --git a/tests/obd2_app/res/mipmap-hdpi/ic_launcher.png b/tests/obd2_app/res/mipmap-hdpi/ic_launcher.png
new file mode 100644
index 0000000..cde69bc
--- /dev/null
+++ b/tests/obd2_app/res/mipmap-hdpi/ic_launcher.png
Binary files differ
diff --git a/tests/obd2_app/res/mipmap-mdpi/ic_launcher.png b/tests/obd2_app/res/mipmap-mdpi/ic_launcher.png
new file mode 100644
index 0000000..c133a0c
--- /dev/null
+++ b/tests/obd2_app/res/mipmap-mdpi/ic_launcher.png
Binary files differ
diff --git a/tests/obd2_app/res/mipmap-xhdpi/ic_launcher.png b/tests/obd2_app/res/mipmap-xhdpi/ic_launcher.png
new file mode 100644
index 0000000..bfa42f0
--- /dev/null
+++ b/tests/obd2_app/res/mipmap-xhdpi/ic_launcher.png
Binary files differ
diff --git a/tests/obd2_app/res/mipmap-xxhdpi/ic_launcher.png b/tests/obd2_app/res/mipmap-xxhdpi/ic_launcher.png
new file mode 100644
index 0000000..324e72c
--- /dev/null
+++ b/tests/obd2_app/res/mipmap-xxhdpi/ic_launcher.png
Binary files differ
diff --git a/tests/obd2_app/res/mipmap-xxxhdpi/ic_launcher.png b/tests/obd2_app/res/mipmap-xxxhdpi/ic_launcher.png
new file mode 100644
index 0000000..aee44e1
--- /dev/null
+++ b/tests/obd2_app/res/mipmap-xxxhdpi/ic_launcher.png
Binary files differ
diff --git a/tests/obd2_app/res/values-w820dp/dimens.xml b/tests/obd2_app/res/values-w820dp/dimens.xml
new file mode 100644
index 0000000..1da9658
--- /dev/null
+++ b/tests/obd2_app/res/values-w820dp/dimens.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2017 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.
+-->
+<resources>
+ <!-- Example customization of dimensions originally defined in res/values/dimens.xml
+ (such as screen margins) for screens with more than 820dp of available width. This
+ would include 7" and 10" devices in landscape (~960dp and ~1280dp respectively). -->
+ <dimen name="activity_horizontal_margin">64dp</dimen>
+</resources>
diff --git a/tests/obd2_app/res/values/arrays.xml b/tests/obd2_app/res/values/arrays.xml
new file mode 100644
index 0000000..2bd7ce3
--- /dev/null
+++ b/tests/obd2_app/res/values/arrays.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2017 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.
+-->
+<resources>
+ <string-array name="scan_delay_entries">
+ <item>2 seconds</item>
+ <item>5 seconds</item>
+ <item>10 seconds</item>
+ </string-array>
+ <string-array name="scan_delay_entryValues">
+ <item>2</item>
+ <item>5</item>
+ <item>10</item>
+ </string-array>
+</resources>
diff --git a/tests/obd2_app/res/values/colors.xml b/tests/obd2_app/res/values/colors.xml
new file mode 100644
index 0000000..49a370a
--- /dev/null
+++ b/tests/obd2_app/res/values/colors.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2017 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.
+-->
+
+<resources>
+ <color name="colorPrimary">#3F51B5</color>
+ <color name="colorPrimaryDark">#303F9F</color>
+ <color name="colorAccent">#FF4081</color>
+</resources>
diff --git a/tests/obd2_app/res/values/dimens.xml b/tests/obd2_app/res/values/dimens.xml
new file mode 100644
index 0000000..261477e
--- /dev/null
+++ b/tests/obd2_app/res/values/dimens.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2017 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.
+-->
+<resources>
+ <!-- Default screen margins, per the Android Design guidelines. -->
+ <dimen name="activity_horizontal_margin">16dp</dimen>
+ <dimen name="activity_vertical_margin">16dp</dimen>
+</resources>
diff --git a/tests/obd2_app/res/values/strings.xml b/tests/obd2_app/res/values/strings.xml
new file mode 100644
index 0000000..c615c4f
--- /dev/null
+++ b/tests/obd2_app/res/values/strings.xml
@@ -0,0 +1,91 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2017 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.
+-->
+<resources>
+ <string name="app_name">Obd2App</string>
+ <string name="title_activity_settings">Settings</string>
+
+ <!-- Strings related to Settings -->
+
+ <!-- Example General settings -->
+ <string name="pref_header_general">General</string>
+
+ <string name="pref_title_social_recommendations">Enable social recommendations</string>
+ <string name="pref_description_social_recommendations">Recommendations for people to contact based
+ on your message history
+ </string>
+
+ <string name="pref_title_display_name">Display name</string>
+ <string name="pref_default_display_name">John Smith</string>
+
+ <string name="pref_title_add_friends_to_messages">Add friends to messages</string>
+ <string-array name="pref_example_list_titles">
+ <item>Always</item>
+ <item>When possible</item>
+ <item>Never</item>
+ </string-array>
+ <string-array name="pref_example_list_values">
+ <item>1</item>
+ <item>0</item>
+ <item>-1</item>
+ </string-array>
+
+ <!-- Example settings for Data & Sync -->
+ <string name="pref_header_data_sync">Data & sync</string>
+
+ <string name="pref_title_sync_frequency">Sync frequency</string>
+ <string-array name="pref_sync_frequency_titles">
+ <item>15 minutes</item>
+ <item>30 minutes</item>
+ <item>1 hour</item>
+ <item>3 hours</item>
+ <item>6 hours</item>
+ <item>Never</item>
+ </string-array>
+ <string-array name="pref_sync_frequency_values">
+ <item>15</item>
+ <item>30</item>
+ <item>60</item>
+ <item>180</item>
+ <item>360</item>
+ <item>-1</item>
+ </string-array>
+
+ <string-array name="list_preference_entries">
+ <item>Entry 1</item>
+ <item>Entry 2</item>
+ <item>Entry 3</item>
+ </string-array>
+
+ <string-array name="list_preference_entry_values">
+ <item>1</item>
+ <item>2</item>
+ <item>3</item>
+ </string-array>
+
+ <string-array name="multi_select_list_preference_default_value"/>
+
+ <string name="pref_title_system_sync_settings">System sync settings</string>
+
+ <!-- Example settings for Notifications -->
+ <string name="pref_header_notifications">Notifications</string>
+
+ <string name="pref_title_new_message_notifications">New message notifications</string>
+
+ <string name="pref_title_ringtone">Ringtone</string>
+ <string name="pref_ringtone_silent">Silent</string>
+
+ <string name="pref_title_vibrate">Vibrate</string>
+</resources>
diff --git a/tests/obd2_app/res/values/styles.xml b/tests/obd2_app/res/values/styles.xml
new file mode 100644
index 0000000..c21c0ac
--- /dev/null
+++ b/tests/obd2_app/res/values/styles.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2017 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.
+-->
+<resources>
+ <style name="AppTheme" parent="android:Theme.Material">
+ </style>
+
+</resources>
diff --git a/tests/obd2_app/res/xml/preferences.xml b/tests/obd2_app/res/xml/preferences.xml
new file mode 100644
index 0000000..0c6f534
--- /dev/null
+++ b/tests/obd2_app/res/xml/preferences.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2017 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.
+-->
+<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
+ <com.google.android.car.obd2app.BluetoothPreference
+ android:key="bluetooth_mac"
+ android:title="OBD2 Dongle"
+ android:dialogTitle="Select OBD2 Scanner" />
+ <com.google.android.car.obd2app.IntegerListPreference
+ android:key="scan_delay"
+ android:title="Time between queries"
+ android:dialogTitle="Select Delay"
+ android:entries="@array/scan_delay_entries"
+ android:entryValues="@array/scan_delay_entryValues"
+ android:defaultValue="2"/>
+</PreferenceScreen>
diff --git a/tests/obd2_app/src/com/google/android/car/obd2app/BluetoothPreference.java b/tests/obd2_app/src/com/google/android/car/obd2app/BluetoothPreference.java
new file mode 100644
index 0000000..59da4c0
--- /dev/null
+++ b/tests/obd2_app/src/com/google/android/car/obd2app/BluetoothPreference.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2017 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.google.android.car.obd2app;
+
+import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothDevice;
+import android.content.Context;
+import android.preference.ListPreference;
+import android.util.AttributeSet;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class BluetoothPreference extends ListPreference {
+ private static final class DeviceEntry {
+ private final String mName;
+ private final String mAddress;
+
+ DeviceEntry(BluetoothDevice device) {
+ mAddress = device.getAddress();
+ if (device.getName() == null) {
+ mName = mAddress;
+ } else {
+ mName = device.getName();
+ }
+ }
+
+ String getName() {
+ return mName;
+ }
+
+ String getAddress() {
+ return mAddress;
+ }
+ }
+
+ public BluetoothPreference(Context context, AttributeSet attrs) {
+ super(context, attrs);
+
+ BluetoothAdapter defaultAdapter = BluetoothAdapter.getDefaultAdapter();
+ List<DeviceEntry> pairedDevices = new ArrayList<>();
+ defaultAdapter
+ .getBondedDevices()
+ .forEach((BluetoothDevice device) -> pairedDevices.add(new DeviceEntry(device)));
+ setEntries(pairedDevices.stream().map(DeviceEntry::getName).toArray(String[]::new));
+ setEntryValues(pairedDevices.stream().map(DeviceEntry::getAddress).toArray(String[]::new));
+ }
+
+ public BluetoothPreference(Context context) {
+ this(context, null);
+ }
+}
diff --git a/tests/obd2_app/src/com/google/android/car/obd2app/IntegerListPreference.java b/tests/obd2_app/src/com/google/android/car/obd2app/IntegerListPreference.java
new file mode 100644
index 0000000..6e9e9dc
--- /dev/null
+++ b/tests/obd2_app/src/com/google/android/car/obd2app/IntegerListPreference.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2017 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.google.android.car.obd2app;
+
+import android.content.Context;
+import android.preference.ListPreference;
+import android.util.AttributeSet;
+
+public class IntegerListPreference extends ListPreference {
+ public IntegerListPreference(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ public IntegerListPreference(Context context) {
+ super(context);
+ }
+
+ @Override
+ protected boolean persistString(String value) {
+ return value != null && persistInt(Integer.valueOf(value));
+ }
+
+ @Override
+ protected String getPersistedString(String defaultReturnValue) {
+ if (getSharedPreferences().contains(getKey())) {
+ return String.valueOf(getPersistedInt(2));
+ } else {
+ return defaultReturnValue;
+ }
+ }
+}
diff --git a/tests/obd2_app/src/com/google/android/car/obd2app/MainActivity.java b/tests/obd2_app/src/com/google/android/car/obd2app/MainActivity.java
new file mode 100644
index 0000000..dc38b5c
--- /dev/null
+++ b/tests/obd2_app/src/com/google/android/car/obd2app/MainActivity.java
@@ -0,0 +1,116 @@
+/*
+ * Copyright (C) 2017 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.google.android.car.obd2app;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.content.pm.ActivityInfo;
+import android.os.Bundle;
+import android.preference.PreferenceManager;
+import android.text.TextUtils;
+import android.util.Log;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.widget.Button;
+import android.widget.TextView;
+import java.util.Timer;
+
+public class MainActivity extends Activity implements StatusNotification {
+ public static final String TAG = MainActivity.class.getSimpleName();
+
+ private static final String BLUETOOTH_MAC_PREFERENCE_ID = "bluetooth_mac";
+ private static final String SCAN_DELAY_PREFERENCE_ID = "scan_delay";
+
+ private Obd2CollectionTask mCollectionTask = null;
+ private final Timer mTimer = new Timer("com.google.android.car.obd2app.collection");
+
+ private String getBluetoothDongleMacFromPreferences(String defaultValue) {
+ SharedPreferences appPreferences = PreferenceManager.getDefaultSharedPreferences(this);
+ return appPreferences.getString(BLUETOOTH_MAC_PREFERENCE_ID, defaultValue);
+ }
+
+ private int getScanDelayFromPreferences(int defaultValue) {
+ SharedPreferences appPreferences = PreferenceManager.getDefaultSharedPreferences(this);
+ return appPreferences.getInt(SCAN_DELAY_PREFERENCE_ID, defaultValue);
+ }
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_main);
+ setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_NOSENSOR);
+ String bluetoothDongleMac = getBluetoothDongleMacFromPreferences("");
+ if (TextUtils.isEmpty(bluetoothDongleMac)) {
+ notifyNoDongle();
+ } else {
+ notifyPaired(bluetoothDongleMac);
+ }
+ findViewById(R.id.connection)
+ .setOnClickListener(
+ new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ handleConnection(v);
+ }
+ });
+ Log.i(TAG, "I did all the things");
+ }
+
+ private void stopConnection() {
+ mCollectionTask.cancel();
+ mTimer.purge();
+ mCollectionTask = null;
+ }
+
+ @Override
+ protected void onDestroy() {
+ stopConnection();
+ }
+
+ public void doSettings(View view) {
+ Intent launchSettings = new Intent(this, SettingsActivity.class);
+ startActivity(launchSettings);
+ }
+
+ @Override
+ public void notify(String status) {
+ Log.i(TAG, status);
+ runOnUiThread(() -> ((TextView) findViewById(R.id.statusBar)).setText(status));
+ }
+
+ public void handleConnection(View view) {
+ String deviceAddress = getBluetoothDongleMacFromPreferences("");
+ Log.i(TAG, "Considering a connection to " + deviceAddress);
+ if (TextUtils.isEmpty(deviceAddress)) {
+ notifyNoDongle();
+ }
+ if (mCollectionTask == null) {
+ mCollectionTask = Obd2CollectionTask.create(this, this, deviceAddress);
+ if (null == mCollectionTask) {
+ notifyConnectionFailed();
+ return;
+ }
+ final int delay = 1000 * getScanDelayFromPreferences(2);
+ mTimer.scheduleAtFixedRate(mCollectionTask, delay, delay);
+ ((Button) view).setText("Disconnect");
+ } else {
+ stopConnection();
+ ((Button) view).setText("Connect");
+ }
+ }
+}
diff --git a/tests/obd2_app/src/com/google/android/car/obd2app/Obd2CollectionTask.java b/tests/obd2_app/src/com/google/android/car/obd2app/Obd2CollectionTask.java
new file mode 100644
index 0000000..31c3db2
--- /dev/null
+++ b/tests/obd2_app/src/com/google/android/car/obd2app/Obd2CollectionTask.java
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 2017 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.google.android.car.obd2app;
+
+import android.annotation.Nullable;
+import android.content.Context;
+import android.os.Environment;
+import android.os.SystemClock;
+import android.util.JsonWriter;
+import android.util.Log;
+
+import com.android.car.obd2.Obd2Connection;
+import com.android.car.obd2.Obd2LiveFrameGenerator;
+import com.android.car.obd2.connections.BluetoothConnection;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStreamWriter;
+import java.util.Objects;
+import java.util.TimerTask;
+
+public class Obd2CollectionTask extends TimerTask {
+ private final Obd2Connection mConnection;
+ private final Obd2LiveFrameGenerator mLiveFrameGenerator;
+ private final StatusNotification mStatusNotification;
+ private final JsonWriter mJsonWriter;
+
+ public static @Nullable Obd2CollectionTask create(
+ Context context, StatusNotification statusNotification, String deviceAddress) {
+ try {
+ return new Obd2CollectionTask(
+ Objects.requireNonNull(context),
+ Objects.requireNonNull(statusNotification),
+ Objects.requireNonNull(deviceAddress));
+ } catch (IOException | InterruptedException | IllegalStateException e) {
+ Log.i(MainActivity.TAG, "Connection failed due to exception", e);
+ return null;
+ }
+ }
+
+ @Override
+ public boolean cancel() {
+ synchronized (mJsonWriter) {
+ try {
+ mJsonWriter.endArray();
+ mJsonWriter.flush();
+ mJsonWriter.close();
+ } catch (IOException e) {
+ Log.w(MainActivity.TAG, "IOException during close", e);
+ }
+ return super.cancel();
+ }
+ }
+
+ @Override
+ public void run() {
+ if (!mConnection.isConnected()) {
+ if (!mConnection.reconnect()) {
+ mStatusNotification.notifyDisconnected();
+ return;
+ }
+ }
+
+ try {
+ synchronized (mJsonWriter) {
+ mLiveFrameGenerator.generate(mJsonWriter);
+ mJsonWriter.flush();
+ }
+ mStatusNotification.notifyDataCapture();
+ } catch (Exception e) {
+ mStatusNotification.notifyException(e);
+ }
+ }
+
+ Obd2CollectionTask(Context context, StatusNotification statusNotification, String deviceAddress)
+ throws IOException, InterruptedException {
+ if (!isExternalStorageWriteable())
+ throw new IOException("Cannot write data to external storage");
+ mStatusNotification = statusNotification;
+ BluetoothConnection bluetoothConnection = new BluetoothConnection(deviceAddress);
+ if (!bluetoothConnection.isConnected()) {
+ statusNotification.notifyConnectionFailed();
+ throw new IllegalStateException("Unable to connect to remote end.");
+ }
+ mConnection = new Obd2Connection(bluetoothConnection);
+ mLiveFrameGenerator = new Obd2LiveFrameGenerator(mConnection);
+ mJsonWriter =
+ new JsonWriter(
+ new OutputStreamWriter(
+ new FileOutputStream(getFilenameForStorage(context))));
+ mJsonWriter.beginArray();
+ }
+
+ private static boolean isExternalStorageWriteable() {
+ String state = Environment.getExternalStorageState();
+ return (Environment.MEDIA_MOUNTED.equals(state));
+ }
+
+ private static File getFilenameForStorage(Context context) {
+ String basename = String.format("obd2app.capture.%d", SystemClock.elapsedRealtimeNanos());
+ return new File(context.getExternalFilesDir(Environment.DIRECTORY_DOCUMENTS), basename);
+ }
+}
diff --git a/tests/obd2_app/src/com/google/android/car/obd2app/SettingsActivity.java b/tests/obd2_app/src/com/google/android/car/obd2app/SettingsActivity.java
new file mode 100644
index 0000000..23f120e
--- /dev/null
+++ b/tests/obd2_app/src/com/google/android/car/obd2app/SettingsActivity.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2017 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.google.android.car.obd2app;
+
+import android.os.Bundle;
+import android.preference.PreferenceActivity;
+
+public class SettingsActivity extends PreferenceActivity {
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ addPreferencesFromResource(R.xml.preferences);
+ }
+}
diff --git a/tests/obd2_app/src/com/google/android/car/obd2app/StatusNotification.java b/tests/obd2_app/src/com/google/android/car/obd2app/StatusNotification.java
new file mode 100644
index 0000000..185c384
--- /dev/null
+++ b/tests/obd2_app/src/com/google/android/car/obd2app/StatusNotification.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2017 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.google.android.car.obd2app;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
+
+interface StatusNotification {
+ void notify(String status);
+
+ default void notifyNoDongle() {
+ notify("No OBD2 dongle paired. Go to Settings.");
+ }
+
+ default void notifyPaired(String deviceAddress) {
+ notify("Paired to " + deviceAddress + ". Ready to capture data.");
+ }
+
+ default void notifyConnectionFailed() {
+ notify("Unable to connect.");
+ }
+
+ default void notifyConnected(String deviceAddress) {
+ notify("Connected to " + deviceAddress + ". Starting data capture.");
+ }
+
+ default void notifyDataCapture() {
+ LocalDateTime now = LocalDateTime.now();
+ DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("MMMM dd yyyy hh:mm:ssa");
+ notify("Successfully captured data at " + now.format(dateTimeFormatter));
+ }
+
+ default void notifyException(Exception e) {
+ StringWriter stringWriter = new StringWriter(1024);
+ e.printStackTrace(new PrintWriter(stringWriter));
+ notify("Exception occurred.\n" + stringWriter.toString());
+ }
+
+ default void notifyDisconnected() {
+ notify("Lost connection to remote end. Will try to reconnect.");
+ }
+}
diff --git a/tools/bootanalyze/Android.mk b/tools/bootanalyze/Android.mk
new file mode 100644
index 0000000..5df0dd8
--- /dev/null
+++ b/tools/bootanalyze/Android.mk
@@ -0,0 +1,20 @@
+# Copyright (C) 2017 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.
+#
+#
+
+LOCAL_PATH := $(call my-dir)
+
+# Include the sub-makefiles
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/tools/emulator/VehicleHalProto_pb2.py b/tools/emulator/VehicleHalProto_pb2.py
index aaad547..f972126 100644
--- a/tools/emulator/VehicleHalProto_pb2.py
+++ b/tools/emulator/VehicleHalProto_pb2.py
@@ -1,20 +1,28 @@
# Generated by the protocol buffer compiler. DO NOT EDIT!
# source: VehicleHalProto.proto
+import sys
+_b=sys.version_info[0]<3 and (lambda x:x) or (lambda x:x.encode('latin1'))
from google.protobuf.internal import enum_type_wrapper
from google.protobuf import descriptor as _descriptor
from google.protobuf import message as _message
from google.protobuf import reflection as _reflection
+from google.protobuf import symbol_database as _symbol_database
from google.protobuf import descriptor_pb2
# @@protoc_insertion_point(imports)
+_sym_db = _symbol_database.Default()
+
DESCRIPTOR = _descriptor.FileDescriptor(
name='VehicleHalProto.proto',
package='emulator',
- serialized_pb='\n\x15VehicleHalProto.proto\x12\x08\x65mulator\"\xba\x01\n\x11VehicleAreaConfig\x12\x0f\n\x07\x61rea_id\x18\x01 \x02(\x05\x12\x17\n\x0fmin_int32_value\x18\x02 \x01(\x11\x12\x17\n\x0fmax_int32_value\x18\x03 \x01(\x11\x12\x17\n\x0fmin_int64_value\x18\x04 \x01(\x12\x12\x17\n\x0fmax_int64_value\x18\x05 \x01(\x12\x12\x17\n\x0fmin_float_value\x18\x06 \x01(\x02\x12\x17\n\x0fmax_float_value\x18\x07 \x01(\x02\"\x9b\x02\n\x11VehiclePropConfig\x12\x0c\n\x04prop\x18\x01 \x02(\x05\x12\x0e\n\x06\x61\x63\x63\x65ss\x18\x02 \x01(\x05\x12\x13\n\x0b\x63hange_mode\x18\x03 \x01(\x05\x12\x12\n\nvalue_type\x18\x04 \x01(\x05\x12\x17\n\x0fsupported_areas\x18\x05 \x01(\x05\x12\x31\n\x0c\x61rea_configs\x18\x06 \x03(\x0b\x32\x1b.emulator.VehicleAreaConfig\x12\x14\n\x0c\x63onfig_flags\x18\x07 \x01(\x05\x12\x14\n\x0c\x63onfig_array\x18\x08 \x03(\x05\x12\x15\n\rconfig_string\x18\t \x01(\t\x12\x17\n\x0fmin_sample_rate\x18\n \x01(\x02\x12\x17\n\x0fmax_sample_rate\x18\x0b \x01(\x02\"\xc5\x01\n\x10VehiclePropValue\x12\x0c\n\x04prop\x18\x01 \x02(\x05\x12\x12\n\nvalue_type\x18\x02 \x01(\x05\x12\x11\n\ttimestamp\x18\x03 \x01(\x03\x12\x0f\n\x07\x61rea_id\x18\x04 \x01(\x05\x12\x14\n\x0cint32_values\x18\x05 \x03(\x11\x12\x14\n\x0cint64_values\x18\x06 \x03(\x12\x12\x14\n\x0c\x66loat_values\x18\x07 \x03(\x02\x12\x14\n\x0cstring_value\x18\x08 \x01(\t\x12\x13\n\x0b\x62ytes_value\x18\t \x01(\x0c\"/\n\x0eVehiclePropGet\x12\x0c\n\x04prop\x18\x01 \x02(\x05\x12\x0f\n\x07\x61rea_id\x18\x02 \x01(\x05\"\xd8\x01\n\x0f\x45mulatorMessage\x12#\n\x08msg_type\x18\x01 \x02(\x0e\x32\x11.emulator.MsgType\x12 \n\x06status\x18\x02 \x01(\x0e\x32\x10.emulator.Status\x12&\n\x04prop\x18\x03 \x03(\x0b\x32\x18.emulator.VehiclePropGet\x12+\n\x06\x63onfig\x18\x04 \x03(\x0b\x32\x1b.emulator.VehiclePropConfig\x12)\n\x05value\x18\x05 \x03(\x0b\x32\x1a.emulator.VehiclePropValue*\x8a\x02\n\x07MsgType\x12\x12\n\x0eGET_CONFIG_CMD\x10\x00\x12\x13\n\x0fGET_CONFIG_RESP\x10\x01\x12\x16\n\x12GET_CONFIG_ALL_CMD\x10\x02\x12\x17\n\x13GET_CONFIG_ALL_RESP\x10\x03\x12\x14\n\x10GET_PROPERTY_CMD\x10\x04\x12\x15\n\x11GET_PROPERTY_RESP\x10\x05\x12\x18\n\x14GET_PROPERTY_ALL_CMD\x10\x06\x12\x19\n\x15GET_PROPERTY_ALL_RESP\x10\x07\x12\x14\n\x10SET_PROPERTY_CMD\x10\x08\x12\x15\n\x11SET_PROPERTY_RESP\x10\t\x12\x16\n\x12SET_PROPERTY_ASYNC\x10\n*\xfb\x01\n\x06Status\x12\r\n\tRESULT_OK\x10\x00\x12\x11\n\rERROR_UNKNOWN\x10\x01\x12\x1b\n\x17\x45RROR_UNIMPLEMENTED_CMD\x10\x02\x12\x1a\n\x16\x45RROR_INVALID_PROPERTY\x10\x03\x12\x19\n\x15\x45RROR_INVALID_AREA_ID\x10\x04\x12 \n\x1c\x45RROR_PROPERTY_UNINITIALIZED\x10\x05\x12\x1d\n\x19\x45RROR_WRITE_ONLY_PROPERTY\x10\x06\x12\x1d\n\x19\x45RROR_MEMORY_ALLOC_FAILED\x10\x07\x12\x1b\n\x17\x45RROR_INVALID_OPERATION\x10\x08\x42\x02H\x03')
+ syntax='proto2',
+ serialized_pb=_b('\n\x15VehicleHalProto.proto\x12\x08\x65mulator\"\xba\x01\n\x11VehicleAreaConfig\x12\x0f\n\x07\x61rea_id\x18\x01 \x02(\x05\x12\x17\n\x0fmin_int32_value\x18\x02 \x01(\x11\x12\x17\n\x0fmax_int32_value\x18\x03 \x01(\x11\x12\x17\n\x0fmin_int64_value\x18\x04 \x01(\x12\x12\x17\n\x0fmax_int64_value\x18\x05 \x01(\x12\x12\x17\n\x0fmin_float_value\x18\x06 \x01(\x02\x12\x17\n\x0fmax_float_value\x18\x07 \x01(\x02\"\x9b\x02\n\x11VehiclePropConfig\x12\x0c\n\x04prop\x18\x01 \x02(\x05\x12\x0e\n\x06\x61\x63\x63\x65ss\x18\x02 \x01(\x05\x12\x13\n\x0b\x63hange_mode\x18\x03 \x01(\x05\x12\x12\n\nvalue_type\x18\x04 \x01(\x05\x12\x17\n\x0fsupported_areas\x18\x05 \x01(\x05\x12\x31\n\x0c\x61rea_configs\x18\x06 \x03(\x0b\x32\x1b.emulator.VehicleAreaConfig\x12\x14\n\x0c\x63onfig_flags\x18\x07 \x01(\x05\x12\x14\n\x0c\x63onfig_array\x18\x08 \x03(\x05\x12\x15\n\rconfig_string\x18\t \x01(\t\x12\x17\n\x0fmin_sample_rate\x18\n \x01(\x02\x12\x17\n\x0fmax_sample_rate\x18\x0b \x01(\x02\"\xc5\x01\n\x10VehiclePropValue\x12\x0c\n\x04prop\x18\x01 \x02(\x05\x12\x12\n\nvalue_type\x18\x02 \x01(\x05\x12\x11\n\ttimestamp\x18\x03 \x01(\x03\x12\x0f\n\x07\x61rea_id\x18\x04 \x01(\x05\x12\x14\n\x0cint32_values\x18\x05 \x03(\x11\x12\x14\n\x0cint64_values\x18\x06 \x03(\x12\x12\x14\n\x0c\x66loat_values\x18\x07 \x03(\x02\x12\x14\n\x0cstring_value\x18\x08 \x01(\t\x12\x13\n\x0b\x62ytes_value\x18\t \x01(\x0c\"/\n\x0eVehiclePropGet\x12\x0c\n\x04prop\x18\x01 \x02(\x05\x12\x0f\n\x07\x61rea_id\x18\x02 \x01(\x05\"\xd8\x01\n\x0f\x45mulatorMessage\x12#\n\x08msg_type\x18\x01 \x02(\x0e\x32\x11.emulator.MsgType\x12 \n\x06status\x18\x02 \x01(\x0e\x32\x10.emulator.Status\x12&\n\x04prop\x18\x03 \x03(\x0b\x32\x18.emulator.VehiclePropGet\x12+\n\x06\x63onfig\x18\x04 \x03(\x0b\x32\x1b.emulator.VehiclePropConfig\x12)\n\x05value\x18\x05 \x03(\x0b\x32\x1a.emulator.VehiclePropValue*\x8a\x02\n\x07MsgType\x12\x12\n\x0eGET_CONFIG_CMD\x10\x00\x12\x13\n\x0fGET_CONFIG_RESP\x10\x01\x12\x16\n\x12GET_CONFIG_ALL_CMD\x10\x02\x12\x17\n\x13GET_CONFIG_ALL_RESP\x10\x03\x12\x14\n\x10GET_PROPERTY_CMD\x10\x04\x12\x15\n\x11GET_PROPERTY_RESP\x10\x05\x12\x18\n\x14GET_PROPERTY_ALL_CMD\x10\x06\x12\x19\n\x15GET_PROPERTY_ALL_RESP\x10\x07\x12\x14\n\x10SET_PROPERTY_CMD\x10\x08\x12\x15\n\x11SET_PROPERTY_RESP\x10\t\x12\x16\n\x12SET_PROPERTY_ASYNC\x10\n*\xfb\x01\n\x06Status\x12\r\n\tRESULT_OK\x10\x00\x12\x11\n\rERROR_UNKNOWN\x10\x01\x12\x1b\n\x17\x45RROR_UNIMPLEMENTED_CMD\x10\x02\x12\x1a\n\x16\x45RROR_INVALID_PROPERTY\x10\x03\x12\x19\n\x15\x45RROR_INVALID_AREA_ID\x10\x04\x12 \n\x1c\x45RROR_PROPERTY_UNINITIALIZED\x10\x05\x12\x1d\n\x19\x45RROR_WRITE_ONLY_PROPERTY\x10\x06\x12\x1d\n\x19\x45RROR_MEMORY_ALLOC_FAILED\x10\x07\x12\x1b\n\x17\x45RROR_INVALID_OPERATION\x10\x08\x42\x02H\x03')
+)
+_sym_db.RegisterFileDescriptor(DESCRIPTOR)
_MSGTYPE = _descriptor.EnumDescriptor(
name='MsgType',
@@ -72,6 +80,7 @@
serialized_start=979,
serialized_end=1245,
)
+_sym_db.RegisterEnumDescriptor(_MSGTYPE)
MsgType = enum_type_wrapper.EnumTypeWrapper(_MSGTYPE)
_STATUS = _descriptor.EnumDescriptor(
@@ -122,6 +131,7 @@
serialized_start=1248,
serialized_end=1499,
)
+_sym_db.RegisterEnumDescriptor(_STATUS)
Status = enum_type_wrapper.EnumTypeWrapper(_STATUS)
GET_CONFIG_CMD = 0
@@ -192,14 +202,14 @@
_descriptor.FieldDescriptor(
name='min_float_value', full_name='emulator.VehicleAreaConfig.min_float_value', index=5,
number=6, type=2, cpp_type=6, label=1,
- has_default_value=False, default_value=0,
+ has_default_value=False, default_value=float(0),
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
options=None),
_descriptor.FieldDescriptor(
name='max_float_value', full_name='emulator.VehicleAreaConfig.max_float_value', index=6,
number=7, type=2, cpp_type=6, label=1,
- has_default_value=False, default_value=0,
+ has_default_value=False, default_value=float(0),
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
options=None),
@@ -211,7 +221,10 @@
],
options=None,
is_extendable=False,
+ syntax='proto2',
extension_ranges=[],
+ oneofs=[
+ ],
serialized_start=36,
serialized_end=222,
)
@@ -283,21 +296,21 @@
_descriptor.FieldDescriptor(
name='config_string', full_name='emulator.VehiclePropConfig.config_string', index=8,
number=9, type=9, cpp_type=9, label=1,
- has_default_value=False, default_value=unicode("", "utf-8"),
+ has_default_value=False, default_value=_b("").decode('utf-8'),
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
options=None),
_descriptor.FieldDescriptor(
name='min_sample_rate', full_name='emulator.VehiclePropConfig.min_sample_rate', index=9,
number=10, type=2, cpp_type=6, label=1,
- has_default_value=False, default_value=0,
+ has_default_value=False, default_value=float(0),
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
options=None),
_descriptor.FieldDescriptor(
name='max_sample_rate', full_name='emulator.VehiclePropConfig.max_sample_rate', index=10,
number=11, type=2, cpp_type=6, label=1,
- has_default_value=False, default_value=0,
+ has_default_value=False, default_value=float(0),
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
options=None),
@@ -309,7 +322,10 @@
],
options=None,
is_extendable=False,
+ syntax='proto2',
extension_ranges=[],
+ oneofs=[
+ ],
serialized_start=225,
serialized_end=508,
)
@@ -374,14 +390,14 @@
_descriptor.FieldDescriptor(
name='string_value', full_name='emulator.VehiclePropValue.string_value', index=7,
number=8, type=9, cpp_type=9, label=1,
- has_default_value=False, default_value=unicode("", "utf-8"),
+ has_default_value=False, default_value=_b("").decode('utf-8'),
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
options=None),
_descriptor.FieldDescriptor(
name='bytes_value', full_name='emulator.VehiclePropValue.bytes_value', index=8,
number=9, type=12, cpp_type=9, label=1,
- has_default_value=False, default_value="",
+ has_default_value=False, default_value=_b(""),
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
options=None),
@@ -393,7 +409,10 @@
],
options=None,
is_extendable=False,
+ syntax='proto2',
extension_ranges=[],
+ oneofs=[
+ ],
serialized_start=511,
serialized_end=708,
)
@@ -428,7 +447,10 @@
],
options=None,
is_extendable=False,
+ syntax='proto2',
extension_ranges=[],
+ oneofs=[
+ ],
serialized_start=710,
serialized_end=757,
)
@@ -484,7 +506,10 @@
],
options=None,
is_extendable=False,
+ syntax='proto2',
extension_ranges=[],
+ oneofs=[
+ ],
serialized_start=760,
serialized_end=976,
)
@@ -500,38 +525,45 @@
DESCRIPTOR.message_types_by_name['VehiclePropValue'] = _VEHICLEPROPVALUE
DESCRIPTOR.message_types_by_name['VehiclePropGet'] = _VEHICLEPROPGET
DESCRIPTOR.message_types_by_name['EmulatorMessage'] = _EMULATORMESSAGE
+DESCRIPTOR.enum_types_by_name['MsgType'] = _MSGTYPE
+DESCRIPTOR.enum_types_by_name['Status'] = _STATUS
-class VehicleAreaConfig(_message.Message):
- __metaclass__ = _reflection.GeneratedProtocolMessageType
- DESCRIPTOR = _VEHICLEAREACONFIG
-
+VehicleAreaConfig = _reflection.GeneratedProtocolMessageType('VehicleAreaConfig', (_message.Message,), dict(
+ DESCRIPTOR = _VEHICLEAREACONFIG,
+ __module__ = 'VehicleHalProto_pb2'
# @@protoc_insertion_point(class_scope:emulator.VehicleAreaConfig)
+ ))
+_sym_db.RegisterMessage(VehicleAreaConfig)
-class VehiclePropConfig(_message.Message):
- __metaclass__ = _reflection.GeneratedProtocolMessageType
- DESCRIPTOR = _VEHICLEPROPCONFIG
-
+VehiclePropConfig = _reflection.GeneratedProtocolMessageType('VehiclePropConfig', (_message.Message,), dict(
+ DESCRIPTOR = _VEHICLEPROPCONFIG,
+ __module__ = 'VehicleHalProto_pb2'
# @@protoc_insertion_point(class_scope:emulator.VehiclePropConfig)
+ ))
+_sym_db.RegisterMessage(VehiclePropConfig)
-class VehiclePropValue(_message.Message):
- __metaclass__ = _reflection.GeneratedProtocolMessageType
- DESCRIPTOR = _VEHICLEPROPVALUE
-
+VehiclePropValue = _reflection.GeneratedProtocolMessageType('VehiclePropValue', (_message.Message,), dict(
+ DESCRIPTOR = _VEHICLEPROPVALUE,
+ __module__ = 'VehicleHalProto_pb2'
# @@protoc_insertion_point(class_scope:emulator.VehiclePropValue)
+ ))
+_sym_db.RegisterMessage(VehiclePropValue)
-class VehiclePropGet(_message.Message):
- __metaclass__ = _reflection.GeneratedProtocolMessageType
- DESCRIPTOR = _VEHICLEPROPGET
-
+VehiclePropGet = _reflection.GeneratedProtocolMessageType('VehiclePropGet', (_message.Message,), dict(
+ DESCRIPTOR = _VEHICLEPROPGET,
+ __module__ = 'VehicleHalProto_pb2'
# @@protoc_insertion_point(class_scope:emulator.VehiclePropGet)
+ ))
+_sym_db.RegisterMessage(VehiclePropGet)
-class EmulatorMessage(_message.Message):
- __metaclass__ = _reflection.GeneratedProtocolMessageType
- DESCRIPTOR = _EMULATORMESSAGE
-
+EmulatorMessage = _reflection.GeneratedProtocolMessageType('EmulatorMessage', (_message.Message,), dict(
+ DESCRIPTOR = _EMULATORMESSAGE,
+ __module__ = 'VehicleHalProto_pb2'
# @@protoc_insertion_point(class_scope:emulator.EmulatorMessage)
+ ))
+_sym_db.RegisterMessage(EmulatorMessage)
DESCRIPTOR.has_options = True
-DESCRIPTOR._options = _descriptor._ParseOptions(descriptor_pb2.FileOptions(), 'H\003')
+DESCRIPTOR._options = _descriptor._ParseOptions(descriptor_pb2.FileOptions(), _b('H\003'))
# @@protoc_insertion_point(module_scope)
diff --git a/tools/emulator/vhal_emulator.py b/tools/emulator/vhal_emulator.py
index 514c0d5..5fbdd74 100644
--- a/tools/emulator/vhal_emulator.py
+++ b/tools/emulator/vhal_emulator.py
@@ -34,21 +34,21 @@
# Get the response message to getConfig()
reply = v.rxMsg()
- print reply
+ print(reply)
# Set left temperature to 70 degrees
v.setProperty(c.VEHICLE_PROPERTY_HVAC_TEMPERATURE_SET, c.VEHICLE_ZONE_ROW_1_LEFT, 70)
# Get the response message to setProperty()
reply = v.rxMsg()
- print reply
+ print(reply)
# Get the left temperature value
v.getProperty(c.VEHICLE_PROPERTY_HVAC_TEMPERATURE_SET, c.VEHICLE_ZONE_ROW_1_LEFT)
# Get the response message to getProperty()
reply = v.rxMsg()
- print reply
+ print(reply)
NOTE: The rxMsg() is a blocking call, so it may be desirable to set up a separate RX thread
to handle any asynchronous messages coming from the device.
@@ -72,6 +72,8 @@
protoc -I=<proto_dir> --python_out=<out_dir> <proto_dir>/VehicleHalProto.proto
"""
+from __future__ import print_function
+
# Suppress .pyc files
import sys
sys.dont_write_bytecode = True
@@ -80,7 +82,9 @@
import struct
import subprocess
-# Generate the protobuf file from vendor/auto/embedded/lib/vehicle_hal:
+# Generate the protobuf file from hardware/interfaces/automotive/vehicle/2.0/default/impl/vhal_v2_0
+# It is recommended to use the protoc provided in: prebuilts/tools/common/m2/repository/com/google/protobuf/protoc/3.0.0
+# or a later version, in order to provide Python 3 compatibility
# protoc -I=proto --python_out=proto proto/VehicleHalProto.proto
import VehicleHalProto_pb2
@@ -123,7 +127,7 @@
"""
For debugging, print the protobuf message string in hex.
"""
- print "len = ", len(data), "str = ", ":".join("{:02x}".format(ord(d)) for d in data)
+ print("len = ", len(data), "str = ", ":".join("{:02x}".format(ord(d)) for d in data))
def openSocket(self):
"""
diff --git a/tools/emulator/vhal_emulator_test.py b/tools/emulator/vhal_emulator_test.py
index 325e0a8..b8a8a39 100644
--- a/tools/emulator/vhal_emulator_test.py
+++ b/tools/emulator/vhal_emulator_test.py
@@ -27,6 +27,8 @@
protoc -I=proto --python_out=proto proto/VehicleHalProto.proto
"""
+from __future__ import print_function
+
# Suppress .pyc files
import sys
sys.dont_write_bytecode = True
@@ -54,7 +56,7 @@
testValue = "test string"
elif valType in self._types.TYPE_BYTES:
# Generate array of integers counting from 0
- testValue = range(len(origValue))
+ testValue = list(range(len(origValue)))
elif valType == vhal_consts_2_0.VEHICLE_VALUE_TYPE_BOOLEAN:
testValue = origValue ^ 1
elif valType in self._types.TYPE_INT32:
@@ -216,7 +218,7 @@
newValue = self._getValueFromMsg(rxMsg)
if newValue != testValue:
self._log.error("testGetSet: set failed for propId=%d, area=%d", cfg.prop, area)
- print "testValue= ", testValue, "newValue= ", newValue
+ print("testValue= ", testValue, "newValue= ", newValue)
continue
# Reset the value to what it was before
@@ -287,4 +289,3 @@
if __name__ == '__main__':
v = VhalTest(vhal_consts_2_0.vhal_types_2_0)
v.runTests()
-
diff --git a/vehicle-hal-support-lib/src/com/android/car/vehiclehal/Utils.java b/vehicle-hal-support-lib/src/com/android/car/vehiclehal/Utils.java
index 34fd9cb..2a923bb 100644
--- a/vehicle-hal-support-lib/src/com/android/car/vehiclehal/Utils.java
+++ b/vehicle-hal-support-lib/src/com/android/car/vehiclehal/Utils.java
@@ -17,14 +17,14 @@
package com.android.car.vehiclehal;
import android.util.SparseArray;
-import com.android.car.vehiclehal.Utils.SparseArrayIterator.SparseArrayEntry;
import java.util.Iterator;
class Utils {
private Utils() {}
static class SparseArrayIterator<T>
- implements Iterable<SparseArrayEntry<T>>, Iterator<SparseArrayEntry<T>> {
+ implements Iterable<SparseArrayIterator.SparseArrayEntry<T>>,
+ Iterator<SparseArrayIterator.SparseArrayEntry<T>> {
static class SparseArrayEntry<U> {
public final int key;
public final U value;