Skip to content

Commit b7050c6

Browse files
committed
Add support of adb pair
1 parent 1601b50 commit b7050c6

File tree

5 files changed

+252
-34
lines changed

5 files changed

+252
-34
lines changed

AdvancedSharpAdbClient.Tests/AdbClientTests.cs

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -457,6 +457,50 @@ public void RemoveAllReversesTest()
457457
() => TestClient.RemoveAllReverseForwards(Device));
458458
}
459459

460+
[Fact]
461+
public void PairIPAddressTest() =>
462+
RunPairTest(
463+
() => TestClient.Pair(IPAddress.Loopback, "114514"),
464+
"127.0.0.1:5555",
465+
"114514");
466+
467+
[Fact]
468+
public void PairDnsEndpointTest() =>
469+
RunPairTest(
470+
() => TestClient.Pair(new DnsEndPoint("localhost", 1234), "114514"),
471+
"localhost:1234",
472+
"114514");
473+
474+
[Fact]
475+
public void PairIPEndpointTest() =>
476+
RunPairTest(
477+
() => TestClient.Pair(new IPEndPoint(IPAddress.Loopback, 4321), "114514"),
478+
"127.0.0.1:4321",
479+
"114514");
480+
481+
[Fact]
482+
public void PairHostEndpointTest() =>
483+
RunPairTest(
484+
() => TestClient.Pair("localhost:9926", "114514"),
485+
"localhost:9926",
486+
"114514");
487+
488+
[Fact]
489+
public async Task PairIPAddressNullTest() =>
490+
_ = await Assert.ThrowsAsync<ArgumentNullException>(() => TestClient.PairAsync((IPAddress)null, "114514"));
491+
492+
[Fact]
493+
public async Task PairDnsEndpointNullTest() =>
494+
_ = await Assert.ThrowsAsync<ArgumentNullException>(() => TestClient.PairAsync(null, "114514"));
495+
496+
[Fact]
497+
public async Task PairIPEndpointNullTest() =>
498+
_ = await Assert.ThrowsAsync<ArgumentNullException>(() => TestClient.PairAsync((IPEndPoint)null, "114514"));
499+
500+
[Fact]
501+
public async Task PairHostEndpointNullTest() =>
502+
_ = await Assert.ThrowsAsync<ArgumentNullException>(() => TestClient.PairAsync((string)null, "114514"));
503+
460504
[Fact]
461505
public void ConnectIPAddressTest() =>
462506
RunConnectTest(
@@ -669,6 +713,25 @@ public void InstallTest()
669713
}
670714
}
671715

716+
private void RunPairTest(Action test, string connectString, string code)
717+
{
718+
string[] requests = new string[]
719+
{
720+
$"host:pair:{code}:{connectString}"
721+
};
722+
723+
string[] responseMessages = new string[]
724+
{
725+
$"Successfully paired to {connectString} [guid=adb-996198a3-xPRwsQ]"
726+
};
727+
728+
RunTest(
729+
OkResponse,
730+
responseMessages,
731+
requests,
732+
test);
733+
}
734+
672735
private void RunConnectTest(Action test, string connectString)
673736
{
674737
string[] requests = new string[]

AdvancedSharpAdbClient.Tests/Dummys/DummyAdbClient.cs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,12 @@ internal class DummyAdbClient : IAdbClient
2020

2121
public EndPoint EndPoint { get; private set; }
2222

23+
public string Pair(DnsEndPoint endpoint, string code) =>
24+
throw new NotImplementedException();
25+
26+
public Task<string> PairAsync(DnsEndPoint endpoint, string code, CancellationToken cancellationToken = default) =>
27+
throw new NotImplementedException();
28+
2329
public string Connect(DnsEndPoint endpoint) =>
2430
throw new NotImplementedException();
2531

@@ -121,6 +127,12 @@ public void Install(DeviceData device, Stream apk, params string[] arguments) =>
121127
public List<string> GetFeatureSet(DeviceData device) =>
122128
throw new NotImplementedException();
123129

130+
public void InstallMultiple(DeviceData device, Stream[] splitapks, string packageName, params string[] arguments) =>
131+
throw new NotImplementedException();
132+
133+
public void InstallMultiple(DeviceData device, Stream baseapk, Stream[] splitapks, params string[] arguments) =>
134+
throw new NotImplementedException();
135+
124136
public string InstallCreated(DeviceData device, string packageName = null, params string[] arguments) =>
125137
throw new NotImplementedException();
126138

AdvancedSharpAdbClient/AdbClient.cs

Lines changed: 32 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -422,6 +422,36 @@ public void Reboot(string into, DeviceData device)
422422
AdbResponse response = socket.ReadAdbResponse();
423423
}
424424

