AppCompactDialogFragment not displaying the OK Button on Android 12 devices

Graham McKechnie 441 Reputation points
2021-12-28T03:46:30.9+00:00

My app is Xamarin.Android – android:targetSdkVersion="31

I have quite a few modal Dialogs in my app, which are all based on AppCompatDialogFragment. Some are more complicated than others and so have their own classes, but they now all appear to have a problem in displaying correctly on Android 12 devices only. On any devices lower than Android 12, they display normally as they have done, since Android 10, when I first converted to AndroidX.

The simplest one of these dialogs is a class called BasicDialogFragment. An instance of it takes 2 strings, a title and a message. The layout is a NestedScrollView containing a ConstraintLayout which has a single Textview for the message, which can be of any length.

The problem is the OK button doesn’t always appear, especially on longer multi-paragraph messages which obviously can scroll. If the message is short enough that scrolling is not required, then the OK button displays normally. On dialogs with longer messages, the button might appear the first time the Dialog is called, the next time it might only be partially visible (but still tappable) and another time it is not visible. Even when not visible the dialog can still be dismissed by tapping in the area where the button should be. Quite often if you rotate the device the button will appear in Landscape and when you rotate back to Portrait the button will appear where previously it didn’t, but there is no consistent pattern to it.

There doesn’t appear to be anything wrong with the NestedScrollView because the text does scroll as you would expect, even with the new spring animation which Android 12 introduced.

I’ve rechecked, the old Android 11 version of the app and it also has the same problem on the Android 12 devices.

I have 3 Pixel devices - 3a (Android12), 4a (still Android11 – so doesn’t have the problem) and a Pixel 6.
All my other devices are Samsung (phones and tablets - Android 7 through Android 11) but none of them has Android 12 yet, so none of them exhibits the problem.

I’m using a MaterialAlertDialogBuilder in the OnCreateDialog of the BasicDialogFragment as below.

public override Dialog OnCreateDialog(Bundle savedInstanceState)
{
    LayoutInflater inflater = LayoutInflater.From(Activity);
    View view = inflater.Inflate(Resource.Layout.generic_dialog, null);

    TextView textViewExplanation = view.FindViewById<TextView>(Resource.Id.textView_explanation);
    textViewExplanation.Text = Arguments.GetString("Message");

    MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(Activity);
    builder.SetTitle(Arguments.GetString("Title"));
    builder.SetPositiveButton(Android.Resource.String.Ok, (sender, args) => { Dismiss(); });
    builder.SetView(view);
    return builder.Create();
}

The following is xml of generic_dialog.xml

<androidx.core.widget.NestedScrollView
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:fillViewport="true"
    android:scrollbars="vertical"
    android:paddingTop="16dp"
    android:paddingBottom="8dp"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin">

    <androidx.constraintlayout.widget.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content">
        <TextView
            android:id="@+id/textView_explanation"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:singleLine="false"
            android:textAppearance="@android:style/TextAppearance.Material"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent"
            tools:text="@string/subscription_explanation_text" />
    </androidx.constraintlayout.widget.ConstraintLayout>

</androidx.core.widget.NestedScrollView>

I first tried to reproduce the problem, by building a simple app based on the Blank app template. Unfortunately, I couldn’t reproduce it with that. So, my next try was to swap to Android Studio and use one of their templates, called Navigation Drawer Activity, which is a single activity, multi fragment app using the NavigationComponent with a navigation graph, which more closely resembles my app, as I also use the NavComponent. However, I couldn’t reproduce the problem when adding my code to it, the dialogs displayed without any problem.

The next step was to convert their app to a Xamarin.Android app. I’ve now done that, and it works just the same as the Android Studio app. The only change I made, other than I borrowed most of their xml, was to replace the fragment tag they had in content_main.xml with an androidx.fragment.app.FragmentContainerView, as that is a recommendation Android made some time ago, but obviously, they haven’t got around to updating their own template. I also ignored the ViewModel and Binding stuff as they don’t really have any relevance with the problem of the OK button not displaying. Again, no luck as this version also works perfectly.

I also removed their FloatingActionButton in app_bar_main.xml and introduced a BottomNavigationView into content_main. My app has no use for a FloatingActionButton but does require a BottomNavigationBar on one of my top-level fragments. In this example, It is only shown on the SlideShowFragment as that mimics my apps behaviour. The two menu items of the BottomNavigationBar have no code attached, so they don’t do anything.

I’m attaching my Xamarin.Android example to this post. If anyone would like the Android Studio version, I can also upload that if required.
The attached app has been built with VS 2022 17.1.0 Prev 1.1 but has also been tested with VS 2022 17.0.4.

I’ve deliberately tried to use an example that displays generic text, so I chose the subscription info as the text, so I didn’t need to expose product or company info in the example of a not as yet released app. Please feel free to modify it with your text. The subscription info is normally displayed as a BottomSheetDialogFragment on my SubscriptionFragment, so I had to add a couple of paras just to make it scrollable to be able to use my BasicDialogFragment on the Pixel 6.

The one thing that I notice that is different between my own app and this example app is if I deliberately display the subscription info on the start destination fragment (not normally available from there) then I can see that the origin x,y of the dialog is lower in my app than it is in the example app on the Pixel 6. This is most obvious when you make both apps go into the background, where you can see them side by side. Unfortunately, I’m not aware of how you can take a screenshot of both apps at the same time. Why the starting point is lower on my app I’ve no idea.

I’ve been chasing this problem now for about 2 weeks and not getting anywhere with it, so I’m hoping someone here will have some brilliant solution.
A couple of warnings, if you haven’t used the navigation component before. Having a nav_graph.xml in a Xamarin.Android app gives the Xamarin.Android designer fits, in that it usually always opens any xml layout file with an error. You soon learn to ignore the error as it has no effect on the building or running of the app. If it does happen to any of you, you can eliminate the error by temporally excluding the nav_graph from the project and then the designer should open any layout file without error. You’ve just got to remember to re-include it again before your build.

The OK button problem has been reported on https://github.com/xamarin/xamarin-android/issues. Issue #6554, however, there appears to be a hold up over there as all reported problems since #6546 are still listed as “needs-triage”, hence my post here.

I look forward to any of your comments and suggestions and thanks for taking the time to have a look at my problem.

Link to zip file: https://drive.google.com/file/d/1cuByKpW38npMrLTiMT9Qk5MDeKIF0drt/view?usp=sharing

Developer technologies | .NET | Xamarin
{count} votes

4 answers

