Skip to content

Commit

Permalink
[Mono.Android] Bind Android 12L Beta 1.
Browse files Browse the repository at this point in the history
  • Loading branch information
jpobst committed Jan 4, 2022
1 parent 72462c5 commit eb6da19
Show file tree
Hide file tree
Showing 19 changed files with 238 additions and 37 deletions.
6 changes: 3 additions & 3 deletions Configuration.Override.props.in
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,11 @@
kept consistent with each other, lest Bad Things Happen™
-->
<!-- The default Android API level to bind in src/Mono.Android -->
<AndroidApiLevel>31</AndroidApiLevel>
<AndroidApiLevel>32</AndroidApiLevel>
<!-- The Xamarin.Android $(TargetFrameworkVersion) value that corresponds to $(AndroidApiLevel) -->
<AndroidFrameworkVersion>v12.0</AndroidFrameworkVersion>
<AndroidFrameworkVersion>v12.1</AndroidFrameworkVersion>
<!-- The default Android API "id" that corresponds to $(AndroidApiLevel) -->
<AndroidPlatformId>31</AndroidPlatformId>
<AndroidPlatformId>32</AndroidPlatformId>

<!--
Colon-separated list of ABIs to build the mono JIT for.
Expand Down
8 changes: 4 additions & 4 deletions Configuration.props
Original file line number Diff line number Diff line change
Expand Up @@ -30,13 +30,13 @@
<AndroidMinimumDotNetApiLevel Condition="'$(AndroidMinimumDotNetApiLevel)' == ''">21</AndroidMinimumDotNetApiLevel>
<AndroidFirstPlatformId Condition="'$(AndroidFirstPlatformId)' == ''">$(AndroidFirstApiLevel)</AndroidFirstPlatformId>
<!-- *Latest* *stable* API level binding that we support; used when building src/Xamarin.Android.Build.Tasks -->
<AndroidLatestStableApiLevel Condition="'$(AndroidLatestStableApiLevel)' == ''">31</AndroidLatestStableApiLevel>
<AndroidLatestStableApiLevel Condition="'$(AndroidLatestStableApiLevel)' == ''">32</AndroidLatestStableApiLevel>
<AndroidLatestStablePlatformId Condition="'$(AndroidLatestStablePlatformId)' == ''">$(AndroidLatestStableApiLevel)</AndroidLatestStablePlatformId>
<AndroidLatestStableFrameworkVersion Condition="'$(AndroidLatestStableFrameworkVersion)'==''">v12.0</AndroidLatestStableFrameworkVersion>
<AndroidLatestStableFrameworkVersion Condition="'$(AndroidLatestStableFrameworkVersion)'==''">v12.1</AndroidLatestStableFrameworkVersion>
<!-- *Latest* *unstable* API level binding that we support; this can be the same as *stable* -->
<AndroidLatestUnstableApiLevel Condition="'$(AndroidLatestUnstableApiLevel)' == ''">32</AndroidLatestUnstableApiLevel>
<AndroidLatestUnstablePlatformId Condition="'$(AndroidLatestUnstablePlatformId)' == ''">Sv2</AndroidLatestUnstablePlatformId>
<AndroidLatestUnstableFrameworkVersion Condition="'$(AndroidLatestUnstableFrameworkVersion)'==''">v12.0.99</AndroidLatestUnstableFrameworkVersion>
<AndroidLatestUnstablePlatformId Condition="'$(AndroidLatestUnstablePlatformId)' == ''">32</AndroidLatestUnstablePlatformId>
<AndroidLatestUnstableFrameworkVersion Condition="'$(AndroidLatestUnstableFrameworkVersion)'==''">v12.1</AndroidLatestUnstableFrameworkVersion>
<!-- The API level and TargetFrameworkVersion for the default Mono.Android.dll build -->
<AndroidApiLevel Condition=" '$(AndroidApiLevel)' == '' ">$(AndroidLatestStableApiLevel)</AndroidApiLevel>
<AndroidPlatformId Condition=" '$(AndroidPlatformId)' == '' ">$(AndroidLatestStablePlatformId)</AndroidPlatformId>
Expand Down
169 changes: 165 additions & 4 deletions Documentation/workflow/HowToAddNewApiLevel.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,13 +54,174 @@ acceptable "breaks":

When Google announces that the APIs are frozen, additional work such as enumification is needed.

---- Somewhat outdated docs below, update when we do this year's stabilization ----
There have been many, many attempts to "automate" the enumification process in the past, to varying
degrees of success. The main problem is that no automated process is going to be perfect, so
they all rely on a human verifying and modifying the results.

However this verification process is long and tedious. Doing it correctly requires almost as much
effort as doing the full process manually. Thus it generally isn't done correctly and many errors
slip in, leaving our users with bad bindings that are hard to fix in the future without breaking API.

Currently we have taken the opposite approach and do the process completely manually, but we
have invested in tooling to make the process as easy as possible.

This tooling is BindingStudio:
https://github.com/jpobst/BindingStudio

It's a Winforms app, so it only runs on Windows. It's ugly as sin, and has very poor UX. However,
it prompts you with the exact decisions you need to make, and handles as much dirty work as possible,
allowing enumification to be done in a few days.

### Extract constants from API

Using BindingStudio:

- Update `CURRENT_API_LEVEL` in MainForm.cs
- Choose `Tools` -> `Add API Level Constants`
- Fill in existing `map.csv`: `xamarin-android/src/Mono.Android/map.csv`
- Fill in new `api.xml`: ex: `xamarin-android/src/Mono.Android/obj/Debug/net6.0/android-32/mcw/api.xml`
- Choose `File` -> `Save`

This adds all the new possible constants from the API level to `map.csv`. They will be
marked with a `?` indicating no determination has been made if they should be enumified or not.

Example:
```
?,32,android/media/Spatializer.SPATIALIZER_IMMERSIVE_LEVEL_MULTICHANNEL,1,,,,
?,32,android/media/Spatializer.SPATIALIZER_IMMERSIVE_LEVEL_NONE,0,,,,
?,32,android/media/Spatializer.SPATIALIZER_IMMERSIVE_LEVEL_OTHER,-1,,,,
```

### Creating enums

Using BindingStudio:

- Choose `File` -> `Open Constant Map`
- Choose existing `map.csv`: `xamarin-android/src/Mono.Android/map.csv`

The left tree view will be populated with every type that has possible constants that require
a decision. Clicking a tree node will show the grid of all constants in the type. The ones
that need to be handled are the ones with `Action` = `None`. (The others are shown because
sometimes the correct action is to add a new constant to an existing enum.)

Select the row(s) containing the constants you want to act on. (Use Control and Shift to select
multiple rows.) There are 3 possible options for constants:

1) Ignore

If the constant(s) should not be part of an enum (like `Math.PI`), click the `Ignore` toolbar
button to leave them as constants.

2) Add to existing enum

If the constant(s) should be added to an existing enum:
- Click the `Add to existing enum` toolbar button.
- The dialog will show all other enums in this type
- Choose the existing enum to add the new constant(s) to
- After accepting the dialog, you may need to click the grid to cause it to refresh
- The constant(s) will be marked as `Enumify` with the `EnumFullType` you specified
- The enum member names may need to be tweaked by changing the `EnumMember` column

3) Create a new enum

If the constant(s) should be added to a brand new enum:
- Click the `Create Enum` toolbar button
- In the dialog, a suggested enum namespace and name will be pre-populated. This may need to be
tweaked as needed.
- Mark `Is Flags` if this should be a `[Flags]` enum type.
- After accepting the dialog, you may need to click the grid to cause it to refresh
- The constant(s) will be marked as `Enumify` with the `EnumFullType` you specified
- The enum member names may need to be tweaked by changing the `EnumMember` column

Once decisions have been made for all new constants in a type, use the left tree view to move
to the next type. You should periodically save your progress with `File` -> `Save` in case
BindingStudio crashes.

The left tree view can be updated by saving and reopening the `map.csv` file.

### Extract methods that possibly need enums

