'How to use Android RRO to overlay a layout?

I'm trying to customize Android 10 AOSP Settings app (com.android.settings) using a Runtime Resource Overlay (RRO). When using a RRO, I can successfully customize any string in Settings app by putting a new value in the RRO's file ./res/values/strings.xml.

However, I cannot manage to overlay not a string but a layout by putting the layout file in the RRO's ./res/layout/ folder.

The RRO gets built, but the ids are different than the ones in the original layout, so after installing the RRO on device, the Settings app will fail to find the elements it expects in the layout file using findViewById().

For instance, I create a RRO containing the following bluetooth_pin_confirm.xml layout file (copied from Settings app source code and simplified) in its res/layout/folder:

<?xml version="1.0" encoding="utf-8"?>
    <LinearLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_height="match_parent"
        android:layout_width="match_parent"
        android:orientation="vertical">

        <TextView
            android:id="@+id/pairing_caption"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
        />
    ...    

    </LinearLayout>

After installing the RRO on device, the Settings app will successfully inflate this file in BluetoothPairingDialogFragment.java

        View view = getActivity().getLayoutInflater().inflate(R.layout.bluetooth_pin_confirm, null);

But then it won't be able to find the views by id:

        TextView pairingViewCaption = (TextView) view.findViewById(R.id.pairing_caption);

R.id.pairing_caption cannot be found so pairingViewCaption will be null

So it seems that the IDs in the layout file from the RRO are different than the original ones.

Indeed, when running aap2 dump on Settings app apk I can see:

resource 0x7f0a02e0 com.android.settings:id/pairing_caption: t=0x12 d=0x00000000 (s=0x0008 r=0x00)

While in the RRO I can see:

resource 0x7f010000 com.foo.settings:id/pairing_caption: t=0x12 d=0x00000000 (s=0x0008 r=0x00)

So yes, the Ids are different.

Now, it should be the whole point of the RRO when overlaying a layout to be able to match the Ids so to keep original Ids but change the layout around them. But how?

I've played a bit with aapt2 options --emit-ids and --stable-ids to try to force generated id to be equal to the one in Settings.apk, but that fails miserably as well:

error: can't assign ID 0x7f0a0303 to resource com.foo.settings:id/pairing_caption with conflicting ID 0x7f010000.

Note that this issue is specific to Android 10 and earlier. It seems that in Android 11 there is a new & better way to define mapping between ids in target and overlay package.

I'm pretty stuck here. Any suggestion would be greatly appreciated



Solution 1:[1]

On the link rro

you can find the following

Note: If you overlay a layout file, make sure all the IDs and app namespace attributes are included in both overlays.xml and overlayable.xml. For example:

<overlay>
<item target="layout/car_ui_base_layout_toolbar" 
      value="@layout/car_ui_base_layout_toolbar" />
<item target="id/car_ui_toolbar_background" 
      value="@id/car_ui_toolbar_background" />
<item target="attr/layout_constraintTop_toBottomOf" 
      value="@attr/layout_constraintTop_toBottomOf" />
</overlay>

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 sucicf1