425+
/// <inheritdoc/>
426+
public string Pair(DnsEndPoint endpoint, string code)
427+
{
428+
if (endpoint == null)
429+
{
430+
throw new ArgumentNullException(nameof(endpoint));
431+
}
432+
433+
using IAdbSocket socket = adbSocketFactory(EndPoint);
434+
socket.SendAdbRequest($"host:pair:{code}:{endpoint.Host}:{endpoint.Port}");
435+
AdbResponse response = socket.ReadAdbResponse();
436+
string results = socket.ReadString();
437+
return results;
438+
}
439+
440+
/// <inheritdoc/>
441+
public async Task<string> PairAsync(DnsEndPoint endpoint, string code, CancellationToken cancellationToken = default)
442+
{
443+
if (endpoint == null)
444+
{
445+
throw new ArgumentNullException(nameof(endpoint));
446+
}
447+
448+
using IAdbSocket socket = adbSocketFactory(EndPoint);
449+
socket.SendAdbRequest($"host:pair:{code}:{endpoint.Host}:{endpoint.Port}");
450+
AdbResponse response = socket.ReadAdbResponse();
451+
string results = await socket.ReadStringAsync(cancellationToken);
452+
return results;
453+
}
454+
425455
/// <inheritdoc/>
426456
public string Connect(DnsEndPoint endpoint)
427457
{
@@ -666,13 +696,7 @@ public void InstallCommit(DeviceData device, string session)
666696
}
667697
}
668698