5) enumification
Using BindingStudio:

See `build-tools/enumification-helpers/README`. Usually it takes many days to complete...
- Update the file paths in `MainForm.FindAPILevelMethodsToolStripMenuItem_Click`
- Run BindingStudio and choose `Tools` -> `Find API Level Methods`

Enumification work can be delayed and only the final API has to be enumified.
This will create a file of every method in the new API level that takes an `int` as a parameter
or returns an `int` as a return value. Each method will be marked with a `?` in the file
to indicate a decision needs to be made to ignore it or map it to an enum.

Example:
```
?,32,android/media,AudioAttributes,getSpatializationBehavior,return,
?,32,android/media,AudioAttributes$Builder,setSpatializationBehavior,sb,
```

### Mapping methods

Using BindingStudio:

- Choose `File` -> `Open Constant Map`
- Choose existing `map.csv`: `xamarin-android/src/Mono.Android/map.csv`
- Choose `File` -> `Open Method Map`
- Choose the new `.csv` created in the previous step

The left tree will populate with every method that possibly should be enumified and
needs a decision to be made. Clicking a method shows the Android documentation for
the method to help make the decision, as well as an area to input the decision.

Note a method may show up multiple times, once for each parameter or return type
(Parameter Name = "return") that is an int. Each one may require a different action.

There are 3 possible options for a method parameter/return type:

1) Unknown

You don't how to handle this method currently, so leaving it in the initial state
of "Unknown" will leave it alone until a decision can be made.

2) Ignore

The method parameter/return type should remain an `int` and not be converted to an enum.

Ex:
```
int Add (int value1, int value2) { ... }
```

Click the "Ignore" radio button and then the "Save" button.

3) Enumify

The method parameter/return type should be changed to an enum.

Ex:
```
void AudioAttributesBuilder.SetSpatializationBehavior (int sb) { ... }
```

- Choose the "Enumify" radio option
- Use the DropDown in the middle to select the enum to use
- When selected, the members of that enum will be shown in the box below the enum
- Alternatively, search for a enum by enum member name using the Search box in the right
- If desired enum is found, clicking it will populate dropdown
- Click "Save"

Use `File` -> `Save` to save your work often!

### Finishing the method map

The official `methodmap.csv` uses a slightly different format than the one used for enumification.

Using BindingStudio:
- Ensure the "new api level method map" CSV file is loaded.
- Choose `Tools` -> `Export Final Method Map`
- Choose a temporary file name
- Open the temporary file, copy the contents to the bottom of the official:
- xamarin-android/src/Mono.Android/methodmap.csv

Congrats! Enumification is complete!

---- Somewhat outdated docs below, update when we do this year's stabilization ----

6) new AndroidManifest.xml elements and attributes

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ public sealed class CheckApiCompatibility : Task
{ "v10.0", "v9.0" },
{ "v11.0", "v10.0" },
{ "v12.0", "v11.0" },
{ "v12.0.99", "v12.0" },
{ "v12.1", "v12.0" },
};

static readonly string assemblyToValidate = "Mono.Android.dll";
Expand Down
4 changes: 2 additions & 2 deletions build-tools/api-merge/merge-configuration.xml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
<File Path="api-29.xml.in" Level="29" />
<File Path="api-30.xml.in" Level="30" />
<File Path="api-31.xml.in" Level="31" />
<File Path="api-Sv2.xml.in" Level="Sv2" />
<File Path="api-32.xml.in" Level="32" />
</Inputs>
<Outputs>
<File Path="android-19\mcw\api.xml" LastLevel="19" />
Expand All @@ -36,6 +36,6 @@
<File Path="android-29\mcw\api.xml" LastLevel="29" />
<File Path="android-30\mcw\api.xml" LastLevel="30" />
<File Path="android-31\mcw\api.xml" LastLevel="31" />
<File Path="android-Sv2\mcw\api.xml" LastLevel="Sv2" />
<File Path="android-32\mcw\api.xml" LastLevel="32" />
</Outputs>
</Configuration>
2 changes: 1 addition & 1 deletion build-tools/api-xml-adjuster/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ API_XML_TOOL = $(BUILDBIN)/api-xml-adjuster.exe
RUNTIME = mono --debug
RUN_CLASS_PARSE = $(RUNTIME) $(CLASS_PARSE)
RUN_API_XML_TOOL = $(RUNTIME) $(API_XML_TOOL)
API_LEVELS = 10 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 Sv2
API_LEVELS = 10 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32

