Skip to content

Instantly share code, notes, and snippets.

@TheSnowfield
Last active March 21, 2024 13:45
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save TheSnowfield/2739d4fc4c1b2abf91f189d892a5d3b8 to your computer and use it in GitHub Desktop.
Save TheSnowfield/2739d4fc4c1b2abf91f189d892a5d3b8 to your computer and use it in GitHub Desktop.

Here is an example that shows you how to create a wear tile use Xamarin.

Prepare the library

  • Create a Xamarin binding library AndroidX.Wear.Tiles.
  • Download the latest androidx.wear.tiles pre-release from maven (current is 1.0.0-alpha11).
    Place the aar file into Jar in your solution, set Build Action to LibraryProjectZip in the property.
  • Download the latest androidx.wear.tiles tiles-proto pre-release from maven (current is 1.0.0-alpha11).
    Place the jar file into Jar folder of your solution, set Build Action to EmbeddedReferenceJar in the property.
  • Add Xamarin.Google.Guava.ListenableFuture NuGet package to this binding solution.
  • Edit the Metadata.xml. (I have fixed some bindings)

Create a tile solution

  • Add the AndroidX.Wear.Tiles to references.
  • Create and paste the MyTileService.cs, also care about the service name attribute.
  • Build and deploy to your watch.

If no errors happened, the Xamarin tile will appear on the Pick a Tile menu,
Select it you will see the Hello world! tile on the screen.