669-
/// <summary>
670-
/// Push multiple APKs to the device and install them.
671-
/// </summary>
672-
/// <param name="device">The device on which to install the application.</param>
673-
/// <param name="baseapk">A <see cref="Stream"/> which represents the baseapk to install.</param>
674-
/// <param name="splitapks"><see cref="Stream"/>s which represents the splitapks to install.</param>
675-
/// <param name="arguments">The arguments to pass to <c>adb instal-create</c>.</param>
699+
/// <inheritdoc/>
676700
public void InstallMultiple(DeviceData device, Stream baseapk, Stream[] splitapks, params string[] arguments)
677701
{
678702
EnsureDevice(device);
@@ -713,13 +737,7 @@ public void InstallMultiple(DeviceData device, Stream baseapk, Stream[] splitapk
713737
InstallCommit(device, session);
714738
}
715739

716-
/// <summary>
717-
/// Push multiple APKs to the device and install them.
718-
/// </summary>
719-
/// <param name="device">The device on which to install the application.</param>
720-
/// <param name="splitapks"><see cref="Stream"/>s which represents the splitapks to install.</param>
721-
/// <param name="packageName">The packagename of the baseapk to install.</param>
722-
/// <param name="arguments">The arguments to pass to <c>adb instal-create</c>.</param>
740+
/// <inheritdoc/>
723741
public void InstallMultiple(DeviceData device, Stream[] splitapks, string packageName, params string[] arguments)
724742
{
725743
EnsureDevice(device);

AdvancedSharpAdbClient/Extensions/AdbClientExtensions.cs

Lines changed: 108 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -84,23 +84,37 @@ public static void ExecuteRemoteCommand(this IAdbClient client, string command,
8484
public static void Reboot(this IAdbClient client, DeviceData device) => client.Reboot(string.Empty, device);
8585

8686
/// <summary>
87-
/// Connect to a device via TCP/IP.
87+
/// Pair with a device for secure TCP/IP communication
8888
/// </summary>
8989
/// <param name="client">An instance of a class that implements the <see cref="IAdbClient"/> interface.</param>
9090
/// <param name="address">The IP address of the remote device.</param>
91+
/// <param name="code">The pairing code.</param>
9192
/// <returns>The results from adb.</returns>
92-
public static string Connect(this IAdbClient client, IPAddress address) =>
93+
public static string Pair(this IAdbClient client, IPAddress address, string code) =>
9394
address == null
9495
? throw new ArgumentNullException(nameof(address))
95-
: client.Connect(new IPEndPoint(address, AdbClient.DefaultPort));
96+
: client.Pair(new IPEndPoint(address, AdbClient.DefaultPort), code);
9697

9798
/// <summary>
98-
/// Connect to a device via TCP/IP.
99+
/// Pair with a device for secure TCP/IP communication
100+
/// </summary>
101+
/// <param name="client">An instance of a class that implements the <see cref="IAdbClient"/> interface.</param>
102+
/// <param name="endpoint">The DNS endpoint at which the <c>adb</c> server on the device is running.</param>
103+
/// <param name="code">The pairing code.</param>
104+
/// <returns>The results from adb.</returns>
105+
public static string Pair(this IAdbClient client, IPEndPoint endpoint, string code) =>
106+
endpoint == null
107+
? throw new ArgumentNullException(nameof(endpoint))
108+
: client.Pair(new DnsEndPoint(endpoint.Address.ToString(), endpoint.Port), code);
109+
110+
/// <summary>
111+
/// Pair with a device for secure TCP/IP communication
99112
/// </summary>
100113
/// <param name="client">An instance of a class that implements the <see cref="IAdbClient"/> interface.</param>
101114
/// <param name="host">The host address of the remote device.</param>
115+
/// <param name="code">The pairing code.</param>
102116
/// <returns>The results from adb.</returns>
103-
public static string Connect(this IAdbClient client, string host)
117+
public static string Pair(this IAdbClient client, string host, string code)
104118
{
105119
if (string.IsNullOrEmpty(host))
106120
{
@@ -111,40 +125,83 @@ public static string Connect(this IAdbClient client, string host)
111125

112126
return values.Length <= 0
113127
? throw new ArgumentNullException(nameof(host))
114-
: client.Connect(new DnsEndPoint(values[0], values.Length == 1 ? AdbClient.DefaultPort : int.Parse(values[1])));
128+
: client.Pair(new DnsEndPoint(values[0], values.Length == 1 ? AdbClient.DefaultPort : int.Parse(values[1])), code);
115129
}
116130

117131
/// <summary>
118-
/// Connect to a device via TCP/IP.
132+
/// Pair with a device for secure TCP/IP communication
119133
/// </summary>
120134
/// <param name="client">An instance of a class that implements the <see cref="IAdbClient"/> interface.</param>
121-
/// <param name="endpoint">The IP endpoint at which the <c>adb</c> server on the device is running.</param>
135+
/// <param name="address">The IP address of the remote device.</param>
136+
/// <param name="code">The pairing code.</param>
122137
/// <returns>The results from adb.</returns>
123-
public static string Connect(this IAdbClient client, IPEndPoint endpoint) =>
138+
public static Task<string> PairAsync(this IAdbClient client, IPAddress address, string code) =>
139+
address == null
140+
? throw new ArgumentNullException(nameof(address))
141+
: client.PairAsync(new IPEndPoint(address, AdbClient.DefaultPort), code);
142+
143+
/// <summary>
144+
/// Pair with a device for secure TCP/IP communication
145+
/// </summary>
146+
/// <param name="client">An instance of a class that implements the <see cref="IAdbClient"/> interface.</param>
147+
/// <param name="endpoint">The DNS endpoint at which the <c>adb</c> server on the device is running.</param>
148+
/// <param name="code">The pairing code.</param>
149+
/// <returns>The results from adb.</returns>
150+
public static Task<string> PairAsync(this IAdbClient client, IPEndPoint endpoint, string code) =>
124151
endpoint == null
125152
? throw new ArgumentNullException(nameof(endpoint))
126-
: client.Connect(new DnsEndPoint(endpoint.Address.ToString(), endpoint.Port));
153+
: client.PairAsync(new DnsEndPoint(endpoint.Address.ToString(), endpoint.Port), code);
154+
155+
/// <summary>
156+
/// Pair with a device for secure TCP/IP communication
157+
/// </summary>
158+
/// <param name="client">An instance of a class that implements the <see cref="IAdbClient"/> interface.</param>
159+
/// <param name="host">The host address of the remote device.</param>
160+
/// <param name="code">The pairing code.</param>
161+
/// <returns>The results from adb.</returns>
162+
public static Task<string> PairAsync(this IAdbClient client, string host, string code)
163+
{
164+
if (string.IsNullOrEmpty(host))
165+
{
166+
throw new ArgumentNullException(nameof(host));
167+
}
168+
169+
string[] values = host.Split(':');
170+
171+
return values.Length <= 0
172+
? throw new ArgumentNullException(nameof(host))
173+
: client.PairAsync(new DnsEndPoint(values[0], values.Length == 1 ? AdbClient.DefaultPort : int.Parse(values[1])), code);
174+
}
127175

128176
/// <summary>
129177
/// Connect to a device via TCP/IP.
130178
/// </summary>
131179
/// <param name="client">An instance of a class that implements the <see cref="IAdbClient"/> interface.</param>
132180
/// <param name="address">The IP address of the remote device.</param>
133-
/// <param name="cancellationToken">A <see cref="CancellationToken"/> which can be used to cancel the asynchronous operation.</param>
134-
/// <returns>An <see cref="Task"/> which return the results from adb.</returns>
135-
public static Task<string> ConnectAsync(this IAdbClient client, IPAddress address, CancellationToken cancellationToken = default) =>
181+
/// <returns>The results from adb.</returns>
182+
public static string Connect(this IAdbClient client, IPAddress address) =>
136183
address == null
137184
? throw new ArgumentNullException(nameof(address))
138-
: client.ConnectAsync(new IPEndPoint(address, AdbClient.DefaultPort), cancellationToken);
185+
: client.Connect(new IPEndPoint(address, AdbClient.DefaultPort));
186+
187+
/// <summary>
188+
/// Connect to a device via TCP/IP.
189+
/// </summary>
190+
/// <param name="client">An instance of a class that implements the <see cref="IAdbClient"/> interface.</param>
191+
/// <param name="endpoint">The IP endpoint at which the <c>adb</c> server on the device is running.</param>
192+
/// <returns>The results from adb.</returns>
193+
public static string Connect(this IAdbClient client, IPEndPoint endpoint) =>
194+
endpoint == null
195+
? throw new ArgumentNullException(nameof(endpoint))
196+
: client.Connect(new DnsEndPoint(endpoint.Address.ToString(), endpoint.Port));
139197

140198
/// <summary>
141199
/// Connect to a device via TCP/IP.
142200
/// </summary>
143201
/// <param name="client">An instance of a class that implements the <see cref="IAdbClient"/> interface.</param>
144202
/// <param name="host">The host address of the remote device.</param>
145-
/// <param name="cancellationToken">A <see cref="CancellationToken"/> which can be used to cancel the asynchronous operation.</param>
146-
/// <returns>An <see cref="Task"/> which return the results from adb.</returns>
147-
public static Task<string> ConnectAsync(this IAdbClient client, string host, CancellationToken cancellationToken = default)
203+
/// <returns>The results from adb.</returns>
204+
public static string Connect(this IAdbClient client, string host)
148205
{
149206
if (string.IsNullOrEmpty(host))
150207
{
@@ -155,9 +212,21 @@ public static Task<string> ConnectAsync(this IAdbClient client, string host, Can
155212

156213
return values.Length <= 0
157214
? throw new ArgumentNullException(nameof(host))
158-
: client.ConnectAsync(new DnsEndPoint(values[0], values.Length == 1 ? AdbClient.DefaultPort : int.Parse(values[1])), cancellationToken);
215+
: client.Connect(new DnsEndPoint(values[0], values.Length == 1 ? AdbClient.DefaultPort : int.Parse(values[1])));
159216
}
160217

218+
/// <summary>
219+
/// Connect to a device via TCP/IP.
220+
/// </summary>
221+
/// <param name="client">An instance of a class that implements the <see cref="IAdbClient"/> interface.</param>
222+
/// <param name="address">The IP address of the remote device.</param>
223+
/// <param name="cancellationToken">A <see cref="CancellationToken"/> which can be used to cancel the asynchronous operation.</param>
224+
/// <returns>An <see cref="Task"/> which return the results from adb.</returns>
225+
public static Task<string> ConnectAsync(this IAdbClient client, IPAddress address, CancellationToken cancellationToken = default) =>
226+
address == null
227+
? throw new ArgumentNullException(nameof(address))
228+
: client.ConnectAsync(new IPEndPoint(address, AdbClient.DefaultPort), cancellationToken);
229+
161230
/// <summary>
162231
/// Connect to a device via TCP/IP.
163232
/// </summary>
@@ -169,5 +238,26 @@ public static Task<string> ConnectAsync(this IAdbClient client, IPEndPoint endpo
169238
endpoint == null
170239
? throw new ArgumentNullException(nameof(endpoint))
171240
: client.ConnectAsync(new DnsEndPoint(endpoint.Address.ToString(), endpoint.Port), cancellationToken);
241+
242+
/// <summary>
243+
/// Connect to a device via TCP/IP.
244+
/// </summary>
245+
/// <param name="client">An instance of a class that implements the <see cref="IAdbClient"/> interface.</param>
246+
/// <param name="host">The host address of the remote device.</param>
247+
/// <param name="cancellationToken">A <see cref="CancellationToken"/> which can be used to cancel the asynchronous operation.</param>
248+
/// <returns>An <see cref="Task"/> which return the results from adb.</returns>
249+
public static Task<string> ConnectAsync(this IAdbClient client, string host, CancellationToken cancellationToken = default)
250+
{
251+
if (string.IsNullOrEmpty(host))
252+
{
253+
throw new ArgumentNullException(nameof(host));
254+
}
255+
256+
string[] values = host.Split(':');
257+
258+
return values.Length <= 0
259+
? throw new ArgumentNullException(nameof(host))
260+
: client.ConnectAsync(new DnsEndPoint(values[0], values.Length == 1 ? AdbClient.DefaultPort : int.Parse(values[1])), cancellationToken);
261+
}
172262
}
173263
}

0 commit comments

Comments
 (0)