1

I'm working on my first Android app. It's designed to be immersive, and hides the NavigationBar on all activites, while providing its own internal navigation through the ActionBar.

I am committed to using the default MediaController view for this app. I'm using android.widget.MediaController as a MediaController for a fullscreen video activity via android.widget.VideoView. I'm also using an extension of android.widget.MediaController which implements MediaController.MediaPlayerControl for a non-full screen audio activity via android.media.MediaPlayer.

After investigating the android.widget.MediaController source, it displays itself as a FrameLayout in a new window, on top of the current activity. Whenever the MediaController is to be shown, it adds itself to the window with a specific set of layout parameters through a call to mWindowManager.addView(mDecor, mDecorLayoutParams); below.

public void show(int timeout) {
    if (!mShowing && mAnchor != null) {
        setProgress();
        if (mPauseButton != null) {
            mPauseButton.requestFocus();
        }
        disableUnsupportedButtons();
        updateFloatingWindowLayout();
        mWindowManager.addView(mDecor, mDecorLayoutParams);
        mShowing = true;
    }
    updatePausePlay();

    // cause the progress bar to be updated even if mShowing
    // was already true.  This happens, for example, if we're
    // paused with the progress bar showing the user hits play.
    post(mShowProgress);

    if (timeout != 0 && !mAccessibilityManager.isTouchExplorationEnabled()) {
        removeCallbacks(mFadeOut);
        postDelayed(mFadeOut, timeout);
    }
}

The result of this call is that the SystemUiVisibility is reset for this window, and the app comes out of immersive mode, showing the NavigationBar.

The problem I have is that every variable of this class is private, as are most methods. There are zero getters or setters for any of the private variables. So, I can't change the show method's interaction with its variables.

While extending the MediaController class, I can only override the show method to immediately call hideNavigation. However, the NavigationBar still briefly appears on screen each time the controller is shown! This isn't a solution I am comfortable with.

// MediaController implementation
@Override
public void show(int timeout) {
    super.show(timeout);

    // hide navigation
    hideNavigation();
}

// hide navigation
public void hideNavigation() {

    // get root view
    View rootView = this.getRootView();

    // options
    final int options =
        View.SYSTEM_UI_FLAG_LAYOUT_STABLE |
        View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION |
        View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN |
        View.SYSTEM_UI_FLAG_HIDE_NAVIGATION |
        View.SYSTEM_UI_FLAG_FULLSCREEN |
        View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
    ;

    // set visibility options
    rootView.setSystemUiVisibility(options);
}

So, given that I can't extend the class properly, due to its private design, I would like to entirely replace it with my own, using most of the code from the original, just with protected variables and methods instead of private ones.

The problem with this approach is that I can't add import com.android.internal.policy.PhoneWindow; to my Android Studio project. How can I include this package in my Gradle build?

compile 'com.android.internal.policy:phonewindow:1.0'

What do I need to change to make this work? Or, is it just not possible?

Additionally, I can see that a call to the getInstance(Context context) method of android.view.accessibility.AccessibilityManager is not recognized, so that will also prevent me from replicating this class.

Why is this method not available?

If there's some other way to forcibly prevent windows from changing their SystemUiVisibility options, or some other way to extend the show method without reproducing the entire class, that would be preferable!

Any guidance would be appreciated.

Phantômaxx
  • 37,901
  • 21
  • 84
  • 115
j.h.
  • 11
  • 2

1 Answers1

0

I'm facing the same issue right now.. I want to make changes to the MediaController class.

I though that there was a bug in the class cause it would not import PhoneWindow, and that getInstance(context) threw errors, but now I see that this is a way to protect the code.

I found this answer on stackoverflow:

As com.android.internal.telefony falls under internal(or hidden) APIs of Android, you can't directly import it. But there are ways to work with them. I'd suggest you to go over this and this to get an idea on how to work with telephony through reflection.

This is not about the PhoneWindow class but I think it would be possible to do something similar with this class. I have not tried this, but maybe you can?

Paal Pedersen
  • 1,070
  • 1
  • 10
  • 13