Skip to content

Commit

Permalink
Merge pull request #68 from yungd1plomat/miuifix
Browse files Browse the repository at this point in the history
Add MIUI support and improve error handling for DumpScreen and DumpScreenString
  • Loading branch information
wherewhere authored Aug 16, 2023
2 parents 258564b + 99f4005 commit 7c617b7
Show file tree
Hide file tree
Showing 9 changed files with 345 additions and 22 deletions.
116 changes: 114 additions & 2 deletions AdvancedSharpAdbClient.Tests/AdbClientTests.Async.cs
Original file line number Diff line number Diff line change
Expand Up @@ -990,6 +990,7 @@ public async void DumpScreenStringAsyncTest()
};

string dump = File.ReadAllText(@"Assets/dumpscreen.txt");
string cleanDump = File.ReadAllText(@"Assets/dumpscreen_clean.txt");
byte[] streamData = Encoding.UTF8.GetBytes(dump);
await using MemoryStream shellStream = new(streamData);

Expand All @@ -1006,7 +1007,117 @@ await RunTestAsync(
shellStream,
async () => xml = await TestClient.DumpScreenStringAsync(device));

Assert.Equal(dump.Replace("Events injected: 1\r\n", "").Replace("UI hierchary dumped to: /dev/tty", "").Trim(), xml);
Assert.Equal(cleanDump, xml);
}

/// <summary>
/// Tests the <see cref="AdbClient.DumpScreenStringAsync(DeviceData, CancellationToken)"/> method.
/// </summary>
[Fact]
public async void DumpScreenStringAsyncMIUITest()
{
DeviceData device = new()
{
Serial = "009d1cd696d5194a",
State = DeviceState.Online
};

string[] requests = new string[]
{
"host:transport:009d1cd696d5194a",
"shell:uiautomator dump /dev/tty"
};

string miuiDump = File.ReadAllText(@"Assets/dumpscreen_miui.txt");
string cleanMIUIDump = File.ReadAllText(@"Assets/dumpscreen_miui_clean.txt");
byte[] miuiStreamData = Encoding.UTF8.GetBytes(miuiDump);
await using MemoryStream miuiStream = new(miuiStreamData);

string miuiXml = string.Empty;

await RunTestAsync(
new AdbResponse[]
{
AdbResponse.OK,
AdbResponse.OK,
},
NoResponseMessages,
requests,
miuiStream,
async () => miuiXml = await TestClient.DumpScreenStringAsync(device));

Assert.Equal(cleanMIUIDump, miuiXml);
}

/// <summary>
/// Tests the <see cref="AdbClient.DumpScreenStringAsync(DeviceData, CancellationToken)"/> method.
/// </summary>
[Fact]
public async void DumpScreenStringAsyncEmptyTest()
{
DeviceData device = new()
{
Serial = "009d1cd696d5194a",
State = DeviceState.Online
};

string[] requests = new string[]
{
"host:transport:009d1cd696d5194a",
"shell:uiautomator dump /dev/tty"
};

byte[] emptyStreamData = Encoding.UTF8.GetBytes(string.Empty);
await using MemoryStream emptyStream = new(emptyStreamData);
string emptyXml = string.Empty;

await RunTestAsync(
new AdbResponse[]
{
AdbResponse.OK,
AdbResponse.OK,
},
NoResponseMessages,
requests,
emptyStream,
async () => emptyXml = await TestClient.DumpScreenStringAsync(device));

Assert.True(string.IsNullOrEmpty(emptyXml));
}

