forked from appium/dotnet-client
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathAndroidDriver.cs
More file actions
603 lines (515 loc) · 31.5 KB
/
Copy pathAndroidDriver.cs
File metadata and controls
603 lines (515 loc) · 31.5 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
//Licensed under the Apache License, Version 2.0 (the "License");
//you may not use this file except in compliance with the License.
//See the NOTICE file distributed with this work for additional
//information regarding copyright ownership.
//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.
using OpenQA.Selenium.Appium.Android.Interfaces;
using OpenQA.Selenium.Appium.Enums;
using OpenQA.Selenium.Appium.Interfaces;
using OpenQA.Selenium.Appium.Service;
using OpenQA.Selenium.Appium.WebSocket;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using OpenQA.Selenium.Appium.Android.Enums;
using System.Threading.Tasks;
namespace OpenQA.Selenium.Appium.Android
{
public class AndroidDriver : AppiumDriver,
IStartsActivity,
INetworkActions, IHasClipboard, IHasPerformanceData,
ISendsKeyEvents,
IPushesFiles, IHasSettings, IListensToLogcatMessages
{
private static readonly string Platform = MobilePlatform.Android;
private readonly StringWebSocketClient _logcatClient = new();
private const int DefaultAppiumPort = 4723;
/// <summary>
/// Initializes a new instance of the AndroidDriver class
/// </summary>
/// <param name="commandExecutor">An <see cref="ICommandExecutor"/> object which executes commands for the driver.</param>
/// <param name="driverOptions">An <see cref="ICapabilities"/> object containing the Appium options.</param>
public AndroidDriver(ICommandExecutor commandExecutor, DriverOptions driverOptions)
: base(commandExecutor, SetPlatformToCapabilities(driverOptions, Platform))
{
}
/// <summary>
/// Initializes a new instance of the AndroidDriver class using Appium options
/// </summary>
/// <param name="driverOptions">An <see cref="DriverOptions"/> object containing the Appium options of the browser.</param>
public AndroidDriver(DriverOptions driverOptions)
: base(SetPlatformToCapabilities(driverOptions, Platform))
{
}
/// <summary>
/// Initializes a new instance of the AndroidDriver class using Appium options and command timeout
/// </summary>
/// <param name="driverOptions">An <see cref="ICapabilities"/> object containing the Appium options.</param>
/// <param name="commandTimeout">The maximum amount of time to wait for each command.</param>
public AndroidDriver(DriverOptions driverOptions, TimeSpan commandTimeout)
: base(SetPlatformToCapabilities(driverOptions, Platform), commandTimeout)
{
}
/// <summary>
/// Initializes a new instance of the AndroidDriver class using the AppiumServiceBuilder instance and Appium options
/// </summary>
/// <param name="builder"> object containing settings of the Appium local service which is going to be started</param>
/// <param name="driverOptions">An <see cref="ICapabilities"/> object containing the Appium options.</param>
public AndroidDriver(AppiumServiceBuilder builder, DriverOptions driverOptions)
: base(builder, SetPlatformToCapabilities(driverOptions, Platform))
{
}
/// <summary>
/// Initializes a new instance of the AndroidDriver class using the AppiumServiceBuilder instance, Appium options and command timeout
/// </summary>
/// <param name="builder"> object containing settings of the Appium local service which is going to be started</param>
/// <param name="driverOptions">An <see cref="ICapabilities"/> object containing the Appium options.</param>
/// <param name="commandTimeout">The maximum amount of time to wait for each command.</param>
public AndroidDriver(AppiumServiceBuilder builder, DriverOptions driverOptions,
TimeSpan commandTimeout)
: base(builder, SetPlatformToCapabilities(driverOptions, Platform), commandTimeout)
{
}
/// <summary>
/// Initializes a new instance of the AndroidDriver class using the specified remote address and Appium options
/// </summary>
/// <param name="remoteAddress">URI containing the address of the WebDriver remote server (e.g. http://127.0.0.1:4723/).</param>
/// <param name="driverOptions">An <see cref="DriverOptions"/> object containing the Appium options.</param>
public AndroidDriver(Uri remoteAddress, DriverOptions driverOptions)
: base(remoteAddress, SetPlatformToCapabilities(driverOptions, Platform))
{
}
/// <summary>
/// Initializes a new instance of the AndroidDriver class using the specified Appium local service and Appium options
/// </summary>
/// <param name="service">the specified Appium local service</param>
/// <param name="driverOptions">An <see cref="ICapabilities"/> object containing the Appium options of the browser.</param>
public AndroidDriver(AppiumLocalService service, DriverOptions driverOptions)
: base(service, SetPlatformToCapabilities(driverOptions, Platform))
{
}
/// <summary>
/// Initializes a new instance of the AndroidDriver class using the specified remote address, Appium options, and command timeout.
/// </summary>
/// <param name="remoteAddress">URI containing the address of the WebDriver remote server (e.g. http://127.0.0.1:4723/).</param>
/// <param name="driverOptions">An <see cref="DriverOptions"/> object containing the Appium options.</param>
/// <param name="commandTimeout">The maximum amount of time to wait for each command.</param>
public AndroidDriver(Uri remoteAddress, DriverOptions driverOptions, TimeSpan commandTimeout)
: base(remoteAddress, SetPlatformToCapabilities(driverOptions, Platform), commandTimeout)
{
}
/// <summary>
/// Initializes a new instance of the AndroidDriver class using the specified Appium local service, Appium options, and command timeout.
/// </summary>
/// <param name="service">the specified Appium local service</param>
/// <param name="driverOptions">An <see cref="ICapabilities"/> object containing the Appium options.</param>
/// <param name="commandTimeout">The maximum amount of time to wait for each command.</param>
public AndroidDriver(AppiumLocalService service, DriverOptions driverOptions,
TimeSpan commandTimeout)
: base(service, SetPlatformToCapabilities(driverOptions, Platform), commandTimeout)
{
}
/// <summary>
/// Initializes a new instance of the AndroidDriver class using the specified remote address, Appium options and AppiumClientConfig.
/// </summary>
/// <param name="remoteAddress">URI containing the address of the WebDriver remote server (e.g. http://127.0.0.1:4723/).</param>
/// <param name="driverOptions">An <see cref="DriverOptions"/> object containing the Appium options.</param>
/// <param name="clientConfig">An instance of <see cref="AppiumClientConfig"/></param>
public AndroidDriver(Uri remoteAddress, DriverOptions driverOptions, AppiumClientConfig clientConfig)
: base(remoteAddress, SetPlatformToCapabilities(driverOptions, Platform), clientConfig)
{
}
/// <summary>
/// Initializes a new instance of the AndroidDriver class using the specified Appium local service, Appium options and AppiumClientConfig,
/// </summary>
/// <param name="service">the specified Appium local service</param>
/// <param name="driverOptions">An <see cref="ICapabilities"/> object containing the Appium options.</param>
/// <param name="clientConfig">An instance of <see cref="AppiumClientConfig"/></param>
public AndroidDriver(AppiumLocalService service, DriverOptions driverOptions, AppiumClientConfig clientConfig)
: base(service, SetPlatformToCapabilities(driverOptions, Platform), clientConfig)
{
}
/// <summary>
/// Initializes a new instance of the AndroidDriver class using the specified remote address, Appium options, command timeout and AppiumClientConfig.
/// </summary>
/// <param name="remoteAddress">URI containing the address of the WebDriver remote server (e.g. http://127.0.0.1:4723/).</param>
/// <param name="driverOptions">An <see cref="DriverOptions"/> object containing the Appium options.</param>
/// <param name="commandTimeout">The maximum amount of time to wait for each command.</param>
/// <param name="clientConfig">An instance of <see cref="AppiumClientConfig"/></param>
public AndroidDriver(Uri remoteAddress, DriverOptions driverOptions, TimeSpan commandTimeout, AppiumClientConfig clientConfig)
: base(remoteAddress, SetPlatformToCapabilities(driverOptions, Platform), commandTimeout, clientConfig)
{
}
/// <summary>
/// Initializes a new instance of the AndroidDriver class using the specified Appium local service, Appium options, command timeout and AppiumClientConfig,
/// </summary>
/// <param name="service">the specified Appium local service</param>
/// <param name="driverOptions">An <see cref="ICapabilities"/> object containing the Appium options.</param>
/// <param name="commandTimeout">The maximum amount of time to wait for each command.</param>
/// <param name="clientConfig">An instance of <see cref="AppiumClientConfig"/></param>
public AndroidDriver(AppiumLocalService service, DriverOptions driverOptions, TimeSpan commandTimeout, AppiumClientConfig clientConfig)
: base(service, SetPlatformToCapabilities(driverOptions, Platform), commandTimeout, clientConfig)
{
}
public string CurrentActivity => AndroidCommandExecutionHelper.GetCurrentActivity(this);
public string CurrentPackage => AndroidCommandExecutionHelper.GetCurrentPackage(this);
#region Activity
/// <summary>
/// Start an Android activity by providing its package name and activity name.
/// For documentation, see <see href="https://github.com/appium/appium-uiautomator2-driver#mobile-startactivity">mobile:startActivity</see>.
/// </summary>
/// <param name="intent">The full name of the activity intent to start, e.g. "com.myapp/.MyActivity"</param>
/// <param name="arguments">Optional dictionary of additional arguments. Values from this dictionary take priority over other parameters.</param>
/// <param name="user">The user ID for which the activity is started. The current user is used by default.</param>
/// <param name="wait">Set to true to block the method call until the Activity Manager's process returns the control to the system. false by default.</param>
/// <param name="stop">Set to true to force stop the target app before starting the activity. false by default.</param>
/// <param name="windowingMode">The windowing mode to launch the activity into. Check WindowConfiguration.java for possible values (constants starting with WINDOWING_MODE_).</param>
/// <param name="activityType">The activity type to launch the activity as. Check WindowConfiguration.java for possible values (constants starting with ACTIVITY_TYPE_).</param>
/// <param name="action">Action name. The actual value for the Activity Manager's -a argument.</param>
/// <param name="uri">Unified resource identifier. The actual value for the Activity Manager's -d argument.</param>
/// <param name="mimeType">Mime type. The actual value for the Activity Manager's -t argument.</param>
/// <param name="identifier">Optional identifier. The actual value for the Activity Manager's -i argument.</param>
/// <param name="categories">One or more category names. The actual value(s) for the Activity Manager's -c argument.</param>
/// <param name="component">Component name. The actual value for the Activity Manager's -n argument.</param>
/// <param name="package">Package name. The actual value for the Activity Manager's -p argument.</param>
/// <param name="extras">Optional intent arguments. Must be represented as an array of arrays, where each subarray contains two or three string items: value type, key (variable name) and the value itself. Supported value types: s (string), sn (null), z (boolean), i (integer), l (long), f (float), u (uri), cn (component name), ia (Integer[]), ial (List<Integer>), la (Long[]), lal (List<Long>), fa (Float[]), fal (List<Float>), sa (String[]), sal (List<String>).</param>
/// <param name="flags">Intent startup-specific flags as a hexadecimal string. Check Intent documentation for available flag values (constants starting with FLAG_ACTIVITY_). Flag values can be merged using logical 'or' operation, e.g. "0x10200000".</param>
public void StartActivity(
string intent,
Dictionary<string, object> arguments = null,
string user = null,
bool? wait = null,
bool? stop = null,
int? windowingMode = null,
int? activityType = null,
string action = null,
string uri = null,
string mimeType = null,
string identifier = null,
string[] categories = null,
string component = null,
string package = null,
string[][] extras = null,
string flags = null) =>
AndroidCommandExecutionHelper.StartActivity(
this, intent, arguments, user, wait, stop, windowingMode, activityType, action, uri, mimeType, identifier, categories, component, package, extras, flags);
#endregion
#region App Management
/// <summary>
/// Install an app on the Android device using mobile: installApp script.
/// For documentation, see <see href="https://github.com/appium/appium-uiautomator2-driver?tab=readme-ov-file#mobile-installapp">mobile: installApp</see>.
/// </summary>
/// <param name="appPath">Full path to the .apk on the local filesystem or a remote URL.</param>
/// <param name="timeout">Optional timeout in milliseconds to wait for the app installation to complete. 60000ms by default.</param>
/// <param name="allowTestPackages">Optional flag to allow test packages installation. false by default.</param>
/// <param name="useSdcard">Optional flag to install the app on sdcard instead of device memory. false by default.</param>
/// <param name="grantPermissions">Optional flag to grant all permissions requested in the app manifest automatically after installation. false by default.</param>
/// <param name="replace">Optional flag to upgrade/reinstall if app is already present. true by default.</param>
/// <param name="checkVersion">Optional flag to skip installation if device has equal or greater app version. false by default.</param>
public void InstallApp(
string appPath,
int? timeout = null,
bool? allowTestPackages = null,
bool? useSdcard = null,
bool? grantPermissions = null,
bool? replace = null,
bool? checkVersion = null) =>
AndroidCommandExecutionHelper.InstallApp(this, appPath, timeout, allowTestPackages, useSdcard, grantPermissions, replace, checkVersion);
#endregion
#region Device Keys
public void PressKeyCode(int keyCode, int metastate = -1) =>
AppiumCommandExecutionHelper.PressKeyCode(this, keyCode, metastate);
public void LongPressKeyCode(int keyCode, int metastate = -1) =>
AppiumCommandExecutionHelper.LongPressKeyCode(this, keyCode, metastate);
public void PressKeyCode(KeyEvent keyEvent) =>
AppiumCommandExecutionHelper.PressKeyCode(this, keyEvent);
public void LongPressKeyCode(KeyEvent keyEvent) =>
AppiumCommandExecutionHelper.LongPressKeyCode(this, keyEvent);
#endregion
#region Device Network
public void ToggleLocationServices() => AndroidCommandExecutionHelper.ToggleLocationServices(this);
public void MakeGsmCall(string phoneNumber, GsmCallActions gsmCallAction) =>
AndroidCommandExecutionHelper.GsmCall(this, phoneNumber, gsmCallAction);
public void SendSms(string phoneNumber, string message) =>
AndroidCommandExecutionHelper.SendSms(this, phoneNumber, message);
public void SetGsmSignalStrength(GsmSignalStrength gsmSignalStrength)
=> AndroidCommandExecutionHelper.SetGsmStrength(this, gsmSignalStrength);
public void SetGsmVoice(GsmVoiceState gsmVoiceState) =>
AndroidCommandExecutionHelper.SetGsmVoice(this, gsmVoiceState);
#endregion
#region Device System
/// <summary>
/// Open the notifications
/// </summary>
public void OpenNotifications() => AndroidCommandExecutionHelper.OpenNotifications(this);
/// <summary>
/// Retrieve visibility and bounds information of the status and navigation bars
/// </summary>
/// <returns>A dictionary whose string keys are named <code>statusBar</code><code>navigationBar</code></returns>
public IDictionary<string, object> GetSystemBars() => AndroidCommandExecutionHelper.GetSystemBars(this);
/// <summary>
/// Retrieve display density(dpi) of the Android device
/// </summary>
/// <returns>Retrieve display density(dpi) of the Android device</returns>
public float GetDisplayDensity() => AndroidCommandExecutionHelper.GetDisplayDensity(this);
#endregion
#region Device Performance Data
public IList<object> GetPerformanceData(string packageName, string performanceDataType) =>
AndroidCommandExecutionHelper.GetPerformanceData(this, packageName, performanceDataType)
?.ToList();
public IList<object> GetPerformanceData(string packageName, string performanceDataType,
int dataReadAttempts)
{
if (dataReadAttempts < 1) throw new ArgumentException($"{nameof(dataReadAttempts)} must be greater than 0");
return AndroidCommandExecutionHelper
.GetPerformanceData(this, packageName, performanceDataType, dataReadAttempts)
?.ToList();
}
public IList<string> GetPerformanceDataTypes() =>
AndroidCommandExecutionHelper.GetPerformanceDataTypes(this)
?.Cast<string>()
.ToList();
#endregion
#region Device Interactions
/// <summary>
/// Locks the device. Optionally, unlocks it after a specified number of seconds.
/// </summary>
/// <param name="seconds">
/// The number of seconds after which the device will be automatically unlocked.
/// Set to 0 or leave it empty to require manual unlock.
/// </param>
/// <exception cref="WebDriverException">Thrown if the command execution fails.</exception>
public void Lock(int? seconds = null)
{
var parameters = new Dictionary<string, object>();
if (seconds.HasValue && seconds.Value > 0)
{
parameters["seconds"] = seconds.Value;
}
ExecuteScript("mobile: lock", parameters);
}
/// <summary>
/// Check if the device is locked
/// </summary>
/// <returns>true if device is locked, false otherwise</returns>
public bool IsLocked() => (bool)ExecuteScript("mobile: isLocked");
#nullable enable
/// <summary>
/// Unlocks the device if it is locked. No operation if the device's screen is not locked.
/// </summary>
/// <param name="key">The unlock key. See the documentation on appium:unlockKey capability for more details.</param>
/// <param name="type">The unlock type. See the documentation on appium:unlockType capability for more details.</param>
/// <param name="strategy">Optional unlock strategy. See the documentation on appium:unlockStrategy capability for more details.</param>
/// <param name="timeoutMs">Optional unlock timeout in milliseconds. See the documentation on appium:unlockSuccessTimeout capability for more details.</param>
/// <exception cref="ArgumentException">Thrown when required arguments are null or empty.</exception>
/// <exception cref="WebDriverException">Thrown if the command execution fails.</exception>
public void Unlock(string key, string type, string? strategy = null, int? timeoutMs = null)
{
if (string.IsNullOrWhiteSpace(key))
throw new ArgumentException("Unlock key is required and cannot be null or whitespace.", nameof(key));
if (string.IsNullOrWhiteSpace(type))
throw new ArgumentException("Unlock type is required and cannot be null or whitespace.", nameof(type));
var parameters = new Dictionary<string, object>
{
{ "key", key },
{ "type", type }
};
if (strategy != null && !string.IsNullOrWhiteSpace(strategy))
{
parameters["strategy"] = strategy;
}
if (timeoutMs.HasValue)
{
parameters["timeoutMs"] = timeoutMs.Value;
}
ExecuteScript("mobile: unlock", parameters);
}
#endregion
public void SetSetting(string setting, object value) =>
AndroidCommandExecutionHelper.SetSetting(this, setting, value);
public void IgnoreUnimportantViews(bool compress) =>
SetSetting(AutomatorSetting.IgnoreUnimportantViews, compress);
public void ConfiguratorSetWaitForIdleTimeout(int timeout) =>
SetSetting(AutomatorSetting.WaitForIDLETimeout, timeout);
public void ConfiguratorSetWaitForSelectorTimeout(int timeout) =>
SetSetting(AutomatorSetting.WaitForSelectorTimeout, timeout);
public void ConfiguratorSetScrollAcknowledgmentTimeout(int timeout) =>
SetSetting(AutomatorSetting.WaitScrollAcknowledgmentTimeout, timeout);
public void ConfiguratorSetKeyInjectionDelay(int delay) =>
SetSetting(AutomatorSetting.KeyInjectionDelay, delay);
public void ConfiguratorSetActionAcknowledgmentTimeout(int timeout) =>
SetSetting(AutomatorSetting.WaitActionAcknowledgmentTimeout, timeout);
public Dictionary<string, object> Settings
{
get => AndroidCommandExecutionHelper.GetSettings(this);
set
{
foreach (var entry in value)
{
SetSetting(entry.Key, entry.Value);
}
}
}
/// <summary>
/// Sets the content to the clipboard
/// </summary>
/// <param name="contentType">An <see cref="ClipboardContentType"/> object to set (PlainText, Image or Url).</param>
/// <param name="base64Content">The base64-encoded content to set.</param>
public void SetClipboard(ClipboardContentType contentType, string base64Content) =>
AppiumCommandExecutionHelper.MobileSetClipboard(this, contentType, base64Content);
/// <summary>
/// Get the content of the clipboard.
/// </summary>
/// <param name="contentType">An <see cref="ClipboardContentType"/> object (PlainText, Image or Url).</param>
/// <remarks>Android supports plaintext only</remarks>
/// <returns>The content of the clipboard as base64-encoded string or an empty string if the clipboard is empty</returns>
public string GetClipboard(ClipboardContentType contentType) =>
AppiumCommandExecutionHelper.MobileGetClipboard(this, contentType);
/// <summary>
/// Sets text to the clipboard
/// </summary>
/// <param name="textContent">The text content.</param>
/// <param name="label">For Android only - A user visible label for the clipboard content.</param>
public void SetClipboardText(string textContent, string label) =>
AppiumCommandExecutionHelper.SetClipboardText(this, textContent, label);
/// <summary>
/// Get the plaintext content of the clipboard.
/// </summary>
/// <remarks>Android supports plaintext only</remarks>
/// <returns>The string content of the clipboard or an empty string if the clipboard is empty</returns>
public string GetClipboardText() => AppiumCommandExecutionHelper.GetClipboardText(this);
/// <summary>
/// Sets the url string to the clipboard
/// </summary>
/// <param name="url">The URL string.</param>
public void SetClipboardUrl(string url) => throw new NotImplementedException();
/// <summary>
/// Gets the url string from the clipboard
/// </summary>
/// <returns>The url string content of the clipboard or an empty string if the clipboard is empty</returns>
public string GetClipboardUrl() => throw new NotImplementedException();
/// <summary>
/// Sets the image to the clipboard
/// </summary>
/// <param name="image">The image object.</param>
public void SetClipboardImage(Image image) => throw new NotImplementedException();
/// <summary>
/// Gets the image from the clipboard
/// </summary>
/// <returns>The image content of the clipboard as base64-encoded string or null if there is no image on the clipboard</returns>
public Image GetClipboardImage() => throw new NotImplementedException();
/// <summary>
/// Gets the State of the app.
/// </summary>
/// <param name="appId">A string containing the id of the app.</param>
/// <returns>an enumeration of the app state.</returns>
public AppState GetAppState(string appId) =>
(AppState)Convert.ToInt32(
ExecuteScript(
"mobile:queryAppState",
new object[] {
new Dictionary<string, object>{
["appId"] = appId
}
}
)?.ToString() ?? throw new InvalidOperationException("ExecuteScript returned null for mobile:queryAppState")
);
#region Logcat Broadcast
/// <summary>
/// Start logcat messages broadcast via web socket.
/// This method assumes that Appium server is running on localhost and
/// is assigned to the default port (4723).
/// </summary>
/// <remarks>
/// This implementation uses a custom WebSocket endpoint and is temporary.
/// In the future, this functionality will be replaced with WebDriver BiDi log events
/// when BiDi support for Android device logs becomes available.
/// </remarks>
public async Task StartLogcatBroadcast() => await StartLogcatBroadcast("127.0.0.1", DefaultAppiumPort);
/// <summary>
/// Start logcat messages broadcast via web socket.
/// This method assumes that Appium server is assigned to the default port (4723).
/// </summary>
/// <param name="host">The name of the host where Appium server is running.</param>
/// <remarks>
/// This implementation uses a custom WebSocket endpoint and is temporary.
/// In the future, this functionality will be replaced with WebDriver BiDi log events
/// when BiDi support for Android device logs becomes available.
/// </remarks>
public async Task StartLogcatBroadcast(string host) => await StartLogcatBroadcast(host, DefaultAppiumPort);
/// <summary>
/// Start logcat messages broadcast via web socket.
/// </summary>
/// <param name="host">The name of the host where Appium server is running.</param>
/// <param name="port">The port of the host where Appium server is running.</param>
/// <remarks>
/// This implementation uses a custom WebSocket endpoint and is temporary.
/// In the future, this functionality will be replaced with WebDriver BiDi log events
/// when BiDi support for Android device logs becomes available.
/// </remarks>
public async Task StartLogcatBroadcast(string host, int port)
{
ExecuteScript("mobile: startLogsBroadcast", new Dictionary<string, object>());
var endpointUri = new Uri($"ws://{host}:{port}/ws/session/{SessionId}/appium/device/logcat");
await _logcatClient.ConnectAsync(endpointUri);
}
/// <summary>
/// Adds a new log messages broadcasting handler.
/// Several handlers might be assigned to a single server.
/// Multiple calls to this method will cause such handler
/// to be called multiple times.
/// </summary>
/// <param name="handler">A function, which accepts a single argument, which is the actual log message.</param>
public void AddLogcatMessagesListener(Action<string> handler) =>
_logcatClient.AddMessageHandler(handler);
/// <summary>
/// Adds a new log broadcasting errors handler.
/// Several handlers might be assigned to a single server.
/// Multiple calls to this method will cause such handler
/// to be called multiple times.
/// </summary>
/// <param name="handler">A function, which accepts a single argument, which is the actual exception instance.</param>
public void AddLogcatErrorsListener(Action<Exception> handler) =>
_logcatClient.AddErrorHandler(handler);
/// <summary>
/// Adds a new log broadcasting connection handler.
/// Several handlers might be assigned to a single server.
/// Multiple calls to this method will cause such handler
/// to be called multiple times.
/// </summary>
/// <param name="handler">A function, which is executed as soon as the client is successfully connected to the web socket.</param>
public void AddLogcatConnectionListener(Action handler) =>
_logcatClient.AddConnectionHandler(handler);
/// <summary>
/// Adds a new log broadcasting disconnection handler.
/// Several handlers might be assigned to a single server.
/// Multiple calls to this method will cause such handler
/// to be called multiple times.
/// </summary>
/// <param name="handler">A function, which is executed as soon as the client is successfully disconnected from the web socket.</param>
public void AddLogcatDisconnectionListener(Action handler) =>
_logcatClient.AddDisconnectionHandler(handler);
/// <summary>
/// Removes all existing logcat handlers.
/// </summary>
public void RemoveAllLogcatListeners() => _logcatClient.RemoveAllHandlers();
/// <summary>
/// Stops logcat messages broadcast via web socket.
/// </summary>
public async Task StopLogcatBroadcast()
{
ExecuteScript("mobile: stopLogsBroadcast", new Dictionary<string, object>());
await _logcatClient.DisconnectAsync();
}
#endregion
}
}