diff options
author | Camil Staps | 2015-04-16 18:23:27 +0200 |
---|---|---|
committer | Camil Staps | 2015-04-16 18:23:27 +0200 |
commit | 8b2061b85722163de3b9e5f47534d7869b16239e (patch) | |
tree | c82d3bf97ed95ec4e8719146bd6dfaed3d1da8f6 /app/src/main/java/com/camilstaps/rushhour/util |
Initial commit
Diffstat (limited to 'app/src/main/java/com/camilstaps/rushhour/util')
3 files changed, 376 insertions, 0 deletions
diff --git a/app/src/main/java/com/camilstaps/rushhour/util/SystemUiHider.java b/app/src/main/java/com/camilstaps/rushhour/util/SystemUiHider.java new file mode 100644 index 0000000..e3eaf77 --- /dev/null +++ b/app/src/main/java/com/camilstaps/rushhour/util/SystemUiHider.java @@ -0,0 +1,172 @@ +package com.camilstaps.rushhour.util; + +import android.app.Activity; +import android.os.Build; +import android.view.View; + +/** + * A utility class that helps with showing and hiding system UI such as the + * status bar and navigation/system bar. This class uses backward-compatibility + * techniques described in <a href= + * "http://developer.android.com/training/backward-compatible-ui/index.html"> + * Creating Backward-Compatible UIs</a> to ensure that devices running any + * version of ndroid OS are supported. More specifically, there are separate + * implementations of this abstract class: for newer devices, + * {@link #getInstance} will return a {@link SystemUiHiderHoneycomb} instance, + * while on older devices {@link #getInstance} will return a + * {@link SystemUiHiderBase} instance. + * <p/> + * For more on system bars, see <a href= + * "http://developer.android.com/design/get-started/ui-overview.html#system-bars" + * > System Bars</a>. + * + * @see android.view.View#setSystemUiVisibility(int) + * @see android.view.WindowManager.LayoutParams#FLAG_FULLSCREEN + */ +public abstract class SystemUiHider { + /** + * 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. + * <p/> + * This flag isn't used on newer devices because the <a + * href="http://developer.android.com/design/patterns/actionbar.html">action + * bar</a>, 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; + + /** + * When this flag is set, {@link #show()} and {@link #hide()} will toggle + * the visibility of the status bar. If there is a navigation bar, show and + * hide will toggle low profile mode. + */ + public static final int FLAG_FULLSCREEN = 0x2; + + /** + * When this flag is set, {@link #show()} and {@link #hide()} will toggle + * the visibility of the navigation bar, if it's present on the device and + * the device allows hiding it. In cases where the navigation bar is present + * but cannot be hidden, show and hide will toggle low profile mode. + */ + public static final int FLAG_HIDE_NAVIGATION = FLAG_FULLSCREEN | 0x4; + + /** + * The activity associated with this UI hider object. + */ + protected Activity mActivity; + + /** + * The view on which {@link View#setSystemUiVisibility(int)} will be called. + */ + protected View mAnchorView; + + /** + * The current UI hider flags. + * + * @see #FLAG_FULLSCREEN + * @see #FLAG_HIDE_NAVIGATION + * @see #FLAG_LAYOUT_IN_SCREEN_OLDER_DEVICES + */ + protected int mFlags; + + /** + * The current visibility callback. + */ + protected OnVisibilityChangeListener mOnVisibilityChangeListener = sDummyListener; + + /** + * Creates and returns an instance of {@link SystemUiHider} that is + * appropriate for this device. The object will be either a + * {@link SystemUiHiderBase} or {@link SystemUiHiderHoneycomb} depending on + * the device. + * + * @param activity The activity whose window's system UI should be + * controlled by this class. + * @param anchorView The view on which + * {@link View#setSystemUiVisibility(int)} will be called. + * @param flags Either 0 or any combination of {@link #FLAG_FULLSCREEN}, + * {@link #FLAG_HIDE_NAVIGATION}, and + * {@link #FLAG_LAYOUT_IN_SCREEN_OLDER_DEVICES}. + */ + public static SystemUiHider getInstance(Activity activity, View anchorView, int flags) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) { + return new SystemUiHiderHoneycomb(activity, anchorView, flags); + } else { + return new SystemUiHiderBase(activity, anchorView, flags); + } + } + + protected SystemUiHider(Activity activity, View anchorView, int flags) { + mActivity = activity; + mAnchorView = anchorView; + mFlags = flags; + } + + /** + * Sets up the system UI hider. Should be called from + * {@link Activity#onCreate}. + */ + public abstract void setup(); + + /** + * Returns whether or not the system UI is visible. + */ + public abstract boolean isVisible(); + + /** + * Hide the system UI. + */ + public abstract void hide(); + + /** + * Show the system UI. + */ + public abstract void show(); + + /** + * Toggle the visibility of the system UI. + */ + public void toggle() { + if (isVisible()) { + hide(); + } else { + show(); + } + } + + /** + * Registers a callback, to be triggered when the system UI visibility + * changes. + */ + public void setOnVisibilityChangeListener(OnVisibilityChangeListener listener) { + if (listener == null) { + listener = sDummyListener; + } + + mOnVisibilityChangeListener = listener; + } + + /** + * A dummy no-op callback for use when there is no other listener set. + */ + private static OnVisibilityChangeListener sDummyListener = new OnVisibilityChangeListener() { + @Override + public void onVisibilityChange(boolean visible) { + } + }; + + /** + * 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); + } +} diff --git a/app/src/main/java/com/camilstaps/rushhour/util/SystemUiHiderBase.java b/app/src/main/java/com/camilstaps/rushhour/util/SystemUiHiderBase.java new file mode 100644 index 0000000..bc8615b --- /dev/null +++ b/app/src/main/java/com/camilstaps/rushhour/util/SystemUiHiderBase.java @@ -0,0 +1,63 @@ +package com.camilstaps.rushhour.util; + +import android.app.Activity; +import android.view.View; +import android.view.WindowManager; + +/** + * A base implementation of {@link SystemUiHider}. Uses APIs available in all + * API levels to show and hide the status bar. + */ +public class SystemUiHiderBase extends SystemUiHider { + /** + * Whether or not the system UI is currently visible. This is a cached value + * from calls to {@link #hide()} and {@link #show()}. + */ + private boolean mVisible = true; + + /** + * Constructor not intended to be called by clients. Use + * {@link SystemUiHider#getInstance} to obtain an instance. + */ + protected SystemUiHiderBase(Activity activity, View anchorView, int flags) { + super(activity, anchorView, flags); + } + + @Override + public void setup() { + if ((mFlags & FLAG_LAYOUT_IN_SCREEN_OLDER_DEVICES) == 0) { + mActivity.getWindow().setFlags( + WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN + | WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS, + WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN + | WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS); + } + } + + @Override + public boolean isVisible() { + return mVisible; + } + + @Override + public void hide() { + if ((mFlags & FLAG_FULLSCREEN) != 0) { + mActivity.getWindow().setFlags( + WindowManager.LayoutParams.FLAG_FULLSCREEN, + WindowManager.LayoutParams.FLAG_FULLSCREEN); + } + mOnVisibilityChangeListener.onVisibilityChange(false); + mVisible = false; + } + + @Override + public void show() { + if ((mFlags & FLAG_FULLSCREEN) != 0) { + mActivity.getWindow().setFlags( + 0, + WindowManager.LayoutParams.FLAG_FULLSCREEN); + } + mOnVisibilityChangeListener.onVisibilityChange(true); + mVisible = true; + } +} diff --git a/app/src/main/java/com/camilstaps/rushhour/util/SystemUiHiderHoneycomb.java b/app/src/main/java/com/camilstaps/rushhour/util/SystemUiHiderHoneycomb.java new file mode 100644 index 0000000..d689923 --- /dev/null +++ b/app/src/main/java/com/camilstaps/rushhour/util/SystemUiHiderHoneycomb.java @@ -0,0 +1,141 @@ +package com.camilstaps.rushhour.util; + +import android.annotation.TargetApi; +import android.app.Activity; +import android.os.Build; +import android.view.View; +import android.view.WindowManager; + +/** + * An API 11+ implementation of {@link SystemUiHider}. Uses APIs available in + * Honeycomb and later (specifically {@link View#setSystemUiVisibility(int)}) to + * show and hide the system UI. + */ +@TargetApi(Build.VERSION_CODES.HONEYCOMB) +public class SystemUiHiderHoneycomb extends SystemUiHiderBase { + /** + * Flags for {@link View#setSystemUiVisibility(int)} to use when showing the + * system UI. + */ + private int mShowFlags; + + /** + * Flags for {@link View#setSystemUiVisibility(int)} to use when hiding the + * system UI. + */ + private int mHideFlags; + + /** + * Flags to test against the first parameter in + * {@link android.view.View.OnSystemUiVisibilityChangeListener#onSystemUiVisibilityChange(int)} + * to determine the system UI visibility state. + */ + private int mTestFlags; + + /** + * Whether or not the system UI is currently visible. This is cached from + * {@link android.view.View.OnSystemUiVisibilityChangeListener}. + */ + private boolean mVisible = true; + + /** + * Constructor not intended to be called by clients. Use + * {@link SystemUiHider#getInstance} to obtain an instance. + */ + protected SystemUiHiderHoneycomb(Activity activity, View anchorView, int flags) { + super(activity, anchorView, flags); + + mShowFlags = View.SYSTEM_UI_FLAG_VISIBLE; + mHideFlags = View.SYSTEM_UI_FLAG_LOW_PROFILE; + mTestFlags = View.SYSTEM_UI_FLAG_LOW_PROFILE; + + if ((mFlags & FLAG_FULLSCREEN) != 0) { + // If the client requested fullscreen, add flags relevant to hiding + // the status bar. Note that some of these constants are new as of + // API 16 (Jelly Bean). It is safe to use them, as they are inlined + // at compile-time and do nothing on pre-Jelly Bean devices. + mShowFlags |= View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN; + mHideFlags |= View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN + | View.SYSTEM_UI_FLAG_FULLSCREEN; + } + + if ((mFlags & FLAG_HIDE_NAVIGATION) != 0) { + // If the client requested hiding navigation, add relevant flags. + mShowFlags |= View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION; + mHideFlags |= View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION + | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION; + mTestFlags |= View.SYSTEM_UI_FLAG_HIDE_NAVIGATION; + } + } + + /** + * {@inheritDoc} + */ + @Override + public void setup() { + mAnchorView.setOnSystemUiVisibilityChangeListener(mSystemUiVisibilityChangeListener); + } + + /** + * {@inheritDoc} + */ + @Override + public void hide() { + mAnchorView.setSystemUiVisibility(mHideFlags); + } + + /** + * {@inheritDoc} + */ + @Override + public void show() { + mAnchorView.setSystemUiVisibility(mShowFlags); + } + + /** + * {@inheritDoc} + */ + @Override + public boolean isVisible() { + return mVisible; + } + + private View.OnSystemUiVisibilityChangeListener mSystemUiVisibilityChangeListener + = new View.OnSystemUiVisibilityChangeListener() { + @Override + public void onSystemUiVisibilityChange(int vis) { + // Test against mTestFlags to see if the system UI is visible. + if ((vis & mTestFlags) != 0) { + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) { + // Pre-Jelly Bean, we must manually hide the action bar + // and use the old window flags API. + mActivity.getActionBar().hide(); + mActivity.getWindow().setFlags( + WindowManager.LayoutParams.FLAG_FULLSCREEN, + WindowManager.LayoutParams.FLAG_FULLSCREEN); + } + + // Trigger the registered listener and cache the visibility + // state. + mOnVisibilityChangeListener.onVisibilityChange(false); + mVisible = false; + + } else { + mAnchorView.setSystemUiVisibility(mShowFlags); + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) { + // Pre-Jelly Bean, we must manually show the action bar + // and use the old window flags API. + mActivity.getActionBar().show(); + mActivity.getWindow().setFlags( + 0, + WindowManager.LayoutParams.FLAG_FULLSCREEN); + } + + // Trigger the registered listener and cache the visibility + // state. + mOnVisibilityChangeListener.onVisibilityChange(true); + mVisible = true; + } + } + }; +} |