/// <summary>
/// Tests the <see cref="AdbClient.DumpScreenStringAsync(DeviceData, CancellationToken)"/> method.
/// </summary>
[Fact]
public async void DumpScreenStringAsyncErrorTest()
{
DeviceData device = new()
{
Serial = "009d1cd696d5194a",
State = DeviceState.Online
};

string[] requests = new string[]
{
"host:transport:009d1cd696d5194a",
"shell:uiautomator dump /dev/tty"
};

string errorXml = File.ReadAllText(@"Assets/dumpscreen_error.txt");
byte[] errorStreamData = Encoding.UTF8.GetBytes(errorXml);
await using MemoryStream errorStream = new(errorStreamData);

await Assert.ThrowsAsync<XmlException>(() =>
RunTestAsync(
new AdbResponse[]
{
AdbResponse.OK,
AdbResponse.OK,
},
NoResponseMessages,
requests,
errorStream,
() => TestClient.DumpScreenStringAsync(device)));
}

/// <summary>
Expand Down Expand Up @@ -1044,8 +1155,9 @@ await RunTestAsync(
shellStream,
async () => xml = await TestClient.DumpScreenAsync(device));

string cleanDump = File.ReadAllText(@"Assets/dumpscreen_clean.txt");
XmlDocument doc = new();
doc.LoadXml(dump.Replace("Events injected: 1\r\n", "").Replace("UI hierchary dumped to: /dev/tty", "").Trim());
doc.LoadXml(cleanDump);

Assert.Equal(doc, xml);
}
Expand Down
118 changes: 115 additions & 3 deletions AdvancedSharpAdbClient.Tests/AdbClientTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
using System.Text;
using System.Xml;
using Xunit;
using System.Data.Common;
using System.Text.RegularExpressions;

namespace AdvancedSharpAdbClient.Tests
{
Expand Down Expand Up @@ -1112,6 +1112,7 @@ public void DumpScreenStringTest()
};

string dump = File.ReadAllText(@"Assets/dumpscreen.txt");
string cleanDump = File.ReadAllText(@"Assets/dumpscreen_clean.txt");
byte[] streamData = Encoding.UTF8.GetBytes(dump);
using MemoryStream shellStream = new(streamData);

Expand All @@ -1128,7 +1129,117 @@ public void DumpScreenStringTest()
shellStream,
() => xml = TestClient.DumpScreenString(device));

Assert.Equal(dump.Replace("Events injected: 1\r\n", "").Replace("UI hierchary dumped to: /dev/tty", "").Trim(), xml);
Assert.Equal(cleanDump, xml);
}

/// <summary>
/// Tests the <see cref="AdbClient.DumpScreenString(DeviceData)"/> method.
/// </summary>
[Fact]
public void DumpScreenStringMIUITest()
{
DeviceData device = new()
{
Serial = "009d1cd696d5194a",
State = DeviceState.Online
};

string[] requests = new string[]
{
"host:transport:009d1cd696d5194a",
"shell:uiautomator dump /dev/tty"
};

string miuidump = File.ReadAllText(@"Assets/dumpscreen_miui.txt");
string cleanMIUIDump = File.ReadAllText(@"Assets/dumpscreen_miui_clean.txt");
byte[] miuiStreamData = Encoding.UTF8.GetBytes(miuidump);
using MemoryStream miuiStream = new(miuiStreamData);

string miuiXml = string.Empty;

RunTest(
new AdbResponse[]
{
AdbResponse.OK,
AdbResponse.OK,
},
NoResponseMessages,
requests,
miuiStream,
() => miuiXml = TestClient.DumpScreenString(device));

Assert.Equal(cleanMIUIDump, miuiXml);
}

/// <summary>
/// Tests the <see cref="AdbClient.DumpScreenString(DeviceData)"/> method.
/// </summary>
[Fact]
public void DumpScreenStringEmptyTest()
{
DeviceData device = new()
{
Serial = "009d1cd696d5194a",
State = DeviceState.Online
};

string[] requests = new string[]
{
"host:transport:009d1cd696d5194a",
"shell:uiautomator dump /dev/tty"
};

byte[] emptyStreamData = Encoding.UTF8.GetBytes(string.Empty);
using MemoryStream emptyStream = new(emptyStreamData);
string emptyXml = string.Empty;

RunTest(
new AdbResponse[]
{
AdbResponse.OK,
AdbResponse.OK,
},
NoResponseMessages,
requests,
emptyStream,
() => emptyXml = TestClient.DumpScreenString(device));

Assert.True(string.IsNullOrEmpty(emptyXml));
}

