@@ -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,76 @@ 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 > GetDeviceIdToUse ( )
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+ Log . Debug ( "Using quest device" ) ;
247+ if ( questDevices . Count > 1 )
248+ {
249+ Log . Warning ( "Multiple quest devices connected - using the first device" ) ;
250+ }
251+
252+ return questDevices . First ( ) . id ;
253+ }
254+ else
255+ {
256+ Log . Debug ( "Using non-quest device" ) ;
257+ return devices . First ( ) . id ;
258+ }
259+
260+ }
261+
190262 private async Task < bool > FindExistingAdbServer ( )
191263 {
192264 _lastDaemonCheck = DateTime . Now ;
@@ -255,7 +327,7 @@ public async Task<ProcessOutput> RunCommand(string command, params int[] allowed
255327 Log . Debug ( "Executing ADB command: {Command}" , $ "adb { command } ") ;
256328 while ( true )
257329 {
258- var output = await ProcessUtil . InvokeAndCaptureOutput ( _adbPath , command ) ;
330+ var output = await ProcessUtil . InvokeAndCaptureOutput ( _adbPath , _chosenDeviceId == null ? command : $ "-s { _chosenDeviceId } " + command ) ;
259331 if ( output . StandardOutput . Length > 0 )
260332 {
261333 Log . Verbose ( "Standard output: {StandardOutput}" , output . StandardOutput ) ;
@@ -286,7 +358,10 @@ public async Task<ProcessOutput> RunCommand(string command, params int[] allowed
286358 }
287359 else if ( allOutput . Contains ( "multiple devices" ) || output . ErrorOutput . Contains ( "more than one device/emulator" ) )
288360 {
289- await _onDisconnect ( DisconnectionType . MultipleDevices ) ;
361+ Log . Information ( "Multiple devices detected, choosing the Quest device if present" ) ;
362+ _chosenDeviceId = await GetDeviceIdToUse ( ) ;
363+
364+ Log . Information ( "Using {DeviceId}" , _chosenDeviceId ) ;
290365 }
291366 else if ( allOutput . Contains ( "unauthorized" ) )
292367 {
0 commit comments