Skip to content

Commit

Permalink
[Xamarin.Android.Build.Tasks] Fix up ForegroundService.ToString() (#8412
Browse files Browse the repository at this point in the history
)

Fixes: #8409

Context: #8272

The [`//service/@android:foregroundServiceType`][0] attribute can be
generated based on the value of the
`Android.App.ServiceAttribute.ForegroundServiceType` property:

	[Service(ForegroundServiceType=ForegroundService.TypeCamera)]
	partial class MyService : Service {
	}

which will result in an `AndroidManifest.xml` fragment such as:

	<service android:foregroundServiceType="camera" android:name="crc64….MyService" />

However, a number of `ForegroundService` enum values have been added
without corresponding updates to `ServiceAttribute` XML generation.
Consequently, using "recently added" values such as
`ForegroundService.TypeHealth` would result in those values *not*
being added to the generated `//service/@android:foregroundServiceType`.

Update `ManifestDocumentElement.cs` to update
`ToString(ForegroundService)` so that all current `ForegroundService`
enum values are supported.  This will allow:

	[Service(ForegroundServiceType=
	    ForegroundService.TypeCamera |      // previously supported
	    ForegroundService.TypeMicrophone)]  // new hawtness
	partial class MyService : Service {
	}

to properly emit:

	<service android:foregroundServiceType="camera|microphone" android:name="crc64….MyService" />

[0]: https://developer.android.com/guide/topics/manifest/service-element#foregroundservicetype
  • Loading branch information
dellis1972 authored Oct 11, 2023
1 parent 6945132 commit 58a81eb
Show file tree
Hide file tree
Showing 3 changed files with 46 additions and 5 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -908,6 +908,33 @@ class TestActivity : Activity { }"
}
}

[Test]
[TestCase ("Android.Content.PM.ForegroundService.TypeSpecialUse", "specialUse")]
[TestCase ("Android.Content.PM.ForegroundService.TypeConnectedDevice", "connectedDevice")]
[TestCase ("Android.Content.PM.ForegroundService.TypeCamera|Android.Content.PM.ForegroundService.TypeMicrophone", "camera|microphone")]
public void AllForegroundServiceTypes (string serviceType, string expected)
{
var proj = new XamarinAndroidApplicationProject {
};

proj.Sources.Add (new BuildItem.Source ("TestActivity.cs") {
TextContent = () => $@"using Android.App;
using Android.Content.PM;
using Android.Views;
[Service (ForegroundServiceType = {serviceType})]
class TestService : Service {{ public override Android.OS.IBinder OnBind (Android.Content.Intent intent) {{ return null; }} }}"
});
using (ProjectBuilder builder = CreateApkBuilder (Path.Combine ("temp", TestName))) {
Assert.IsTrue (builder.Build (proj), "Build should have succeeded");
string manifest = builder.Output.GetIntermediaryAsText (Path.Combine ("android", "AndroidManifest.xml"));
var doc = XDocument.Parse (manifest);
var ns = XNamespace.Get ("http://schemas.android.com/apk/res/android");
IEnumerable<XElement> services = doc.Element ("manifest")?.Element ("application")?.Elements ("service");
XElement e = services.FirstOrDefault (x => x.Attribute (ns.GetName ("foregroundServiceType"))?.Value == expected);
Assert.IsNotNull (e, $"Manifest should contain an service with a foregroundServiceType of {expected}");
}
}

[Test]
public void AllServiceAttributeProperties ([Values ("legacy", "manifestmerger.jar")] string manifestMerger)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ public void AssertCommercialBuild (bool fail = false)
}
}

char [] invalidChars = { '{', '}', '(', ')', '$', ':', ';', '\"', '\'', ',', '=' };
char [] invalidChars = { '{', '}', '(', ')', '$', ':', ';', '\"', '\'', ',', '=', '|' };

public string TestName {
get {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -383,12 +383,26 @@ static string ToString (ForegroundService value)
values.Add ("mediaProjection");
if (value.HasFlag (ForegroundService.TypePhoneCall))
values.Add ("phoneCall");

// These can be changed to enum members when API-R is the stable binding.
if (value.HasFlag ((ForegroundService)64))
if (value.HasFlag (ForegroundService.TypeCamera))
values.Add ("camera");
if (value.HasFlag ((ForegroundService)128))
if (value.HasFlag (ForegroundService.TypeMicrophone))
values.Add ("microphone");
if (value.HasFlag (ForegroundService.TypeHealth))
values.Add ("health");
if (value.HasFlag (ForegroundService.TypeRemoteMessaging))
values.Add ("remoteMessaging");
if (value.HasFlag (ForegroundService.TypeSystemExempted))
values.Add ("systemExempted");
if (value.HasFlag (ForegroundService.TypeShortService))
values.Add ("shortService");
if (value.HasFlag (ForegroundService.TypeSpecialUse))
values.Add ("specialUse");

// When including a non-stable value you can cast the integer value
// to ForegroundService. We need to do this because the Build.Tasks
// only build against the latest STABLE api.
//if (value.HasFlag ((ForegroundService)128))
// values.Add ("newValue");

return string.Join ("|", values.ToArray ());
}
Expand Down

0 comments on commit 58a81eb

Please sign in to comment.