<metadata>
<attr path="/api/package[@name='androidx.wear.tiles']/class[@name='LayoutElementBuilders.Image.Builder']/method[@name='build' and count(parameter)=0]" name="managedReturn">ILayoutElement</attr>
<attr path="/api/package[@name='androidx.wear.tiles']/class[@name='DimensionBuilders.WrappedDimensionProp.Builder']/method[@name='build' and count(parameter)=0]" name="managedReturn">IContainerDimension</attr>
<attr path="/api/package[@name='androidx.wear.tiles']/class[@name='LayoutElementBuilders.Arc.Builder']/method[@name='build' and count(parameter)=0]" name="managedReturn">ILayoutElement</attr>
<attr path="/api/package[@name='androidx.wear.tiles']/class[@name='LayoutElementBuilders.ArcAdapter.Builder']/method[@name='build' and count(parameter)=0]" name="managedReturn">IArcLayoutElement</attr>
<attr path="/api/package[@name='androidx.wear.tiles']/class[@name='LayoutElementBuilders.ArcLine.Builder']/method[@name='build' and count(parameter)=0]" name="managedReturn">IArcLayoutElement</attr>
<attr path="/api/package[@name='androidx.wear.tiles']/class[@name='LayoutElementBuilders.ArcSpacer.Builder']/method[@name='build' and count(parameter)=0]" name="managedReturn">IArcLayoutElement</attr>
<attr path="/api/package[@name='androidx.wear.tiles']/class[@name='LayoutElementBuilders.ArcText.Builder']/method[@name='build' and count(parameter)=0]" name="managedReturn">IArcLayoutElement</attr>
<attr path="/api/package[@name='androidx.wear.tiles']/class[@name='LayoutElementBuilders.Box.Builder']/method[@name='build' and count(parameter)=0]" name="managedReturn">ILayoutElement</attr>
<attr path="/api/package[@name='androidx.wear.tiles']/class[@name='LayoutElementBuilders.Column.Builder']/method[@name='build' and count(parameter)=0]" name="managedReturn">ILayoutElement</attr>
<attr path="/api/package[@name='androidx.wear.tiles']/class[@name='LayoutElementBuilders.Row.Builder']/method[@name='build' and count(parameter)=0]" name="managedReturn">ILayoutElement</attr>
<attr path="/api/package[@name='androidx.wear.tiles']/class[@name='LayoutElementBuilders.Spacer.Builder']/method[@name='build' and count(parameter)=0]" name="managedReturn">ILayoutElement</attr>
<attr path="/api/package[@name='androidx.wear.tiles']/class[@name='LayoutElementBuilders.SpanImage.Builder']/method[@name='build' and count(parameter)=0]" name="managedReturn">ISpan</attr>
<attr path="/api/package[@name='androidx.wear.tiles']/class[@name='LayoutElementBuilders.Spannable.Builder']/method[@name='build' and count(parameter)=0]" name="managedReturn">ILayoutElement</attr>
<attr path="/api/package[@name='androidx.wear.tiles']/class[@name='LayoutElementBuilders.SpanText.Builder']/method[@name='build' and count(parameter)=0]" name="managedReturn">ISpan</attr>
<attr path="/api/package[@name='androidx.wear.tiles']/class[@name='LayoutElementBuilders.Text.Builder']/method[@name='build' and count(parameter)=0]" name="managedReturn">ILayoutElement</attr>
<remove-node path="/api/package[@name='androidx.wear.tiles']/class[@name='DimensionBuilders.DpProp.Builder']" />
<remove-node path="/api/package[@name='androidx.wear.tiles']/class[@name='DimensionBuilders.ExpandedDimensionProp.Builder']" />
<attr path="/api/package[@name='androidx.wear.tiles']/class[@name='DimensionBuilders.ProportionalDimensionProp.Builder']/method[@name='build' and count(parameter)=0]" name="managedReturn">IImageDimension</attr>
<attr path="/api/package[@name='androidx.wear.tiles']/class[@name='ActionBuilders.AndroidBooleanExtra.Builder']/method[@name='build' and count(parameter)=0]" name="managedReturn">IAndroidExtra</attr>
<attr path="/api/package[@name='androidx.wear.tiles']/class[@name='ActionBuilders.AndroidDoubleExtra.Builder']/method[@name='build' and count(parameter)=0]" name="managedReturn">IAndroidExtra</attr>
<attr path="/api/package[@name='androidx.wear.tiles']/class[@name='ActionBuilders.AndroidIntExtra.Builder']/method[@name='build' and count(parameter)=0]" name="managedReturn">IAndroidExtra</attr>
<attr path="/api/package[@name='androidx.wear.tiles']/class[@name='ActionBuilders.AndroidLongExtra.Builder']/method[@name='build' and count(parameter)=0]" name="managedReturn">IAndroidExtra</attr>
<attr path="/api/package[@name='androidx.wear.tiles']/class[@name='ActionBuilders.AndroidStringExtra.Builder']/method[@name='build' and count(parameter)=0]" name="managedReturn">IAndroidExtra</attr>
<attr path="/api/package[@name='androidx.wear.tiles']/class[@name='ActionBuilders.LaunchAction.Builder']/method[@name='build' and count(parameter)=0]" name="managedReturn">IAction</attr>
<attr path="/api/package[@name='androidx.wear.tiles']/class[@name='ActionBuilders.LoadAction.Builder']/method[@name='build' and count(parameter)=0]" name="managedReturn">IAction</attr>
</metadata>
using Android.App;
using Android.Content;
using Android.Util;
using Androidx.Wear.Tiles;
using Google.Common.Util.Concurrent;
using Java.Lang;
using Java.Util.Concurrent;
namespace App.Services
{
[Service(Name = "com.companyname.app.MyTileService", Enabled = true, Exported = true,
Permission = "com.google.android.wearable.permission.BIND_TILE_PROVIDER")]
[IntentFilter(new[] { "androidx.wear.tiles.action.BIND_TILE_PROVIDER" })]
public class MyTileService : TileService
{
private const string ResourcesVersion = "1";
protected override IListenableFuture OnTileRequest
(RequestBuilders.TileRequest p0)
{
Log.Debug("App", "Called OnTileRequest");
// Create text view
var text = new LayoutElementBuilders.Text.Builder();
{
text.SetText("Hello world!");
}
// Create layout
var layout = new LayoutElementBuilders
.Layout.Builder();
{
layout.SetRoot(text.Build());
}
// Create timeline
var timeline = new TimelineBuilders.Timeline.Builder();
{
var entry = new TimelineBuilders.TimelineEntry.Builder();
{
entry.SetLayout(layout.Build());
}
timeline.AddTimelineEntry(entry.Build());
}
// Create tile
var tile = new TileBuilders.Tile.Builder();
{
tile.SetTimeline(timeline.Build());
tile.SetResourcesVersion(ResourcesVersion);
return Futures.ImmediateFuture(tile.Build());
}
}
protected override IListenableFuture OnResourcesRequest
(RequestBuilders.ResourcesRequest p0)
{
Log.Debug("App", "Called OnResourcesRequest");
var resource = new ResourceBuilders.Resources.Builder();
{
resource.SetVersion(ResourcesVersion);
return Futures.ImmediateFuture(resource.Build());
}
}
}
public static class Futures
{
public static ImmediateFuture ImmediateFuture(Java.Lang.Object value)
=> new ImmediateFuture(value);
}
public class ImmediateFuture : Java.Lang.Object, IListenableFuture
{
public bool IsDone => true;
public bool IsCancelled => false;
private Java.Lang.Object _obj;
public ImmediateFuture(Java.Lang.Object o)
=> _obj = o;
public void AddListener(IRunnable p0, IExecutor p1)
=> p1.Execute(p0);
public bool Cancel(bool mayInterruptIfRunning) => false;
public Java.Lang.Object Get() => _obj;
public Java.Lang.Object Get(long timeout, TimeUnit unit) => Get();
}
}
@zandiarash
Copy link

I've searched a lote but I did not found an example of WearOS Tile until I found this page, Special Thanks.

@TheSnowfield
Copy link
Author

I've searched a lote but I did not found an example of WearOS Tile until I found this page, Special Thanks.

I PRed to Xamarin's official example repository on GitHub 2 yrs ago, but got no reply for now.
xamarin/monodroid-samples#326

@zandiarash
Copy link

Well Done Dear @TheSnowfield , Thanks again.
May I ask you some questions?
Can we make tile layout with XAML? if not what should I search to find a document for making Tile UI?
Can we make tile layout in MAUI?

@TheSnowfield
Copy link
Author

Well Done Dear @TheSnowfield , Thanks again. May I ask you some questions? Can we make tile layout with XAML? if not what should I search to find a document for making Tile UI? Can we make tile layout in MAUI?

I'm not continuing to research Android Tile these days,
Thus I recommend you read Android docs and follow their steps. If the package or dependencies aren't met in Xamarin, you must import them as manually as this article does. Because some packages are in the alpha, Xamarin often doesn't port them to NuGet.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment