From 34e13d90eda9bfda7a70998d190a95c88aa3d3d1 Mon Sep 17 00:00:00 2001 From: John Spurlock Date: Sat, 10 Aug 2013 06:52:28 -0400 Subject: [PATCH] Update transient navigation confirmation logic. Show the confirmation toast when hiding the transient navigation bar only the first time per app, per reboot. Hitting the power key while the transient nav is hidden is taken as a signal of possible user confusion, so reshow the prompt the next time. This requires the confirmation prompt to live in policy (not sysui). It arguably should have been here in the first place, since the transient bar state/policy was here, and sysui should not have not been able to fail to display the prompt correctly. Also take this opportunity to remove a hack wrt positioning the confirmation properly while the nav bar is transitioning. Toasts now support LAYOUT_HIDE_NAVIGATION if applied to the toast's view. Bug: 10246225 Change-Id: Ieb6355e4ca975c0758918a39e3c2ec13da81c7f4 --- .../res}/res/values-land/refs.xml | 4 +- .../res}/res/values-sw600dp-port/refs.xml | 4 +- core/res/res/values/strings.xml | 5 + core/res/res/values/symbols.xml | 2 + packages/SystemUI/res/values/strings.xml | 6 - .../statusbar/phone/PhoneStatusBar.java | 85 +------------- .../systemui/statusbar/policy/Prefs.java | 2 - .../policy/impl/PhoneWindowManager.java | 38 ++++-- .../impl/TransientNavigationConfirmation.java | 110 ++++++++++++++++++ 9 files changed, 149 insertions(+), 107 deletions(-) rename {packages/SystemUI => core/res}/res/values-land/refs.xml (82%) rename {packages/SystemUI => core/res}/res/values-sw600dp-port/refs.xml (82%) create mode 100644 policy/src/com/android/internal/policy/impl/TransientNavigationConfirmation.java diff --git a/packages/SystemUI/res/values-land/refs.xml b/core/res/res/values-land/refs.xml similarity index 82% rename from packages/SystemUI/res/values-land/refs.xml rename to core/res/res/values-land/refs.xml index 62fb77dad59c0..cda38cf2f2a40 100644 --- a/packages/SystemUI/res/values-land/refs.xml +++ b/core/res/res/values-land/refs.xml @@ -16,5 +16,5 @@ */ --> - @string/hiding_navigation_confirmation_message_long - + @string/transient_navigation_confirmation_long + \ No newline at end of file diff --git a/packages/SystemUI/res/values-sw600dp-port/refs.xml b/core/res/res/values-sw600dp-port/refs.xml similarity index 82% rename from packages/SystemUI/res/values-sw600dp-port/refs.xml rename to core/res/res/values-sw600dp-port/refs.xml index 62fb77dad59c0..cda38cf2f2a40 100644 --- a/packages/SystemUI/res/values-sw600dp-port/refs.xml +++ b/core/res/res/values-sw600dp-port/refs.xml @@ -16,5 +16,5 @@ */ --> - @string/hiding_navigation_confirmation_message_long - + @string/transient_navigation_confirmation_long + \ No newline at end of file diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml index 138debf06f98c..e497c85c87965 100644 --- a/core/res/res/values/strings.xml +++ b/core/res/res/values/strings.xml @@ -4313,4 +4313,9 @@ Incorrect PIN. Try again in %d seconds. + + Swipe edge of screen to reveal bar + + + Swipe from edge of screen to reveal system bar diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index 2e05663207345..cd0c872daac91 100755 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -870,6 +870,8 @@ + + diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml index 33a85c3a8ed6a..eec81778ed51f 100644 --- a/packages/SystemUI/res/values/strings.xml +++ b/packages/SystemUI/res/values/strings.xml @@ -503,10 +503,4 @@ Notifications appear here Access them anytime by swiping down.\nSwipe down again for system controls. - - - Swipe edge of screen to reveal bar - - - Swipe from edge of screen to reveal system bar diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java index c914a340c63a8..0a09a5236fc69 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java @@ -57,7 +57,6 @@ import android.view.Gravity; import android.view.MotionEvent; import android.view.VelocityTracker; import android.view.View; -import android.view.View.MeasureSpec; import android.view.ViewGroup; import android.view.ViewGroup.LayoutParams; import android.view.ViewPropertyAnimator; @@ -72,7 +71,7 @@ import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.ScrollView; import android.widget.TextView; -import android.widget.Toast; + import com.android.internal.statusbar.StatusBarIcon; import com.android.systemui.EventLogTags; import com.android.systemui.R; @@ -129,8 +128,6 @@ public class PhoneStatusBar extends BaseStatusBar { private static final int STATUS_OR_NAV_TRANSIENT = View.STATUS_BAR_TRANSIENT | View.NAVIGATION_BAR_TRANSIENT; - private static final int TRANSIENT_NAV_HIDING = - View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_ALLOW_TRANSIENT; private static final long AUTOHIDE_TIMEOUT_MS = 3000; private static final float TRANSPARENT_ALPHA = 0.7f; @@ -314,37 +311,6 @@ public class PhoneStatusBar extends BaseStatusBar { } }; - private Toast mHidingNavigationConfirmation; - private boolean mHidingNavigationConfirmationDismissed; - - private final View.OnTouchListener mDismissHidingNavigationConfirmationOnTouchOutside = - new View.OnTouchListener() { - @Override - public boolean onTouch(View v, MotionEvent event) { - if (event.getActionMasked() == MotionEvent.ACTION_OUTSIDE) { - dismissHidingNavigationConfirmation(); - } - return false; - } - }; - - private final Runnable mHidingNavigationConfirmationAction = new Runnable() { - @Override - public void run() { - if (mHidingNavigationConfirmation != null) { - final boolean isGloballyConfirmed = Prefs.read(mContext) - .getBoolean(Prefs.HIDING_NAVIGATION_CONFIRMED, false); - if (!isGloballyConfirmed) { - // user pressed button, consider this a confirmation - Prefs.edit(mContext) - .putBoolean(Prefs.HIDING_NAVIGATION_CONFIRMED, true) - .apply(); - } - dismissHidingNavigationConfirmation(); - } - } - }; - private boolean mAutohideSuspended; private final Runnable mAutohide = new Runnable() { @@ -1955,16 +1921,6 @@ public class PhoneStatusBar extends BaseStatusBar { } } - // update hiding navigation confirmation - if (mNavigationBarView != null) { - boolean oldShowConfirm = (oldVal & TRANSIENT_NAV_HIDING) == TRANSIENT_NAV_HIDING; - boolean newShowConfirm = (newVal & TRANSIENT_NAV_HIDING) == TRANSIENT_NAV_HIDING; - if (!oldShowConfirm && newShowConfirm) { - mHidingNavigationConfirmationDismissed = false; - } - setHidingNavigationConfirmationVisible(newShowConfirm); - } - // send updated sysui visibility to window manager notifyUiVisibilityChanged(mSystemUiVisibility); } @@ -1987,45 +1943,6 @@ public class PhoneStatusBar extends BaseStatusBar { : BAR_MODE_NORMAL; } - private void dismissHidingNavigationConfirmation() { - if (mHidingNavigationConfirmation != null) { - mHidingNavigationConfirmationDismissed = true; - mHidingNavigationConfirmation.cancel(); - mHidingNavigationConfirmation = null; - } - } - - private void setHidingNavigationConfirmationVisible(boolean visible) { - if (DEBUG) Log.d(TAG, "setHidingNavigationConfirmationVisible " + visible); - if (visible && - mHidingNavigationConfirmation == null && !mHidingNavigationConfirmationDismissed) { - // create the confirmation toast bar - int msg = R.string.hiding_navigation_confirmation_message; - mHidingNavigationConfirmation = Toast.makeBar(mContext, msg, Toast.LENGTH_INFINITE) - .setAction(com.android.internal.R.string.ok, - mHidingNavigationConfirmationAction); - View v = mHidingNavigationConfirmation.getView(); - v.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION); - boolean isGloballyConfirmed = Prefs.read(mContext) - .getBoolean(Prefs.HIDING_NAVIGATION_CONFIRMED, false); - if (isGloballyConfirmed) { - // dismiss on outside touch if globally confirmed - v.setOnTouchListener(mDismissHidingNavigationConfirmationOnTouchOutside); - } - // position at the bottom like normal toasts, but use top gravity - // to avoid jumping around when showing/hiding the nav bar - v.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED); - int offsetY = mContext.getResources().getDimensionPixelSize( - com.android.internal.R.dimen.toast_y_offset); - mHidingNavigationConfirmation.setGravity(Gravity.TOP, - 0, mCurrentDisplaySize.y - v.getMeasuredHeight() / 2 - offsetY); - // show the confirmation - mHidingNavigationConfirmation.show(); - } else if (!visible) { - dismissHidingNavigationConfirmation(); - } - } - @Override public void resumeAutohide() { if (mAutohideSuspended) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/Prefs.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/Prefs.java index 3d51f209798df..16a92ea8e3f87 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/Prefs.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/Prefs.java @@ -25,8 +25,6 @@ public class Prefs { public static final String SHOWN_COMPAT_MODE_HELP = "shown_compat_mode_help"; public static final String SHOWN_QUICK_SETTINGS_HELP = "shown_quick_settings_help"; - public static final String HIDING_NAVIGATION_CONFIRMED = "hiding_navigation_confirmed"; - public static SharedPreferences read(Context context) { return context.getSharedPreferences(Prefs.SHARED_PREFS_NAME, Context.MODE_PRIVATE); } diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java index ae7120f6c72a0..952dfdaf10a42 100644 --- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java +++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java @@ -558,6 +558,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { private static final int TRANSIENT_BAR_HIDING = 2; private int mStatusTransientBar; private int mNavigationTransientBar; + private TransientNavigationConfirmation mTransientNavigationConfirmation; private SystemGesturesPointerEventListener mSystemGestures; @@ -942,6 +943,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { } } }); + mTransientNavigationConfirmation = new TransientNavigationConfirmation(mContext, mHandler); mWindowManagerFuncs.registerPointerEventListener(mSystemGestures); mVibrator = (Vibrator)context.getSystemService(Context.VIBRATOR_SERVICE); @@ -3173,11 +3175,12 @@ public class PhoneWindowManager implements WindowManagerPolicy { = mOverscanScreenTop + mOverscanScreenHeight; } else if (mCanHideNavigationBar && (sysUiFl & View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION) != 0 - && attrs.type >= WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW - && attrs.type <= WindowManager.LayoutParams.LAST_SUB_WINDOW) { + && (attrs.type == TYPE_TOAST + || (attrs.type >= WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW + && attrs.type <= WindowManager.LayoutParams.LAST_SUB_WINDOW))) { // Asking for layout as if the nav bar is hidden, lets the // application extend into the unrestricted screen area. We - // only do this for application windows to ensure no window that + // only do this for application windows (or toasts) to ensure no window that // can be above the nav bar can do this. // XXX This assumes that an app asking for this will also // ask for layout in only content. We can't currently figure out @@ -3879,6 +3882,9 @@ public class PhoneWindowManager implements WindowManagerPolicy { case KeyEvent.KEYCODE_POWER: { result &= ~ACTION_PASS_TO_USER; if (down) { + if (isScreenOn && isNavigationBarTransient(mLastSystemUiFlags)) { + mTransientNavigationConfirmation.unconfirmLastPackage(); + } if (isScreenOn && !mPowerKeyTriggered && (event.getFlags() & KeyEvent.FLAG_FALLBACK) == 0) { mPowerKeyTriggered = true; @@ -5019,7 +5025,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { if (mForcingShowNavBar && mFocusedWindow.getSurfaceLayer() < mForcingShowNavBarLayer) { tmpVisibility &= ~View.SYSTEM_UI_CLEARABLE_FLAGS; } - final int visibility = updateTransientBarsLw(tmpVisibility); + final int visibility = updateTransientBarsLw(mLastSystemUiFlags, tmpVisibility); final int diff = visibility ^ mLastSystemUiFlags; final boolean needsMenu = mFocusedWindow.getNeedsMenuLw(mTopFullscreenOpaqueWindowState); if (diff == 0 && mLastFocusNeedsMenu == needsMenu @@ -5047,7 +5053,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { return diff; } - private int updateTransientBarsLw(int vis) { + private int updateTransientBarsLw(int oldVis, int vis) { if (ImmersiveModeTesting.enabled) { vis = ImmersiveModeTesting.applyForced(mFocusedWindow, vis); } @@ -5059,9 +5065,10 @@ public class PhoneWindowManager implements WindowManagerPolicy { | View.SYSTEM_UI_FLAG_ALLOW_TRANSIENT; vis = (vis & ~flags) | (mLastSystemUiFlags & flags); } - boolean transientAllowed = (vis & View.SYSTEM_UI_FLAG_ALLOW_TRANSIENT) != 0; if (mStatusTransientBar == TRANSIENT_BAR_SHOWING) { // status transient bar requested + boolean transientAllowed = + (vis & View.SYSTEM_UI_FLAG_ALLOW_TRANSIENT) != 0; boolean hideStatusBarWM = (mFocusedWindow.getAttrs().flags & WindowManager.LayoutParams.FLAG_FULLSCREEN) != 0; @@ -5092,13 +5099,16 @@ public class PhoneWindowManager implements WindowManagerPolicy { } } } + boolean oldTransientNav = isNavigationBarTransient(oldVis); + boolean isTransientNav = isNavigationBarTransient(vis); + if (mFocusedWindow != null && oldTransientNav != isTransientNav) { + final int uid = getCurrentUserId(); + final String pkg = mFocusedWindow.getOwningPackage(); + mTransientNavigationConfirmation.transientNavigationChanged(uid, pkg, isTransientNav); + } if (mNavigationTransientBar == TRANSIENT_BAR_SHOWING) { // navigation transient bar requested - boolean hideNavigationBarSysui = - (vis & View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) != 0; - boolean transientNavigationBarAllowed = - mNavigationBar != null && hideNavigationBarSysui && transientAllowed; - if (!transientNavigationBarAllowed) { + if (!isTransientNav) { mNavigationTransientBar = TRANSIENT_BAR_NONE; } else { // show navigation transient bar @@ -5112,6 +5122,12 @@ public class PhoneWindowManager implements WindowManagerPolicy { return vis; } + private boolean isNavigationBarTransient(int vis) { + return mNavigationBar != null + && (vis & View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) != 0 + && (vis & View.SYSTEM_UI_FLAG_ALLOW_TRANSIENT) != 0; + } + private boolean setBarShowingLw(WindowState win, final boolean show) { final int window = win == mStatusBar ? StatusBarManager.WINDOW_STATUS_BAR diff --git a/policy/src/com/android/internal/policy/impl/TransientNavigationConfirmation.java b/policy/src/com/android/internal/policy/impl/TransientNavigationConfirmation.java new file mode 100644 index 0000000000000..bd5bd80de45a5 --- /dev/null +++ b/policy/src/com/android/internal/policy/impl/TransientNavigationConfirmation.java @@ -0,0 +1,110 @@ +/* + * Copyright (C) 2013 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.android.internal.policy.impl; + +import android.content.Context; +import android.os.Handler; +import android.util.ArraySet; +import android.util.Slog; +import android.view.View; +import android.widget.Toast; + +import com.android.internal.R; + +/** + * Helper to manage showing/hiding a confirmation prompt when the transient navigation bar + * is hidden. + */ +public class TransientNavigationConfirmation { + private final String TAG = "TransientNavigationConfirmation"; + private final boolean DEBUG = false; + + private final Context mContext; + private final Handler mHandler; + private final ArraySet mConfirmedUserPackages = new ArraySet(); + + private final Runnable mHandleDismiss = new Runnable() { + @Override + public void run() { + if (mToast != null) { + mToast.cancel(); + mToast = null; + } + } + }; + + private Toast mToast; + private String mLastUserPackage; + + public TransientNavigationConfirmation(Context context, Handler handler) { + mContext = context; + mHandler = handler; + } + + public void transientNavigationChanged(int userId, String pkg, boolean isNavTransient) { + if (pkg == null) { + return; + } + String userPkg = userId + ":" + pkg; + if (isNavTransient) { + mLastUserPackage = userPkg; + if (!mConfirmedUserPackages.contains(userPkg)) { + if (DEBUG) Slog.d(TAG, "Showing transient navigation confirmation for " + userPkg); + mHandler.post(handleShowConfirmation(userPkg)); + } + } else { + mLastUserPackage = null; + if (DEBUG) Slog.d(TAG, "Hiding transient navigation confirmation for " + userPkg); + mHandler.post(mHandleDismiss); + } + } + + public void unconfirmLastPackage() { + if (mLastUserPackage != null) { + if (DEBUG) Slog.d(TAG, "Unconfirming transient navigation for " + mLastUserPackage); + mConfirmedUserPackages.remove(mLastUserPackage); + } + } + + private Runnable handleShowConfirmation(final String userPkg) { + return new Runnable() { + @Override + public void run() { + // create the confirmation toast bar + final int msg = R.string.transient_navigation_confirmation; + mToast = Toast.makeBar(mContext, msg, Toast.LENGTH_INFINITE); + mToast.setAction(R.string.ok, confirmAction(userPkg)); + + // we will be hiding the nav bar, so layout as if it's already hidden + mToast.getView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION); + + // show the confirmation + mToast.show(); + } + }; + } + + private Runnable confirmAction(final String userPkg) { + return new Runnable() { + @Override + public void run() { + mConfirmedUserPackages.add(userPkg); + mHandleDismiss.run(); + } + }; + } +}