diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index cd13217f..a52b049a 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -14,7 +14,7 @@ on: workflow_dispatch: env: - DOTNET_VERSION: '9.0.x' # The .NET SDK version to use + DOTNET_VERSION: '10.0.x' # The .NET SDK version to use jobs: build-and-test: @@ -45,7 +45,7 @@ jobs: run: dotnet test --no-restore --blame-hang-timeout 1m -p:FullTargets=false pack-and-publish: - name: pack-and-publish + if: github.event_name == 'push' needs: build-and-test runs-on: windows-latest env: diff --git a/AdvancedSharpAdbClient.Tests/AdbClientTests.Async.cs b/AdvancedSharpAdbClient.Tests/AdbClientTests.Async.cs index ba1c14c4..ee238518 100644 --- a/AdvancedSharpAdbClient.Tests/AdbClientTests.Async.cs +++ b/AdvancedSharpAdbClient.Tests/AdbClientTests.Async.cs @@ -935,7 +935,7 @@ await RunTestAsync( () => TestClient.InstallCommitAsync(Device, "936013062")); } -#if WINDOWS10_0_18362_0_OR_GREATER +#if WINDOWS10_0_17763_0_OR_GREATER /// /// Tests the method. /// diff --git a/AdvancedSharpAdbClient.Tests/AdbClientTests.cs b/AdvancedSharpAdbClient.Tests/AdbClientTests.cs index 4beaef40..c703acac 100644 --- a/AdvancedSharpAdbClient.Tests/AdbClientTests.cs +++ b/AdvancedSharpAdbClient.Tests/AdbClientTests.cs @@ -65,6 +65,16 @@ public void FormAdbRequestTest() Assert.Equal("000Chost:version"u8, AdbClient.FormAdbRequest("host:version")); } + /// + /// Tests the method. + /// + [Fact] + public void FormAdbRequestSpanTest() + { + Assert.Equal("0009host:kill"u8, AdbClient.FormAdbRequest("host:kill".AsSpan())); + Assert.Equal("000Chost:version"u8, AdbClient.FormAdbRequest("host:version".AsSpan())); + } + /// /// Tests the method. /// @@ -75,6 +85,16 @@ public void CreateAdbForwardRequestTest() Assert.Equal("0012tcp:1981:127.0.0.1"u8, AdbClient.CreateAdbForwardRequest("127.0.0.1", 1981)); } + /// + /// Tests the method. + /// + [Fact] + public void CreateAdbForwardRequestSpanTest() + { + Assert.Equal("0008tcp:1984"u8, AdbClient.CreateAdbForwardRequest([], 1984)); + Assert.Equal("0012tcp:1981:127.0.0.1"u8, AdbClient.CreateAdbForwardRequest("127.0.0.1".AsSpan(), 1981)); + } + /// /// Tests the method. /// @@ -1139,7 +1159,7 @@ public void GetFeatureSetTest() public void CloneTest() { Assert.True(TestClient is ICloneable); -#if WINDOWS10_0_18362_0_OR_GREATER +#if WINDOWS10_0_17763_0_OR_GREATER Assert.True(TestClient is ICloneable); #endif AdbClient client = TestClient.Clone(); @@ -1149,6 +1169,16 @@ public void CloneTest() Assert.Equal(endPoint, client.EndPoint); } + /// + /// Tests the method. + /// + [Fact] + public void ToStringTest() + { + AdbClient adbClient = new(); + Assert.Equal($"The {typeof(AdbClient)} communicate with adb server at '127.0.0.1:5037'.", adbClient.ToString()); + } + private void RunConnectTest(Action test, string connectString) { string[] requests = [$"host:connect:{connectString}"]; diff --git a/AdvancedSharpAdbClient.Tests/AdbCommandLineClientTests.cs b/AdvancedSharpAdbClient.Tests/AdbCommandLineClientTests.cs index 9a589945..f01540e1 100644 --- a/AdvancedSharpAdbClient.Tests/AdbCommandLineClientTests.cs +++ b/AdvancedSharpAdbClient.Tests/AdbCommandLineClientTests.cs @@ -64,5 +64,17 @@ public void StartServerTest() commandLine.StartServer(); Assert.True(commandLine.ServerStarted); } + + /// + /// Tests the method. + /// + [Fact] + public void ToStringTest() + { + DummyAdbCommandLineClient commandLine = new(); + Assert.Equal($"The {typeof(DummyAdbCommandLineClient)} process with adb command line at '{ServerName}'.", commandLine.ToString()); + } + + private static string ServerName => OperatingSystem.IsWindows() ? "adb.exe" : "adb"; } } diff --git a/AdvancedSharpAdbClient.Tests/AdbServerTests.cs b/AdvancedSharpAdbClient.Tests/AdbServerTests.cs index de5136fe..249212b9 100644 --- a/AdvancedSharpAdbClient.Tests/AdbServerTests.cs +++ b/AdvancedSharpAdbClient.Tests/AdbServerTests.cs @@ -2,7 +2,6 @@ using System; using System.Net; using System.Net.Sockets; -using System.Runtime.InteropServices; using Xunit; namespace AdvancedSharpAdbClient.Tests @@ -262,6 +261,15 @@ public void CloneTest() Assert.Equal(endPoint, server.EndPoint); } + /// + /// Tests the method. + /// + [Fact] + public void ToStringTest() + { + Assert.Equal($"The {typeof(AdbServer)} communicate with adb at '127.0.0.1:5037'.", adbServer.ToString()); + } + /// /// Tests the method. /// @@ -269,6 +277,6 @@ public void CloneTest() public void ConstructorAdbClientNullTest() => _ = Assert.Throws(() => new AdbServer((EndPoint)null, adbSocketFactory, adbCommandLineClientFactory)); - private static string ServerName => RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? "adb.exe" : "adb"; + private static string ServerName => OperatingSystem.IsWindows() ? "adb.exe" : "adb"; } } diff --git a/AdvancedSharpAdbClient.Tests/AdbSocketTests.cs b/AdvancedSharpAdbClient.Tests/AdbSocketTests.cs index 05eecd14..b3067d42 100644 --- a/AdvancedSharpAdbClient.Tests/AdbSocketTests.cs +++ b/AdvancedSharpAdbClient.Tests/AdbSocketTests.cs @@ -1,5 +1,6 @@ using System; using System.IO; +using System.Runtime.CompilerServices; using System.Text; using Xunit; @@ -266,6 +267,17 @@ public void SendAdbRequestTest() => socket => socket.SendAdbRequest("Test"), "0004Test"u8.ToArray()); + /// + /// Tests the method. + /// + [Fact] + public void SendAdbRequestSpanTest() + { + RunTest( + socket => socket.SendAdbRequest((DefaultInterpolatedStringHandler)$"Test"), + "0004Test"u8.ToArray()); + } + /// /// Tests the method. /// @@ -297,6 +309,17 @@ public void CloneTest() Assert.Equal(adbSocket.Connected, socket.Connected); } + /// + /// Tests the method. + /// + [Fact] + public void ToStringTest() + { + using DummyTcpSocket tcpSocket = new(); + using AdbSocket adbSocket = new(tcpSocket); + Assert.Equal($"{typeof(AdbSocket)} {{ {nameof(AdbSocket.Socket)} = {tcpSocket} }}", adbSocket.ToString()); + } + private static void RunTest(Action test, byte[] expectedDataSent) { using DummyTcpSocket tcpSocket = new(); diff --git a/AdvancedSharpAdbClient.Tests/AdvancedSharpAdbClient.Tests.csproj b/AdvancedSharpAdbClient.Tests/AdvancedSharpAdbClient.Tests.csproj index 286e9bd9..dd742435 100644 --- a/AdvancedSharpAdbClient.Tests/AdvancedSharpAdbClient.Tests.csproj +++ b/AdvancedSharpAdbClient.Tests/AdvancedSharpAdbClient.Tests.csproj @@ -7,14 +7,14 @@ - + - net8.0-windows10.0.17763.0 + net10.0-windows10.0.17763.0 - net8.0 + net10.0 @@ -23,10 +23,10 @@ runtime; build; native; contentfiles; analyzers; buildtransitive - + - + runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/AdvancedSharpAdbClient.Tests/DeviceCommands/DeviceClientTexts.Async.cs b/AdvancedSharpAdbClient.Tests/DeviceCommands/DeviceClientTexts.Async.cs index 23195239..598da93c 100644 --- a/AdvancedSharpAdbClient.Tests/DeviceCommands/DeviceClientTexts.Async.cs +++ b/AdvancedSharpAdbClient.Tests/DeviceCommands/DeviceClientTexts.Async.cs @@ -105,7 +105,7 @@ public async Task DumpScreenAsyncTest() Assert.Equal(doc, xml); } -#if WINDOWS10_0_18362_0_OR_GREATER +#if WINDOWS10_0_17763_0_OR_GREATER /// /// Tests the method. /// diff --git a/AdvancedSharpAdbClient.Tests/DeviceCommands/DeviceClientTexts.cs b/AdvancedSharpAdbClient.Tests/DeviceCommands/DeviceClientTexts.cs index 382faf36..23cb8b5d 100644 --- a/AdvancedSharpAdbClient.Tests/DeviceCommands/DeviceClientTexts.cs +++ b/AdvancedSharpAdbClient.Tests/DeviceCommands/DeviceClientTexts.cs @@ -191,7 +191,7 @@ public void DumpScreenTest() Assert.Equal(doc, xml); } -#if WINDOWS10_0_18362_0_OR_GREATER +#if WINDOWS10_0_17763_0_OR_GREATER /// /// Tests the method. /// diff --git a/AdvancedSharpAdbClient.Tests/DeviceCommands/DeviceExtensionsTests.Async.cs b/AdvancedSharpAdbClient.Tests/DeviceCommands/DeviceExtensionsTests.Async.cs index 0851b398..33cfb31f 100644 --- a/AdvancedSharpAdbClient.Tests/DeviceCommands/DeviceExtensionsTests.Async.cs +++ b/AdvancedSharpAdbClient.Tests/DeviceCommands/DeviceExtensionsTests.Async.cs @@ -1,5 +1,6 @@ using NSubstitute; using System.Collections.Generic; +using System.Linq; using System.Text; using System.Threading; using System.Threading.Tasks; @@ -164,7 +165,7 @@ public async Task GetDirectoryAsyncListingTest() { Assert.Equal(remotePath, x.ArgAt(0)); Assert.Equal(default, x.ArgAt(1)); - return stats.AsEnumerableAsync(x.ArgAt(1)); + return stats.ToAsyncEnumerable(x.ArgAt(1)); }); Factories.SyncServiceFactory = (c, d) => diff --git a/AdvancedSharpAdbClient.Tests/DeviceCommands/Models/VersionInfoTests.cs b/AdvancedSharpAdbClient.Tests/DeviceCommands/Models/VersionInfoTests.cs index 8d9da8f1..8197d472 100644 --- a/AdvancedSharpAdbClient.Tests/DeviceCommands/Models/VersionInfoTests.cs +++ b/AdvancedSharpAdbClient.Tests/DeviceCommands/Models/VersionInfoTests.cs @@ -32,7 +32,7 @@ public void TryAsVersionTest(int versionCode, string versionName, bool expected) } } -#if WINDOWS10_0_18362_0_OR_GREATER +#if WINDOWS10_0_17763_0_OR_GREATER /// /// Tests the method. /// diff --git a/AdvancedSharpAdbClient.Tests/DeviceCommands/PackageManagerTests.cs b/AdvancedSharpAdbClient.Tests/DeviceCommands/PackageManagerTests.cs index 1fc000d2..52a9057c 100644 --- a/AdvancedSharpAdbClient.Tests/DeviceCommands/PackageManagerTests.cs +++ b/AdvancedSharpAdbClient.Tests/DeviceCommands/PackageManagerTests.cs @@ -18,7 +18,7 @@ public void ConstructorNullTest() { _ = Assert.Throws(() => new PackageManager(null, default)); _ = Assert.Throws(() => new PackageManager(null, new DeviceData { Serial = "169.254.109.177:5555" })); - _ = Assert.Throws(() => new PackageManager(Substitute.For(), default)); + _ = Assert.Throws(() => new PackageManager(Substitute.For(), default)); } [Theory] @@ -257,6 +257,14 @@ public void GetPackageVersionInfoTest() Assert.Equal("11.0.62 (448-160311229)", versionInfo.VersionName); } + [Fact] + public void ToStringTest() + { + DummyAdbClient client = new(); + PackageManager manager = new(client, Device, skipInit: true); + Assert.Equal($"{typeof(PackageManager)} {{ {nameof(PackageManager.Device)} = {Device}, {nameof(PackageManager.AdbClient)} = {client} }}", manager.ToString()); + } + private struct InstallProgress(params PackageInstallProgressState[] states) : IProgress { private PackageInstallProgressState? state; diff --git a/AdvancedSharpAdbClient.Tests/DeviceMonitorTests.Async.cs b/AdvancedSharpAdbClient.Tests/DeviceMonitorTests.Async.cs index cbd021a3..7e7d6462 100644 --- a/AdvancedSharpAdbClient.Tests/DeviceMonitorTests.Async.cs +++ b/AdvancedSharpAdbClient.Tests/DeviceMonitorTests.Async.cs @@ -53,6 +53,8 @@ await RunTestAsync( Assert.Single(sink.ListChangedEvents); Assert.Single(sink.DisconnectedEvents); Assert.Equal("169.254.109.177:5555", sink.DisconnectedEvents[0].Device.Serial); + Assert.False(sink.DisconnectedEvents[0].IsConnect); + Assert.Equal("Device disconnected: 169.254.109.177:5555", sink.DisconnectedEvents[0].ToString()); } [Fact] @@ -101,6 +103,8 @@ await RunTestAsync( Assert.Single(sink.ListChangedEvents); Assert.Empty(sink.DisconnectedEvents); Assert.Equal("169.254.109.177:5555", sink.ConnectedEvents[0].Device.Serial); + Assert.True(sink.ConnectedEvents[0].IsConnect); + Assert.Equal("Device connected: 169.254.109.177:5555", sink.ConnectedEvents[0].ToString()); } /// @@ -126,6 +130,8 @@ await RunTestAsync( Assert.Equal("169.254.109.177:5555", monitor.Devices[0].Serial); Assert.Single(sink.ConnectedEvents); Assert.Equal("169.254.109.177:5555", sink.ConnectedEvents[0].Device.Serial); + Assert.True(sink.ConnectedEvents[0].IsConnect); + Assert.Equal("Device connected: 169.254.109.177:5555", sink.ConnectedEvents[0].ToString()); Assert.Empty(sink.ChangedEvents); Assert.Single(sink.NotifiedEvents); Assert.Single(sink.ListChangedEvents); @@ -180,6 +186,9 @@ await RunTestAsync( Assert.Single(sink.ListChangedEvents); Assert.Empty(sink.DisconnectedEvents); Assert.Equal("169.254.109.177:5555", sink.ChangedEvents[0].Device.Serial); + Assert.Equal(DeviceState.Offline, sink.ChangedEvents[0].OldState); + Assert.Equal(DeviceState.Online, sink.ChangedEvents[0].NewState); + Assert.Equal("Device state changed: 169.254.109.177:5555 Offline -> Online", sink.ChangedEvents[0].ToString()); } [Fact] diff --git a/AdvancedSharpAdbClient.Tests/DeviceMonitorTests.cs b/AdvancedSharpAdbClient.Tests/DeviceMonitorTests.cs index c29ee6be..50aae730 100644 --- a/AdvancedSharpAdbClient.Tests/DeviceMonitorTests.cs +++ b/AdvancedSharpAdbClient.Tests/DeviceMonitorTests.cs @@ -83,6 +83,8 @@ public void DeviceDisconnectedTest() Assert.Single(sink.ListChangedEvents); Assert.Single(sink.DisconnectedEvents); Assert.Equal("169.254.109.177:5555", sink.DisconnectedEvents[0].Device.Serial); + Assert.False(sink.DisconnectedEvents[0].IsConnect); + Assert.Equal("Device disconnected: 169.254.109.177:5555", sink.DisconnectedEvents[0].ToString()); } [Fact] @@ -131,6 +133,8 @@ public void DeviceConnectedTest() Assert.Single(sink.ListChangedEvents); Assert.Empty(sink.DisconnectedEvents); Assert.Equal("169.254.109.177:5555", sink.ConnectedEvents[0].Device.Serial); + Assert.True(sink.ConnectedEvents[0].IsConnect); + Assert.Equal("Device connected: 169.254.109.177:5555", sink.ConnectedEvents[0].ToString()); } /// @@ -156,6 +160,8 @@ public void StartInitialDeviceListTest() Assert.Equal("169.254.109.177:5555", monitor.Devices[0].Serial); Assert.Single(sink.ConnectedEvents); Assert.Equal("169.254.109.177:5555", sink.ConnectedEvents[0].Device.Serial); + Assert.True(sink.ConnectedEvents[0].IsConnect); + Assert.Equal("Device connected: 169.254.109.177:5555", sink.ConnectedEvents[0].ToString()); Assert.Empty(sink.ChangedEvents); Assert.Single(sink.NotifiedEvents); Assert.Single(sink.ListChangedEvents); @@ -210,6 +216,9 @@ public void TriggeredWhenStatusChangedTest() Assert.Single(sink.ListChangedEvents); Assert.Empty(sink.DisconnectedEvents); Assert.Equal("169.254.109.177:5555", sink.ChangedEvents[0].Device.Serial); + Assert.Equal(DeviceState.Offline, sink.ChangedEvents[0].OldState); + Assert.Equal(DeviceState.Online, sink.ChangedEvents[0].NewState); + Assert.Equal("Device state changed: 169.254.109.177:5555 Offline -> Online", sink.ChangedEvents[0].ToString()); } [Fact] @@ -295,5 +304,15 @@ public void CloneTest() using DeviceMonitor monitor = deviceMonitor.Clone(); Assert.NotEqual(deviceMonitor.Socket, monitor.Socket); } + + /// + /// Tests the method. + /// + [Fact] + public void ToStringTest() + { + using DeviceMonitor deviceMonitor = new(Socket); + Assert.Equal($"{typeof(DeviceMonitor)} {{ {nameof(DeviceMonitor.Socket)} = {Socket}, {nameof(DeviceMonitor.IsRunning)} = False }}", deviceMonitor.ToString()); + } } } diff --git a/AdvancedSharpAdbClient.Tests/Dummys/DummyAdbClient.cs b/AdvancedSharpAdbClient.Tests/Dummys/DummyAdbClient.cs index 7d7be238..f2b8b31a 100644 --- a/AdvancedSharpAdbClient.Tests/Dummys/DummyAdbClient.cs +++ b/AdvancedSharpAdbClient.Tests/Dummys/DummyAdbClient.cs @@ -40,14 +40,15 @@ public IAsyncEnumerable ExecuteRemoteEnumerableAsync(string command, Dev public void ExecuteServerCommand(string target, string command) { - StringBuilder requestBuilder = new(); - if (!StringExtensions.IsNullOrWhiteSpace(target)) + DefaultInterpolatedStringHandler requestBuilder = new(1, 2); + if (!string.IsNullOrWhiteSpace(target)) { - _ = requestBuilder.Append(target).Append(':'); + requestBuilder.AppendLiteral(target); + requestBuilder.AppendFormatted(':'); } - _ = requestBuilder.Append(command); + requestBuilder.AppendLiteral(command); - string request = requestBuilder.ToString(); + string request = requestBuilder.ToStringAndClear(); ReceivedCommands.Add(request); } @@ -56,14 +57,15 @@ public void ExecuteServerCommand(string target, string command, IAdbSocket socke public void ExecuteServerCommand(string target, string command, IShellOutputReceiver receiver, Encoding encoding) { - StringBuilder requestBuilder = new(); - if (!StringExtensions.IsNullOrWhiteSpace(target)) + DefaultInterpolatedStringHandler requestBuilder = new(1, 2); + if (!string.IsNullOrWhiteSpace(target)) { - _ = requestBuilder.Append(target).Append(':'); + requestBuilder.AppendLiteral(target); + requestBuilder.AppendFormatted(':'); } - _ = requestBuilder.Append(command); + requestBuilder.AppendLiteral(command); - string request = requestBuilder.ToString(); + string request = requestBuilder.ToStringAndClear(); ReceivedCommands.Add(request); if (Commands.TryGetValue(request, out string value)) @@ -91,14 +93,15 @@ public void ExecuteServerCommand(string target, string command, IAdbSocket socke public IEnumerable ExecuteServerEnumerable(string target, string command, Encoding encoding) { - StringBuilder requestBuilder = new(); - if (!StringExtensions.IsNullOrWhiteSpace(target)) + DefaultInterpolatedStringHandler requestBuilder = new(1, 2); + if (!string.IsNullOrWhiteSpace(target)) { - _ = requestBuilder.Append(target).Append(':'); + requestBuilder.AppendLiteral(target); + requestBuilder.AppendFormatted(':'); } - _ = requestBuilder.Append(command); + requestBuilder.AppendLiteral(command); - string request = requestBuilder.ToString(); + string request = requestBuilder.ToStringAndClear(); ReceivedCommands.Add(request); if (Commands.TryGetValue(request, out string value)) @@ -122,14 +125,15 @@ public async Task ExecuteServerCommandAsync(string target, string command, Cance { await Task.Yield(); - StringBuilder requestBuilder = new(); - if (!StringExtensions.IsNullOrWhiteSpace(target)) + DefaultInterpolatedStringHandler requestBuilder = new(1, 2); + if (!string.IsNullOrWhiteSpace(target)) { - _ = requestBuilder.Append(target).Append(':'); + requestBuilder.AppendLiteral(target); + requestBuilder.AppendFormatted(':'); } - _ = requestBuilder.Append(command); + requestBuilder.AppendLiteral(command); - string request = requestBuilder.ToString(); + string request = requestBuilder.ToStringAndClear(); ReceivedCommands.Add(request); } @@ -138,14 +142,15 @@ public Task ExecuteServerCommandAsync(string target, string command, IAdbSocket public async Task ExecuteServerCommandAsync(string target, string command, IShellOutputReceiver receiver, Encoding encoding, CancellationToken cancellationToken = default) { - StringBuilder requestBuilder = new(); - if (!StringExtensions.IsNullOrWhiteSpace(target)) + DefaultInterpolatedStringHandler requestBuilder = new(1, 2); + if (!string.IsNullOrWhiteSpace(target)) { - _ = requestBuilder.Append(target).Append(':'); + requestBuilder.AppendLiteral(target); + requestBuilder.AppendFormatted(':'); } - _ = requestBuilder.Append(command); + requestBuilder.AppendLiteral(command); - string request = requestBuilder.ToString(); + string request = requestBuilder.ToStringAndClear(); ReceivedCommands.Add(request); if (Commands.TryGetValue(request, out string value)) @@ -173,14 +178,15 @@ public Task ExecuteServerCommandAsync(string target, string command, IAdbSocket public async IAsyncEnumerable ExecuteServerEnumerableAsync(string target, string command, Encoding encoding, [EnumeratorCancellation] CancellationToken cancellationToken) { - StringBuilder requestBuilder = new(); - if (!StringExtensions.IsNullOrWhiteSpace(target)) + DefaultInterpolatedStringHandler requestBuilder = new(1, 2); + if (!string.IsNullOrWhiteSpace(target)) { - _ = requestBuilder.Append(target).Append(':'); + requestBuilder.AppendLiteral(target); + requestBuilder.AppendFormatted(':'); } - _ = requestBuilder.Append(command); + requestBuilder.AppendLiteral(command); - string request = requestBuilder.ToString(); + string request = requestBuilder.ToStringAndClear(); ReceivedCommands.Add(request); if (Commands.TryGetValue(request, out string value)) diff --git a/AdvancedSharpAdbClient.Tests/Dummys/DummyAdbCommandLineClient.cs b/AdvancedSharpAdbClient.Tests/Dummys/DummyAdbCommandLineClient.cs index aef700c2..dde88fae 100644 --- a/AdvancedSharpAdbClient.Tests/Dummys/DummyAdbCommandLineClient.cs +++ b/AdvancedSharpAdbClient.Tests/Dummys/DummyAdbCommandLineClient.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using System.Runtime.InteropServices; using System.Threading; using System.Threading.Tasks; @@ -28,20 +27,19 @@ protected override int RunProcess(string filename, string command, ICollection RunProcessAsync(string filename, string comma return RunProcess(filename, command, errorOutput, standardOutput, Timeout.Infinite); } - private static string ServerName => RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? "adb.exe" : "adb"; + private static string ServerName => OperatingSystem.IsWindows() ? "adb.exe" : "adb"; } } diff --git a/AdvancedSharpAdbClient.Tests/Dummys/DummyAdbSocket.cs b/AdvancedSharpAdbClient.Tests/Dummys/DummyAdbSocket.cs index c54d040b..0a7db301 100644 --- a/AdvancedSharpAdbClient.Tests/Dummys/DummyAdbSocket.cs +++ b/AdvancedSharpAdbClient.Tests/Dummys/DummyAdbSocket.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.IO; using System.Net.Sockets; +using System.Runtime.CompilerServices; using System.Threading; using System.Threading.Tasks; using Xunit; @@ -17,7 +18,7 @@ internal partial class DummyAdbSocket : IDummyAdbSocket, ICloneable and to throw /// a indicating that the adb server has forcefully closed the connection. /// - public const string ServerDisconnected = "ServerDisconnected"; + public const string ServerDisconnected = nameof(ServerDisconnected); public DummyAdbSocket() => IsConnected = true; @@ -65,6 +66,8 @@ internal partial class DummyAdbSocket : IDummyAdbSocket, ICloneable Requests.Add(request); + public void SendAdbRequest(DefaultInterpolatedStringHandler request) => Requests.Add(request.ToString()); + public int Read(byte[] data) { Span actual = SyncDataReceived.Dequeue(); diff --git a/AdvancedSharpAdbClient.Tests/Dummys/Logs/DummyLogger.cs b/AdvancedSharpAdbClient.Tests/Dummys/Logs/DummyLogger.cs index a6cb3d63..0d588a46 100644 --- a/AdvancedSharpAdbClient.Tests/Dummys/Logs/DummyLogger.cs +++ b/AdvancedSharpAdbClient.Tests/Dummys/Logs/DummyLogger.cs @@ -5,8 +5,7 @@ namespace AdvancedSharpAdbClient.Logs.Tests { internal class DummyLogger(string name) : ILogger { - public string Name { get; } = name; - + public string Name => name; public void Log(LogLevel logLevel, Exception exception, string message, params object[] args) { Debug.Write($"{Name} logged: "); @@ -14,10 +13,9 @@ public void Log(LogLevel logLevel, Exception exception, string message, params o } } - internal class DummyLogger : DummyLogger, ILogger + internal class DummyLogger : DummyLogger, ILogger where T : allows ref struct { public Type Type { get; } = typeof(T); - public DummyLogger() : base(typeof(T).Name) { } } diff --git a/AdvancedSharpAdbClient.Tests/Dummys/Logs/DummyLoggerFactory.cs b/AdvancedSharpAdbClient.Tests/Dummys/Logs/DummyLoggerFactory.cs index 97980ccc..1e26f1bd 100644 --- a/AdvancedSharpAdbClient.Tests/Dummys/Logs/DummyLoggerFactory.cs +++ b/AdvancedSharpAdbClient.Tests/Dummys/Logs/DummyLoggerFactory.cs @@ -4,6 +4,6 @@ internal class DummyLoggerFactory : ILoggerFactory { public ILogger CreateLogger(string categoryName) => new DummyLogger(categoryName); - public ILogger CreateLogger() => new DummyLogger(); + public ILogger CreateLogger() where T : allows ref struct => new DummyLogger(); } } diff --git a/AdvancedSharpAdbClient.Tests/Extensions/AdbClientExtensionsTests.Async.cs b/AdvancedSharpAdbClient.Tests/Extensions/AdbClientExtensionsTests.Async.cs index 7603dcda..2f559540 100644 --- a/AdvancedSharpAdbClient.Tests/Extensions/AdbClientExtensionsTests.Async.cs +++ b/AdvancedSharpAdbClient.Tests/Extensions/AdbClientExtensionsTests.Async.cs @@ -51,7 +51,7 @@ public async Task ExecuteServerCommandAsyncTest() Assert.Equal(command, x.ArgAt(1)); Assert.Equal(encoding, x.ArgAt(2)); Assert.Equal(default, x.ArgAt(3)); - return result.AsEnumerableAsync(x.ArgAt(3)); + return result.ToAsyncEnumerable(x.ArgAt(3)); }); _ = client.ExecuteServerEnumerableAsync(Arg.Any(), Arg.Any(), Arg.Any(), Arg.Any(), Arg.Any()) .Returns(x => @@ -61,7 +61,7 @@ public async Task ExecuteServerCommandAsyncTest() Assert.Equal(socket, x.ArgAt(2)); Assert.Equal(encoding, x.ArgAt(3)); Assert.Equal(default, x.ArgAt(4)); - return result.AsEnumerableAsync(x.ArgAt(4)); + return result.ToAsyncEnumerable(x.ArgAt(4)); }); await client.ExecuteServerCommandAsync(target, command, receiver); @@ -102,7 +102,7 @@ public async Task ExecuteRemoteCommandAsyncTest() Assert.Equal(device, x.ArgAt(1)); Assert.Equal(encoding, x.ArgAt(2)); Assert.Equal(default, x.ArgAt(3)); - return result.AsEnumerableAsync(x.ArgAt(3)); + return result.ToAsyncEnumerable(x.ArgAt(3)); }); await client.ExecuteRemoteCommandAsync(command, device, receiver); diff --git a/AdvancedSharpAdbClient.Tests/Extensions/EnumerableExtensionsTests.cs b/AdvancedSharpAdbClient.Tests/Extensions/EnumerableExtensionsTests.cs index 94f0b900..d52c4de1 100644 --- a/AdvancedSharpAdbClient.Tests/Extensions/EnumerableExtensionsTests.cs +++ b/AdvancedSharpAdbClient.Tests/Extensions/EnumerableExtensionsTests.cs @@ -42,8 +42,8 @@ public void AddRangeTest() public async Task TaskToArrayTest() { int[] array = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; - Task> arrayTask = TaskExExtensions.Delay(10).ContinueWith(_ => array.Select(x => x)); - IEnumerable> taskArray = array.Select(x => TaskExExtensions.Delay(x).ContinueWith(_ => x)); + Task> arrayTask = Task.Delay(10).ContinueWith(_ => array.Select(x => x)); + IEnumerable> taskArray = array.Select(x => Task.Delay(x).ContinueWith(_ => x)); Assert.Equal(array, await taskArray.ToArrayAsync()); Assert.Equal(array, await arrayTask.ToArrayAsync()); } diff --git a/AdvancedSharpAdbClient.Tests/Extensions/ExceptionExtensionsTests.cs b/AdvancedSharpAdbClient.Tests/Extensions/ExceptionExtensionsTests.cs deleted file mode 100644 index 945f62ba..00000000 --- a/AdvancedSharpAdbClient.Tests/Extensions/ExceptionExtensionsTests.cs +++ /dev/null @@ -1,67 +0,0 @@ -using System; -using Xunit; - -namespace AdvancedSharpAdbClient.Polyfills.Tests -{ - /// - /// Tests the class. - /// - public class ExceptionExtensionsTests - { - [Theory] - [InlineData(null)] - [InlineData("")] - [InlineData("name")] - public void ThrowIfNullTest(string paramName) - { - foreach (object o in new[] { new object(), string.Empty, "argument" }) - { - ExceptionExtensions.ThrowIfNull(o); - ExceptionExtensions.ThrowIfNull(o, nameof(paramName)); - } - - Assert.Equal(paramName, Assert.Throws(() => ExceptionExtensions.ThrowIfNull(null, paramName)).ParamName); - } - - [Fact] - public void ThrowIfGreaterThanTest() - { - Assert.Equal(1, Assert.Throws(() => ExceptionExtensions.ThrowIfGreaterThan(1, 0)).ActualValue); - Assert.Equal(1u, Assert.Throws(() => ExceptionExtensions.ThrowIfGreaterThan(1, 0)).ActualValue); - Assert.Equal(1.000000001, Assert.Throws(() => ExceptionExtensions.ThrowIfGreaterThan(1.000000001, 1)).ActualValue); - Assert.Equal(1.00001f, Assert.Throws(() => ExceptionExtensions.ThrowIfGreaterThan(1.00001f, 1)).ActualValue); - - ExceptionExtensions.ThrowIfGreaterThan(1, 2); - } - - [Fact] - public static void ThrowIfLessThanTest() - { - Assert.Equal(0, Assert.Throws(() => ExceptionExtensions.ThrowIfLessThan(0, 1)).ActualValue); - Assert.Equal(0u, Assert.Throws(() => ExceptionExtensions.ThrowIfLessThan(0, 1)).ActualValue); - Assert.Equal(1d, Assert.Throws(() => ExceptionExtensions.ThrowIfLessThan(1, 1.000000001)).ActualValue); - Assert.Equal(1f, Assert.Throws(() => ExceptionExtensions.ThrowIfLessThan(1, 1.00001f)).ActualValue); - - ExceptionExtensions.ThrowIfLessThan(2, 1); - } - - [Fact] - public static void ThrowIfNegativeTest() - { - Assert.Equal(-1d, Assert.Throws(() => ExceptionExtensions.ThrowIfNegative(-1d)).ActualValue); - - ExceptionExtensions.ThrowIfNegative(0); - ExceptionExtensions.ThrowIfNegative(1); - } - - [Fact] - public static void ThrowIfTest() - { - object obj = new(); - ObjectDisposedException ex = Assert.Throws( - () => ExceptionExtensions.ThrowIf(true, obj)); - - Assert.Equal("System.Object", ex.ObjectName); - } - } -} diff --git a/AdvancedSharpAdbClient.Tests/Logs/LogTests.cs b/AdvancedSharpAdbClient.Tests/Logs/LogTests.cs index a5c67741..8aab49f5 100644 --- a/AdvancedSharpAdbClient.Tests/Logs/LogTests.cs +++ b/AdvancedSharpAdbClient.Tests/Logs/LogTests.cs @@ -1,5 +1,7 @@ -using System; +using Microsoft.VisualStudio.TestPlatform.CommunicationUtilities; +using System; using System.Collections.Generic; +using System.Diagnostics; using System.IO; using System.Threading.Tasks; using Xunit; @@ -32,6 +34,7 @@ public void ReadLogTest() Assert.Equal(Priority.Info, androidLog.Priority); Assert.Equal("ActivityManager", androidLog.Tag); Assert.Equal("Start proc com.google.android.gm for broadcast com.google.android.gm/.widget.GmailWidgetProvider: pid=7026 uid=10066 gids={50066, 9997, 3003, 1028, 1015} abi=x86", androidLog.Message); + Assert.Equal($"{log.TimeStamp.LocalDateTime:yy-MM-dd HH:mm:ss.fff} 707 707 I ActivityManager: Start proc com.google.android.gm for broadcast com.google.android.gm/.widget.GmailWidgetProvider: pid=7026 uid=10066 gids={{50066, 9997, 3003, 1028, 1015}} abi=x86", androidLog.ToString()); Assert.NotNull(reader.ReadEntry()); Assert.NotNull(reader.ReadEntry()); @@ -61,6 +64,7 @@ public async Task ReadLogAsyncTest() Assert.Equal(Priority.Info, androidLog.Priority); Assert.Equal("ActivityManager", androidLog.Tag); Assert.Equal("Start proc com.google.android.gm for broadcast com.google.android.gm/.widget.GmailWidgetProvider: pid=7026 uid=10066 gids={50066, 9997, 3003, 1028, 1015} abi=x86", androidLog.Message); + Assert.Equal($"{log.TimeStamp.LocalDateTime:yy-MM-dd HH:mm:ss.fff} 707 707 I ActivityManager: Start proc com.google.android.gm for broadcast com.google.android.gm/.widget.GmailWidgetProvider: pid=7026 uid=10066 gids={{50066, 9997, 3003, 1028, 1015}} abi=x86", androidLog.ToString()); Assert.NotNull(await reader.ReadEntryAsync()); Assert.NotNull(await reader.ReadEntryAsync()); @@ -89,6 +93,7 @@ public void ReadEventLogTest() Assert.Single(eventLog.Values); Assert.NotNull(eventLog.Values[0]); Assert.IsType>(eventLog.Values[0]); + Assert.Equal($"{entry.TimeStamp.LocalDateTime:yy-MM-dd HH:mm:ss.fff} 707 707 0 : System.Collections.Generic.List`1[System.Object]", eventLog.ToString()); List list = (List)eventLog.Values[0]; Assert.Equal(3, list.Count); @@ -123,6 +128,7 @@ public async Task ReadEventLogAsyncTest() Assert.Single(eventLog.Values); Assert.NotNull(eventLog.Values[0]); Assert.IsType>(eventLog.Values[0]); + Assert.Equal($"{entry.TimeStamp.LocalDateTime:yy-MM-dd HH:mm:ss.fff} 707 707 0 : System.Collections.Generic.List`1[System.Object]", eventLog.ToString()); List list = (List)eventLog.Values[0]; Assert.Equal(3, list.Count); diff --git a/AdvancedSharpAdbClient.Tests/Models/ForwardDataTests.cs b/AdvancedSharpAdbClient.Tests/Models/ForwardDataTests.cs index 30958db1..3f1402d9 100644 --- a/AdvancedSharpAdbClient.Tests/Models/ForwardDataTests.cs +++ b/AdvancedSharpAdbClient.Tests/Models/ForwardDataTests.cs @@ -10,14 +10,15 @@ public class ForwardDataTests [Fact] public void SpecTest() { - ForwardData data = new() - { - Local = "tcp:1234", - Remote = "tcp:4321" - }; + ForwardData data = new( + serialNumber: "emulator-5554", + local: "tcp:1234", + remote: "tcp:4321" + ); Assert.Equal("tcp:1234", data.LocalSpec.ToString()); Assert.Equal("tcp:4321", data.RemoteSpec.ToString()); + Assert.Equal("emulator-5554 tcp:1234 tcp:4321", data.ToString()); } } } diff --git a/AdvancedSharpAdbClient.Tests/Models/FramebufferTests.cs b/AdvancedSharpAdbClient.Tests/Models/FramebufferTests.cs index ba88bd5a..3d66a5b6 100644 --- a/AdvancedSharpAdbClient.Tests/Models/FramebufferTests.cs +++ b/AdvancedSharpAdbClient.Tests/Models/FramebufferTests.cs @@ -14,12 +14,12 @@ public class FramebufferTests [Fact] public void ConstructorNullTest() { - _ = Assert.Throws(() => new Framebuffer(default, (AdbClient)null)); - _ = Assert.Throws(() => new Framebuffer(default, (EndPoint)null)); + _ = Assert.Throws(() => new Framebuffer(default, (AdbClient)null)); + _ = Assert.Throws(() => new Framebuffer(default, (EndPoint)null)); _ = Assert.Throws(() => new Framebuffer(new DeviceData { Serial = "169.254.109.177:5555" }, (AdbClient)null)); _ = Assert.Throws(() => new Framebuffer(new DeviceData { Serial = "169.254.109.177:5555" }, (EndPoint)null)); - _ = Assert.Throws(() => new Framebuffer(default, new AdbClient())); - _ = Assert.Throws(() => new Framebuffer(default, AdbClient.DefaultEndPoint)); + _ = Assert.Throws(() => new Framebuffer(default, new AdbClient())); + _ = Assert.Throws(() => new Framebuffer(default, AdbClient.DefaultEndPoint)); } [Fact] diff --git a/AdvancedSharpAdbClient.Tests/NamespaceDocTests.cs b/AdvancedSharpAdbClient.Tests/NamespaceDocTests.cs new file mode 100644 index 00000000..e747948a --- /dev/null +++ b/AdvancedSharpAdbClient.Tests/NamespaceDocTests.cs @@ -0,0 +1,27 @@ +using Xunit; + +namespace AdvancedSharpAdbClient.Tests +{ + /// + /// Tests the class. + /// + public class NamespaceDocTests + { + /// + /// Tests the property. + /// + [Fact] + public void NameTest() + { + Assert.Equal("AdvancedSharpAdbClient", NamespaceDoc.Name); + Assert.Equal("AdvancedSharpAdbClient.DeviceCommands", DeviceCommands.NamespaceDoc.Name); + Assert.Equal("AdvancedSharpAdbClient.DeviceCommands.Models", DeviceCommands.Models.NamespaceDoc.Name); + Assert.Equal("AdvancedSharpAdbClient.DeviceCommands.Receivers", DeviceCommands.Receivers.NamespaceDoc.Name); + Assert.Equal("AdvancedSharpAdbClient.Exceptions", Exceptions.NamespaceDoc.Name); + Assert.Equal("AdvancedSharpAdbClient.Logs", Logs.NamespaceDoc.Name); + Assert.Equal("AdvancedSharpAdbClient.Models", Models.NamespaceDoc.Name); + Assert.Equal("AdvancedSharpAdbClient.Polyfills", Polyfills.NamespaceDoc.Name); + Assert.Equal("AdvancedSharpAdbClient.Receivers", Receivers.NamespaceDoc.Name); + } + } +} diff --git a/AdvancedSharpAdbClient.Tests/Properties/GlobalUsings.cs b/AdvancedSharpAdbClient.Tests/Properties/GlobalUsings.cs index a22aa63d..07658998 100644 --- a/AdvancedSharpAdbClient.Tests/Properties/GlobalUsings.cs +++ b/AdvancedSharpAdbClient.Tests/Properties/GlobalUsings.cs @@ -13,7 +13,7 @@ global using AdvancedSharpAdbClient.Logs.Tests; #endregion -#if WINDOWS10_0_18362_0_OR_GREATER +#if WINDOWS10_0_17763_0_OR_GREATER global using Windows.ApplicationModel; global using System.Runtime.InteropServices.WindowsRuntime; global using Windows.Storage; diff --git a/AdvancedSharpAdbClient.Tests/SyncServiceTests.Async.cs b/AdvancedSharpAdbClient.Tests/SyncServiceTests.Async.cs index c17cb2cc..c7e7b7a8 100644 --- a/AdvancedSharpAdbClient.Tests/SyncServiceTests.Async.cs +++ b/AdvancedSharpAdbClient.Tests/SyncServiceTests.Async.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.IO; +using System.Linq; using System.Threading; using System.Threading.Tasks; using Xunit; @@ -32,10 +33,12 @@ public async Task StatAsyncTest() return value; }); + Assert.Equal("/fstab.donatello", value.Path); Assert.Equal(UnixFileStatus.Regular, value.FileMode.GetFileType()); Assert.Equal((UnixFileStatus)416, value.FileMode.GetPermissions()); Assert.Equal(597, value.Size); Assert.Equal(DateTimeExtensions.Epoch.ToLocalTime(), value.Time); + Assert.Equal($"-rw-r-----\t597\t{value.Time}\t/fstab.donatello", value.ToString()); } /// @@ -75,24 +78,28 @@ public async Task GetListingAsyncTest() Assert.Equal((UnixFileStatus)16873, dir.FileMode); Assert.Equal(0, dir.Size); Assert.Equal(time, dir.Time); + Assert.Equal($"drwxr-x--x\t0\t{dir.Time}\t.", dir.ToString()); FileStatistics parentDir = value[1]; Assert.Equal("..", parentDir.Path); Assert.Equal((UnixFileStatus)16877, parentDir.FileMode); Assert.Equal(0, parentDir.Size); Assert.Equal(time, parentDir.Time); + Assert.Equal($"drwxr-xr-x\t0\t{dir.Time}\t..", parentDir.ToString()); FileStatistics sdcard0 = value[2]; Assert.Equal("sdcard0", sdcard0.Path); Assert.Equal((UnixFileStatus)41471, sdcard0.FileMode); Assert.Equal(24, sdcard0.Size); Assert.Equal(time, sdcard0.Time); + Assert.Equal($"lrwxrwxrwx\t24\t{dir.Time}\tsdcard0", sdcard0.ToString()); FileStatistics emulated = value[3]; Assert.Equal("emulated", emulated.Path); Assert.Equal((UnixFileStatus)16749, emulated.FileMode); Assert.Equal(0, emulated.Size); Assert.Equal(time, emulated.Time); + Assert.Equal($"dr-xr-xr-x\t0\t{dir.Time}\temulated", emulated.ToString()); } /// @@ -132,24 +139,28 @@ public async Task GetAsyncListingTest() Assert.Equal((UnixFileStatus)16873, dir.FileMode); Assert.Equal(0, dir.Size); Assert.Equal(time, dir.Time); + Assert.Equal($"drwxr-x--x\t0\t{dir.Time}\t.", dir.ToString()); FileStatistics parentDir = value[1]; Assert.Equal("..", parentDir.Path); Assert.Equal((UnixFileStatus)16877, parentDir.FileMode); Assert.Equal(0, parentDir.Size); Assert.Equal(time, parentDir.Time); + Assert.Equal($"drwxr-xr-x\t0\t{dir.Time}\t..", parentDir.ToString()); FileStatistics sdcard0 = value[2]; Assert.Equal("sdcard0", sdcard0.Path); Assert.Equal((UnixFileStatus)41471, sdcard0.FileMode); Assert.Equal(24, sdcard0.Size); Assert.Equal(time, sdcard0.Time); + Assert.Equal($"lrwxrwxrwx\t24\t{dir.Time}\tsdcard0", sdcard0.ToString()); FileStatistics emulated = value[3]; Assert.Equal("emulated", emulated.Path); Assert.Equal((UnixFileStatus)16749, emulated.FileMode); Assert.Equal(0, emulated.Size); Assert.Equal(time, emulated.Time); + Assert.Equal($"dr-xr-xr-x\t0\t{dir.Time}\temulated", emulated.ToString()); } /// diff --git a/AdvancedSharpAdbClient.Tests/SyncServiceTests.cs b/AdvancedSharpAdbClient.Tests/SyncServiceTests.cs index 0cc2bffa..7155e657 100644 --- a/AdvancedSharpAdbClient.Tests/SyncServiceTests.cs +++ b/AdvancedSharpAdbClient.Tests/SyncServiceTests.cs @@ -41,10 +41,12 @@ public void StatTest() return value; }); + Assert.Equal("/fstab.donatello", value.Path); Assert.Equal(UnixFileStatus.Regular, value.FileMode.GetFileType()); Assert.Equal((UnixFileStatus)416, value.FileMode.GetPermissions()); Assert.Equal(597, value.Size); Assert.Equal(DateTimeExtensions.Epoch.ToLocalTime(), value.Time); + Assert.Equal($"-rw-r-----\t597\t{value.Time}\t/fstab.donatello", value.ToString()); } /// @@ -69,7 +71,7 @@ public void GetListingTest() () => { using SyncService service = new(Socket, Device); - FileStatistics[] value = service.GetDirectoryListing("/storage").ToArray(); + FileStatistics[] value = [.. service.GetDirectoryListing("/storage")]; Assert.False(service.IsProcessing); Assert.True(service.IsOutdate); return value; @@ -84,24 +86,28 @@ public void GetListingTest() Assert.Equal((UnixFileStatus)16873, dir.FileMode); Assert.Equal(0, dir.Size); Assert.Equal(time, dir.Time); + Assert.Equal($"drwxr-x--x\t0\t{dir.Time}\t.", dir.ToString()); FileStatistics parentDir = value[1]; Assert.Equal("..", parentDir.Path); Assert.Equal((UnixFileStatus)16877, parentDir.FileMode); Assert.Equal(0, parentDir.Size); Assert.Equal(time, parentDir.Time); + Assert.Equal($"drwxr-xr-x\t0\t{dir.Time}\t..", parentDir.ToString()); FileStatistics sdcard0 = value[2]; Assert.Equal("sdcard0", sdcard0.Path); Assert.Equal((UnixFileStatus)41471, sdcard0.FileMode); Assert.Equal(24, sdcard0.Size); Assert.Equal(time, sdcard0.Time); + Assert.Equal($"lrwxrwxrwx\t24\t{dir.Time}\tsdcard0", sdcard0.ToString()); FileStatistics emulated = value[3]; Assert.Equal("emulated", emulated.Path); Assert.Equal((UnixFileStatus)16749, emulated.FileMode); Assert.Equal(0, emulated.Size); Assert.Equal(time, emulated.Time); + Assert.Equal($"dr-xr-xr-x\t0\t{dir.Time}\temulated", emulated.ToString()); } /// @@ -233,12 +239,36 @@ public void CloneTest() socket.Responses.Enqueue(AdbResponse.OK); using SyncService syncService = new(socket, Device); Assert.True(syncService is ICloneable); -#if WINDOWS10_0_18362_0_OR_GREATER +#if WINDOWS10_0_17763_0_OR_GREATER Assert.True(syncService is ICloneable); #endif using SyncService service = syncService.Clone(); Assert.NotEqual(syncService.Socket, service.Socket); Assert.Equal(syncService.Device, service.Device); } + + /// + /// Tests the method. + /// + [Fact] + public void ToStringTest() + { + DummyAdbSocket socket = new() + { + Requests = + { + "host:transport:169.254.109.177:5555", + "sync:", + "host:transport:169.254.109.177:5555", + "sync:" + } + }; + socket.Responses.Enqueue(AdbResponse.OK); + socket.Responses.Enqueue(AdbResponse.OK); + socket.Responses.Enqueue(AdbResponse.OK); + socket.Responses.Enqueue(AdbResponse.OK); + using SyncService service = new(socket, Device); + Assert.Equal($"{typeof(SyncService)} {{ {nameof(SyncService.Socket)} = {socket}, {nameof(SyncService.Device)} = {Device} }}", service.ToString()); + } } } diff --git a/AdvancedSharpAdbClient.Tests/TcpSocketTests.cs b/AdvancedSharpAdbClient.Tests/TcpSocketTests.cs index 5f8f3ec8..9f308404 100644 --- a/AdvancedSharpAdbClient.Tests/TcpSocketTests.cs +++ b/AdvancedSharpAdbClient.Tests/TcpSocketTests.cs @@ -1,7 +1,6 @@ using System; using System.Net; using System.Net.Sockets; -using System.Runtime.InteropServices; using System.Text; using Xunit; @@ -42,8 +41,8 @@ public void LifecycleSpanTest() ReadOnlySpan data = "GET / HTTP/1.1\n\n"u8; socket.Send(data, SocketFlags.None); - byte[] responseData = new byte[128]; - socket.Receive([.. responseData], SocketFlags.None); + Span responseData = new byte[128]; + socket.Receive(responseData, SocketFlags.None); _ = Encoding.ASCII.GetString(responseData); } @@ -78,7 +77,7 @@ public void BufferSizeTest() ReceiveBufferSize = 1024 }; // https://stackoverflow.com/questions/29356626/is-there-a-way-to-reduce-the-minimum-lower-limit-of-the-socket-send-buffer-size - Assert.Equal(RuntimeInformation.IsOSPlatform(OSPlatform.Linux) ? 2304 : 1024, socket.ReceiveBufferSize); + Assert.Equal(OperatingSystem.IsLinux() ? 2304 : 1024, socket.ReceiveBufferSize); } /// @@ -105,5 +104,21 @@ public void CloneTest() Assert.Equal(tcpSocket.EndPoint, socket.EndPoint); Assert.True(socket.Connected); } + + /// + /// Tests the method. + /// + [Fact] + public void ToStringTest() + { + using TcpSocket socket = new(); + Assert.Equal($"The {typeof(TcpSocket)} without initialized.", socket.ToString()); + + socket.Connect(new DnsEndPoint("www.bing.com", 80)); + Assert.Equal($"The {typeof(TcpSocket)} connect with 'Unspecified/www.bing.com:80'.", socket.ToString()); + + socket.Dispose(); + Assert.Equal($"The {typeof(TcpSocket)} disconnect with 'Unspecified/www.bing.com:80'.", socket.ToString()); + } } } diff --git a/AdvancedSharpAdbClient.sln b/AdvancedSharpAdbClient.sln deleted file mode 100644 index 1aa58846..00000000 --- a/AdvancedSharpAdbClient.sln +++ /dev/null @@ -1,71 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 17 -VisualStudioVersion = 17.3.32505.426 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AdvancedSharpAdbClient", "AdvancedSharpAdbClient\AdvancedSharpAdbClient.csproj", "{65473257-E70F-410B-9269-D0C0F771EA87}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AdvancedSharpAdbClient.Tests", "AdvancedSharpAdbClient.Tests\AdvancedSharpAdbClient.Tests.csproj", "{F1B44867-B64E-4813-8F13-0B0918AEC202}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Debug|ARM = Debug|ARM - Debug|ARM64 = Debug|ARM64 - Debug|x64 = Debug|x64 - Debug|x86 = Debug|x86 - Release|Any CPU = Release|Any CPU - Release|ARM = Release|ARM - Release|ARM64 = Release|ARM64 - Release|x64 = Release|x64 - Release|x86 = Release|x86 - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {65473257-E70F-410B-9269-D0C0F771EA87}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {65473257-E70F-410B-9269-D0C0F771EA87}.Debug|Any CPU.Build.0 = Debug|Any CPU - {65473257-E70F-410B-9269-D0C0F771EA87}.Debug|ARM.ActiveCfg = Debug|Any CPU - {65473257-E70F-410B-9269-D0C0F771EA87}.Debug|ARM.Build.0 = Debug|Any CPU - {65473257-E70F-410B-9269-D0C0F771EA87}.Debug|ARM64.ActiveCfg = Debug|Any CPU - {65473257-E70F-410B-9269-D0C0F771EA87}.Debug|ARM64.Build.0 = Debug|Any CPU - {65473257-E70F-410B-9269-D0C0F771EA87}.Debug|x64.ActiveCfg = Debug|Any CPU - {65473257-E70F-410B-9269-D0C0F771EA87}.Debug|x64.Build.0 = Debug|Any CPU - {65473257-E70F-410B-9269-D0C0F771EA87}.Debug|x86.ActiveCfg = Debug|Any CPU - {65473257-E70F-410B-9269-D0C0F771EA87}.Debug|x86.Build.0 = Debug|Any CPU - {65473257-E70F-410B-9269-D0C0F771EA87}.Release|Any CPU.ActiveCfg = Release|Any CPU - {65473257-E70F-410B-9269-D0C0F771EA87}.Release|Any CPU.Build.0 = Release|Any CPU - {65473257-E70F-410B-9269-D0C0F771EA87}.Release|ARM.ActiveCfg = Release|Any CPU - {65473257-E70F-410B-9269-D0C0F771EA87}.Release|ARM.Build.0 = Release|Any CPU - {65473257-E70F-410B-9269-D0C0F771EA87}.Release|ARM64.ActiveCfg = Release|Any CPU - {65473257-E70F-410B-9269-D0C0F771EA87}.Release|ARM64.Build.0 = Release|Any CPU - {65473257-E70F-410B-9269-D0C0F771EA87}.Release|x64.ActiveCfg = Release|Any CPU - {65473257-E70F-410B-9269-D0C0F771EA87}.Release|x64.Build.0 = Release|Any CPU - {65473257-E70F-410B-9269-D0C0F771EA87}.Release|x86.ActiveCfg = Release|Any CPU - {65473257-E70F-410B-9269-D0C0F771EA87}.Release|x86.Build.0 = Release|Any CPU - {F1B44867-B64E-4813-8F13-0B0918AEC202}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {F1B44867-B64E-4813-8F13-0B0918AEC202}.Debug|Any CPU.Build.0 = Debug|Any CPU - {F1B44867-B64E-4813-8F13-0B0918AEC202}.Debug|ARM.ActiveCfg = Debug|Any CPU - {F1B44867-B64E-4813-8F13-0B0918AEC202}.Debug|ARM.Build.0 = Debug|Any CPU - {F1B44867-B64E-4813-8F13-0B0918AEC202}.Debug|ARM64.ActiveCfg = Debug|Any CPU - {F1B44867-B64E-4813-8F13-0B0918AEC202}.Debug|ARM64.Build.0 = Debug|Any CPU - {F1B44867-B64E-4813-8F13-0B0918AEC202}.Debug|x64.ActiveCfg = Debug|Any CPU - {F1B44867-B64E-4813-8F13-0B0918AEC202}.Debug|x64.Build.0 = Debug|Any CPU - {F1B44867-B64E-4813-8F13-0B0918AEC202}.Debug|x86.ActiveCfg = Debug|Any CPU - {F1B44867-B64E-4813-8F13-0B0918AEC202}.Debug|x86.Build.0 = Debug|Any CPU - {F1B44867-B64E-4813-8F13-0B0918AEC202}.Release|Any CPU.ActiveCfg = Release|Any CPU - {F1B44867-B64E-4813-8F13-0B0918AEC202}.Release|Any CPU.Build.0 = Release|Any CPU - {F1B44867-B64E-4813-8F13-0B0918AEC202}.Release|ARM.ActiveCfg = Release|Any CPU - {F1B44867-B64E-4813-8F13-0B0918AEC202}.Release|ARM.Build.0 = Release|Any CPU - {F1B44867-B64E-4813-8F13-0B0918AEC202}.Release|ARM64.ActiveCfg = Release|Any CPU - {F1B44867-B64E-4813-8F13-0B0918AEC202}.Release|ARM64.Build.0 = Release|Any CPU - {F1B44867-B64E-4813-8F13-0B0918AEC202}.Release|x64.ActiveCfg = Release|Any CPU - {F1B44867-B64E-4813-8F13-0B0918AEC202}.Release|x64.Build.0 = Release|Any CPU - {F1B44867-B64E-4813-8F13-0B0918AEC202}.Release|x86.ActiveCfg = Release|Any CPU - {F1B44867-B64E-4813-8F13-0B0918AEC202}.Release|x86.Build.0 = Release|Any CPU - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection - GlobalSection(ExtensibilityGlobals) = postSolution - SolutionGuid = {0ACB9022-5726-46AD-868D-C43F8A25BD23} - EndGlobalSection -EndGlobal diff --git a/AdvancedSharpAdbClient.slnx b/AdvancedSharpAdbClient.slnx new file mode 100644 index 00000000..3a862bcb --- /dev/null +++ b/AdvancedSharpAdbClient.slnx @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/AdvancedSharpAdbClient/AdbClient.Async.cs b/AdvancedSharpAdbClient/AdbClient.Async.cs index c44267fb..f560b318 100644 --- a/AdvancedSharpAdbClient/AdbClient.Async.cs +++ b/AdvancedSharpAdbClient/AdbClient.Async.cs @@ -169,14 +169,15 @@ public async Task ExecuteServerCommandAsync(string target, string command, Cance /// public virtual async Task ExecuteServerCommandAsync(string target, string command, IAdbSocket socket, CancellationToken cancellationToken = default) { - StringBuilder request = new(); - if (!StringExtensions.IsNullOrWhiteSpace(target)) + DefaultInterpolatedStringHandler request = new(1, 2); + if (!string.IsNullOrWhiteSpace(target)) { - _ = request.Append(target).Append(':'); + request.AppendLiteral(target); + request.AppendFormatted(':'); } - _ = request.Append(command); + request.AppendLiteral(command); - await socket.SendAdbRequestAsync(request.ToString(), cancellationToken); + await socket.SendAdbRequestAsync(request.ToStringAndClear(), cancellationToken); await socket.ReadAdbResponseAsync(cancellationToken).ConfigureAwait(false); try @@ -217,7 +218,7 @@ public async Task ExecuteRemoteCommandAsync(string command, DeviceData device, C /// public async Task ExecuteServerCommandAsync(string target, string command, IShellOutputReceiver? receiver, Encoding encoding, CancellationToken cancellationToken = default) { - ExceptionExtensions.ThrowIfNull(encoding); + ArgumentNullException.ThrowIfNull(encoding); using IAdbSocket socket = CreateAdbSocket(); await ExecuteServerCommandAsync(target, command, socket, receiver, encoding, cancellationToken); } @@ -225,16 +226,17 @@ public async Task ExecuteServerCommandAsync(string target, string command, IShel /// public virtual async Task ExecuteServerCommandAsync(string target, string command, IAdbSocket socket, IShellOutputReceiver? receiver, Encoding encoding, CancellationToken cancellationToken = default) { - ExceptionExtensions.ThrowIfNull(encoding); + ArgumentNullException.ThrowIfNull(encoding); - StringBuilder request = new(); - if (!StringExtensions.IsNullOrWhiteSpace(target)) + DefaultInterpolatedStringHandler request = new(1, 2); + if (!string.IsNullOrWhiteSpace(target)) { - _ = request.Append(target).Append(':'); + request.AppendLiteral(target); + request.AppendFormatted(':'); } - _ = request.Append(command); + request.AppendLiteral(command); - await socket.SendAdbRequestAsync(request.ToString(), cancellationToken); + await socket.SendAdbRequestAsync(request.ToStringAndClear(), cancellationToken); _ = await socket.ReadAdbResponseAsync(cancellationToken).ConfigureAwait(false); try @@ -271,7 +273,7 @@ public virtual async Task ExecuteServerCommandAsync(string target, string comman public async Task ExecuteRemoteCommandAsync(string command, DeviceData device, IShellOutputReceiver? receiver, Encoding encoding, CancellationToken cancellationToken = default) { EnsureDevice(device); - ExceptionExtensions.ThrowIfNull(encoding); + ArgumentNullException.ThrowIfNull(encoding); using IAdbSocket socket = CreateAdbSocket(); await socket.SetDeviceAsync(device, cancellationToken); @@ -283,7 +285,7 @@ public async Task ExecuteRemoteCommandAsync(string command, DeviceData device, I /// public async IAsyncEnumerable ExecuteServerEnumerableAsync(string target, string command, Encoding encoding, [EnumeratorCancellation] CancellationToken cancellationToken = default) { - ExceptionExtensions.ThrowIfNull(encoding); + ArgumentNullException.ThrowIfNull(encoding); using IAdbSocket socket = CreateAdbSocket(); await foreach (string? line in ExecuteServerEnumerableAsync(target, command, socket, encoding, cancellationToken).ConfigureAwait(false)) { @@ -294,16 +296,17 @@ public async IAsyncEnumerable ExecuteServerEnumerableAsync(string target /// public virtual async IAsyncEnumerable ExecuteServerEnumerableAsync(string target, string command, IAdbSocket socket, Encoding encoding, [EnumeratorCancellation] CancellationToken cancellationToken = default) { - ExceptionExtensions.ThrowIfNull(encoding); + ArgumentNullException.ThrowIfNull(encoding); - StringBuilder request = new(); - if (!StringExtensions.IsNullOrWhiteSpace(target)) + DefaultInterpolatedStringHandler request = new(1, 2); + if (!string.IsNullOrWhiteSpace(target)) { - _ = request.Append(target).Append(':'); + request.AppendLiteral(target); + request.AppendFormatted(':'); } - _ = request.Append(command); + request.AppendLiteral(command); - await socket.SendAdbRequestAsync(request.ToString(), cancellationToken); + await socket.SendAdbRequestAsync(request.ToStringAndClear(), cancellationToken); _ = await socket.ReadAdbResponseAsync(cancellationToken).ConfigureAwait(false); using StreamReader reader = new(socket.GetShellStream(), encoding); @@ -337,7 +340,7 @@ public virtual async IAsyncEnumerable ExecuteServerEnumerableAsync(strin public async IAsyncEnumerable ExecuteRemoteEnumerableAsync(string command, DeviceData device, Encoding encoding, [EnumeratorCancellation] CancellationToken cancellationToken = default) { EnsureDevice(device); - ExceptionExtensions.ThrowIfNull(encoding); + ArgumentNullException.ThrowIfNull(encoding); using IAdbSocket socket = CreateAdbSocket(); await socket.SetDeviceAsync(device, cancellationToken); @@ -358,14 +361,16 @@ public async IAsyncEnumerable RunLogServiceAsync(DeviceData device, [E using IAdbSocket socket = CreateAdbSocket(); await socket.SetDeviceAsync(device, cancellationToken).ConfigureAwait(false); - StringBuilder request = new("shell:logcat -B"); + DefaultInterpolatedStringHandler request = new(19, logNames.Length); + request.AppendLiteral("shell:logcat -B"); foreach (LogId logName in logNames) { - _ = request.Append(" -b ").Append(logName.ToString().ToLowerInvariant()); + request.AppendLiteral(" -b "); + request.AppendLiteral(logName.ToString().ToLowerInvariant()); } - await socket.SendAdbRequestAsync(request.ToString(), cancellationToken).ConfigureAwait(false); + await socket.SendAdbRequestAsync(request.ToStringAndClear(), cancellationToken).ConfigureAwait(false); _ = await socket.ReadAdbResponseAsync(cancellationToken).ConfigureAwait(false); #if COMP_NETSTANDARD2_1 @@ -403,21 +408,23 @@ public async IAsyncEnumerable RunLogServiceAsync(DeviceData device, [E public async Task RunLogServiceAsync(DeviceData device, Action messageSink, CancellationToken cancellationToken = default, params LogId[] logNames) { EnsureDevice(device); - ExceptionExtensions.ThrowIfNull(messageSink); + ArgumentNullException.ThrowIfNull(messageSink); // The 'log' service has been deprecated, see // https://android.googlesource.com/platform/system/core/+/7aa39a7b199bb9803d3fd47246ee9530b4a96177 using IAdbSocket socket = CreateAdbSocket(); await socket.SetDeviceAsync(device, cancellationToken).ConfigureAwait(false); - StringBuilder request = new("shell:logcat -B"); + DefaultInterpolatedStringHandler request = new(19, logNames.Length); + request.AppendLiteral("shell:logcat -B"); foreach (LogId logName in logNames) { - _ = request.Append(" -b ").Append(logName.ToString().ToLowerInvariant()); + request.AppendLiteral(" -b "); + request.AppendLiteral(logName.ToString().ToLowerInvariant()); } - await socket.SendAdbRequestAsync(request.ToString(), cancellationToken).ConfigureAwait(false); + await socket.SendAdbRequestAsync(request.ToStringAndClear(), cancellationToken).ConfigureAwait(false); _ = await socket.ReadAdbResponseAsync(cancellationToken).ConfigureAwait(false); #if COMP_NETSTANDARD2_1 @@ -477,7 +484,7 @@ public async Task RebootAsync(string into, DeviceData device, CancellationToken /// public async Task PairAsync(string host, int port, string code, CancellationToken cancellationToken = default) { - ExceptionExtensions.ThrowIfNull(host); + ArgumentNullException.ThrowIfNull(host); using IAdbSocket socket = CreateAdbSocket(); string address = host.Contains(':') ? host : $"{host}:{port}"; @@ -490,7 +497,7 @@ public async Task PairAsync(string host, int port, string code, Cancella /// public async Task ConnectAsync(string host, int port = DefaultPort, CancellationToken cancellationToken = default) { - ExceptionExtensions.ThrowIfNull(host); + ArgumentNullException.ThrowIfNull(host); using IAdbSocket socket = CreateAdbSocket(); string address = host.Contains(':') ? host : $"{host}:{port}"; @@ -503,7 +510,7 @@ public async Task ConnectAsync(string host, int port = DefaultPort, Canc /// public async Task DisconnectAsync(string host, int port = DefaultPort, CancellationToken cancellationToken = default) { - ExceptionExtensions.ThrowIfNull(host); + ArgumentNullException.ThrowIfNull(host); using IAdbSocket socket = CreateAdbSocket(); string address = host.Contains(':') ? host : $"{host}:{port}"; @@ -557,7 +564,7 @@ protected async Task RootAsync(string request, DeviceData device, CancellationTo { // Give adbd some time to kill itself and come back up. // We can't use wait-for-device because devices (e.g. adb over network) might not come back. - await TaskExExtensions.Delay(3000, cancellationToken).ConfigureAwait(false); + await Task.Delay(3000, cancellationToken).ConfigureAwait(false); } } @@ -567,31 +574,34 @@ public virtual async Task InstallAsync(DeviceData device, Stream apk, Action 0) - { - await socket.SendAsync(buffer.AsMemory(0, read), cancellationToken).ConfigureAwait(false); #else while ((read = await apk.ReadAsync(buffer, 0, buffer.Length, cancellationToken).ConfigureAwait(false)) > 0) +#endif { +#if COMP_NETSTANDARD2_1 + await socket.SendAsync(buffer.AsMemory(0, read), cancellationToken).ConfigureAwait(false); +#else await socket.SendAsync(buffer, read, cancellationToken).ConfigureAwait(false); #endif totalBytesRead += read; @@ -636,8 +648,8 @@ public async Task InstallMultipleAsync(DeviceData device, Stream baseAPK, IEnume callback?.Invoke(new InstallProgressEventArgs(PackageInstallProgressState.Preparing)); EnsureDevice(device); - ExceptionExtensions.ThrowIfNull(baseAPK); - ExceptionExtensions.ThrowIfNull(splitAPKs); + ArgumentNullException.ThrowIfNull(baseAPK); + ArgumentNullException.ThrowIfNull(splitAPKs); if (!baseAPK.CanRead || !baseAPK.CanSeek) { @@ -689,8 +701,8 @@ public async Task InstallMultipleAsync(DeviceData device, IEnumerable sp callback?.Invoke(new InstallProgressEventArgs(PackageInstallProgressState.Preparing)); EnsureDevice(device); - ExceptionExtensions.ThrowIfNull(splitAPKs); - ExceptionExtensions.ThrowIfNull(packageName); + ArgumentNullException.ThrowIfNull(splitAPKs); + ArgumentNullException.ThrowIfNull(packageName); if (splitAPKs.Any(apk => apk == null || !apk.CanRead || !apk.CanSeek)) { @@ -731,20 +743,22 @@ public async Task InstallCreateAsync(DeviceData device, CancellationToke { EnsureDevice(device); - StringBuilder requestBuilder = new("exec:cmd package 'install-create'"); + using IAdbSocket socket = CreateAdbSocket(); + await socket.SetDeviceAsync(device, cancellationToken).ConfigureAwait(false); + + DefaultInterpolatedStringHandler requestBuilder = new(33, arguments?.Length ?? 0); + requestBuilder.AppendLiteral("exec:cmd package 'install-create'"); if (arguments != null) { foreach (string argument in arguments) { - _ = requestBuilder.Append(' ').Append(argument); + requestBuilder.AppendFormatted(' '); + requestBuilder.AppendLiteral(argument); } } - using IAdbSocket socket = CreateAdbSocket(); - await socket.SetDeviceAsync(device, cancellationToken).ConfigureAwait(false); - - await socket.SendAdbRequestAsync(requestBuilder.ToString(), cancellationToken).ConfigureAwait(false); + await socket.SendAdbRequestAsync(requestBuilder.ToStringAndClear(), cancellationToken).ConfigureAwait(false); _ = await socket.ReadAdbResponseAsync(cancellationToken).ConfigureAwait(false); using StreamReader reader = new(socket.GetShellStream(), Encoding); @@ -765,24 +779,26 @@ public async Task InstallCreateAsync(DeviceData device, CancellationToke public async Task InstallCreateAsync(DeviceData device, string packageName, CancellationToken cancellationToken = default, params string[] arguments) { EnsureDevice(device); - ExceptionExtensions.ThrowIfNull(packageName); + ArgumentNullException.ThrowIfNull(packageName); + + using IAdbSocket socket = CreateAdbSocket(); + await socket.SetDeviceAsync(device, cancellationToken).ConfigureAwait(false); - StringBuilder requestBuilder = - new StringBuilder("exec:cmd package 'install-create'") - .Append(" -p ").Append(packageName); + DefaultInterpolatedStringHandler requestBuilder = new(37 + packageName.Length, arguments?.Length ?? 0); + requestBuilder.AppendLiteral("exec:cmd package 'install-create'"); + requestBuilder.AppendFormatted(" -p "); + requestBuilder.AppendLiteral(packageName); if (arguments != null) { foreach (string argument in arguments) { - _ = requestBuilder.Append(' ').Append(argument); + requestBuilder.AppendFormatted(' '); + requestBuilder.AppendLiteral(argument); } } - using IAdbSocket socket = CreateAdbSocket(); - await socket.SetDeviceAsync(device, cancellationToken).ConfigureAwait(false); - - await socket.SendAdbRequestAsync(requestBuilder.ToString(), cancellationToken).ConfigureAwait(false); + await socket.SendAdbRequestAsync(requestBuilder.ToStringAndClear(), cancellationToken).ConfigureAwait(false); _ = await socket.ReadAdbResponseAsync(cancellationToken).ConfigureAwait(false); using StreamReader reader = new(socket.GetShellStream(), Encoding); @@ -805,27 +821,19 @@ public virtual async Task InstallWriteAsync(DeviceData device, Stream apk, strin callback?.Invoke(0); EnsureDevice(device); - ExceptionExtensions.ThrowIfNull(apk); - ExceptionExtensions.ThrowIfNull(apkName); - ExceptionExtensions.ThrowIfNull(session); + ArgumentNullException.ThrowIfNull(apk); + ArgumentNullException.ThrowIfNull(apkName); + ArgumentNullException.ThrowIfNull(session); if (!apk.CanRead || !apk.CanSeek) { throw new ArgumentOutOfRangeException(nameof(apk), "The apk stream must be a readable and seekable stream"); } - StringBuilder requestBuilder = - new StringBuilder($"exec:cmd package 'install-write'") - // add size parameter [required for streaming installs] - // do last to override any user specified value - .Append(" -S ").Append(apk.Length) - .Append(' ').Append(session).Append(' ') - .Append(apkName).Append(".apk"); - using IAdbSocket socket = CreateAdbSocket(); await socket.SetDeviceAsync(device, cancellationToken).ConfigureAwait(false); - await socket.SendAdbRequestAsync(requestBuilder.ToString(), cancellationToken).ConfigureAwait(false); + await socket.SendAdbRequestAsync($"exec:cmd package 'install-write' -S {apk.Length} {session} {apkName}.apk", cancellationToken).ConfigureAwait(false); _ = await socket.ReadAdbResponseAsync(cancellationToken).ConfigureAwait(false); byte[] buffer = new byte[32 * 1024]; @@ -836,11 +844,13 @@ public virtual async Task InstallWriteAsync(DeviceData device, Stream apk, strin #if HAS_BUFFERS while ((read = await apk.ReadAsync(buffer, cancellationToken).ConfigureAwait(false)) > 0) - { - await socket.SendAsync(buffer.AsMemory(0, read), cancellationToken).ConfigureAwait(false); #else while ((read = await apk.ReadAsync(buffer, 0, buffer.Length, cancellationToken).ConfigureAwait(false)) > 0) +#endif { +#if COMP_NETSTANDARD2_1 + await socket.SendAsync(buffer.AsMemory(0, read), cancellationToken).ConfigureAwait(false); +#else await socket.SendAsync(buffer, read, cancellationToken).ConfigureAwait(false); #endif totalBytesRead += read; @@ -878,27 +888,19 @@ protected virtual async Task InstallWriteAsync(DeviceData device, Stream apk, st callback?.Invoke(apkName, 0); EnsureDevice(device); - ExceptionExtensions.ThrowIfNull(apk); - ExceptionExtensions.ThrowIfNull(apkName); - ExceptionExtensions.ThrowIfNull(session); + ArgumentNullException.ThrowIfNull(apk); + ArgumentNullException.ThrowIfNull(apkName); + ArgumentNullException.ThrowIfNull(session); if (!apk.CanRead || !apk.CanSeek) { throw new ArgumentOutOfRangeException(nameof(apk), "The apk stream must be a readable and seekable stream"); } - StringBuilder requestBuilder = - new StringBuilder($"exec:cmd package 'install-write'") - // add size parameter [required for streaming installs] - // do last to override any user specified value - .Append(" -S ").Append(apk.Length) - .Append(' ').Append(session).Append(' ') - .Append(apkName).Append(".apk"); - using IAdbSocket socket = CreateAdbSocket(); await socket.SetDeviceAsync(device, cancellationToken).ConfigureAwait(false); - await socket.SendAdbRequestAsync(requestBuilder.ToString(), cancellationToken).ConfigureAwait(false); + await socket.SendAdbRequestAsync($"exec:cmd package 'install-write' -S {apk.Length} {session} {apkName}.apk", cancellationToken).ConfigureAwait(false); _ = await socket.ReadAdbResponseAsync(cancellationToken).ConfigureAwait(false); byte[] buffer = new byte[32 * 1024]; @@ -907,7 +909,7 @@ protected virtual async Task InstallWriteAsync(DeviceData device, Stream apk, st long totalBytesToProcess = apk.Length; long totalBytesRead = 0; -#if HAS_BUFFERS +#if COMP_NETSTANDARD2_1 while ((read = await apk.ReadAsync(buffer, cancellationToken).ConfigureAwait(false)) > 0) { await socket.SendAsync(buffer.AsMemory(0, read), cancellationToken).ConfigureAwait(false); @@ -955,39 +957,39 @@ public async Task InstallCommitAsync(DeviceData device, string session, Cancella #if HAS_WINRT /// -#if NET - [SupportedOSPlatform("Windows10.0.10240.0")] -#endif public virtual async Task InstallAsync(DeviceData device, IRandomAccessStream apk, Action? callback = null, CancellationToken cancellationToken = default, params string[] arguments) { callback?.Invoke(new InstallProgressEventArgs(PackageInstallProgressState.Preparing)); EnsureDevice(device); - ExceptionExtensions.ThrowIfNull(apk); + ArgumentNullException.ThrowIfNull(apk); if (!apk.CanRead) { throw new ArgumentOutOfRangeException(nameof(apk), "The apk stream must be a readable stream"); } - StringBuilder requestBuilder = new("exec:cmd package 'install'"); + using IAdbSocket socket = CreateAdbSocket(); + await socket.SetDeviceAsync(device, cancellationToken).ConfigureAwait(false); + + DefaultInterpolatedStringHandler requestBuilder = new(30, (arguments?.Length ?? 0) + 1); + requestBuilder.AppendLiteral("exec:cmd package 'install'"); if (arguments != null) { foreach (string argument in arguments) { - _ = requestBuilder.Append(' ').Append(argument); + requestBuilder.AppendFormatted(' '); + requestBuilder.AppendLiteral(argument); } } // add size parameter [required for streaming installs] // do last to override any user specified value - _ = requestBuilder.Append($" -S {apk.Size}"); - - using IAdbSocket socket = CreateAdbSocket(); - await socket.SetDeviceAsync(device, cancellationToken).ConfigureAwait(false); + requestBuilder.AppendLiteral(" -S "); + requestBuilder.AppendFormatted(apk.Size); - await socket.SendAdbRequestAsync(requestBuilder.ToString(), cancellationToken).ConfigureAwait(false); + await socket.SendAdbRequestAsync(requestBuilder.ToStringAndClear(), cancellationToken).ConfigureAwait(false); _ = await socket.ReadAdbResponseAsync(cancellationToken).ConfigureAwait(false); byte[] buffer = new byte[32 * 1024]; @@ -1026,16 +1028,13 @@ public virtual async Task InstallAsync(DeviceData device, IRandomAccessStream ap } /// -#if HAS_WINRT && NET - [SupportedOSPlatform("Windows10.0.10240.0")] -#endif public async Task InstallMultipleAsync(DeviceData device, IRandomAccessStream baseAPK, IEnumerable splitAPKs, Action? callback = null, CancellationToken cancellationToken = default, params string[] arguments) { callback?.Invoke(new InstallProgressEventArgs(PackageInstallProgressState.Preparing)); EnsureDevice(device); - ExceptionExtensions.ThrowIfNull(baseAPK); - ExceptionExtensions.ThrowIfNull(splitAPKs); + ArgumentNullException.ThrowIfNull(baseAPK); + ArgumentNullException.ThrowIfNull(splitAPKs); if (!baseAPK.CanRead) { @@ -1082,16 +1081,13 @@ void OnSplitSyncProgressChanged(string? sender, double args) } /// -#if HAS_WINRT && NET - [SupportedOSPlatform("Windows10.0.10240.0")] -#endif public async Task InstallMultipleAsync(DeviceData device, IEnumerable splitAPKs, string packageName, Action? callback = null, CancellationToken cancellationToken = default, params string[] arguments) { callback?.Invoke(new InstallProgressEventArgs(PackageInstallProgressState.Preparing)); EnsureDevice(device); - ExceptionExtensions.ThrowIfNull(splitAPKs); - ExceptionExtensions.ThrowIfNull(packageName); + ArgumentNullException.ThrowIfNull(splitAPKs); + ArgumentNullException.ThrowIfNull(packageName); if (splitAPKs.Any(apk => apk == null || !apk.CanRead)) { @@ -1128,35 +1124,24 @@ void OnSyncProgressChanged(string? sender, double args) } /// -#if NET - [SupportedOSPlatform("Windows10.0.10240.0")] -#endif public virtual async Task InstallWriteAsync(DeviceData device, IRandomAccessStream apk, string apkName, string session, Action? callback = null, CancellationToken cancellationToken = default) { callback?.Invoke(0); EnsureDevice(device); - ExceptionExtensions.ThrowIfNull(apk); - ExceptionExtensions.ThrowIfNull(apkName); - ExceptionExtensions.ThrowIfNull(session); + ArgumentNullException.ThrowIfNull(apk); + ArgumentNullException.ThrowIfNull(apkName); + ArgumentNullException.ThrowIfNull(session); if (!apk.CanRead) { throw new ArgumentOutOfRangeException(nameof(apk), "The apk stream must be a readable stream"); } - StringBuilder requestBuilder = - new StringBuilder($"exec:cmd package 'install-write'") - // add size parameter [required for streaming installs] - // do last to override any user specified value - .Append(" -S ").Append(apk.Size) - .Append(' ').Append(session).Append(' ') - .Append(apkName).Append(".apk"); - using IAdbSocket socket = CreateAdbSocket(); await socket.SetDeviceAsync(device, cancellationToken).ConfigureAwait(false); - await socket.SendAdbRequestAsync(requestBuilder.ToString(), cancellationToken).ConfigureAwait(false); + await socket.SendAdbRequestAsync($"exec:cmd package 'install-write' -S {apk.Size} {session} {apkName}.apk", cancellationToken).ConfigureAwait(false); _ = await socket.ReadAdbResponseAsync(cancellationToken).ConfigureAwait(false); byte[] buffer = new byte[32 * 1024]; @@ -1203,35 +1188,24 @@ public virtual async Task InstallWriteAsync(DeviceData device, IRandomAccessStre /// The progress is reported as a value between 0 and 100, representing the percentage of the apk which has been transferred. /// A which can be used to cancel the asynchronous operation. /// A which represents the asynchronous operation. -#if NET - [SupportedOSPlatform("Windows10.0.10240.0")] -#endif protected virtual async Task InstallWriteAsync(DeviceData device, IRandomAccessStream apk, string apkName, string session, Action? callback, CancellationToken cancellationToken = default) { callback?.Invoke(apkName, 0); EnsureDevice(device); - ExceptionExtensions.ThrowIfNull(apk); - ExceptionExtensions.ThrowIfNull(apkName); - ExceptionExtensions.ThrowIfNull(session); + ArgumentNullException.ThrowIfNull(apk); + ArgumentNullException.ThrowIfNull(apkName); + ArgumentNullException.ThrowIfNull(session); if (!apk.CanRead) { throw new ArgumentOutOfRangeException(nameof(apk), "The apk stream must be a readable stream"); } - StringBuilder requestBuilder = - new StringBuilder($"exec:cmd package 'install-write'") - // add size parameter [required for streaming installs] - // do last to override any user specified value - .Append(" -S ").Append(apk.Size) - .Append(' ').Append(session).Append(' ') - .Append(apkName).Append(".apk"); - using IAdbSocket socket = CreateAdbSocket(); await socket.SetDeviceAsync(device, cancellationToken).ConfigureAwait(false); - await socket.SendAdbRequestAsync(requestBuilder.ToString(), cancellationToken).ConfigureAwait(false); + await socket.SendAdbRequestAsync($"exec:cmd package 'install-write' -S {apk.Size} {session} {apkName}.apk", cancellationToken).ConfigureAwait(false); _ = await socket.ReadAdbResponseAsync(cancellationToken).ConfigureAwait(false); byte[] buffer = new byte[32 * 1024]; @@ -1274,22 +1248,25 @@ public async Task UninstallAsync(DeviceData device, string packageName, Cancella { EnsureDevice(device); - StringBuilder requestBuilder = new("exec:cmd package 'uninstall'"); + using IAdbSocket socket = CreateAdbSocket(); + await socket.SetDeviceAsync(device, cancellationToken).ConfigureAwait(false); + + DefaultInterpolatedStringHandler requestBuilder = new(29, (arguments?.Length ?? 0) + 1); + requestBuilder.AppendLiteral("exec:cmd package 'uninstall'"); if (arguments != null) { foreach (string argument in arguments) { - _ = requestBuilder.Append(' ').Append(argument); + requestBuilder.AppendFormatted(' '); + requestBuilder.AppendLiteral(argument); } } - _ = requestBuilder.Append(' ').Append(packageName); - - using IAdbSocket socket = CreateAdbSocket(); - await socket.SetDeviceAsync(device, cancellationToken).ConfigureAwait(false); + requestBuilder.AppendFormatted(' '); + requestBuilder.AppendLiteral(packageName); - await socket.SendAdbRequestAsync(requestBuilder.ToString(), cancellationToken).ConfigureAwait(false); + await socket.SendAdbRequestAsync(requestBuilder.ToStringAndClear(), cancellationToken).ConfigureAwait(false); _ = await socket.ReadAdbResponseAsync(cancellationToken).ConfigureAwait(false); using StreamReader reader = new(socket.GetShellStream(), Encoding); diff --git a/AdvancedSharpAdbClient/AdbClient.cs b/AdvancedSharpAdbClient/AdbClient.cs index e4b32f6f..b844d7e7 100644 --- a/AdvancedSharpAdbClient/AdbClient.cs +++ b/AdvancedSharpAdbClient/AdbClient.cs @@ -29,7 +29,7 @@ namespace AdvancedSharpAdbClient /// adb_client.c /// adb.c /// - [DebuggerDisplay($"{nameof(AdbClient)} \\{{ {nameof(EndPoint)} = {{{nameof(EndPoint)}}} }}")] + [DebuggerDisplay($"{{{nameof(GetType)}().{nameof(Type.ToString)}(),nq}} \\{{ {nameof(EndPoint)} = {{{nameof(EndPoint)}}} }}")] public partial class AdbClient : IAdbClient, ICloneable, ICloneable #if HAS_WINRT , IAdbClient.IWinRT @@ -89,7 +89,7 @@ public AdbClient(string host, int port) /// The to create . public AdbClient(EndPoint endPoint, Func adbSocketFactory) { - ExceptionExtensions.ThrowIfNull(endPoint); + ArgumentNullException.ThrowIfNull(endPoint); if (endPoint is not (IPEndPoint or DnsEndPoint)) { @@ -177,7 +177,49 @@ public static byte[] CreateAdbForwardRequest(string address, int port) return FormAdbRequest(request); } - /// +#if HAS_BUFFERS + /// + /// Create an ASCII string preceded by four hex digits. The opening "####" + /// is the length of the rest of the string, encoded as ASCII hex(case + /// doesn't matter). + /// + /// The request to form. + /// An array containing ####req. + public static byte[] FormAdbRequest(ReadOnlySpan req) + { + int payloadLength = Encoding.GetByteCount(req); +#if NET10_0_OR_GREATER + DefaultInterpolatedStringHandler resultStr = $"{payloadLength:X4}{req}"; + ReadOnlySpan text = resultStr.Text; + int byteCount = Encoding.GetByteCount(text); + byte[] result = new byte[byteCount]; + _ = Encoding.GetBytes(text, result); +#else + string resultStr = $"{payloadLength:X4}{req}"; + byte[] result = Encoding.GetBytes(resultStr); +#endif + return result; + } + + /// + /// Creates the adb forward request. + /// + /// The address. + /// The port. + /// This returns an array containing "####tcp:{port}:{addStr}". + public static byte[] CreateAdbForwardRequest(ReadOnlySpan address, int port) + { +#if NET10_0_OR_GREATER + DefaultInterpolatedStringHandler request = address.IsEmpty ? (DefaultInterpolatedStringHandler)$"tcp:{port}" : $"tcp:{port}:{address}"; + return FormAdbRequest(request.Text); +#else + string request = address == null ? $"tcp:{port}" : $"tcp:{port}:{address}"; + return FormAdbRequest(request); +#endif + } +#endif + + /// public int GetAdbVersion() { using IAdbSocket socket = CreateAdbSocket(); @@ -330,14 +372,15 @@ public void ExecuteServerCommand(string target, string command) /// public virtual void ExecuteServerCommand(string target, string command, IAdbSocket socket) { - StringBuilder request = new(); - if (!StringExtensions.IsNullOrWhiteSpace(target)) + DefaultInterpolatedStringHandler request = new(1, 2); + if (!string.IsNullOrWhiteSpace(target)) { - _ = request.Append(target).Append(':'); + request.AppendLiteral(target); + request.AppendFormatted(':'); } - _ = request.Append(command); + request.AppendLiteral(command); - socket.SendAdbRequest(request.ToString()); + socket.SendAdbRequest(request); _ = socket.ReadAdbResponse(); try @@ -347,7 +390,7 @@ public virtual void ExecuteServerCommand(string target, string command, IAdbSock // break too soon in certain cases (about every 10 loops, so it appears to be a timing // issue). Checking for reader.ReadLine() to return null appears to be much more robust // -- one of the integration test fetches output 1000 times and found no truncations. - while (reader.ReadLine() != null) ; + while (reader.ReadLine() != null) { } } catch (Exception e) { @@ -369,7 +412,7 @@ public void ExecuteRemoteCommand(string command, DeviceData device) /// public void ExecuteServerCommand(string target, string command, IShellOutputReceiver? receiver, Encoding encoding) { - ExceptionExtensions.ThrowIfNull(encoding); + ArgumentNullException.ThrowIfNull(encoding); using IAdbSocket socket = CreateAdbSocket(); ExecuteServerCommand(target, command, socket, receiver, encoding); } @@ -377,16 +420,17 @@ public void ExecuteServerCommand(string target, string command, IShellOutputRece /// public virtual void ExecuteServerCommand(string target, string command, IAdbSocket socket, IShellOutputReceiver? receiver, Encoding encoding) { - ExceptionExtensions.ThrowIfNull(encoding); + ArgumentNullException.ThrowIfNull(encoding); - StringBuilder request = new(); - if (!StringExtensions.IsNullOrWhiteSpace(target)) + DefaultInterpolatedStringHandler request = new(1, 2); + if (!string.IsNullOrWhiteSpace(target)) { - _ = request.Append(target).Append(':'); + request.AppendLiteral(target); + request.AppendFormatted(':'); } - _ = request.Append(command); + request.AppendLiteral(command); - socket.SendAdbRequest(request.ToString()); + socket.SendAdbRequest(request); _ = socket.ReadAdbResponse(); try @@ -427,7 +471,7 @@ public void ExecuteRemoteCommand(string command, DeviceData device, IShellOutput /// public IEnumerable ExecuteServerEnumerable(string target, string command, Encoding encoding) { - ExceptionExtensions.ThrowIfNull(encoding); + ArgumentNullException.ThrowIfNull(encoding); using IAdbSocket socket = CreateAdbSocket(); foreach (string line in ExecuteServerEnumerable(target, command, socket, encoding)) { @@ -438,16 +482,17 @@ public IEnumerable ExecuteServerEnumerable(string target, string command /// public virtual IEnumerable ExecuteServerEnumerable(string target, string command, IAdbSocket socket, Encoding encoding) { - ExceptionExtensions.ThrowIfNull(encoding); + ArgumentNullException.ThrowIfNull(encoding); - StringBuilder request = new(); - if (!StringExtensions.IsNullOrWhiteSpace(target)) + DefaultInterpolatedStringHandler request = new(1, 2); + if (!string.IsNullOrWhiteSpace(target)) { - _ = request.Append(target).Append(':'); + request.AppendLiteral(target); + request.AppendFormatted(':'); } - _ = request.Append(command); + request.AppendLiteral(command); - socket.SendAdbRequest(request.ToString()); + socket.SendAdbRequest(request); _ = socket.ReadAdbResponse(); using StreamReader reader = new(socket.GetShellStream(), encoding); @@ -495,14 +540,16 @@ public IEnumerable RunLogService(DeviceData device, params LogId[] log using IAdbSocket socket = CreateAdbSocket(); socket.SetDevice(device); - StringBuilder request = new("shell:logcat -B"); + DefaultInterpolatedStringHandler request = new(19, logNames.Length); + request.AppendLiteral("shell:logcat -B"); foreach (LogId logName in logNames) { - _ = request.Append(" -b ").Append(logName.ToString().ToLowerInvariant()); + request.AppendLiteral(" -b "); + request.AppendLiteral(logName.ToString().ToLowerInvariant()); } - socket.SendAdbRequest(request.ToString()); + socket.SendAdbRequest(request); _ = socket.ReadAdbResponse(); using Stream stream = socket.GetShellStream(); @@ -535,21 +582,23 @@ public IEnumerable RunLogService(DeviceData device, params LogId[] log public void RunLogService(DeviceData device, Action messageSink, in bool isCancelled = false, params LogId[] logNames) { EnsureDevice(device); - ExceptionExtensions.ThrowIfNull(messageSink); + ArgumentNullException.ThrowIfNull(messageSink); // The 'log' service has been deprecated, see // https://android.googlesource.com/platform/system/core/+/7aa39a7b199bb9803d3fd47246ee9530b4a96177 using IAdbSocket socket = CreateAdbSocket(); socket.SetDevice(device); - StringBuilder request = new("shell:logcat -B"); + DefaultInterpolatedStringHandler request = new(19, logNames.Length); + request.AppendLiteral("shell:logcat -B"); foreach (LogId logName in logNames) { - _ = request.Append(" -b ").Append(logName.ToString().ToLowerInvariant()); + request.AppendLiteral(" -b "); + request.AppendLiteral(logName.ToString().ToLowerInvariant()); } - socket.SendAdbRequest(request.ToString()); + socket.SendAdbRequest(request); _ = socket.ReadAdbResponse(); using Stream stream = socket.GetShellStream(); @@ -612,7 +661,7 @@ public void Reboot(string into, DeviceData device) /// public string Pair(string host, int port, string code) { - ExceptionExtensions.ThrowIfNull(host); + ArgumentNullException.ThrowIfNull(host); using IAdbSocket socket = CreateAdbSocket(); string address = host.Contains(':') ? host : $"{host}:{port}"; @@ -625,7 +674,7 @@ public string Pair(string host, int port, string code) /// public string Connect(string host, int port = DefaultPort) { - ExceptionExtensions.ThrowIfNull(host); + ArgumentNullException.ThrowIfNull(host); using IAdbSocket socket = CreateAdbSocket(); string address = host.Contains(':') ? host : $"{host}:{port}"; @@ -638,7 +687,7 @@ public string Connect(string host, int port = DefaultPort) /// public string Disconnect(string host, int port = DefaultPort) { - ExceptionExtensions.ThrowIfNull(host); + ArgumentNullException.ThrowIfNull(host); using IAdbSocket socket = CreateAdbSocket(); string address = host.Contains(':') ? host : $"{host}:{port}"; @@ -692,7 +741,7 @@ protected void Root(string request, DeviceData device) #if HAS_PROCESS && !WINDOWS_UWP Thread.Sleep(3000); #else - TaskExExtensions.Delay(3000).AwaitByTaskCompleteSource(); + Task.Delay(3000).AwaitByTaskCompleteSource(); #endif } } @@ -703,31 +752,34 @@ public virtual void Install(DeviceData device, Stream apk, Action 0) - { - socket.Send(buffer.AsSpan(0, read)); #else while ((read = apk.Read(buffer, 0, buffer.Length)) > 0) +#endif { +#if COMP_NETSTANDARD2_1 + socket.Send(buffer.AsSpan(0, read)); +#else socket.Send(buffer, read); #endif totalBytesRead += read; @@ -772,8 +826,8 @@ public void InstallMultiple(DeviceData device, Stream baseAPK, IEnumerable splitAPKs, st callback?.Invoke(new InstallProgressEventArgs(PackageInstallProgressState.Preparing)); EnsureDevice(device); - ExceptionExtensions.ThrowIfNull(splitAPKs); - ExceptionExtensions.ThrowIfNull(packageName); + ArgumentNullException.ThrowIfNull(splitAPKs); + ArgumentNullException.ThrowIfNull(packageName); if (splitAPKs.Any(apk => apk == null || !apk.CanRead || !apk.CanSeek)) { @@ -875,20 +929,22 @@ public string InstallCreate(DeviceData device, params string[] arguments) { EnsureDevice(device); - StringBuilder requestBuilder = new("exec:cmd package 'install-create'"); + using IAdbSocket socket = CreateAdbSocket(); + socket.SetDevice(device); + + DefaultInterpolatedStringHandler requestBuilder = new(33, arguments?.Length ?? 0); + requestBuilder.AppendLiteral("exec:cmd package 'install-create'"); if (arguments != null) { foreach (string argument in arguments) { - _ = requestBuilder.Append(' ').Append(argument); + requestBuilder.AppendFormatted(' '); + requestBuilder.AppendLiteral(argument); } } - using IAdbSocket socket = CreateAdbSocket(); - socket.SetDevice(device); - - socket.SendAdbRequest(requestBuilder.ToString()); + socket.SendAdbRequest(requestBuilder); _ = socket.ReadAdbResponse(); using StreamReader reader = new(socket.GetShellStream(), Encoding); @@ -908,24 +964,26 @@ public string InstallCreate(DeviceData device, params string[] arguments) public string InstallCreate(DeviceData device, string packageName, params string[] arguments) { EnsureDevice(device); - ExceptionExtensions.ThrowIfNull(packageName); + ArgumentNullException.ThrowIfNull(packageName); - StringBuilder requestBuilder = - new StringBuilder("exec:cmd package 'install-create'") - .Append(" -p ").Append(packageName); + using IAdbSocket socket = CreateAdbSocket(); + socket.SetDevice(device); + + DefaultInterpolatedStringHandler requestBuilder = new(37 + packageName.Length, arguments?.Length ?? 0); + requestBuilder.AppendLiteral("exec:cmd package 'install-create'"); + requestBuilder.AppendFormatted(" -p "); + requestBuilder.AppendLiteral(packageName); if (arguments != null) { foreach (string argument in arguments) { - _ = requestBuilder.Append(' ').Append(argument); + requestBuilder.AppendFormatted(' '); + requestBuilder.AppendLiteral(argument); } } - using IAdbSocket socket = CreateAdbSocket(); - socket.SetDevice(device); - - socket.SendAdbRequest(requestBuilder.ToString()); + socket.SendAdbRequest(requestBuilder); _ = socket.ReadAdbResponse(); using StreamReader reader = new(socket.GetShellStream(), Encoding); @@ -947,27 +1005,19 @@ public virtual void InstallWrite(DeviceData device, Stream apk, string apkName, callback?.Invoke(0); EnsureDevice(device); - ExceptionExtensions.ThrowIfNull(apk); - ExceptionExtensions.ThrowIfNull(apkName); - ExceptionExtensions.ThrowIfNull(session); + ArgumentNullException.ThrowIfNull(apk); + ArgumentNullException.ThrowIfNull(apkName); + ArgumentNullException.ThrowIfNull(session); if (!apk.CanRead || !apk.CanSeek) { throw new ArgumentOutOfRangeException(nameof(apk), "The apk stream must be a readable and seekable stream"); } - StringBuilder requestBuilder = - new StringBuilder($"exec:cmd package 'install-write'") - // add size parameter [required for streaming installs] - // do last to override any user specified value - .Append(" -S ").Append(apk.Length) - .Append(' ').Append(session).Append(' ') - .Append(apkName).Append(".apk"); - using IAdbSocket socket = CreateAdbSocket(); socket.SetDevice(device); - socket.SendAdbRequest(requestBuilder.ToString()); + socket.SendAdbRequest($"exec:cmd package 'install-write' -S {apk.Length} {session} {apkName}.apk"); _ = socket.ReadAdbResponse(); byte[] buffer = new byte[32 * 1024]; @@ -978,11 +1028,13 @@ public virtual void InstallWrite(DeviceData device, Stream apk, string apkName, #if HAS_BUFFERS while ((read = apk.Read(buffer)) > 0) - { - socket.Send(buffer.AsSpan(0, read)); #else while ((read = apk.Read(buffer, 0, buffer.Length)) > 0) +#endif { +#if COMP_NETSTANDARD2_1 + socket.Send(buffer.AsSpan(0, read)); +#else socket.Send(buffer, read); #endif totalBytesRead += read; @@ -1017,27 +1069,19 @@ protected virtual void InstallWrite(DeviceData device, Stream apk, string apkNam callback?.Invoke(apkName, 0); EnsureDevice(device); - ExceptionExtensions.ThrowIfNull(apk); - ExceptionExtensions.ThrowIfNull(apkName); - ExceptionExtensions.ThrowIfNull(session); + ArgumentNullException.ThrowIfNull(apk); + ArgumentNullException.ThrowIfNull(apkName); + ArgumentNullException.ThrowIfNull(session); if (!apk.CanRead || !apk.CanSeek) { throw new ArgumentOutOfRangeException(nameof(apk), "The apk stream must be a readable and seekable stream"); } - StringBuilder requestBuilder = - new StringBuilder($"exec:cmd package 'install-write'") - // add size parameter [required for streaming installs] - // do last to override any user specified value - .Append(" -S ").Append(apk.Length) - .Append(' ').Append(session).Append(' ') - .Append(apkName).Append(".apk"); - using IAdbSocket socket = CreateAdbSocket(); socket.SetDevice(device); - socket.SendAdbRequest(requestBuilder.ToString()); + socket.SendAdbRequest($"exec:cmd package 'install-write' -S {apk.Length} {session} {apkName}.apk"); _ = socket.ReadAdbResponse(); byte[] buffer = new byte[32 * 1024]; @@ -1048,11 +1092,13 @@ protected virtual void InstallWrite(DeviceData device, Stream apk, string apkNam #if HAS_BUFFERS while ((read = apk.Read(buffer)) > 0) - { - socket.Send(buffer.AsSpan(0, read)); #else while ((read = apk.Read(buffer, 0, buffer.Length)) > 0) +#endif { +#if COMP_NETSTANDARD2_1 + socket.Send(buffer.AsSpan(0, read)); +#else socket.Send(buffer, read); #endif totalBytesRead += read; @@ -1099,22 +1145,25 @@ public void Uninstall(DeviceData device, string packageName, params string[] arg { EnsureDevice(device); - StringBuilder requestBuilder = new("exec:cmd package 'uninstall'"); + using IAdbSocket socket = CreateAdbSocket(); + socket.SetDevice(device); + + DefaultInterpolatedStringHandler requestBuilder = new(29, (arguments?.Length ?? 0) + 1); + requestBuilder.AppendLiteral("exec:cmd package 'uninstall'"); if (arguments != null) { foreach (string argument in arguments) { - _ = requestBuilder.Append(' ').Append(argument); + requestBuilder.AppendFormatted(' '); + requestBuilder.AppendLiteral(argument); } } - _ = requestBuilder.Append(' ').Append(packageName); - - using IAdbSocket socket = CreateAdbSocket(); - socket.SetDevice(device); + requestBuilder.AppendFormatted(' '); + requestBuilder.AppendLiteral(packageName); - socket.SendAdbRequest(requestBuilder.ToString()); + socket.SendAdbRequest(requestBuilder); _ = socket.ReadAdbResponse(); using StreamReader reader = new(socket.GetShellStream(), Encoding); @@ -1146,7 +1195,7 @@ public IEnumerable GetFeatureSet(DeviceData device) public IAdbSocket CreateAdbSocket() => AdbSocketFactory(EndPoint); /// - public override string ToString() => $"The {nameof(AdbClient)} communicate with adb server at {EndPoint}"; + public override string ToString() => $"The {GetType()} communicate with adb server at '{EndPoint}'."; /// /// Creates a new object that is a copy of the current instance with new . diff --git a/AdvancedSharpAdbClient/AdbCommandLineClient.Async.cs b/AdvancedSharpAdbClient/AdbCommandLineClient.Async.cs index dfda3c9e..e81d0057 100644 --- a/AdvancedSharpAdbClient/AdbCommandLineClient.Async.cs +++ b/AdvancedSharpAdbClient/AdbCommandLineClient.Async.cs @@ -5,11 +5,9 @@ using System; using System.Collections.Generic; -using System.ComponentModel; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.IO; -using System.Security.Cryptography; using System.Threading; namespace AdvancedSharpAdbClient @@ -48,7 +46,7 @@ public virtual async Task> ExecuteAdbCommandAsync(string command, C int status = await RunAdbProcessInnerAsync(command, errorOutput, standardOutput, cancellationToken).ConfigureAwait(false); if (errorOutput.Count > 0) { - string error = StringExtensions.Join(Environment.NewLine, errorOutput!); + string error = string.Join(Environment.NewLine, errorOutput!); throw new AdbException($"The adb process returned error code {status} when running command {command} with error output:{Environment.NewLine}{error}", error); } else @@ -76,14 +74,11 @@ public async Task StartServerAsync(CancellationToken cancellationToken = default } /// -#if HAS_WINRT && NET - [SupportedOSPlatform("Windows10.0.10240.0")] -#endif - public virtual Task CheckAdbFileExistsAsync(string adbPath, CancellationToken cancellationToken = default) => adbPath == "adb" ? TaskExExtensions.FromResult(true) : + public virtual Task CheckAdbFileExistsAsync(string adbPath, CancellationToken cancellationToken = default) => adbPath == "adb" ? Task.FromResult(true) : #if HAS_WINRT StorageFile.GetFileFromPathAsync(Extensions.GetFullPath(adbPath)).AsTask(cancellationToken).ContinueWith(x => x.Result != null && x.Result.IsOfType(StorageItemTypes.File)); #else - TaskExExtensions.FromResult(File.Exists(adbPath)); + Task.FromResult(File.Exists(adbPath)); #endif /// @@ -119,7 +114,7 @@ protected async Task RunAdbProcessAsync(string command, ICollection? err /// Use this command only for adb commands that return immediately, such as adb version. protected async Task RunAdbProcessInnerAsync(string command, ICollection? errorOutput, ICollection? standardOutput, CancellationToken cancellationToken = default) { - ExceptionExtensions.ThrowIfNull(command); + ArgumentNullException.ThrowIfNull(command); return await RunProcessAsync(AdbPath, command, errorOutput, standardOutput, cancellationToken).ConfigureAwait(false); } @@ -145,24 +140,30 @@ protected virtual async Task RunProcessAsync(string filename, string comman CreateNoWindow = true, WindowStyle = ProcessWindowStyle.Hidden, UseShellExecute = false, - RedirectStandardError = true, - RedirectStandardOutput = true + RedirectStandardError = errorOutput != null, + RedirectStandardOutput = standardOutput != null }; using Process process = Process.Start(psi) ?? throw new AdbException($"The adb process could not be started. The process returned null when starting {filename} {command}"); using (CancellationTokenRegistration registration = cancellationToken.Register(process.Kill)) { - string standardErrorString = await process.StandardError.ReadToEndAsync(cancellationToken).ConfigureAwait(false); - string standardOutputString = await process.StandardOutput.ReadToEndAsync(cancellationToken).ConfigureAwait(false); - - errorOutput?.AddRange(standardErrorString.Split(separator, StringSplitOptions.RemoveEmptyEntries)); - standardOutput?.AddRange(standardOutputString.Split(separator, StringSplitOptions.RemoveEmptyEntries)); - } - - if (!process.HasExited) - { - process.Kill(); + if (errorOutput != null) + { + string standardErrorString = await process.StandardError.ReadToEndAsync(cancellationToken).ConfigureAwait(false); + errorOutput.AddRange(standardErrorString.Split(separator, StringSplitOptions.RemoveEmptyEntries)); + } + + if (standardOutput != null) + { + string standardOutputString = await process.StandardOutput.ReadToEndAsync(cancellationToken).ConfigureAwait(false); + standardOutput.AddRange(standardOutputString.Split(separator, StringSplitOptions.RemoveEmptyEntries)); + } + + if (!process.HasExited) + { + await process.WaitForExitAsync(cancellationToken).ConfigureAwait(false); + } } // get the return code from the process diff --git a/AdvancedSharpAdbClient/AdbCommandLineClient.cs b/AdvancedSharpAdbClient/AdbCommandLineClient.cs index 29a5e257..827e47eb 100644 --- a/AdvancedSharpAdbClient/AdbCommandLineClient.cs +++ b/AdvancedSharpAdbClient/AdbCommandLineClient.cs @@ -15,7 +15,7 @@ namespace AdvancedSharpAdbClient /// /// Provides methods for interacting with the adb.exe command line client. /// - [DebuggerDisplay($"{nameof(AdbCommandLineClient)} \\{{ {nameof(AdbPath)} = {{{nameof(AdbPath)}}} }}")] + [DebuggerDisplay($"{{{nameof(GetType)}().{nameof(Type.ToString)}(),nq}} \\{{ {nameof(AdbPath)} = {{{nameof(AdbPath)}}} }}")] public partial class AdbCommandLineClient : IAdbCommandLineClient { #if HAS_PROCESS @@ -36,12 +36,9 @@ public partial class AdbCommandLineClient : IAdbCommandLineClient /// The path to the adb.exe executable. /// Doesn't check adb file when . /// The logger to use when logging. -#if HAS_WINRT && NET - [SupportedOSPlatform("Windows10.0.10240.0")] -#endif public AdbCommandLineClient(string adbPath, bool isForce = false, ILogger? logger = null) { - if (StringExtensions.IsNullOrWhiteSpace(adbPath)) + if (string.IsNullOrWhiteSpace(adbPath)) { throw new ArgumentNullException(nameof(adbPath)); } @@ -114,7 +111,7 @@ public virtual List ExecuteAdbCommand(string command, int timeout = 5000 int status = RunAdbProcessInner(command, errorOutput, standardOutput, timeout); if (errorOutput.Count > 0) { - string error = StringExtensions.Join(Environment.NewLine, errorOutput!); + string error = string.Join(Environment.NewLine, errorOutput!); throw new AdbException($"The adb process returned error code {status} when running command {command} with error output:{Environment.NewLine}{error}", error); } else @@ -126,9 +123,6 @@ public virtual List ExecuteAdbCommand(string command, int timeout = 5000 } /// -#if HAS_WINRT && NET - [SupportedOSPlatform("Windows10.0.10240.0")] -#endif public virtual bool CheckAdbFileExists(string adbPath) => adbPath == "adb" || #if HAS_WINRT (StorageFile.GetFileFromPathAsync(Extensions.GetFullPath(adbPath)).AwaitByTaskCompleteSource() is StorageFile file && file.IsOfType(StorageItemTypes.File)); @@ -137,27 +131,30 @@ public virtual bool CheckAdbFileExists(string adbPath) => adbPath == "adb" || #endif /// - public override string ToString() => $"The {nameof(AdbCommandLineClient)} process with adb command line at {AdbPath}"; + public override string ToString() => $"The {GetType()} process with adb command line at '{AdbPath}'."; /// /// Throws an error if the path does not point to a valid instance of adb.exe. /// /// The path to validate. +#if NET + [SupportedOSPlatformGuard("Windows")] + [SupportedOSPlatformGuard("Linux")] + [SupportedOSPlatformGuard("OSX")] + [SupportedOSPlatformGuard("FreeBSD")] +#endif protected virtual void EnsureIsValidAdbFile(string adbPath) { if (adbPath == "adb") { return; } - bool isWindows = Extensions.IsWindowsPlatform(); - bool isUnix = Extensions.IsUnixPlatform(); - - if (isWindows) + if (OperatingSystem.IsWindows()) { if (!string.Equals(Path.GetFileName(adbPath), "adb.exe", StringComparison.OrdinalIgnoreCase)) { throw new ArgumentOutOfRangeException(nameof(adbPath), $"{adbPath} does not seem to be a valid adb.exe executable. The path must end with `adb.exe`"); } } - else if (isUnix) + else if (OperatingSystem.IsLinux() || OperatingSystem.IsMacOS() || OperatingSystem.IsFreeBSD()) { if (!string.Equals(Path.GetFileName(adbPath), "adb", StringComparison.OrdinalIgnoreCase)) { @@ -166,7 +163,7 @@ protected virtual void EnsureIsValidAdbFile(string adbPath) } else { - throw new NotSupportedException("SharpAdbClient only supports launching adb.exe on Windows, Mac OS and Linux"); + throw new NotSupportedException("SharpAdbClient only supports launching adb on Windows, Mac OS and Linux"); } } @@ -204,7 +201,7 @@ protected void RunAdbProcess(string command, ICollection? errorOutput, I /// adb version. This operation times out after 5 seconds in default. protected int RunAdbProcessInner(string command, ICollection? errorOutput, ICollection? standardOutput, int timeout = 5000) { - ExceptionExtensions.ThrowIfNull(command); + ArgumentNullException.ThrowIfNull(command); return RunProcess(AdbPath, command, errorOutput, standardOutput, timeout); } @@ -265,8 +262,8 @@ protected virtual int RunProcess(string filename, string command, ICollection RestartServerAsync(CancellationToken cancellation /// public Task RestartServerAsync(string adbPath, CancellationToken cancellationToken = default) => - StringExtensions.IsNullOrWhiteSpace(adbPath) ? RestartServerAsync(cancellationToken) : StartServerAsync(adbPath, true, cancellationToken); + string.IsNullOrWhiteSpace(adbPath) ? RestartServerAsync(cancellationToken) : StartServerAsync(adbPath, true, cancellationToken); /// public async Task StopServerAsync(CancellationToken cancellationToken = default) diff --git a/AdvancedSharpAdbClient/AdbServer.cs b/AdvancedSharpAdbClient/AdbServer.cs index d03442f0..cd3fcae3 100644 --- a/AdvancedSharpAdbClient/AdbServer.cs +++ b/AdvancedSharpAdbClient/AdbServer.cs @@ -20,7 +20,7 @@ namespace AdvancedSharpAdbClient /// giant multiplexing loop whose purpose is to orchestrate the exchange of data /// between clients and devices. /// - [DebuggerDisplay($"{nameof(AdbServer)} \\{{ {nameof(EndPoint)} = {{{nameof(EndPoint)}}}, {nameof(CachedAdbPath)} = {{{nameof(CachedAdbPath)}}} }}")] + [DebuggerDisplay($"{{{nameof(GetType)}().{nameof(Type.ToString)}(),nq}} \\{{ {nameof(EndPoint)} = {{{nameof(EndPoint)}}}, {nameof(CachedAdbPath)} = {{{nameof(CachedAdbPath)}}} }}")] public partial class AdbServer : IAdbServer, ICloneable, ICloneable { /// @@ -112,7 +112,7 @@ public AdbServer(IAdbClient adbClient, Func adbSocketFacto /// The to create . public AdbServer(EndPoint endPoint, Func adbSocketFactory, Func adbCommandLineClientFactory) { - ExceptionExtensions.ThrowIfNull(endPoint); + ArgumentNullException.ThrowIfNull(endPoint); if (endPoint is not (IPEndPoint or DnsEndPoint)) { @@ -154,7 +154,7 @@ public AdbServer(Func adbSocketFactory, Func /// if is starting adb server; otherwise, . /// - protected static bool IsStarting { get; set; } = false; + protected static bool IsStarting { get; set; } /// /// The path to the adb server. Cached from calls to . Used when restarting @@ -225,7 +225,7 @@ public StartServerResult StartServer(string adbPath, bool restartServerIfNewer = /// public StartServerResult RestartServer(string adbPath) => - StringExtensions.IsNullOrWhiteSpace(adbPath) ? RestartServer() : StartServer(adbPath, true); + string.IsNullOrWhiteSpace(adbPath) ? RestartServer() : StartServer(adbPath, true); /// public void StopServer() @@ -272,7 +272,7 @@ public AdbServerStatus GetStatus() public IAdbSocket CreateAdbSocket() => AdbSocketFactory(EndPoint); /// - public override string ToString() => $"The {nameof(AdbServer)} communicate with adb at {EndPoint}"; + public override string ToString() => $"The {GetType()} communicate with adb at '{EndPoint}'."; /// /// Creates a new object that is a copy of the current instance with new . diff --git a/AdvancedSharpAdbClient/AdbSocket.Async.cs b/AdvancedSharpAdbClient/AdbSocket.Async.cs index 367516e5..307f3372 100644 --- a/AdvancedSharpAdbClient/AdbSocket.Async.cs +++ b/AdvancedSharpAdbClient/AdbSocket.Async.cs @@ -85,7 +85,7 @@ public Task SendSyncRequestAsync(SyncCommand command, string path, UnixFileStatu /// public async Task SendSyncRequestAsync(SyncCommand command, string path, CancellationToken cancellationToken = default) { - ExceptionExtensions.ThrowIfNull(path); + ArgumentNullException.ThrowIfNull(path); byte[] pathBytes = AdbClient.Encoding.GetBytes(path); await SendSyncRequestAsync(command, pathBytes.Length, cancellationToken).ConfigureAwait(false); _ = await WriteAsync(pathBytes, cancellationToken).ConfigureAwait(false); @@ -124,28 +124,20 @@ public async Task SendAdbRequestAsync(string request, CancellationToken cancella /// public virtual Task ReadAsync(byte[] data, CancellationToken cancellationToken = default) => -#if HAS_BUFFERS - ReadAsync(data.AsMemory(), cancellationToken).AsTask(); -#else ReadAsync(data, 0, data.Length, cancellationToken); -#endif /// public virtual Task ReadAsync(byte[] data, int length, CancellationToken cancellationToken = default) => -#if HAS_BUFFERS - ReadAsync(data.AsMemory(0, length), cancellationToken).AsTask(); -#else ReadAsync(data, 0, length, cancellationToken); -#endif /// public virtual async Task ReadAsync(byte[] data, int offset, int length, CancellationToken cancellationToken = default) { - ExceptionExtensions.ThrowIfNull(data); - ExceptionExtensions.ThrowIfNegative(offset); + ArgumentNullException.ThrowIfNull(data); + ArgumentOutOfRangeException.ThrowIfNegative(offset); length = length != -1 ? length : data.Length; - ExceptionExtensions.ThrowIfLessThan(data.Length, length, nameof(data)); + ArgumentOutOfRangeException.ThrowIfLessThan(data.Length, length, nameof(data)); int count = -1; int totalRead = offset; @@ -260,7 +252,7 @@ public async Task SetDeviceAsync(DeviceData device, CancellationToken cancellati { // if the device is not null, then we first tell adb we're looking to talk // to a specific device - if (device != null) + if (!device.IsEmpty) { await (uint.TryParse(device.TransportId, out uint tid) ? SendAdbRequestAsync($"host:transport-id:{tid}", cancellationToken).ConfigureAwait(false) @@ -284,7 +276,7 @@ public async Task SetDeviceAsync(DeviceData device, CancellationToken cancellati } } -#if HAS_BUFFERS +#if COMP_NETSTANDARD2_1 /// public virtual async ValueTask SendAsync(ReadOnlyMemory data, CancellationToken cancellationToken = default) { @@ -306,8 +298,6 @@ public virtual async ValueTask SendAsync(ReadOnlyMemory data, Cancellation /// public virtual async ValueTask ReadAsync(Memory data, CancellationToken cancellationToken = default) { - ExceptionExtensions.ThrowIfNull(data); - int count = -1; int totalRead = 0; int length = data.Length; @@ -369,7 +359,7 @@ protected virtual async Task WriteAsync(byte[] data, CancellationToken can return true; } -#if HAS_BUFFERS +#if COMP_NETSTANDARD2_1 /// /// Asynchronously write until all data in "data" is written or the connection fails or times out. /// diff --git a/AdvancedSharpAdbClient/AdbSocket.cs b/AdvancedSharpAdbClient/AdbSocket.cs index 2cd6368b..8bc9e7eb 100644 --- a/AdvancedSharpAdbClient/AdbSocket.cs +++ b/AdvancedSharpAdbClient/AdbSocket.cs @@ -8,6 +8,7 @@ using System.IO; using System.Net; using System.Net.Sockets; +using System.Runtime.CompilerServices; using System.Text; namespace AdvancedSharpAdbClient @@ -24,7 +25,7 @@ namespace AdvancedSharpAdbClient /// /// The at which the Android Debug Bridge is listening for clients. /// The logger to use when logging. - [DebuggerDisplay($"{nameof(AdbSocket)} \\{{ {nameof(Connected)} = {{{nameof(Connected)}}}, {nameof(Socket)} = {{{nameof(Socket)}}} }}")] + [DebuggerDisplay($"{{{nameof(GetType)}().{nameof(Type.ToString)}(),nq}} \\{{ {nameof(Connected)} = {{{nameof(Connected)}}}, {nameof(Socket)} = {{{nameof(Socket)}}} }}")] public partial class AdbSocket(ITcpSocket socket, ILogger? logger = null) : IAdbSocket, ICloneable, ICloneable { /// @@ -160,7 +161,7 @@ public void SendSyncRequest(SyncCommand command, string path, UnixFileStatus per /// public void SendSyncRequest(SyncCommand command, string path) { - ExceptionExtensions.ThrowIfNull(path); + ArgumentNullException.ThrowIfNull(path); byte[] pathBytes = AdbClient.Encoding.GetBytes(path); SendSyncRequest(command, pathBytes.Length); _ = Write(pathBytes); @@ -197,30 +198,32 @@ public void SendAdbRequest(string request) } } +#if NET10_0_OR_GREATER /// - public virtual int Read(byte[] data) => -#if HAS_BUFFERS - Read(data.AsSpan()); -#else - Read(data, 0, data.Length); + public void SendAdbRequest(DefaultInterpolatedStringHandler request) + { + byte[] data = AdbClient.FormAdbRequest(request.Text); + if (!Write(data)) + { + throw new IOException($"Failed sending the request '{request.Text}' to ADB"); + } + } #endif /// - public virtual int Read(byte[] data, int length) => -#if HAS_BUFFERS - Read(data.AsSpan(0, length)); -#else - Read(data, 0, length); -#endif + public virtual int Read(byte[] data) => Read(data, 0, data.Length); + + /// + public virtual int Read(byte[] data, int length) => Read(data, 0, length); /// public virtual int Read(byte[] data, int offset, int length) { - ExceptionExtensions.ThrowIfNull(data); - ExceptionExtensions.ThrowIfNegative(offset); + ArgumentNullException.ThrowIfNull(data); + ArgumentOutOfRangeException.ThrowIfNegative(offset); length = length != -1 ? length : data.Length; - ExceptionExtensions.ThrowIfLessThan(data.Length, length, nameof(data)); + ArgumentOutOfRangeException.ThrowIfLessThan(data.Length, length, nameof(data)); int count = -1; int totalRead = offset; @@ -328,7 +331,7 @@ public AdbResponse ReadAdbResponse() return response; } -#if HAS_BUFFERS +#if COMP_NETSTANDARD2_1 /// public virtual void Send(ReadOnlySpan data) { @@ -399,7 +402,7 @@ public void SetDevice(DeviceData device) { // if the device is not null, then we first tell adb we're looking to talk // to a specific device - if (device != null) + if (!device.IsEmpty) { if (uint.TryParse(device.TransportId, out uint tid)) { @@ -449,7 +452,7 @@ protected virtual bool Write(byte[] data) return true; } -#if HAS_BUFFERS +#if COMP_NETSTANDARD2_1 /// /// Write until all data in "data" is written or the connection fails or times out. /// @@ -554,14 +557,7 @@ public void Dispose() } /// - public override string ToString() => - new StringBuilder(nameof(AdbSocket)) - .Append(" { ") - .Append(nameof(Socket)) - .Append(" = ") - .Append(Socket) - .Append(" }") - .ToString(); + public override string ToString() => $"{GetType()} {{ {nameof(Socket)} = {Socket} }}"; /// public void Close() => Socket.Dispose(); diff --git a/AdvancedSharpAdbClient/AdvancedSharpAdbClient.csproj b/AdvancedSharpAdbClient/AdvancedSharpAdbClient.csproj index c289f372..a9081e18 100644 --- a/AdvancedSharpAdbClient/AdvancedSharpAdbClient.csproj +++ b/AdvancedSharpAdbClient/AdvancedSharpAdbClient.csproj @@ -1,36 +1,27 @@  + False True True Enable Icon.png README.md + False - - - - $(AssemblyName).Standard - netstandard1.3;netstandard2.0;netstandard2.1;net6.0 - $(TargetFrameworks);net2.0;net4.5 - - - - - $(NoWarn);NU1603;NU1605;NU1902;NU1903 - net6.0;net8.0;net9.0;netcoreapp2.1;netcoreapp3.1;netstandard1.3;netstandard2.0;netstandard2.1 - $(TargetFrameworks);net2.0;net3.5-client;net4.0-client;net4.5;net4.6.1;net4.8;net8.0-windows10.0.17763.0;net9.0-windows10.0.17763.0 - $(TargetFrameworks);netcore5.0;uap10.0;uap10.0.15138.0 - - - - - net8.0;netcoreapp3.1;netstandard1.3;netstandard2.0;netstandard2.1 - $(TargetFrameworks);net2.0;net3.5-client;net4.5;net4.8;net8.0-windows10.0.17763.0 - - - + + $(NoWarn);NU1903 + net8.0;net10.0;netstandard1.3;netstandard2.0;netstandard2.1 + $(TargetFrameworks);net2.0;net3.5-client;net4.5;net4.8;net8.0-windows10.0.17763.0;net10.0-windows10.0.17763.0 + + + + $(NoWarn);NU1603;NU1605;NU1902 + $(TargetFrameworks);net6.0;netcoreapp2.1;netcoreapp3.1 + $(TargetFrameworks);net4.0-client;net4.6.1 + $(TargetFrameworks);netcore5.0;uap10.0;uap10.0.15138.0 + @@ -61,6 +52,7 @@ True + 10.0.10240.0 @@ -115,10 +107,18 @@ + + $(DefineConstants);COMP_NETSTANDARD2_0 + + $(DefineConstants);COMP_NETSTANDARD2_1 + + True + + True @@ -150,7 +150,7 @@ $(DefineConstants);HAS_VALUETUPLE diff --git a/AdvancedSharpAdbClient/DeviceCommands/DeviceClient.Async.cs b/AdvancedSharpAdbClient/DeviceCommands/DeviceClient.Async.cs index 257e3273..9a647a44 100644 --- a/AdvancedSharpAdbClient/DeviceCommands/DeviceClient.Async.cs +++ b/AdvancedSharpAdbClient/DeviceCommands/DeviceClient.Async.cs @@ -65,9 +65,6 @@ public async Task DumpScreenStringAsync(CancellationToken cancellationTo /// /// A which can be used to cancel the asynchronous operation. /// A which returns a containing current hierarchy. -#if NET - [SupportedOSPlatform("Windows10.0.10240.0")] -#endif public async Task DumpScreenWinRTAsync(CancellationToken cancellationToken = default) { string xmlString = await DumpScreenStringAsync(cancellationToken).ConfigureAwait(false); @@ -473,7 +470,7 @@ public async Task SendTextAsync(string text, CancellationToken cancellationToken public async Task ClearInputAsync(int charCount, CancellationToken cancellationToken = default) { await SendKeyEventAsync("KEYCODE_MOVE_END", cancellationToken).ConfigureAwait(false); - await SendKeyEventAsync(StringExtensions.Join(" ", Enumerable.Repeat("KEYCODE_DEL", charCount)), cancellationToken).ConfigureAwait(false); + await SendKeyEventAsync(string.Join(" ", Enumerable.Repeat("KEYCODE_DEL", charCount)), cancellationToken).ConfigureAwait(false); } /// diff --git a/AdvancedSharpAdbClient/DeviceCommands/DeviceClient.cs b/AdvancedSharpAdbClient/DeviceCommands/DeviceClient.cs index f2831735..ddc4a75b 100644 --- a/AdvancedSharpAdbClient/DeviceCommands/DeviceClient.cs +++ b/AdvancedSharpAdbClient/DeviceCommands/DeviceClient.cs @@ -21,33 +21,23 @@ namespace AdvancedSharpAdbClient.DeviceCommands [DebuggerDisplay($"{{{nameof(ToString)}(),nq}}")] public partial record class DeviceClient(IAdbClient AdbClient, DeviceData Device) : ICloneable, ICloneable { - /// - /// The to use when communicating with the device. - /// - private IAdbClient adbClient = AdbClient ?? throw new ArgumentNullException(nameof(AdbClient)); - - /// - /// The device on which to process command. - /// - private DeviceData device = DeviceData.EnsureDevice(ref Device); - /// /// Gets the to use when communicating with the device. /// public IAdbClient AdbClient { - get => adbClient; - init => adbClient = value ?? throw new ArgumentNullException(nameof(AdbClient)); - } + get; + init => field = value ?? throw new ArgumentNullException(nameof(AdbClient)); + } = AdbClient ?? throw new ArgumentNullException(nameof(AdbClient)); /// /// Gets the device on which to process command. /// public DeviceData Device { - get => device; - init => device = DeviceData.EnsureDevice(ref value); - } + get; + init => field = DeviceData.EnsureDevice(value); + } = DeviceData.EnsureDevice(Device); /// /// Gets the current device screen snapshot. @@ -95,9 +85,6 @@ public string DumpScreenString() /// Gets the current device screen snapshot. /// /// A containing current hierarchy. -#if NET - [SupportedOSPlatform("Windows10.0.10240.0")] -#endif public Windows.Data.Xml.Dom.XmlDocument? DumpScreenWinRT() { Windows.Data.Xml.Dom.XmlDocument doc = new(); @@ -409,7 +396,7 @@ public void SendText(string text) public void ClearInput(int charCount) { SendKeyEvent("KEYCODE_MOVE_END"); - SendKeyEvent(StringExtensions.Join(" ", Enumerable.Repeat("KEYCODE_DEL", charCount))); + SendKeyEvent(string.Join(" ", Enumerable.Repeat("KEYCODE_DEL", charCount))); } /// @@ -451,14 +438,14 @@ public void Deconstruct(out IAdbClient client, out DeviceData device) /// object ICloneable.Clone() => ((ICloneable)this).Clone(); -#if !NET40_OR_GREATER && !NETCOREAPP2_0_OR_GREATER && !NETSTANDARD2_0_OR_GREATER && !UAP10_0_15138_0 +#if !NET40_OR_GREATER && !COMP_NETSTANDARD2_0 /// public override int GetHashCode() => HashCode.Combine(EqualityContract, AdbClient, Device); /// public virtual bool Equals(DeviceClient? other) => - (object?)this == other || - (other != (object?)null + (object)this == other || + (other is not null && EqualityComparer.Default.Equals(EqualityContract, other.EqualityContract) && EqualityComparer.Default.Equals(AdbClient, other.AdbClient) && EqualityComparer.Default.Equals(Device, other.Device)); diff --git a/AdvancedSharpAdbClient/DeviceCommands/DeviceExtensions.Async.cs b/AdvancedSharpAdbClient/DeviceCommands/DeviceExtensions.Async.cs index 601674d4..87942535 100644 --- a/AdvancedSharpAdbClient/DeviceCommands/DeviceExtensions.Async.cs +++ b/AdvancedSharpAdbClient/DeviceCommands/DeviceExtensions.Async.cs @@ -353,9 +353,6 @@ public static async Task> GetEnvironmentVariablesAsyn /// A which can be used to cancel the asynchronous operation. /// The arguments to pass to adb install. /// A which represents the asynchronous operation. -#if HAS_WINRT && NET - [SupportedOSPlatform("Windows10.0.10240.0")] -#endif public static Task InstallPackageAsync(this IAdbClient client, DeviceData device, string packageFilePath, Action? callback = null, CancellationToken cancellationToken = default, params string[] arguments) { PackageManager manager = new(client, device, skipInit: true); @@ -374,9 +371,6 @@ public static Task InstallPackageAsync(this IAdbClient client, DeviceData device /// A which can be used to cancel the asynchronous operation. /// The arguments to pass to pm install-create. /// A which represents the asynchronous operation. -#if HAS_WINRT && NET - [SupportedOSPlatform("Windows10.0.10240.0")] -#endif public static Task InstallMultiplePackageAsync(this IAdbClient client, DeviceData device, string basePackageFilePath, IEnumerable splitPackageFilePaths, Action? callback = null, CancellationToken cancellationToken = default, params string[] arguments) { PackageManager manager = new(client, device, skipInit: true); @@ -395,9 +389,6 @@ public static Task InstallMultiplePackageAsync(this IAdbClient client, DeviceDat /// A which can be used to cancel the asynchronous operation. /// The arguments to pass to pm install-create. /// A which represents the asynchronous operation. -#if HAS_WINRT && NET - [SupportedOSPlatform("Windows10.0.10240.0")] -#endif public static Task InstallMultiplePackageAsync(this IAdbClient client, DeviceData device, IEnumerable splitPackageFilePaths, string packageName, Action? callback = null, CancellationToken cancellationToken = default, params string[] arguments) { PackageManager manager = new(client, device, skipInit: true); @@ -456,9 +447,6 @@ public static async Task PushAsync(this IAdbClient client, DeviceData device, /// A which can be used to cancel the asynchronous operation. /// The arguments to pass to adb install. /// A which represents the asynchronous operation. -#if HAS_WINRT && NET - [SupportedOSPlatform("Windows10.0.10240.0")] -#endif public static Task InstallPackageAsync(this IAdbClient client, DeviceData device, string packageFilePath, IProgress? progress = null, CancellationToken cancellationToken = default, params string[] arguments) { PackageManager manager = new(client, device, skipInit: true); @@ -477,9 +465,6 @@ public static Task InstallPackageAsync(this IAdbClient client, DeviceData device /// A which can be used to cancel the asynchronous operation. /// The arguments to pass to pm install-create. /// A which represents the asynchronous operation. -#if HAS_WINRT && NET - [SupportedOSPlatform("Windows10.0.10240.0")] -#endif public static Task InstallMultiplePackageAsync(this IAdbClient client, DeviceData device, string basePackageFilePath, IEnumerable splitPackageFilePaths, IProgress? progress = null, CancellationToken cancellationToken = default, params string[] arguments) { PackageManager manager = new(client, device, skipInit: true); @@ -498,9 +483,6 @@ public static Task InstallMultiplePackageAsync(this IAdbClient client, DeviceDat /// A which can be used to cancel the asynchronous operation. /// The arguments to pass to pm install-create. /// A which represents the asynchronous operation. -#if HAS_WINRT && NET - [SupportedOSPlatform("Windows10.0.10240.0")] -#endif public static Task InstallMultiplePackageAsync(this IAdbClient client, DeviceData device, IEnumerable splitPackageFilePaths, string packageName, IProgress? progress = null, CancellationToken cancellationToken = default, params string[] arguments) { PackageManager manager = new(client, device, skipInit: true); diff --git a/AdvancedSharpAdbClient/DeviceCommands/DeviceExtensions.cs b/AdvancedSharpAdbClient/DeviceCommands/DeviceExtensions.cs index 0a1ab7e5..362e805b 100644 --- a/AdvancedSharpAdbClient/DeviceCommands/DeviceExtensions.cs +++ b/AdvancedSharpAdbClient/DeviceCommands/DeviceExtensions.cs @@ -7,7 +7,7 @@ using System.Drawing; using System.IO; using System.Linq; -using System.Text; +using System.Runtime.CompilerServices; using System.Xml; namespace AdvancedSharpAdbClient.DeviceCommands @@ -290,9 +290,6 @@ public static Dictionary GetEnvironmentVariables(this IAdbClient /// An optional parameter which, when specified, returns progress notifications. /// The progress is reported as , representing the state of installation. /// The arguments to pass to adb install. -#if HAS_WINRT && NET - [SupportedOSPlatform("Windows10.0.10240.0")] -#endif public static void InstallPackage(this IAdbClient client, DeviceData device, string packageFilePath, Action? callback = null, params string[] arguments) { PackageManager manager = new(client, device, skipInit: true); @@ -309,9 +306,6 @@ public static void InstallPackage(this IAdbClient client, DeviceData device, str /// An optional parameter which, when specified, returns progress notifications. /// The progress is reported as , representing the state of installation. /// The arguments to pass to pm install-create. -#if HAS_WINRT && NET - [SupportedOSPlatform("Windows10.0.10240.0")] -#endif public static void InstallMultiplePackage(this IAdbClient client, DeviceData device, string basePackageFilePath, IEnumerable splitPackageFilePaths, Action? callback = null, params string[] arguments) { PackageManager manager = new(client, device, skipInit: true); @@ -328,9 +322,6 @@ public static void InstallMultiplePackage(this IAdbClient client, DeviceData dev /// An optional parameter which, when specified, returns progress notifications. /// The progress is reported as , representing the state of installation. /// The arguments to pass to pm install-create. -#if HAS_WINRT && NET - [SupportedOSPlatform("Windows10.0.10240.0")] -#endif public static void InstallMultiplePackage(this IAdbClient client, DeviceData device, IEnumerable splitPackageFilePaths, string packageName, Action? callback = null, params string[] arguments) { PackageManager manager = new(client, device, skipInit: true); @@ -386,9 +377,6 @@ public static void Push(this IAdbClient client, DeviceData device, /// An optional parameter which, when specified, returns progress notifications. /// The progress is reported as , representing the state of installation. /// The arguments to pass to adb install. -#if HAS_WINRT && NET - [SupportedOSPlatform("Windows10.0.10240.0")] -#endif public static void InstallPackage(this IAdbClient client, DeviceData device, string packageFilePath, IProgress? progress = null, params string[] arguments) { PackageManager manager = new(client, device, skipInit: true); @@ -405,9 +393,6 @@ public static void InstallPackage(this IAdbClient client, DeviceData device, str /// An optional parameter which, when specified, returns progress notifications. /// The progress is reported as , representing the state of installation. /// The arguments to pass to pm install-create. -#if HAS_WINRT && NET - [SupportedOSPlatform("Windows10.0.10240.0")] -#endif public static void InstallMultiplePackage(this IAdbClient client, DeviceData device, string basePackageFilePath, IEnumerable splitPackageFilePaths, IProgress? progress = null, params string[] arguments) { PackageManager manager = new(client, device, skipInit: true); @@ -424,9 +409,6 @@ public static void InstallMultiplePackage(this IAdbClient client, DeviceData dev /// An optional parameter which, when specified, returns progress notifications. /// The progress is reported as , representing the state of installation. /// The arguments to pass to pm install-create. -#if HAS_WINRT && NET - [SupportedOSPlatform("Windows10.0.10240.0")] -#endif public static void InstallMultiplePackage(this IAdbClient client, DeviceData device, IEnumerable splitPackageFilePaths, string packageName, IProgress? progress = null, params string[] arguments) { PackageManager manager = new(client, device, skipInit: true); @@ -567,19 +549,23 @@ public static List ListProcesses(this IAdbClient client, DeviceD // Doing cat on each file one by one takes too much time. Doing cat on all of them at the same time doesn't work // either, because the command line would be too long. // So we do it 25 processes at at time. - StringBuilder catBuilder = new(); + DefaultInterpolatedStringHandler catBuilder = new(3, pids.Count); ProcessOutputReceiver processOutputReceiver = new(); - _ = catBuilder.Append("cat"); + catBuilder.AppendLiteral("cat"); for (int i = 0; i < pids.Count; i++) { - _ = catBuilder.Append(" /proc/").Append(pids[i]).Append("/cmdline /proc/").Append(pids[i]).Append("/stat"); + catBuilder.AppendLiteral(" /proc/"); + catBuilder.AppendFormatted(pids[i]); + catBuilder.AppendLiteral("/cmdline /proc/"); + catBuilder.AppendFormatted(pids[i]); + catBuilder.AppendLiteral("/stat"); if (i > 0 && (i % 25 == 0 || i == pids.Count - 1)) { - client.ExecuteShellCommand(device, catBuilder.ToString(), processOutputReceiver); - _ = catBuilder.Clear().Append("cat"); + client.ExecuteShellCommand(device, catBuilder.ToStringAndClear(), processOutputReceiver); + catBuilder.AppendLiteral("cat"); } } diff --git a/AdvancedSharpAdbClient/DeviceCommands/LinuxPath.cs b/AdvancedSharpAdbClient/DeviceCommands/LinuxPath.cs index 1368f40f..08b85f85 100644 --- a/AdvancedSharpAdbClient/DeviceCommands/LinuxPath.cs +++ b/AdvancedSharpAdbClient/DeviceCommands/LinuxPath.cs @@ -38,7 +38,7 @@ public static partial class LinuxPath /// The combined path. public static string Combine(params string[] paths) { - ExceptionExtensions.ThrowIfNull(paths); + ArgumentNullException.ThrowIfNull(paths); int capacity = 0; int num2 = 0; @@ -208,7 +208,7 @@ public static bool IsPathRooted(string path) /// The path. internal static void CheckInvalidPathChars(string path) { - ExceptionExtensions.ThrowIfNull(path); + ArgumentNullException.ThrowIfNull(path); if (path.ToCharArray().Any(c => c < 0x20 || InvalidCharacters.Contains(c))) { diff --git a/AdvancedSharpAdbClient/DeviceCommands/Models/AndroidProcess.cs b/AdvancedSharpAdbClient/DeviceCommands/Models/AndroidProcess.cs index 578ce726..ff7c96b5 100644 --- a/AdvancedSharpAdbClient/DeviceCommands/Models/AndroidProcess.cs +++ b/AdvancedSharpAdbClient/DeviceCommands/Models/AndroidProcess.cs @@ -19,7 +19,7 @@ public readonly struct AndroidProcess /// Because stat does not contain the full process name, this can be useful. public AndroidProcess(string line, bool cmdLinePrefix = false) { - ExceptionExtensions.ThrowIfNull(line); + ArgumentNullException.ThrowIfNull(line); // See http://man7.org/linux/man-pages/man5/proc.5.html, // section /proc/[pid]/stat, for more information about the file format diff --git a/AdvancedSharpAdbClient/DeviceCommands/Models/Element.cs b/AdvancedSharpAdbClient/DeviceCommands/Models/Element.cs index 86c9e4f0..979338ed 100644 --- a/AdvancedSharpAdbClient/DeviceCommands/Models/Element.cs +++ b/AdvancedSharpAdbClient/DeviceCommands/Models/Element.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Generic; +using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Drawing; using System.Linq; @@ -15,6 +16,7 @@ namespace AdvancedSharpAdbClient.DeviceCommands.Models /// /// Implement of screen element, likes Selenium. /// + [DebuggerDisplay($"{{{nameof(GetType)}().{nameof(Type.ToString)}(),nq}} \\{{ {nameof(Bounds)} = {{{nameof(Bounds)}}}, {nameof(Class)} = {{{nameof(Class)}}}, {nameof(Text)} = {{{nameof(Text)}}}, {nameof(Package)} = {{{nameof(Package)}}}, {nameof(Device)} = {{{nameof(Device)}}} }}")] public class Element : IEquatable { /// @@ -90,15 +92,12 @@ static IEnumerable FindElements(IAdbClient client, DeviceData device, X /// The current ADB client that manages the connection. /// The current device containing the element. /// The of the element. -#if NET - [SupportedOSPlatform("Windows10.0.10240.0")] -#endif public Element(IAdbClient client, DeviceData device, Windows.Data.Xml.Dom.IXmlNode xmlNode) { Client = client; Device = device; - ExceptionExtensions.ThrowIfNull(xmlNode); + ArgumentNullException.ThrowIfNull(xmlNode); XmlDocument doc = new(); doc.LoadXml(xmlNode.GetXml()); Node = doc.FirstChild; @@ -219,9 +218,6 @@ static IEnumerable FindElements(IAdbClient client, DeviceData device, W /// The current device containing the element. /// The of the element. /// The new that this method creates. -#if NET - [SupportedOSPlatform("Windows10.0.10240.0")] -#endif public static Element? FromIXmlNode(IAdbClient client, DeviceData device, Windows.Data.Xml.Dom.IXmlNode xmlNode) => xmlNode.Attributes?.GetNamedItem("bounds") != null ? new Element(client, device, xmlNode) : null; #endif @@ -431,7 +427,7 @@ public IEnumerable FindDescendants() /// public bool Equals([NotNullWhen(true)] Element? other) => (object?)this == other || - (other != (object?)null + (other is not null && EqualityComparer.Default.Equals(Client, other.Client) && EqualityComparer.Default.Equals(Device, other.Device) && (Node == null @@ -445,17 +441,17 @@ public bool Equals([NotNullWhen(true)] Element? other) => /// /// Tests whether two objects are equally. /// - /// The structure that is to the left of the equality operator. - /// The structure that is to the right of the equality operator. - /// This operator returns if the two structures are equally; otherwise . + /// The class that is to the left of the equality operator. + /// The class that is to the right of the equality operator. + /// This operator returns if the two class are equally; otherwise . public static bool operator ==(Element? left, Element? right) => (object?)left == right || (left?.Equals(right) ?? false); /// /// Tests whether two objects are different. /// - /// The structure that is to the left of the inequality operator. - /// The structure that is to the right of the inequality operator. - /// This operator returns if the two structures are unequally; otherwise . + /// The class that is to the left of the inequality operator. + /// The class that is to the right of the inequality operator. + /// This operator returns if the two class are unequally; otherwise . public static bool operator !=(Element? left, Element? right) => !(left == right); /// diff --git a/AdvancedSharpAdbClient/DeviceCommands/Models/NamespaceDoc.cs b/AdvancedSharpAdbClient/DeviceCommands/Models/NamespaceDoc.cs index 948e7f20..0626e449 100644 --- a/AdvancedSharpAdbClient/DeviceCommands/Models/NamespaceDoc.cs +++ b/AdvancedSharpAdbClient/DeviceCommands/Models/NamespaceDoc.cs @@ -13,5 +13,11 @@ namespace AdvancedSharpAdbClient.DeviceCommands.Models /// Copyright (c) The Android Open Source Project, Ryan Conrad, Quamotion, yungd1plomat, wherewhere. All rights reserved. [CompilerGenerated] [EditorBrowsable(EditorBrowsableState.Never)] - internal abstract class NamespaceDoc : AdvancedSharpAdbClient.Models.NamespaceDoc; + internal abstract class NamespaceDoc : AdvancedSharpAdbClient.Models.NamespaceDoc + { + /// + /// The name of the namespace . + /// + public new const string Name = $"{DeviceCommands.NamespaceDoc.Name}.{nameof(Models)}"; + } } diff --git a/AdvancedSharpAdbClient/DeviceCommands/Models/VersionInfo.cs b/AdvancedSharpAdbClient/DeviceCommands/Models/VersionInfo.cs index abdeeba8..d0a35105 100644 --- a/AdvancedSharpAdbClient/DeviceCommands/Models/VersionInfo.cs +++ b/AdvancedSharpAdbClient/DeviceCommands/Models/VersionInfo.cs @@ -70,9 +70,6 @@ public readonly bool TryAsVersion(out Version? version) /// /// The object. /// if the was successfully parsed; otherwise, . -#if NET - [SupportedOSPlatform("Windows10.0.10240.0")] -#endif public readonly bool TryAsPackageVersion(out PackageVersion version) { ushort[] numbs = GetVersionNumbers(VersionName).Split('.', StringSplitOptions.RemoveEmptyEntries).Select(ushort.Parse).Take(4).ToArray(); diff --git a/AdvancedSharpAdbClient/DeviceCommands/NamespaceDoc.cs b/AdvancedSharpAdbClient/DeviceCommands/NamespaceDoc.cs index 8ac288c0..8e5f4ec0 100644 --- a/AdvancedSharpAdbClient/DeviceCommands/NamespaceDoc.cs +++ b/AdvancedSharpAdbClient/DeviceCommands/NamespaceDoc.cs @@ -3,7 +3,6 @@ // using System.ComponentModel; -using System.Runtime.CompilerServices; namespace AdvancedSharpAdbClient.DeviceCommands { @@ -11,7 +10,12 @@ namespace AdvancedSharpAdbClient.DeviceCommands /// The classes in this namespace provide Device Commands of adb. /// /// Copyright (c) The Android Open Source Project, Ryan Conrad, Quamotion, yungd1plomat, wherewhere. All rights reserved. - [CompilerGenerated] [EditorBrowsable(EditorBrowsableState.Never)] - internal abstract class NamespaceDoc : AdvancedSharpAdbClient.NamespaceDoc; + internal abstract class NamespaceDoc : AdvancedSharpAdbClient.NamespaceDoc + { + /// + /// The name of the namespace . + /// + public new const string Name = $"{AdvancedSharpAdbClient.NamespaceDoc.Name}.{nameof(DeviceCommands)}"; + } } diff --git a/AdvancedSharpAdbClient/DeviceCommands/PackageManager.Async.cs b/AdvancedSharpAdbClient/DeviceCommands/PackageManager.Async.cs index 9f950c2a..5268df13 100644 --- a/AdvancedSharpAdbClient/DeviceCommands/PackageManager.Async.cs +++ b/AdvancedSharpAdbClient/DeviceCommands/PackageManager.Async.cs @@ -7,7 +7,7 @@ using System.Collections.Generic; using System.IO; using System.Linq; -using System.Text; +using System.Runtime.CompilerServices; using System.Threading; namespace AdvancedSharpAdbClient.DeviceCommands @@ -23,17 +23,19 @@ public Task RefreshPackagesAsync(CancellationToken cancellationToken = default) { ValidateDevice(); - StringBuilder requestBuilder = new(ListFull); + DefaultInterpolatedStringHandler requestBuilder = new(19, Arguments?.Length ?? 0); + requestBuilder.AppendLiteral(ListFull); if (Arguments != null) { foreach (string argument in Arguments) { - _ = requestBuilder.Append(' ').Append(argument); + requestBuilder.AppendFormatted(' '); + requestBuilder.AppendLiteral(argument); } } - string cmd = requestBuilder.ToString(); + string cmd = requestBuilder.ToStringAndClear(); PackageManagerReceiver pmr = new(this); return AdbClient.ExecuteShellCommandAsync(Device, cmd, pmr, cancellationToken); } @@ -47,9 +49,6 @@ public Task RefreshPackagesAsync(CancellationToken cancellationToken = default) /// A which can be used to cancel the asynchronous operation. /// The arguments to pass to adb install. /// A which represents the asynchronous operation. -#if HAS_WINRT && NET - [SupportedOSPlatform("Windows10.0.10240.0")] -#endif public async Task InstallPackageAsync(string packageFilePath, Action? callback = null, CancellationToken cancellationToken = default, params string[] arguments) { callback?.Invoke(new InstallProgressEventArgs(PackageInstallProgressState.Preparing)); @@ -85,19 +84,23 @@ public async Task InstallRemotePackageAsync(string remoteFilePath, ActionA which can be used to cancel the asynchronous operation. /// The arguments to pass to pm install-create. /// A which represents the asynchronous operation. -#if HAS_WINRT && NET - [SupportedOSPlatform("Windows10.0.10240.0")] -#endif public async Task InstallMultiplePackageAsync(string basePackageFilePath, IEnumerable splitPackageFilePaths, Action? callback = null, CancellationToken cancellationToken = default, params string[] arguments) { callback?.Invoke(new InstallProgressEventArgs(PackageInstallProgressState.Preparing)); @@ -195,9 +195,6 @@ await splitRemoteFilePaths.Select(async x => /// A which can be used to cancel the asynchronous operation. /// The arguments to pass to pm install-create. /// A which represents the asynchronous operation. -#if HAS_WINRT && NET - [SupportedOSPlatform("Windows10.0.10240.0")] -#endif public async Task InstallMultiplePackageAsync(IEnumerable splitPackageFilePaths, string packageName, Action? callback = null, CancellationToken cancellationToken = default, params string[] arguments) { callback?.Invoke(new InstallProgressEventArgs(PackageInstallProgressState.Preparing)); @@ -359,9 +356,6 @@ await splitRemoteFilePaths.Select(async (splitRemoteFilePath, index) => /// A which can be used to cancel the asynchronous operation. /// The arguments to pass to adb install. /// A which represents the asynchronous operation. -#if HAS_WINRT && NET - [SupportedOSPlatform("Windows10.0.10240.0")] -#endif public async Task InstallPackageAsync(string packageFilePath, IProgress? progress = null, CancellationToken cancellationToken = default, params string[] arguments) => await InstallPackageAsync(packageFilePath, progress.AsAction(), cancellationToken, arguments).ConfigureAwait(false); @@ -387,9 +381,6 @@ public async Task InstallRemotePackageAsync(string remoteFilePath, IProgressA which can be used to cancel the asynchronous operation. /// The arguments to pass to pm install-create. /// A which represents the asynchronous operation. -#if HAS_WINRT && NET - [SupportedOSPlatform("Windows10.0.10240.0")] -#endif public async Task InstallMultiplePackageAsync(string basePackageFilePath, IEnumerable splitPackageFilePaths, IProgress? progress = null, CancellationToken cancellationToken = default, params string[] arguments) => await InstallMultiplePackageAsync(basePackageFilePath, splitPackageFilePaths, progress.AsAction(), cancellationToken, arguments).ConfigureAwait(false); @@ -403,9 +394,6 @@ public async Task InstallMultiplePackageAsync(string basePackageFilePath, IEnume /// A which can be used to cancel the asynchronous operation. /// The arguments to pass to pm install-create. /// A which represents the asynchronous operation. -#if HAS_WINRT && NET - [SupportedOSPlatform("Windows10.0.10240.0")] -#endif public async Task InstallMultiplePackageAsync(IEnumerable splitPackageFilePaths, string packageName, IProgress? progress = null, CancellationToken cancellationToken = default, params string[] arguments) => await InstallMultiplePackageAsync(splitPackageFilePaths, packageName, progress.AsAction(), cancellationToken, arguments).ConfigureAwait(false); @@ -456,19 +444,22 @@ public async Task UninstallPackageAsync(string packageName, CancellationToken ca { ValidateDevice(); - StringBuilder requestBuilder = new("pm uninstall"); + DefaultInterpolatedStringHandler requestBuilder = new(13, (arguments?.Length ?? 0) + 1); + requestBuilder.AppendLiteral("pm uninstall"); if (arguments != null) { foreach (string argument in arguments) { - _ = requestBuilder.Append(' ').Append(argument); + requestBuilder.AppendFormatted(' '); + requestBuilder.AppendFormatted(argument); } } - _ = requestBuilder.Append(' ').Append(packageName); + requestBuilder.AppendFormatted(' '); + requestBuilder.AppendLiteral(packageName); - string cmd = requestBuilder.ToString(); + string cmd = requestBuilder.ToStringAndClear(); InstallOutputReceiver receiver = new(); await AdbClient.ExecuteShellCommandAsync(Device, cmd, receiver, cancellationToken).ConfigureAwait(false); if (!string.IsNullOrEmpty(receiver.ErrorMessage)) @@ -503,22 +494,25 @@ protected async Task CreateInstallSessionAsync(string? packageName = nul { ValidateDevice(); - StringBuilder requestBuilder = new("pm install-create"); + DefaultInterpolatedStringHandler requestBuilder = new(21, (arguments?.Length ?? 0) + 1); + requestBuilder.AppendLiteral("pm install-create"); - if (!StringExtensions.IsNullOrWhiteSpace(packageName)) + if (!string.IsNullOrWhiteSpace(packageName)) { - _ = requestBuilder.Append(" -p ").Append(packageName); + requestBuilder.AppendLiteral(" -p "); + requestBuilder.AppendLiteral(packageName!); } if (arguments != null) { foreach (string argument in arguments) { - _ = requestBuilder.Append(' ').Append(argument); + requestBuilder.AppendFormatted(' '); + requestBuilder.AppendFormatted(argument); } } - string cmd = requestBuilder.ToString(); + string cmd = requestBuilder.ToStringAndClear(); InstallOutputReceiver receiver = new(); await AdbClient.ExecuteShellCommandAsync(Device, cmd, receiver, cancellationToken).ConfigureAwait(false); @@ -561,14 +555,11 @@ protected async Task WriteInstallSessionAsync(string session, string apkName, st /// The file to be opened for reading. /// A which can be used to cancel the asynchronous operation. /// A which returns a read-only on the specified path. -#if HAS_WINRT && NET - [SupportedOSPlatform("Windows10.0.10240.0")] -#endif protected virtual Task GetFileStreamAsync(string path, CancellationToken cancellationToken = default) => #if HAS_WINRT StorageFile.GetFileFromPathAsync(Extensions.GetFullPath(path)).AsTask(cancellationToken).ContinueWith(x => x.Result.OpenStreamForReadAsync()).Unwrap(); #else - TaskExExtensions.FromResult(File.OpenRead(path)); + Task.FromResult(File.OpenRead(path)); #endif /// @@ -579,9 +570,6 @@ protected virtual Task GetFileStreamAsync(string path, CancellationToken /// A which can be used to cancel the asynchronous operation. /// A which returns the destination path on device for file. /// If fatal error occurred when pushing file. -#if HAS_WINRT && NET - [SupportedOSPlatform("Windows10.0.10240.0")] -#endif protected virtual async Task SyncPackageToDeviceAsync(string localFilePath, Action? callback, CancellationToken cancellationToken = default) { callback?.Invoke(localFilePath, new SyncProgressChangedEventArgs(0, 100)); diff --git a/AdvancedSharpAdbClient/DeviceCommands/PackageManager.cs b/AdvancedSharpAdbClient/DeviceCommands/PackageManager.cs index 34a6cb8c..97328bcc 100644 --- a/AdvancedSharpAdbClient/DeviceCommands/PackageManager.cs +++ b/AdvancedSharpAdbClient/DeviceCommands/PackageManager.cs @@ -7,7 +7,7 @@ using System.Diagnostics; using System.IO; using System.Linq; -using System.Text; +using System.Runtime.CompilerServices; namespace AdvancedSharpAdbClient.DeviceCommands { @@ -64,7 +64,7 @@ public PackageManager(IAdbClient client, DeviceData device, params string[] argu public PackageManager(IAdbClient client, DeviceData device, Func? syncServiceFactory = null, bool skipInit = false, ILogger? logger = null, params string[] arguments) { AdbClient = client ?? throw new ArgumentNullException(nameof(client)); - Device = DeviceData.EnsureDevice(ref device); + Device = DeviceData.EnsureDevice(device); Packages = []; Arguments = arguments; @@ -131,17 +131,19 @@ public void RefreshPackages() { ValidateDevice(); - StringBuilder requestBuilder = new(ListFull); + DefaultInterpolatedStringHandler requestBuilder = new(19, Arguments?.Length ?? 0); + requestBuilder.AppendLiteral(ListFull); if (Arguments != null) { foreach (string argument in Arguments) { - _ = requestBuilder.Append(' ').Append(argument); + requestBuilder.AppendFormatted(' '); + requestBuilder.AppendLiteral(argument); } } - string cmd = requestBuilder.ToString(); + string cmd = requestBuilder.ToStringAndClear(); PackageManagerReceiver pmr = new(this); AdbClient.ExecuteShellCommand(Device, cmd, pmr); } @@ -153,9 +155,6 @@ public void RefreshPackages() /// An optional parameter which, when specified, returns progress notifications. /// The progress is reported as , representing the state of installation. /// The arguments to pass to adb install. -#if HAS_WINRT && NET - [SupportedOSPlatform("Windows10.0.10240.0")] -#endif public void InstallPackage(string packageFilePath, Action? callback = null, params string[] arguments) { callback?.Invoke(new InstallProgressEventArgs(PackageInstallProgressState.Preparing)); @@ -189,19 +188,23 @@ public void InstallRemotePackage(string remoteFilePath, ActionAn optional parameter which, when specified, returns progress notifications. /// The progress is reported as , representing the state of installation. /// The arguments to pass to pm install-create. -#if HAS_WINRT && NET - [SupportedOSPlatform("Windows10.0.10240.0")] -#endif public void InstallMultiplePackage(string basePackageFilePath, IEnumerable splitPackageFilePaths, Action? callback = null, params string[] arguments) { callback?.Invoke(new InstallProgressEventArgs(PackageInstallProgressState.Preparing)); @@ -284,9 +284,6 @@ void OnSplitSyncProgressChanged(string? sender, SyncProgressChangedEventArgs arg /// An optional parameter which, when specified, returns progress notifications. /// The progress is reported as , representing the state of installation. /// The arguments to pass to pm install-create. -#if HAS_WINRT && NET - [SupportedOSPlatform("Windows10.0.10240.0")] -#endif public void InstallMultiplePackage(IEnumerable splitPackageFilePaths, string packageName, Action? callback = null, params string[] arguments) { callback?.Invoke(new InstallProgressEventArgs(PackageInstallProgressState.Preparing)); @@ -421,9 +418,6 @@ public void InstallMultipleRemotePackage(IEnumerable splitRemoteFilePath /// An optional parameter which, when specified, returns progress notifications. /// The progress is reported as , representing the state of installation. /// The arguments to pass to adb install. -#if HAS_WINRT && NET - [SupportedOSPlatform("Windows10.0.10240.0")] -#endif public void InstallPackage(string packageFilePath, IProgress? progress = null, params string[] arguments) => InstallPackage(packageFilePath, progress.AsAction(), arguments); @@ -445,9 +439,6 @@ public void InstallRemotePackage(string remoteFilePath, IProgressAn optional parameter which, when specified, returns progress notifications. /// The progress is reported as , representing the state of installation. /// The arguments to pass to pm install-create. -#if HAS_WINRT && NET - [SupportedOSPlatform("Windows10.0.10240.0")] -#endif public void InstallMultiplePackage(string basePackageFilePath, IEnumerable splitPackageFilePaths, IProgress? progress = null, params string[] arguments) => InstallMultiplePackage(basePackageFilePath, splitPackageFilePaths, progress.AsAction(), arguments); @@ -459,9 +450,6 @@ public void InstallMultiplePackage(string basePackageFilePath, IEnumerableAn optional parameter which, when specified, returns progress notifications. /// The progress is reported as , representing the state of installation. /// The arguments to pass to pm install-create. -#if HAS_WINRT && NET - [SupportedOSPlatform("Windows10.0.10240.0")] -#endif public void InstallMultiplePackage(IEnumerable splitPackageFilePaths, string packageName, IProgress? progress = null, params string[] arguments) => InstallMultiplePackage(splitPackageFilePaths, packageName, progress.AsAction(), arguments); @@ -497,19 +485,22 @@ public void UninstallPackage(string packageName, params string[] arguments) { ValidateDevice(); - StringBuilder requestBuilder = new("pm uninstall"); + DefaultInterpolatedStringHandler requestBuilder = new(13, (arguments?.Length ?? 0) + 1); + requestBuilder.AppendLiteral("pm uninstall"); if (arguments != null) { foreach (string argument in arguments) { - _ = requestBuilder.Append(' ').Append(argument); + requestBuilder.AppendFormatted(' '); + requestBuilder.AppendFormatted(argument); } } - _ = requestBuilder.Append(' ').Append(packageName); + requestBuilder.AppendFormatted(' '); + requestBuilder.AppendLiteral(packageName); - string cmd = requestBuilder.ToString(); + string cmd = requestBuilder.ToStringAndClear(); InstallOutputReceiver receiver = new(); AdbClient.ExecuteShellCommand(Device, cmd, receiver); if (!string.IsNullOrEmpty(receiver.ErrorMessage)) @@ -533,18 +524,7 @@ public VersionInfo GetVersionInfo(string packageName) } /// - public override string ToString() => - new StringBuilder(nameof(PackageManager)) - .Append(" { ") - .Append(nameof(Device)) - .Append(" = ") - .Append(Device) - .Append(", ") - .Append(nameof(AdbClient)) - .Append(" = ") - .Append(AdbClient) - .Append(" }") - .ToString(); + public override string ToString() => $"{GetType()} {{ {nameof(Device)} = {Device}, {nameof(AdbClient)} = {AdbClient} }}"; /// /// Like "install", but starts an install session. @@ -556,22 +536,25 @@ protected string CreateInstallSession(string? packageName = null, params string[ { ValidateDevice(); - StringBuilder requestBuilder = new("pm install-create"); + DefaultInterpolatedStringHandler requestBuilder = new(21, (arguments?.Length ?? 0) + 1); + requestBuilder.AppendLiteral("pm install-create"); - if (!StringExtensions.IsNullOrWhiteSpace(packageName)) + if (!string.IsNullOrWhiteSpace(packageName)) { - _ = requestBuilder.Append(" -p ").Append(packageName); + requestBuilder.AppendLiteral(" -p "); + requestBuilder.AppendLiteral(packageName!); } if (arguments != null) { foreach (string argument in arguments) { - _ = requestBuilder.Append(' ').Append(argument); + requestBuilder.AppendFormatted(' '); + requestBuilder.AppendFormatted(argument); } } - string cmd = requestBuilder.ToString(); + string cmd = requestBuilder.ToStringAndClear(); InstallOutputReceiver receiver = new(); AdbClient.ExecuteShellCommand(Device, cmd, receiver); @@ -611,9 +594,6 @@ protected void WriteInstallSession(string session, string apkName, string path) /// /// The file to be opened for reading. /// A read-only on the specified path. -#if HAS_WINRT && NET - [SupportedOSPlatform("Windows10.0.10240.0")] -#endif protected virtual Stream GetFileStream(string path) => #if HAS_WINRT StorageFile.GetFileFromPathAsync(Extensions.GetFullPath(path)).AwaitByTaskCompleteSource().OpenStreamForReadAsync().AwaitByTaskCompleteSource(); @@ -628,9 +608,6 @@ protected virtual Stream GetFileStream(string path) => /// An optional parameter which, when specified, returns progress notifications. /// Destination path on device for file. /// If fatal error occurred when pushing file. -#if HAS_WINRT && NET - [SupportedOSPlatform("Windows10.0.10240.0")] -#endif protected virtual string SyncPackageToDevice(string localFilePath, Action? callback) { callback?.Invoke(localFilePath, new SyncProgressChangedEventArgs(0, 100)); diff --git a/AdvancedSharpAdbClient/DeviceCommands/Receivers/EnvironmentVariablesReceiver.cs b/AdvancedSharpAdbClient/DeviceCommands/Receivers/EnvironmentVariablesReceiver.cs index 280211c0..694311b7 100644 --- a/AdvancedSharpAdbClient/DeviceCommands/Receivers/EnvironmentVariablesReceiver.cs +++ b/AdvancedSharpAdbClient/DeviceCommands/Receivers/EnvironmentVariablesReceiver.cs @@ -2,6 +2,7 @@ // Copyright (c) The Android Open Source Project, Ryan Conrad, Quamotion, yungd1plomat, wherewhere. All rights reserved. // +using System; using System.Collections.Generic; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; @@ -12,7 +13,7 @@ namespace AdvancedSharpAdbClient.DeviceCommands.Receivers /// /// Processes the output of the printenv command, which dumps all environment variables of an Android device. /// - [DebuggerDisplay($"{nameof(EnvironmentVariablesReceiver)} \\{{ {nameof(EnvironmentVariables)} = {{{nameof(EnvironmentVariables)}}} }}")] + [DebuggerDisplay($"{{{nameof(GetType)}().{nameof(Type.ToString)}(),nq}} \\{{ {nameof(EnvironmentVariables)} = {{{nameof(EnvironmentVariables)}}} }}")] public sealed partial class EnvironmentVariablesReceiver : ShellOutputReceiver { /// diff --git a/AdvancedSharpAdbClient/DeviceCommands/Receivers/GetPropReceiver.cs b/AdvancedSharpAdbClient/DeviceCommands/Receivers/GetPropReceiver.cs index 0484bac7..1cc3ec26 100644 --- a/AdvancedSharpAdbClient/DeviceCommands/Receivers/GetPropReceiver.cs +++ b/AdvancedSharpAdbClient/DeviceCommands/Receivers/GetPropReceiver.cs @@ -2,6 +2,7 @@ // Copyright (c) The Android Open Source Project, Ryan Conrad, Quamotion, yungd1plomat, wherewhere. All rights reserved. // +using System; using System.Collections.Generic; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; @@ -12,7 +13,7 @@ namespace AdvancedSharpAdbClient.DeviceCommands.Receivers /// /// Parses the output of the getprop command, which lists all properties of an Android device. /// - [DebuggerDisplay($"{nameof(GetPropReceiver)} \\{{ {nameof(Properties)} = {{{nameof(Properties)}}} }}")] + [DebuggerDisplay($"{{{nameof(GetType)}().{nameof(Type.ToString)}(),nq}} \\{{ {nameof(Properties)} = {{{nameof(Properties)}}} }}")] public sealed partial class GetPropReceiver : ShellOutputReceiver { /// diff --git a/AdvancedSharpAdbClient/DeviceCommands/Receivers/InfoOutputReceiver.cs b/AdvancedSharpAdbClient/DeviceCommands/Receivers/InfoOutputReceiver.cs index 49a5a2cf..21fbeeca 100644 --- a/AdvancedSharpAdbClient/DeviceCommands/Receivers/InfoOutputReceiver.cs +++ b/AdvancedSharpAdbClient/DeviceCommands/Receivers/InfoOutputReceiver.cs @@ -12,7 +12,7 @@ namespace AdvancedSharpAdbClient.DeviceCommands.Receivers /// /// Processes command line output of a adb shell command. /// - [DebuggerDisplay($"{nameof(InfoOutputReceiver)} \\{{ {nameof(Properties)} = {{{nameof(Properties)}}}, {nameof(PropertyParsers)} = {{{nameof(PropertyParsers)}}} }}")] + [DebuggerDisplay($"{{{nameof(GetType)}().{nameof(Type.ToString)}(),nq}} \\{{ {nameof(Properties)} = {{{nameof(Properties)}}}, {nameof(PropertyParsers)} = {{{nameof(PropertyParsers)}}} }}")] public class InfoOutputReceiver : ShellOutputReceiver { /// diff --git a/AdvancedSharpAdbClient/DeviceCommands/Receivers/InstallOutputReceiver.cs b/AdvancedSharpAdbClient/DeviceCommands/Receivers/InstallOutputReceiver.cs index 3e0078c9..d6ad99f5 100644 --- a/AdvancedSharpAdbClient/DeviceCommands/Receivers/InstallOutputReceiver.cs +++ b/AdvancedSharpAdbClient/DeviceCommands/Receivers/InstallOutputReceiver.cs @@ -2,6 +2,7 @@ // Copyright (c) The Android Open Source Project, Ryan Conrad, Quamotion, yungd1plomat, wherewhere. All rights reserved. // +using System; using System.Diagnostics; using System.Text.RegularExpressions; @@ -10,7 +11,7 @@ namespace AdvancedSharpAdbClient.DeviceCommands.Receivers /// /// Processes output of the pm install command. /// - [DebuggerDisplay($"{nameof(InstallOutputReceiver)} \\{{ {nameof(Success)} = {{{nameof(Success)}}}, {nameof(SuccessMessage)} = {{{nameof(SuccessMessage)}}}, {nameof(ErrorMessage)} = {{{nameof(ErrorMessage)}}} }}")] + [DebuggerDisplay($"{{{nameof(GetType)}().{nameof(Type.ToString)}(),nq}} \\{{ {nameof(Success)} = {{{nameof(Success)}}}, {nameof(SuccessMessage)} = {{{nameof(SuccessMessage)}}}, {nameof(ErrorMessage)} = {{{nameof(ErrorMessage)}}} }}")] public partial class InstallOutputReceiver : ShellOutputReceiver { /// @@ -99,7 +100,7 @@ public override bool AddOutput(string line) if (m.Success) { string msg = m.Groups[1].Value; - ErrorMessage = StringExtensions.IsNullOrWhiteSpace(msg) ? UnknownError : msg; + ErrorMessage = string.IsNullOrWhiteSpace(msg) ? UnknownError : msg; } Success = false; @@ -116,7 +117,7 @@ public override bool AddOutput(string line) if (m.Success) { string msg = m.Groups[1].Value; - ErrorMessage = StringExtensions.IsNullOrWhiteSpace(msg) ? UnknownError : msg; + ErrorMessage = string.IsNullOrWhiteSpace(msg) ? UnknownError : msg; } Success = false; diff --git a/AdvancedSharpAdbClient/DeviceCommands/Receivers/NamespaceDoc.cs b/AdvancedSharpAdbClient/DeviceCommands/Receivers/NamespaceDoc.cs index c0a6f632..b36210a3 100644 --- a/AdvancedSharpAdbClient/DeviceCommands/Receivers/NamespaceDoc.cs +++ b/AdvancedSharpAdbClient/DeviceCommands/Receivers/NamespaceDoc.cs @@ -3,7 +3,6 @@ // using System.ComponentModel; -using System.Runtime.CompilerServices; namespace AdvancedSharpAdbClient.DeviceCommands.Receivers { @@ -11,7 +10,12 @@ namespace AdvancedSharpAdbClient.DeviceCommands.Receivers /// The classes in this namespace provide receivers for . /// /// Copyright (c) The Android Open Source Project, Ryan Conrad, Quamotion, yungd1plomat, wherewhere. All rights reserved. - [CompilerGenerated] [EditorBrowsable(EditorBrowsableState.Never)] - internal abstract class NamespaceDoc : AdvancedSharpAdbClient.Receivers.NamespaceDoc; + internal abstract class NamespaceDoc : AdvancedSharpAdbClient.Receivers.NamespaceDoc + { + /// + /// The name of the namespace . + /// + public new const string Name = $"{DeviceCommands.NamespaceDoc.Name}.{nameof(Receivers)}"; + } } diff --git a/AdvancedSharpAdbClient/DeviceCommands/Receivers/PackageManagerReceiver.cs b/AdvancedSharpAdbClient/DeviceCommands/Receivers/PackageManagerReceiver.cs index cdd6ac49..bec2d03f 100644 --- a/AdvancedSharpAdbClient/DeviceCommands/Receivers/PackageManagerReceiver.cs +++ b/AdvancedSharpAdbClient/DeviceCommands/Receivers/PackageManagerReceiver.cs @@ -2,6 +2,7 @@ // Copyright (c) The Android Open Source Project, Ryan Conrad, Quamotion, yungd1plomat, wherewhere. All rights reserved. // +using System; using System.Collections.Generic; using System.Diagnostics; @@ -11,7 +12,7 @@ namespace AdvancedSharpAdbClient.DeviceCommands.Receivers /// Parses the output of the various pm commands. /// /// The parent package manager. - [DebuggerDisplay($"{nameof(PackageManagerReceiver)} \\{{ {nameof(PackageManager)} = {{{nameof(PackageManager)}}} }}")] + [DebuggerDisplay($"{{{nameof(GetType)}().{nameof(Type.ToString)}(),nq}} \\{{ {nameof(PackageManager)} = {{{nameof(PackageManager)}}} }}")] public class PackageManagerReceiver(PackageManager packageManager) : MultiLineReceiver { /// @@ -31,7 +32,7 @@ protected override void ProcessNewLines(params IEnumerable lines) foreach (string line in lines) { - if (line != null && line.StartsWith("package:")) + if (line?.StartsWith("package:") == true) { // Samples include: // package:/system/app/LegacyCamera.apk=com.android.camera diff --git a/AdvancedSharpAdbClient/DeviceCommands/Receivers/ProcessOutputReceiver.cs b/AdvancedSharpAdbClient/DeviceCommands/Receivers/ProcessOutputReceiver.cs index fb97a753..f757179d 100644 --- a/AdvancedSharpAdbClient/DeviceCommands/Receivers/ProcessOutputReceiver.cs +++ b/AdvancedSharpAdbClient/DeviceCommands/Receivers/ProcessOutputReceiver.cs @@ -2,6 +2,7 @@ // Copyright (c) The Android Open Source Project, Ryan Conrad, Quamotion, yungd1plomat, wherewhere. All rights reserved. // +using System; using System.Collections.Generic; using System.Diagnostics; @@ -10,7 +11,7 @@ namespace AdvancedSharpAdbClient.DeviceCommands.Receivers /// /// Parses the output of a cat /proc/[pid]/stat command. /// - [DebuggerDisplay($"{nameof(ProcessOutputReceiver)} \\{{ {nameof(Processes)} = {{{nameof(Processes)}}} }}")] + [DebuggerDisplay($"{{{nameof(GetType)}().{nameof(Type.ToString)}(),nq}} \\{{ {nameof(Processes)} = {{{nameof(Processes)}}} }}")] public class ProcessOutputReceiver : ShellOutputReceiver { /// diff --git a/AdvancedSharpAdbClient/DeviceCommands/Receivers/VersionInfoReceiver.cs b/AdvancedSharpAdbClient/DeviceCommands/Receivers/VersionInfoReceiver.cs index 15d5920d..fd78f2b4 100644 --- a/AdvancedSharpAdbClient/DeviceCommands/Receivers/VersionInfoReceiver.cs +++ b/AdvancedSharpAdbClient/DeviceCommands/Receivers/VersionInfoReceiver.cs @@ -11,7 +11,7 @@ namespace AdvancedSharpAdbClient.DeviceCommands.Receivers /// /// Processes command line output of the dumpsys package command. /// - [DebuggerDisplay($"{nameof(VersionInfoReceiver)} \\{{ {nameof(VersionInfo)} = {{{nameof(VersionInfo)}}} }}")] + [DebuggerDisplay($"{{{nameof(GetType)}().{nameof(Type.ToString)}(),nq}} \\{{ {nameof(VersionInfo)} = {{{nameof(VersionInfo)}}} }}")] public partial class VersionInfoReceiver : InfoOutputReceiver { /// @@ -67,7 +67,7 @@ private void CheckPackagesSection(string line) // We check whether the line is indented. If it's not, and it's not an empty line, we take it is // a section header line and update the data accordingly. - if (StringExtensions.IsNullOrWhiteSpace(line)) + if (string.IsNullOrWhiteSpace(line)) { return; } diff --git a/AdvancedSharpAdbClient/DeviceMonitor.Async.cs b/AdvancedSharpAdbClient/DeviceMonitor.Async.cs index 9520f9b5..82467c95 100644 --- a/AdvancedSharpAdbClient/DeviceMonitor.Async.cs +++ b/AdvancedSharpAdbClient/DeviceMonitor.Async.cs @@ -19,11 +19,7 @@ public partial class DeviceMonitor /// is used to block the method until the /// has processed the first list of devices. /// -#if NET protected TaskCompletionSource? FirstDeviceListParsed; -#else - protected TaskCompletionSource? FirstDeviceListParsed; -#endif /// /// A that can be used to cancel the . @@ -137,15 +133,7 @@ protected virtual async Task DeviceMonitorLoopAsync(CancellationToken cancellati if (FirstDeviceListParsed != null) { // Switch to the background thread to avoid blocking the caller. - _ = Task.Factory.StartNew( -#if NET - () => FirstDeviceListParsed?.TrySetResult(), -#else - () => FirstDeviceListParsed?.TrySetResult(null), -#endif - default, - TaskCreationOptions.None, - TaskScheduler.Default); + _ = Task.Run(FirstDeviceListParsed.TrySetResult); } } catch (TaskCanceledException ex) @@ -272,7 +260,7 @@ private async Task InitializeSocketAsync(CancellationToken cancellationToken) public void GetResult() { } /// - public void OnCompleted(Action continuation) => _ = Task.Factory.StartNew(continuation, default, TaskCreationOptions.None, TaskScheduler.Default); + public void OnCompleted(Action continuation) => _ = Task.Run(continuation, default); } } } diff --git a/AdvancedSharpAdbClient/DeviceMonitor.cs b/AdvancedSharpAdbClient/DeviceMonitor.cs index 44a228e9..bb629fb3 100644 --- a/AdvancedSharpAdbClient/DeviceMonitor.cs +++ b/AdvancedSharpAdbClient/DeviceMonitor.cs @@ -10,7 +10,6 @@ using System.Linq; using System.Net; using System.Net.Sockets; -using System.Text; using System.Threading; namespace AdvancedSharpAdbClient @@ -35,7 +34,7 @@ namespace AdvancedSharpAdbClient /// } /// /// - [DebuggerDisplay($"{nameof(DeviceMonitor)} \\{{ {nameof(IsRunning)} = {{{nameof(IsRunning)}}}, {nameof(Devices)} = {{{nameof(Devices)}}}, {nameof(Socket)} = {{{nameof(Socket)}}} }}")] + [DebuggerDisplay($"{{{nameof(GetType)}().{nameof(Type.ToString)}(),nq}} \\{{ {nameof(IsRunning)} = {{{nameof(IsRunning)}}}, {nameof(Devices)} = \\{{ {{{nameof(Devices)}}} }}, {nameof(Socket)} = {{{nameof(Socket)}}} }}")] public partial class DeviceMonitor : IDeviceMonitor, ICloneable, ICloneable #if COMP_NETSTANDARD2_1 , IAsyncDisposable @@ -359,7 +358,7 @@ protected virtual void UpdateDevices(params IEnumerable collection) // add them to the list, and start monitoring them. bool isChanged = false; - List devices = collection.ToList(); + List devices = [.. collection]; for (int i = this.devices.Count; --i >= 0;) { DeviceData currentDevice = this.devices[i]; @@ -391,7 +390,7 @@ protected virtual void UpdateDevices(params IEnumerable collection) foreach (DeviceData device in devices) { this.devices.Add(device); - DeviceConnected?.Invoke(this, new DeviceDataConnectEventArgs(device, false)); + DeviceConnected?.Invoke(this, new DeviceDataConnectEventArgs(device, true)); } isChanged = true; } @@ -404,18 +403,7 @@ protected virtual void UpdateDevices(params IEnumerable collection) } /// - public override string ToString() => - new StringBuilder(nameof(SyncService)) - .Append(" { ") - .Append(nameof(Socket)) - .Append(" = ") - .Append(Socket) - .Append(", ") - .Append(nameof(IsRunning)) - .Append(" = ") - .Append(IsRunning) - .Append(" }") - .ToString(); + public override string ToString() => $"{GetType()} {{ {nameof(Socket)} = {Socket}, {nameof(IsRunning)} = {IsRunning} }}"; /// public virtual DeviceMonitor Clone() => diff --git a/AdvancedSharpAdbClient/Exceptions/JavaException.cs b/AdvancedSharpAdbClient/Exceptions/JavaException.cs index 1ebc89b9..d45547fb 100644 --- a/AdvancedSharpAdbClient/Exceptions/JavaException.cs +++ b/AdvancedSharpAdbClient/Exceptions/JavaException.cs @@ -121,10 +121,10 @@ public static JavaException Parse(params IEnumerable lines) exception = m.Groups[1].Value; message = m.Groups[2].Value; - message = StringExtensions.IsNullOrWhiteSpace(message) ? UnknownError : message; + message = string.IsNullOrWhiteSpace(message) ? UnknownError : message; } } - else if (!StringExtensions.IsNullOrWhiteSpace(line)) + else if (!string.IsNullOrWhiteSpace(line)) { stackTrace.AppendLine(line.TrimEnd()); } diff --git a/AdvancedSharpAdbClient/Exceptions/NamespaceDoc.cs b/AdvancedSharpAdbClient/Exceptions/NamespaceDoc.cs index b29dcbfa..43992c78 100644 --- a/AdvancedSharpAdbClient/Exceptions/NamespaceDoc.cs +++ b/AdvancedSharpAdbClient/Exceptions/NamespaceDoc.cs @@ -14,5 +14,11 @@ namespace AdvancedSharpAdbClient.Exceptions /// Copyright (c) The Android Open Source Project, Ryan Conrad, Quamotion, yungd1plomat, wherewhere. All rights reserved. [CompilerGenerated] [EditorBrowsable(EditorBrowsableState.Never)] - internal abstract class NamespaceDoc : AdvancedSharpAdbClient.NamespaceDoc; + internal abstract class NamespaceDoc : AdvancedSharpAdbClient.NamespaceDoc + { + /// + /// The name of the namespace . + /// + public new const string Name = $"{AdvancedSharpAdbClient.NamespaceDoc.Name}.{nameof(Exceptions)}"; + } } diff --git a/AdvancedSharpAdbClient/Extensions/EnumerableBuilder.cs b/AdvancedSharpAdbClient/Extensions/EnumerableBuilder.cs index 51a82001..f6e6f385 100644 --- a/AdvancedSharpAdbClient/Extensions/EnumerableBuilder.cs +++ b/AdvancedSharpAdbClient/Extensions/EnumerableBuilder.cs @@ -52,7 +52,7 @@ public static FileStatistics FileStatisticsCreator(ReadOnlySpan values) { FileMode = (UnixFileStatus)ReadInt32(values), Size = ReadInt32(values), - Time = DateTimeExtensions.FromUnixTimeSeconds(ReadInt32(values)) + Time = DateTimeOffset.FromUnixTimeSeconds(ReadInt32(values)) }; int ReadInt32(in ReadOnlySpan data) => data[index++] | (data[index++] << 8) | (data[index++] << 16) | (data[index++] << 24); } @@ -151,7 +151,7 @@ public static UnixFileStatus UnixFileStatusCreator(ReadOnlySpan values) => return null; } - DateTimeOffset timestamp = DateTimeExtensions.FromUnixTimeSeconds(sec); + DateTimeOffset timestamp = DateTimeOffset.FromUnixTimeSeconds(sec); switch (id) { diff --git a/AdvancedSharpAdbClient/Extensions/Extensions.cs b/AdvancedSharpAdbClient/Extensions/Extensions.cs index 40509e23..2e74777a 100644 --- a/AdvancedSharpAdbClient/Extensions/Extensions.cs +++ b/AdvancedSharpAdbClient/Extensions/Extensions.cs @@ -4,11 +4,12 @@ using System; using System.ComponentModel; +using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.IO; using System.Net; using System.Net.Sockets; -using System.Runtime.InteropServices; +using System.Runtime.CompilerServices; using System.Threading; namespace AdvancedSharpAdbClient @@ -113,6 +114,19 @@ public static Task ReadToEndAsync(this TextReader reader, CancellationTo /// /// The to release. public static void Close(this TextReader reader) => reader.Dispose(); +#else +#if HAS_TASK && !NET5_0_OR_GREATER + /// + /// Instructs the Process component to wait for the associated process to exit, or + /// for the to be canceled. + /// + /// The to wait for. + /// An optional token to cancel the asynchronous operation. + /// A task that will complete when the process has exited, cancellation has been requested, + /// or an error occurs. + public static Task WaitForExitAsync(this Process process, CancellationToken cancellationToken = default) => + Task.Run(process.WaitForExit, cancellationToken); +#endif #endif #if NETFRAMEWORK && !NET40_OR_GREATER @@ -163,42 +177,12 @@ public static string GetFullPath(string path) => : Path.GetFullPath(path); #endif -#if NET - [SupportedOSPlatformGuard("Windows")] -#endif - public static bool IsWindowsPlatform() => -#if NETCORE && !UAP10_0_15138_0 - true; -#elif !NETFRAMEWORK || NET48_OR_GREATER - RuntimeInformation.IsOSPlatform(OSPlatform.Windows); -#else - Environment.OSVersion.Platform - is PlatformID.Win32S - or PlatformID.Win32Windows - or PlatformID.Win32NT - or PlatformID.WinCE - or PlatformID.Xbox; -#endif - -#if NET - [SupportedOSPlatformGuard("Linux")] - [SupportedOSPlatformGuard("OSX")] - [SupportedOSPlatformGuard("FreeBSD")] -#endif - public static bool IsUnixPlatform() => -#if NETCORE && !UAP10_0_15138_0 - false; -#elif !NETFRAMEWORK || NET48_OR_GREATER - RuntimeInformation.IsOSPlatform(OSPlatform.Linux) - || RuntimeInformation.IsOSPlatform(OSPlatform.OSX) -#if NETCOREAPP3_0_OR_GREATER - || RuntimeInformation.IsOSPlatform(OSPlatform.FreeBSD) -#endif - ; -#else - Environment.OSVersion.Platform - is PlatformID.Unix - or PlatformID.MacOSX; -#endif + /// + /// Sends a request to the Android Debug Bridge.To read the response, call + /// . + /// + /// The socket to use. + /// The request to send. + public static void SendAdbRequest(this IAdbSocket socket, scoped in DefaultInterpolatedStringHandler request) => socket.SendAdbRequest(request.ToString()); } } diff --git a/AdvancedSharpAdbClient/Extensions/Factories.cs b/AdvancedSharpAdbClient/Extensions/Factories.cs index ed11bdb9..89b10bba 100644 --- a/AdvancedSharpAdbClient/Extensions/Factories.cs +++ b/AdvancedSharpAdbClient/Extensions/Factories.cs @@ -13,9 +13,6 @@ namespace AdvancedSharpAdbClient /// public static class Factories { -#if HAS_WINRT && NET - [SupportedOSPlatform("Windows10.0.10240.0")] -#endif static Factories() => Reset(); /// @@ -52,9 +49,7 @@ public static class Factories nameof(AdbClientFactory), nameof(AdbCommandLineClientFactory), nameof(SyncServiceFactory))] -#if HAS_WINRT && NET - [SupportedOSPlatform("Windows10.0.10240.0")] -#endif + public static void Reset() { AdbSocketFactory = endPoint => new AdbSocket(endPoint); diff --git a/AdvancedSharpAdbClient/Extensions/SyncCommandConverter.cs b/AdvancedSharpAdbClient/Extensions/SyncCommandConverter.cs index 7660cde5..77fcc2eb 100644 --- a/AdvancedSharpAdbClient/Extensions/SyncCommandConverter.cs +++ b/AdvancedSharpAdbClient/Extensions/SyncCommandConverter.cs @@ -13,69 +13,74 @@ namespace AdvancedSharpAdbClient.Models public static class SyncCommandConverter { /// - /// Gets the byte array that represents the . + /// The extension for the enum. /// - /// The to convert. - /// A byte array that represents the . - public static byte[] GetBytes(this SyncCommand command) + /// The to extend. + extension(SyncCommand command) { - if (command == 0) + /// + /// Gets the byte array that represents the . + /// + /// A byte array that represents the . + public byte[] GetBytes() { - return [0, 0, 0, 0]; - } - - if (command is < SyncCommand.STAT or > SyncCommand.LST2) - { - throw new ArgumentOutOfRangeException(nameof(command), $"{command} is not a valid sync command"); - } + if (command == 0) + { + return [0, 0, 0, 0]; + } - string commandText = command.ToString(); - byte[] commandBytes = AdbClient.Encoding.GetBytes(commandText); + if (command is < SyncCommand.STAT or > SyncCommand.LST2) + { + throw new ArgumentOutOfRangeException(nameof(command), $"{command} is not a valid sync command"); + } - return commandBytes; - } + string commandText = command.ToString(); + byte[] commandBytes = AdbClient.Encoding.GetBytes(commandText); - /// - /// Returns an enumerator that iterates through the . - /// - /// The to convert. - /// An enumerator that can be used to iterate through the . - public static IEnumerator GetEnumerator(this SyncCommand command) => ((IEnumerable)command.GetBytes()).GetEnumerator(); + return commandBytes; + } - /// - /// Determines which is represented by this byte array. - /// - /// A byte array that represents a . - /// The corresponding . - public static SyncCommand GetCommand(byte[] value) - { - ExceptionExtensions.ThrowIfNull(value); + /// + /// Returns an enumerator that iterates through the . + /// + /// An enumerator that can be used to iterate through the . + public IEnumerator GetEnumerator() => ((IEnumerable)command.GetBytes()).GetEnumerator(); - if (value.Length != 4) + /// + /// Determines which is represented by this byte array. + /// + /// A byte array that represents a . + /// The corresponding . + public static SyncCommand GetCommand(byte[] value) { - throw new ArgumentOutOfRangeException(nameof(value)); - } + ArgumentNullException.ThrowIfNull(value); - string commandText = AdbClient.Encoding.GetString(value); - return commandText == "\0\0\0\0" ? 0 : EnumExtensions.TryParse(commandText, true, out SyncCommand command) ? command : throw new ArgumentOutOfRangeException(nameof(value), $"{commandText} is not a valid sync command"); - } + if (value.Length != 4) + { + throw new ArgumentOutOfRangeException(nameof(value)); + } + + string commandText = AdbClient.Encoding.GetString(value); + return commandText == "\0\0\0\0" ? 0 : Enum.TryParse(commandText, true, out SyncCommand result) ? result : throw new ArgumentOutOfRangeException(nameof(value), $"{commandText} is not a valid sync command"); + } #if HAS_BUFFERS - /// - /// Determines which is represented by this byte array. - /// - /// A byte array that represents a . - /// The corresponding . - public static SyncCommand GetCommand(ReadOnlySpan value) - { - if (value.Length != 4) + /// + /// Determines which is represented by this byte array. + /// + /// A byte array that represents a . + /// The corresponding . + public static SyncCommand GetCommand(ReadOnlySpan value) { - throw new ArgumentOutOfRangeException(nameof(value)); - } + if (value.Length != 4) + { + throw new ArgumentOutOfRangeException(nameof(value)); + } - string commandText = AdbClient.Encoding.GetString(value); - return commandText == "\0\0\0\0" ? 0 : EnumExtensions.TryParse(commandText, true, out SyncCommand command) ? command : throw new ArgumentOutOfRangeException(nameof(value), $"{commandText} is not a valid sync command"); - } + string commandText = AdbClient.Encoding.GetString(value); + return commandText == "\0\0\0\0" ? 0 : Enum.TryParse(commandText, true, out SyncCommand result) ? result : throw new ArgumentOutOfRangeException(nameof(value), $"{commandText} is not a valid sync command"); + } #endif + } } } diff --git a/AdvancedSharpAdbClient/Extensions/UnixFileStatusExtensions.cs b/AdvancedSharpAdbClient/Extensions/UnixFileStatusExtensions.cs index 5797dbc3..2e6bcc02 100644 --- a/AdvancedSharpAdbClient/Extensions/UnixFileStatusExtensions.cs +++ b/AdvancedSharpAdbClient/Extensions/UnixFileStatusExtensions.cs @@ -106,7 +106,7 @@ public static class UnixFileStatusExtensions /// A representing the parsed permission code. public static UnixFileStatus FromPermissionCode(string code) { - ExceptionExtensions.ThrowIfNull(code); + ArgumentNullException.ThrowIfNull(code); if (code.Length is not (9 or 10)) { diff --git a/AdvancedSharpAdbClient/Interfaces/IAdbClient.Async.cs b/AdvancedSharpAdbClient/Interfaces/IAdbClient.Async.cs index e6a6c5c6..f32435ea 100644 --- a/AdvancedSharpAdbClient/Interfaces/IAdbClient.Async.cs +++ b/AdvancedSharpAdbClient/Interfaces/IAdbClient.Async.cs @@ -6,7 +6,6 @@ using System; using System.Collections.Generic; using System.IO; -using System.Net; using System.Text; using System.Threading; @@ -239,7 +238,7 @@ public partial interface IAdbClient /// A which can be used to cancel the asynchronous operation. /// A of strings, each representing a line of output from the command. IAsyncEnumerable ExecuteServerEnumerableAsync(string target, string command, Encoding encoding, CancellationToken cancellationToken) => - ExecuteServerEnumerable(target, command, encoding).AsEnumerableAsync(cancellationToken); + ExecuteServerEnumerable(target, command, encoding).ToAsyncEnumerable(cancellationToken); /// /// Asynchronously executes a command on the adb server and returns the output. @@ -252,7 +251,7 @@ IAsyncEnumerable ExecuteServerEnumerableAsync(string target, string comm /// A which can be used to cancel the asynchronous operation. /// A of strings, each representing a line of output from the command. IAsyncEnumerable ExecuteServerEnumerableAsync(string target, string command, IAdbSocket socket, Encoding encoding, CancellationToken cancellationToken) => - ExecuteServerEnumerable(target, command, socket, encoding).AsEnumerableAsync(cancellationToken); + ExecuteServerEnumerable(target, command, socket, encoding).ToAsyncEnumerable(cancellationToken); /// /// Asynchronously executes a command on the device and returns the output. @@ -263,7 +262,7 @@ IAsyncEnumerable ExecuteServerEnumerableAsync(string target, string comm /// A which can be used to cancel the asynchronous operation. /// A of strings, each representing a line of output from the command. IAsyncEnumerable ExecuteRemoteEnumerableAsync(string command, DeviceData device, Encoding encoding, CancellationToken cancellationToken) => - ExecuteRemoteEnumerable(command, device, encoding).AsEnumerableAsync(cancellationToken); + ExecuteRemoteEnumerable(command, device, encoding).ToAsyncEnumerable(cancellationToken); /// /// Asynchronously runs the event log service on a device and returns it. @@ -273,7 +272,7 @@ IAsyncEnumerable ExecuteRemoteEnumerableAsync(string command, DeviceData /// Optionally, the names of the logs to receive. /// A which contains the log entries. IAsyncEnumerable RunLogServiceAsync(DeviceData device, CancellationToken cancellationToken, params LogId[] logNames) => - RunLogService(device, logNames).AsEnumerableAsync(cancellationToken); + RunLogService(device, logNames).ToAsyncEnumerable(cancellationToken); #endif /// diff --git a/AdvancedSharpAdbClient/Interfaces/IAdbSocket.Async.cs b/AdvancedSharpAdbClient/Interfaces/IAdbSocket.Async.cs index 926781b6..39ad6899 100644 --- a/AdvancedSharpAdbClient/Interfaces/IAdbSocket.Async.cs +++ b/AdvancedSharpAdbClient/Interfaces/IAdbSocket.Async.cs @@ -134,18 +134,14 @@ public partial interface IAdbSocket /// A object that represents the response from the Android Debug Bridge. Task ReadAdbResponseAsync(CancellationToken cancellationToken); -#if HAS_BUFFERS +#if COMP_NETSTANDARD2_1 /// /// Asynchronously sends the specified number of bytes of data to a , /// /// A array that acts as a buffer, containing the data to send. /// A that can be used to cancel the task. /// A that represents the asynchronous operation. - public ValueTask SendAsync(ReadOnlyMemory data, CancellationToken cancellationToken = default) -#if COMP_NETSTANDARD2_1 - => new(SendAsync(data.ToArray(), cancellationToken)) -#endif - ; + public ValueTask SendAsync(ReadOnlyMemory data, CancellationToken cancellationToken = default) => new(SendAsync(data.ToArray(), data.Length, cancellationToken)); /// /// Asynchronously receives data from a into a receive buffer. @@ -155,22 +151,14 @@ public ValueTask SendAsync(ReadOnlyMemory data, CancellationToken cancella /// Cancelling the task will also close the socket. /// A that represents the asynchronous operation. The result value of the task contains the number of bytes received. public ValueTask ReadAsync(Memory data, CancellationToken cancellationToken) -#if COMP_NETSTANDARD2_1 { byte[] bytes = new byte[data.Length]; - return new(ReadAsync(bytes, cancellationToken).ContinueWith(x => + return new(ReadAsync(bytes, bytes.Length, cancellationToken).ContinueWith(x => { - int length = x.Result; - for (int i = 0; i < length; i++) - { - data.Span[i] = bytes[i]; - } - return length; + bytes.CopyTo(data); + return x.Result; })); } -#else - ; -#endif #endif /// diff --git a/AdvancedSharpAdbClient/Interfaces/IAdbSocket.cs b/AdvancedSharpAdbClient/Interfaces/IAdbSocket.cs index 0e7e95de..66657b71 100644 --- a/AdvancedSharpAdbClient/Interfaces/IAdbSocket.cs +++ b/AdvancedSharpAdbClient/Interfaces/IAdbSocket.cs @@ -5,6 +5,7 @@ using System; using System.IO; using System.Net.Sockets; +using System.Runtime.CompilerServices; namespace AdvancedSharpAdbClient { @@ -77,6 +78,26 @@ public partial interface IAdbSocket : IDisposable /// The request to send. void SendAdbRequest(string request); +#if NET10_0_OR_GREATER + /// + /// Sends a request to the Android Debug Bridge.To read the response, call + /// . + /// + /// The request to send. + void SendAdbRequest(DefaultInterpolatedStringHandler request) + { + byte[] data = AdbClient.FormAdbRequest(request.Text); + try + { + Send(data); + } + catch (IOException) + { + throw new IOException($"Failed sending the request '{request.Text}' to ADB"); + } + } +#endif + /// /// Reads from the socket until the array is filled, or no more data is coming(because /// the socket closed or the timeout expired). @@ -135,16 +156,12 @@ public partial interface IAdbSocket : IDisposable /// A object that represents the response from the Android Debug Bridge. AdbResponse ReadAdbResponse(); -#if HAS_BUFFERS +#if COMP_NETSTANDARD2_1 /// /// Sends the specified number of bytes of data to a , /// /// A span of bytes that acts as a buffer, containing the data to send. - void Send(ReadOnlySpan data) -#if COMP_NETSTANDARD2_1 - => Send(data.ToArray()) -#endif - ; + void Send(ReadOnlySpan data) => Send(data.ToArray(), data.Length); /// /// Reads from the socket until the array is filled, or no more data is coming(because @@ -154,19 +171,12 @@ void Send(ReadOnlySpan data) /// The total number of bytes read. /// This uses the default time out value. int Read(Span data) -#if COMP_NETSTANDARD2_1 { byte[] bytes = new byte[data.Length]; - int length = Read(bytes); - for (int i = 0; i < length; i++) - { - data[i] = bytes[i]; - } + int length = Read(bytes, data.Length); + bytes.CopyTo(data); return length; } -#else - ; -#endif #endif /// diff --git a/AdvancedSharpAdbClient/Interfaces/ISyncService.Async.cs b/AdvancedSharpAdbClient/Interfaces/ISyncService.Async.cs index 93e7292d..e41a39cd 100644 --- a/AdvancedSharpAdbClient/Interfaces/ISyncService.Async.cs +++ b/AdvancedSharpAdbClient/Interfaces/ISyncService.Async.cs @@ -58,7 +58,7 @@ public partial interface ISyncService /// A that can be used to cancel the task. /// An which returns for each child item of the directory, a object with information of the item. IAsyncEnumerable GetDirectoryAsyncListing(string remotePath, CancellationToken cancellationToken) => - GetDirectoryListingAsync(remotePath, cancellationToken).ContinueWith(x => x.Result as IEnumerable).AsEnumerableAsync(cancellationToken); + GetDirectoryListingAsync(remotePath, cancellationToken).ContinueWith(x => x.Result as IEnumerable).ToAsyncEnumerable(cancellationToken); #endif /// diff --git a/AdvancedSharpAdbClient/Interfaces/ITcpSocket.Async.cs b/AdvancedSharpAdbClient/Interfaces/ITcpSocket.Async.cs index c2fae3b4..b3edd701 100644 --- a/AdvancedSharpAdbClient/Interfaces/ITcpSocket.Async.cs +++ b/AdvancedSharpAdbClient/Interfaces/ITcpSocket.Async.cs @@ -99,7 +99,7 @@ public partial interface ITcpSocket /// A which returns the number of bytes received. Task ReceiveAsync(byte[] buffer, int offset, int size, SocketFlags socketFlags, CancellationToken cancellationToken); -#if HAS_BUFFERS +#if COMP_NETSTANDARD2_1 /// /// Asynchronously sends the specified number of bytes of data to a connected /// using the specified . @@ -109,10 +109,7 @@ public partial interface ITcpSocket /// A which can be used to cancel the asynchronous task. /// A which returns the number of bytes sent to the Socket. public ValueTask SendAsync(ReadOnlyMemory buffer, SocketFlags socketFlags, CancellationToken cancellationToken) -#if COMP_NETSTANDARD2_1 - => new(ReceiveAsync(buffer.ToArray(), socketFlags, cancellationToken)) -#endif - ; + => new(ReceiveAsync(buffer.ToArray(), buffer.Length, socketFlags, cancellationToken)); /// /// Asynchronously receives the specified number of bytes from a bound @@ -124,22 +121,14 @@ public ValueTask SendAsync(ReadOnlyMemory buffer, SocketFlags socketF /// Cancelling the task will also close the socket. /// A which returns the number of bytes received. public ValueTask ReceiveAsync(Memory buffer, SocketFlags socketFlags, CancellationToken cancellationToken) -#if COMP_NETSTANDARD2_1 { byte[] bytes = new byte[buffer.Length]; - return new(ReceiveAsync(bytes, socketFlags, cancellationToken).ContinueWith(x => + return new(ReceiveAsync(bytes, bytes.Length, socketFlags, cancellationToken).ContinueWith(x => { - int length = x.Result; - for (int i = 0; i < length; i++) - { - buffer.Span[i] = bytes[i]; - } - return length; + bytes.CopyTo(buffer); + return x.Result; })); } -#else - ; -#endif #endif } } diff --git a/AdvancedSharpAdbClient/Interfaces/ITcpSocket.cs b/AdvancedSharpAdbClient/Interfaces/ITcpSocket.cs index a9ad3554..57bc4b31 100644 --- a/AdvancedSharpAdbClient/Interfaces/ITcpSocket.cs +++ b/AdvancedSharpAdbClient/Interfaces/ITcpSocket.cs @@ -101,7 +101,7 @@ public partial interface ITcpSocket : IDisposable /// The number of bytes received. int Receive(byte[] buffer, int offset, int size, SocketFlags socketFlags); -#if HAS_BUFFERS +#if COMP_NETSTANDARD2_1 /// /// Sends the specified number of bytes of data to a connected /// using the specified . @@ -109,11 +109,7 @@ public partial interface ITcpSocket : IDisposable /// A span of bytes that contains the data to be sent. /// A bitwise combination of the SocketFlags values. /// The number of bytes sent to the Socket. - int Send(ReadOnlySpan buffer, SocketFlags socketFlags) -#if COMP_NETSTANDARD2_1 - => Send(buffer.ToArray(), buffer.Length, socketFlags) -#endif - ; + int Send(ReadOnlySpan buffer, SocketFlags socketFlags) => Send(buffer.ToArray(), buffer.Length, socketFlags); /// /// Receives the specified number of bytes from a bound @@ -123,19 +119,12 @@ int Send(ReadOnlySpan buffer, SocketFlags socketFlags) /// A bitwise combination of the SocketFlags values. /// The number of bytes received. int Receive(Span buffer, SocketFlags socketFlags) -#if COMP_NETSTANDARD2_1 { byte[] bytes = new byte[buffer.Length]; int length = Receive(bytes, bytes.Length, socketFlags); - for (int i = 0; i < length; i++) - { - buffer[i] = bytes[i]; - } + bytes.CopyTo(buffer); return length; } -#else - ; -#endif #endif /// diff --git a/AdvancedSharpAdbClient/Logs/AndroidLogEntry.cs b/AdvancedSharpAdbClient/Logs/AndroidLogEntry.cs index f3321b20..82b20a5f 100644 --- a/AdvancedSharpAdbClient/Logs/AndroidLogEntry.cs +++ b/AdvancedSharpAdbClient/Logs/AndroidLogEntry.cs @@ -2,6 +2,7 @@ // Copyright (c) The Android Open Source Project, Ryan Conrad, Quamotion, yungd1plomat, wherewhere. All rights reserved. // +using System; using System.Collections.Generic; using System.Diagnostics; @@ -11,13 +12,13 @@ namespace AdvancedSharpAdbClient.Logs /// Represents a standard Android log entry (an entry in any Android log buffer except the Event buffer). /// /// - [DebuggerDisplay($"{nameof(AndroidLogEntry)} \\{{ {nameof(TimeStamp)} = {{{nameof(TimeStamp)}}}, {nameof(ProcessId)} = {{{nameof(ProcessId)}}}, {nameof(Priority)} = {{{nameof(Priority)}}}, {nameof(Tag)} = {{{nameof(Tag)}}}, {nameof(Message)} = {{{nameof(Message)}}} }}")] + [DebuggerDisplay($"{{{nameof(GetType)}().{nameof(Type.ToString)}(),nq}} \\{{ {nameof(TimeStamp)} = {{{nameof(TimeStamp)}}}, {nameof(ProcessId)} = {{{nameof(ProcessId)}}}, {nameof(Priority)} = {{{nameof(Priority)}}}, {nameof(Tag)} = {{{nameof(Tag)}}}, {nameof(Message)} = {{{nameof(Message)}}} }}")] public class AndroidLogEntry : LogEntry { /// /// Maps Android log priorities to chars used to represent them in the system log. /// - private static readonly Dictionary PriorityFormatters = new(6) + private static readonly Dictionary PriorityFormatters = new(7) { { Priority.Verbose, 'V' }, { Priority.Debug, 'D' }, diff --git a/AdvancedSharpAdbClient/Logs/EventLogEntry.cs b/AdvancedSharpAdbClient/Logs/EventLogEntry.cs index 24d288f3..2d0ea5aa 100644 --- a/AdvancedSharpAdbClient/Logs/EventLogEntry.cs +++ b/AdvancedSharpAdbClient/Logs/EventLogEntry.cs @@ -2,6 +2,7 @@ // Copyright (c) The Android Open Source Project, Ryan Conrad, Quamotion, yungd1plomat, wherewhere. All rights reserved. // +using System; using System.Collections.Generic; using System.Diagnostics; @@ -11,7 +12,7 @@ namespace AdvancedSharpAdbClient.Logs /// Represents an entry in event buffer of the the Android log. /// /// - [DebuggerDisplay($"{nameof(AndroidLogEntry)} \\{{ {nameof(TimeStamp)} = {{{nameof(TimeStamp)}}}, {nameof(ProcessId)} = {{{nameof(ProcessId)}}}, {nameof(Tag)} = {{{nameof(Tag)}}}, {nameof(Values)} = {{{nameof(Values)}}} }}")] + [DebuggerDisplay($"{{{nameof(GetType)}().{nameof(Type.ToString)}(),nq}} \\{{ {nameof(TimeStamp)} = {{{nameof(TimeStamp)}}}, {nameof(ProcessId)} = {{{nameof(ProcessId)}}}, {nameof(Tag)} = {{{nameof(Tag)}}}, {nameof(Values)} = {{{nameof(Values)}}} }}")] public class EventLogEntry : LogEntry { /// @@ -32,6 +33,6 @@ public EventLogEntry() { } /// public override string ToString() => - $"{TimeStamp.LocalDateTime:yy-MM-dd HH:mm:ss.fff} {ProcessId,5} {ProcessId,5} {Tag,-8}: {StringExtensions.Join(", ", Values)}"; + $"{TimeStamp.LocalDateTime:yy-MM-dd HH:mm:ss.fff} {ProcessId,5} {ProcessId,5} {Tag,-8}: {string.Join(", ", Values)}"; } } diff --git a/AdvancedSharpAdbClient/Logs/LogEntry.cs b/AdvancedSharpAdbClient/Logs/LogEntry.cs index 40bcb79b..abfd5369 100644 --- a/AdvancedSharpAdbClient/Logs/LogEntry.cs +++ b/AdvancedSharpAdbClient/Logs/LogEntry.cs @@ -18,7 +18,7 @@ namespace AdvancedSharpAdbClient.Logs #if HAS_BUFFERS [CollectionBuilder(typeof(EnumerableBuilder), nameof(EnumerableBuilder.LogEntryCreator))] #endif - [DebuggerDisplay($"{nameof(AndroidLogEntry)} \\{{ {nameof(PayloadLength)} = {{{nameof(PayloadLength)}}}, {nameof(HeaderSize)} = {{{nameof(HeaderSize)}}}, {nameof(ProcessId)} = {{{nameof(ProcessId)}}}, {nameof(ThreadId)} = {{{nameof(ThreadId)}}}, {nameof(TimeStamp)} = {{{nameof(TimeStamp)}}}, {nameof(NanoSeconds)} = {{{nameof(NanoSeconds)}}}, {nameof(Id)} = {{{nameof(Id)}}}, {nameof(Uid)} = {{{nameof(Uid)}}}, {nameof(Data)} = {{{nameof(Data)}}} }}")] + [DebuggerDisplay($"{{{nameof(GetType)}().{nameof(Type.ToString)}(),nq}} \\{{ {nameof(PayloadLength)} = {{{nameof(PayloadLength)}}}, {nameof(HeaderSize)} = {{{nameof(HeaderSize)}}}, {nameof(ProcessId)} = {{{nameof(ProcessId)}}}, {nameof(ThreadId)} = {{{nameof(ThreadId)}}}, {nameof(TimeStamp)} = {{{nameof(TimeStamp)}}}, {nameof(NanoSeconds)} = {{{nameof(NanoSeconds)}}}, {nameof(Id)} = {{{nameof(Id)}}}, {nameof(Uid)} = {{{nameof(Uid)}}}, {nameof(Data)} = {{{nameof(Data)}}} }}")] public class LogEntry { /// diff --git a/AdvancedSharpAdbClient/Logs/LogReader.Async.cs b/AdvancedSharpAdbClient/Logs/LogReader.Async.cs index 08f3a7d7..dd2047b5 100644 --- a/AdvancedSharpAdbClient/Logs/LogReader.Async.cs +++ b/AdvancedSharpAdbClient/Logs/LogReader.Async.cs @@ -96,7 +96,7 @@ public partial class LogReader return null; } - DateTimeOffset timestamp = DateTimeExtensions.FromUnixTimeSeconds(sec); + DateTimeOffset timestamp = DateTimeOffset.FromUnixTimeSeconds(sec); switch (id) { diff --git a/AdvancedSharpAdbClient/Logs/LogReader.cs b/AdvancedSharpAdbClient/Logs/LogReader.cs index d906fad5..685b1913 100644 --- a/AdvancedSharpAdbClient/Logs/LogReader.cs +++ b/AdvancedSharpAdbClient/Logs/LogReader.cs @@ -103,7 +103,7 @@ public partial class LogReader(Stream stream) return null; } - DateTimeOffset timestamp = DateTimeExtensions.FromUnixTimeSeconds(sec); + DateTimeOffset timestamp = DateTimeOffset.FromUnixTimeSeconds(sec); switch (id) { diff --git a/AdvancedSharpAdbClient/Logs/NamespaceDoc.cs b/AdvancedSharpAdbClient/Logs/NamespaceDoc.cs index 431a8685..783002d6 100644 --- a/AdvancedSharpAdbClient/Logs/NamespaceDoc.cs +++ b/AdvancedSharpAdbClient/Logs/NamespaceDoc.cs @@ -3,7 +3,6 @@ // using System.ComponentModel; -using System.Runtime.CompilerServices; namespace AdvancedSharpAdbClient.Logs { @@ -11,7 +10,12 @@ namespace AdvancedSharpAdbClient.Logs /// The classes in this namespace provide access to the Android system log. /// /// Copyright (c) The Android Open Source Project, Ryan Conrad, Quamotion, yungd1plomat, wherewhere. All rights reserved. - [CompilerGenerated] [EditorBrowsable(EditorBrowsableState.Never)] - internal abstract class NamespaceDoc : AdvancedSharpAdbClient.NamespaceDoc; + internal abstract class NamespaceDoc : AdvancedSharpAdbClient.NamespaceDoc + { + /// + /// The name of the namespace . + /// + public new const string Name = $"{AdvancedSharpAdbClient.NamespaceDoc.Name}.{nameof(Logs)}"; + } } diff --git a/AdvancedSharpAdbClient/Models/AdbCommandLineStatus.cs b/AdvancedSharpAdbClient/Models/AdbCommandLineStatus.cs index 0d051db4..66c93e27 100644 --- a/AdvancedSharpAdbClient/Models/AdbCommandLineStatus.cs +++ b/AdvancedSharpAdbClient/Models/AdbCommandLineStatus.cs @@ -17,7 +17,7 @@ namespace AdvancedSharpAdbClient.Models #if HAS_BUFFERS [CollectionBuilder(typeof(EnumerableBuilder), nameof(EnumerableBuilder.AdbCommandLineStatusCreator))] #endif - [DebuggerDisplay($"{nameof(AdbServerStatus)} \\{{ {nameof(AdbVersion)} = {{{nameof(AdbVersion)}}}, {nameof(FileVersion)} = {{{nameof(FileVersion)}}}, {nameof(FilePath)} = {{{nameof(FilePath)}}} }}")] + [DebuggerDisplay($"{{{nameof(GetType)}().{nameof(Type.ToString)}(),nq}} \\{{ {nameof(AdbVersion)} = {{{nameof(AdbVersion)}}}, {nameof(FileVersion)} = {{{nameof(FileVersion)}}}, {nameof(FilePath)} = {{{nameof(FilePath)}}} }}")] public readonly partial record struct AdbCommandLineStatus(Version? AdbVersion, string? FileVersion, string? FilePath) { /// @@ -149,7 +149,7 @@ public readonly IEnumerator GetEnumerator() } /// - public override string ToString() => string.Join(Environment.NewLine, (string[])[.. this]); + public override string ToString() => string.Join(Environment.NewLine, [.. this]); #if NET7_0_OR_GREATER [GeneratedRegex(VersionPattern)] diff --git a/AdvancedSharpAdbClient/Models/AdbResponse.cs b/AdvancedSharpAdbClient/Models/AdbResponse.cs index 9a021c24..5503db77 100644 --- a/AdvancedSharpAdbClient/Models/AdbResponse.cs +++ b/AdvancedSharpAdbClient/Models/AdbResponse.cs @@ -12,7 +12,7 @@ namespace AdvancedSharpAdbClient.Models /// The response returned by ADB server. /// /// the message of . - [DebuggerDisplay($"{nameof(AdbResponse)} \\{{ {nameof(IOSuccess)} = {{{nameof(IOSuccess)}}}, {nameof(Okay)} = {{{nameof(Okay)}}}, {nameof(Timeout)} = {{{nameof(Timeout)}}}, {nameof(Message)} = {{{nameof(Message)}}} }}")] + [DebuggerDisplay($"{{{nameof(GetType)}().{nameof(Type.ToString)}(),nq}} \\{{ {nameof(IOSuccess)} = {{{nameof(IOSuccess)}}}, {nameof(Okay)} = {{{nameof(Okay)}}}, {nameof(Timeout)} = {{{nameof(Timeout)}}}, {nameof(Message)} = {{{nameof(Message)}}} }}")] public readonly struct AdbResponse(string message) : IEquatable { /// diff --git a/AdvancedSharpAdbClient/Models/AdbServerStatus.cs b/AdvancedSharpAdbClient/Models/AdbServerStatus.cs index 77318a09..2393987d 100644 --- a/AdvancedSharpAdbClient/Models/AdbServerStatus.cs +++ b/AdvancedSharpAdbClient/Models/AdbServerStatus.cs @@ -12,7 +12,7 @@ namespace AdvancedSharpAdbClient.Models /// /// The value indicating whether the server is currently running. /// The version of the server when it is running. - [DebuggerDisplay($"{nameof(AdbServerStatus)} \\{{ {nameof(IsRunning)} = {{{nameof(IsRunning)}}}, {nameof(Version)} = {{{nameof(Version)}}} }}")] + [DebuggerDisplay($"{{{nameof(GetType)}().{nameof(Type.ToString)}(),nq}} \\{{ {nameof(IsRunning)} = {{{nameof(IsRunning)}}}, {nameof(Version)} = {{{nameof(Version)}}} }}")] public readonly record struct AdbServerStatus(bool IsRunning, Version? Version) { /// diff --git a/AdvancedSharpAdbClient/Models/ColorData.cs b/AdvancedSharpAdbClient/Models/ColorData.cs index f15e151a..86eb2a7f 100644 --- a/AdvancedSharpAdbClient/Models/ColorData.cs +++ b/AdvancedSharpAdbClient/Models/ColorData.cs @@ -7,7 +7,6 @@ using System.Collections.Generic; using System.Diagnostics; using System.Runtime.CompilerServices; -using System.Text; namespace AdvancedSharpAdbClient.Models { @@ -67,20 +66,6 @@ public readonly record struct ColorData(uint Offset, uint Length) : IReadOnlyLis _ => throw new IndexOutOfRangeException("Index was out of range. Must be non-negative and less than the size of the collection.") }; - /// - /// Provides a string representation of the struct. - /// - /// The to append the string representation to. - /// if the members were appended to the ; otherwise, . - private bool PrintMembers(StringBuilder builder) - { - _ = builder.Append("Offset = ") - .Append(Offset) - .Append(", Length = ") - .Append(Length); - return true; - } - /// /// Deconstruct the struct. /// diff --git a/AdvancedSharpAdbClient/Models/DeviceData.EventArgs.cs b/AdvancedSharpAdbClient/Models/DeviceData.EventArgs.cs index 91d2be86..5dee9de3 100644 --- a/AdvancedSharpAdbClient/Models/DeviceData.EventArgs.cs +++ b/AdvancedSharpAdbClient/Models/DeviceData.EventArgs.cs @@ -6,7 +6,7 @@ using System.Collections.Generic; using System.Diagnostics; using System.Linq; -using System.Text; +using System.Runtime.CompilerServices; namespace AdvancedSharpAdbClient.Models { @@ -14,7 +14,7 @@ namespace AdvancedSharpAdbClient.Models /// The event arguments that are passed when a device event occurs. /// /// The device. - [DebuggerDisplay($"{nameof(DeviceDataEventArgs)} \\{{ {nameof(Device)} = {{{nameof(Device)}}} }}")] + [DebuggerDisplay($"{{{nameof(GetType)}().{nameof(Type.ToString)}(),nq}} \\{{ {nameof(Device)} = {{{nameof(Device)}}} }}")] public abstract class DeviceDataEventArgs(DeviceData device) : EventArgs { /// @@ -26,16 +26,20 @@ public abstract class DeviceDataEventArgs(DeviceData device) : EventArgs /// public override string ToString() { - StringBuilder builder = new("Device changed"); + DefaultInterpolatedStringHandler builder = new(18, 2); + builder.AppendLiteral("Device changed"); if (!Device.IsEmpty) { - _ = builder.Append(": ").Append(Device.Serial); + builder.AppendLiteral(": "); + builder.AppendLiteral(Device.Serial); if (!string.IsNullOrEmpty(Device.Name)) { - _ = builder.Append('(').Append(Device.Name).Append(')'); + builder.AppendFormatted('('); + builder.AppendLiteral(Device.Name); + builder.AppendFormatted(')'); } } - return builder.ToString(); + return builder.ToStringAndClear(); } } @@ -43,7 +47,7 @@ public override string ToString() /// The event arguments that are passed when a device event occurs. /// /// The list of device. - [DebuggerDisplay($"{nameof(DeviceDataNotifyEventArgs)} \\{{ {nameof(Devices)} = {{{nameof(Devices)}}} }}")] + [DebuggerDisplay($"{{{nameof(GetType)}().{nameof(Type.ToString)}(),nq}} \\{{ {nameof(Devices)} = {{{nameof(Devices)}}} }}")] public sealed class DeviceDataNotifyEventArgs(params IEnumerable devices) : EventArgs { /// @@ -61,7 +65,7 @@ public sealed class DeviceDataNotifyEventArgs(params IEnumerable dev /// /// The device. /// The device after the reported change. - [DebuggerDisplay($"{nameof(DeviceDataConnectEventArgs)} \\{{ {nameof(Device)} = {{{nameof(Device)}}}, {nameof(IsConnect)} = {{{nameof(IsConnect)}}} }}")] + [DebuggerDisplay($"{{{nameof(GetType)}().{nameof(Type.ToString)}(),nq}} \\{{ {nameof(Device)} = {{{nameof(Device)}}}, {nameof(IsConnect)} = {{{nameof(IsConnect)}}} }}")] public sealed class DeviceDataConnectEventArgs(DeviceData device, bool isConnect) : DeviceDataEventArgs(device) { /// @@ -72,20 +76,24 @@ public sealed class DeviceDataConnectEventArgs(DeviceData device, bool isConnect /// public override string ToString() { - StringBuilder builder = new StringBuilder("Device ") - .Append(IsConnect ? "connected" : "disconnected"); + DefaultInterpolatedStringHandler builder = new(23, 2); + builder.AppendLiteral("Device "); + builder.AppendLiteral(IsConnect ? "connected" : "disconnected"); if (Device.IsEmpty) { - return builder.ToString(); + return builder.ToStringAndClear(); } else { - _ = builder.Append(": ").Append(Device.Serial); + builder.AppendLiteral(": "); + builder.AppendLiteral(Device.Serial); if (!string.IsNullOrEmpty(Device.Name)) { - _ = builder.Append('(').Append(Device.Name).Append(')'); + builder.AppendFormatted('('); + builder.AppendLiteral(Device.Name); + builder.AppendFormatted(')'); } - return builder.ToString(); + return builder.ToStringAndClear(); } } } @@ -96,7 +104,7 @@ public override string ToString() /// The device. /// The state of the device after the reported change. /// The state of the device before the reported change. - [DebuggerDisplay($"{nameof(DeviceDataChangeEventArgs)} \\{{ {nameof(Device)} = {{{nameof(Device)}}}, {nameof(NewState)} = {{{nameof(NewState)}}}, {nameof(OldState)} = {{{nameof(OldState)}}} }}")] + [DebuggerDisplay($"{{{nameof(GetType)}().{nameof(Type.ToString)}(),nq}} \\{{ {nameof(Device)} = {{{nameof(Device)}}}, {nameof(NewState)} = {{{nameof(NewState)}}}, {nameof(OldState)} = {{{nameof(OldState)}}} }}")] public sealed class DeviceDataChangeEventArgs(DeviceData device, DeviceState newState, DeviceState oldState) : DeviceDataEventArgs(device) { /// @@ -112,17 +120,24 @@ public sealed class DeviceDataChangeEventArgs(DeviceData device, DeviceState new /// public override string ToString() { - StringBuilder builder = new("Device state changed:"); + DefaultInterpolatedStringHandler builder = new(29, 4); + builder.AppendLiteral("Device state changed:"); if (!Device.IsEmpty) { - _ = builder.Append(' ').Append(Device.Serial); + builder.AppendFormatted(' '); + builder.AppendLiteral(Device.Serial); if (!string.IsNullOrEmpty(Device.Name)) { - _ = builder.Append('(').Append(Device.Name).Append(')'); + builder.AppendFormatted('('); + builder.AppendLiteral(Device.Name); + builder.AppendFormatted(')'); } } - _ = builder.Append($" {OldState} -> {NewState}"); - return builder.ToString(); + builder.AppendFormatted(' '); + builder.AppendFormatted(OldState); + builder.AppendLiteral(" -> "); + builder.AppendFormatted(NewState); + return builder.ToStringAndClear(); } } } diff --git a/AdvancedSharpAdbClient/Models/DeviceData.cs b/AdvancedSharpAdbClient/Models/DeviceData.cs index 9d5e25c1..251d2615 100644 --- a/AdvancedSharpAdbClient/Models/DeviceData.cs +++ b/AdvancedSharpAdbClient/Models/DeviceData.cs @@ -3,11 +3,11 @@ // using System; +using System.Collections.Generic; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Net; using System.Runtime.CompilerServices; -using System.Text; using System.Text.RegularExpressions; namespace AdvancedSharpAdbClient.Models @@ -16,7 +16,7 @@ namespace AdvancedSharpAdbClient.Models /// Represents a device that is connected to the Android Debug Bridge. /// [DebuggerDisplay($"{{{nameof(GetDebuggerDisplay)}(),nq}}")] - public readonly partial struct DeviceData : IEquatable + public sealed partial class DeviceData() : IEquatable { /// /// A regular expression that can be used to parse the device information that is returned by the Android Debut Bridge. @@ -29,11 +29,11 @@ namespace AdvancedSharpAdbClient.Models private static readonly Regex Regex = DeviceDataRegex(); /// - /// Initializes a new instance of the struct based on + /// Initializes a new instance of the class based on /// data retrieved from the Android Debug Bridge. /// /// The data retrieved from the Android Debug Bridge that represents a device. - public DeviceData(string data) + public DeviceData(string data) : this() { Match match = Regex.Match(data); if (match.Success) @@ -157,32 +157,34 @@ public DeviceData(string data) public override bool Equals([NotNullWhen(true)] object? obj) => obj is DeviceData other && Equals(other); /// - public bool Equals(DeviceData other) => - Serial == other.Serial - && State == other.State - && Model == other.Model - && Product == other.Product - && Name == other.Name - && Features == other.Features - && Usb == other.Usb - && TransportId == other.TransportId - && Message == other.Message; + public bool Equals([NotNullWhen(true)] DeviceData? other) => + (object)this == other || + (other is not null + && Serial == other.Serial + && State == other.State + && Model == other.Model + && Product == other.Product + && Name == other.Name + && Features == other.Features + && Usb == other.Usb + && TransportId == other.TransportId + && Message == other.Message); /// /// Tests whether two objects are equally. /// - /// The structure that is to the left of the equality operator. - /// The structure that is to the right of the equality operator. - /// This operator returns if the two structures are equally; otherwise . - public static bool operator ==(DeviceData? left, DeviceData? right) => left.Equals(right); + /// The class that is to the left of the equality operator. + /// The class that is to the right of the equality operator. + /// This operator returns if the two class are equally; otherwise . + public static bool operator ==(DeviceData? left, DeviceData? right) => EqualityComparer.Default.Equals(left, right); /// /// Tests whether two objects are different. /// - /// The structure that is to the left of the inequality operator. - /// The structure that is to the right of the inequality operator. - /// This operator returns if the two structures are unequally; otherwise . - public static bool operator !=(DeviceData? left, DeviceData? right) => !left.Equals(right); + /// The class that is to the left of the inequality operator. + /// The class that is to the right of the inequality operator. + /// This operator returns if the two class are unequally; otherwise . + public static bool operator !=(DeviceData? left, DeviceData? right) => !(left == right); /// public override int GetHashCode() @@ -208,63 +210,80 @@ public override string ToString() return $"An empty {GetType()} without {nameof(TransportId)} and {nameof(Serial)}"; } - StringBuilder builder = - new StringBuilder(Serial) - .Append('\t'); + DefaultInterpolatedStringHandler builder = new(55, 9); + builder.AppendLiteral(Serial); + builder.AppendFormatted('\t'); - _ = State switch + switch(State) { - DeviceState.Online => builder.Append("device"), - DeviceState.NoPermissions => builder.Append("no permissions"), - DeviceState.Connecting - or DeviceState.Offline - or DeviceState.BootLoader - or DeviceState.Host - or DeviceState.Recovery - or DeviceState.Download - or DeviceState.Sideload - or DeviceState.Unauthorized - or DeviceState.Authorizing - or DeviceState.Unknown => builder.Append(State.ToString().ToLowerInvariant()), - _ => builder.AppendFormat("unknown({0:X})", (int)State), - }; + case DeviceState.Online: + builder.AppendLiteral("device"); + break; + case DeviceState.NoPermissions: + builder.AppendLiteral("no permissions"); + break; + case DeviceState.Connecting + or DeviceState.Offline + or DeviceState.BootLoader + or DeviceState.Host + or DeviceState.Recovery + or DeviceState.Download + or DeviceState.Sideload + or DeviceState.Unauthorized + or DeviceState.Authorizing + or DeviceState.Unknown: + builder.AppendLiteral(State.ToString().ToLowerInvariant()); + break; + default: + builder.AppendLiteral("unknown("); + builder.AppendFormatted((int)State, "X"); + builder.AppendFormatted(')'); + break; + } if (!string.IsNullOrEmpty(Message)) { - _ = builder.Append(' ').Append(Message); + builder.AppendFormatted(' '); + builder.AppendLiteral(Message); } if (!string.IsNullOrEmpty(Usb)) { - _ = builder.Append(" usb:").Append(Usb); + builder.AppendLiteral(" usb:"); + builder.AppendLiteral(Usb); } if (!string.IsNullOrEmpty(Product)) { - _ = builder.Append(" product:").Append(Product); + builder.AppendLiteral(" product:"); + builder.AppendLiteral(Product); } if (!string.IsNullOrEmpty(Model)) { - _ = builder.Append(" model:").Append(Model); + builder.AppendLiteral(" model:"); + builder.AppendLiteral(Model); } if (!string.IsNullOrEmpty(Name)) { - _ = builder.Append(" device:").Append(Name); + builder.AppendLiteral(" device:"); + builder.AppendLiteral(Name); } if (Features?.Length > 0) { - _ = builder.Append(" features:").Append(StringExtensions.Join(',', Features)); + builder.AppendLiteral(" features:"); + builder.AppendLiteral(string.Join(',', Features)); } if (!string.IsNullOrEmpty(TransportId)) { - _ = builder.Append(" transport_id:").Append(TransportId); + builder.AppendLiteral(" transport_id:"); + builder.AppendLiteral(TransportId); } - return builder.ToString(); + return builder.ToStringAndClear(); } /// @@ -274,13 +293,14 @@ or DeviceState.Authorizing /// The name of the parameter with which corresponds. /// The parameter, if it is valid. /// The does not have a valid serial number. - public static ref DeviceData EnsureDevice(ref DeviceData device, [CallerArgumentExpression(nameof(device))] string? paramName = "device") + public static DeviceData EnsureDevice([NotNull] DeviceData? device, [CallerArgumentExpression(nameof(device))] string? paramName = "device") { + ArgumentNullException.ThrowIfNull(device, paramName); if (device.IsEmpty) { - throw new ArgumentOutOfRangeException(nameof(device), "You must specific a transport ID or serial number for the device"); + throw new ArgumentOutOfRangeException(paramName, "You must specific a transport ID or serial number for the device"); } - return ref device; + return device; } /// @@ -301,7 +321,7 @@ public static DeviceState GetStateFromString(string state) return DeviceState.NoPermissions; } // Else, we try to match a value of the DeviceState enumeration. - else if (EnumExtensions.TryParse(state, true, out DeviceState value)) + else if (Enum.TryParse(state, true, out DeviceState value)) { return value; } @@ -316,81 +336,64 @@ public static DeviceState GetStateFromString(string state) /// The value of the for this instance. private string GetDebuggerDisplay() { - StringBuilder builder = - new StringBuilder(nameof(DeviceData)) - .Append(" { "); + DefaultInterpolatedStringHandler builder = new(113, 9); + builder.AppendFormatted(GetType()); + builder.AppendLiteral($" {{ "); if (!string.IsNullOrEmpty(Serial)) { - _ = builder - .Append(nameof(Serial)) - .Append(" = ") - .Append(Serial) - .Append(", "); + builder.AppendLiteral($"{nameof(Serial)} = "); + builder.AppendLiteral(Serial); + builder.AppendLiteral(", "); } - _ = builder - .Append(nameof(State)) - .Append(" = ") - .Append(State); + builder.AppendLiteral($"{nameof(State)} = "); + builder.AppendFormatted(State); if (!string.IsNullOrEmpty(Message)) { - _ = builder - .Append(nameof(Message)) - .Append(" = ") - .Append(Message); + builder.AppendLiteral($"{nameof(Message)} = "); + builder.AppendLiteral(Message); } if (!string.IsNullOrEmpty(Usb)) { - _ = builder - .Append(nameof(Usb)) - .Append(" = ") - .Append(Usb); + builder.AppendLiteral($"{nameof(Usb)} = "); + builder.AppendLiteral(Usb); } if (!string.IsNullOrEmpty(Product)) { - _ = builder - .Append(nameof(Product)) - .Append(" = ") - .Append(Product); + builder.AppendLiteral($"{nameof(Product)} = "); + builder.AppendLiteral(Product); } if (!string.IsNullOrEmpty(Model)) { - _ = builder - .Append(nameof(Model)) - .Append(" = ") - .Append(Model); + builder.AppendLiteral($"{nameof(Model)} = "); + builder.AppendLiteral(Model); } if (!string.IsNullOrEmpty(Name)) { - _ = builder - .Append(nameof(Name)) - .Append(" = ") - .Append(Name); + builder.AppendLiteral($"{nameof(Name)} = "); + builder.AppendLiteral(Name); } if (Features?.Length > 0) { - _ = builder - .Append(nameof(Features)) - .Append(" = ") - .Append(Features); + builder.AppendLiteral($"{nameof(Features)} = "); + builder.AppendLiteral(string.Join(',', Features)); } if (!string.IsNullOrEmpty(TransportId)) { - _ = builder - .Append(nameof(TransportId)) - .Append(" = ") - .Append(TransportId); + builder.AppendLiteral($"{nameof(TransportId)} = "); + builder.AppendLiteral(TransportId); } - return builder.Append(" }").ToString(); + builder.AppendLiteral(" }"); + return builder.ToStringAndClear(); } #if NET7_0_OR_GREATER diff --git a/AdvancedSharpAdbClient/Models/FileStatistics.cs b/AdvancedSharpAdbClient/Models/FileStatistics.cs index 45205a8b..cca2449d 100644 --- a/AdvancedSharpAdbClient/Models/FileStatistics.cs +++ b/AdvancedSharpAdbClient/Models/FileStatistics.cs @@ -17,7 +17,7 @@ namespace AdvancedSharpAdbClient.Models #if HAS_BUFFERS [CollectionBuilder(typeof(EnumerableBuilder), nameof(EnumerableBuilder.FileStatisticsCreator))] #endif - [DebuggerDisplay($"{nameof(FileStatistics)} \\{{ {nameof(Path)} = {{{nameof(Path)}}}, {nameof(FileMode)} = {{{nameof(FileMode)}}}, {nameof(Size)} = {{{nameof(Size)}}}, {nameof(Time)} = {{{nameof(Time)}}} }}")] + [DebuggerDisplay($"{{{nameof(GetType)}().{nameof(Type.ToString)}(),nq}} \\{{ {nameof(Path)} = {{{nameof(Path)}}}, {nameof(FileMode)} = {{{nameof(FileMode)}}}, {nameof(Size)} = {{{nameof(Size)}}}, {nameof(Time)} = {{{nameof(Time)}}} }}")] public struct FileStatistics : IEquatable { /// @@ -99,6 +99,6 @@ public readonly bool Equals(FileStatistics other) => public override readonly int GetHashCode() => HashCode.Combine(Path, FileMode, Size, Time); /// - public override readonly string ToString() => StringExtensions.Join('\t', FileMode.ToPermissionCode(), Size, Time, Path); + public override readonly string ToString() => string.Join('\t', FileMode.ToPermissionCode()!, Size, Time, Path!); } } diff --git a/AdvancedSharpAdbClient/Models/ForwardData.cs b/AdvancedSharpAdbClient/Models/ForwardData.cs index a2ebad6e..3b19b2d4 100644 --- a/AdvancedSharpAdbClient/Models/ForwardData.cs +++ b/AdvancedSharpAdbClient/Models/ForwardData.cs @@ -3,6 +3,7 @@ // using System; +using System.Collections.Generic; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; @@ -11,11 +12,11 @@ namespace AdvancedSharpAdbClient.Models /// /// Contains information about port forwarding configured by the Android Debug Bridge. /// - [DebuggerDisplay($"{nameof(AdbServerStatus)} \\{{ {nameof(SerialNumber)} = {{{nameof(SerialNumber)}}}, {nameof(LocalSpec)} = {{{nameof(LocalSpec)}}}, {nameof(RemoteSpec)} = {{{nameof(RemoteSpec)}}} }}")] - public readonly struct ForwardData : IEquatable + [DebuggerDisplay($"{{{nameof(GetType)}().{nameof(Type.ToString)}(),nq}} \\{{ {nameof(SerialNumber)} = {{{nameof(SerialNumber)}}}, {nameof(LocalSpec)} = {{{nameof(LocalSpec)}}}, {nameof(RemoteSpec)} = {{{nameof(RemoteSpec)}}} }}")] + public sealed class ForwardData : IEquatable { /// - /// Initializes a new instance of the struct. + /// Initializes a new instance of the class. /// /// The serial number of the device for which the port forwarding is configured. /// The that represents the local (PC) endpoint. @@ -76,26 +77,28 @@ public ForwardData(string value) public override bool Equals([NotNullWhen(true)] object? obj) => obj is ForwardData other && Equals(other); /// - public bool Equals(ForwardData other) => - SerialNumber == other.SerialNumber - && Local == other.Local - && Remote == other.Remote; + public bool Equals([NotNullWhen(true)] ForwardData? other) => + (object)this == other || + (other is not null + && SerialNumber == other.SerialNumber + && Local == other.Local + && Remote == other.Remote); /// /// Tests whether two objects are equally. /// - /// The structure that is to the left of the equality operator. - /// The structure that is to the right of the equality operator. - /// This operator returns if the two structures are equally; otherwise . - public static bool operator ==(ForwardData left, ForwardData right) => left.Equals(right); + /// The class that is to the left of the equality operator. + /// The class that is to the right of the equality operator. + /// This operator returns if the two class are equally; otherwise . + public static bool operator ==(ForwardData? left, ForwardData? right) => EqualityComparer.Default.Equals(left, right); /// /// Tests whether two objects are different. /// - /// The structure that is to the left of the inequality operator. - /// The structure that is to the right of the inequality operator. - /// This operator returns if the two structures are unequally; otherwise . - public static bool operator !=(ForwardData left, ForwardData right) => !left.Equals(right); + /// The class that is to the left of the inequality operator. + /// The class that is to the right of the inequality operator. + /// This operator returns if the two class are unequally; otherwise . + public static bool operator !=(ForwardData? left, ForwardData? right) => !(left == right); /// public override int GetHashCode() => HashCode.Combine(SerialNumber, Local, Remote); diff --git a/AdvancedSharpAdbClient/Models/ForwardSpec.cs b/AdvancedSharpAdbClient/Models/ForwardSpec.cs index 1f35075f..b856dd4a 100644 --- a/AdvancedSharpAdbClient/Models/ForwardSpec.cs +++ b/AdvancedSharpAdbClient/Models/ForwardSpec.cs @@ -13,7 +13,7 @@ namespace AdvancedSharpAdbClient.Models /// /// Represents an adb forward specification as used by the various adb port forwarding functions. /// - [DebuggerDisplay($"{nameof(ForwardSpec)} \\{{ {nameof(Protocol)} = {{{nameof(Protocol)}}}, {nameof(Port)} = {{{nameof(Port)}}}, {nameof(SocketName)} = {{{nameof(SocketName)}}}, {nameof(ProcessId)} = {{{nameof(ProcessId)}}} }}")] + [DebuggerDisplay($"{{{nameof(GetType)}().{nameof(Type.ToString)}(),nq}} \\{{ {nameof(Protocol)} = {{{nameof(Protocol)}}}, {nameof(Port)} = {{{nameof(Port)}}}, {nameof(SocketName)} = {{{nameof(SocketName)}}}, {nameof(ProcessId)} = {{{nameof(ProcessId)}}} }}")] public readonly struct ForwardSpec : IEquatable { /// @@ -37,7 +37,7 @@ namespace AdvancedSharpAdbClient.Models /// A which represents a . public ForwardSpec(string spec) { - ExceptionExtensions.ThrowIfNull(spec); + ArgumentNullException.ThrowIfNull(spec); string[] parts = spec.Split(':', 2, StringSplitOptions.RemoveEmptyEntries); diff --git a/AdvancedSharpAdbClient/Models/Framebuffer.cs b/AdvancedSharpAdbClient/Models/Framebuffer.cs index 9ab1f032..06bf3b1c 100644 --- a/AdvancedSharpAdbClient/Models/Framebuffer.cs +++ b/AdvancedSharpAdbClient/Models/Framebuffer.cs @@ -7,7 +7,6 @@ using System.Diagnostics.CodeAnalysis; using System.Drawing; using System.Net; -using System.Text; using System.Threading; namespace AdvancedSharpAdbClient.Models @@ -18,7 +17,7 @@ namespace AdvancedSharpAdbClient.Models /// The device for which to fetch the frame buffer. /// The at which the adb server is listening. /// The to create . - [DebuggerDisplay($"{nameof(Framebuffer)} \\{{ {nameof(Header)} = {{{nameof(Header)}}}, {nameof(Data)} = {{{nameof(Data)}}}, {nameof(Device)} = {{{nameof(Device)}}}, {nameof(EndPoint)} = {{{nameof(EndPoint)}}} }}")] + [DebuggerDisplay($"{{{nameof(GetType)}().{nameof(Type.ToString)}(),nq}} \\{{ {nameof(Header)} = {{{nameof(Header)}}}, {nameof(Data)} = {{{nameof(Data)}}}, {nameof(Device)} = {{{nameof(Device)}}}, {nameof(EndPoint)} = {{{nameof(EndPoint)}}} }}")] public sealed partial class Framebuffer(DeviceData device, EndPoint endPoint, Func adbSocketFactory) : IDisposable, ICloneable, ICloneable { /// @@ -79,7 +78,7 @@ public Framebuffer(DeviceData device) : this(device, AdbClient.DefaultEndPoint, /// /// Gets the device for which to fetch the frame buffer. /// - public DeviceData Device { get; } = DeviceData.EnsureDevice(ref device); + public DeviceData Device { get; } = DeviceData.EnsureDevice(device); /// /// Gets the at which the adb server is listening. @@ -141,7 +140,7 @@ public void Refresh(bool reset = false) } // followed by the actual framebuffer content -#if HAS_BUFFERS +#if COMP_NETSTANDARD2_1 _ = socket.Read(Data.AsSpan(0, (int)Header.Size)); #else _ = socket.Read(Data, (int)Header.Size); @@ -193,7 +192,7 @@ public async Task RefreshAsync(bool reset = false, CancellationToken cancellatio } // followed by the actual framebuffer content -#if HAS_BUFFERS +#if COMP_NETSTANDARD2_1 _ = await socket.ReadAsync(Data.AsMemory(0, (int)Header.Size), cancellationToken).ConfigureAwait(false); #else _ = await socket.ReadAsync(Data, (int)Header.Size, cancellationToken).ConfigureAwait(false); @@ -240,9 +239,6 @@ public async Task RefreshAsync(bool reset = false, CancellationToken cancellatio /// /// A which can be used to cancel the asynchronous task. /// An which represents the framebuffer data. -#if NET - [SupportedOSPlatform("Windows10.0.10240.0")] -#endif public Task ToBitmapAsync(CancellationToken cancellationToken = default) { EnsureNotDisposed(); @@ -255,9 +251,6 @@ public async Task RefreshAsync(bool reset = false, CancellationToken cancellatio /// The target to invoke the code on. /// A which can be used to cancel the asynchronous task. /// An which represents the framebuffer data. -#if NET - [SupportedOSPlatform("Windows10.0.10240.0")] -#endif public Task ToBitmapAsync(CoreDispatcher dispatcher, CancellationToken cancellationToken = default) { EnsureNotDisposed(); @@ -282,18 +275,7 @@ public async Task RefreshAsync(bool reset = false, CancellationToken cancellatio #endif /// - public override string ToString() => - new StringBuilder(nameof(Framebuffer)) - .Append(" { ") - .Append(nameof(Header)) - .Append(" = ") - .Append(Header) - .Append(", ") - .Append(nameof(Data)) - .Append(" = ") - .Append(Data) - .Append(" }") - .ToString(); + public override string ToString() => $"{GetType()} {{ {nameof(Header)} = {Header}, {nameof(Data)} = {Data} }}"; /// private void Dispose(bool disposing) @@ -335,6 +317,6 @@ public void Dispose() /// /// Throws an exception if this has been disposed. /// - private void EnsureNotDisposed() => ExceptionExtensions.ThrowIf(disposed, this); + private void EnsureNotDisposed() => ObjectDisposedException.ThrowIf(disposed, this); } } diff --git a/AdvancedSharpAdbClient/Models/FramebufferHeader.cs b/AdvancedSharpAdbClient/Models/FramebufferHeader.cs index 1c4c553a..f3b9b431 100644 --- a/AdvancedSharpAdbClient/Models/FramebufferHeader.cs +++ b/AdvancedSharpAdbClient/Models/FramebufferHeader.cs @@ -9,7 +9,6 @@ using System.Drawing; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; -using System.Text; #if HAS_WUXC using System.Threading; @@ -274,7 +273,7 @@ public byte this[int index] #endif public Bitmap? ToImage(byte[] buffer) { - ExceptionExtensions.ThrowIfNull(buffer); + ArgumentNullException.ThrowIfNull(buffer); // This happens, for example, when DRM is enabled. In that scenario, no screenshot is taken on the device and an empty // framebuffer is returned; we'll just return null. @@ -308,7 +307,7 @@ public byte this[int index] private PixelFormat StandardizePixelFormat(ref byte[] buffer) { // Initial parameter validation. - ExceptionExtensions.ThrowIfNull(buffer); + ArgumentNullException.ThrowIfNull(buffer); if (buffer.Length < Width * Height * (Bpp / 8)) { @@ -413,12 +412,9 @@ private PixelFormat StandardizePixelFormat(ref byte[] buffer) /// Gets is supported. /// #if NET - [SupportedOSPlatform("Windows10.0.10240.0")] [SupportedOSPlatformGuard("Windows10.0.18362.0")] #endif -#pragma warning disable CA1416 public static bool IsHasThreadAccessSupported { get; } = ApiInformation.IsMethodPresent("Windows.System.DispatcherQueue", "HasThreadAccess"); -#pragma warning restore CA1416 /// /// Converts a array containing the raw frame buffer data to a . @@ -428,9 +424,6 @@ private PixelFormat StandardizePixelFormat(ref byte[] buffer) /// A which can be used to cancel the asynchronous task. /// A that represents the image contained in the frame buffer, or /// if the framebuffer does not contain any data. This can happen when DRM is enabled on the device. -#if NET - [SupportedOSPlatform("Windows10.0.10240.0")] -#endif public Task ToBitmapAsync(byte[] buffer, CoreDispatcher dispatcher, CancellationToken cancellationToken = default) { if (dispatcher.HasThreadAccess) @@ -505,12 +498,9 @@ private PixelFormat StandardizePixelFormat(ref byte[] buffer) /// A which can be used to cancel the asynchronous task. /// A that represents the image contained in the frame buffer, or /// if the framebuffer does not contain any data. This can happen when DRM is enabled on the device. -#if NET - [SupportedOSPlatform("Windows10.0.10240.0")] -#endif public async Task ToBitmapAsync(byte[] buffer, CancellationToken cancellationToken = default) { - ExceptionExtensions.ThrowIfNull(buffer); + ArgumentNullException.ThrowIfNull(buffer); // This happens, for example, when DRM is enabled. In that scenario, no screenshot is taken on the device and an empty // framebuffer is returned; we'll just return null. @@ -541,13 +531,10 @@ private PixelFormat StandardizePixelFormat(ref byte[] buffer) /// A byte array in which the images are stored according to this . /// A which describes how the alpha channel is stored. /// A that describes how the image data is represented in this . -#if NET - [SupportedOSPlatform("Windows10.0.10240.0")] -#endif private BitmapPixelFormat StandardizePixelFormat(byte[] buffer, out BitmapAlphaMode alphaMode) { // Initial parameter validation. - ExceptionExtensions.ThrowIfNull(buffer); + ArgumentNullException.ThrowIfNull(buffer); if (buffer.Length < Width * Height * (Bpp / 8)) { @@ -589,57 +576,35 @@ private BitmapPixelFormat StandardizePixelFormat(byte[] buffer, out BitmapAlphaM /// public override string ToString() { - StringBuilder builder = - new StringBuilder(nameof(FramebufferHeader)) - .Append(" { ") - .Append(nameof(Version)) - .Append(" = ") - .Append(Version) - .Append(", ") - .Append(nameof(Bpp)) - .Append(" = ") - .Append(Bpp); + DefaultInterpolatedStringHandler handler = new(121, 10); + handler.AppendFormatted(GetType()); + handler.AppendLiteral($" {{ {nameof(Version)} = "); + handler.AppendFormatted(Version); + handler.AppendLiteral($", {nameof(Bpp)} = "); + handler.AppendFormatted(Bpp); if (Version >= 2) { - _ = builder - .Append(", ") - .Append(nameof(ColorSpace)) - .Append(" = ") - .Append(ColorSpace); + handler.AppendLiteral($", {nameof(ColorSpace)} = "); + handler.AppendFormatted(ColorSpace); } - return builder - .Append(", ") - .Append(nameof(Size)) - .Append(" = ") - .Append(Size) - .Append(", ") - .Append(nameof(Width)) - .Append(" = ") - .Append(Width) - .Append(", ") - .Append(nameof(Height)) - .Append(" = ") - .Append(Height) - .Append(", ") - .Append(nameof(Red)) - .Append(" = ") - .Append(Red) - .Append(", ") - .Append(nameof(Blue)) - .Append(" = ") - .Append(Blue) - .Append(", ") - .Append(nameof(Green)) - .Append(" = ") - .Append(Green) - .Append(", ") - .Append(nameof(Alpha)) - .Append(" = ") - .Append(Alpha) - .Append(" }") - .ToString(); + handler.AppendLiteral($", {nameof(Size)} = "); + handler.AppendFormatted(Size); + handler.AppendLiteral($", {nameof(Width)} = "); + handler.AppendFormatted(Width); + handler.AppendLiteral($", {nameof(Height)} = "); + handler.AppendFormatted(Height); + handler.AppendLiteral($", {nameof(Red)} = "); + handler.AppendFormatted(Red); + handler.AppendLiteral($", {nameof(Blue)} = "); + handler.AppendFormatted(Blue); + handler.AppendLiteral($", {nameof(Green)} = "); + handler.AppendFormatted(Green); + handler.AppendLiteral($", {nameof(Alpha)} = "); + handler.AppendFormatted(Alpha); + handler.AppendLiteral(" }"); + return handler.ToStringAndClear(); } /// diff --git a/AdvancedSharpAdbClient/Models/InstallProgress.EventArgs.cs b/AdvancedSharpAdbClient/Models/InstallProgress.EventArgs.cs index 6cba3240..088cbedf 100644 --- a/AdvancedSharpAdbClient/Models/InstallProgress.EventArgs.cs +++ b/AdvancedSharpAdbClient/Models/InstallProgress.EventArgs.cs @@ -5,8 +5,8 @@ using System; using System.Collections.Generic; using System.Diagnostics; +using System.Runtime.CompilerServices; using System.Runtime.InteropServices; -using System.Text; namespace AdvancedSharpAdbClient.Models { @@ -14,7 +14,7 @@ namespace AdvancedSharpAdbClient.Models /// Represents the state of apk installation. /// /// The state of the installation. - [DebuggerDisplay($"{nameof(SyncProgressChangedEventArgs)} \\{{ {nameof(State)} = {{{nameof(State)}}}, {nameof(PackageFinished)} = {{{nameof(PackageFinished)}}}, {nameof(PackageRequired)} = {{{nameof(PackageRequired)}}}, {nameof(UploadProgress)} = {{{nameof(UploadProgress)}}} }}")] + [DebuggerDisplay($"{{{nameof(GetType)}().{nameof(Type.ToString)}(),nq}} \\{{ {nameof(State)} = {{{nameof(State)}}}, {nameof(PackageFinished)} = {{{nameof(PackageFinished)}}}, {nameof(PackageRequired)} = {{{nameof(PackageRequired)}}}, {nameof(UploadProgress)} = {{{nameof(UploadProgress)}}} }}")] public sealed class InstallProgressEventArgs(PackageInstallProgressState state) : EventArgs { /// @@ -88,24 +88,31 @@ public override string ToString() split.Add(c); } - StringBuilder builder = + DefaultInterpolatedStringHandler builder = new(4, 4); #if NET - new StringBuilder().Append(CollectionsMarshal.AsSpan(split)); + builder.AppendFormatted(CollectionsMarshal.AsSpan(split)); +#elif HAS_BUFFERS + builder.AppendFormatted([.. split]); #else - new(new string(split.ToArray())); + builder.AppendLiteral(new string([.. split])); #endif if (PackageRequired > 0) { - _ = builder.Append(' ').Append(PackageFinished).Append('/').Append(PackageRequired); + builder.AppendFormatted(' '); + builder.AppendFormatted(PackageFinished); + builder.AppendFormatted('/'); + builder.AppendFormatted(PackageRequired); } if (UploadProgress > 0) { - _ = builder.Append(' ').Append(UploadProgress).Append('%'); + builder.AppendFormatted(' '); + builder.AppendFormatted(UploadProgress); + builder.AppendFormatted('%'); } - return builder.ToString(); + return builder.ToStringAndClear(); } } } diff --git a/AdvancedSharpAdbClient/Models/NamespaceDoc.cs b/AdvancedSharpAdbClient/Models/NamespaceDoc.cs index 6a3ebf5e..6b178527 100644 --- a/AdvancedSharpAdbClient/Models/NamespaceDoc.cs +++ b/AdvancedSharpAdbClient/Models/NamespaceDoc.cs @@ -3,7 +3,6 @@ // using System.ComponentModel; -using System.Runtime.CompilerServices; namespace AdvancedSharpAdbClient.Models { @@ -11,7 +10,12 @@ namespace AdvancedSharpAdbClient.Models /// The classes in this namespace provide models for . /// /// Copyright (c) The Android Open Source Project, Ryan Conrad, Quamotion, yungd1plomat, wherewhere. All rights reserved. - [CompilerGenerated] [EditorBrowsable(EditorBrowsableState.Never)] - internal abstract class NamespaceDoc : AdvancedSharpAdbClient.NamespaceDoc; + internal abstract class NamespaceDoc : AdvancedSharpAdbClient.NamespaceDoc + { + /// + /// The name of the namespace . + /// + public new const string Name = $"{AdvancedSharpAdbClient.NamespaceDoc.Name}.{nameof(Models)}"; + } } diff --git a/AdvancedSharpAdbClient/Models/ShellStream.cs b/AdvancedSharpAdbClient/Models/ShellStream.cs index 98829755..09c6c93a 100644 --- a/AdvancedSharpAdbClient/Models/ShellStream.cs +++ b/AdvancedSharpAdbClient/Models/ShellStream.cs @@ -5,7 +5,6 @@ using System; using System.Diagnostics; using System.IO; -using System.Text; using System.Threading; namespace AdvancedSharpAdbClient.Models @@ -34,7 +33,7 @@ public partial class ShellStream : Stream /// if the should close the stream when closed; otherwise, . public ShellStream(Stream inner, bool closeStream = false) { - ExceptionExtensions.ThrowIfNull(inner); + ArgumentNullException.ThrowIfNull(inner); if (!inner.CanRead) { @@ -472,14 +471,7 @@ async Task ReadAsync(byte[] buffer, int offset, int count, CancellationToke public override void Write(byte[] buffer, int offset, int count) => Inner.Write(buffer, offset, count); /// - public override string ToString() => - new StringBuilder(nameof(ShellStream)) - .Append(" { ") - .Append(nameof(Inner)) - .Append(" = ") - .Append(Inner) - .Append(" }") - .ToString(); + public override string ToString() => $"{GetType()} {{ {nameof(Inner)} = {Inner} }}"; /// protected override void Dispose(bool disposing) diff --git a/AdvancedSharpAdbClient/Models/SyncService.EventArgs.cs b/AdvancedSharpAdbClient/Models/SyncService.EventArgs.cs index ea975b31..d62dd0e9 100644 --- a/AdvancedSharpAdbClient/Models/SyncService.EventArgs.cs +++ b/AdvancedSharpAdbClient/Models/SyncService.EventArgs.cs @@ -10,7 +10,7 @@ namespace AdvancedSharpAdbClient.Models /// /// Provides data for the interface. /// - [DebuggerDisplay($"{nameof(SyncProgressChangedEventArgs)} \\{{ {nameof(ReceivedBytesSize)} = {{{nameof(ReceivedBytesSize)}}}, {nameof(TotalBytesToReceive)} = {{{nameof(TotalBytesToReceive)}}}, {nameof(ProgressPercentage)} = {{{nameof(ProgressPercentage)}}} }}")] + [DebuggerDisplay($"{{{nameof(GetType)}().{nameof(Type.ToString)}(),nq}} \\{{ {nameof(ReceivedBytesSize)} = {{{nameof(ReceivedBytesSize)}}}, {nameof(TotalBytesToReceive)} = {{{nameof(TotalBytesToReceive)}}}, {nameof(ProgressPercentage)} = {{{nameof(ProgressPercentage)}}} }}")] public sealed class SyncProgressChangedEventArgs(long current, long total) : EventArgs { /// diff --git a/AdvancedSharpAdbClient/NamespaceDoc.cs b/AdvancedSharpAdbClient/NamespaceDoc.cs index 369dd1e1..f1130f5b 100644 --- a/AdvancedSharpAdbClient/NamespaceDoc.cs +++ b/AdvancedSharpAdbClient/NamespaceDoc.cs @@ -3,7 +3,6 @@ // using System.ComponentModel; -using System.Runtime.CompilerServices; namespace AdvancedSharpAdbClient { @@ -43,7 +42,12 @@ namespace AdvancedSharpAdbClient /// Copyright (c) The Android Open Source Project, Ryan Conrad, Quamotion, yungd1plomat, wherewhere. All rights reserved. /// /// - [CompilerGenerated] [EditorBrowsable(EditorBrowsableState.Never)] - internal abstract class NamespaceDoc; + internal abstract class NamespaceDoc + { + /// + /// The name of the namespace . + /// + public const string Name = nameof(AdvancedSharpAdbClient); + } } diff --git a/AdvancedSharpAdbClient/Polyfills/Attributes/SerializableAttribute.cs b/AdvancedSharpAdbClient/Polyfills/Attributes/SerializableAttribute.cs index 38818fdb..5411dede 100644 --- a/AdvancedSharpAdbClient/Polyfills/Attributes/SerializableAttribute.cs +++ b/AdvancedSharpAdbClient/Polyfills/Attributes/SerializableAttribute.cs @@ -1,4 +1,4 @@ -#if (NETSTANDARD && !NETSTANDARD2_0_OR_GREATER) || (NETCORE && !UAP10_0_15138_0) +#if !NETFRAMEWORK && !NETCOREAPP && !COMP_NETSTANDARD2_0 // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. diff --git a/AdvancedSharpAdbClient/Polyfills/DnsEndPoint.cs b/AdvancedSharpAdbClient/Polyfills/DnsEndPoint.cs index 939c2fb5..e28b27cf 100644 --- a/AdvancedSharpAdbClient/Polyfills/DnsEndPoint.cs +++ b/AdvancedSharpAdbClient/Polyfills/DnsEndPoint.cs @@ -33,7 +33,7 @@ public DnsEndPoint(string host, int port) : this(host, port, AddressFamily.Unspe /// The parameter contains an empty string.-or- is Unknown. public DnsEndPoint(string host, int port, AddressFamily addressFamily) { - ExceptionExtensions.ThrowIfNull(host); + ArgumentNullException.ThrowIfNull(host); if (port is < IPEndPoint.MinPort or > IPEndPoint.MaxPort) { diff --git a/AdvancedSharpAdbClient/Polyfills/Extensions/DateTimeExtensions.cs b/AdvancedSharpAdbClient/Polyfills/Extensions/DateTimeExtensions.cs index 73a22264..2bf0e1a3 100644 --- a/AdvancedSharpAdbClient/Polyfills/Extensions/DateTimeExtensions.cs +++ b/AdvancedSharpAdbClient/Polyfills/Extensions/DateTimeExtensions.cs @@ -55,51 +55,53 @@ internal static class DateTimeExtensions /// public static DateTime Epoch { get; } = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc); -#if NET20 -#pragma warning disable CS1574 -#endif +#if NETFRAMEWORK && !NET46_OR_GREATER /// - /// Converts a Unix time expressed as the number of seconds that have elapsed - /// since 1970-01-01T00:00:00Z to a value. + /// The extension for the struct. /// - /// A Unix time, expressed as the number of seconds that have elapsed - /// since 1970-01-01T00:00:00Z (January 1, 1970, at 12:00 AM UTC). For Unix times before this date, - /// its value is negative. - /// A date and time value that represents the same moment in time as the Unix time. - /// is less than -62,135,596,800. - /// -or- is greater than 253,402,300,799. - /// The Offset property value of the returned instance is - /// , which represents Coordinated Universal Time. You can convert it to the time in - /// a specific time zone by calling the method. - public static DateTimeOffset FromUnixTimeSeconds(long seconds) + /// The to extend. + extension(DateTimeOffset dateTimeOffset) { -#if NETFRAMEWORK && !NET46_OR_GREATER - if (seconds is < UnixMinSeconds or > UnixMaxSeconds) +#if NET20 +#pragma warning disable CS1574 +#endif + /// + /// Converts a Unix time expressed as the number of seconds that have elapsed + /// since 1970-01-01T00:00:00Z to a value. + /// + /// A Unix time, expressed as the number of seconds that have elapsed + /// since 1970-01-01T00:00:00Z (January 1, 1970, at 12:00 AM UTC). For Unix times before this date, + /// its value is negative. + /// A date and time value that represents the same moment in time as the Unix time. + /// is less than -62,135,596,800. + /// -or- is greater than 253,402,300,799. + /// The Offset property value of the returned instance is + /// , which represents Coordinated Universal Time. You can convert it to the time in + /// a specific time zone by calling the method. + public static DateTimeOffset FromUnixTimeSeconds(long seconds) { - throw new ArgumentOutOfRangeException(nameof(seconds), - $"Valid values are between {UnixMinSeconds} and {UnixMaxSeconds}, inclusive."); - } + if (seconds is < UnixMinSeconds or > UnixMaxSeconds) + { + throw new ArgumentOutOfRangeException(nameof(seconds), + $"Valid values are between {UnixMinSeconds} and {UnixMaxSeconds}, inclusive."); + } - long ticks = (seconds * TimeSpan.TicksPerSecond) + UnixEpochTicks; - return new DateTimeOffset(ticks, TimeSpan.Zero); -#else - return DateTimeOffset.FromUnixTimeSeconds(seconds); -#endif - } + long ticks = (seconds * TimeSpan.TicksPerSecond) + UnixEpochTicks; + return new DateTimeOffset(ticks, TimeSpan.Zero); + } #if NET20 #pragma warning restore CS1574 #endif -#if NETFRAMEWORK && !NET46_OR_GREATER - /// - /// Returns the number of seconds that have elapsed since 1970-01-01T00:00:00Z. - /// - /// The DateTimeOffset - /// The number of seconds that have elapsed since 1970-01-01T00:00:00Z. - public static long ToUnixTimeSeconds(this DateTimeOffset dateTimeOffset) - { - long seconds = dateTimeOffset.UtcDateTime.Ticks / TimeSpan.TicksPerSecond; - return seconds - UnixEpochSeconds; + /// + /// Returns the number of seconds that have elapsed since 1970-01-01T00:00:00Z. + /// + /// The number of seconds that have elapsed since 1970-01-01T00:00:00Z. + public long ToUnixTimeSeconds() + { + long seconds = dateTimeOffset.UtcDateTime.Ticks / TimeSpan.TicksPerSecond; + return seconds - UnixEpochSeconds; + } } #endif } diff --git a/AdvancedSharpAdbClient/Polyfills/Extensions/EnumExtensions.cs b/AdvancedSharpAdbClient/Polyfills/Extensions/EnumExtensions.cs index 921a6e1a..b4bbe219 100644 --- a/AdvancedSharpAdbClient/Polyfills/Extensions/EnumExtensions.cs +++ b/AdvancedSharpAdbClient/Polyfills/Extensions/EnumExtensions.cs @@ -1,4 +1,5 @@ -// +#if NETFRAMEWORK && !NET40_OR_GREATER +// // Copyright (c) The Android Open Source Project, Ryan Conrad, Quamotion, yungd1plomat, wherewhere. All rights reserved. // @@ -14,44 +15,38 @@ namespace AdvancedSharpAdbClient.Polyfills internal static class EnumExtensions { /// - /// Converts the string representation of the name or numeric value of one or more - /// enumerated constants to an equivalent enumerated object. A parameter specifies - /// whether the operation is case-sensitive. The return value indicates whether the - /// conversion succeeded. + /// The extension for the class. /// - /// The enumeration type to which to convert . - /// The string representation of the enumeration name or underlying value to convert. - /// to ignore case; to consider case. - /// When this method returns, contains an object of type whose - /// value is represented by if the parse operation succeeds. If the parse operation fails, - /// contains the default value of the underlying type of . This parameter is passed uninitialized. - /// if the value parameter was converted successfully; otherwise, . - /// is not an enumeration type. - public static bool TryParse(string value, bool ignoreCase, out TEnum result) where TEnum : struct + extension(Enum) { -#if NETFRAMEWORK && !NET40_OR_GREATER - string strTypeFixed = value.Replace(' ', '_'); - if (Enum.IsDefined(typeof(TEnum), strTypeFixed)) + /// + /// Converts the string representation of the name or numeric value of one or more + /// enumerated constants to an equivalent enumerated object. A parameter specifies + /// whether the operation is case-sensitive. The return value indicates whether the + /// conversion succeeded. + /// + /// The enumeration type to which to convert . + /// The string representation of the enumeration name or underlying value to convert. + /// to ignore case; to consider case. + /// When this method returns, contains an object of type whose + /// value is represented by if the parse operation succeeds. If the parse operation fails, + /// contains the default value of the underlying type of . This parameter is passed uninitialized. + /// if the value parameter was converted successfully; otherwise, . + /// is not an enumeration type. + public static bool TryParse(string value, bool ignoreCase, out TEnum result) where TEnum : struct { - result = (TEnum)Enum.Parse(typeof(TEnum), strTypeFixed, ignoreCase); - return true; - } - else - { - foreach (string str in Enum.GetNames(typeof(TEnum))) + try + { + result = (TEnum)Enum.Parse(typeof(TEnum), value, ignoreCase); + return true; + } + catch (Exception ex) when (typeof(TEnum).IsEnum || ex is not ArgumentException) { - if (str.Equals(strTypeFixed, StringComparison.OrdinalIgnoreCase)) - { - result = (TEnum)Enum.Parse(typeof(TEnum), str, ignoreCase); - return true; - } } result = default; return false; } -#else - return Enum.TryParse(value, ignoreCase, out result); -#endif } } } +#endif \ No newline at end of file diff --git a/AdvancedSharpAdbClient/Polyfills/Extensions/EnumerableExtensions.cs b/AdvancedSharpAdbClient/Polyfills/Extensions/EnumerableExtensions.cs index dce6803d..6b81a70d 100644 --- a/AdvancedSharpAdbClient/Polyfills/Extensions/EnumerableExtensions.cs +++ b/AdvancedSharpAdbClient/Polyfills/Extensions/EnumerableExtensions.cs @@ -28,8 +28,8 @@ internal static class EnumerableExtensions /// or is null. public static void AddRange(this ICollection source, params IEnumerable collection) { - ExceptionExtensions.ThrowIfNull(source); - ExceptionExtensions.ThrowIfNull(collection); + ArgumentNullException.ThrowIfNull(source); + ArgumentNullException.ThrowIfNull(collection); if (source is List list) { @@ -70,23 +70,6 @@ public static Task ToArrayAsync(this IEnumerable - /// Asynchronously creates a from an . - /// - /// The type of the elements of . - /// The to create a from. - /// A which can be used to cancel the asynchronous operation. - /// A which returns a that contains elements from the input sequence. - public static async ValueTask> ToListAsync(this IAsyncEnumerable source, CancellationToken cancellationToken = default) - { - List list = []; - await foreach (TSource item in source.WithCancellation(cancellationToken).ConfigureAwait(false)) - { - list.Add(item); - } - return list; - } - /// /// Returns the input typed as . /// @@ -94,7 +77,7 @@ public static async ValueTask> ToListAsync(this IAsyncEnu /// The sequence to type as . /// A which can be used to cancel the asynchronous operation. /// The input sequence typed as . - public static async IAsyncEnumerable AsEnumerableAsync(this IEnumerable source, [EnumeratorCancellation] CancellationToken cancellationToken = default) + public static async IAsyncEnumerable ToAsyncEnumerable(this IEnumerable source, [EnumeratorCancellation] CancellationToken cancellationToken = default) { using IEnumerator enumerator = source.GetEnumerator(); while (!cancellationToken.IsCancellationRequested && enumerator.MoveNext()) @@ -111,7 +94,7 @@ public static async IAsyncEnumerable AsEnumerableAsync(this IE /// The sequence to type as . /// A which can be used to cancel the asynchronous operation. /// The input sequence typed as . - public static async IAsyncEnumerable AsEnumerableAsync(this Task> source, [EnumeratorCancellation] CancellationToken cancellationToken = default) + public static async IAsyncEnumerable ToAsyncEnumerable(this Task> source, [EnumeratorCancellation] CancellationToken cancellationToken = default) { using IEnumerator enumerator = await source.ContinueWith(x => x.Result.GetEnumerator()).ConfigureAwait(false); while (!cancellationToken.IsCancellationRequested && enumerator.MoveNext()) diff --git a/AdvancedSharpAdbClient/Polyfills/Extensions/ExceptionExtensions.cs b/AdvancedSharpAdbClient/Polyfills/Extensions/ExceptionExtensions.cs index ec05e085..7f8391f7 100644 --- a/AdvancedSharpAdbClient/Polyfills/Extensions/ExceptionExtensions.cs +++ b/AdvancedSharpAdbClient/Polyfills/Extensions/ExceptionExtensions.cs @@ -1,4 +1,5 @@ -// +#if !NET8_0_OR_GREATER +// // Copyright (c) The Android Open Source Project, Ryan Conrad, Quamotion, yungd1plomat, wherewhere. All rights reserved. // @@ -16,98 +17,99 @@ namespace AdvancedSharpAdbClient.Polyfills [EditorBrowsable(EditorBrowsableState.Never)] internal static class ExceptionExtensions { +#if !NET6_0_OR_GREATER /// - /// Throws an if is null. + /// The extension for the class. /// - /// The reference type argument to validate as non-null. - /// The name of the parameter with which corresponds. - public static void ThrowIfNull([NotNull] object? argument, [CallerArgumentExpression(nameof(argument))] string? paramName = null) + extension(ArgumentNullException) { -#if NET6_0_OR_GREATER - ArgumentNullException.ThrowIfNull(argument, paramName); -#else - if (argument is null) + /// + /// Throws an if is null. + /// + /// The reference type argument to validate as non-null. + /// The name of the parameter with which corresponds. + public static void ThrowIfNull([NotNull] object? argument, [CallerArgumentExpression(nameof(argument))] string? paramName = null) { - throw new ArgumentNullException(paramName); + if (argument is null) + { + throw new ArgumentNullException(paramName); + } } -#endif } +#endif /// - /// Throws an if is greater than . + /// The extension for the class. /// - /// The argument to validate as less or equal than . - /// The value to compare with . - /// The name of the parameter with which corresponds. - public static void ThrowIfGreaterThan(T value, T other, [CallerArgumentExpression(nameof(value))] string? paramName = null) - where T : IComparable + extension(ArgumentOutOfRangeException) { -#if NET8_0_OR_GREATER - ArgumentOutOfRangeException.ThrowIfGreaterThan(value, other, paramName); -#else - if (value.CompareTo(other) > 0) + /// + /// Throws an if is greater than . + /// + /// The argument to validate as less or equal than . + /// The value to compare with . + /// The name of the parameter with which corresponds. + public static void ThrowIfGreaterThan(T value, T other, [CallerArgumentExpression(nameof(value))] string? paramName = null) + where T : IComparable { - throw new ArgumentOutOfRangeException(paramName, value, $"'{paramName}' must be less than or equal to '{value}'."); + if (value.CompareTo(other) > 0) + { + throw new ArgumentOutOfRangeException(paramName, value, $"'{paramName}' must be less than or equal to '{value}'."); + } } -#endif - } - /// - /// Throws an if is less than . - /// - /// The argument to validate as greater than or equal than . - /// The value to compare with . - /// The name of the parameter with which corresponds. - public static void ThrowIfLessThan(T value, T other, [CallerArgumentExpression(nameof(value))] string? paramName = null) - where T : IComparable - { -#if NET8_0_OR_GREATER - ArgumentOutOfRangeException.ThrowIfLessThan(value, other, paramName); -#else - if (value.CompareTo(other) < 0) + /// + /// Throws an if is less than . + /// + /// The argument to validate as greater than or equal than . + /// The value to compare with . + /// The name of the parameter with which corresponds. + public static void ThrowIfLessThan(T value, T other, [CallerArgumentExpression(nameof(value))] string? paramName = null) + where T : IComparable { - throw new ArgumentOutOfRangeException(paramName, value, $"'{paramName}' must be greater than or equal to '{value}'."); + if (value.CompareTo(other) < 0) + { + throw new ArgumentOutOfRangeException(paramName, value, $"'{paramName}' must be greater than or equal to '{value}'."); + } } -#endif - } - /// - /// Throws an if is negative. - /// - /// The argument to validate as non-negative. - /// The name of the parameter with which corresponds. - public static void ThrowIfNegative(T value, [CallerArgumentExpression(nameof(value))] string? paramName = null) -#if NET8_0_OR_GREATER - where T : INumberBase - { - ArgumentOutOfRangeException.ThrowIfNegative(value, paramName); -#else - where T : struct, IComparable - { - if (value.CompareTo(default) < 0) + /// + /// Throws an if is negative. + /// + /// The argument to validate as non-negative. + /// The name of the parameter with which corresponds. + public static void ThrowIfNegative(T value, [CallerArgumentExpression(nameof(value))] string? paramName = null) + where T : struct, IComparable { - throw new ArgumentOutOfRangeException(paramName, value, $"{paramName} ('{value}') must be a non-negative value."); + if (value.CompareTo(default) < 0) + { + throw new ArgumentOutOfRangeException(paramName, value, $"{paramName} ('{value}') must be a non-negative value."); + } } -#endif } +#if !NET7_0_OR_GREATER /// - /// Throws an if the specified is . + /// The extension for the class. /// - /// The condition to evaluate. - /// The object whose type's full name should be included in any resulting . - /// The is . - [StackTraceHidden] - public static void ThrowIf([DoesNotReturnIf(true)] bool condition, object instance) + extension(ObjectDisposedException) { -#if NET7_0_OR_GREATER - ObjectDisposedException.ThrowIf(condition, instance); -#else - if (condition) + /// + /// Throws an if the specified is . + /// + /// The condition to evaluate. + /// The object whose type's full name should be included in any resulting . + /// The is . + [StackTraceHidden] + public static void ThrowIf([DoesNotReturnIf(true)] bool condition, object instance) { - throw new ObjectDisposedException(instance?.GetType().FullName); + if (condition) + { + throw new ObjectDisposedException(instance?.GetType().FullName); + } } -#endif } +#endif } } +#endif \ No newline at end of file diff --git a/AdvancedSharpAdbClient/Polyfills/Extensions/OperatingSystemExtensions.cs b/AdvancedSharpAdbClient/Polyfills/Extensions/OperatingSystemExtensions.cs new file mode 100644 index 00000000..a82a07a0 --- /dev/null +++ b/AdvancedSharpAdbClient/Polyfills/Extensions/OperatingSystemExtensions.cs @@ -0,0 +1,75 @@ +#if !NET +// +// Copyright (c) The Android Open Source Project, Ryan Conrad, Quamotion, yungd1plomat, wherewhere. All rights reserved. +// + +using System; +using System.ComponentModel; +using System.Runtime.InteropServices; + +namespace AdvancedSharpAdbClient.Polyfills +{ + /// + /// Provides extension methods for the class. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + internal static class OperatingSystemExtensions + { + /// + /// The extension for the class. + /// + extension(OperatingSystem) + { + /// + /// Indicates whether the current application is running on Windows. + /// + public static bool IsWindows() => +#if NETCORE && !UAP10_0_15138_0 + true; +#elif !NETFRAMEWORK || NET48_OR_GREATER + RuntimeInformation.IsOSPlatform(OSPlatform.Windows); +#else + Environment.OSVersion.Platform + is PlatformID.Win32S + or PlatformID.Win32Windows + or PlatformID.Win32NT + or PlatformID.WinCE + or PlatformID.Xbox; +#endif + + /// + /// Indicates whether the current application is running on Linux. + /// + public static bool IsLinux() => +#if NETCORE && !UAP10_0_15138_0 + false; +#elif !NETFRAMEWORK || NET48_OR_GREATER + RuntimeInformation.IsOSPlatform(OSPlatform.Linux); +#else + Environment.OSVersion.Platform == PlatformID.Unix; +#endif + + /// + /// Indicates whether the current application is running on macOS. + /// + public static bool IsMacOS() => +#if NETCORE && !UAP10_0_15138_0 + false; +#elif !NETFRAMEWORK || NET48_OR_GREATER + RuntimeInformation.IsOSPlatform(OSPlatform.OSX); +#else + Environment.OSVersion.Platform == PlatformID.MacOSX; +#endif + /// + /// Indicates whether the current application is running on FreeBSD. + /// + public static bool IsFreeBSD() => +#if NETCOREAPP3_0_OR_GREATER + RuntimeInformation.IsOSPlatform(OSPlatform.FreeBSD); +#else + false; +#endif + } + } +} +#endif \ No newline at end of file diff --git a/AdvancedSharpAdbClient/Polyfills/Extensions/SocketExtensions.cs b/AdvancedSharpAdbClient/Polyfills/Extensions/SocketExtensions.cs index d6d86b6f..51d0a568 100644 --- a/AdvancedSharpAdbClient/Polyfills/Extensions/SocketExtensions.cs +++ b/AdvancedSharpAdbClient/Polyfills/Extensions/SocketExtensions.cs @@ -5,6 +5,7 @@ using System; using System.ComponentModel; +using System.Net; using System.Net.Sockets; using System.Threading; @@ -16,6 +17,18 @@ namespace AdvancedSharpAdbClient.Polyfills [EditorBrowsable(EditorBrowsableState.Never)] internal static class SocketExtensions { +#if !NET6_0_OR_GREATER + /// + /// Establishes a connection to a remote host. + /// + /// The socket to connect. + /// The endpoint to connect to. + /// A cancellation token that can be used to cancel the asynchronous operation. + /// An asynchronous task that completes when the connection is established. + public static Task ConnectAsync(this Socket socket, EndPoint remoteEP, CancellationToken cancellationToken) => + Task.Run(() => socket.Connect(remoteEP), cancellationToken); +#endif + /// /// Asynchronously receives data from a connected socket. /// @@ -26,11 +39,7 @@ internal static class SocketExtensions /// Cancelling the task will also close the socket. /// A which returns the number of bytes received. public static Task ReceiveAsync(this Socket socket, byte[] buffer, SocketFlags socketFlags, CancellationToken cancellationToken = default) => -#if HAS_BUFFERS - socket.ReceiveAsync(buffer.AsMemory(), socketFlags, cancellationToken).AsTask(); -#else socket.ReceiveAsync(buffer, 0, buffer.Length, socketFlags, cancellationToken); -#endif /// /// Asynchronously receives data from a connected socket. @@ -43,11 +52,7 @@ public static Task ReceiveAsync(this Socket socket, byte[] buffer, SocketFl /// Cancelling the task will also close the socket. /// A which returns the number of bytes received. public static Task ReceiveAsync(this Socket socket, byte[] buffer, int size, SocketFlags socketFlags, CancellationToken cancellationToken = default) => -#if HAS_BUFFERS - socket.ReceiveAsync(buffer.AsMemory(0, size), socketFlags, cancellationToken).AsTask(); -#else socket.ReceiveAsync(buffer, 0, size, socketFlags, cancellationToken); -#endif /// /// Asynchronously receives data from a connected socket. @@ -98,7 +103,7 @@ public static Task ReceiveAsync(this Socket socket, byte[] buffer, int offs return taskCompletionSource.Task; #else - return Task.Factory.StartNew(() => socket.Receive(buffer, offset, size, socketFlags), cancellationToken, TaskCreationOptions.None, TaskScheduler.Default); + return Task.Run(() => socket.Receive(buffer, offset, size, socketFlags), cancellationToken); #endif } @@ -112,11 +117,7 @@ public static Task ReceiveAsync(this Socket socket, byte[] buffer, int offs /// Cancelling the task will also close the socket. /// A which returns the number of bytes sent. public static Task SendAsync(this Socket socket, byte[] buffer, SocketFlags socketFlags, CancellationToken cancellationToken = default) => -#if HAS_BUFFERS - socket.SendAsync(buffer.AsMemory(), socketFlags, cancellationToken).AsTask(); -#else socket.SendAsync(buffer, 0, buffer.Length, socketFlags, cancellationToken); -#endif /// /// Asynchronously sends data to a connected socket. @@ -129,11 +130,7 @@ public static Task SendAsync(this Socket socket, byte[] buffer, SocketFlags /// Cancelling the task will also close the socket. /// A which returns the number of bytes sent. public static Task SendAsync(this Socket socket, byte[] buffer, int size, SocketFlags socketFlags, CancellationToken cancellationToken = default) => -#if HAS_BUFFERS - socket.SendAsync(buffer.AsMemory(0, size), socketFlags, cancellationToken).AsTask(); -#else socket.SendAsync(buffer, 0, size, socketFlags, cancellationToken); -#endif /// /// Asynchronously sends data to a connected socket. @@ -183,7 +180,7 @@ public static Task SendAsync(this Socket socket, byte[] buffer, int offset, return taskCompletionSource.Task; #else - return Task.Factory.StartNew(() => socket.Send(buffer, offset, size, socketFlags), cancellationToken, TaskCreationOptions.None, TaskScheduler.Default); + return Task.Run(() => socket.Send(buffer, offset, size, socketFlags), cancellationToken); #endif } } diff --git a/AdvancedSharpAdbClient/Polyfills/Extensions/StringExtensions.cs b/AdvancedSharpAdbClient/Polyfills/Extensions/StringExtensions.cs index 0afed780..62586705 100644 --- a/AdvancedSharpAdbClient/Polyfills/Extensions/StringExtensions.cs +++ b/AdvancedSharpAdbClient/Polyfills/Extensions/StringExtensions.cs @@ -1,10 +1,12 @@ -// +#if !HAS_FULLSTRING +// // Copyright (c) The Android Open Source Project, Ryan Conrad, Quamotion, yungd1plomat, wherewhere. All rights reserved. // using System; using System.Collections.Generic; using System.ComponentModel; +using System.Diagnostics.CodeAnalysis; using System.Text; namespace AdvancedSharpAdbClient.Polyfills @@ -16,255 +18,311 @@ namespace AdvancedSharpAdbClient.Polyfills internal static class StringExtensions { /// - /// Indicates whether a specified string is , empty, or consists only of white-space characters. + /// The extension for the class. /// - /// The string to test. - /// if the parameter is or - /// , or if consists exclusively of white-space characters. - public static bool IsNullOrWhiteSpace(string? value) + /// The to extend. + extension(string text) { #if NETFRAMEWORK && !NET40_OR_GREATER - if (value == null) + /// + /// Indicates whether a specified string is , empty, or consists only of white-space characters. + /// + /// The string to test. + /// if the parameter is or + /// , or if consists exclusively of white-space characters. + public static bool IsNullOrWhiteSpace([NotNullWhen(false)] string? value) { - return true; - } + if (value == null) + { + return true; + } - for (int i = 0; i < value.Length; i++) - { - if (!char.IsWhiteSpace(value[i])) + for (int i = 0; i < value.Length; i++) { - return false; + if (!char.IsWhiteSpace(value[i])) + { + return false; + } } - } - return true; -#else - return string.IsNullOrWhiteSpace(value); + return true; + } #endif - } -#if !HAS_FULLSTRING - /// - /// Returns a value indicating whether a specified string occurs within this string, using the specified comparison rules. - /// - /// A sequence in which to locate a value. - /// The string to seek. - /// One of the enumeration values that specifies the rules to use in the comparison. - /// if the parameter occurs within this string, - /// or if is the empty string (""); otherwise, . - public static bool Contains(this string text, string value, StringComparison comparisonType) => - text.IndexOf(value, comparisonType) != -1; + /// + /// Returns a value indicating whether a specified string occurs within this string, using the specified comparison rules. + /// + /// The string to seek. + /// One of the enumeration values that specifies the rules to use in the comparison. + /// if the parameter occurs within this string, + /// or if is the empty string (""); otherwise, . + public bool Contains(string value, StringComparison comparisonType) => text.IndexOf(value, comparisonType) >= 0; - /// - /// Splits a string into substrings based on a specified delimiting character and, optionally, options. - /// - /// The string to split. - /// A character that delimits the substrings in this string. - /// A bitwise combination of the enumeration values that specifies whether to trim substrings and include empty substrings. - /// An array whose elements contain the substrings from this instance that are delimited by . - public static string[] Split(this string text, char separator, StringSplitOptions options = StringSplitOptions.None) => - text.Split([separator], options); + /// + /// Splits a string into substrings based on a specified delimiting character and, optionally, options. + /// + /// A character that delimits the substrings in this string. + /// A bitwise combination of the enumeration values that specifies whether to trim substrings and include empty substrings. + /// An array whose elements contain the substrings from this instance that are delimited by . + public string[] Split(char separator, StringSplitOptions options = StringSplitOptions.None) => text.Split([separator], options); - /// - /// Splits a string into a maximum number of substrings based on a specified delimiting - /// character and, optionally, options. Splits a string into a maximum number of - /// substrings based on the provided character separator, optionally omitting empty - /// substrings from the result. - /// - /// The string to split. - /// A character that delimits the substrings in this string. - /// The maximum number of elements expected in the array. - /// A bitwise combination of the enumeration values that specifies whether to trim substrings and include empty substrings. - /// An array that contains at most count substrings from this instance that are delimited by . - public static string[] Split(this string text, char separator, int count, StringSplitOptions options = StringSplitOptions.None) => - text.Split([separator], count, options); + /// + /// Splits a string into a maximum number of substrings based on a specified delimiting + /// character and, optionally, options. Splits a string into a maximum number of + /// substrings based on the provided character separator, optionally omitting empty + /// substrings from the result. + /// + /// A character that delimits the substrings in this string. + /// The maximum number of elements expected in the array. + /// A bitwise combination of the enumeration values that specifies whether to trim substrings and include empty substrings. + /// An array that contains at most count substrings from this instance that are delimited by . + public string[] Split(char separator, int count, StringSplitOptions options = StringSplitOptions.None) => text.Split([separator], count, options); - /// - /// Determines whether this string instance starts with the specified character. - /// - /// A sequence in which to locate a value. - /// The character to compare. - /// if matches the beginning of this string; otherwise, . - public static bool StartsWith(this string text, char value) => text.StartsWith(new string([value])); + /// + /// Determines whether this string instance starts with the specified character. + /// + /// The character to compare. + /// if matches the beginning of this string; otherwise, . + public bool StartsWith(char value) => text.StartsWith(new string([value])); - /// - /// Determines whether the end of this string instance matches the specified character. - /// - /// A sequence in which to locate a value. - /// The character to compare to the character at the end of this instance. - /// if matches the end of this instance; otherwise, . - public static bool EndsWith(this string text, char value) => text.EndsWith(new string([value])); -#endif - - /// - /// Concatenates the string representations of an array of objects, using the specified separator between each member. - /// - /// The string to use as a separator. is included - /// in the returned string only if has more than one element. - /// An array of objects whose string representations will be concatenated. - /// A string that consists of the elements of delimited by the - /// string.-or- if values has zero elements. - public static string Join(char separator, params object?[] values) => -#if HAS_FULLSTRING - string.Join(separator, values); -#else - Join(new string([separator]), values); -#endif + /// + /// Determines whether the end of this string instance matches the specified character. + /// + /// The character to compare to the character at the end of this instance. + /// if matches the end of this instance; otherwise, . + public bool EndsWith(char value) => text.EndsWith(new string([value])); + + /// + /// Concatenates the string representations of an array of objects, using the specified separator between each member. + /// + /// The character to use as a separator. is included + /// in the returned string only if has more than one element. + /// An array of objects whose string representations will be concatenated. + /// A string that consists of the elements of delimited by the character. + /// -or- if has zero elements. + public static string Join(char separator, params object?[] values) + { + ArgumentNullException.ThrowIfNull(values); - /// - /// Concatenates an array of strings, using the specified separator between each member. - /// - /// The string to use as a separator. is included - /// in the returned string only if has more than one element. - /// An array of strings to concatenate. - /// A string that consists of the elements of delimited by the - /// string.-or- if values has zero elements. - public static string Join(char separator, params string?[] value) => -#if HAS_FULLSTRING - string.Join(separator, value); -#else - string.Join(new string([separator]), value); -#endif + if (values.Length <= 0) + { + return string.Empty; + } - /// - /// Concatenates the elements of an object array, using the specified separator between each element. - /// - /// The string to use as a separator. is included - /// in the returned string only if has more than one element. - /// An array that contains the elements to concatenate. - /// A string that consists of the elements of delimited by the - /// string.-or- if values has zero elements. - public static string Join(string? separator, params object?[] values) - { -#if NETFRAMEWORK && !NET40_OR_GREATER - ExceptionExtensions.ThrowIfNull(values); + string? firstString = values[0]?.ToString(); - if (values.Length == 0 || values[0] == null) - { - return string.Empty; - } + if (values.Length == 1) + { + return firstString ?? string.Empty; + } - separator ??= string.Empty; + StringBuilder result = new(); - StringBuilder stringBuilder = new(); - string? text = values[0]?.ToString(); - if (text != null) - { - _ = stringBuilder.Append(text); - } + result.Append(firstString); - for (int i = 1; i < values.Length; i++) - { - _ = stringBuilder.Append(separator); - if (values[i] != null) + for (int i = 1; i < values.Length; i++) { - text = values[i]?.ToString(); - if (text != null) + result.Append(separator); + object? value = values[i]; + if (value != null) { - _ = stringBuilder.Append(text); + result.Append(value.ToString()); } } + + return result.ToString(); } + + /// + /// Concatenates an array of strings, using the specified separator between each member. + /// + /// The character to use as a separator. is included + /// in the returned string only if has more than one element. + /// An array of strings to concatenate. + /// A string that consists of the elements of delimited by the character. + /// -or- if has zero elements. + public static string Join(char separator, params string?[] value) + { + ArgumentNullException.ThrowIfNull(value); - return stringBuilder.ToString(); -#else - return string.Join(separator, values); -#endif - } + if (value.Length <= 1) + { + return value.Length <= 0 ? + string.Empty : + value[0] ?? string.Empty; + } + + return string.Join(new string([separator]), value); + } - /// - /// Concatenates the members of a collection, using the specified separator between each member. - /// - /// The type of the members of values. - /// The string to use as a separator. is included - /// in the returned string only if has more than one element. - /// A collection that contains the objects to concatenate. - /// A string that consists of the elements of delimited by the - /// string.-or- if values has zero elements. - public static string Join(string? separator, IEnumerable values) - { #if NETFRAMEWORK && !NET40_OR_GREATER - ExceptionExtensions.ThrowIfNull(values); + /// + /// Concatenates the elements of an object array, using the specified separator between each element. + /// + /// The string to use as a separator. is included in + /// the returned string only if has more than one element. + /// An array that contains the elements to concatenate. + /// A string that consists of the elements of delimited by the string. + /// -or- if has zero elements.-or- + /// .NET Framework only: if the first element of is . + /// is . + public static string Join(string? separator, params object?[] values) + { + ArgumentNullException.ThrowIfNull(values); - separator ??= string.Empty; + if (values.Length <= 0) + { + return string.Empty; + } - using IEnumerator enumerator = values.GetEnumerator(); + string? firstString = values[0]?.ToString(); - if (!enumerator.MoveNext()) - { - return string.Empty; - } + if (values.Length == 1) + { + return firstString ?? string.Empty; + } - StringBuilder stringBuilder = new(); - if (enumerator.Current != null) - { - string? text = enumerator.Current.ToString(); - if (text != null) + StringBuilder result = new(); + + result.Append(firstString); + + for (int i = 1; i < values.Length; i++) { - stringBuilder.Append(text); + result.Append(separator); + object? value = values[i]; + if (value != null) + { + result.Append(value.ToString()); + } } + return result.ToString(); } - while (enumerator.MoveNext()) + /// + /// Concatenates the members of a collection, using the specified separator between each member. + /// + /// The type of the members of . + /// The string to use as a separator. is included in + /// the returned string only if has more than one element. + /// A collection that contains the objects to concatenate. + /// A string that consists of the elements of delimited by the string. + /// -or- if has zero elements. + /// is . + public static string Join(string? separator, IEnumerable values) { - stringBuilder.Append(separator); - if (enumerator.Current != null) + ArgumentNullException.ThrowIfNull(values); + + if (typeof(T) == typeof(string)) { - string? text = enumerator.Current.ToString(); - if (text != null) + if (values is string?[] valuesArray) { - stringBuilder.Append(text); + return string.Join(separator, valuesArray); } } - } - return stringBuilder.ToString(); -#else - return string.Join(separator, values); -#endif - } + using IEnumerator e = values.GetEnumerator(); + if (!e.MoveNext()) + { + // If the enumerator is empty, just return an empty string. + return string.Empty; + } - /// - /// Concatenates the members of a constructed collection of type , - /// using the specified separator between each member. - /// - /// The string to use as a separator. is included - /// in the returned string only if has more than one element. - /// A collection that contains the strings to concatenate. - /// A string that consists of the elements of delimited by the - /// string.-or- if values has zero elements. - public static string Join(string? separator, IEnumerable values) - { -#if NETFRAMEWORK && !NET40_OR_GREATER - ExceptionExtensions.ThrowIfNull(values); + if (e is IEnumerator en) + { + // Special-case T==char, as we can handle that case much more efficiently, + // and string.Concat(IEnumerable) can be used as an efficient + // enumerable-based equivalent of new string(char[]). + + char c = en.Current; // save the first value + if (!en.MoveNext()) + { + // There was only one char. Return a string from it directly. + return new string([c]); + } - separator ??= string.Empty; + // Create the builder, add the char we already enumerated, + // add the rest, and then get the resulting string. + StringBuilder result = new(); + result.Append(c); // first value + do + { + result.Append(separator); + c = en.Current; + result.Append(c); + } + while (en.MoveNext()); + return result.ToString(); + } + else + { + // For all other Ts, fall back to calling ToString on each and appending the resulting + // string to a builder. - using IEnumerator enumerator = values.GetEnumerator(); - if (!enumerator.MoveNext()) - { - return string.Empty; - } + string? firstString = e.Current?.ToString(); // save the first value + if (!e.MoveNext()) + { + return firstString ?? string.Empty; + } - StringBuilder result = new(); - if (enumerator.Current != null) - { - _ = result.Append(enumerator.Current); + StringBuilder result = new(); + + result.Append(firstString); + do + { + result.Append(separator); + result.Append(e.Current?.ToString()); + } + while (e.MoveNext()); + + return result.ToString(); + } } - while (enumerator.MoveNext()) + /// + /// Concatenates the members of a constructed collection of type , + /// using the specified separator between each member. + /// + /// The string to use as a separator. is included in + /// the returned string only if values has more than one element. + /// A collection that contains the strings to concatenate. + /// A string that consists of the elements of delimited by the string. + /// -or- if has zero elements. + /// is . + public static string Join(string? separator, IEnumerable values) { - _ = result.Append(separator); - if (enumerator.Current != null) + ArgumentNullException.ThrowIfNull(values); + + using IEnumerator en = values.GetEnumerator(); + if (!en.MoveNext()) + { + return string.Empty; + } + + string? firstValue = en.Current; + + if (!en.MoveNext()) { - _ = result.Append(enumerator.Current); + // Only one value available + return firstValue ?? string.Empty; } + + // Null separator and values are handled by the StringBuilder + StringBuilder result = new(); + + result.Append(firstValue); + + do + { + result.Append(separator); + result.Append(en.Current); + } + while (en.MoveNext()); + + return result.ToString(); } - return result.ToString(); -#else - return string.Join(separator, values); #endif } } } +#endif \ No newline at end of file diff --git a/AdvancedSharpAdbClient/Polyfills/Extensions/TaskCompletionSourceExtensions.cs b/AdvancedSharpAdbClient/Polyfills/Extensions/TaskCompletionSourceExtensions.cs new file mode 100644 index 00000000..4e9a26e1 --- /dev/null +++ b/AdvancedSharpAdbClient/Polyfills/Extensions/TaskCompletionSourceExtensions.cs @@ -0,0 +1,19 @@ +#if !NET && HAS_TASK +global using TaskCompletionSource = System.Threading.Tasks.TaskCompletionSource; + +namespace AdvancedSharpAdbClient.Polyfills +{ + /// + /// Provides extension methods for the class. + /// + internal static class TaskCompletionSourceExtensions + { + /// + /// Attempts to transition the underlying into the state. + /// + /// The to set the result for. + /// if the operation was successful; otherwise, . + public static bool TrySetResult(this TaskCompletionSource source) => source.TrySetResult(null); + } +} +#endif \ No newline at end of file diff --git a/AdvancedSharpAdbClient/Polyfills/Extensions/TaskExExtensions.cs b/AdvancedSharpAdbClient/Polyfills/Extensions/TaskExExtensions.cs index 9d7eb6c9..51876553 100644 --- a/AdvancedSharpAdbClient/Polyfills/Extensions/TaskExExtensions.cs +++ b/AdvancedSharpAdbClient/Polyfills/Extensions/TaskExExtensions.cs @@ -6,9 +6,7 @@ using System; using System.Collections.Generic; using System.ComponentModel; -using System.Runtime.CompilerServices; using System.Threading; -using System.Threading.Tasks; #if NET40 using Microsoft.Runtime.CompilerServices; @@ -26,39 +24,75 @@ internal static class TaskExExtensions /// /// Singleton cached task that's been completed successfully. /// - internal static readonly Task s_cachedCompleted = + private static readonly Task s_cachedCompleted = #if NET45_OR_GREATER Task. #else TaskEx. #endif FromResult(null); +#endif /// - /// Gets a task that's already been completed successfully. - /// - public static Task CompletedTask => s_cachedCompleted; -#else - /// - /// Gets a task that's already been completed successfully. + /// The extension for the class. /// - public static Task CompletedTask => Task.CompletedTask; + extension(Task) + { +#if NETFRAMEWORK && !NET46_OR_GREATER + /// + /// Gets a task that's already been completed successfully. + /// + public static Task CompletedTask => s_cachedCompleted; #endif - /// - /// Creates a task that completes after a specified number of milliseconds. - /// - /// The number of milliseconds to wait before completing the returned task, or -1 to wait indefinitely. - /// A cancellation token to observe while waiting for the task to complete. - /// A task that represents the time delay. - /// The argument is less than -1. - public static Task Delay(int dueTime, CancellationToken cancellationToken = default) => #if NETFRAMEWORK && !NET45_OR_GREATER - TaskEx -#else - Task + /// + /// Queues the specified work to run on the ThreadPool and returns a handle for that work. + /// + /// The work to execute asynchronously + /// A cancellation token that should be used to cancel the work + /// A Task that represents the work queued to execute in the ThreadPool. + /// The parameter was null. + /// The associated with was disposed. + public static Task Run(Action action, CancellationToken cancellationToken) => TaskEx.Run(action, cancellationToken); + + /// + /// Queues the specified work to run on the ThreadPool and returns a handle for that work. + /// + /// The work to execute asynchronously + /// A that represents the work queued to execute in the ThreadPool. + /// The parameter was null. + public static Task Run(Func function) => TaskEx.Run(function); + + /// + /// Queues the specified work to run on the ThreadPool and returns a handle for that work. + /// + /// The work to execute asynchronously + /// A cancellation token that should be used to cancel the work + /// A that represents the work queued to execute in the ThreadPool. + /// The parameter was null. + /// The associated with was disposed. + public static Task Run(Func function, CancellationToken cancellationToken) => TaskEx.Run(function, cancellationToken); + + /// + /// Creates a task that completes after a specified number of milliseconds. + /// + /// The number of milliseconds to wait before completing the returned task, or -1 to wait indefinitely. + /// A cancellation token to observe while waiting for the task to complete. + /// A task that represents the time delay. + /// The argument is less than -1. + public static Task Delay(int dueTime, CancellationToken cancellationToken = default) => TaskEx.Delay(dueTime, cancellationToken); + + /// + /// Creates a that's completed successfully with the specified result. + /// + /// The type of the result returned by the task. + /// The result to store into the completed task. + /// The successfully completed task. + public static Task FromResult(TResult result) => TaskEx.FromResult(result); #endif - .Delay(dueTime, cancellationToken); + } + /// /// Creates a task that will complete when all of the objects in an enumerable collection have completed. @@ -87,20 +121,6 @@ public static Task WhenAll(this IEnumerable> t #endif .WhenAll(tasks); - /// - /// Creates a that's completed successfully with the specified result. - /// - /// The type of the result returned by the task. - /// The result to store into the completed task. - /// The successfully completed task. - public static Task FromResult(TResult result) => -#if NETFRAMEWORK && !NET45_OR_GREATER - TaskEx -#else - Task -#endif - .FromResult(result); - #if HAS_WINRT /// /// Wait a synchronously by and return the result. @@ -109,14 +129,11 @@ public static Task FromResult(TResult result) => /// The to wait. /// A cancellation token that can be used to cancel the work if it has not yet started. /// The result of the completed task. -#if NET - [SupportedOSPlatform("Windows10.0.10240.0")] -#endif public static TResult AwaitByTaskCompleteSource(this IAsyncOperation function, CancellationToken cancellationToken = default) { TaskCompletionSource taskCompletionSource = new(); Task task = taskCompletionSource.Task; - _ = Task.Factory.StartNew(async () => + _ = Task.Run(async () => { try { @@ -140,24 +157,14 @@ public static TResult AwaitByTaskCompleteSource(this IAsyncOperationA cancellation token that can be used to cancel the work if it has not yet started. public static void AwaitByTaskCompleteSource(this Task function, CancellationToken cancellationToken = default) { -#if NET TaskCompletionSource taskCompletionSource = new(); -#else - TaskCompletionSource taskCompletionSource = new(); -#endif -#pragma warning disable IDE0008 - var task = taskCompletionSource.Task; -#pragma warning restore IDE0008 - _ = Task.Factory.StartNew(async () => + Task task = taskCompletionSource.Task; + _ = Task.Run(async () => { try { await function.ConfigureAwait(false); -#if NET _ = taskCompletionSource.TrySetResult(); -#else - _ = taskCompletionSource.TrySetResult(null); -#endif } catch (Exception e) { @@ -178,7 +185,7 @@ public static TResult AwaitByTaskCompleteSource(this Task func { TaskCompletionSource taskCompletionSource = new(); Task task = taskCompletionSource.Task; - _ = Task.Factory.StartNew(async () => + _ = Task.Run(async () => { try { diff --git a/AdvancedSharpAdbClient/Polyfills/HashCode.cs b/AdvancedSharpAdbClient/Polyfills/HashCode.cs index ad2da502..0b1d9b7b 100644 --- a/AdvancedSharpAdbClient/Polyfills/HashCode.cs +++ b/AdvancedSharpAdbClient/Polyfills/HashCode.cs @@ -1,4 +1,4 @@ -#if !NET461_OR_GREATER && !NETCOREAPP2_1_OR_GREATER && !NETSTANDARD2_0_OR_GREATER && !UAP10_0_15138_0 +#if !COMP_NETSTANDARD2_0 // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. diff --git a/AdvancedSharpAdbClient/Polyfills/Interfaces/ICloneable.cs b/AdvancedSharpAdbClient/Polyfills/Interfaces/ICloneable.cs index 93ace10d..fffb6308 100644 --- a/AdvancedSharpAdbClient/Polyfills/Interfaces/ICloneable.cs +++ b/AdvancedSharpAdbClient/Polyfills/Interfaces/ICloneable.cs @@ -2,7 +2,7 @@ // Copyright (c) The Android Open Source Project, Ryan Conrad, Quamotion, yungd1plomat, wherewhere. All rights reserved. // -#if !NETFRAMEWORK && !NETCOREAPP2_0_OR_GREATER && !NETSTANDARD2_0_OR_GREATER && !UAP10_0_15138_0 +#if !NETFRAMEWORK && !COMP_NETSTANDARD2_0 // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. diff --git a/AdvancedSharpAdbClient/Polyfills/Interfaces/IReadOnlyCollection.cs b/AdvancedSharpAdbClient/Polyfills/Interfaces/IReadOnlyCollection.cs index c690da19..09e3c807 100644 --- a/AdvancedSharpAdbClient/Polyfills/Interfaces/IReadOnlyCollection.cs +++ b/AdvancedSharpAdbClient/Polyfills/Interfaces/IReadOnlyCollection.cs @@ -11,7 +11,11 @@ namespace System.Collections.Generic /// /// The type of the elements. [EditorBrowsable(EditorBrowsableState.Never)] +#if NET40_OR_GREATER + internal interface IReadOnlyCollection : IEnumerable +#else internal interface IReadOnlyCollection : IEnumerable +#endif { /// /// Gets the number of elements in the collection. diff --git a/AdvancedSharpAdbClient/Polyfills/Interfaces/IReadOnlyList.cs b/AdvancedSharpAdbClient/Polyfills/Interfaces/IReadOnlyList.cs index 477e5a69..a31a6a29 100644 --- a/AdvancedSharpAdbClient/Polyfills/Interfaces/IReadOnlyList.cs +++ b/AdvancedSharpAdbClient/Polyfills/Interfaces/IReadOnlyList.cs @@ -11,7 +11,11 @@ namespace System.Collections.Generic /// /// The type of elements in the read-only list. [EditorBrowsable(EditorBrowsableState.Never)] +#if NET40_OR_GREATER + internal interface IReadOnlyList : IReadOnlyCollection +#else internal interface IReadOnlyList : IReadOnlyCollection +#endif { /// /// Gets the element at the specified index in the read-only list. diff --git a/AdvancedSharpAdbClient/Polyfills/NamespaceDoc.cs b/AdvancedSharpAdbClient/Polyfills/NamespaceDoc.cs index 7bc3a48d..3c98eb41 100644 --- a/AdvancedSharpAdbClient/Polyfills/NamespaceDoc.cs +++ b/AdvancedSharpAdbClient/Polyfills/NamespaceDoc.cs @@ -13,5 +13,11 @@ namespace AdvancedSharpAdbClient.Polyfills /// Copyright (c) The Android Open Source Project, Ryan Conrad, Quamotion, yungd1plomat, wherewhere. All rights reserved. [CompilerGenerated] [EditorBrowsable(EditorBrowsableState.Never)] - internal abstract class NamespaceDoc : AdvancedSharpAdbClient.NamespaceDoc; + internal abstract class NamespaceDoc : AdvancedSharpAdbClient.NamespaceDoc + { + /// + /// The name of the namespace . + /// + public new const string Name = $"{AdvancedSharpAdbClient.NamespaceDoc.Name}.{nameof(Polyfills)}"; + } } diff --git a/AdvancedSharpAdbClient/Polyfills/OperatingSystem.cs b/AdvancedSharpAdbClient/Polyfills/OperatingSystem.cs new file mode 100644 index 00000000..503b0988 --- /dev/null +++ b/AdvancedSharpAdbClient/Polyfills/OperatingSystem.cs @@ -0,0 +1,17 @@ +#if !NETFRAMEWORK && !COMP_NETSTANDARD2_0 +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.ComponentModel; + +namespace System +{ + /// + /// Represents information about an operating system, such as the version and platform identifier. This class cannot be inherited. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + internal static class OperatingSystem; +} +#else +[assembly: System.Runtime.CompilerServices.TypeForwardedTo(typeof(System.OperatingSystem))] +#endif \ No newline at end of file diff --git a/AdvancedSharpAdbClient/Polyfills/Range.cs b/AdvancedSharpAdbClient/Polyfills/Range.cs index 88ca6aad..ca2aa8e7 100644 --- a/AdvancedSharpAdbClient/Polyfills/Range.cs +++ b/AdvancedSharpAdbClient/Polyfills/Range.cs @@ -104,4 +104,7 @@ public Tuple GetOffsetAndLength(int length) #endif } } +#elif COMP_NETSTANDARD2_1 +[assembly: System.Runtime.CompilerServices.TypeForwardedTo(typeof(System.Index))] +[assembly: System.Runtime.CompilerServices.TypeForwardedTo(typeof(System.Range))] #endif \ No newline at end of file diff --git a/AdvancedSharpAdbClient/Polyfills/StringHandler.cs b/AdvancedSharpAdbClient/Polyfills/StringHandler.cs index b719d162..2c4d078f 100644 --- a/AdvancedSharpAdbClient/Polyfills/StringHandler.cs +++ b/AdvancedSharpAdbClient/Polyfills/StringHandler.cs @@ -11,7 +11,7 @@ namespace System.Runtime.CompilerServices /// Provides a handler used by the language compiler to process interpolated strings into instances. /// [InterpolatedStringHandler] - internal readonly struct DefaultInterpolatedStringHandler + internal readonly ref struct DefaultInterpolatedStringHandler { /// /// Expected average length of formatted data used for an individual interpolation expression result. @@ -31,14 +31,14 @@ internal readonly struct DefaultInterpolatedStringHandler private const int MinimumArrayPoolLength = 256; /// - /// Optional provider to pass to IFormattable.ToString or ISpanFormattable.TryFormat calls. + /// The associated to which to append. /// - private readonly IFormatProvider? _provider; + private readonly StringBuilder _stringBuilder; /// - /// The used to build the string. + /// Optional provider to pass to IFormattable.ToString or ISpanFormattable.TryFormat calls. /// - private readonly StringBuilder _builder; + private readonly IFormatProvider? _provider; /// /// Whether provides an ICustomFormatter. @@ -57,7 +57,7 @@ internal readonly struct DefaultInterpolatedStringHandler /// public DefaultInterpolatedStringHandler() { - _builder = new StringBuilder(); + _stringBuilder = new StringBuilder(); _hasCustomFormatter = false; } @@ -69,7 +69,7 @@ public DefaultInterpolatedStringHandler() /// This is intended to be called only by compiler-generated code. Arguments are not validated as they'd otherwise be for members intended to be used directly. public DefaultInterpolatedStringHandler(int literalLength, int formattedCount) { - _builder = new StringBuilder(GetDefaultLength(literalLength, formattedCount)); + _stringBuilder = new StringBuilder(GetDefaultLength(literalLength, formattedCount)); _hasCustomFormatter = false; } @@ -82,7 +82,7 @@ public DefaultInterpolatedStringHandler(int literalLength, int formattedCount) /// This is intended to be called only by compiler-generated code. Arguments are not validated as they'd otherwise be for members intended to be used directly. public DefaultInterpolatedStringHandler(int literalLength, int formattedCount, IFormatProvider? provider) { - _builder = new StringBuilder(GetDefaultLength(literalLength, formattedCount)); + _stringBuilder = new StringBuilder(GetDefaultLength(literalLength, formattedCount)); _provider = provider; _hasCustomFormatter = provider != null && HasCustomFormatter(provider); } @@ -98,7 +98,7 @@ internal static int GetDefaultLength(int literalLength, int formattedCount) => /// Gets the built . /// /// The built string. - public override string ToString() => _builder.ToString(); + public override string ToString() => _stringBuilder.ToString(); /// /// Gets the built and clears the handler. @@ -112,17 +112,44 @@ internal static int GetDefaultLength(int literalLength, int formattedCount) => /// public string ToStringAndClear() { - string result = _builder.ToString(); - _ = _builder.Clear(); + string result = _stringBuilder.ToString(); + _ = _stringBuilder.Clear(); return result; } + /// + /// Clears the handler. + /// + /// + /// This releases any resources used by the handler. The method should be invoked only + /// once and as the last thing performed on the handler. Subsequent use is erroneous, ill-defined, + /// and may destabilize the process, as may using any other copies of the handler after + /// is called on any one of them. + /// + [MethodImpl((MethodImplOptions)0x100)] + public void Clear() => _ = _stringBuilder.Clear(); + +#if HAS_BUFFERS + /// + /// Gets a span of the characters appended to the handler. + /// + public ReadOnlySpan Text + { + get + { + Span result = new char[_stringBuilder.Length]; + _stringBuilder.CopyTo(0, result, _stringBuilder.Length); + return result; + } + } +#endif + /// /// Writes the specified string to the handler. /// /// The string to write. [MethodImpl((MethodImplOptions)0x100)] - public void AppendLiteral(string value) => _ = _builder.Append(value); + public void AppendLiteral(string value) => _ = _stringBuilder.Append(value); #region AppendFormatted #region AppendFormatted T @@ -142,7 +169,7 @@ public void AppendFormatted(T value) string? s = value switch { - IFormattable formattable => formattable.ToString(format: null, _provider), // constrained call avoiding boxing for value types + IFormattable => ((IFormattable)value).ToString(format: null, _provider), // constrained call avoiding boxing for value types _ => value?.ToString(), }; @@ -169,7 +196,7 @@ public void AppendFormatted(T value, string? format) string? s = value switch { - IFormattable formattable => formattable.ToString(format, _provider), // constrained call avoiding boxing for value types + IFormattable => ((IFormattable)value).ToString(format, _provider), // constrained call avoiding boxing for value types _ => value?.ToString(), }; @@ -187,7 +214,7 @@ public void AppendFormatted(T value, string? format) /// The type of the value to write. public void AppendFormatted(T value, int alignment) { - int startingPos = _builder.Length; + int startingPos = _stringBuilder.Length; AppendFormatted(value); if (alignment != 0) { @@ -204,7 +231,7 @@ public void AppendFormatted(T value, int alignment) /// The type of the value to write. public void AppendFormatted(T value, int alignment, string? format) { - int startingPos = _builder.Length; + int startingPos = _stringBuilder.Length; AppendFormatted(value, format); if (alignment != 0) { @@ -251,7 +278,7 @@ public void AppendFormatted(string? value, int alignment = 0, string? format = n /// Writes the specified character span to the handler. /// /// The span to write. - public void AppendFormatted(params ReadOnlySpan value) => _ = _builder.Append(value); + public void AppendFormatted(ReadOnlySpan value) => _ = _stringBuilder.Append(value); /// /// Writes the specified string of chars to the handler. @@ -281,13 +308,13 @@ public void AppendFormatted(ReadOnlySpan value, int alignment = 0, string? if (leftAlign) { AppendFormatted(value); - int _pos = _builder.Length; - _ = _builder.Insert(_pos, " ", paddingRequired); + int _pos = _stringBuilder.Length; + _ = _stringBuilder.Insert(_pos, " ", paddingRequired); } else { - int _pos = _builder.Length; - _ = _builder.Insert(_pos, " ", paddingRequired); + int _pos = _stringBuilder.Length; + _ = _stringBuilder.Insert(_pos, " ", paddingRequired); AppendFormatted(value); } } @@ -307,6 +334,45 @@ public void AppendFormatted(object? value, int alignment = 0, string? format = n // exists purely to help make cases from (b) compile. Just delegate to the T-based implementation. AppendFormatted(value, alignment, format); #endregion + + #region AppendFormatted char + /// + /// Writes the specified value to the handler. + /// + /// The value to write. + public void AppendFormatted(char value) + { + // If there's a custom formatter, always use it. + if (_hasCustomFormatter) + { + AppendCustomFormatter(value, format: null); + return; + } + +#if NETFRAMEWORK || COMP_NETSTANDARD2_0 + _ = _provider == null + ? _stringBuilder.Append(value) + : _stringBuilder.Append(value.ToString(_provider)); +#else + _stringBuilder.Append(value); +#endif + } + + /// + /// Writes the specified value to the handler. + /// + /// The value to write. + /// Minimum number of characters that should be written for this value. If the value is negative, it indicates left-aligned and the required minimum is the absolute value. + public void AppendFormatted(char value, int alignment) + { + int startingPos = _stringBuilder.Length; + AppendFormatted(value); + if (alignment != 0) + { + AppendOrInsertAlignmentIfNeeded(startingPos, alignment); + } + } + #endregion #endregion /// @@ -341,7 +407,7 @@ private void AppendCustomFormatter(T value, string? format) /// Non-zero minimum number of characters that should be written for this value. If the value is negative, it indicates left-aligned and the required minimum is the absolute value. private void AppendOrInsertAlignmentIfNeeded(int startingPos, int alignment) { - int _pos = _builder.Length; + int _pos = _stringBuilder.Length; int charsWritten = _pos - startingPos; bool leftAlign = false; @@ -355,12 +421,12 @@ private void AppendOrInsertAlignmentIfNeeded(int startingPos, int alignment) if (paddingNeeded > 0) { _ = leftAlign - ? _builder.Insert(_pos, " ", paddingNeeded) - : _builder.Insert(startingPos, " ", paddingNeeded); + ? _stringBuilder.Insert(_pos, " ", paddingNeeded) + : _stringBuilder.Insert(startingPos, " ", paddingNeeded); } } } } #else -[assembly: System.Runtime.CompilerServices.TypeForwardedTo(typeof(System.Runtime.CompilerServices.DefaultInterpolatedStringHandler))] + [assembly: System.Runtime.CompilerServices.TypeForwardedTo(typeof(System.Runtime.CompilerServices.DefaultInterpolatedStringHandler))] #endif \ No newline at end of file diff --git a/AdvancedSharpAdbClient/Receivers/ConsoleOutputReceiver.cs b/AdvancedSharpAdbClient/Receivers/ConsoleOutputReceiver.cs index b82af86f..23df4e0c 100644 --- a/AdvancedSharpAdbClient/Receivers/ConsoleOutputReceiver.cs +++ b/AdvancedSharpAdbClient/Receivers/ConsoleOutputReceiver.cs @@ -2,6 +2,7 @@ // Copyright (c) The Android Open Source Project, Ryan Conrad, Quamotion, yungd1plomat, wherewhere. All rights reserved. // +using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; @@ -15,7 +16,7 @@ namespace AdvancedSharpAdbClient.Receivers /// fetch the console output that was received, used the method. /// /// The logger to use when logging. - [DebuggerDisplay($"{nameof(ConsoleOutputReceiver)} \\{{ {nameof(TrimLines)} = {{{nameof(TrimLines)}}}, {nameof(ParsesErrors)} = {{{nameof(ParsesErrors)}}}, {nameof(Lines)} = {{{nameof(Lines)}}}, {nameof(Output)} = {{{nameof(Output)}}} }}")] + [DebuggerDisplay($"{{{nameof(GetType)}().{nameof(Type.ToString)}(),nq}} \\{{ {nameof(TrimLines)} = {{{nameof(TrimLines)}}}, {nameof(ParsesErrors)} = {{{nameof(ParsesErrors)}}}, {nameof(Lines)} = {{{nameof(Lines)}}}, {nameof(Output)} = {{{nameof(Output)}}} }}")] public partial class ConsoleOutputReceiver(ILogger? logger = null) : MultiLineReceiver { /// diff --git a/AdvancedSharpAdbClient/Receivers/FunctionOutputReceiver.Async.cs b/AdvancedSharpAdbClient/Receivers/FunctionOutputReceiver.Async.cs index 5d71a692..6c517f9f 100644 --- a/AdvancedSharpAdbClient/Receivers/FunctionOutputReceiver.Async.cs +++ b/AdvancedSharpAdbClient/Receivers/FunctionOutputReceiver.Async.cs @@ -11,11 +11,11 @@ namespace AdvancedSharpAdbClient.Receivers { /// public Task AddOutputAsync(string line, CancellationToken cancellationToken = default) => - TaskExExtensions.FromResult(predicate(line)); + Task.FromResult(predicate(line)); /// public Task FlushAsync(CancellationToken cancellationToken = default) => - TaskExExtensions.CompletedTask; + Task.CompletedTask; } } #endif \ No newline at end of file diff --git a/AdvancedSharpAdbClient/Receivers/MultiLineReceiver.Async.cs b/AdvancedSharpAdbClient/Receivers/MultiLineReceiver.Async.cs index 26900215..318c368c 100644 --- a/AdvancedSharpAdbClient/Receivers/MultiLineReceiver.Async.cs +++ b/AdvancedSharpAdbClient/Receivers/MultiLineReceiver.Async.cs @@ -39,7 +39,7 @@ public override async Task FlushAsync(CancellationToken cancellationToken = defa protected virtual Task ThrowOnErrorAsync(string line, CancellationToken cancellationToken = default) { ThrowOnError(line); - return TaskExExtensions.CompletedTask; + return Task.CompletedTask; } /// @@ -51,7 +51,7 @@ protected virtual Task ThrowOnErrorAsync(string line, CancellationToken cancella protected virtual Task ProcessNewLinesAsync(IEnumerable lines, CancellationToken cancellationToken = default) { ProcessNewLines(lines); - return TaskExExtensions.CompletedTask; + return Task.CompletedTask; } } } diff --git a/AdvancedSharpAdbClient/Receivers/MultiLineReceiver.cs b/AdvancedSharpAdbClient/Receivers/MultiLineReceiver.cs index db6765df..d79ddbb3 100644 --- a/AdvancedSharpAdbClient/Receivers/MultiLineReceiver.cs +++ b/AdvancedSharpAdbClient/Receivers/MultiLineReceiver.cs @@ -2,6 +2,7 @@ // Copyright (c) The Android Open Source Project, Ryan Conrad, Quamotion, yungd1plomat, wherewhere. All rights reserved. // +using System; using System.Collections.Generic; using System.Diagnostics; @@ -10,7 +11,7 @@ namespace AdvancedSharpAdbClient.Receivers /// /// A multiline receiver to receive and process shell output with multi lines. /// - [DebuggerDisplay($"{nameof(MultiLineReceiver)} \\{{ {nameof(TrimLines)} = {{{nameof(TrimLines)}}}, {nameof(ParsesErrors)} = {{{nameof(ParsesErrors)}}}, {nameof(Lines)} = {{{nameof(Lines)}}} }}")] + [DebuggerDisplay($"{{{nameof(GetType)}().{nameof(Type.ToString)}(),nq}} \\{{ {nameof(TrimLines)} = {{{nameof(TrimLines)}}}, {nameof(ParsesErrors)} = {{{nameof(ParsesErrors)}}}, {nameof(Lines)} = {{{nameof(Lines)}}} }}")] public abstract partial class MultiLineReceiver : ShellOutputReceiver { /// @@ -22,7 +23,7 @@ public MultiLineReceiver() { } /// Gets or sets a value indicating whether [trim lines]. /// /// if [trim lines]; otherwise, . - public bool TrimLines { get; set; } = false; + public bool TrimLines { get; set; } /// /// Gets or sets a value indicating whether the receiver parses error messages. diff --git a/AdvancedSharpAdbClient/Receivers/NamespaceDoc.cs b/AdvancedSharpAdbClient/Receivers/NamespaceDoc.cs index 634bb60d..e3c5da16 100644 --- a/AdvancedSharpAdbClient/Receivers/NamespaceDoc.cs +++ b/AdvancedSharpAdbClient/Receivers/NamespaceDoc.cs @@ -3,7 +3,6 @@ // using System.ComponentModel; -using System.Runtime.CompilerServices; using System.Text; namespace AdvancedSharpAdbClient.Receivers @@ -12,7 +11,12 @@ namespace AdvancedSharpAdbClient.Receivers /// The classes in this namespace provide receivers for . /// /// Copyright (c) The Android Open Source Project, Ryan Conrad, Quamotion, yungd1plomat, wherewhere. All rights reserved. - [CompilerGenerated] [EditorBrowsable(EditorBrowsableState.Never)] - internal abstract class NamespaceDoc : AdvancedSharpAdbClient.NamespaceDoc; + internal abstract class NamespaceDoc : AdvancedSharpAdbClient.NamespaceDoc + { + /// + /// The name of the namespace . + /// + public new const string Name = $"{AdvancedSharpAdbClient.NamespaceDoc.Name}.{nameof(Receivers)}"; + } } diff --git a/AdvancedSharpAdbClient/Receivers/ShellOutputReceiver.Async.cs b/AdvancedSharpAdbClient/Receivers/ShellOutputReceiver.Async.cs index 612a20cc..35227587 100644 --- a/AdvancedSharpAdbClient/Receivers/ShellOutputReceiver.Async.cs +++ b/AdvancedSharpAdbClient/Receivers/ShellOutputReceiver.Async.cs @@ -11,7 +11,7 @@ public abstract partial class ShellOutputReceiver { /// public virtual Task AddOutputAsync(string line, CancellationToken cancellationToken = default) => - TaskExExtensions.FromResult(AddOutput(line)); + Task.FromResult(AddOutput(line)); /// public virtual Task FlushAsync(CancellationToken cancellationToken = default) => @@ -25,7 +25,7 @@ public virtual Task FlushAsync(CancellationToken cancellationToken = default) => protected virtual Task DoneAsync(CancellationToken cancellationToken = default) { Done(); - return TaskExExtensions.CompletedTask; + return Task.CompletedTask; } } } diff --git a/AdvancedSharpAdbClient/SyncService.Async.cs b/AdvancedSharpAdbClient/SyncService.Async.cs index 1707cfc3..3f0acaec 100644 --- a/AdvancedSharpAdbClient/SyncService.Async.cs +++ b/AdvancedSharpAdbClient/SyncService.Async.cs @@ -40,8 +40,8 @@ public virtual async Task PushAsync(Stream stream, string remotePath, UnixFileSt { if (IsProcessing) { throw new InvalidOperationException($"The {nameof(SyncService)} is currently processing a request. Please {nameof(Clone)} a new {nameof(ISyncService)} or wait until the process is finished."); } - ExceptionExtensions.ThrowIfNull(stream); - ExceptionExtensions.ThrowIfNull(remotePath); + ArgumentNullException.ThrowIfNull(stream); + ArgumentNullException.ThrowIfNull(remotePath); if (remotePath.Length > MaxPathLength) { @@ -100,7 +100,7 @@ await stream.ReadAsync(buffer, headerSize, maxDataSize, cancellationToken).Confi Buffer.BlockCopy(lengthBytes, 0, buffer, startPosition + dataBytes.Length, lengthBytes.Length); // now send the data to the device -#if HAS_BUFFERS +#if COMP_NETSTANDARD2_1 await Socket.SendAsync(buffer.AsMemory(startPosition, read + dataBytes.Length + lengthBytes.Length), cancellationToken).ConfigureAwait(false); #else await Socket.SendAsync(buffer, startPosition, read + dataBytes.Length + lengthBytes.Length, cancellationToken).ConfigureAwait(false); @@ -141,8 +141,8 @@ public virtual async Task PullAsync(string remotePath, Stream stream, Action -#if NET - [SupportedOSPlatform("Windows10.0.10240.0")] -#endif public virtual async Task PushAsync(IInputStream stream, string remotePath, UnixFileStatus permission, DateTimeOffset timestamp, Action? progress = null, CancellationToken cancellationToken = default) { if (IsProcessing) { throw new InvalidOperationException($"The {nameof(SyncService)} is currently processing a request. Please {nameof(Clone)} a new {nameof(ISyncService)} or wait until the process is finished."); } - ExceptionExtensions.ThrowIfNull(stream); - ExceptionExtensions.ThrowIfNull(remotePath); + ArgumentNullException.ThrowIfNull(stream); + ArgumentNullException.ThrowIfNull(remotePath); if (remotePath.Length > MaxPathLength) { @@ -324,15 +324,12 @@ public virtual async Task PushAsync(IInputStream stream, string remotePath, Unix } /// -#if NET - [SupportedOSPlatform("Windows10.0.10240.0")] -#endif public virtual async Task PullAsync(string remotePath, IOutputStream stream, Action? progress = null, CancellationToken cancellationToken = default) { if (IsProcessing) { throw new InvalidOperationException($"The {nameof(SyncService)} is currently processing a request. Please {nameof(Clone)} a new {nameof(ISyncService)} or wait until the process is finished."); } - ExceptionExtensions.ThrowIfNull(remotePath); - ExceptionExtensions.ThrowIfNull(stream); + ArgumentNullException.ThrowIfNull(remotePath); + ArgumentNullException.ThrowIfNull(stream); if (IsOutdate) { await ReopenAsync(cancellationToken).ConfigureAwait(false); } @@ -528,7 +525,7 @@ public async IAsyncEnumerable GetDirectoryAsyncListing(string re /// A which returns a object that contains information about the file. protected async Task ReadStatisticsAsync(CancellationToken cancellationToken = default) { -#if HAS_BUFFERS +#if COMP_NETSTANDARD2_1 Memory statResult = new byte[12]; _ = await Socket.ReadAsync(statResult, cancellationToken).ConfigureAwait(false); return EnumerableBuilder.FileStatisticsCreator(statResult.Span); @@ -540,7 +537,7 @@ protected async Task ReadStatisticsAsync(CancellationToken cance { FileMode = (UnixFileStatus)ReadInt32(statResult), Size = ReadInt32(statResult), - Time = DateTimeExtensions.FromUnixTimeSeconds(ReadInt32(statResult)) + Time = DateTimeOffset.FromUnixTimeSeconds(ReadInt32(statResult)) }; int ReadInt32(byte[] data) => data[index++] | (data[index++] << 8) | (data[index++] << 16) | (data[index++] << 24); #endif diff --git a/AdvancedSharpAdbClient/SyncService.cs b/AdvancedSharpAdbClient/SyncService.cs index e58464e7..8e313cbe 100644 --- a/AdvancedSharpAdbClient/SyncService.cs +++ b/AdvancedSharpAdbClient/SyncService.cs @@ -7,7 +7,6 @@ using System.Diagnostics; using System.IO; using System.Net; -using System.Text; namespace AdvancedSharpAdbClient { @@ -41,7 +40,7 @@ namespace AdvancedSharpAdbClient /// } /// /// - [DebuggerDisplay($"{nameof(SyncService)} \\{{ {nameof(IsOpen)} = {{{nameof(IsOpen)}}}, {nameof(Device)} = {{{nameof(Device)}}}, {nameof(Socket)} = {{{nameof(Socket)}}}, {nameof(MaxBufferSize)} = {{{nameof(MaxBufferSize)}}} }}")] + [DebuggerDisplay($"{{{nameof(GetType)}().{nameof(Type.ToString)}(),nq}} \\{{ {nameof(IsOpen)} = {{{nameof(IsOpen)}}}, {nameof(Device)} = {{{nameof(Device)}}}, {nameof(Socket)} = {{{nameof(Socket)}}}, {nameof(MaxBufferSize)} = {{{nameof(MaxBufferSize)}}} }}")] public partial class SyncService : ISyncService, ICloneable, ICloneable #if HAS_WINRT , ISyncService.IWinRT @@ -100,7 +99,7 @@ public SyncService(EndPoint endPoint, DeviceData device) /// The device on which to interact with the files. public SyncService(IAdbSocket socket, DeviceData device) { - Device = DeviceData.EnsureDevice(ref device); + Device = DeviceData.EnsureDevice(device); Socket = socket ?? throw new ArgumentNullException(nameof(socket)); Open(); } @@ -150,8 +149,8 @@ public virtual void Push(Stream stream, string remotePath, UnixFileStatus permis { if (IsProcessing) { throw new InvalidOperationException($"The {nameof(SyncService)} is currently processing a request. Please {nameof(Clone)} a new {nameof(ISyncService)} or wait until the process is finished."); } - ExceptionExtensions.ThrowIfNull(stream); - ExceptionExtensions.ThrowIfNull(remotePath); + ArgumentNullException.ThrowIfNull(stream); + ArgumentNullException.ThrowIfNull(remotePath); if (remotePath.Length > MaxPathLength) { @@ -210,7 +209,7 @@ public virtual void Push(Stream stream, string remotePath, UnixFileStatus permis Buffer.BlockCopy(lengthBytes, 0, buffer, startPosition + dataBytes.Length, lengthBytes.Length); // now send the data to the device -#if HAS_BUFFERS +#if COMP_NETSTANDARD2_1 Socket.Send(buffer.AsSpan(startPosition, read + dataBytes.Length + lengthBytes.Length)); #else Socket.Send(buffer, startPosition, read + dataBytes.Length + lengthBytes.Length); @@ -248,8 +247,8 @@ public virtual void Pull(string remoteFilePath, Stream stream, Action - public override string ToString() => - new StringBuilder(nameof(SyncService)) - .Append(" { ") - .Append(nameof(Socket)) - .Append(" = ") - .Append(Socket) - .Append(", ") - .Append(nameof(Device)) - .Append(" = ") - .Append(Device) - .Append(" }") - .ToString(); + public override string ToString() => $"{GetType()} {{ {nameof(Socket)} = {Socket}, {nameof(Device)} = {Device} }}"; /// /// Creates a new object that is a copy of the current instance with new . @@ -438,7 +429,7 @@ Socket is ICloneable cloneable /// A object that contains information about the file. protected FileStatistics ReadStatistics() { -#if HAS_BUFFERS +#if COMP_NETSTANDARD2_1 Span statResult = stackalloc byte[12]; _ = Socket.Read(statResult); return EnumerableBuilder.FileStatisticsCreator(statResult); @@ -450,7 +441,7 @@ protected FileStatistics ReadStatistics() { FileMode = (UnixFileStatus)ReadInt32(statResult), Size = ReadInt32(statResult), - Time = DateTimeExtensions.FromUnixTimeSeconds(ReadInt32(statResult)) + Time = DateTimeOffset.FromUnixTimeSeconds(ReadInt32(statResult)) }; int ReadInt32(byte[] data) => data[index++] | (data[index++] << 8) | (data[index++] << 16) | (data[index++] << 24); #endif diff --git a/AdvancedSharpAdbClient/TcpSocket.Async.cs b/AdvancedSharpAdbClient/TcpSocket.Async.cs index c83764b8..5808f6df 100644 --- a/AdvancedSharpAdbClient/TcpSocket.Async.cs +++ b/AdvancedSharpAdbClient/TcpSocket.Async.cs @@ -17,7 +17,7 @@ public partial class TcpSocket [MemberNotNull(nameof(EndPoint))] public async Task ConnectAsync(EndPoint endPoint, CancellationToken cancellationToken = default) { - ExceptionExtensions.ThrowIfNull(endPoint); + ArgumentNullException.ThrowIfNull(endPoint); if (endPoint is not (IPEndPoint or DnsEndPoint)) { @@ -25,11 +25,7 @@ public async Task ConnectAsync(EndPoint endPoint, CancellationToken cancellation } EndPoint = endPoint; -#if NET6_0_OR_GREATER await Socket.ConnectAsync(endPoint, cancellationToken).ConfigureAwait(false); -#else - await Task.Factory.StartNew(() => Socket.Connect(endPoint), cancellationToken, TaskCreationOptions.None, TaskScheduler.Default).ConfigureAwait(false); -#endif Socket.Blocking = true; } @@ -45,7 +41,7 @@ public Task ReconnectAsync(bool isForce, CancellationToken cancellationToken = d else { // Already connected - nothing to do. - return TaskExExtensions.CompletedTask; + return Task.CompletedTask; } } diff --git a/AdvancedSharpAdbClient/TcpSocket.cs b/AdvancedSharpAdbClient/TcpSocket.cs index 48b0143d..088a5166 100644 --- a/AdvancedSharpAdbClient/TcpSocket.cs +++ b/AdvancedSharpAdbClient/TcpSocket.cs @@ -8,14 +8,14 @@ using System.IO; using System.Net; using System.Net.Sockets; -using System.Text; +using System.Runtime.CompilerServices; namespace AdvancedSharpAdbClient { /// /// Implements the interface using the standard class. /// - [DebuggerDisplay($"{nameof(TcpSocket)} \\{{ {nameof(Socket)} = {{{nameof(Socket)}}}, {nameof(Connected)} = {{{nameof(Connected)}}}, {nameof(EndPoint)} = {{{nameof(EndPoint)}}}, {nameof(ReceiveBufferSize)} = {{{nameof(ReceiveBufferSize)}}} }}")] + [DebuggerDisplay($"{{{nameof(GetType)}().{nameof(Type.ToString)}(),nq}} \\{{ {nameof(Socket)} = {{{nameof(Socket)}}}, {nameof(Connected)} = {{{nameof(Connected)}}}, {nameof(EndPoint)} = {{{nameof(EndPoint)}}}, {nameof(ReceiveBufferSize)} = {{{nameof(ReceiveBufferSize)}}} }}")] public sealed partial class TcpSocket : ITcpSocket, ICloneable, ICloneable { /// @@ -47,7 +47,7 @@ public int ReceiveBufferSize [MemberNotNull(nameof(EndPoint))] public void Connect(EndPoint endPoint) { - ExceptionExtensions.ThrowIfNull(endPoint); + ArgumentNullException.ThrowIfNull(endPoint); if (endPoint is not (IPEndPoint or DnsEndPoint)) { @@ -134,16 +134,29 @@ public int Receive(Span buffer, SocketFlags socketFlags) => /// public override string ToString() { - StringBuilder builder = - new StringBuilder("The ") - .Append(nameof(TcpSocket)); - return (Connected - ? builder.Append(" connect with ") - .Append(EndPoint) - : EndPoint == null - ? builder.Append(" without initialized") - : builder.Append(" disconnect with ") - .Append(EndPoint)).ToString(); + DefaultInterpolatedStringHandler handler = new(33, 1); + handler.AppendLiteral("The "); + handler.AppendFormatted(GetType()); + + if (Connected) + { + handler.AppendLiteral(" connect with '"); + handler.AppendFormatted(EndPoint); + handler.AppendFormatted('\''); + } + else if (EndPoint == null) + { + handler.AppendLiteral(" without initialized"); + } + else + { + handler.AppendLiteral(" disconnect with '"); + handler.AppendFormatted(EndPoint); + handler.AppendFormatted('\''); + } + + handler.AppendFormatted('.'); + return handler.ToStringAndClear(); } /// diff --git a/Directory.Build.props b/Directory.Build.props index b0a5d3aa..7dccf16d 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -10,7 +10,7 @@ True True True - latest + preview https://raw.githubusercontent.com/SharpAdb/AdvancedSharpAdbClient/main/logo.png Apache-2.0 https://github.com/SharpAdb/AdvancedSharpAdbClient @@ -23,13 +23,12 @@ https://github.com/SharpAdb/AdvancedSharpAdbClient snupkg .NET client for adb, Android Debug Bridge (AdvancedSharpAdbClient) - 3.4.14 + 3.5.15 False False - False False True $(MSBuildProjectName.Contains('.Test')) diff --git a/Directory.Build.props.buildschema.json b/Directory.Build.props.buildschema.json new file mode 100644 index 00000000..aa0cda1f --- /dev/null +++ b/Directory.Build.props.buildschema.json @@ -0,0 +1,23 @@ +{ + "$schema": "https://github.com/mhutch/MonoDevelop.MSBuildEditor/raw/refs/heads/main/MonoDevelop.MSBuild/Schemas/buildschema.json", + "properties": { + "FullTargets": { + "description": "Value indicating whether target to all platforms", + "type": "bool", + "defaultValue": "false" + }, + "ImportAsync": { + "description": "Value indicating whether reference the AsyncBridge and Microsoft.Bcl.Async", + "type": "bool", + "defaultValue": "false" + }, + "IsWindows": { + "description": "Value indicating whether is running on Windows", + "type": "bool" + }, + "IsTestProject": { + "description": "Value indicating whether the project is a test project", + "type": "bool" + } + } +} \ No newline at end of file