diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index d74aaeb20bcb7..52c3db5f42ee1 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -4839,24 +4839,28 @@
sans-serif
- You are in lock-to-app mode. To exit, touch and hold the Recents button
+ To unpin this screen, touch and hold Back and Recents at the same time.
+
+ To unpin this screen, touch and hold Recents.
- You are in Lock-to-App mode.
+ Screen is pinned. Unpinning isn\'t allowed by your organization.
- Use lock-to-app?
+ Use screen pinning?
- Lock-to-app locks the display in a single app.\n\nTo exit, touch and hold the Recents button.
+ Screen pinning locks the display in a single view.\n\nTo exit, touch and hold Back and Recents at the same time.
+
+ Screen pinning locks the display in a single view.\n\nTo exit, touch and hold Recents.
NO, THANKS
START
- Locked to app
+ Screen pinned
- No longer locked to app
+ Screen unpinned
- Ask for %1$s before exiting
+ Ask for %1$s before unpinning
PIN
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 220f5ab872242..45ba51e23818c 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -610,9 +610,11 @@
+
+
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 a29eaed90026d..7a9cbef7e93b1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -91,6 +91,8 @@ import android.view.ViewPropertyAnimator;
import android.view.ViewStub;
import android.view.ViewTreeObserver;
import android.view.WindowManager;
+import android.view.accessibility.AccessibilityEvent;
+import android.view.accessibility.AccessibilityManager;
import android.view.animation.AccelerateDecelerateInterpolator;
import android.view.animation.AccelerateInterpolator;
import android.view.animation.Animation;
@@ -137,6 +139,7 @@ import com.android.systemui.statusbar.policy.CastControllerImpl;
import com.android.systemui.statusbar.policy.FlashlightController;
import com.android.systemui.statusbar.policy.HeadsUpNotificationView;
import com.android.systemui.statusbar.policy.HotspotControllerImpl;
+import com.android.systemui.statusbar.policy.KeyButtonView;
import com.android.systemui.statusbar.policy.KeyguardMonitor;
import com.android.systemui.statusbar.policy.KeyguardUserSwitcher;
import com.android.systemui.statusbar.policy.LocationControllerImpl;
@@ -210,6 +213,9 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
public static final int FADE_KEYGUARD_START_DELAY = 100;
public static final int FADE_KEYGUARD_DURATION = 300;
+ /** Allow some time inbetween the long press for back and recents. */
+ private static final int LOCK_TO_APP_GESTURE_TOLERENCE = 200;
+
PhoneStatusBarPolicy mIconPolicy;
// These are no longer handled by the policy, because we need custom strategies for them
@@ -1054,10 +1060,13 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
}
};
- private View.OnLongClickListener mLockToAppClickListener = new View.OnLongClickListener() {
+ private long mLastLockToAppLongPress;
+ private AccessibilityManager mAccessibilityManager;
+ private View.OnLongClickListener mLongPressBackRecentsListener =
+ new View.OnLongClickListener() {
@Override
public boolean onLongClick(View v) {
- toggleLockedApp();
+ handleLongPressBackRecents(v);
return true;
}
};
@@ -1106,7 +1115,9 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
mNavigationBarView.getRecentsButton().setOnClickListener(mRecentsClickListener);
mNavigationBarView.getRecentsButton().setOnTouchListener(mRecentsPreloadOnTouchListener);
mNavigationBarView.getRecentsButton().setLongClickable(true);
- mNavigationBarView.getRecentsButton().setOnLongClickListener(mLockToAppClickListener);
+ mNavigationBarView.getRecentsButton().setOnLongClickListener(mLongPressBackRecentsListener);
+ mNavigationBarView.getBackButton().setLongClickable(true);
+ mNavigationBarView.getBackButton().setOnLongClickListener(mLongPressBackRecentsListener);
mNavigationBarView.getHomeButton().setOnTouchListener(mHomeActionListener);
updateSearchPanel();
}
@@ -3773,15 +3784,58 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
mStackScroller.setAnimationsEnabled(true);
}
- public void toggleLockedApp() {
- Log.d(TAG, "Trying to toggle lock-to-app");
+ /**
+ * This handles long-press of both back and recents. They are
+ * handled together to capture them both being long-pressed
+ * at the same time to exit screen pinning (lock task).
+ *
+ * When accessibility mode is on, only a long-press from recents
+ * is required to exit.
+ *
+ * In all other circumstances we try to pass through long-press events
+ * for Back, so that apps can still use it. Which can be from two things.
+ * 1) Not currently in screen pinning (lock task).
+ * 2) Back is long-pressed without recents.
+ */
+ private void handleLongPressBackRecents(View v) {
try {
+ boolean sendBackLongPress = false;
IActivityManager activityManager = ActivityManagerNative.getDefault();
- if (activityManager.isInLockTaskMode()) {
- activityManager.stopLockTaskModeOnCurrent();
+ if (mAccessibilityManager == null) {
+ mAccessibilityManager = (AccessibilityManager)
+ mContext.getSystemService(Context.ACCESSIBILITY_SERVICE);
+ }
+ boolean isAccessiblityEnabled = mAccessibilityManager.isEnabled();
+ if (activityManager.isInLockTaskMode() && !isAccessiblityEnabled) {
+ long time = System.currentTimeMillis();
+ // If we recently long-pressed the other button then they were
+ // long-pressed 'together'
+ if ((time - mLastLockToAppLongPress) < LOCK_TO_APP_GESTURE_TOLERENCE) {
+ activityManager.stopLockTaskModeOnCurrent();
+ } else if ((v.getId() == R.id.back)
+ && !mNavigationBarView.getRecentsButton().isPressed()) {
+ // If we aren't pressing recents right now then they presses
+ // won't be together, so send the standard long-press action.
+ sendBackLongPress = true;
+ }
+ mLastLockToAppLongPress = time;
+ } else {
+ // If this is back still need to handle sending the long-press event.
+ if (v.getId() == R.id.back) {
+ sendBackLongPress = true;
+ } else if (isAccessiblityEnabled && activityManager.isInLockTaskMode()) {
+ // When in accessibility mode a long press that is recents (not back)
+ // should stop lock task.
+ activityManager.stopLockTaskModeOnCurrent();
+ }
+ }
+ if (sendBackLongPress) {
+ KeyButtonView keyButtonView = (KeyButtonView) v;
+ keyButtonView.sendEvent(KeyEvent.ACTION_DOWN, KeyEvent.FLAG_LONG_PRESS);
+ keyButtonView.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_LONG_CLICKED);
}
} catch (RemoteException e) {
- Log.d(TAG, "Unable to toggle Lock-to-app", e);
+ Log.d(TAG, "Unable to reach activity manager", e);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java
index 330b599fe3b99..e9581fcc48808 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java
@@ -56,12 +56,12 @@ public class KeyButtonView extends ImageView {
public void run() {
if (isPressed()) {
// Log.d("KeyButtonView", "longpressed: " + this);
- if (mCode != 0) {
- sendEvent(KeyEvent.ACTION_DOWN, KeyEvent.FLAG_LONG_PRESS);
- sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_LONG_CLICKED);
- } else {
+ if (isLongClickable()) {
// Just an old-fashioned ImageView
performLongClick();
+ } else {
+ sendEvent(KeyEvent.ACTION_DOWN, KeyEvent.FLAG_LONG_PRESS);
+ sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_LONG_CLICKED);
}
}
}
@@ -216,7 +216,7 @@ public class KeyButtonView extends ImageView {
return true;
}
- void sendEvent(int action, int flags) {
+ public void sendEvent(int action, int flags) {
sendEvent(action, flags, SystemClock.uptimeMillis());
}
diff --git a/services/core/java/com/android/server/am/LockTaskNotify.java b/services/core/java/com/android/server/am/LockTaskNotify.java
index 6f9b23d181fd1..cf65243f3f8a7 100644
--- a/services/core/java/com/android/server/am/LockTaskNotify.java
+++ b/services/core/java/com/android/server/am/LockTaskNotify.java
@@ -19,6 +19,7 @@ package com.android.server.am;
import android.content.Context;
import android.os.Handler;
import android.os.Message;
+import android.view.accessibility.AccessibilityManager;
import android.widget.Toast;
import com.android.internal.R;
@@ -32,9 +33,12 @@ public class LockTaskNotify {
private final Context mContext;
private final H mHandler;
+ private AccessibilityManager mAccessibilityManager;
public LockTaskNotify(Context context) {
mContext = context;
+ mAccessibilityManager = (AccessibilityManager)
+ mContext.getSystemService(Context.ACCESSIBILITY_SERVICE);
mHandler = new H();
}
@@ -45,6 +49,9 @@ public class LockTaskNotify {
public void handleShowToast(boolean isLocked) {
String text = mContext.getString(isLocked
? R.string.lock_to_app_toast_locked : R.string.lock_to_app_toast);
+ if (!isLocked && mAccessibilityManager.isEnabled()) {
+ text = mContext.getString(R.string.lock_to_app_toast_accessible);
+ }
Toast.makeText(mContext, text, Toast.LENGTH_LONG).show();
}
diff --git a/services/core/java/com/android/server/am/LockToAppRequestDialog.java b/services/core/java/com/android/server/am/LockToAppRequestDialog.java
index 0847b52460784..12dcf7eee57cc 100644
--- a/services/core/java/com/android/server/am/LockToAppRequestDialog.java
+++ b/services/core/java/com/android/server/am/LockToAppRequestDialog.java
@@ -13,6 +13,7 @@ import android.provider.Settings;
import android.provider.Settings.SettingNotFoundException;
import android.util.Slog;
import android.view.WindowManager;
+import android.view.accessibility.AccessibilityManager;
import android.widget.CheckBox;
import com.android.internal.R;
@@ -33,8 +34,12 @@ public class LockToAppRequestDialog implements OnClickListener {
private ILockSettings mLockSettingsService;
+ private AccessibilityManager mAccessibilityService;
+
public LockToAppRequestDialog(Context context, ActivityManagerService activityManagerService) {
mContext = context;
+ mAccessibilityService = (AccessibilityManager)
+ mContext.getSystemService(Context.ACCESSIBILITY_SERVICE);
mService = activityManagerService;
}
@@ -78,7 +83,9 @@ public class LockToAppRequestDialog implements OnClickListener {
final int unlockStringId = getLockString(task.userId);
final Resources r = Resources.getSystem();
- final String description= r.getString(R.string.lock_to_app_description);
+ final String description= r.getString(mAccessibilityService.isEnabled()
+ ? R.string.lock_to_app_description_accessible
+ : R.string.lock_to_app_description);
AlertDialog.Builder builder = new AlertDialog.Builder(mContext)
.setTitle(r.getString(R.string.lock_to_app_title))
.setMessage(description)