diff --git a/openpilot/starpilot/galaxy/tests/test_android_auto.mjs b/openpilot/starpilot/galaxy/tests/test_android_auto.mjs index e7191629ef..9b71967c4e 100644 --- a/openpilot/starpilot/galaxy/tests/test_android_auto.mjs +++ b/openpilot/starpilot/galaxy/tests/test_android_auto.mjs @@ -513,14 +513,23 @@ const namedCalls = [] named.control = (action, extra) => namedCalls.push([action, extra]) named.saveCarType(0, 'Wireless adapter') assert.deepEqual(namedCalls, [['car_type', { carType: 'adapter' }]]) -// A tuned car profile only shows up when one is detected or pinned. -const profiled = page(setup) -assert.equal(profiled.showProfile, false, 'standard cars see nothing') -profiled.runtime = { car_profile_label: 'Hyundai Palisade', car_profile_source: 'detected' } -assert.equal(profiled.showProfile, true) -profiled.runtime = { car_profile_label: '', car_profile_source: 'override' } -assert.equal(profiled.showProfile, true, 'a pinned standard profile can be undone') +// The adapter model picks the AAWireless tuning; any other adapter keeps the regular pairing. +const dongle = page(setup) +dongle.runtime = { car_type: 'adapter', car_profile: 'default', car_profile_source: 'standard' } +assert.equal(dongle.adapterRow.value, 'Choose one', 'no default: the owner picks') +assert.match(dongle.pairingReason, /adapter model/) +dongle.runtime = { car_type: 'adapter', car_profile: 'default', car_profile_source: 'override' } +assert.equal(dongle.adapterRow.value, 'Other') +assert.deepEqual(dongle.adapterRow.choices, ['AAWireless v1', 'Other']) +dongle.runtime = { car_type: 'adapter', car_profile: 'aawireless', car_profile_source: 'override' } +assert.equal(dongle.adapterRow.value, 'AAWireless v1') +const dongleCalls = [] +dongle.control = (action, extra) => dongleCalls.push([action, extra]) +dongle.saveAdapter(0, 'Other') +dongle.saveAdapter(0, 'AAWireless v1') +assert.deepEqual(dongleCalls, [['car_profile', { profile: 'default' }], ['car_profile', { profile: 'aawireless' }]]) +assert.match(AndroidAutoPage.template, /adapterSetup" :row="adapterRow"/) assert.match(AndroidAutoPage.template, /What’s in your car\?|carTypeRow/) assert.match(AndroidAutoPage.template, /runtime\?\.pairing_note/) assert.match(AndroidAutoPage.template, /'Find ' \+ findLabel/) -console.log('Android Auto page: setup type, adapter checklist and car profile line passed') +console.log('Android Auto page: setup type, adapter checklist and adapter model passed') diff --git a/openpilot/starpilot/galaxy/web/js/android-auto.js b/openpilot/starpilot/galaxy/web/js/android-auto.js index 02ad0f6a4d..20da1dfbee 100644 --- a/openpilot/starpilot/galaxy/web/js/android-auto.js +++ b/openpilot/starpilot/galaxy/web/js/android-auto.js @@ -44,6 +44,7 @@ export function uploadPackage(path, options, progress, makeRequest = () => new X } const ADDRESS = /^(?:[0-9A-F]{2}:){5}[0-9A-F]{2}$/ +const ADAPTER_MODELS = { aawireless: "AAWireless v1", default: "Other" } const HEAD_UNIT_APPS = { headunitpad: "HeadunitPad", openheadunit: "Open Headunit" } const HOTSPOT_LINK = `Galaxy Wi-Fi Hotspot` const APP_SETUP = ` @@ -510,7 +511,12 @@ export const AndroidAutoPage = { return { label: "What’s in your car?", value: labels[this.carType], choices: Object.values(labels), available: true, action: true, reason: "Built-in: the car supports wireless Android Auto. Adapter: a dongle such as AAWireless, Motorola MA1 or Carlinkit. Both the adapter and your car get paired." } }, - showProfile() { return !!(this.runtime?.car_profile_label || this.runtime?.car_profile_source === "override") }, + adapterRow() { + const chosen = this.runtime?.car_profile_source === "override" + return { label: "Adapter", value: !chosen ? "Choose one" : this.runtime.car_profile === "aawireless" ? ADAPTER_MODELS.aawireless : ADAPTER_MODELS.default, + choices: Object.values(ADAPTER_MODELS), available: true, action: true, + reason: "AAWireless v1 gets video and car-data settings tuned for that dongle. Other adapters use the regular pairing." } + }, appDisabled() { return !this.setup?.enabled || !this.setup.parked || !!this.pairing?.active || !!this.runtime?.running }, @@ -573,6 +579,7 @@ export const AndroidAutoPage = { if (!this.setup.installReady) return "This build is missing the Android Auto display or encoder." if (this.setup.enabled && !this.setup.serviceReady) return "Waiting for the Android Auto service to start." if (!this.setup.bluetoothEnabled && this.setup.enabled) return "Turn on Bluetooth on the Bluetooth page." + if (this.adapterSetup && this.runtime?.car_profile_source !== "override") return "Choose your adapter model first." if (!this.setup.parked) return "Use offroad mode or Park before starting pairing." if (this.runtime?.running) return "Disconnect from your car before pairing." return "" @@ -582,6 +589,7 @@ export const AndroidAutoPage = { if (!this.setup?.enabled) return "Turn on Android Auto Support in step 1." if (!this.setup.serviceReady) return "Waiting for the Android Auto service to start." if (this.pairing?.active) return "Finish or cancel pairing first." + if (this.adapterSetup && this.runtime?.car_profile_source !== "override") return "Choose your adapter model in step 2 first." return "" }, waitingForCar() { @@ -606,6 +614,10 @@ export const AndroidAutoPage = { if (carType === this.carType) return false return carType ? this.control("car_type", { carType }) : false }, + saveAdapter(index, value) { + const profile = Object.keys(ADAPTER_MODELS).find(key => ADAPTER_MODELS[key] === value) + return profile ? this.control("car_profile", { profile }) : false + }, saveApp(index, value) { const connection = Object.keys(HEAD_UNIT_APPS).find(key => HEAD_UNIT_APPS[key] === value) || "wireless" return this.control("connection", { connection }) @@ -795,10 +807,7 @@ export const AndroidAutoPage = { Wired AA is unavailable: {{ runtime.wired_blocked }}. -

- {{ runtime.car_profile_source === 'override' ? 'Using standard settings for this car.' : 'Tuned for ' + runtime.car_profile_label + ' (detected).' }} -

+