XML_OUTPUT_DIR = .

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ class BuildAndroidPlatforms
new AndroidPlatform (apiName: "Q", apiLevel: 29, platformID: "29", include: "v10.0", framework: "v10.0"),
new AndroidPlatform (apiName: "R", apiLevel: 30, platformID: "30", include: "v11.0", framework: "v11.0"),
new AndroidPlatform (apiName: "S", apiLevel: 31, platformID: "31", include: "v12.0", framework: "v12.0"),
new AndroidPlatform (apiName: "Sv2", apiLevel: 32, platformID: "Sv2", include: "v12.0.99",framework: "v12.0.99", stable: false),
new AndroidPlatform (apiName: "Sv2", apiLevel: 32, platformID: "32", include: "v12.1", framework: "v12.1"),
};

// These are here until we can drop "legacy" targets and use only .NET6+
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ public AndroidToolchain ()
new AndroidPlatformComponent ("platform-29_r01", apiLevel: "29", pkgRevision: "1"),
new AndroidPlatformComponent ("platform-30_r01", apiLevel: "30", pkgRevision: "1"),
new AndroidPlatformComponent ("platform-31_r01", apiLevel: "31", pkgRevision: "1"),
new AndroidPlatformComponent ("platform-Sv2_r01", apiLevel: "Sv2", pkgRevision: "1"),
new AndroidPlatformComponent ("platform-32_r01", apiLevel: "32", pkgRevision: "1"),

new AndroidToolchainComponent ("sources-31_r01", destDir: Path.Combine ("platforms", $"android-31", "src"), pkgRevision: "1", dependencyType: AndroidToolchainComponentType.BuildDependency),

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6856,6 +6856,9 @@ package android.hardware.camera2.params
copyElements(int[] destination, int offset)
equals(java.lang.Object obj)
getElement(int column, int row)
class DeviceStateSensorOrientationMap
equals(java.lang.Object obj)
getSensorOrientation(long deviceState)
class ExtensionSessionConfiguration
#ctor(int extension, java.util.List<android.hardware.camera2.params.OutputConfiguration> outputs, java.util.concurrent.Executor executor, android.hardware.camera2.CameraExtensionSession.StateCallback listener)
class InputConfiguration
Expand Down Expand Up @@ -18985,12 +18988,12 @@ package android.view
interface ActionProvider.VisibilityListener
onActionProviderVisibilityChanged(boolean isVisible)
interface AttachedSurfaceControl
addOnSurfaceTransformHintChangedListener(android.view.AttachedSurfaceControl.OnSurfaceTransformHintChangedListener listener)
addOnBufferTransformHintChangedListener(android.view.AttachedSurfaceControl.OnBufferTransformHintChangedListener listener)
applyTransactionOnDraw(android.view.SurfaceControl.Transaction t)
buildReparentTransaction(android.view.SurfaceControl child)
removeOnSurfaceTransformHintChangedListener(android.view.AttachedSurfaceControl.OnSurfaceTransformHintChangedListener listener)
interface AttachedSurfaceControl.OnSurfaceTransformHintChangedListener
onSurfaceTransformHintChanged(int hint)
removeOnBufferTransformHintChangedListener(android.view.AttachedSurfaceControl.OnBufferTransformHintChangedListener listener)
interface AttachedSurfaceControl.OnBufferTransformHintChangedListener
onBufferTransformHintChanged(int hint)
class Choreographer
postFrameCallback(android.view.Choreographer.FrameCallback callback)
postFrameCallbackDelayed(android.view.Choreographer.FrameCallback callback, long delayMillis)
Expand Down
Loading

0 comments on commit eb6da19

Please sign in to comment.