Skip to content

Commit 536bbc3

Browse files
authored
Merge pull request #50 from ilamp/main
App Status Support
2 parents 6ece9be + 9af50e7 commit 536bbc3

File tree

8 files changed

+181
-7
lines changed

8 files changed

+181
-7
lines changed

AdvancedSharpAdbClient.Tests/AdvancedSharpAdbClient.Tests.csproj

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
<PropertyGroup>
44
<NoWarn>CS1591</NoWarn>
55
<LangVersion>latest</LangVersion>
6+
<NoWarn>CS1591</NoWarn>
67
<TargetFramework>net6.0</TargetFramework>
78
</PropertyGroup>
89

@@ -16,6 +17,9 @@
1617
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.5" PrivateAssets="all">
1718
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
1819
</PackageReference>
20+
<PackageReference Include="coverlet.msbuild" Version="3.2.0" PrivateAssets="all">
21+
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
22+
</PackageReference>
1923
</ItemGroup>
2024

2125
<ItemGroup>

AdvancedSharpAdbClient.Tests/Dummys/DummyAdbClient.cs

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ public Task ExecuteRemoteCommandAsync(string command, DeviceData device, IShellO
8383

8484
public void ClearInput(DeviceData device, int charCount) => throw new NotImplementedException();
8585

86-
public Task ClearInputAsync(DeviceData device, int charcount, CancellationToken cancellationToken) => throw new NotImplementedException();
86+
public Task ClearInputAsync(DeviceData device, int charCount, CancellationToken cancellationToken) => throw new NotImplementedException();
8787

8888
public void Click(DeviceData device, Cords cords) => throw new NotImplementedException();
8989

@@ -131,6 +131,10 @@ public Task ExecuteRemoteCommandAsync(string command, DeviceData device, IShellO
131131

132132
public Task<int> GetAdbVersionAsync(CancellationToken cancellationToken) => throw new NotImplementedException();
133133

134+
public AppStatus GetAppStatus(DeviceData device, string packageName) => throw new NotImplementedException();
135+
136+
public Task<AppStatus> GetAppStatusAsync(DeviceData device, string packageName, CancellationToken cancellationToken) => throw new NotImplementedException();
137+
134138
public List<DeviceData> GetDevices() => throw new NotImplementedException();
135139

136140
public Task<List<DeviceData>> GetDevicesAsync(CancellationToken cancellationToken) => throw new NotImplementedException();
@@ -177,6 +181,14 @@ public Task ExecuteRemoteCommandAsync(string command, DeviceData device, IShellO
177181

178182
public Task InstallWriteAsync(DeviceData device, Stream apk, string apkName, string session, CancellationToken cancellationToken) => throw new NotImplementedException();
179183

184+
public bool IsAppRunning(DeviceData device, string packageName) => throw new NotImplementedException();
185+
186+
public Task<bool> IsAppRunningAsync(DeviceData device, string packageName, CancellationToken cancellationToken) => throw new NotImplementedException();
187+
188+
public bool IsCurrentApp(DeviceData device, string packageName) => throw new NotImplementedException();
189+
190+
public Task<bool> IsCurrentAppAsync(DeviceData device, string packageName, CancellationToken cancellationToken) => throw new NotImplementedException();
191+
180192
public void KillAdb() => throw new NotImplementedException();
181193

182194
public Task KillAdbAsync(CancellationToken cancellationToken) => throw new NotImplementedException();

AdvancedSharpAdbClient/AdbClient.Async.cs

Lines changed: 43 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -452,9 +452,9 @@ public async Task InstallAsync(DeviceData device, Stream apk, CancellationToken
452452
throw new AdbException(value);
453453
}
454454
}
455-
455+
456456
/// <inheritdoc/>
457-
public Task InstallMultipleAsync(DeviceData device, Stream[] splitAPKs, string packageName, params string[] arguments)=>
457+
public Task InstallMultipleAsync(DeviceData device, Stream[] splitAPKs, string packageName, params string[] arguments) =>
458458
InstallMultipleAsync(device, splitAPKs, packageName, default, arguments);
459459

460460
/// <inheritdoc/>
@@ -709,7 +709,7 @@ public async Task<XmlDocument> DumpScreenAsync(DeviceData device, CancellationTo
709709
}
710710
return null;
711711
}
712-
712+
713713
/// <inheritdoc/>
714714
public async Task ClickAsync(DeviceData device, Cords cords, CancellationToken cancellationToken = default)
715715
{
@@ -793,7 +793,46 @@ public async Task SwipeAsync(DeviceData device, int x1, int y1, int x2, int y2,
793793
throw new ElementNotFoundException("Coordinates of element is invalid");
794794
}
795795
}
796-
796+
797+
/// <inheritdoc/>
798+
public async Task<bool> IsCurrentAppAsync(DeviceData device, string packageName, CancellationToken cancellationToken = default)
799+
{
800+
ConsoleOutputReceiver receiver = new();
801+
await ExecuteRemoteCommandAsync($"dumpsys activity activities | grep mResumedActivity", device, receiver, cancellationToken);
802+
string response = receiver.ToString().Trim();
803+
return response.ToString().Contains(packageName);
804+
}
805+
806+
/// <inheritdoc/>
807+
public async Task<bool> IsAppRunningAsync(DeviceData device, string packageName, CancellationToken cancellationToken = default)
808+
{
809+
ConsoleOutputReceiver receiver = new();
810+
await ExecuteRemoteCommandAsync($"pidof {packageName}", device, receiver, cancellationToken);
811+
string response = receiver.ToString().Trim();
812+
bool intParsed = int.TryParse(response, out int pid);
813+
return intParsed && pid > 0;
814+
}
815+
816+
/// <inheritdoc/>
817+
public async Task<AppStatus> GetAppStatusAsync(DeviceData device, string packageName, CancellationToken cancellationToken = default)
818+
{
819+
// Check if the app is in foreground
820+
bool currentApp = await IsCurrentAppAsync(device, packageName, cancellationToken);
821+
if (currentApp)
822+
{
823+
return AppStatus.Foreground;
824+
}
825+
826+
// Check if the app is running in background
827+
bool isAppRunning = await IsAppRunningAsync(device, packageName, cancellationToken);
828+
if (isAppRunning)
829+
{
830+
return AppStatus.Background;
831+
}
832+
833+
return AppStatus.Stopped;
834+
}
835+
797836
/// <inheritdoc/>
798837
public async Task<Element> FindElementAsync(DeviceData device, string xpath, CancellationToken cancellationToken = default)
799838
{

AdvancedSharpAdbClient/AdbClient.cs

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -755,6 +755,45 @@ public void Swipe(DeviceData device, int x1, int y1, int x2, int y2, long speed)
755755
}
756756
}
757757

