@@ -83,6 +83,8 @@ public class AndroidDebugBridge
8383 private DateTime _lastDaemonCheck ; // The last time at which QP checked for existing ADB daemons
8484 private Process ? _logcatProcess ;
8585
86+ private string ? _chosenDeviceId ;
87+
8688 public AndroidDebugBridge ( ExternalFilesDownloader filesDownloader , Func < DisconnectionType , Task > onDisconnect )
8789 {
8890 _filesDownloader = filesDownloader ;
@@ -187,6 +189,74 @@ private async Task<bool> SetAdbPathIfValid(string adbExecutablePath)
187189 }
188190 }
189191
192+ /// <summary>
193+ /// Lists the devices connected to ADB.
194+ /// </summary>
195+ /// <returns>A list of the ADB devices.</returns>
196+ private async Task < List < ( string id , string model ) > > ListDevicesInternal ( )
197+ {
198+ var output = await ProcessUtil . InvokeAndCaptureOutput ( _adbExecutableName , "devices -l" ) ;
199+ Log . Debug ( "Listing devices output {Output}" , output . AllOutput ) ;
200+
201+ string [ ] lines = output . StandardOutput . Trim ( ) . Split ( '\n ' ) ;
202+
203+ var devices = new List < ( string id , string model ) > ( ) ;
204+ for ( int i = 1 ; i < lines . Length ; i ++ )
205+ {
206+ string line = lines [ i ] ;
207+
208+ var endIdIdx = line . IndexOf ( ' ' ) ;
209+ if ( endIdIdx == - 1 )
210+ {
211+ continue ;
212+ }
213+
214+ string id = line . Substring ( 0 , endIdIdx ) ;
215+ int modelIdx = line . IndexOf ( "model:" ) ;
216+ if ( modelIdx == - 1 )
217+ {
218+ continue ;
219+ }
220+
221+ int endModelIdx = line . IndexOf ( ' ' , modelIdx ) ;
222+ if ( endModelIdx == - 1 )
223+ {
224+ continue ;
225+ }
226+
227+ string model = line . Substring ( modelIdx + 6 , endModelIdx - modelIdx - 6 ) ;
228+
229+ devices . Add ( ( id , model ) ) ;
230+ }
231+
232+ return devices ;
233+ }
234+
235+ /// <returns>The device ID of one of the Quest devices connected, or a non-quest device if no quest is present.</returns>
236+ private async Task < ( string id , string model ) > GetDeviceToUse ( )
237+ {
238+ var devices = await ListDevicesInternal ( ) ;
239+
240+ var questDevices = devices
241+ . Where ( device => device . id . Contains ( "quest" , StringComparison . OrdinalIgnoreCase ) )
242+ . ToList ( ) ;
243+
244+ if ( questDevices . Any ( ) )
245+ {
246+ if ( questDevices . Count > 1 )
247+ {
248+ Log . Warning ( "Multiple quest devices connected - using the first device" ) ;
249+ }
250+
251+ return questDevices . First ( ) ;
252+ }
253+ else
254+ {
255+ return devices . First ( ) ;
256+ }
257+
258+ }
259+
190260 private async Task < bool > FindExistingAdbServer ( )
191261 {
192262 _lastDaemonCheck = DateTime . Now ;
@@ -255,7 +325,7 @@ public async Task<ProcessOutput> RunCommand(string command, params int[] allowed
255325 Log . Debug ( "Executing ADB command: {Command}" , $ "adb { command } ") ;
256326 while ( true )
257327 {
258- var output = await ProcessUtil . InvokeAndCaptureOutput ( _adbPath , command ) ;
328+ var output = await ProcessUtil . InvokeAndCaptureOutput ( _adbPath , _chosenDeviceId == null ? command : $ "-s { _chosenDeviceId } " + command ) ;
259329 if ( output . StandardOutput . Length > 0 )
260330 {
261331 Log . Verbose ( "Standard output: {StandardOutput}" , output . StandardOutput ) ;
@@ -286,7 +356,11 @@ public async Task<ProcessOutput> RunCommand(string command, params int[] allowed
286356 }
287357 else if ( allOutput . Contains ( "multiple devices" ) || output . ErrorOutput . Contains ( "more than one device/emulator" ) )
288358 {
289- await _onDisconnect ( DisconnectionType . MultipleDevices ) ;
359+ Log . Information ( "Multiple devices detected, choosing the Quest device if present" ) ;
360+ var device = await GetDeviceToUse ( ) ;
361+ _chosenDeviceId = device . id ;
362+
363+ Log . Information ( "Using id: {DeviceId} model: {Model}" , device . id , device . model ) ;
290364 }
291365 else if ( allOutput . Contains ( "unauthorized" ) )
292366 {
0 commit comments