From 325a79db86d70433c5cde26db12c8f2c84ae3702 Mon Sep 17 00:00:00 2001 From: wherewhere Date: Mon, 14 Aug 2023 20:09:26 +0800 Subject: [PATCH 1/4] Improve virtual member of root --- .../Dummys/TracingAdbSocket.cs | 30 +------------ AdvancedSharpAdbClient/AdbClient.cs | 2 +- .../AdbCommandLineClient.Async.cs | 4 +- .../AdbCommandLineClient.cs | 8 ++-- AdvancedSharpAdbClient/AdbServer.Async.cs | 6 +-- AdvancedSharpAdbClient/AdbServer.cs | 14 +++--- AdvancedSharpAdbClient/AdbSocket.Async.cs | 26 +++++------ AdvancedSharpAdbClient/AdbSocket.cs | 43 +++++++++++-------- AdvancedSharpAdbClient/DeviceMonitor.Async.cs | 11 ++--- AdvancedSharpAdbClient/DeviceMonitor.cs | 19 ++++---- AdvancedSharpAdbClient/Models/Framebuffer.cs | 2 +- AdvancedSharpAdbClient/SyncService.Async.cs | 14 +++--- AdvancedSharpAdbClient/SyncService.cs | 31 ++++++++----- AdvancedSharpAdbClient/TcpSocket.Async.cs | 8 ++-- AdvancedSharpAdbClient/TcpSocket.cs | 32 ++++++++++---- 15 files changed, 131 insertions(+), 119 deletions(-) diff --git a/AdvancedSharpAdbClient.Tests/Dummys/TracingAdbSocket.cs b/AdvancedSharpAdbClient.Tests/Dummys/TracingAdbSocket.cs index bb3d5c3e..936ad99d 100644 --- a/AdvancedSharpAdbClient.Tests/Dummys/TracingAdbSocket.cs +++ b/AdvancedSharpAdbClient.Tests/Dummys/TracingAdbSocket.cs @@ -38,28 +38,14 @@ public TracingAdbSocket(EndPoint endPoint) : base(endPoint) public bool WaitForNewData { get; set; } - public override void Dispose() + protected override void Dispose(bool disposing) { if (DoDispose) { - base.Dispose(); + base.Dispose(disposing); } } - public override int Read(byte[] data) - { - StackTrace trace = new(); - - int read = base.Read(data); - - if (trace != null && trace.GetFrames()[1].GetMethod().DeclaringType != typeof(AdbSocket)) - { - SyncDataReceived.Enqueue(data); - } - - return read; - } - public override int Read(byte[] data, int length) { StackTrace trace = new(); @@ -146,18 +132,6 @@ public override SyncCommand ReadSyncResponse() return response; } - public override void Send(byte[] data, int length) - { - StackTrace trace = new(); - - base.Send(data, length); - - if (trace != null && trace.GetFrames()[1].GetMethod().DeclaringType != typeof(AdbSocket)) - { - SyncDataSent.Enqueue(data.Take(length).ToArray()); - } - } - public override void Reconnect() { base.Reconnect(); diff --git a/AdvancedSharpAdbClient/AdbClient.cs b/AdvancedSharpAdbClient/AdbClient.cs index ef4a49fc..362dc54d 100644 --- a/AdvancedSharpAdbClient/AdbClient.cs +++ b/AdvancedSharpAdbClient/AdbClient.cs @@ -48,7 +48,7 @@ public partial class AdbClient : IAdbClient [Obsolete("This function has been removed since SharpAdbClient. Here is a placeholder which function is gets a new instance instead of gets or sets the default instance.")] public static IAdbClient Instance => new AdbClient(); - private readonly Func adbSocketFactory; + protected readonly Func adbSocketFactory; /// /// Initializes a new instance of the class. diff --git a/AdvancedSharpAdbClient/AdbCommandLineClient.Async.cs b/AdvancedSharpAdbClient/AdbCommandLineClient.Async.cs index 6ddfd676..8a58c5d2 100644 --- a/AdvancedSharpAdbClient/AdbCommandLineClient.Async.cs +++ b/AdvancedSharpAdbClient/AdbCommandLineClient.Async.cs @@ -19,7 +19,7 @@ public partial class AdbCommandLineClient /// /// A which can be used to cancel the asynchronous operation. /// A which return a object that contains the version number of the Android Command Line client. - public async Task GetVersionAsync(CancellationToken cancellationToken = default) + public virtual async Task GetVersionAsync(CancellationToken cancellationToken = default) { // Run the adb.exe version command and capture the output. List standardOutput = new(); @@ -46,7 +46,7 @@ public async Task GetVersionAsync(CancellationToken cancellationToken = /// /// A which can be used to cancel the asynchronous operation. /// A which represents the asynchronous operation. - public async Task StartServerAsync(CancellationToken cancellationToken = default) + public virtual async Task StartServerAsync(CancellationToken cancellationToken = default) { int status = await RunAdbProcessInnerAsync("start-server", null, null, cancellationToken); diff --git a/AdvancedSharpAdbClient/AdbCommandLineClient.cs b/AdvancedSharpAdbClient/AdbCommandLineClient.cs index 1a733b0e..8cd435c8 100644 --- a/AdvancedSharpAdbClient/AdbCommandLineClient.cs +++ b/AdvancedSharpAdbClient/AdbCommandLineClient.cs @@ -20,13 +20,13 @@ public partial class AdbCommandLineClient : IAdbCommandLineClient /// /// The regex pattern for getting the adb version from the adb version command. /// - private const string AdbVersionPattern = "^.*(\\d+)\\.(\\d+)\\.(\\d+)$"; + protected const string AdbVersionPattern = "^.*(\\d+)\\.(\\d+)\\.(\\d+)$"; #if HAS_LOGGER /// /// The logger to use when logging messages. /// - private readonly ILogger logger; + protected readonly ILogger logger; #endif #if !HAS_LOGGER @@ -94,7 +94,7 @@ public AdbCommandLineClient(string adbPath, bool isForce = false /// Queries adb for its version number and checks it against . /// /// A object that contains the version number of the Android Command Line client. - public Version GetVersion() + public virtual Version GetVersion() { // Run the adb.exe version command and capture the output. List standardOutput = new(); @@ -119,7 +119,7 @@ public Version GetVersion() /// /// Starts the adb server by running the adb start-server command. /// - public void StartServer() + public virtual void StartServer() { int status = RunAdbProcessInner("start-server", null, null); diff --git a/AdvancedSharpAdbClient/AdbServer.Async.cs b/AdvancedSharpAdbClient/AdbServer.Async.cs index b328c6ab..3dc11978 100644 --- a/AdvancedSharpAdbClient/AdbServer.Async.cs +++ b/AdvancedSharpAdbClient/AdbServer.Async.cs @@ -13,7 +13,7 @@ namespace AdvancedSharpAdbClient public partial class AdbServer { /// - public async Task StartServerAsync(string adbPath, bool restartServerIfNewer, CancellationToken cancellationToken = default) + public virtual async Task StartServerAsync(string adbPath, bool restartServerIfNewer, CancellationToken cancellationToken = default) { AdbServerStatus serverStatus = await GetStatusAsync(cancellationToken); Version commandLineVersion = null; @@ -66,7 +66,7 @@ public async Task StartServerAsync(string adbPath, bool resta public Task RestartServerAsync(CancellationToken cancellationToken = default) => RestartServerAsync(null, cancellationToken); /// - public async Task RestartServerAsync(string adbPath, CancellationToken cancellationToken = default) + public virtual async Task RestartServerAsync(string adbPath, CancellationToken cancellationToken = default) { adbPath ??= cachedAdbPath; @@ -99,7 +99,7 @@ await Utilities.Run(() => } /// - public async Task GetStatusAsync(CancellationToken cancellationToken = default) + public virtual async Task GetStatusAsync(CancellationToken cancellationToken = default) { // Try to connect to a running instance of the adb server try diff --git a/AdvancedSharpAdbClient/AdbServer.cs b/AdvancedSharpAdbClient/AdbServer.cs index f82abfd4..a08a9d72 100644 --- a/AdvancedSharpAdbClient/AdbServer.cs +++ b/AdvancedSharpAdbClient/AdbServer.cs @@ -49,25 +49,25 @@ public partial class AdbServer : IAdbServer /// /// A lock used to ensure only one caller at a time can attempt to restart adb. /// - private static readonly object RestartLock = new(); + protected static readonly object RestartLock = new(); /// /// The path to the adb server. Cached from calls to . Used when restarting /// the server to figure out where adb is located. /// - private static string cachedAdbPath; + protected static string cachedAdbPath; /// /// The current ADB client that manages the connection. /// - private readonly IAdbClient adbClient; + protected readonly IAdbClient adbClient; /// /// Gets or sets a function that returns a new instance of a class that implements the /// interface, that can be used to interact with the /// adb.exe command line client. /// - private readonly Func adbCommandLineClientFactory; + protected readonly Func adbCommandLineClientFactory; /// /// Initializes a new instance of the class. @@ -109,7 +109,7 @@ public AdbServer(IAdbClient adbClient, Func adbCo public static IAdbServer Instance { get; set; } = new AdbServer(); /// - public StartServerResult StartServer(string adbPath, bool restartServerIfNewer) + public virtual StartServerResult StartServer(string adbPath, bool restartServerIfNewer) { AdbServerStatus serverStatus = GetStatus(); Version commandLineVersion = null; @@ -159,7 +159,7 @@ public StartServerResult StartServer(string adbPath, bool restartServerIfNewer) } /// - public StartServerResult RestartServer(string adbPath = null) + public virtual StartServerResult RestartServer(string adbPath = null) { adbPath ??= cachedAdbPath; @@ -175,7 +175,7 @@ public StartServerResult RestartServer(string adbPath = null) } /// - public AdbServerStatus GetStatus() + public virtual AdbServerStatus GetStatus() { // Try to connect to a running instance of the adb server try diff --git a/AdvancedSharpAdbClient/AdbSocket.Async.cs b/AdvancedSharpAdbClient/AdbSocket.Async.cs index 04b3d030..34559e0b 100644 --- a/AdvancedSharpAdbClient/AdbSocket.Async.cs +++ b/AdvancedSharpAdbClient/AdbSocket.Async.cs @@ -15,7 +15,7 @@ namespace AdvancedSharpAdbClient public partial class AdbSocket { /// - public virtual Task SendAsync(byte[] data, int length, CancellationToken cancellationToken = default) => SendAsync(data, 0, length, cancellationToken); + public Task SendAsync(byte[] data, int length, CancellationToken cancellationToken = default) => SendAsync(data, 0, length, cancellationToken); /// public virtual async Task SendAsync(byte[] data, int offset, int length, CancellationToken cancellationToken = default) @@ -41,7 +41,7 @@ public virtual async Task SendAsync(byte[] data, int offset, int length, Cancell } /// - public virtual Task SendSyncRequestAsync(SyncCommand command, string path, int permissions, CancellationToken cancellationToken = default) => + public Task SendSyncRequestAsync(SyncCommand command, string path, int permissions, CancellationToken cancellationToken = default) => SendSyncRequestAsync(command, $"{path},{permissions}", cancellationToken); /// @@ -87,7 +87,7 @@ public virtual async Task SendAdbRequestAsync(string request, CancellationToken } /// - public virtual Task ReadAsync(byte[] data, CancellationToken cancellationToken = default) => + public Task ReadAsync(byte[] data, CancellationToken cancellationToken = default) => ReadAsync(data, data.Length, cancellationToken); /// @@ -205,7 +205,7 @@ public virtual async Task ReadAdbResponseAsync(CancellationToken ca } /// - public async Task SetDeviceAsync(DeviceData device, CancellationToken cancellationToken = default) + public virtual async Task SetDeviceAsync(DeviceData device, CancellationToken cancellationToken = default) { // if the device is not null, then we first tell adb we're looking to talk // to a specific device @@ -238,7 +238,7 @@ public async Task SetDeviceAsync(DeviceData device, CancellationToken cancellati /// A which can be used to cancel the asynchronous task. /// Returns if all data was written; otherwise, . /// This uses the default time out value. - protected async Task WriteAsync(byte[] data, CancellationToken cancellationToken = default) + protected virtual async Task WriteAsync(byte[] data, CancellationToken cancellationToken = default) { try { @@ -263,27 +263,27 @@ protected async Task WriteAsync(byte[] data, CancellationToken cancellatio /// /// A which can be used to cancel the asynchronous task. /// A that represents the response received from ADB. - protected async Task ReadAdbResponseInnerAsync(CancellationToken cancellationToken = default) + protected virtual async Task ReadAdbResponseInnerAsync(CancellationToken cancellationToken = default) { - AdbResponse resp = new(); + AdbResponse rasps = new(); byte[] reply = new byte[4]; _ = await ReadAsync(reply, cancellationToken); - resp.IOSuccess = true; + rasps.IOSuccess = true; - resp.Okay = IsOkay(reply); + rasps.Okay = IsOkay(reply); - if (!resp.Okay) + if (!rasps.Okay) { string message = await ReadStringAsync(cancellationToken); - resp.Message = message; + rasps.Message = message; #if HAS_LOGGER - logger.LogError($"Got reply '{ReplyToString(reply)}', diag='{resp.Message}'"); + logger.LogError($"Got reply '{ReplyToString(reply)}', diag='{rasps.Message}'"); #endif } - return resp; + return rasps; } } } diff --git a/AdvancedSharpAdbClient/AdbSocket.cs b/AdvancedSharpAdbClient/AdbSocket.cs index 2af502bd..e8430f9e 100644 --- a/AdvancedSharpAdbClient/AdbSocket.cs +++ b/AdvancedSharpAdbClient/AdbSocket.cs @@ -29,13 +29,13 @@ public partial class AdbSocket : IAdbSocket /// /// The underlying TCP socket that manages the connection with the ADB server. /// - private readonly ITcpSocket socket; + protected readonly ITcpSocket socket; #if HAS_LOGGER /// /// The logger to use when logging messages. /// - private readonly ILogger logger; + protected readonly ILogger logger; #endif #if !HAS_LOGGER @@ -130,7 +130,7 @@ public AdbSocket(ITcpSocket socket) public virtual void Reconnect() => socket.Reconnect(); /// - public virtual void Send(byte[] data, int length) => Send(data, 0, length); + public void Send(byte[] data, int length) => Send(data, 0, length); /// public virtual void Send(byte[] data, int offset, int length) @@ -156,7 +156,7 @@ public virtual void Send(byte[] data, int offset, int length) } /// - public virtual void SendSyncRequest(SyncCommand command, string path, int permissions) => + public void SendSyncRequest(SyncCommand command, string path, int permissions) => SendSyncRequest(command, $"{path},{permissions}"); /// @@ -202,7 +202,7 @@ public virtual void SendAdbRequest(string request) } /// - public virtual int Read(byte[] data) => Read(data, data.Length); + public int Read(byte[] data) => Read(data, data.Length); /// public virtual int Read(byte[] data, int length) @@ -358,7 +358,7 @@ public void SetDevice(DeviceData device) /// The data to send. /// Returns if all data was written; otherwise, . /// This uses the default time out value. - protected bool Write(byte[] data) + protected virtual bool Write(byte[] data) { try { @@ -382,27 +382,27 @@ protected bool Write(byte[] data) /// Reads the response from ADB after a command. /// /// A that represents the response received from ADB. - protected AdbResponse ReadAdbResponseInner() + protected virtual AdbResponse ReadAdbResponseInner() { - AdbResponse resp = new(); + AdbResponse rasps = new(); byte[] reply = new byte[4]; Read(reply); - resp.IOSuccess = true; + rasps.IOSuccess = true; - resp.Okay = IsOkay(reply); + rasps.Okay = IsOkay(reply); - if (!resp.Okay) + if (!rasps.Okay) { string message = ReadString(); - resp.Message = message; + rasps.Message = message; #if HAS_LOGGER - logger.LogError($"Got reply '{ReplyToString(reply)}', diag='{resp.Message}'"); + logger.LogError($"Got reply '{ReplyToString(reply)}', diag='{rasps.Message}'"); #endif } - return resp; + return rasps; } /// @@ -410,7 +410,7 @@ protected AdbResponse ReadAdbResponseInner() /// /// A array that represents the ADB reply. /// A that represents the ADB reply. - protected string ReplyToString(byte[] reply) + protected virtual string ReplyToString(byte[] reply) { string result; try @@ -434,9 +434,18 @@ protected string ReplyToString(byte[] reply) /// /// Releases all resources used by the current instance of the class. /// - public virtual void Dispose() + protected virtual void Dispose(bool disposing) { - socket.Dispose(); + if (disposing) + { + socket.Dispose(); + } + } + + /// + public void Dispose() + { + Dispose(disposing: true); GC.SuppressFinalize(this); } } diff --git a/AdvancedSharpAdbClient/DeviceMonitor.Async.cs b/AdvancedSharpAdbClient/DeviceMonitor.Async.cs index 76c308d1..f441cab9 100644 --- a/AdvancedSharpAdbClient/DeviceMonitor.Async.cs +++ b/AdvancedSharpAdbClient/DeviceMonitor.Async.cs @@ -16,20 +16,20 @@ public partial class DeviceMonitor /// is used to block the method until the /// has processed the first list of devices. /// - private readonly ManualResetEvent firstDeviceListParsed = new(false); + protected readonly ManualResetEvent firstDeviceListParsed = new(false); /// /// A that can be used to cancel the . /// - private readonly CancellationTokenSource monitorTaskCancellationTokenSource = new(); + protected readonly CancellationTokenSource monitorTaskCancellationTokenSource = new(); /// /// The that monitors the and waits for device notifications. /// - private Task monitorTask; + protected Task monitorTask; /// - public async Task StartAsync(CancellationToken cancellationToken = default) + public virtual async Task StartAsync(CancellationToken cancellationToken = default) { if (monitorTask == null) { @@ -94,6 +94,7 @@ public async DisposeAsync() { await DisposeAsyncCore().ConfigureAwait(false); + Dispose(disposing: false); #if NETCOREAPP3_0_OR_GREATER || NETSTANDARD2_1_OR_GREATER GC.SuppressFinalize(this); #else @@ -106,7 +107,7 @@ public async /// /// A which can be used to cancel the asynchronous operation. /// A which represents the asynchronous operation. - private async Task DeviceMonitorLoopAsync(CancellationToken cancellationToken = default) + protected virtual async Task DeviceMonitorLoopAsync(CancellationToken cancellationToken = default) { IsRunning = true; diff --git a/AdvancedSharpAdbClient/DeviceMonitor.cs b/AdvancedSharpAdbClient/DeviceMonitor.cs index 82e724fc..f7ae7ac3 100644 --- a/AdvancedSharpAdbClient/DeviceMonitor.cs +++ b/AdvancedSharpAdbClient/DeviceMonitor.cs @@ -39,13 +39,13 @@ public partial class DeviceMonitor : IDeviceMonitor /// /// The logger to use when logging messages. /// - private readonly ILogger logger; + protected readonly ILogger logger; #endif /// /// The list of devices currently connected to the Android Debug Bridge. /// - private readonly List devices; + protected readonly List devices; #if !HAS_TASK /// @@ -53,17 +53,17 @@ public partial class DeviceMonitor : IDeviceMonitor /// is used to block the method until the /// has processed the first list of devices. /// - private readonly ManualResetEvent firstDeviceListParsed = new(false); + protected readonly ManualResetEvent firstDeviceListParsed = new(false); /// /// A that can be used to cancel the . /// - private bool isMonitorThreadCancel = false; + protected bool isMonitorThreadCancel = false; /// /// The that monitors the and waits for device notifications. /// - private Thread monitorThread; + protected Thread monitorThread; #endif #if !HAS_LOGGER @@ -119,7 +119,7 @@ public DeviceMonitor(IAdbSocket socket public bool IsRunning { get; private set; } /// - public void Start() + public virtual void Start() { #if HAS_TASK if (monitorTask == null) @@ -237,7 +237,7 @@ public void Dispose() /// /// Monitors the devices. This connects to the Debug Bridge /// - private void DeviceMonitorLoop() + protected virtual void DeviceMonitorLoop() { IsRunning = true; @@ -291,7 +291,10 @@ private void ProcessIncomingDeviceData(string result) UpdateDevices(currentDevices); } - private void UpdateDevices(IEnumerable devices) + /// + /// Processes the incoming . + /// + protected virtual void UpdateDevices(IEnumerable devices) { lock (this.devices) { diff --git a/AdvancedSharpAdbClient/Models/Framebuffer.cs b/AdvancedSharpAdbClient/Models/Framebuffer.cs index f81879c1..fe1f8145 100644 --- a/AdvancedSharpAdbClient/Models/Framebuffer.cs +++ b/AdvancedSharpAdbClient/Models/Framebuffer.cs @@ -239,7 +239,7 @@ public Task ToBitmap(DispatcherQueue dispatcher, CancellationTo /// protected virtual void Dispose(bool disposing) { - if (!disposed) + if (!disposed && disposing) { #if HAS_BUFFERS if (Data != null) diff --git a/AdvancedSharpAdbClient/SyncService.Async.cs b/AdvancedSharpAdbClient/SyncService.Async.cs index 98b55d0d..d7fc5d85 100644 --- a/AdvancedSharpAdbClient/SyncService.Async.cs +++ b/AdvancedSharpAdbClient/SyncService.Async.cs @@ -16,7 +16,7 @@ namespace AdvancedSharpAdbClient public partial class SyncService { /// - public async Task OpenAsync(CancellationToken cancellationToken = default) + public virtual async Task OpenAsync(CancellationToken cancellationToken = default) { // target a specific device await Socket.SetDeviceAsync(Device, cancellationToken); @@ -31,7 +31,7 @@ public async Task OpenAsync(CancellationToken cancellationToken = default) /// A that enables to connection with the adb server. /// A which can be used to cancel the asynchronous operation. /// A which represents the asynchronous operation. - public Task ReopenAsync(IAdbSocket socket, CancellationToken cancellationToken = default) + public virtual Task ReopenAsync(IAdbSocket socket, CancellationToken cancellationToken = default) { if (Socket != null) { @@ -51,7 +51,7 @@ public Task ReopenAsync(IAdbSocket socket, CancellationToken cancellationToken = public Task ReopenAsync(IAdbClient client, CancellationToken cancellationToken = default) => ReopenAsync(Factories.AdbSocketFactory(client.EndPoint), cancellationToken); /// - public async Task PushAsync(Stream stream, string remotePath, int permissions, DateTimeOffset timestamp, IProgress progress, CancellationToken cancellationToken = default) + public virtual async Task PushAsync(Stream stream, string remotePath, int permissions, DateTimeOffset timestamp, IProgress progress, CancellationToken cancellationToken = default) { ExceptionExtensions.ThrowIfNull(stream); @@ -143,7 +143,7 @@ public async Task PushAsync(Stream stream, string remotePath, int permissions, D } /// - public async Task PullAsync(string remoteFilePath, Stream stream, IProgress progress, CancellationToken cancellationToken = default) + public virtual async Task PullAsync(string remoteFilePath, Stream stream, IProgress progress, CancellationToken cancellationToken = default) { ExceptionExtensions.ThrowIfNull(remoteFilePath); @@ -215,7 +215,7 @@ public async Task PullAsync(string remoteFilePath, Stream stream, IProgress } /// - public async Task StatAsync(string remotePath, CancellationToken cancellationToken = default) + public virtual async Task StatAsync(string remotePath, CancellationToken cancellationToken = default) { // create the stat request message. await Socket.SendSyncRequestAsync(SyncCommand.STAT, remotePath, cancellationToken); @@ -238,7 +238,7 @@ public async Task StatAsync(string remotePath, CancellationToken } /// - public async Task> GetDirectoryListingAsync(string remotePath, CancellationToken cancellationToken = default) + public virtual async Task> GetDirectoryListingAsync(string remotePath, CancellationToken cancellationToken = default) { Collection value = new(); @@ -270,7 +270,7 @@ public async Task> GetDirectoryListingAsync(string r #if NETCOREAPP3_0_OR_GREATER || NETSTANDARD2_1_OR_GREATER /// - public async IAsyncEnumerable GetDirectoryAsyncListing(string remotePath, [EnumeratorCancellation] CancellationToken cancellationToken = default) + public virtual async IAsyncEnumerable GetDirectoryAsyncListing(string remotePath, [EnumeratorCancellation] CancellationToken cancellationToken = default) { // create the stat request message. await Socket.SendSyncRequestAsync(SyncCommand.LIST, remotePath, cancellationToken); diff --git a/AdvancedSharpAdbClient/SyncService.cs b/AdvancedSharpAdbClient/SyncService.cs index 4fd23f96..d29577ab 100644 --- a/AdvancedSharpAdbClient/SyncService.cs +++ b/AdvancedSharpAdbClient/SyncService.cs @@ -45,7 +45,7 @@ public partial class SyncService : ISyncService /// /// The maximum length of a path on the remote device. /// - private const int MaxPathLength = 1024; + protected const int MaxPathLength = 1024; /// public event EventHandler SyncProgressChanged; @@ -91,7 +91,7 @@ public SyncService(IAdbSocket socket, DeviceData device) public bool IsOpen => Socket != null && Socket.Connected; /// - public void Open() + public virtual void Open() { // target a specific device Socket.SetDevice(Device); @@ -104,7 +104,7 @@ public void Open() /// Reopen this connection. /// /// A that enables to connection with the adb server. - public void Reopen(IAdbSocket socket) + public virtual void Reopen(IAdbSocket socket) { if (Socket != null) { @@ -122,7 +122,7 @@ public void Reopen(IAdbSocket socket) public void Reopen(IAdbClient client) => Reopen(Factories.AdbSocketFactory(client.EndPoint)); /// - public void Push(Stream stream, string remotePath, int permissions, DateTimeOffset timestamp, IProgress progress + public virtual void Push(Stream stream, string remotePath, int permissions, DateTimeOffset timestamp, IProgress progress #if HAS_TASK , CancellationToken cancellationToken = default #endif @@ -220,7 +220,7 @@ public void Push(Stream stream, string remotePath, int permissions, DateTimeOffs } /// - public void Pull(string remoteFilePath, Stream stream, IProgress progress + public virtual void Pull(string remoteFilePath, Stream stream, IProgress progress #if HAS_TASK , CancellationToken cancellationToken = default #endif @@ -291,7 +291,7 @@ public void Pull(string remoteFilePath, Stream stream, IProgress progress } /// - public FileStatistics Stat(string remotePath) + public virtual FileStatistics Stat(string remotePath) { // create the stat request message. Socket.SendSyncRequest(SyncCommand.STAT, remotePath); @@ -314,7 +314,7 @@ public FileStatistics Stat(string remotePath) } /// - public IEnumerable GetDirectoryListing(string remotePath) + public virtual IEnumerable GetDirectoryListing(string remotePath) { // create the stat request message. Socket.SendSyncRequest(SyncCommand.LIST, remotePath); @@ -343,13 +343,22 @@ public IEnumerable GetDirectoryListing(string remotePath) /// /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. /// - public void Dispose() + protected virtual void Dispose(bool disposing) { - if (Socket != null) + if (disposing) { - Socket.Dispose(); - Socket = null; + if (Socket != null) + { + Socket.Dispose(); + Socket = null; + } } + } + + /// + public void Dispose() + { + Dispose(disposing: true); GC.SuppressFinalize(this); } diff --git a/AdvancedSharpAdbClient/TcpSocket.Async.cs b/AdvancedSharpAdbClient/TcpSocket.Async.cs index c529f989..d4387163 100644 --- a/AdvancedSharpAdbClient/TcpSocket.Async.cs +++ b/AdvancedSharpAdbClient/TcpSocket.Async.cs @@ -13,21 +13,21 @@ public partial class TcpSocket { #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER /// - public async Task SendAsync(byte[] buffer, int offset, int size, SocketFlags socketFlags, CancellationToken cancellationToken = default) => + public virtual async Task SendAsync(byte[] buffer, int offset, int size, SocketFlags socketFlags, CancellationToken cancellationToken = default) => await socket.SendAsync(buffer.AsMemory().Slice(offset, size), socketFlags, cancellationToken); #else /// - public async Task SendAsync(byte[] buffer, int offset, int size, SocketFlags socketFlags, CancellationToken cancellationToken = default) => + public virtual async Task SendAsync(byte[] buffer, int offset, int size, SocketFlags socketFlags, CancellationToken cancellationToken = default) => await Utilities.Run(() => Send(buffer, offset, size, socketFlags), cancellationToken); #endif #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER /// - public async Task ReceiveAsync(byte[] buffer, int offset, int size, SocketFlags socketFlags, CancellationToken cancellationToken = default) => + public virtual async Task ReceiveAsync(byte[] buffer, int offset, int size, SocketFlags socketFlags, CancellationToken cancellationToken = default) => await socket.ReceiveAsync(buffer.AsMemory().Slice(offset, size), socketFlags, cancellationToken); #else /// - public Task ReceiveAsync(byte[] buffer, int offset, int size, SocketFlags socketFlags, CancellationToken cancellationToken = default) => + public virtual Task ReceiveAsync(byte[] buffer, int offset, int size, SocketFlags socketFlags, CancellationToken cancellationToken = default) => socket.ReceiveAsync(buffer, offset, size, socketFlags, cancellationToken); #endif } diff --git a/AdvancedSharpAdbClient/TcpSocket.cs b/AdvancedSharpAdbClient/TcpSocket.cs index 1a535f9b..129a74ca 100644 --- a/AdvancedSharpAdbClient/TcpSocket.cs +++ b/AdvancedSharpAdbClient/TcpSocket.cs @@ -10,12 +10,19 @@ namespace AdvancedSharpAdbClient { /// - /// Implements the interface using the standard class. + /// Implements the interface using the standard class. /// public partial class TcpSocket : ITcpSocket { - private Socket socket; - private EndPoint endPoint; + /// + /// The underlying socket that manages the connection. + /// + protected Socket socket; + + /// + /// The at which the socket is listening. + /// + protected EndPoint endPoint; /// /// Initializes a new instance of the class. @@ -33,7 +40,7 @@ public int ReceiveBufferSize } /// - public void Connect(EndPoint endPoint) + public virtual void Connect(EndPoint endPoint) { if (endPoint is not (IPEndPoint or DnsEndPoint)) { @@ -46,7 +53,7 @@ public void Connect(EndPoint endPoint) } /// - public void Reconnect() + public virtual void Reconnect() { if (socket.Connected) { @@ -58,19 +65,28 @@ public void Reconnect() Connect(endPoint); } + /// + protected virtual void Dispose(bool disposing) + { + if (disposing) + { + socket.Dispose(); + } + } + /// public void Dispose() { - socket.Dispose(); + Dispose(disposing: true); GC.SuppressFinalize(this); } /// - public int Send(byte[] buffer, int offset, int size, SocketFlags socketFlags) => + public virtual int Send(byte[] buffer, int offset, int size, SocketFlags socketFlags) => socket.Send(buffer, offset, size, socketFlags); /// - public int Receive(byte[] buffer, int size, SocketFlags socketFlags) => + public virtual int Receive(byte[] buffer, int size, SocketFlags socketFlags) => socket.Receive(buffer, size, socketFlags); /// From 3933af83d2f96e678bc0c295cec54c0438a2ff5f Mon Sep 17 00:00:00 2001 From: wherewhere Date: Mon, 14 Aug 2023 20:23:39 +0800 Subject: [PATCH 2/4] Improve virtual member of Receivers --- AdvancedSharpAdbClient/AdbClient.cs | 3 ++ .../Receivers/ConsoleOutputReceiver.cs | 36 ++++++++++++++----- .../Receivers/MultilineReceiver.cs | 12 +++---- 3 files changed, 35 insertions(+), 16 deletions(-) diff --git a/AdvancedSharpAdbClient/AdbClient.cs b/AdvancedSharpAdbClient/AdbClient.cs index 362dc54d..5b88c78c 100644 --- a/AdvancedSharpAdbClient/AdbClient.cs +++ b/AdvancedSharpAdbClient/AdbClient.cs @@ -48,6 +48,9 @@ public partial class AdbClient : IAdbClient [Obsolete("This function has been removed since SharpAdbClient. Here is a placeholder which function is gets a new instance instead of gets or sets the default instance.")] public static IAdbClient Instance => new AdbClient(); + /// + /// The to create . + /// protected readonly Func adbSocketFactory; /// diff --git a/AdvancedSharpAdbClient/Receivers/ConsoleOutputReceiver.cs b/AdvancedSharpAdbClient/Receivers/ConsoleOutputReceiver.cs index 058bd969..5ad3702f 100644 --- a/AdvancedSharpAdbClient/Receivers/ConsoleOutputReceiver.cs +++ b/AdvancedSharpAdbClient/Receivers/ConsoleOutputReceiver.cs @@ -14,21 +14,24 @@ namespace AdvancedSharpAdbClient /// Receives console output, and makes the console output available as a . To /// fetch the console output that was received, used the method. /// - public class ConsoleOutputReceiver : MultiLineReceiver + public partial class ConsoleOutputReceiver : MultiLineReceiver { - private const RegexOptions DefaultRegexOptions = RegexOptions.Singleline | RegexOptions.IgnoreCase; + /// + /// The default to use when parsing the output. + /// + protected const RegexOptions DefaultRegexOptions = RegexOptions.Singleline | RegexOptions.IgnoreCase; #if HAS_LOGGER /// /// The logger to use when logging messages. /// - private readonly ILogger logger; + protected readonly ILogger logger; #endif /// /// A which receives all output from the device. /// - private readonly StringBuilder output = new(); + protected readonly StringBuilder output = new(); #if !HAS_LOGGER #pragma warning disable CS1572 // XML 注释中有 param 标记,但是没有该名称的参数 @@ -61,7 +64,7 @@ public ConsoleOutputReceiver( /// Throws an error message if the console output line contains an error message. /// /// The line to inspect. - public void ThrowOnError(string line) + public virtual void ThrowOnError(string line) { if (!ParsesErrors) { @@ -91,7 +94,7 @@ public void ThrowOnError(string line) } // for "aborting" commands - if (Regex.IsMatch(line, "Aborting.$", DefaultRegexOptions)) + if (AbortingRegex().IsMatch(line)) { #if HAS_LOGGER logger.LogWarning($"The remote execution returned: {line}"); @@ -101,7 +104,7 @@ public void ThrowOnError(string line) // for busybox applets // cmd: applet not found - if (Regex.IsMatch(line, "applet not found$", DefaultRegexOptions)) + if (AppletRegex().IsMatch(line)) { #if HAS_LOGGER logger.LogWarning($"The remote execution returned: '{line}'"); @@ -111,7 +114,7 @@ public void ThrowOnError(string line) // checks if the permission to execute the command was denied. // workitem: 16822 - if (Regex.IsMatch(line, "(permission|access) denied$", DefaultRegexOptions)) + if (DeniedRegex().IsMatch(line)) { #if HAS_LOGGER logger.LogWarning($"The remote execution returned: '{line}'"); @@ -141,5 +144,22 @@ protected override void ProcessNewLines(IEnumerable lines) #endif } } + +#if NET7_0_OR_GREATER + [GeneratedRegex("Aborting.$", DefaultRegexOptions)] + private static partial Regex AbortingRegex(); + + [GeneratedRegex("applet not found$", DefaultRegexOptions)] + private static partial Regex AppletRegex(); + + [GeneratedRegex("(permission|access) denied$", DefaultRegexOptions)] + private static partial Regex DeniedRegex(); +#else + private static Regex AbortingRegex() => new("Aborting.$", DefaultRegexOptions); + + private static Regex AppletRegex() => new("applet not found$", DefaultRegexOptions); + + private static Regex DeniedRegex() => new("(permission|access) denied$", DefaultRegexOptions); +#endif } } diff --git a/AdvancedSharpAdbClient/Receivers/MultilineReceiver.cs b/AdvancedSharpAdbClient/Receivers/MultilineReceiver.cs index 2a53d6f0..095a797f 100644 --- a/AdvancedSharpAdbClient/Receivers/MultilineReceiver.cs +++ b/AdvancedSharpAdbClient/Receivers/MultilineReceiver.cs @@ -25,9 +25,7 @@ public abstract class MultiLineReceiver : IShellOutputReceiver /// /// Gets or sets a value indicating whether the receiver parses error messages. /// - /// - /// if this receiver parsers error messages; otherwise . - /// + /// if this receiver parsers error messages; otherwise . /// /// The default value is . If set to , the /// will detect common error messages and throw an exception. @@ -43,15 +41,13 @@ public abstract class MultiLineReceiver : IShellOutputReceiver /// /// Adds a line to the output. /// - /// - /// The line to add to the output. - /// - public void AddOutput(string line) => Lines.Add(line); + /// The line to add to the output. + public virtual void AddOutput(string line) => Lines.Add(line); /// /// Flushes the output. /// - public void Flush() + public virtual void Flush() { if (Lines.Count > 0) { From ec8601576a6727072d467ea9e540e9fd5ffa950c Mon Sep 17 00:00:00 2001 From: wherewhere Date: Mon, 14 Aug 2023 20:50:50 +0800 Subject: [PATCH 3/4] Add IXmlNode of Element --- AdvancedSharpAdbClient/Models/Element.cs | 75 ++++++++++++++++++-- AdvancedSharpAdbClient/Models/Framebuffer.cs | 14 ++-- 2 files changed, 75 insertions(+), 14 deletions(-) diff --git a/AdvancedSharpAdbClient/Models/Element.cs b/AdvancedSharpAdbClient/Models/Element.cs index 6a9b1ba1..315a13e6 100644 --- a/AdvancedSharpAdbClient/Models/Element.cs +++ b/AdvancedSharpAdbClient/Models/Element.cs @@ -17,12 +17,12 @@ public class Element /// /// Gets or sets the current ADB client that manages the connection. /// - private IAdbClient Client { get; set; } + protected IAdbClient Client { get; set; } /// /// Gets the current device containing the element. /// - private DeviceData Device { get; } + protected DeviceData Device { get; } /// /// Gets the coordinates and size of the element. @@ -54,10 +54,7 @@ public class Element /// /// The zero-based index of the element to get or set. /// The element at the specified index. - public Element this[int index] - { - get => Children[index]; - } + public Element this[int index] => Children[index]; /// /// Initializes a new instance of the class. @@ -110,6 +107,31 @@ public Element(IAdbClient client, DeviceData device, XmlNode node, List Cords = area.Center; // Average x1, y1, x2, y2 } +#if WINDOWS_UWP || WINDOWS10_0_17763_0_OR_GREATER + /// + /// Initializes a new instance of the class. + /// + /// The current ADB client that manages the connection. + /// The current device containing the element. + /// The of the element. + /// The children of the element. + /// The coordinates and size of the element. + /// Gets or sets element attributes. + public Element(IAdbClient client, DeviceData device, Windows.Data.Xml.Dom.IXmlNode node, List children, Area area, Dictionary attributes) + { + XmlDocument doc = new(); + doc.LoadXml(node.GetXml()); + + Client = client; + Device = device; + Node = doc.FirstChild; + Children = children; + Area = area; + Attributes = attributes; + Cords = area.Center; // Average x1, y1, x2, y2 + } +#endif + /// /// Creates a new with the specified . /// @@ -147,10 +169,49 @@ public static Element FromXmlNode(IAdbClient client, DeviceData device, XmlNode return null; } +#if WINDOWS_UWP || WINDOWS10_0_17763_0_OR_GREATER + /// + /// Creates a new with the specified . + /// + /// The current ADB client that manages the connection. + /// The current device containing the element. + /// The of the element. + /// The new that this method creates. + public static Element FromIXmlNode(IAdbClient client, DeviceData device, Windows.Data.Xml.Dom.IXmlNode xmlNode) + { + string bounds = xmlNode.Attributes?.GetNamedItem("bounds")?.NodeValue?.ToString(); + if (bounds != null) + { + int[] cords = bounds.Replace("][", ",").Replace("[", "").Replace("]", "").Split(',').Select(int.Parse).ToArray(); // x1, y1, x2, y2 + Dictionary attributes = new(xmlNode.Attributes.Count); + foreach (Windows.Data.Xml.Dom.IXmlNode at in xmlNode.Attributes) + { + attributes[at.NodeName] = at.NodeValue.ToString(); + } + Area area = Area.FromLTRB(cords[0], cords[1], cords[2], cords[3]); + Windows.Data.Xml.Dom.XmlNodeList childNodes = xmlNode.ChildNodes; + List elements = new(childNodes?.Count ?? 0); + if (childNodes != null) + { + foreach (Windows.Data.Xml.Dom.IXmlNode childNode in childNodes) + { + Element element = FromIXmlNode(client, device, childNode); + if (element != null) + { + elements.Add(element); + } + } + } + return new Element(client, device, xmlNode, elements, area, attributes); + } + return null; + } +#endif + /// /// Gets the count of in this element. /// - public int GetChildCount() + public virtual int GetChildCount() { int count = Children.Count; Children.ForEach(x => count += x.GetChildCount()); diff --git a/AdvancedSharpAdbClient/Models/Framebuffer.cs b/AdvancedSharpAdbClient/Models/Framebuffer.cs index fe1f8145..6093e46a 100644 --- a/AdvancedSharpAdbClient/Models/Framebuffer.cs +++ b/AdvancedSharpAdbClient/Models/Framebuffer.cs @@ -83,7 +83,7 @@ public Framebuffer(DeviceData device) : this(device, AdbClient.DefaultEndPoint) /// and properties to get the updated framebuffer data. /// /// Refreshes the header of framebuffer when . - public void Refresh(bool reset = false) + public virtual void Refresh(bool reset = false) { EnsureNotDisposed(); @@ -131,7 +131,7 @@ public void Refresh(bool reset = false) /// Refreshes the header of framebuffer when . /// A which can be used to cancel the asynchronous task. /// A which represents the asynchronous operation. - public async Task RefreshAsync(bool reset = false, CancellationToken cancellationToken = default) + public virtual async Task RefreshAsync(bool reset = false, CancellationToken cancellationToken = default) { EnsureNotDisposed(); @@ -180,7 +180,7 @@ public async Task RefreshAsync(bool reset = false, CancellationToken cancellatio #if NET [SupportedOSPlatform("windows")] #endif - public Bitmap ToImage() + public virtual Bitmap ToImage() { EnsureNotDisposed(); return Data == null ? throw new InvalidOperationException($"Call {nameof(Refresh)} first") : Header.ToImage(Data); @@ -205,7 +205,7 @@ public Bitmap ToImage() /// /// A which can be used to cancel the asynchronous task. /// An which represents the framebuffer data. - public Task ToBitmap(CancellationToken cancellationToken = default) + public virtual Task ToBitmap(CancellationToken cancellationToken = default) { EnsureNotDisposed(); return Data == null ? throw new InvalidOperationException($"Call {nameof(RefreshAsync)} first") : Header.ToBitmap(Data, cancellationToken); @@ -217,7 +217,7 @@ public Task ToBitmap(CancellationToken cancellationToken = defa /// The target to invoke the code on. /// A which can be used to cancel the asynchronous task. /// An which represents the framebuffer data. - public Task ToBitmap(CoreDispatcher dispatcher, CancellationToken cancellationToken = default) + public virtual Task ToBitmap(CoreDispatcher dispatcher, CancellationToken cancellationToken = default) { EnsureNotDisposed(); return Data == null ? throw new InvalidOperationException($"Call {nameof(RefreshAsync)} first") : Header.ToBitmap(Data, dispatcher, cancellationToken); @@ -229,7 +229,7 @@ public Task ToBitmap(CoreDispatcher dispatcher, CancellationTok /// The target to invoke the code on. /// A which can be used to cancel the asynchronous task. /// An which represents the framebuffer data. - public Task ToBitmap(DispatcherQueue dispatcher, CancellationToken cancellationToken = default) + public virtual Task ToBitmap(DispatcherQueue dispatcher, CancellationToken cancellationToken = default) { EnsureNotDisposed(); return Data == null ? throw new InvalidOperationException($"Call {nameof(RefreshAsync)} first") : Header.ToBitmap(Data, dispatcher, cancellationToken); @@ -263,6 +263,6 @@ public void Dispose() /// /// Throws an exception if this has been disposed. /// - protected void EnsureNotDisposed() => ExceptionExtensions.ThrowIf(disposed, this); + protected virtual void EnsureNotDisposed() => ExceptionExtensions.ThrowIf(disposed, this); } } From b51b876ace3af9d754aa2262de638f9e8d320cf7 Mon Sep 17 00:00:00 2001 From: wherewhere Date: Mon, 14 Aug 2023 21:08:51 +0800 Subject: [PATCH 4/4] Improve virtual member of DeviceCommands --- AdvancedSharpAdbClient/AdbClient.cs | 2 +- .../DeviceCommands/PackageManager.Async.cs | 26 ++++++------ .../DeviceCommands/PackageManager.cs | 41 ++++++++++--------- AdvancedSharpAdbClient/Logs/LogReader.cs | 32 ++++++++++++--- 4 files changed, 62 insertions(+), 39 deletions(-) diff --git a/AdvancedSharpAdbClient/AdbClient.cs b/AdvancedSharpAdbClient/AdbClient.cs index 5b88c78c..ee47b37e 100644 --- a/AdvancedSharpAdbClient/AdbClient.cs +++ b/AdvancedSharpAdbClient/AdbClient.cs @@ -134,7 +134,7 @@ public AdbClient(EndPoint endPoint, Func adbSocketFactory) /// /// Gets the at which the adb server is listening. /// - public EndPoint EndPoint { get; private set; } + public EndPoint EndPoint { get; protected set; } /// /// Create an ASCII string preceded by four hex digits. The opening "####" diff --git a/AdvancedSharpAdbClient/DeviceCommands/PackageManager.Async.cs b/AdvancedSharpAdbClient/DeviceCommands/PackageManager.Async.cs index e03abc30..f110464c 100644 --- a/AdvancedSharpAdbClient/DeviceCommands/PackageManager.Async.cs +++ b/AdvancedSharpAdbClient/DeviceCommands/PackageManager.Async.cs @@ -19,7 +19,7 @@ public partial class PackageManager /// /// A which can be used to cancel the asynchronous operation. /// A which represents the asynchronous operation. - public Task RefreshPackagesAsync(CancellationToken cancellationToken = default) + public virtual Task RefreshPackagesAsync(CancellationToken cancellationToken = default) { ValidateDevice(); @@ -37,7 +37,7 @@ public Task RefreshPackagesAsync(CancellationToken cancellationToken = default) /// if re-install of app should be performed; otherwise, . /// A which can be used to cancel the asynchronous operation. /// A which represents the asynchronous operation. - public async Task InstallPackageAsync(string packageFilePath, bool reinstall, CancellationToken cancellationToken = default) + public virtual async Task InstallPackageAsync(string packageFilePath, bool reinstall, CancellationToken cancellationToken = default) { ValidateDevice(); @@ -62,7 +62,7 @@ void OnSyncProgressChanged(object sender, SyncProgressChangedEventArgs args) => /// Set to if re-install of app should be performed. /// A which can be used to cancel the asynchronous operation. /// A which represents the asynchronous operation. - public async Task InstallRemotePackageAsync(string remoteFilePath, bool reinstall, CancellationToken cancellationToken = default) + public virtual async Task InstallRemotePackageAsync(string remoteFilePath, bool reinstall, CancellationToken cancellationToken = default) { InstallProgressChanged?.Invoke(this, new InstallProgressEventArgs(PackageInstallProgressState.Installing)); @@ -88,7 +88,7 @@ public async Task InstallRemotePackageAsync(string remoteFilePath, bool reinstal /// Set to if re-install of app should be performed. /// A which can be used to cancel the asynchronous operation. /// A which represents the asynchronous operation. - public async Task InstallMultiplePackageAsync(string basePackageFilePath, IList splitPackageFilePaths, bool reinstall, CancellationToken cancellationToken = default) + public virtual async Task InstallMultiplePackageAsync(string basePackageFilePath, IList splitPackageFilePaths, bool reinstall, CancellationToken cancellationToken = default) { ValidateDevice(); @@ -154,7 +154,7 @@ void OnSplitSyncProgressChanged(object sender, SyncProgressChangedEventArgs args /// Set to if re-install of app should be performed. /// A which can be used to cancel the asynchronous operation. /// A which represents the asynchronous operation. - public async Task InstallMultiplePackageAsync(IList splitPackageFilePaths, string packageName, bool reinstall, CancellationToken cancellationToken = default) + public virtual async Task InstallMultiplePackageAsync(IList splitPackageFilePaths, string packageName, bool reinstall, CancellationToken cancellationToken = default) { ValidateDevice(); @@ -212,7 +212,7 @@ void OnSyncProgressChanged(object sender, SyncProgressChangedEventArgs args) /// Set to if re-install of app should be performed. /// A which can be used to cancel the asynchronous operation. /// A which represents the asynchronous operation. - public async Task InstallMultipleRemotePackageAsync(string baseRemoteFilePath, IList splitRemoteFilePaths, bool reinstall, CancellationToken cancellationToken = default) + public virtual async Task InstallMultipleRemotePackageAsync(string baseRemoteFilePath, IList splitRemoteFilePaths, bool reinstall, CancellationToken cancellationToken = default) { InstallProgressChanged?.Invoke(this, new InstallProgressEventArgs(PackageInstallProgressState.CreateSession)); @@ -263,7 +263,7 @@ public async Task InstallMultipleRemotePackageAsync(string baseRemoteFilePath, I /// Set to if re-install of app should be performed. /// A which can be used to cancel the asynchronous operation. /// A which represents the asynchronous operation. - public async Task InstallMultipleRemotePackageAsync(IList splitRemoteFilePaths, string packageName, bool reinstall, CancellationToken cancellationToken = default) + public virtual async Task InstallMultipleRemotePackageAsync(IList splitRemoteFilePaths, string packageName, bool reinstall, CancellationToken cancellationToken = default) { InstallProgressChanged?.Invoke(this, new InstallProgressEventArgs(PackageInstallProgressState.CreateSession)); @@ -308,7 +308,7 @@ public async Task InstallMultipleRemotePackageAsync(IList splitRemoteFil /// The name of the package to uninstall. /// A which can be used to cancel the asynchronous operation. /// A which represents the asynchronous operation. - public async Task UninstallPackageAsync(string packageName, CancellationToken cancellationToken = default) + public virtual async Task UninstallPackageAsync(string packageName, CancellationToken cancellationToken = default) { ValidateDevice(); @@ -326,7 +326,7 @@ public async Task UninstallPackageAsync(string packageName, CancellationToken ca /// The name of the package from which to get the application version. /// A which can be used to cancel the asynchronous operation. /// A which return the of target application. - public async Task GetVersionInfoAsync(string packageName, CancellationToken cancellationToken = default) + public virtual async Task GetVersionInfoAsync(string packageName, CancellationToken cancellationToken = default) { ValidateDevice(); @@ -343,7 +343,7 @@ public async Task GetVersionInfoAsync(string packageName, Cancellat /// A which can be used to cancel the asynchronous operation. /// A which return the destination path on device for file. /// If fatal error occurred when pushing file. - private async Task SyncPackageToDeviceAsync(string localFilePath, Action progress, CancellationToken cancellationToken = default) + protected virtual async Task SyncPackageToDeviceAsync(string localFilePath, Action progress, CancellationToken cancellationToken = default) { progress(localFilePath, new SyncProgressChangedEventArgs(0, 0)); @@ -406,7 +406,7 @@ private async Task SyncPackageToDeviceAsync(string localFilePath, Action /// A which can be used to cancel the asynchronous operation. /// A which represents the asynchronous operation. /// If file removal failed. - private async Task RemoveRemotePackageAsync(string remoteFilePath, CancellationToken cancellationToken = default) + protected virtual async Task RemoveRemotePackageAsync(string remoteFilePath, CancellationToken cancellationToken = default) { // now we delete the app we synced try @@ -432,7 +432,7 @@ private async Task RemoveRemotePackageAsync(string remoteFilePath, CancellationT /// The absolute package name of the base app. /// A which can be used to cancel the asynchronous operation. /// A which return the session ID. - private async Task CreateInstallSessionAsync(bool reinstall, string packageName = null, CancellationToken cancellationToken = default) + protected virtual async Task CreateInstallSessionAsync(bool reinstall, string packageName = null, CancellationToken cancellationToken = default) { ValidateDevice(); @@ -463,7 +463,7 @@ private async Task CreateInstallSessionAsync(bool reinstall, string pack /// The absolute file path to package file on device. /// A which can be used to cancel the asynchronous operation. /// A which represents the asynchronous operation. - private async Task WriteInstallSessionAsync(string session, string apkName, string path, CancellationToken cancellationToken = default) + protected virtual async Task WriteInstallSessionAsync(string session, string apkName, string path, CancellationToken cancellationToken = default) { ValidateDevice(); diff --git a/AdvancedSharpAdbClient/DeviceCommands/PackageManager.cs b/AdvancedSharpAdbClient/DeviceCommands/PackageManager.cs index d0421c4a..9f56ba00 100644 --- a/AdvancedSharpAdbClient/DeviceCommands/PackageManager.cs +++ b/AdvancedSharpAdbClient/DeviceCommands/PackageManager.cs @@ -24,31 +24,31 @@ public partial class PackageManager /// /// The command that list all packages installed on the device. /// - private const string ListFull = "pm list packages -f"; + protected const string ListFull = "pm list packages -f"; /// /// The command that list all third party packages installed on the device. /// - private const string ListThirdPartyOnly = "pm list packages -f -3"; + protected const string ListThirdPartyOnly = "pm list packages -f -3"; #if HAS_LOGGER /// /// The logger to use when logging messages. /// - private readonly ILogger logger; + protected readonly ILogger logger; #endif /// /// The to use when communicating with the device. /// - private readonly IAdbClient client; + protected readonly IAdbClient client; /// /// A function which returns a new instance of a class /// that implements the interface, /// that can be used to transfer files to and from a given device. /// - private readonly Func syncServiceFactory; + protected readonly Func syncServiceFactory; /// /// Occurs when there is a change in the status of the installing. @@ -117,7 +117,7 @@ public PackageManager(IAdbClient client, DeviceData device, bool thirdPartyOnly /// /// Refreshes the packages. /// - public void RefreshPackages() + public virtual void RefreshPackages() { ValidateDevice(); @@ -138,7 +138,7 @@ public void RefreshPackages() /// /// The absolute file system path to file on local host to install. /// if re-install of app should be performed; otherwise, . - public void InstallPackage(string packageFilePath, bool reinstall) + public virtual void InstallPackage(string packageFilePath, bool reinstall) { ValidateDevice(); @@ -161,7 +161,7 @@ void OnSyncProgressChanged(object sender, SyncProgressChangedEventArgs args) => /// /// absolute file path to package file on device. /// Set to if re-install of app should be performed. - public void InstallRemotePackage(string remoteFilePath, bool reinstall) + public virtual void InstallRemotePackage(string remoteFilePath, bool reinstall) { InstallProgressChanged?.Invoke(this, new InstallProgressEventArgs(PackageInstallProgressState.Installing)); @@ -185,7 +185,7 @@ public void InstallRemotePackage(string remoteFilePath, bool reinstall) /// The absolute base app file system path to file on local host to install. /// The absolute split app file system paths to file on local host to install. /// Set to if re-install of app should be performed. - public void InstallMultiplePackage(string basePackageFilePath, IList splitPackageFilePaths, bool reinstall) + public virtual void InstallMultiplePackage(string basePackageFilePath, IList splitPackageFilePaths, bool reinstall) { ValidateDevice(); @@ -244,7 +244,7 @@ void OnSplitSyncProgressChanged(object sender, SyncProgressChangedEventArgs args /// The absolute split app file system paths to file on local host to install. /// The absolute package name of the base app. /// Set to if re-install of app should be performed. - public void InstallMultiplePackage(IList splitPackageFilePaths, string packageName, bool reinstall) + public virtual void InstallMultiplePackage(IList splitPackageFilePaths, string packageName, bool reinstall) { ValidateDevice(); @@ -295,7 +295,7 @@ void OnSyncProgressChanged(object sender, SyncProgressChangedEventArgs args) /// The absolute base app file path to package file on device. /// The absolute split app file paths to package file on device. /// Set to if re-install of app should be performed. - public void InstallMultipleRemotePackage(string baseRemoteFilePath, IList splitRemoteFilePaths, bool reinstall) + public virtual void InstallMultipleRemotePackage(string baseRemoteFilePath, IList splitRemoteFilePaths, bool reinstall) { InstallProgressChanged?.Invoke(this, new InstallProgressEventArgs(PackageInstallProgressState.CreateSession)); @@ -340,7 +340,7 @@ public void InstallMultipleRemotePackage(string baseRemoteFilePath, IListThe absolute split app file paths to package file on device. /// The absolute package name of the base app. /// Set to if re-install of app should be performed. - public void InstallMultipleRemotePackage(IList splitRemoteFilePaths, string packageName, bool reinstall) + public virtual void InstallMultipleRemotePackage(IList splitRemoteFilePaths, string packageName, bool reinstall) { InstallProgressChanged?.Invoke(this, new InstallProgressEventArgs(PackageInstallProgressState.CreateSession)); @@ -379,7 +379,7 @@ public void InstallMultipleRemotePackage(IList splitRemoteFilePaths, str /// Uninstalls a package from the device. /// /// The name of the package to uninstall. - public void UninstallPackage(string packageName) + public virtual void UninstallPackage(string packageName) { ValidateDevice(); @@ -396,7 +396,7 @@ public void UninstallPackage(string packageName) /// /// The name of the package from which to get the application version. /// The of target application. - public VersionInfo GetVersionInfo(string packageName) + public virtual VersionInfo GetVersionInfo(string packageName) { ValidateDevice(); @@ -405,7 +405,10 @@ public VersionInfo GetVersionInfo(string packageName) return receiver.VersionInfo; } - private void ValidateDevice() + /// + /// Validates the device is online. + /// + protected void ValidateDevice() { if (Device.State != DeviceState.Online) { @@ -420,7 +423,7 @@ private void ValidateDevice() /// An optional parameter which, when specified, returns progress notifications. /// Destination path on device for file. /// If fatal error occurred when pushing file. - private string SyncPackageToDevice(string localFilePath, Action progress) + protected virtual string SyncPackageToDevice(string localFilePath, Action progress) { progress(localFilePath, new SyncProgressChangedEventArgs(0, 0)); @@ -482,7 +485,7 @@ private string SyncPackageToDevice(string localFilePath, Action /// Path on device of file to remove. /// If file removal failed. - private void RemoveRemotePackage(string remoteFilePath) + protected virtual void RemoveRemotePackage(string remoteFilePath) { // now we delete the app we synced try @@ -507,7 +510,7 @@ private void RemoveRemotePackage(string remoteFilePath) /// Set to if re-install of app should be performed. /// The absolute package name of the base app. /// Session ID. - private string CreateInstallSession(bool reinstall, string packageName = null) + protected virtual string CreateInstallSession(bool reinstall, string packageName = null) { ValidateDevice(); @@ -536,7 +539,7 @@ private string CreateInstallSession(bool reinstall, string packageName = null) /// The session ID of the install session. /// The name of the application. /// The absolute file path to package file on device. - private void WriteInstallSession(string session, string apkName, string path) + protected virtual void WriteInstallSession(string session, string apkName, string path) { ValidateDevice(); diff --git a/AdvancedSharpAdbClient/Logs/LogReader.cs b/AdvancedSharpAdbClient/Logs/LogReader.cs index c4bdeeb5..dec055bd 100644 --- a/AdvancedSharpAdbClient/Logs/LogReader.cs +++ b/AdvancedSharpAdbClient/Logs/LogReader.cs @@ -15,6 +15,9 @@ namespace AdvancedSharpAdbClient.Logs /// public partial class LogReader { + /// + /// The that contains the logcat data. + /// private readonly Stream stream; /// @@ -27,7 +30,7 @@ public partial class LogReader /// Reads the next from the stream. /// /// A new object. - public LogEntry ReadEntry() + public virtual LogEntry ReadEntry() { // Read the log data in binary format. This format is defined at // https://android.googlesource.com/platform/system/core/+/master/include/log/logger.h @@ -186,7 +189,10 @@ or LogId.Radio } } - private void ReadLogEntry(BinaryReader reader, Collection parent) + /// + /// Reads a single log entry from the stream. + /// + protected void ReadLogEntry(BinaryReader reader, Collection parent) { EventLogType type = (EventLogType)reader.ReadByte(); @@ -225,28 +231,42 @@ private void ReadLogEntry(BinaryReader reader, Collection parent) break; } } - private ushort? ReadUInt16() + + /// + /// Reads a from the stream. + /// + protected ushort? ReadUInt16() { byte[] data = ReadBytesSafe(2); return data == null ? null : BitConverter.ToUInt16(data, 0); } - private uint? ReadUInt32() + /// + /// Reads a from the stream. + /// + protected uint? ReadUInt32() { byte[] data = ReadBytesSafe(4); return data == null ? null : BitConverter.ToUInt32(data, 0); } - private int? ReadInt32() + /// + /// Reads a from the stream. + /// + protected int? ReadInt32() { byte[] data = ReadBytesSafe(4); return data == null ? null : BitConverter.ToInt32(data, 0); } - private byte[] ReadBytesSafe(int count) + /// + /// Reads bytes from the stream, making sure that the requested number of bytes + /// + /// The number of bytes to read. + protected byte[] ReadBytesSafe(int count) { int totalRead = 0; byte[] data = new byte[count];