SystemUiHelper

July 31, 2015 ยท View on GitHub

/*

  • Copyright (C) 2014 The Android Open Source Project
  • Licensed under the Apache License, Version 2.0 (the "License");
  • you may not use this file except in compliance with the License.
  • You may obtain a copy of the License at
  •  http://www.apache.org/licenses/LICENSE-2.0
    
  • Unless required by applicable law or agreed to in writing, software
  • distributed under the License is distributed on an "AS IS" BASIS,
  • WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  • See the License for the specific language governing permissions and
  • limitations under the License. */

package com.example.android.systemuivis;

import android.app.Activity; import android.os.Build; import android.os.Handler; import android.os.Looper; import android.view.WindowManager;

/**

  • Helper for controlling the visibility of the System UI across the various API levels. To use

  • this API, instantiate an instance of this class with the required level. The level specifies the

  • extent to which the System UI's visibility is changed when you call {@link #hide()}

  • or {@link #toggle()}. */ public final class SystemUiHelper {

    /**

    • In this level, the helper will toggle low profile mode. */ public static final int LEVEL_LOW_PROFILE = 0;

    /**

    • In this level, the helper will toggle the visibility of the status bar.
    • If there is a navigation bar, it will toggle low profile mode. */ public static final int LEVEL_HIDE_STATUS_BAR = 1;

    /**

    • In this level, the helper will toggle the visibility of the navigation bar
    • (if present and if possible) and status bar. In cases where the navigation
    • bar is present but cannot be hidden, it will toggle low profile mode. */ public static final int LEVEL_LEAN_BACK = 2;

    /**

    • In this level, the helper will toggle the visibility of the navigation bar
    • (if present and if possible) and status bar, in an immersive mode. This means that the app
    • will continue to receive all touch events. The user can reveal the system bars with an
    • inward swipe along the region where the system bars normally appear.
    • The {@link #FLAG_IMMERSIVE_STICKY} flag can be used to control how the system bars are

    • displayed. */ public static final int LEVEL_IMMERSIVE = 3;

    /**

    • When this flag is set, the
    • {@link android.view.WindowManager.LayoutParams#FLAG_LAYOUT_IN_SCREEN}
    • flag will be set on older devices, making the status bar "float" on top
    • of the activity layout. This is most useful when there are no controls at
    • the top of the activity layout.
    • This flag isn't used on newer devices because the <a
    • href="http://developer.android.com/design/patterns/actionbar.html">action
    • bar, the most important structural element of an Android app, should
    • be visible and not obscured by the system UI. */ public static final int FLAG_LAYOUT_IN_SCREEN_OLDER_DEVICES = 0x1;

    /**

    • Used with {@link #LEVEL_IMMERSIVE}. When this flag is set, an inward swipe in the system
    • bars areas will cause the system bars to temporarily appear in a semi-transparent state,
    • but no flags are cleared, and your system UI visibility change listeners are not triggered.
    • The bars automatically hide again after a short delay, or if the user interacts with the
    • middle of the screen. */ public static final int FLAG_IMMERSIVE_STICKY = 0x2;

    private static final String LOG_TAG = SystemUiHelper.class.getSimpleName();

    private final SystemUiHelperImpl mImpl;

    private final Handler mHandler; private final Runnable mHideRunnable;

    /**

    • Construct a new SystemUiHelper.
    • @param activity The Activity who's system UI should be changed
    • @param level The level of hiding. Should be either {@link #LEVEL_LOW_PROFILE},
    •          {@link #LEVEL_HIDE_STATUS_BAR}, {@link #LEVEL_LEAN_BACK} or
      
    •          {@link #LEVEL_IMMERSIVE}
      
    • @param flags Additional options. See {@link #FLAG_LAYOUT_IN_SCREEN_OLDER_DEVICES} and
    •          {@link #FLAG_IMMERSIVE_STICKY}
      

    */ public SystemUiHelper(Activity activity, int level, int flags) { this(activity, level, flags, null); }

    /**

    • Construct a new SystemUiHelper.

    • @param activity The Activity who's system UI should be changed

    • @param level The level of hiding. Should be either {@link #LEVEL_LOW_PROFILE},

    •          {@link #LEVEL_HIDE_STATUS_BAR}, {@link #LEVEL_LEAN_BACK} or
      
    •          {@link #LEVEL_IMMERSIVE}
      
    • @param flags Additional options. See {@link #FLAG_LAYOUT_IN_SCREEN_OLDER_DEVICES} and

    •          {@link #FLAG_IMMERSIVE_STICKY}
      
    • @param listener A listener which is called when the system visibility is changed */ public SystemUiHelper(Activity activity, int level, int flags, OnVisibilityChangeListener listener) {

      mHandler = new Handler(Looper.getMainLooper()); mHideRunnable = new HideRunnable();

      // Create impl if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { mImpl = new SystemUiHelperImplKK(activity, level, flags, listener); } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { mImpl = new SystemUiHelperImplJB(activity, level, flags, listener); } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) { mImpl = new SystemUiHelperImplICS(activity, level, flags, listener); } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) { mImpl = new SystemUiHelperImplHC(activity, level, flags, listener); } else { mImpl = new SystemUiHelperImplBase(activity, level, flags, listener); } }

    /**

    • @return true if the system UI is currently showing. What this means depends on the mode this
    •     {@link android.example.android.systemuivis.SystemUiHelper} was instantiated with.
      

    */ public boolean isShowing() { return mImpl.isShowing(); }

    /**

    • Show the system UI. What this means depends on the mode this {@link android.example.android.systemuivis.SystemUiHelper} was
    • instantiated with.
    • Any currently queued delayed hide requests will be removed.

    */ public void show() { // Ensure that any currently queued hide calls are removed removeQueuedRunnables();

     mImpl.show();
    

    }

    /**

    • Hide the system UI. What this means depends on the mode this {@link android.example.android.systemuivis.SystemUiHelper} was
    • instantiated with.
    • Any currently queued delayed hide requests will be removed.

    */ public void hide() { // Ensure that any currently queued hide calls are removed removeQueuedRunnables();

     mImpl.hide();
    

    }

    /**

    • Request that the system UI is hidden after a delay.
    • Any currently queued delayed hide requests will be removed.

    • @param delayMillis The delay (in milliseconds) until the Runnable
    •    will be executed.
      

    */ public void delayHide(long delayMillis) { // Ensure that any currently queued hide calls are removed removeQueuedRunnables();

     mHandler.postDelayed(mHideRunnable, delayMillis);
    

    }

    /**

    • Toggle whether the system UI is displayed. */ public void toggle() { if (mImpl.isShowing()) { mImpl.hide(); } else { mImpl.show(); } }

    private void removeQueuedRunnables() { // Ensure that any currently queued hide calls are removed mHandler.removeCallbacks(mHideRunnable); }

    /**

    • A callback interface used to listen for system UI visibility changes. / public interface OnVisibilityChangeListener { /*
      • Called when the system UI visibility has changed.
      • @param visible True if the system UI is visible. */ public void onVisibilityChange(boolean visible); }

    static abstract class SystemUiHelperImpl {

     final Activity mActivity;
     final int mLevel;
     final int mFlags;
     final OnVisibilityChangeListener mOnVisibilityChangeListener;
    
     boolean mIsShowing = true;
    
     SystemUiHelperImpl(Activity activity, int level, int flags,
             OnVisibilityChangeListener onVisibilityChangeListener) {
         mActivity = activity;
         mLevel = level;
         mFlags = flags;
         mOnVisibilityChangeListener = onVisibilityChangeListener;
     }
    
     abstract void show();
     abstract void hide();
    
     boolean isShowing() {
         return mIsShowing;
     }
    
     void setIsShowing(boolean isShowing) {
         mIsShowing = isShowing;
    
         if (mOnVisibilityChangeListener != null) {
             mOnVisibilityChangeListener.onVisibilityChange(mIsShowing);
         }
     }
    

    }

    /**

    • Base implementation. Used on API level 10 and below. */ static class SystemUiHelperImplBase extends SystemUiHelperImpl {

      SystemUiHelperImplBase(Activity activity, int level, int flags, OnVisibilityChangeListener onVisibilityChangeListener) { super(activity, level, flags, onVisibilityChangeListener);

       if ((mFlags & SystemUiHelper.FLAG_LAYOUT_IN_SCREEN_OLDER_DEVICES) != 0) {
           mActivity.getWindow().addFlags(
                   WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
                           | WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS);
       }
      

      }

      @Override void show() { if (mLevel > SystemUiHelper.LEVEL_LOW_PROFILE) { mActivity.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN); setIsShowing(true); } }

      @Override void hide() { if (mLevel > SystemUiHelper.LEVEL_LOW_PROFILE) { mActivity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN); setIsShowing(false); } } }

    private class HideRunnable implements Runnable { @Override public void run() { hide(); } }

}