“Clarifying for bangs” on Android P. What to do with Android Cutout?

  • Tutorial
September 2007 burned. It was September 2017, Apple returned the fashion to the bangs, presenting the iPhone X. No wonder our friends from China, without thinking twice, copied this design from Apple (although the very first mini bang was still in Essential Phone, which didn’t take off). But what do we see now? Huawei P20, Asus Zenfone 5, OnePlus 6, Motorola One Power, Xiaomi Redmi 6 and other more or less well-known manufacturers have already released or announced phones with bangs. Samsung and Google remained the last strongholds in this race for the HYIP fight for framelessness. Or not? According to rumors, Google Pixel 3 XL will also be with this crapwith an elegant neckline. Well, we, as developers, need only optimize our applications for this cut-out, so that users can continue to use them comfortably. For details, I ask under the cat.



First we need to figure out whether the application needs optimization at all.
If you have a fullscreen application or are present in the subject windowActionBarOverlay = true, then it is most likely needed.

Almost all applications are far from a single screen, and you can not notice how one of them will go layout. Especially if in application the volumetric legacy code. Therefore, it is still worth going through all the main screens and double-check. Let's see what you need to do.

1. Prepare a test device / emulator


In order to test your app with a bang, you need (thanks, cap!) Android P. Currently, Android P Preview 5 is available for the following devices (thanks to Project Treble):
Essential Phone;
Google Pixel 2;
Google Pixel 2 XL;
Google Pixel;
Google Pixel XL;
Nokia 7 plus;
Oneplus 6;
Oppo R15 Pro;
Sony Xperia XZ2;
Vivo X21UD;
Vivo X21;
Xiaomi Mi Mix 2S.

To install Android P on your device, just go here and tap “Get Beta” for your device. Get it through the air or roll yourself - the choice is yours. Instructions on the site is attached.
But if you can not or do not want to install Android P on the device, then no one has canceled the emulator. Instructions for setting up here .

2. Include the very bang software (if there is no hardware)


Everything is simple: go to System -> Developer options -> Simulate a display with a cutout.
There are 3 options to choose from:
  • Corner
  • Double
  • Tall


They look like this:
CornerDoubleTall

3. Go through the main screens


Of course, this case will all be different. Someone simple logic, someone not very. I will give a couple of examples of screens with a go-through layout, which I found in our application.
ExploreProfile

Now let's see what there are ways to eliminate the shortcomings of the layout.

Not raising compileSdkVersion

Starting with the 20th API, the WindowInsets class appeared , which is Rect objects that describe accessible and inaccessible parts of the screen. Together with them in the View appeared such methods, with the help of which we can process the coordinates of inaccessible parts of the screen:

WindowInsets dispatchApplyWindowInsets(WindowInsets);
WindowInsets onApplyWindowInsets(WindowInsets);
voidrequestApplyInsets();
voidsetOnApplyWindowInsetsListener(OnApplyWindowInsetsListener);

Details on how to use them, here .

You can use these methods in two ways:
a) put a tag android:fitsSystemWindows="true"in the layout on your layout or view;
b) do it from the code:

layout.setFitsSystemWindows(true);
layout.requestApplyInsets();

It wasIt became

Increase compileSdkVersion to version 28

In the near future we will have to switch to this version, so why not prepare for it now? But be careful, if you have unit tests in the project (and I hope you have them), the JUnit package has moved. How to connect it, described here .

So, what options does the Android P now provide us with?

A. WindowManager.LayoutParams has 3 new flags:

How to apply?

window.attributes.layoutInDisplayCutoutMode =
    WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES

B. If option A does not suit you and you need to take into account the location of the ill-fated cut-out (for example, you have something displayed directly in the status bar, as messages on the connection in the Telegram), then in this case the new DisplayCutout class will help .
Consider his methods:

With them you can already do everything that is enough imagination. Want - move marginthe code on them. Want - process in OnApplyWindowInsetsListenerand do consumeDisplayCutout(). Perhaps you need more complex manipulations. I will give a simple example of how to denote a fringe.

classSampleFragment() : Fragment() {
	privatelateinitvar root: ViewGroup
	overridefunonCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
		return inflater.inflate(R.layout.sample_fragment, container, false)
	}
	overridefunonViewCreated(view: View, savedInstanceState: Bundle?) {
		super.onViewCreated(view, savedInstanceState)
		root = view.findViewById(R.id.root)
		addArrowsToCutout()
	}
	privatefunaddArrowsToCutout() {
		//Нужно учитывать, что фрагмент должен успеть сделать attach к window, иначе тут будут null'ыval cutoutList = root.rootWindowInsets?.displayCutout?.boundingRects
		cutoutList?.forEach {
			addArrow(context!!.getDrawable(R.drawable.left), it.left.toFloat(), it.top + (it.bottom - it.top).toFloat() / 2,
			         ::calculateLeftArrow)
			addArrow(context!!.getDrawable(R.drawable.right), it.right.toFloat(), it.top + (it.bottom - it.top).toFloat() / 2,
			         ::calculateRightArrow)
			addArrow(context!!.getDrawable(R.drawable.top), it.left + (it.right - it.left).toFloat() / 2, it.top.toFloat(),
			         ::calculateTopArrow)
			addArrow(context!!.getDrawable(R.drawable.bottom), it.left + (it.right - it.left).toFloat() / 2, it.bottom.toFloat(),
			         ::calculateBottomArrow)
		}
	}
	privatefunaddArrow(arrowIcon: Drawable, x: Float, y: Float, calculation: (View, Float, Float) -> Unit) {
		val arrowView = ImageView(context)
		arrowView.setImageDrawable(arrowIcon)
		arrowView.layoutParams = ViewGroup.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT)
		root.addView(arrowView)
		arrowView.post {
			calculation(arrowView, x, y)
		}
	}
	privatefuncalculateLeftArrow(arrowView: View, x: Float, y: Float) {
		arrowView.x = x - arrowView.width
		arrowView.y = y - arrowView.height / 2
	}
	privatefuncalculateRightArrow(arrowView: View, x: Float, y: Float) {
		arrowView.x = x
		arrowView.y = y - arrowView.height / 2
	}
	privatefuncalculateTopArrow(arrowView: View, x: Float, y: Float) {
		arrowView.x = x - arrowView.width / 2
		arrowView.y = y - arrowView.height
	}
	privatefuncalculateBottomArrow(arrowView: View, x: Float, y: Float) {
		arrowView.x = x - arrowView.width / 2
		arrowView.y = y
	}
}

Portrait


CornerDoubleTall


Landscape


Corner
Double
Tall

So, as we see, the bang will bring us some inconvenience and will force us to make extra gestures / additional manipulations. In principle, everything is solved. The main thing is to start eliminating the shortcomings of the layout as early as possible in order to have enough time to prepare. Good luck with the edits. Do not break your Google Play!

Also popular now: