Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Video player lights out mode in Android using appcompat-v7

I'm porting a codebase from native Holo (Theme.Holo etc) to the appcompat-v7 (Theme.AppCompat and so on). The last section contains the tl;dr if you don't want to read the details.


The issue

Everything's working but I had issues replicating one behaviour that was quite easy to have using the old ActionBar. I have a video player, and in landscape I want it to behave like YouTube: hide (animating) the player controls, app bar and status bar. On user interaction, the UI controls should leave this "lights out" mode and go back to the normal state. A timer would then go back to lights out mode if the user doesn't touch the screen for X seconds. The same code that worked with the ActionBar doesn't do the trick with a Toolbar.

So, what I am using is:

  • An opaque Status Bar
  • setSystemUiVisibility() using one of these combos:
    • default: View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
    • lights out: View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LOW_PROFILE | View.SYSTEM_UI_FLAG_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_STABLE
  • minSdkVersion is 16
  • to show and hide the ActionBar I simply called show() and hide() on it
  • to implement the same behaviour on the app bar I subclassed Toolbar and added a show() and a hide() method that do the same (first simply using setVisibility(), and then using animations -- getting the same results)

The LAYOUT_STABLE made so that the appbar would end up behind the status bar, of course (as it implies a fitSystemWindows. Since the appbar is a normal View in the view hierarchy and is not in the decor like the ActionBar was, it is affected by that flag. This was what I was seeing on screen:

App bar behind the status bar

Not immediately clear what the toolbar bounds are, as the app bar is dark on dark, but you can see the title is cut and "misaligned". This is because the toolbar was correctly sized but behind the status bar. My main problem was at that point that there is no public API to get the status bar height, rectangle or anything else to shift my app bar vertically to show below the status bar.

Testing was performed mostly on a N5 on LPX13D (latest Lollipop public build at the time of writing), but the same could be seen happening on Android 4.4.


The hacky solution

That said, after quite some time and some failed attempts at making it work in a not-too-hacky way (including the rather desperate attempt of trying to put it into the decor myself), I resorted to this nasty way of making it work:

  1. In onResume:
    a. Call setSystemUiVisibility(View.SYSTEM_UI_FLAG_VISIBLE) even when I wouldn't normally do it (landscape)
    b. Register an OnPreDrawListener

  2. In the OnPreDrawListener:
    a. Get the root view using View root = getRootView().findViewById(R.id.my_root)
    b. Get the root view height: int rootTop = getAbsoluteViewTop(root) (see below)
    c. Use that top (intending it as a status bar height) as a paddingTop for the appbar
    d. Set the SystemUiVisibility I'd normally use (LAYOUT_STABLE etc)
    e. Suppress the drawing pass

  3. In the next drawing pass, unregister the OnPreDrawListener

This is the getAbsoluteViewTop() method:

private int getAbsoluteViewTop(View view) {
    int[] location = new int[2];
    view.getLocationOnScreen(location);
    return location[LOCATION_Y];
}

tl;dr and question

tl;dr: there is no way to do a proper "lights out" mode with a Toolbar unless hacky hacks are employed.

Question: is there an official and clean way to implement this lights out mode with Toolbar?
I couldn't find anything in the docs. The status bar is not accessible (and all the ways to find out its size you can find on SO are broken, FYI). But maybe I'm missing something. I would love to get rid of this hack.

like image 326
rock3r Avatar asked Nov 10 '14 18:11

rock3r


People also ask

How do I fix AppCompat error v7?

How do I fix AppCompat error v7? "You must have the latest versions of SDK Tools / Build Tools / Platform Tools." This trick resolved my problem. I have all updated Tools except "Build Tools". So I just update the "Build Tools", restarted eclipse then clean "appcompat" project and found my problem is solved.

What is AppCompat in Android?

453. An Android support library that enables the use of the ActionBar and Material Design specific implementations such as Toolbar for older devices down to Android v2.


2 Answers

I've found fitssystemwindows pretty unreliable as well when you want some elements of the view hierarchy to be fullscreen and some elements to be below the status bar or action bar. But I've never seen the action bar behind the status bar. Is the Toolbar set as the activity actionbar? Are you using Window.FEATURE_ACTION_BAR_OVERLAY? Anyway, if all you need is to get a number of pixels for the paddingTop in onResume(), it might be a bit cleaner (still hacky though) to do something like the following rather than use OnPreDrawListeners.

class MyVideoActivity extends Activity {
    Toolbar bar;

    //...

    @Override protected void onResume() {
        super.onResume();
        bar.setPaddingTop(getStatusBarHeight());
    }

    int getStatusBarHeight() {
        int result = 0;
        Resources res = getResources();
        int resourceId = res.getIdentifier("status_bar_height", "dimen", "android");
        if (resourceId > 0) {
            result = res.getDimensionPixelSize(resourceId);
        }
        return result;
    }
}
like image 158
bkDJ Avatar answered Oct 24 '22 06:10

bkDJ


Not sure if this will help but have you looked at using

getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
            WindowManager.LayoutParams.FLAG_FULLSCREEN);

in the onCreate method of your video activity? It might be a good starting point. This basically hides the status bar and makes my video full screen.

This is the layout I also use:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:orientation="horizontal"
              android:layout_width="fill_parent"
              android:layout_height="fill_parent"
              android:background="@color/black">

        <VideoView
            android:id="@id/videoSurface"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_centerHorizontal="true"
            android:layout_centerVertical="true"
            android:layout_centerInParent="true"
            android:layout_alignParentTop="true"
            android:layout_alignParentBottom="true"
            android:layout_alignParentLeft="true"
            android:layout_alignParentRight="true"
            android:layout_gravity="center"
            />

</RelativeLayout>

I know some of the parameters are redundant but in the end it gives me the desired effect I wanted. It might be a good starting point for you?

like image 31
devnullpointer Avatar answered Oct 24 '22 05:10

devnullpointer