758+
/// <inheritdoc/>
759+
public bool IsCurrentApp(DeviceData device, string packageName)
760+
{
761+
ConsoleOutputReceiver receiver = new();
762+
ExecuteRemoteCommand($"dumpsys activity activities | grep mResumedActivity", device, receiver);
763+
string response = receiver.ToString().Trim();
764+
return response.ToString().Contains(packageName);
765+
}
766+
767+
/// <inheritdoc/>
768+
public bool IsAppRunning(DeviceData device, string packageName)
769+
{
770+
ConsoleOutputReceiver receiver = new();
771+
ExecuteRemoteCommand($"pidof {packageName}", device, receiver);
772+
string response = receiver.ToString().Trim();
773+
bool intParsed = int.TryParse(response, out int pid);
774+
return intParsed && pid > 0;
775+
}
776+
777+
/// <inheritdoc/>
778+
public AppStatus GetAppStatus(DeviceData device, string packageName)
779+
{
780+
// Check if the app is in foreground
781+
bool currentApp = IsCurrentApp(device, packageName);
782+
if (currentApp)
783+
{
784+
return AppStatus.Foreground;
785+
}
786+
787+
// Check if the app is running in background
788+
bool isAppRunning = IsAppRunning(device, packageName);
789+
if (isAppRunning)
790+
{
791+
return AppStatus.Background;
792+
}
793+
794+
return AppStatus.Stopped;
795+
}
796+
758797
/// <inheritdoc/>
759798
public Element FindElement(DeviceData device, string xpath, TimeSpan timeout = default)
760799
{
@@ -829,7 +868,7 @@ public Element[] FindElements(DeviceData device, string xpath, TimeSpan timeout
829868
}
830869
return null;
831870
}
832-
871+
833872
/// <inheritdoc/>
834873
public void SendKeyEvent(DeviceData device, string key)
835874
{

AdvancedSharpAdbClient/DeviceCommands/Models/AndroidProcessState.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ public enum AndroidProcessState
1515
Unknown,
1616

1717
/// <summary>
18-
/// Running or runnable (on run queue).
18+
/// Foreground or runnable (on run queue).
1919
/// </summary>
2020
R,
2121

AdvancedSharpAdbClient/Interfaces/IAdbClient.Async.cs

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -468,6 +468,33 @@ public partial interface IAdbClient
468468
/// <returns>A <see cref="Task"/> which represents the asynchronous operation.</returns>
469469
Task SwipeAsync(DeviceData device, int x1, int y1, int x2, int y2, long speed, CancellationToken cancellationToken);
470470

471+
/// <summary>
472+
/// Check if the app is running in foreground.
473+
/// </summary>
474+
/// <param name="device">The device on which to check.</param>
475+
/// <param name="packageName">The package name of the app to check.</param>
476+
/// <param name="cancellationToken">A <see cref="CancellationToken"/> which can be used to cancel the asynchronous operation.</param>
477+
/// <returns>An <see cref="Task"/> which return the result. <see langword="true"/> if the app is running in foreground; otherwise, <see langword="false"/>.</returns>
478+
Task<bool> IsCurrentAppAsync(DeviceData device, string packageName, CancellationToken cancellationToken);
479+
480+
/// <summary>
481+
/// Check if the app is running in background.
482+
/// </summary>
483+
/// <param name="device">The device on which to check.</param>
484+
/// <param name="packageName">The package name of the app to check.</param>
485+
/// <param name="cancellationToken">A <see cref="CancellationToken"/> which can be used to cancel the asynchronous operation.</param>
486+
/// <returns>An <see cref="Task"/> which return the result. <see langword="true"/> if the app is running in background; otherwise, <see langword="false"/>.</returns>
487+
Task<bool> IsAppRunningAsync(DeviceData device, string packageName, CancellationToken cancellationToken);
488+
489+
/// <summary>
490+
/// Get the <see cref="AppStatus"/> of the app.
491+
/// </summary>
492+
/// <param name="device">The device on which to get status.</param>
493+
/// <param name="packageName">The package name of the app to check.</param>
494+
/// <param name="cancellationToken">A <see cref="CancellationToken"/> which can be used to cancel the asynchronous operation.</param>
495+
/// <returns>An <see cref="Task"/> which return the <see cref="AppStatus"/> of the app. Foreground, stopped or running in background.</returns>
496+
Task<AppStatus> GetAppStatusAsync(DeviceData device, string packageName, CancellationToken cancellationToken);
497+
471498
/// <summary>
472499
/// Get element by xpath asynchronously. You can specify the waiting time in timeout.
473500
/// </summary>

AdvancedSharpAdbClient/Interfaces/IAdbClient.cs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -409,6 +409,30 @@ public partial interface IAdbClient
409409
/// <param name="speed"></param>
410410
void Swipe(DeviceData device, int x1, int y1, int x2, int y2, long speed);
411411

412+
/// <summary>
413+
/// Check if the app is running in foreground.
414+
/// </summary>
415+
/// <param name="device">The device on which to check.</param>
416+
/// <param name="packageName">The package name of the app to check.</param>
417+
/// <returns><see langword="true"/> if the app is running in foreground; otherwise, <see langword="false"/>.</returns>
418+
bool IsCurrentApp(DeviceData device, string packageName);
419+
420+
/// <summary>
421+
/// Check if the app is running in background.
422+
/// </summary>
423+
/// <param name="device">The device on which to check.</param>
424+
/// <param name="packageName">The package name of the app to check.</param>
425+
/// <returns><see langword="true"/> if the app is running in background; otherwise, <see langword="false"/>.</returns>
426+
bool IsAppRunning(DeviceData device, string packageName);
427+
428+
/// <summary>
429+
/// Get the <see cref="AppStatus"/> of the app.
430+
/// </summary>
431+
/// <param name="device">The device on which to get status.</param>
432+
/// <param name="packageName">The package name of the app to check.</param>
433+
/// <returns>The <see cref="AppStatus"/> of the app. Foreground, stopped or running in background.</returns>
434+
AppStatus GetAppStatus(DeviceData device, string packageName);
435+
412436
/// <summary>
413437
/// Get element by xpath. You can specify the waiting time in timeout.
414438
/// </summary>
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
// <copyright file="AppStatus.cs" company="The Android Open Source Project, Ryan Conrad, Quamotion, yungd1plomat, wherewhere">
2+
// Copyright (c) The Android Open Source Project, Ryan Conrad, Quamotion, yungd1plomat, wherewhere. All rights reserved.
3+
// </copyright>
4+
5+
using System;
6+
7+
namespace AdvancedSharpAdbClient
8+
{
9+
/// <summary>
10+
/// The status of an application if it is stopped or running in foreground or background.
11+
/// </summary>
12+
public enum AppStatus
13+
{
14+
/// <summary>
15+
/// The application is stopped.
16+
/// </summary>
17+
Stopped = 0B00,
18+
19+
/// <summary>
20+
/// The application is running in background.
21+
/// </summary>
22+
Background = 0B01,
23+
24+
/// <summary>
25+
/// The application is running in foreground.
26+
/// </summary>
27+
Foreground = 0B11,
28+
}
29+
}

0 commit comments

Comments
 (0)