Search code examples
androiduser-interfaceandroid-studioandroid-5.0-lollipopfullscreen

Android 5.0, prevent status bar expansion


This is a very old problem, but after making so much effort, I still cannot figure out a possible solution.

The Aim

Actually quite simple. I would like to develop some full screen apps (e.g. games), where the status bar does not expand, however the user touches the screen.

The app should be able to work on Android 5.0, sdk 21 (Lollipop).

What I have done so far

I find this post, which describes how to cover the status bar with a CustomView that absorbs touch events, but it doesn't work for me ...

I even changed the size of the CustomView so that it covers the whole screen, but it still doesn't work, and it cannot even cover my button.

The codes I use are attached below. When run on the device, both the button and the status bar work - nothing is blocked.

Am I missing something?

Codes

In AndroidManifest.xml:

<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>

<application
    android:allowBackup="true"
    android:icon="@mipmap/ic_launcher"
    android:supportsRtl="true"
    android:theme="@android:style/Theme.Holo.NoActionBar.Fullscreen">
    <activity android:name=".MainActivity">
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />

            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
    </activity>
</application>

In activity_main.xml:

<TextView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="Hello World!"
    android:id="@+id/text_show" />

<Button
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="Click"
    android:id="@+id/button_click"
    android:onClick="changeText"
    android:layout_centerVertical="true"
    android:layout_centerHorizontal="true" />

In MainActivity.java:

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    WindowManager manager = ((WindowManager) getApplicationContext()
            .getSystemService(Context.WINDOW_SERVICE));
    WindowManager.LayoutParams localLayoutParams = new WindowManager.LayoutParams();
    localLayoutParams.type = WindowManager.LayoutParams.TYPE_SYSTEM_ERROR;
    localLayoutParams.gravity = Gravity.TOP;
    localLayoutParams.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE|
            // this is to enable the notification to recieve touch events
            WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL |
            // Draws over status bar
            WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;
    localLayoutParams.width = WindowManager.LayoutParams.MATCH_PARENT;
    localLayoutParams.height = (int) (50 * getResources()
            .getDisplayMetrics().scaledDensity);
    localLayoutParams.format = PixelFormat.TRANSPARENT;
    CustomViewGroup view = new CustomViewGroup(this);
    manager.addView(view, localLayoutParams);
    setContentView(R.layout.activity_main);
}
boolean key = false;
public void changeText(View view) {
    TextView tv = (TextView) findViewById(R.id.text_show);
    if (key) {
        tv.setText("hahaha");
    } else {
        tv.setText("eroero");
    }
    key = ! key;
}

In CustomViewGroup (copied from the above link):

public class CustomViewGroup extends ViewGroup {
    public CustomViewGroup(Context context) {
        super(context);
    }
    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
    }
    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        Log.v("CustomViewGroup", "**********Intercepted");
        return true;
    }
}

Solution

  • Finally the best I can do is to use the Task Lock feature introduced in Android 5.0.

    Reference: startLockTask.

    The issues of this method:

    1. Unless you have a helper app that grant lock task permission to your full screen app, the user will be asked if (s)he allows the lock.
    2. Once locked, the user can still use physical buttons (home, back, volumn, etc.).

    Since my intention is not to have a kiosk mode, I don't really care about point 2.

    Point 1 is also acceptable, but a bit annoying since it will (and should) be asked every time onResume is called.

    This can be solved by setting a service app as device owner, which grants permission to apps that demand it. But the user has to do this him(her)self (c.f. this answer), which is reasonable, otherwise an app would be able to totally kidnap your device.