Update transient navigation confirmation wording & behavior

1. Decrease transient navigation confirmation annoyance.

  - Only use the power-key as a signal if we detect a screen-off
    screen-on within a short threshold value.

 - Auto-confirm if user performs the indicated gesture.

 - Remember confirmation across reboots.

2. Update wording to new final wording.  Remove now obsolete
short + long versions.  Decrease message font temporarily
until the new platform toast redesign is finalized.

3. Remove pre-ship ImmersiveModeTesting debug helper.

Bug:10602929
Change-Id: I0bff826391058c7b282eeb61817b93b79de84893
This commit is contained in:
John Spurlock
2013-09-05 11:31:54 -04:00
parent 6421aa061a
commit d67ec25a9c
9 changed files with 106 additions and 129 deletions

View File

@@ -4365,6 +4365,9 @@ public final class Settings {
/** @hide */
public static final String BAR_SERVICE_COMPONENT = "bar_service_component";
/** @hide */
public static final String TRANSIENT_NAV_CONFIRMATIONS = "transient_nav_confirmations";
/**
* This are the settings to be backed up.
*

View File

@@ -35,7 +35,7 @@
android:paddingRight="16dp"
android:singleLine="true"
android:textColor="@android:color/white"
android:textSize="16sp" />
android:textSize="14sp" />
<LinearLayout
android:id="@android:id/button1"

View File

@@ -1,20 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
* 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.
*/
-->
<resources>
<item type="string" name="transient_navigation_confirmation">@string/transient_navigation_confirmation_long</item>
</resources>

View File

@@ -1,20 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
* 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.
*/
-->
<resources>
<item type="string" name="transient_navigation_confirmation">@string/transient_navigation_confirmation_long</item>
</resources>

View File

@@ -1241,4 +1241,8 @@
To do this, add 21407 item to values-mcc214-mnc04/config.xml -->
<string-array translatable="false" name="config_operatorConsideredNonRoaming">
</string-array>
<!-- Threshold (in ms) under which a screen off / screen on will be considered a reset of the
transient navigation confirmation prompt.-->
<integer name="config_transient_navigation_confirmation_panic">5000</integer>
</resources>

View File

@@ -4344,9 +4344,7 @@
<!-- PIN entry dialog tells the user to not enter a PIN for a while. [CHAR LIMIT=none] -->
<string name="restr_pin_try_later">Try again later</string>
<!-- Toast bar message when hiding the transient navigation bar [CHAR LIMIT=35] -->
<string name="transient_navigation_confirmation">Swipe edge of screen to reveal bar</string>
<!-- Toast bar message when hiding the transient navigation bar [CHAR LIMIT=45] -->
<string name="transient_navigation_confirmation">Swipe down from the top to exit full screen</string>
<!-- Longer version of toast bar message when hiding the transient navigation bar (if room) -->
<string name="transient_navigation_confirmation_long">Swipe from edge of screen to reveal system bar</string>
</resources>

View File

@@ -301,6 +301,7 @@
<java-symbol type="integer" name="config_ntpThreshold" />
<java-symbol type="integer" name="config_ntpTimeout" />
<java-symbol type="integer" name="config_toastDefaultGravity" />
<java-symbol type="integer" name="config_transient_navigation_confirmation_panic" />
<java-symbol type="integer" name="config_wifi_framework_scan_interval" />
<java-symbol type="integer" name="config_wifi_supplicant_scan_interval" />
<java-symbol type="integer" name="config_wifi_scan_interval_p2p_connected" />
@@ -885,7 +886,6 @@
<java-symbol type="string" name="write_fail_reason_cancelled" />
<java-symbol type="string" name="write_fail_reason_cannot_write" />
<java-symbol type="string" name="transient_navigation_confirmation" />
<java-symbol type="string" name="transient_navigation_confirmation_long" />
<java-symbol type="string" name="ssl_ca_cert_noti_by_unknown" />
<java-symbol type="string" name="ssl_ca_cert_noti_managed" />
<java-symbol type="string" name="ssl_ca_cert_warning" />

View File

@@ -34,7 +34,6 @@ import android.content.ServiceConnection;
import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.content.pm.UserInfo;
import android.content.res.CompatibilityInfo;
import android.content.res.Configuration;
import android.content.res.Resources;
@@ -105,7 +104,6 @@ import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.HashSet;
import static android.view.WindowManager.LayoutParams.*;
import static android.view.WindowManagerPolicy.WindowManagerFuncs.LID_ABSENT;
@@ -531,7 +529,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
Settings.Secure.DEFAULT_INPUT_METHOD), false, this,
UserHandle.USER_ALL);
resolver.registerContentObserver(Settings.System.getUriFor(
ImmersiveModeTesting.ENABLED_SETTING), false, this,
Settings.Secure.TRANSIENT_NAV_CONFIRMATIONS), false, this,
UserHandle.USER_ALL);
updateSettings();
}
@@ -947,9 +945,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
}
@Override
public void onDebug() {
if (ImmersiveModeTesting.enabled) {
ImmersiveModeTesting.toggleForceImmersiveMode(mFocusedWindow, mContext);
}
// no-op
}
});
mTransientNavigationConfirmation = new TransientNavigationConfirmation(mContext);
@@ -1168,8 +1164,9 @@ public class PhoneWindowManager implements WindowManagerPolicy {
mHasSoftInput = hasSoftInput;
updateRotation = true;
}
ImmersiveModeTesting.enabled = Settings.System.getIntForUser(resolver,
ImmersiveModeTesting.ENABLED_SETTING, 0, UserHandle.USER_CURRENT) != 0;
if (mTransientNavigationConfirmation != null) {
mTransientNavigationConfirmation.loadSetting();
}
}
if (updateRotation) {
updateRotation(true);
@@ -3892,9 +3889,8 @@ public class PhoneWindowManager implements WindowManagerPolicy {
case KeyEvent.KEYCODE_POWER: {
result &= ~ACTION_PASS_TO_USER;
if (down) {
if (isScreenOn && isTransientNavigationAllowed(mLastSystemUiFlags)) {
mTransientNavigationConfirmation.unconfirmLastPackage();
}
mTransientNavigationConfirmation.onPowerKeyDown(isScreenOn, event.getDownTime(),
isTransientNavigationAllowed(mLastSystemUiFlags));
if (isScreenOn && !mPowerKeyTriggered
&& (event.getFlags() & KeyEvent.FLAG_FALLBACK) == 0) {
mPowerKeyTriggered = true;
@@ -4173,6 +4169,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
}
if (sb) mStatusBarController.showTransient();
if (nb) mNavigationBarController.showTransient();
mTransientNavigationConfirmation.confirmCurrentPrompt();
updateSystemUiVisibilityLw();
}
}
@@ -5039,10 +5036,6 @@ public class PhoneWindowManager implements WindowManagerPolicy {
}
private int updateSystemBarsLw(int oldVis, int vis) {
if (ImmersiveModeTesting.enabled) {
vis = ImmersiveModeTesting.applyForced(mFocusedWindow, vis);
}
// prevent status bar interaction from clearing certain flags
boolean statusBarHasFocus = mFocusedWindow.getAttrs().type == TYPE_STATUS_BAR;
if (statusBarHasFocus) {
@@ -5086,8 +5079,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
boolean isTransientNav = isTransientNavigationAllowed(vis);
if (mFocusedWindow != null && oldTransientNav != isTransientNav) {
final String pkg = mFocusedWindow.getOwningPackage();
mTransientNavigationConfirmation.transientNavigationChanged(mCurrentUserId, pkg,
isTransientNav);
mTransientNavigationConfirmation.transientNavigationChanged(pkg, isTransientNav);
}
vis = mNavigationBarController.updateVisibilityLw(isTransientNav, oldVis, vis);
@@ -5104,53 +5096,6 @@ public class PhoneWindowManager implements WindowManagerPolicy {
&& (vis & View.SYSTEM_UI_FLAG_IMMERSIVE) != 0;
}
// Temporary helper that allows testing immersive mode on existing apps
// TODO remove
private static final class ImmersiveModeTesting {
static String ENABLED_SETTING = "immersive_mode_testing_enabled";
static boolean enabled = false;
private static final HashSet<String> sForced = new HashSet<String>();
private static String parseActivity(WindowState win) {
if (win != null && win.getAppToken() != null) {
String str = win.getAppToken().toString();
int end = str.lastIndexOf(' ');
if (end > 0) {
int start = str.lastIndexOf(' ', end - 1);
if (start > -1) {
return str.substring(start + 1, end);
}
}
}
return null;
}
public static int applyForced(WindowState focused, int vis) {
if (sForced.contains(parseActivity(focused))) {
vis |= View.SYSTEM_UI_FLAG_HIDE_NAVIGATION |
View.SYSTEM_UI_FLAG_FULLSCREEN |
View.SYSTEM_UI_FLAG_IMMERSIVE;
}
return vis;
}
public static void toggleForceImmersiveMode(WindowState focused, Context context) {
String activity = parseActivity(focused);
if (activity != null) {
String action;
if (sForced.contains(activity)) {
sForced.remove(activity);
action = "Force immersive mode disabled";
} else {
sForced.add(activity);
action = "Force immersive mode enabled";
}
android.widget.Toast.makeText(context,
action + " for " + activity, android.widget.Toast.LENGTH_SHORT).show();
}
}
}
// Use this instead of checking config_showNavigationBar so that it can be consistently
// overridden by qemu.hw.mainkeys in the emulator.
@Override

View File

@@ -19,16 +19,20 @@ package com.android.internal.policy.impl;
import android.content.Context;
import android.os.Handler;
import android.os.Message;
import android.os.UserHandle;
import android.provider.Settings;
import android.text.TextUtils;
import android.util.ArraySet;
import android.util.Slog;
import android.view.View;
import android.view.animation.Animation;
import android.view.animation.AnimationSet;
import android.view.animation.AnimationUtils;
import android.widget.Toast;
import com.android.internal.R;
import java.util.Arrays;
/**
* Helper to manage showing/hiding a confirmation prompt when the transient navigation bar
* is hidden.
@@ -39,16 +43,22 @@ public class TransientNavigationConfirmation {
private final Context mContext;
private final H mHandler;
private final ArraySet<String> mConfirmedUserPackages = new ArraySet<String>();
private final ArraySet<String> mConfirmedPackages = new ArraySet<String>();
private final long mShowDelayMs;
private final long mPanicThresholdMs;
private Toast mToast;
private String mLastUserPackage;
private String mLastPackage;
private String mPromptPackage;
private long mPanicTime;
private String mPanicPackage;
public TransientNavigationConfirmation(Context context) {
mContext = context;
mHandler = new H();
mShowDelayMs = getNavBarExitDuration() * 3;
mPanicThresholdMs = context.getResources()
.getInteger(R.integer.config_transient_navigation_confirmation_panic);
}
private long getNavBarExitDuration() {
@@ -56,44 +66,97 @@ public class TransientNavigationConfirmation {
return exit != null ? exit.getDuration() : 0;
}
public void transientNavigationChanged(int userId, String pkg, boolean isNavTransient) {
public void loadSetting() {
if (DEBUG) Slog.d(TAG, "loadSetting()");
mConfirmedPackages.clear();
String packages = null;
try {
packages = Settings.Secure.getStringForUser(mContext.getContentResolver(),
Settings.Secure.TRANSIENT_NAV_CONFIRMATIONS,
UserHandle.USER_CURRENT);
if (packages != null) {
mConfirmedPackages.addAll(Arrays.asList(packages.split(",")));
if (DEBUG) Slog.d(TAG, "Loaded mConfirmedPackages=" + mConfirmedPackages);
}
} catch (Throwable t) {
Slog.w(TAG, "Error loading confirmations, packages=" + packages, t);
}
}
private void saveSetting() {
if (DEBUG) Slog.d(TAG, "saveSetting()");
try {
final String packages = TextUtils.join(",", mConfirmedPackages);
Settings.Secure.putStringForUser(mContext.getContentResolver(),
Settings.Secure.TRANSIENT_NAV_CONFIRMATIONS,
packages,
UserHandle.USER_CURRENT);
if (DEBUG) Slog.d(TAG, "Saved packages=" + packages);
} catch (Throwable t) {
Slog.w(TAG, "Error saving confirmations, mConfirmedPackages=" + mConfirmedPackages, t);
}
}
public void transientNavigationChanged(String pkg, boolean isNavTransient) {
if (pkg == null) {
return;
}
String userPkg = userId + ":" + pkg;
mHandler.removeMessages(H.SHOW);
if (isNavTransient) {
mLastUserPackage = userPkg;
if (!mConfirmedUserPackages.contains(userPkg)) {
if (DEBUG) Slog.d(TAG, "Showing transient navigation confirmation for " + userPkg);
mHandler.sendMessageDelayed(mHandler.obtainMessage(H.SHOW, userPkg), mShowDelayMs);
mLastPackage = pkg;
if (!mConfirmedPackages.contains(pkg)) {
mHandler.sendMessageDelayed(mHandler.obtainMessage(H.SHOW, pkg), mShowDelayMs);
}
} else {
mLastUserPackage = null;
if (DEBUG) Slog.d(TAG, "Hiding transient navigation confirmation for " + userPkg);
mLastPackage = null;
mHandler.sendEmptyMessage(H.HIDE);
}
}
public void unconfirmLastPackage() {
if (mLastUserPackage != null) {
if (DEBUG) Slog.d(TAG, "Unconfirming transient navigation for " + mLastUserPackage);
mConfirmedUserPackages.remove(mLastUserPackage);
public void onPowerKeyDown(boolean isScreenOn, long time, boolean transientNavigationAllowed) {
if (mPanicPackage != null && !isScreenOn && (time - mPanicTime < mPanicThresholdMs)) {
// turning the screen back on within the panic threshold
unconfirmPackage(mPanicPackage);
}
if (isScreenOn && transientNavigationAllowed) {
// turning the screen off, remember if we were hiding the transient nav
mPanicTime = time;
mPanicPackage = mLastPackage;
} else {
mPanicTime = 0;
mPanicPackage = null;
}
}
public void confirmCurrentPrompt() {
mHandler.post(confirmAction(mPromptPackage));
}
private void unconfirmPackage(String pkg) {
if (pkg != null) {
if (DEBUG) Slog.d(TAG, "Unconfirming transient navigation for " + pkg);
mConfirmedPackages.remove(pkg);
saveSetting();
}
}
private void handleHide() {
if (mToast != null) {
if (DEBUG) Slog.d(TAG,
"Hiding transient navigation confirmation for " + mPromptPackage);
mToast.cancel();
mToast = null;
}
}
private void handleShow(String userPkg) {
private void handleShow(String pkg) {
mPromptPackage = pkg;
if (DEBUG) Slog.d(TAG, "Showing transient navigation confirmation for " + pkg);
// 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));
mToast.setAction(R.string.ok, confirmAction(pkg));
// 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);
@@ -102,11 +165,15 @@ public class TransientNavigationConfirmation {
mToast.show();
}
private Runnable confirmAction(final String userPkg) {
private Runnable confirmAction(final String pkg) {
return new Runnable() {
@Override
public void run() {
mConfirmedUserPackages.add(userPkg);
if (pkg != null && !mConfirmedPackages.contains(pkg)) {
if (DEBUG) Slog.d(TAG, "Confirming transient navigation for " + pkg);
mConfirmedPackages.add(pkg);
saveSetting();
}
handleHide();
}
};