From 05eea4d0c1b34c94d5831ba97e4fa45411739c59 Mon Sep 17 00:00:00 2001 From: rsilveira Date: Wed, 20 May 2026 15:50:33 -0300 Subject: [PATCH 1/3] fix: reset i-MID status on exit and harden system service calls to prevent head unit crashes --- .../smg/hu/manager/HondaConnectManager.java | 209 +++++++++++++----- .../it/smg/hu/projection/InputDevice.java | 57 ++--- 2 files changed, 190 insertions(+), 76 deletions(-) diff --git a/app/src/main/java/it/smg/hu/manager/HondaConnectManager.java b/app/src/main/java/it/smg/hu/manager/HondaConnectManager.java index 66d4c99a..ac594e6a 100644 --- a/app/src/main/java/it/smg/hu/manager/HondaConnectManager.java +++ b/app/src/main/java/it/smg/hu/manager/HondaConnectManager.java @@ -68,8 +68,8 @@ static class ModeMgrMode { private static HondaConnectManager instance_; - private final ModeMgrManager modeMgrManager_; - private final StateMgrManager stateMgrManager_; + private ModeMgrManager modeMgrManager_; + private StateMgrManager stateMgrManager_; private IModeMgrServiceCallBack modeMgrServiceCallBack_; private IModeMgrServiceSWKeyEventCallBack modeMgrServiceSWKeyEventCallBack_; @@ -98,22 +98,38 @@ static class ModeMgrMode { private final Handler mainHandler_; private final List listeners_ = new ArrayList<>(); + private static Context appContext_; + public static void init(Context context){ - instance_ = new HondaConnectManager(context); + appContext_ = context.getApplicationContext(); + instance_ = new HondaConnectManager(appContext_); } public static HondaConnectManager instance(){ + if (instance_ == null) { + synchronized (HondaConnectManager.class) { + if (instance_ == null && appContext_ != null) { + instance_ = new HondaConnectManager(appContext_); + } + } + } return instance_; } public void addListener(HondaListener listener) { - if (!listeners_.contains(listener)) { - listeners_.add(listener); + if (listener == null) return; + synchronized (listeners_) { + if (!listeners_.contains(listener)) { + listeners_.add(listener); + } } } public void removeListener(HondaListener listener) { - listeners_.remove(listener); + if (listener == null) return; + synchronized (listeners_) { + listeners_.remove(listener); + } } @SuppressLint("WrongConstant") @@ -126,14 +142,19 @@ private HondaConnectManager(Context context){ micVrStarted_ = false; mainHandler_ = new Handler(Looper.getMainLooper()); - modeMgrManager_ = (ModeMgrManager) context.getSystemService(ModeMgrService); - if (modeMgrManager_ == null){ - if (Log.isWarn()) Log.w(TAG, "modeMgrManager null"); + modeMgrManager_ = null; + stateMgrManager_ = null; + + try { + modeMgrManager_ = (ModeMgrManager) context.getSystemService(ModeMgrService); + } catch (Throwable t) { + Log.e(TAG, "Could not get ModeMgrService", t); } - stateMgrManager_ = (StateMgrManager) context.getSystemService(StateMgrService); - if (stateMgrManager_ == null) { - if (Log.isWarn()) Log.w(TAG, "stateMgrManager null"); + try { + stateMgrManager_ = (StateMgrManager) context.getSystemService(StateMgrService); + } catch (Throwable t) { + Log.e(TAG, "Could not get StateMgrService", t); } steeringMenuServiceConnection_ = new ServiceConnection() { @@ -141,23 +162,39 @@ private HondaConnectManager(Context context){ @Override public void onServiceConnected(ComponentName name, IBinder service) { - if (Log.isVerbose()) Log.v(TAG, "Honda Wheel Service connected"); - boundToSteeringMenuService_ = true; - steeringMenuServiceIface_ = ISteeringMenuService.Stub.asInterface(service); - - registerSteeringMenuCallback(); - - if (pControl_.authType != Constants.AUTH_TYPE_PREINSTALL){ - notifySteeringMenuDispMode(1); + try { + if (Log.isVerbose()) Log.v(TAG, "Honda Wheel Service connected"); + boundToSteeringMenuService_ = true; + steeringMenuServiceIface_ = ISteeringMenuService.Stub.asInterface(service); + + int idx = settings_.advanced.steeringWheelIdx(); + mainHandler_.post(() -> { + try { + Toast.makeText(context_.getApplicationContext(), "Wheel Service Connected (Idx: " + idx + ")", Toast.LENGTH_SHORT).show(); + } catch (Throwable t) {} + }); + + registerSteeringMenuCallback(); + + if (pControl_ != null && pControl_.authType != Constants.AUTH_TYPE_PREINSTALL){ + notifySteeringMenuDispMode(1); + } + } catch (Throwable t) { + Log.e(TAG, "Error in onServiceConnected Wheel", t); } - } @Override public void onServiceDisconnected(ComponentName name) { if (Log.isVerbose()) Log.v(TAG, "Honda Wheel Service disconnected"); + try { + if (modeMgrManager_ != null) { + modeMgrManager_.setImidConnectStatus(0); + } + } catch (Throwable t) {} boundToSteeringMenuService_ = false; steeringMenuServiceIface_ = null; + steeringMenuServiceCallback_ = null; } }; @@ -166,15 +203,23 @@ public void onServiceDisconnected(ComponentName name) { @Override public void onServiceConnected(ComponentName name, IBinder service) { - if (Log.isVerbose()) Log.v(TAG, "Honda EcNc Service connected"); - boundToEcNcService_ = true; - ecNcServiceIface_ = IEcNcService.Stub.asInterface(service); + try { + if (Log.isVerbose()) Log.v(TAG, "Honda EcNc Service connected"); + boundToEcNcService_ = true; + ecNcServiceIface_ = IEcNcService.Stub.asInterface(service); + } catch (Throwable t) { + Log.e(TAG, "Error in onServiceConnected EcNc", t); + } } @Override public void onServiceDisconnected(ComponentName name) { if (Log.isVerbose()) Log.v(TAG, "Honda EcNc Service disconnected"); - + try { + if (modeMgrManager_ != null) { + modeMgrManager_.setImidConnectStatus(0); + } + } catch (Throwable t) {} boundToEcNcService_ = false; ecNcServiceIface_ = null; micVrStarted_ = false; // force to false @@ -203,7 +248,7 @@ public void onServiceDisconnected(ComponentName name) { } public int mediaAudioStream(ChannelId audioChannel){ - if (pControl_.authType == Constants.AUTH_TYPE_PREINSTALL){ + if (pControl_ != null && pControl_.authType == Constants.AUTH_TYPE_PREINSTALL){ switch (audioChannel) { case SPEECH_AUDIO: case SYSTEM_AUDIO: @@ -229,6 +274,14 @@ public void adjustPermission(){ } public void requestAudioFocus(){ + if (pControl_ == null) { + if (Log.isWarn()) Log.w(TAG, "requestAudioFocus -> pControl_ is null"); + return; + } + if (modeMgrManager_ == null) { + if (Log.isWarn()) Log.w(TAG, "requestAudioFocus -> modeMgrManager_ is null"); + return; + } if (Log.isDebug()) Log.d(TAG, "requestAudioFocus -> app with auth " + pControl_.authType); if (Log.isVerbose()) Log.v(TAG, "requestAudioFocus modeMgr audio hasAudioFocus= " + hasAudioFocus_); @@ -246,8 +299,8 @@ public void requestAudioFocus(){ try { modeMgrManager_.setImidConnectStatus(1); - } catch (Exception e) { - Log.w(TAG, "Could not set i-MID connect status", e); + } catch (Throwable t) { + Log.w(TAG, "Could not set i-MID connect status", t); } hasAudioFocus_ = true; @@ -255,6 +308,14 @@ public void requestAudioFocus(){ } public void releaseAudioFocus(){ + if (pControl_ == null) { + if (Log.isWarn()) Log.w(TAG, "releaseAudioFocus -> pControl_ is null"); + return; + } + if (modeMgrManager_ == null) { + if (Log.isWarn()) Log.w(TAG, "releaseAudioFocus -> modeMgrManager_ is null"); + return; + } if (Log.isDebug()) Log.d(TAG, "releaseAudioFocus -> app with auth " + pControl_.authType); if (Log.isVerbose()) Log.v(TAG, "releaseAudioFocus modeMgr audio hasAudioFocus= " + hasAudioFocus_); @@ -263,6 +324,14 @@ public void releaseAudioFocus(){ int idx = settings_.advanced.modeMgrAudioIdx(); int ret; + try { + if (Log.isDebug()) Log.d(TAG, "releaseAudioFocus -> resetting i-MID and Steering Display"); + modeMgrManager_.setImidConnectStatus(0); + notifySteeringMenuDispMode(0); + } catch (Throwable t) { + Log.w(TAG, "Could not reset i-MID/Steering status", t); + } + if (Log.isVerbose()) Log.v(TAG, "releaseAudioFocus sendModeMgrOffReq idx= " + idx + ", state = " + ModeMgrMode.REQUEST_MODE); ret = modeMgrManager_.sendModeMgrOffReq(idx, ModeMgrMode.REQUEST_MODE); if (Log.isVerbose()) Log.v(TAG, "releaseAudioFocus sendModeMgrOffReq ret= " + ret); @@ -273,17 +342,25 @@ public void releaseAudioFocus(){ public void increaseVolume(){ if (Log.isVerbose()) Log.v(TAG, "increaseVolume"); - modeMgrManager_.reqModeMgrSteeringVolCmd(true); + if (modeMgrManager_ != null) { + modeMgrManager_.reqModeMgrSteeringVolCmd(true); + } } public void decreaseVolume(){ if (Log.isVerbose()) Log.v(TAG, "decreaseVolume"); - modeMgrManager_.reqModeMgrSteeringVolCmd(false); + if (modeMgrManager_ != null) { + modeMgrManager_.reqModeMgrSteeringVolCmd(false); + } } // Used in onCreate public void initialize(){ - if (Log.isDebug()) Log.d(TAG, "initialize -> app with auth " + pControl_.authType); + if (pControl_ != null) { + if (Log.isDebug()) Log.d(TAG, "initialize -> app with auth " + pControl_.authType); + } else { + if (Log.isDebug()) Log.d(TAG, "initialize -> pControl_ is null"); + } bindToEcNcService(); bindToWheelService(); @@ -292,6 +369,10 @@ public void initialize(){ // Used in onResume public void initAudioBinding(){ + if (pControl_ == null) { + if (Log.isWarn()) Log.w(TAG, "initAudioBinding -> pControl_ is null"); + return; + } if (Log.isDebug()) Log.d(TAG, "initAudioBinding -> app with auth " + pControl_.authType); // if app has THIRD_PARTY auth will have exclusive audio focus, only bind wheel service if (pControl_.authType == Constants.AUTH_TYPE_PREINSTALL){ @@ -316,19 +397,23 @@ public void initAudioBinding(){ // Used in onPause (app in background) public void sendToBackground(){ - if (Log.isDebug()) Log.d(TAG, "sendToBackground -> app with auth " + pControl_.authType + " unregister SW callback"); + if (pControl_ != null) { + if (Log.isDebug()) Log.d(TAG, "sendToBackground -> app with auth " + pControl_.authType + " unregister SW callback"); + } unregisterSteeringMenuCallback(); unregisterStateMgrCallback(); notifySteeringMenuDispMode(0); } public void endAudioBinding(){ - if (Log.isDebug()) Log.d(TAG, "endAudioBinding -> app with auth " + pControl_.authType); + if (pControl_ != null) { + if (Log.isDebug()) Log.d(TAG, "endAudioBinding -> app with auth " + pControl_.authType); + } stopMicSession(); unbindFromEcNcService(); - if (pControl_.authType == Constants.AUTH_TYPE_PREINSTALL){ + if (pControl_ != null && pControl_.authType == Constants.AUTH_TYPE_PREINSTALL){ if (Log.isDebug()) Log.d(TAG, "endAudioBinding -> auth PREINSTALL -> release audio and unregister modemgr callback"); releaseAudioFocus(); unregisterModeMgrCallback(); @@ -341,12 +426,14 @@ public void endAudioBinding(){ private void notifySteeringMenuDispMode(int mode){ if (Log.isDebug()) Log.d(TAG, "notifySteeringMenuDispMode -> boundToSteeringMenuService= " + boundToSteeringMenuService_); - if (boundToSteeringMenuService_) { + if (boundToSteeringMenuService_ && steeringMenuServiceIface_ != null) { try { - int idx = settings_.advanced.steeringWheelIdx(); - if (idx > 0) { - if (Log.isVerbose()) Log.v(TAG, "notifySteeringMenuDispMode " + mode + " addr " + idx); - steeringMenuServiceIface_.notifySteeringMenuDispMode(idx, mode); + if (settings_ != null && settings_.advanced != null) { + int idx = settings_.advanced.steeringWheelIdx(); + if (idx > 0) { + if (Log.isVerbose()) Log.v(TAG, "notifySteeringMenuDispMode " + mode + " addr " + idx); + steeringMenuServiceIface_.notifySteeringMenuDispMode(idx, mode); + } } } catch (RemoteException e) { Log.e(TAG, "Error registering", e); @@ -371,14 +458,14 @@ private void registerSteeringMenuCallback(){ private void unregisterSteeringMenuCallback(){ if (Log.isDebug()) Log.d(TAG, "unregisterSteeringMenuCallback -> boundToSteeringMenuService= " + boundToSteeringMenuService_ + ", steeringMenuServiceCallback= " + (steeringMenuServiceCallback_ == null ? "null" : "not null")); try { - if (boundToSteeringMenuService_ && steeringMenuServiceCallback_ != null) { + if (boundToSteeringMenuService_ && steeringMenuServiceIface_ != null && steeringMenuServiceCallback_ != null) { int idx = settings_.advanced.steeringWheelIdx(); if (Log.isVerbose()) Log.v(TAG, "unregisterCallbackEx swaddr " + idx); steeringMenuServiceIface_.unregisterCallbackEx(steeringMenuServiceCallback_, idx); steeringMenuServiceCallback_ = null; } - } catch (RemoteException e) { - Log.e(TAG, "Error unregisterCallbackEx", e); + } catch (Throwable t) { + Log.e(TAG, "Error unregisterCallbackEx", t); } } @@ -492,6 +579,7 @@ private void unbindToWheelService(){ private void unregisterModeMgrCallback() { if (Log.isVerbose()) Log.v(TAG, "unregisterModeMgrCallback"); + if (modeMgrManager_ == null) return; int idx = settings_.advanced.modeMgrAudioIdx(); if (Log.isVerbose()) Log.v(TAG, "unregisterModeMgrCallback idx " + idx); @@ -527,7 +615,11 @@ private void registerStateMgrCallback() { StateMgrInfo currentState = stateMgrManager_.getAllState(); if (currentState != null) { boolean isNight = currentState.dayNightState == StateMgrServiceConst.STATE_NIGHT; - for (HondaListener l : listeners_) l.onDayNightUpdate(isNight); + List listenersCopy; + synchronized (listeners_) { + listenersCopy = new ArrayList<>(listeners_); + } + for (HondaListener l : listenersCopy) l.onDayNightUpdate(isNight); } } } @@ -561,20 +653,32 @@ private void unregisterStateMgrCallback() { private class SteeringMenuServiceCallback extends ISteeringMenuServiceCallback.Stub { private static final String TAG = "HondaConnectManager-ISteeringMenuServiceCallback"; - public void onShowView() { + @Override + public void onShowView() throws RemoteException { if (Log.isVerbose()) Log.v(TAG, "onShowView"); notifySteeringMenuDispMode(1); } - public boolean onFinishView(boolean flg, boolean anime) { + @Override + public boolean onFinishView(boolean flg, boolean anime) throws RemoteException { if (Log.isVerbose()) Log.v(TAG, "onFinishView"); return true; } - public boolean onSteeringSWDown(int keytype) { - if (Log.isVerbose()) Log.v(TAG, "onSteeringSWDown " + keytype); - for (HondaListener l : listeners_) { - l.onSteeringWheelKey(keytype); + @Override + public boolean onSteeringSWDown(int keytype) throws RemoteException { + if (Log.isDebug()) Log.d(TAG, "onSteeringSWDown " + keytype); + + List listenersCopy; + synchronized (listeners_) { + listenersCopy = new ArrayList<>(listeners_); + } + for (HondaListener l : listenersCopy) { + try { + l.onSteeringWheelKey(keytype); + } catch (Throwable t) { + Log.e(TAG, "Error in listener callback", t); + } } return true; } @@ -589,7 +693,11 @@ public void onChangeState(StateMgrInfo stateMgrInfo) throws RemoteException { if (stateMgrInfo.updateState.dayNightStateC) { boolean isNight = stateMgrInfo.dayNightState == StateMgrServiceConst.STATE_NIGHT; if (Log.isDebug()) Log.d(TAG, "DayNight state changed, isNight: " + isNight); - for (HondaListener l : listeners_) { + List listenersCopy; + synchronized (listeners_) { + listenersCopy = new ArrayList<>(listeners_); + } + for (HondaListener l : listenersCopy) { l.onDayNightUpdate(isNight); } } @@ -670,3 +778,4 @@ public void insDispApl(int disp, int extInfo1, int extInfo2) throws RemoteExcept } }; } + diff --git a/app/src/main/java/it/smg/hu/projection/InputDevice.java b/app/src/main/java/it/smg/hu/projection/InputDevice.java index c312dfc6..6661ab79 100644 --- a/app/src/main/java/it/smg/hu/projection/InputDevice.java +++ b/app/src/main/java/it/smg/hu/projection/InputDevice.java @@ -220,33 +220,38 @@ public void onDayNightUpdate(boolean isNight) { @Override public void onSteeringWheelKey(int keyType) { - if (Log.isDebug()) Log.d(TAG, "onSteeringWheelKey: " + keyType); - - // Map Honda specific key types to Android Auto button codes - // These are keys that might not be captured by onKey - int buttonCode = -1; - switch (keyType) { - case 3: // CH/TRK UP - buttonCode = 0x57; // NEXT - break; - case 4: // CH/TRK DOWN - buttonCode = 0x58; // PREV - break; - case 8: // Pick up - buttonCode = 0x05; // PHONE - break; - case 9: // Hang up - buttonCode = 0x06; // CALL_END - break; - case 10: // Talk - buttonCode = 0x54; // MICROPHONE_1 - break; - } + try { + if (Log.isDebug()) Log.d(TAG, "onSteeringWheelKey: " + keyType); + + // Map Honda specific key types to Android Auto button codes + int buttonCode = -1; + switch (keyType) { + case 1: // Some units use 1/2 for track + case 3: // CH/TRK UP + buttonCode = 87; // KEYCODE_MEDIA_NEXT + break; + case 2: + case 4: // CH/TRK DOWN + buttonCode = 88; // KEYCODE_MEDIA_PREVIOUS + break; + case 8: // Pick up + buttonCode = 5; // KEYCODE_CALL + break; + case 9: // Hang up + buttonCode = 6; // KEYCODE_ENDCALL + break; + case 10: // Talk + buttonCode = 84; // KEYCODE_SEARCH (often used for VR) + break; + } - if (buttonCode != -1) { - if (Log.isVerbose()) Log.v(TAG, "Sending button event for Honda key " + keyType + " -> " + buttonCode); - sendButtonEvent(0, buttonCode); // DOWN - sendButtonEvent(1, buttonCode); // UP + if (buttonCode != -1) { + if (Log.isVerbose()) Log.v(TAG, "Sending button event for Honda key " + keyType + " -> " + buttonCode); + sendButtonEvent(0, buttonCode); // DOWN + sendButtonEvent(1, buttonCode); // UP + } + } catch (Throwable t) { + Log.e(TAG, "Error handling steering wheel key", t); } } From 0226881ae7229b24e398b4eab284fe44f51495b3 Mon Sep 17 00:00:00 2001 From: rsilveira Date: Tue, 2 Jun 2026 11:58:14 -0300 Subject: [PATCH 2/3] fix: ensure audio focus release and update steering index for HR-V 2016 --- .../main/java/it/smg/hu/config/Settings.java | 2 +- .../smg/hu/manager/HondaConnectManager.java | 91 +++++++++++++------ 2 files changed, 65 insertions(+), 28 deletions(-) diff --git a/app/src/main/java/it/smg/hu/config/Settings.java b/app/src/main/java/it/smg/hu/config/Settings.java index 226dd493..daad03ed 100644 --- a/app/src/main/java/it/smg/hu/config/Settings.java +++ b/app/src/main/java/it/smg/hu/config/Settings.java @@ -511,7 +511,7 @@ public class Advanced extends Base{ public final static boolean ADVANCED_ENABLE_HONDA_MIC_VR_DEFAULT_VALUE = true; public final static String ADVANCED_SW_MODE_DEFAULT_VALUE = "SW SERVICE"; public final static int ADVANCED_MODEMGRAUDIO_IDX_DEFAULT_VALUE = 213; // 223 appmode, 220 appmodepic, 213 3rd party, 214 3rd party pic, 197 bt, 92 cam, 98 cd, 196 dab, 216 hdmi, 201 ipod, 222 mirrolink, 221 mirrorlink pic, 255 off, 87 phone, 198 tel rcv, 199 usb audio, 133 voicetag, 136 siri, 96 radio - public final static int ADVANCED_SW_IDX_DEFAULT_VALUE = 260; // 258 source, 263 source header, 259 disp, 260 menu, 265 launcher, 266 imid + public final static int ADVANCED_SW_IDX_DEFAULT_VALUE = 160; // 258 source, 263 source header, 259 disp, 260 menu, 265 launcher, 266 imid, 160 verified for HR-V 2016 public void logDir(String logDir){ SP.edit().putString(ADVANCED_LOG_DIR, logDir).apply(); diff --git a/app/src/main/java/it/smg/hu/manager/HondaConnectManager.java b/app/src/main/java/it/smg/hu/manager/HondaConnectManager.java index ac594e6a..37c1d6f5 100644 --- a/app/src/main/java/it/smg/hu/manager/HondaConnectManager.java +++ b/app/src/main/java/it/smg/hu/manager/HondaConnectManager.java @@ -160,6 +160,19 @@ private HondaConnectManager(Context context){ steeringMenuServiceConnection_ = new ServiceConnection() { private static final String TAG = "HondaConnectManager-steeringServiceConnection"; + private IBinder.DeathRecipient deathRecipient = new IBinder.DeathRecipient() { + @Override + public void binderDied() { + Log.e(TAG, "SteeringMenuService DIED! Unbinding and attempting recovery."); + boundToSteeringMenuService_ = false; + steeringMenuServiceIface_ = null; + steeringMenuServiceCallback_ = null; + try { + context_.unbindService(steeringMenuServiceConnection_); + } catch (Exception e) {} + } + }; + @Override public void onServiceConnected(ComponentName name, IBinder service) { try { @@ -167,6 +180,12 @@ public void onServiceConnected(ComponentName name, IBinder service) { boundToSteeringMenuService_ = true; steeringMenuServiceIface_ = ISteeringMenuService.Stub.asInterface(service); + try { + service.linkToDeath(deathRecipient, 0); + } catch (RemoteException e) { + Log.e(TAG, "Failed to link to death for Wheel Service", e); + } + int idx = settings_.advanced.steeringWheelIdx(); mainHandler_.post(() -> { try { @@ -201,12 +220,31 @@ public void onServiceDisconnected(ComponentName name) { ecNcServiceConnection_ = new ServiceConnection() { private static final String TAG = "HondaConnectManager-ecNcServiceConnection"; + private IBinder.DeathRecipient deathRecipient = new IBinder.DeathRecipient() { + @Override + public void binderDied() { + Log.e(TAG, "EcNcService DIED! Unbinding and attempting recovery."); + boundToEcNcService_ = false; + ecNcServiceIface_ = null; + micVrStarted_ = false; + try { + context_.unbindService(ecNcServiceConnection_); + } catch (Exception e) {} + } + }; + @Override public void onServiceConnected(ComponentName name, IBinder service) { try { if (Log.isVerbose()) Log.v(TAG, "Honda EcNc Service connected"); boundToEcNcService_ = true; ecNcServiceIface_ = IEcNcService.Stub.asInterface(service); + + try { + service.linkToDeath(deathRecipient, 0); + } catch (RemoteException e) { + Log.e(TAG, "Failed to link to death for EcNc Service", e); + } } catch (Throwable t) { Log.e(TAG, "Error in onServiceConnected EcNc", t); } @@ -283,10 +321,8 @@ public void requestAudioFocus(){ return; } if (Log.isDebug()) Log.d(TAG, "requestAudioFocus -> app with auth " + pControl_.authType); - if (Log.isVerbose()) Log.v(TAG, "requestAudioFocus modeMgr audio hasAudioFocus= " + hasAudioFocus_); - - // If AUTH_TYPE <> preinstall the app has already audio focus - if (pControl_.authType == Constants.AUTH_TYPE_PREINSTALL && !hasAudioFocus_) { + + if (!hasAudioFocus_) { int idx = settings_.advanced.modeMgrAudioIdx(); int ret; @@ -317,10 +353,8 @@ public void releaseAudioFocus(){ return; } if (Log.isDebug()) Log.d(TAG, "releaseAudioFocus -> app with auth " + pControl_.authType); - if (Log.isVerbose()) Log.v(TAG, "releaseAudioFocus modeMgr audio hasAudioFocus= " + hasAudioFocus_); - // If AUTH_TYPE <> preinstall the app has already audio focus - if (pControl_.authType == Constants.AUTH_TYPE_PREINSTALL && hasAudioFocus_) { + if (hasAudioFocus_) { int idx = settings_.advanced.modeMgrAudioIdx(); int ret; @@ -336,6 +370,11 @@ public void releaseAudioFocus(){ ret = modeMgrManager_.sendModeMgrOffReq(idx, ModeMgrMode.REQUEST_MODE); if (Log.isVerbose()) Log.v(TAG, "releaseAudioFocus sendModeMgrOffReq ret= " + ret); + try { + // Notify ModeMgr that we are truly OFF to release native radio + modeMgrManager_.notifyModeMgrStatus(idx, 0); + } catch (Throwable t) {} + hasAudioFocus_ = false; } } @@ -374,23 +413,22 @@ public void initAudioBinding(){ return; } if (Log.isDebug()) Log.d(TAG, "initAudioBinding -> app with auth " + pControl_.authType); - // if app has THIRD_PARTY auth will have exclusive audio focus, only bind wheel service - if (pControl_.authType == Constants.AUTH_TYPE_PREINSTALL){ - if (Log.isVerbose()) Log.v(TAG, "initAudioBinding -> app auth = preinstall -> register ModeMgr and SW callback"); + + // Deep Sleep Recovery: Attempt to rebind services if they died + if (!boundToSteeringMenuService_) { + Log.w(TAG, "Wheel service is not bound during initAudioBinding. Attempting to recover..."); + bindToWheelService(); + } + if (!boundToEcNcService_) { + bindToEcNcService(); + } - registerModeMgrCallback(); - registerSteeringMenuCallback(); - registerStateMgrCallback(); + // register all regardless of authType to be safe + registerModeMgrCallback(); + registerSteeringMenuCallback(); + registerStateMgrCallback(); - if (Log.isVerbose()) Log.v(TAG, "initAudioBinding -> hasAudioFocus= " + hasAudioFocus_); - if (hasAudioFocus_){ - notifySteeringMenuDispMode(1); - } - } else { - // THIRD_PARTY - if (Log.isVerbose()) Log.v(TAG, "initAudioBinding -> using authType not PREINSTALL -> register SW callback and notify"); - registerSteeringMenuCallback(); - registerStateMgrCallback(); + if (hasAudioFocus_){ notifySteeringMenuDispMode(1); } } @@ -413,11 +451,9 @@ public void endAudioBinding(){ stopMicSession(); unbindFromEcNcService(); - if (pControl_ != null && pControl_.authType == Constants.AUTH_TYPE_PREINSTALL){ - if (Log.isDebug()) Log.d(TAG, "endAudioBinding -> auth PREINSTALL -> release audio and unregister modemgr callback"); - releaseAudioFocus(); - unregisterModeMgrCallback(); - } + if (Log.isDebug()) Log.d(TAG, "endAudioBinding -> release audio and unregister callbacks"); + releaseAudioFocus(); + unregisterModeMgrCallback(); unregisterSteeringMenuCallback(); unregisterStateMgrCallback(); @@ -447,6 +483,7 @@ private void registerSteeringMenuCallback(){ if (boundToSteeringMenuService_ && steeringMenuServiceCallback_ == null) { int idx = settings_.advanced.steeringWheelIdx(); if (Log.isVerbose()) Log.v(TAG, "registerCallbackEx swaddr " + idx); + steeringMenuServiceCallback_ = new SteeringMenuServiceCallback(); steeringMenuServiceIface_.registerCallbackEx(steeringMenuServiceCallback_, idx); } From 633b0319d9b0c731128e282c0cbd73b30f653130 Mon Sep 17 00:00:00 2001 From: rsilveira Date: Tue, 2 Jun 2026 11:59:27 -0300 Subject: [PATCH 3/3] fix: correct default steering wheel index to 260 --- app/src/main/java/it/smg/hu/config/Settings.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/it/smg/hu/config/Settings.java b/app/src/main/java/it/smg/hu/config/Settings.java index daad03ed..7befcf29 100644 --- a/app/src/main/java/it/smg/hu/config/Settings.java +++ b/app/src/main/java/it/smg/hu/config/Settings.java @@ -511,7 +511,7 @@ public class Advanced extends Base{ public final static boolean ADVANCED_ENABLE_HONDA_MIC_VR_DEFAULT_VALUE = true; public final static String ADVANCED_SW_MODE_DEFAULT_VALUE = "SW SERVICE"; public final static int ADVANCED_MODEMGRAUDIO_IDX_DEFAULT_VALUE = 213; // 223 appmode, 220 appmodepic, 213 3rd party, 214 3rd party pic, 197 bt, 92 cam, 98 cd, 196 dab, 216 hdmi, 201 ipod, 222 mirrolink, 221 mirrorlink pic, 255 off, 87 phone, 198 tel rcv, 199 usb audio, 133 voicetag, 136 siri, 96 radio - public final static int ADVANCED_SW_IDX_DEFAULT_VALUE = 160; // 258 source, 263 source header, 259 disp, 260 menu, 265 launcher, 266 imid, 160 verified for HR-V 2016 + public final static int ADVANCED_SW_IDX_DEFAULT_VALUE = 260; // 258 source, 263 source header, 259 disp, 260 menu, 265 launcher, 266 imid, 260 verified for HR-V 2016 public void logDir(String logDir){ SP.edit().putString(ADVANCED_LOG_DIR, logDir).apply();