/// <summary>
/// Tests the <see cref="AdbClient.DumpScreenString(DeviceData)"/> method.
/// </summary>
[Fact]
public void DumpScreenStringErrorTest()
{
DeviceData device = new()
{
Serial = "009d1cd696d5194a",
State = DeviceState.Online
};

string[] requests = new string[]
{
"host:transport:009d1cd696d5194a",
"shell:uiautomator dump /dev/tty"
};

string errorXml = File.ReadAllText(@"Assets/dumpscreen_error.txt");
byte[] errorStreamData = Encoding.UTF8.GetBytes(errorXml);
using MemoryStream errorStream = new(errorStreamData);

Assert.Throws<XmlException>(() =>
RunTest(
new AdbResponse[]
{
AdbResponse.OK,
AdbResponse.OK,
},
NoResponseMessages,
requests,
errorStream,
() => TestClient.DumpScreenString(device)));
}

/// <summary>
Expand Down Expand Up @@ -1166,8 +1277,9 @@ public void DumpScreenTest()
shellStream,
() => xml = TestClient.DumpScreen(device));

string cleanDump = File.ReadAllText(@"Assets/dumpscreen_clean.txt");
XmlDocument doc = new();
doc.LoadXml(dump.Replace("Events injected: 1\r\n", "").Replace("UI hierchary dumped to: /dev/tty", "").Trim());
doc.LoadXml(cleanDump);

Assert.Equal(doc, xml);
}
Expand Down
12 changes: 12 additions & 0 deletions AdvancedSharpAdbClient.Tests/AdvancedSharpAdbClient.Tests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,18 @@
<None Update="Assets\dumpscreen.txt">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Assets\dumpscreen_clean.txt">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Assets\dumpscreen_error.txt">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Assets\dumpscreen_miui.txt">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Assets\dumpscreen_miui_clean.txt">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Assets\dumpsys_package.txt">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
Expand Down
1 change: 1 addition & 0 deletions AdvancedSharpAdbClient.Tests/Assets/dumpscreen_clean.txt

Large diffs are not rendered by default.

30 changes: 30 additions & 0 deletions AdvancedSharpAdbClient.Tests/Assets/dumpscreen_error.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
java.io.FileNotFoundException: /data/system/theme_config/theme_compatibility.xml: open failed: ENOENT (No such file or directory)
at libcore.io.IoBridge.open(IoBridge.java:574)
at java.io.FileInputStream.<init>(FileInputStream.java:160)
at java.io.FileInputStream.<init>(FileInputStream.java:115)
at java.io.FileReader.<init>(FileReader.java:60)
at miui.content.res.ThemeCompatibilityLoader.getVersion(ThemeCompatibilityLoader.java:108)
at miui.content.res.ThemeCompatibilityLoader.getConfigDocumentTree(ThemeCompatibilityLoader.java:126)
at miui.content.res.ThemeCompatibilityLoader.loadConfig(ThemeCompatibilityLoader.java:59)
at miui.content.res.ThemeCompatibility.<clinit>(ThemeCompatibility.java:31)
at miui.content.res.ThemeCompatibility.isThemeEnabled(ThemeCompatibility.java:111)
at android.content.res.MiuiResourcesImpl.<clinit>(MiuiResourcesImpl.java:41)
at android.content.res.MiuiResources.<init>(MiuiResources.java:58)
at android.content.res.IMiuiResourceImpl.createResources(IMiuiResourceImpl.java:13)
at android.content.res.ThemeManagerStub.createMiuiResources(ThemeManagerStub.java:56)
at android.content.res.Resources.getSystem(Resources.java:235)
at android.util.MiuiMultiWindowAdapter.<clinit>(MiuiMultiWindowAdapter.java:81)
at android.util.MiuiMultiWindowAdapter.getSize(MiuiMultiWindowAdapter.java:305)
at com.xiaomi.freeform.MiuiFreeformImpl.getSize(MiuiFreeformImpl.java:53)
at android.util.MiuiFreeformUtils.getSize(MiuiFreeformUtils.java:49)
at android.view.Display.getSize(Display.java:796)
at com.android.commands.uiautomator.DumpCommand.run(DumpCommand.java:110)
at com.android.commands.uiautomator.Launcher.main(Launcher.java:83)
at com.android.internal.os.RuntimeInit.nativeFinishInit(Native Method)
at com.android.internal.os.RuntimeInit.main(RuntimeInit.java:363)
Caused by: android.system.ErrnoException: open failed: ENOENT (No such file or directory)
at libcore.io.Linux.open(Native Method)
at libcore.io.ForwardingOs.open(ForwardingOs.java:563)
at libcore.io.BlockGuardOs.open(BlockGuardOs.java:274)
at libcore.io.IoBridge.open(IoBridge.java:560)
... 22 more
31 changes: 31 additions & 0 deletions AdvancedSharpAdbClient.Tests/Assets/dumpscreen_miui.txt