Sort by: Most helpful
  1. Graham McKechnie 441 Reputation points
    2021-12-29T11:02:09.78+00:00

    @JarvanZhang Sorry for the misleading information. I mean the OK Button is shown well in my test with Android 12 on pixel 5.

    That's ok. You are getting what I'd expect and what I get with the test app.

    Does this problem only occur on Pixel 6 or all the Android 12 devices? Every device has different settings of the screen.

    With my app, the missing OK button occurs on both my Android 12 devices - Pixel 3a and Pixel 6. However, the test app shows the OK button on both of those devices.

    My Pixel 4a is still running Android 11 (deliberately keeping at 11), so it is also fine - shows the OK button with my app and the test app.

    I hope that clears it up for you. Thanks for your replies.


  2. Graham McKechnie 441 Reputation points
    2022-01-13T01:21:48.967+00:00

    @JarvanZhang

    I've tested the sample of the link. You mentioned that the issue occurs on your project, but it work fine in the test app.

    Yes, I agree with you, my sample app works just fine, so I would expect your test app would also work fine. I was away for most of last week, so I’ve only just got back to figuring out the differences between my real app and the test app I uploaded.

    I’ve made some progress after discovering (basically had forgotten that it was there) a styles.xml in the V21 folder. Obviously, a hangover from the original app when it supported Lollipop. However, it is only a one-liner <item name="android:windowTranslucentStatus">true</item>.

    Luckily there were some notes there, that I made when I first started converting the app to Android 10 or was it 9. The pertinent part was – without this - Prevents the Appbar/Toolbar from extending to the full width of the screen in landscape when LayoutInDisplayCutoutMode is ShortEdges.

    The following screenshot demonstrates the distorted or shortened AppBar.
    https://drive.google.com/file/d/1CtGJQDFUbSY9UVthBCMAYE4DMP9DExXK/view?usp=sharing

    You get a similar result when you do the reverse Landscape except then it is the left side that is not extended.

    And after adding WindowTranslucentStatus
    https://drive.google.com/file/d/1Nt8kEk_aOgSSVn9_OissPbg7Z2aDPx7A/view?usp=sharing

    My minimum SDK is now Android 7, so the V21 folder can go, but that doesn’t fix the problem. However, what is obvious is that the OK button problem is related to this. If you add it back into the styles.xml of the test app then the OK button will disappear on an Android 12 device. Note it is not necessarily the first time you open the dialog, but it usually fails on the first rotation of the dialog and once it fails it stays missing or partially missing.

    Example:
    https://drive.google.com/file/d/12EfUAvbpnQXQBbYJHkCOYSw5zPmnt2-Q/view?usp=sharing

    The reason I’m using ShortEdges is that I have quite a few immersive fragments that show for instance a graph in one of the fragments and in another I show up to 24 gauges via a ViewPager2. Rather than letterbox those fragments I give the user a preference option to use all of the screen. Corner notches don’t affect the gauges that display, centre notches can potentially (depending on the device) have a very small overlap. The graph of the graph fragment is unaffected by the notches. The user also has a choice of backgrounds for the gauges – either black or a carbon fibre background. Using the carbon fibre background while letterboxed looks terrible on devices with notches because then you have the black background of where the Statusbar is contrasted against the carbon fibre background.

    Therefore the new problem with the OK button when building for Android12 is caused by <item name="android:windowTranslucentStatus">true</item> being in styles.xml. If you test without that line, then you can open the dialog as many times as you like, and the OK button always displays. However, then you also have the problem of shortened AppBarLayout in Landscape when using LayoutInDisplayCutoutMode.ShortEdges

    To get around that I’m now using Window.AddFlags(WindowManagerFlags.TranslucentStatus) in the first line of OnCreate in the MainActivity. Then everything works again as it did when building the app for Android 10 and 11. However there is a problem here because TranslucentStatus and also TranslucentNavigation are both meant to be deprecated as of API 30, but Xamarin isn’t showing them as deprecated, even in the latest preview VS 17.1.0 Preview 2.0

    Also note from Google’s docs - When this flag is enabled for a window, it automatically sets the system UI visibility flags.
    View#SYSTEM_UI_FLAG_LAYOUT_STABLE and View#SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN

    This probably explains why the shortened AppBarLayout was extended to full screen when I first used android:windowTranslucentStatus true in styles while building for Android 9. The suggested replacement for both windowTranslucentStatus and windowTranslucentNavigation is to use Window#setStatusBarColor(int) with a half-translucent color instead. e.g. Window.SetStatusBarColor(new Color(ContextCompat.GetColor(this, Resource.Color.red_700)));

    The two above flags were also deprecated in Android 11, along with just about every other UI_FLAG

    Well, the above works for a translucent status bar, but then you are back to the shortened AppBarLayout, so in deprecating them, they also change behaviour with no apparent solution.

    This attached example now includes the IOnApplyWindowInsetsListener from my app and the OnApplyWindowInsets which is used to control Window.Attributes.LayoutInDisplayCutoutMode, ShortEdges or Default depending on whether the bool devicesWithNotchesAllowFullScreen is true or false.

    The project contains <item name="android:windowTranslucentStatus">true</item> in styles.xml, to demonstrate that the OK button doesn’t display.

    Therefore to get the OK button to display comment out or remove that line from styles.xml. The button should then display. However, when you rotate the device, the shortened AppBarLayout will be visible.

    The next step is to uncomment the line Window.AddFlags(WindowManagerFlags.TranslucentStatus); in the MainActivity and that will correct the problem with the AppBarLayout and the OK Button will still be visible each time the dialog is displayed.

    In conclusion, I have a short term solution, but obviously, I’m looking for a long term solution. Appreciate it if you or anyone else has a better solution.

    Link to project. https://drive.google.com/file/d/1cuByKpW38npMrLTiMT9Qk5MDeKIF0drt/view?usp=sharing

    PS
    The screenshots referred to above are also contained within the project in its root folder.


  3. Graham McKechnie 441 Reputation points
    2022-01-13T10:35:21.553+00:00

    @JarvanZhang

    Did you try the sample I uploaded?

    If you do as you have just suggested then you get back the shortened AppBarLayout. It is has nothing to do with detecting the build version.

    I made the point that Window.AddFlags(WindowManagerFlags.TranslucentStatus) does far more than just make a Translucent status bar.

    Please try the steps I outlined in my last post.


  4. Graham McKechnie 441 Reputation points
    2022-01-15T02:52:29.57+00:00

    @JarvanZhang

    Do you test the code on physical device or emulator? Try testing the project on above two emulators to check if the shorten layout will occur.

    I’ve said repeatedly in this thread that I’ve tested on real Android 12 devices.

    Since I started this thread, I’ve now upgraded all my Pixel phones to Android 12 – Pixel 3a, Pixel 4a and Pixel 6. I’ve also upgraded my Samsung S20 5G to Android 12. All those phones perform identically using the latest test app I uploaded. They all exhibit the shortened AppLayout and they all have the problem of the disappearing OK button.

    Since my app relies on Bluetooth, I never use Android emulators as they don’t support Bluetooth therefore for everyday development of my real app they are totally useless to me.

    The Android 12 test app demonstrates two problems 1. The shortened AppBarLayout and 2. The disappearing OK Button. I’m pleased you can now at least acknowledge the disappearing OK button.

    Please note that none of these devices had either problem with the Android 11 version of the same app when they were running Android 11.

    The shortened AppBarLayout is not actually an Android 12, problem but a problem related to using Window.Attributes.LayoutInDisplayCutoutMode = LayoutInDisplayCutoutMode.ShortEdges which was introduced with Android 9. Therefore, you don’t even need to test on an Android 12 device to demonstrate the AppBarLayout problem. Any phone running Android 9 or above will demonstrate that problem. However, if the phone you happen to test doesn’t have a notch then the only way to demonstrate the problem is to go to Developer Options and choose Simulate display with cutout (Samsung devices) or Display cutout on (Pixel devices ). As I don’t use emulators, I can’t comment on whether that option is available on an emulator. However, I’m assuming that you must at least have an Android phone available to you that runs Android 9 or above, so you can test without using an emulator.

    So, referring to the AppBarLayout problem. I apologise for not giving implicit instructions regarding the test app, I wrongly assumed that you would see the problem from the code.

    Please check the following in the test app I uploaded to demonstrate the AppBarLayout problem.

    1. Make sure private bool devicesWithNotchesAllowFullScreen = true in the MainActivity.
    2. Comment the line Window.AddFlags(WindowManagerFlags.TranslucentStatus) in the OnCreate on the MainActivity.
    3. Comment the line <item name="android:windowTranslucentStatus">true</item> in styles.xml
    4. If your Android 9 and above device doesn’t have a notch, make sure you choose under Developer Options that you have a cutout e.g. Corner or punch hole.

    Now run the app and then rotate the screen. The appBarLayout will now be shortened. Check the code in OnApplyWindowInsets and it should be obvious why the screen is now fully extended into the cutout area, but the AppBarLayout is not. It should look identical to the screenshot I previously shared. Now set devicesWithNotchesAllowFullScreen = false and re-run the app and rotate the screen and you then should see a default letterboxed landscape display.

    To overcome the problem of shortened AppBarLayout.

    1. Uncomment the line <item name="android:windowTranslucentStatus">true</item> in styles.
    2. Reset devicesWithNotchesAllowFullScreen = true.

    Rerun the app and rotate the screen to Landscape now you should see a fully extended AppBarLayout.

    So the above fixes the problem of the AppBarLayout and my real app ran like that from Android 9 through 11. Devices running less than 9 had no problem because they don’t have notches.

    You may also like to read the comments I wrote as a reminder for myself (Notes about Window.Attributes.LayoutInDisplayCutoutMode) in OnDestinationChanged for more of an insight about LayoutInDisplayCutoutMode.

    BasicDialogFragment test on Android 12 devices.

    Without any code changes attempt to open the Subscription Information dialog on an Android 12 device via the 3 button menu on the home fragment. It may open successfully with the OK button displayed, rotate the screen a couple of times and eventually, the OK button will disappear. Even when it has disappeared or is partially visible, you can still tap where the button should be, and the dialog will be dismissed. Usually, once it has disappeared, it stays that way.

    Fix for Android 12

    1. Comment the line <item name="android:windowTranslucentStatus">true</item> in styles.xml as it not required anymore.
    2. Check devicesWithNotchesAllowFullScreen = true.
    3. Uncomment Window.AddFlags(WindowManagerFlags.TranslucentStatus) in OnCreate of the MainActivity.
    4. If your Android 9 and above device doesn’t have a notch, make sure you choose under Developer Options that you have a cutout e.g. Corner or punch hole.
    5. Do run on an Android 12 device to confirm that the behaviour of the OK remains visible on multiple rotations.
      Hopefully, with these instructions, you should get the same result as I do.

    Conclusion

    As I said earlier in the thread, this is a short-term solution that is working fine right now for all Android versions between 7 and 12. However, I don’t like using deprecated features such WindowManagerFlags.TranslucentStatus because eventually, they come back to bite on you on the bum. Far better in the long term to deal with it now.

    You can see in my code example I did try Google’s recommended replacement for WindowManagerFlags.TranslucentStatus being Window.SetStatusBarColor(). However, as I suspected, all it did was change the status bar to a translucent colour and again screwed up the AppBarLayout.

    From the above testing, it is quite obvious WindowManagerFlags.TranslucentStatus does much more than make the status bar translucent. It does as their new documentation states, it automatically sets the already deprecated (deprecated by android 11) system UI visibility flags.
    View#SYSTEM_UI_FLAG_LAYOUT_STABLE and View#SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN.

    0 comments No comments

Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.