diff --git a/.external b/.external index eaa12dfe14f..63a656c5bee 100644 --- a/.external +++ b/.external @@ -1,2 +1,2 @@ -xamarin/monodroid:master@0eef889156e92ff0d47e62477f10798b6d5b5c29 +xamarin/monodroid:master@27736a7ffc48d606ab45598f761e873f8572f46a mono/mono:2020-02@ac596375c762c6b8dbe3c802f0ce626004eab51c diff --git a/Documentation/guides/building-apps/build-properties.md b/Documentation/guides/building-apps/build-properties.md index 7cbd10a0a27..6b3e75ff7ce 100644 --- a/Documentation/guides/building-apps/build-properties.md +++ b/Documentation/guides/building-apps/build-properties.md @@ -274,6 +274,30 @@ to `pkcs12`. Added in Xamarin.Android 10.2. + +## AndroidDeviceUserId + +Allows deploying and debugging the application under guest +or work accounts. The value is the `uid` value you get +from the following adb command + +``` +adb shell pm list users +``` + +This will return the following data + +``` +Users: + UserInfo{0:Owner:c13} running + UserInfo{10:Guest:404} +``` + +The `uid` is the first integer value. In the example they +are `0` and `10`. + +Added in Xamarin.Android 11.2 + ## AndroidDexTool An enum-style property with valid diff --git a/Documentation/release-notes/5311.md b/Documentation/release-notes/5311.md new file mode 100644 index 00000000000..57411b39e99 --- /dev/null +++ b/Documentation/release-notes/5311.md @@ -0,0 +1,33 @@ +### Build and deployment performance + +* [GitHub PR 5311](https://github.com/xamarin/xamarin-android/pull/5311): + Add support for deploying and debugging against different user accounts + on Android Devices. In order to use this you need to specify the + `AndroidDeviceUserId` in either your csproj or on the command line. + + ```xml + + 10 + + ``` + + ``` + msbuild foo.csproj /t:Install /p:AndroidDeviceUserId=10 + ``` + + The value is the `uid` value you get from the following adb command + + ``` + adb shell pm list users + ``` + + This will return the following data + + ``` + Users: + UserInfo{0:Owner:c13} running + UserInfo{10:Guest:404} + ``` + + The `uid` is the first integer value. In the example they + are `0` and `10`. \ No newline at end of file diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Utilities/DeviceTest.cs b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Utilities/DeviceTest.cs index a5fc67ec10f..94de779bfc0 100644 --- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Utilities/DeviceTest.cs +++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Utilities/DeviceTest.cs @@ -13,11 +13,14 @@ namespace Xamarin.Android.Build.Tests { public class DeviceTest: BaseTest { + public const string GuestUserName = "guest1"; + [OneTimeSetUp] public void DeviceSetup () { SetAdbLogcatBufferSize (64); RunAdbCommand ("logcat -c"); + CreateGuestUser (GuestUserName); } [TearDown] @@ -42,6 +45,7 @@ protected override void CleanupTest () ClearAdbLogcat (); + base.CleanupTest (); } @@ -260,5 +264,42 @@ protected static string [] GetOverrideDirectoryPaths (string packageName) $"/storage/sdcard/Android/data/{packageName}/files/.__override__", }; } + + protected static void CreateGuestUser (string username) + { + if (GetUserId (username) != -1) + RunAdbCommand ($"shell pm create-user --guest {username}"); + } + + protected static void DeleteGuestUser (string username) + { + int userId = GetUserId (username); + if (userId > 0) + RunAdbCommand ($"shell pm remove-user --guest {userId}"); + } + + protected static int GetUserId (string username) + { + string output = RunAdbCommand ($"shell pm list users"); + Regex regex = new Regex (@"UserInfo{(?\d+):" + username, RegexOptions.Compiled); + Console.WriteLine (output); + var match = regex.Match (output); + if (match.Success) { + return int.Parse (match.Groups ["userId"].Value); + } + return -1; + } + + protected static bool SwitchUser (string username) + { + int userId = GetUserId (username); + if (userId == -1) + userId = 0; + if (userId >= 0) { + RunAdbCommand ($"shell am switch-user {userId}"); + return true; + } + return false; + } } } diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Android/XamarinAndroidApplicationProject.cs b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Android/XamarinAndroidApplicationProject.cs index 47b59aa6ee2..176d7001ee8 100644 --- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Android/XamarinAndroidApplicationProject.cs +++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Android/XamarinAndroidApplicationProject.cs @@ -40,6 +40,7 @@ public XamarinAndroidApplicationProject (string debugConfigurationName = "Debug" if (Builder.UseDotNet) { SetProperty (KnownProperties.OutputType, "Exe"); SetProperty ("XamarinAndroidSupportSkipVerifyVersions", "True"); + SetProperty ("_FastDeploymentDiagnosticLogging", "True"); // Workaround for AndroidX, see: https://github.com/xamarin/AndroidSupportComponents/pull/239 Imports.Add (new Import (() => "Directory.Build.targets") { @@ -51,6 +52,7 @@ public XamarinAndroidApplicationProject (string debugConfigurationName = "Debug" " }); } else { + SetProperty ("_FastDeploymentDiagnosticLogging", "True"); SetProperty ("AndroidApplication", "True"); SetProperty ("AndroidResgenClass", "Resource"); SetProperty ("AndroidResgenFile", () => "Resources\\Resource.designer" + Language.DefaultDesignerExtension); diff --git a/tests/MSBuildDeviceIntegration/Tests/BundleToolTests.cs b/tests/MSBuildDeviceIntegration/Tests/BundleToolTests.cs index 6765e55bf53..1fa8c80ae0f 100644 --- a/tests/MSBuildDeviceIntegration/Tests/BundleToolTests.cs +++ b/tests/MSBuildDeviceIntegration/Tests/BundleToolTests.cs @@ -253,6 +253,7 @@ public void ApkSet () { AssertHasDevices (); + appBuilder.BuildLogFile = "install.log"; Assert.IsTrue (appBuilder.RunTarget (app, "Install"), "App should have installed."); var aab = Path.Combine (intermediate, "android", "bin", "UnnamedProject.UnnamedProject.apks"); diff --git a/tests/MSBuildDeviceIntegration/Tests/DebuggingTest.cs b/tests/MSBuildDeviceIntegration/Tests/DebuggingTest.cs index 6691d601239..bba76474bc1 100755 --- a/tests/MSBuildDeviceIntegration/Tests/DebuggingTest.cs +++ b/tests/MSBuildDeviceIntegration/Tests/DebuggingTest.cs @@ -8,6 +8,7 @@ using Mono.Debugging.Soft; using NUnit.Framework; using Xamarin.ProjectTools; +using System.Collections.Generic; namespace Xamarin.Android.Build.Tests { @@ -251,36 +252,63 @@ public override void OnCreate () /* embedAssemblies */ true, /* fastDevType */ "Assemblies", /* allowDeltaInstall */ false, + /* user */ null, }, new object[] { /* embedAssemblies */ false, /* fastDevType */ "Assemblies", /* allowDeltaInstall */ false, + /* user */ null, }, new object[] { /* embedAssemblies */ false, /* fastDevType */ "Assemblies", /* allowDeltaInstall */ true, + /* user */ null, }, new object[] { /* embedAssemblies */ false, /* fastDevType */ "Assemblies:Dexes", /* allowDeltaInstall */ false, + /* user */ null, }, new object[] { /* embedAssemblies */ false, /* fastDevType */ "Assemblies:Dexes", /* allowDeltaInstall */ true, + /* user */ null, + }, + new object[] { + /* embedAssemblies */ true, + /* fastDevType */ "Assemblies", + /* allowDeltaInstall */ false, + /* user */ DeviceTest.GuestUserName, + }, + new object[] { + /* embedAssemblies */ false, + /* fastDevType */ "Assemblies", + /* allowDeltaInstall */ false, + /* user */ DeviceTest.GuestUserName, }, }; #pragma warning restore 414 [Test, Category ("SmokeTests"), Category ("Debugger")] [TestCaseSource (nameof(DebuggerTestCases))] - public void ApplicationRunsWithDebuggerAndBreaks (bool embedAssemblies, string fastDevType, bool allowDeltaInstall) + public void ApplicationRunsWithDebuggerAndBreaks (bool embedAssemblies, string fastDevType, bool allowDeltaInstall, string username) { AssertCommercialBuild (); AssertHasDevices (); + + int userId = GetUserId (username); + List parameters = new List (); + if (userId >= 0) + parameters.Add ($"AndroidDeviceUserId={userId}"); + if (SwitchUser (username)) { + WaitFor (5); + ClickButton ("", "android:id/button1", "Yes continue"); + } + var proj = new XamarinFormsAndroidApplicationProject () { IsRelease = false, EmbedAssembliesIntoApk = embedAssemblies, @@ -291,7 +319,7 @@ public void ApplicationRunsWithDebuggerAndBreaks (bool embedAssemblies, string f proj.SetDefaultTargetDevice (); using (var b = CreateApkBuilder (Path.Combine ("temp", TestName))) { SetTargetFrameworkAndManifest (proj, b); - Assert.True (b.Install (proj), "Project should have installed."); + Assert.True (b.Install (proj, parameters: parameters.ToArray ()), "Project should have installed."); int breakcountHitCount = 0; ManualResetEvent resetEvent = new ManualResetEvent (false); @@ -324,11 +352,13 @@ public void ApplicationRunsWithDebuggerAndBreaks (bool embedAssemblies, string f options.EvaluationOptions.UseExternalTypeResolver = true; ClearAdbLogcat (); b.BuildLogFile = "run.log"; - Assert.True (b.RunTarget (proj, "_Run", doNotCleanupOnUpdate: true, parameters: new string [] { - $"AndroidSdbTargetPort={port}", - $"AndroidSdbHostPort={port}", - "AndroidAttachDebugger=True", - }), "Project should have run."); + + parameters.Add ($"AndroidSdbTargetPort={port}"); + parameters.Add ($"AndroidSdbHostPort={port}"); + parameters.Add ("AndroidAttachDebugger=True"); + + Assert.True (b.RunTarget (proj, "_Run", doNotCleanupOnUpdate: true, + parameters: parameters.ToArray ()), "Project should have run."); Assert.IsTrue (WaitForDebuggerToStart (Path.Combine (Root, b.ProjectDirectory, "logcat.log")), "Activity should have started"); // we need to give a bit of time for the debug server to start up.