Large diffs are not rendered by default.

Large diffs are not rendered by default.

26 changes: 17 additions & 9 deletions AdvancedSharpAdbClient/AdbClient.Async.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
using System.Net;
using System.Runtime.CompilerServices;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using System.Xml;

Expand Down Expand Up @@ -661,19 +662,28 @@ public async Task<string> DumpScreenStringAsync(DeviceData device, CancellationT
await socket.SendAdbRequestAsync("shell:uiautomator dump /dev/tty", cancellationToken);
AdbResponse response = await socket.ReadAdbResponseAsync(cancellationToken);
using StreamReader reader = new(socket.GetShellStream(), Encoding);
string xmlString = await reader.ReadToEndAsync(cancellationToken).ConfigureAwait(false);
xmlString = xmlString.Replace("Events injected: 1\r\n", "").Replace("UI hierchary dumped to: /dev/tty", "").Trim();
return xmlString;
string xmlString = reader.ReadToEnd()
.Replace("Events injected: 1\r\n", string.Empty)
.Replace("UI hierchary dumped to: /dev/tty", string.Empty)
.Trim();
if (string.IsNullOrEmpty(xmlString) || xmlString.StartsWith("<?xml"))
{
return xmlString;
}
Match xmlMatch = GetXMLRegex().Match(xmlString);
if (!xmlMatch.Success)
{
throw new XmlException("An error occurred while receiving xml: " + xmlString);
}
return xmlMatch.Value;
}

/// <inheritdoc/>
public async Task<XmlDocument> DumpScreenAsync(DeviceData device, CancellationToken cancellationToken = default)
{
XmlDocument doc = new();
string xmlString = await DumpScreenStringAsync(device, cancellationToken);
if (!string.IsNullOrEmpty(xmlString)
&& !xmlString.StartsWith("ERROR", StringComparison.OrdinalIgnoreCase)
&& !xmlString.StartsWith("java.lang."))
if (!string.IsNullOrEmpty(xmlString))
{
doc.LoadXml(xmlString);
return doc;
Expand All @@ -687,9 +697,7 @@ public async Task<XmlDocument> DumpScreenAsync(DeviceData device, CancellationTo
{
Windows.Data.Xml.Dom.XmlDocument doc = new();
string xmlString = await DumpScreenStringAsync(device, cancellationToken);
if (!string.IsNullOrEmpty(xmlString)
&& !xmlString.StartsWith("ERROR", StringComparison.OrdinalIgnoreCase)
&& !xmlString.StartsWith("java.lang."))
if (!string.IsNullOrEmpty(xmlString))
{
doc.LoadXml(xmlString);
return doc;
Expand Down
Loading

0 comments on commit 7c617b7

Please sign in to comment.