Loading core/res/res/values/config.xml +33 −0 Original line number Diff line number Diff line Loading @@ -1051,6 +1051,39 @@ --> <integer name="config_shortPressOnSleepBehavior">0</integer> <!-- Control the behavior when the user long presses the stem primary button. Stem primary button is only used on watch form factor. If a device is not a watch, setting this config is no-op. 0 - Nothing 1 - Launch voice assistant --> <integer name="config_longPressOnStemPrimaryBehavior">0</integer> <!-- Control the behavior when the user double presses the stem primary button. Stem primary button is only used on watch form factor. If a device is not a watch, setting this config is no-op. 0 - Nothing 1 - Switch to the recent app --> <integer name="config_doublePressOnStemPrimaryBehavior">0</integer> <!-- Control the behavior when the user triple presses the stem primary button. Stem primary button is only used on watch form factor. If a device is not a watch, setting this config is no-op. 0 - Nothing 1 - Toggle accessibility --> <integer name="config_triplePressOnStemPrimaryBehavior">0</integer> <!-- Control the behavior when the user short presses the stem primary button. Stem primary button is only used on watch form factor. If a device is not a watch, setting this config is no-op. 0 - Nothing 1 - Go to launch all apps --> <integer name="config_shortPressOnStemPrimaryBehavior">0</integer> <!-- Time to wait while a button is pressed before triggering a very long press. --> <integer name="config_veryLongPressTimeout">3500</integer> Loading core/res/res/values/symbols.xml +4 −0 Original line number Diff line number Diff line Loading @@ -459,6 +459,10 @@ <java-symbol type="integer" name="config_toastDefaultGravity" /> <java-symbol type="integer" name="config_triplePressOnPowerBehavior" /> <java-symbol type="integer" name="config_shortPressOnSleepBehavior" /> <java-symbol type="integer" name="config_longPressOnStemPrimaryBehavior" /> <java-symbol type="integer" name="config_shortPressOnStemPrimaryBehavior" /> <java-symbol type="integer" name="config_doublePressOnStemPrimaryBehavior" /> <java-symbol type="integer" name="config_triplePressOnStemPrimaryBehavior" /> <java-symbol type="integer" name="config_windowOutsetBottom" /> <java-symbol type="integer" name="db_connection_pool_size" /> <java-symbol type="integer" name="db_journal_size_limit" /> Loading services/core/java/com/android/server/policy/PhoneWindowManager.java +306 −0 Original line number Diff line number Diff line Loading @@ -93,8 +93,10 @@ import static com.android.server.wm.WindowManagerPolicyProto.ROTATION_MODE; import static com.android.server.wm.WindowManagerPolicyProto.SCREEN_ON_FULLY; import static com.android.server.wm.WindowManagerPolicyProto.WINDOW_MANAGER_DRAW_COMPLETE; import android.accessibilityservice.AccessibilityServiceInfo; import android.annotation.Nullable; import android.app.ActivityManager; import android.app.ActivityManager.RecentTaskInfo; import android.app.ActivityManagerInternal; import android.app.ActivityTaskManager; import android.app.AppOpsManager; Loading @@ -105,6 +107,7 @@ import android.app.SearchManager; import android.app.UiModeManager; import android.content.ActivityNotFoundException; import android.content.BroadcastReceiver; import android.content.ComponentName; import android.content.ContentResolver; import android.content.Context; import android.content.Intent; Loading @@ -113,6 +116,7 @@ import android.content.pm.ActivityInfo; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.content.pm.ServiceInfo; import android.content.res.CompatibilityInfo; import android.content.res.Configuration; import android.content.res.Resources; Loading Loading @@ -191,6 +195,7 @@ import android.view.autofill.AutofillManagerInternal; import com.android.internal.R; import com.android.internal.accessibility.AccessibilityShortcutController; import com.android.internal.accessibility.util.AccessibilityUtils; import com.android.internal.app.AssistUtils; import com.android.internal.inputmethod.SoftInputShowHideReason; import com.android.internal.logging.MetricsLogger; Loading Loading @@ -230,6 +235,7 @@ import java.io.IOException; import java.io.PrintWriter; import java.util.HashSet; import java.util.List; import java.util.Set; /** * WindowManagerPolicy implementation for the Android phone UI. This Loading Loading @@ -308,6 +314,22 @@ public class PhoneWindowManager implements WindowManagerPolicy { static final int PENDING_KEY_NULL = -1; // Must match: config_shortPressOnStemPrimaryBehavior in config.xml static final int SHORT_PRESS_PRIMARY_NOTHING = 0; static final int SHORT_PRESS_PRIMARY_LAUNCH_ALL_APPS = 1; // Must match: config_longPressOnStemPrimaryBehavior in config.xml static final int LONG_PRESS_PRIMARY_NOTHING = 0; static final int LONG_PRESS_PRIMARY_LAUNCH_VOICE_ASSISTANT = 1; // Must match: config_doublePressOnStemPrimaryBehavior in config.xml static final int DOUBLE_PRESS_PRIMARY_NOTHING = 0; static final int DOUBLE_PRESS_PRIMARY_SWITCH_RECENT_APP = 1; // Must match: config_triplePressOnStemPrimaryBehavior in config.xml static final int TRIPLE_PRESS_PRIMARY_NOTHING = 0; static final int TRIPLE_PRESS_PRIMARY_TOGGLE_ACCESSIBILITY = 1; static public final String SYSTEM_DIALOG_REASON_KEY = "reason"; static public final String SYSTEM_DIALOG_REASON_GLOBAL_ACTIONS = "globalactions"; static public final String SYSTEM_DIALOG_REASON_RECENT_APPS = "recentapps"; Loading @@ -315,6 +337,8 @@ public class PhoneWindowManager implements WindowManagerPolicy { static public final String SYSTEM_DIALOG_REASON_ASSIST = "assist"; static public final String SYSTEM_DIALOG_REASON_SCREENSHOT = "screenshot"; private static final String TALKBACK_LABEL = "TalkBack"; private static final int POWER_BUTTON_SUPPRESSION_DELAY_DEFAULT_MILLIS = 800; private static final AudioAttributes VIBRATION_ATTRIBUTES = new AudioAttributes.Builder() .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION) Loading Loading @@ -487,6 +511,10 @@ public class PhoneWindowManager implements WindowManagerPolicy { int mShortPressOnSleepBehavior; int mShortPressOnWindowBehavior; int mPowerVolUpBehavior; int mShortPressOnStemPrimaryBehavior; int mDoublePressOnStemPrimaryBehavior; int mTriplePressOnStemPrimaryBehavior; int mLongPressOnStemPrimaryBehavior; boolean mHasSoftInput = false; boolean mHapticTextHandleEnabled; boolean mUseTvRouting; Loading Loading @@ -1192,6 +1220,170 @@ public class PhoneWindowManager implements WindowManagerPolicy { return mLongPressOnPowerBehavior; } private void stemPrimaryPress(int count) { if (DEBUG_INPUT) { Slog.d(TAG, "stemPrimaryPress: " + count); } if (count == 3) { stemPrimaryTriplePressAction(mTriplePressOnStemPrimaryBehavior); } else if (count == 2) { stemPrimaryDoublePressAction(mDoublePressOnStemPrimaryBehavior); } else if (count == 1) { stemPrimarySinglePressAction(mShortPressOnStemPrimaryBehavior); } } private void stemPrimarySinglePressAction(int behavior) { switch (behavior) { case SHORT_PRESS_PRIMARY_NOTHING: break; case SHORT_PRESS_PRIMARY_LAUNCH_ALL_APPS: if (DEBUG_INPUT) { Slog.d(TAG, "Executing stem primary short press action behavior."); } final boolean keyguardActive = mKeyguardDelegate != null && mKeyguardDelegate.isShowing(); if (!keyguardActive) { Intent intent = new Intent(Intent.ACTION_ALL_APPS); intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED); startActivityAsUser(intent, UserHandle.CURRENT_OR_SELF); } break; } } private void stemPrimaryDoublePressAction(int behavior) { switch (behavior) { case DOUBLE_PRESS_PRIMARY_NOTHING: break; case DOUBLE_PRESS_PRIMARY_SWITCH_RECENT_APP: if (DEBUG_INPUT) { Slog.d(TAG, "Executing stem primary double press action behavior."); } final boolean keyguardActive = mKeyguardDelegate == null ? false : mKeyguardDelegate.isShowing(); if (!keyguardActive) { switchRecentTask(); } break; } } private void stemPrimaryTriplePressAction(int behavior) { switch (behavior) { case TRIPLE_PRESS_PRIMARY_NOTHING: break; case TRIPLE_PRESS_PRIMARY_TOGGLE_ACCESSIBILITY: if (DEBUG_INPUT) { Slog.d(TAG, "Executing stem primary triple press action behavior."); } toggleTalkBack(); break; } } private void stemPrimaryLongPress() { if (DEBUG_INPUT) { Slog.d(TAG, "Executing stem primary long press action behavior."); } switch (mLongPressOnStemPrimaryBehavior) { case LONG_PRESS_PRIMARY_NOTHING: break; case LONG_PRESS_PRIMARY_LAUNCH_VOICE_ASSISTANT: launchVoiceAssist(/* allowDuringSetup= */false); break; } } private void toggleTalkBack() { final ComponentName componentName = getTalkbackComponent(); if (componentName == null) { return; } final Set<ComponentName> enabledServices = AccessibilityUtils.getEnabledServicesFromSettings(mContext, mCurrentUserId); AccessibilityUtils.setAccessibilityServiceState(mContext, componentName, !enabledServices.contains(componentName)); } private ComponentName getTalkbackComponent() { AccessibilityManager accessibilityManager = mContext.getSystemService( AccessibilityManager.class); List<AccessibilityServiceInfo> serviceInfos = accessibilityManager.getInstalledAccessibilityServiceList(); for (AccessibilityServiceInfo service : serviceInfos) { final ServiceInfo serviceInfo = service.getResolveInfo().serviceInfo; if (isTalkback(serviceInfo)) { return new ComponentName(serviceInfo.packageName, serviceInfo.name); } } return null; } private boolean isTalkback(ServiceInfo info) { String label = info.loadLabel(mPackageManager).toString(); return label.equals(TALKBACK_LABEL); } /** * Load most recent task (expect current task) and bring it to the front. */ private void switchRecentTask() { RecentTaskInfo targetTask = mActivityTaskManagerInternal.getMostRecentTaskFromBackground(); if (targetTask == null) { if (DEBUG_INPUT) { Slog.w(TAG, "No recent task available! Show watch face."); } goHome(); return; } if (DEBUG_INPUT) { Slog.d( TAG, "Starting task from recents. id=" + targetTask.id + ", persistentId=" + targetTask.persistentId + ", topActivity=" + targetTask.topActivity + ", baseIntent=" + targetTask.baseIntent); } try { ActivityManager.getService().startActivityFromRecents(targetTask.persistentId, null); } catch (RemoteException e) { Slog.e(TAG, "Failed to start task " + targetTask.persistentId + " from recents", e); } } private int getMaxMultiPressStemPrimaryCount() { switch (mTriplePressOnStemPrimaryBehavior) { case TRIPLE_PRESS_PRIMARY_NOTHING: break; case TRIPLE_PRESS_PRIMARY_TOGGLE_ACCESSIBILITY: if (Settings.System.getIntForUser( mContext.getContentResolver(), Settings.System.WEAR_ACCESSIBILITY_GESTURE_ENABLED, /* def= */ 0, UserHandle.USER_CURRENT) == 1) { return 3; } break; } if (mDoublePressOnStemPrimaryBehavior != DOUBLE_PRESS_PRIMARY_NOTHING) { return 2; } return 1; } private boolean hasLongPressOnPowerBehavior() { return getResolvedLongPressOnPowerBehavior() != LONG_PRESS_POWER_NOTHING; } Loading @@ -1204,6 +1396,16 @@ public class PhoneWindowManager implements WindowManagerPolicy { return mLongPressOnBackBehavior != LONG_PRESS_BACK_NOTHING; } private boolean hasLongPressOnStemPrimaryBehavior() { return mLongPressOnStemPrimaryBehavior != LONG_PRESS_PRIMARY_NOTHING; } private boolean hasStemPrimaryBehavior() { return getMaxMultiPressStemPrimaryCount() > 1 || hasLongPressOnStemPrimaryBehavior() || mShortPressOnStemPrimaryBehavior != SHORT_PRESS_PRIMARY_NOTHING; } private void interceptScreenshotChord() { mHandler.removeCallbacks(mScreenshotRunnable); mScreenshotRunnable.setScreenshotType(TAKE_SCREENSHOT_FULLSCREEN); Loading Loading @@ -2037,6 +2239,35 @@ public class PhoneWindowManager implements WindowManagerPolicy { } } /** * Rule for single stem primary key gesture. */ private final class StemPrimaryKeyRule extends SingleKeyGestureDetector.SingleKeyRule { StemPrimaryKeyRule(int gestures) { super(mContext, KeyEvent.KEYCODE_STEM_PRIMARY, gestures); } @Override int getMaxMultiPressCount() { return getMaxMultiPressStemPrimaryCount(); } @Override void onPress(long downTime) { stemPrimaryPress(1 /*count*/); } @Override void onLongPress(long eventTime) { stemPrimaryLongPress(); } @Override void onMultiPress(long downTime, int count) { stemPrimaryPress(count); } } private void initSingleKeyGestureRules() { mSingleKeyGestureDetector = new SingleKeyGestureDetector(); Loading @@ -2052,6 +2283,13 @@ public class PhoneWindowManager implements WindowManagerPolicy { if (hasLongPressOnBackBehavior()) { mSingleKeyGestureDetector.addRule(new BackKeyRule(KEY_LONGPRESS)); } if (hasStemPrimaryBehavior()) { int stemPrimaryKeyGestures = 0; if (hasLongPressOnStemPrimaryBehavior()) { stemPrimaryKeyGestures |= KEY_LONGPRESS; } mSingleKeyGestureDetector.addRule(new StemPrimaryKeyRule(stemPrimaryKeyGestures)); } } /** Loading Loading @@ -2080,6 +2318,14 @@ public class PhoneWindowManager implements WindowManagerPolicy { if (mPackageManager.hasSystemFeature(FEATURE_PICTURE_IN_PICTURE)) { mShortPressOnWindowBehavior = SHORT_PRESS_WINDOW_PICTURE_IN_PICTURE; } mShortPressOnStemPrimaryBehavior = mContext.getResources().getInteger( com.android.internal.R.integer.config_shortPressOnStemPrimaryBehavior); mLongPressOnStemPrimaryBehavior = mContext.getResources().getInteger( com.android.internal.R.integer.config_longPressOnStemPrimaryBehavior); mDoublePressOnStemPrimaryBehavior = mContext.getResources().getInteger( com.android.internal.R.integer.config_doublePressOnStemPrimaryBehavior); mTriplePressOnStemPrimaryBehavior = mContext.getResources().getInteger( com.android.internal.R.integer.config_triplePressOnStemPrimaryBehavior); } public void updateSettings() { Loading Loading @@ -5380,6 +5626,22 @@ public class PhoneWindowManager implements WindowManagerPolicy { pw.print(prefix); pw.print("mShortPressOnWindowBehavior="); pw.println(shortPressOnWindowBehaviorToString(mShortPressOnWindowBehavior)); pw.print(prefix); pw.print("mShortPressOnStemPrimaryBehavior="); pw.println(shortPressOnStemPrimaryBehaviorToString( mShortPressOnStemPrimaryBehavior)); pw.print(prefix); pw.print("mDoublePressOnStemPrimaryBehavior="); pw.println(doublePressOnStemPrimaryBehaviorToString( mDoublePressOnStemPrimaryBehavior)); pw.print(prefix); pw.print("mTriplePressOnStemPrimaryBehavior="); pw.println(triplePressOnStemPrimaryBehaviorToString( mTriplePressOnStemPrimaryBehavior)); pw.print(prefix); pw.print("mLongPressOnStemPrimaryBehavior="); pw.println(longPressOnStemPrimaryBehaviorToString( mLongPressOnStemPrimaryBehavior)); pw.print(prefix); pw.print("mAllowStartActivityForLongPressOnPowerDuringSetup="); pw.println(mAllowStartActivityForLongPressOnPowerDuringSetup); Loading Loading @@ -5596,6 +5858,50 @@ public class PhoneWindowManager implements WindowManagerPolicy { } } private static String shortPressOnStemPrimaryBehaviorToString(int behavior) { switch (behavior) { case SHORT_PRESS_PRIMARY_NOTHING: return "SHORT_PRESS_PRIMARY_NOTHING"; case SHORT_PRESS_PRIMARY_LAUNCH_ALL_APPS: return "SHORT_PRESS_PRIMARY_LAUNCH_ALL_APPS"; default: return Integer.toString(behavior); } } private static String doublePressOnStemPrimaryBehaviorToString(int behavior) { switch (behavior) { case DOUBLE_PRESS_PRIMARY_NOTHING: return "DOUBLE_PRESS_PRIMARY_NOTHING"; case DOUBLE_PRESS_PRIMARY_SWITCH_RECENT_APP: return "DOUBLE_PRESS_PRIMARY_SWITCH_RECENT_APP"; default: return Integer.toString(behavior); } } private static String triplePressOnStemPrimaryBehaviorToString(int behavior) { switch (behavior) { case TRIPLE_PRESS_PRIMARY_NOTHING: return "TRIPLE_PRESS_PRIMARY_NOTHING"; case TRIPLE_PRESS_PRIMARY_TOGGLE_ACCESSIBILITY: return "TRIPLE_PRESS_PRIMARY_TOGGLE_ACCESSIBILITY"; default: return Integer.toString(behavior); } } private static String longPressOnStemPrimaryBehaviorToString(int behavior) { switch (behavior) { case LONG_PRESS_PRIMARY_NOTHING: return "LONG_PRESS_PRIMARY_NOTHING"; case LONG_PRESS_PRIMARY_LAUNCH_VOICE_ASSISTANT: return "LONG_PRESS_PRIMARY_LAUNCH_VOICE_ASSISTANT"; default: return Integer.toString(behavior); } } private static String lidBehaviorToString(int behavior) { switch (behavior) { case LID_BEHAVIOR_LOCK: Loading services/core/java/com/android/server/policy/SingleKeyGestureDetector.java +5 −1 Original line number Diff line number Diff line Loading @@ -53,6 +53,7 @@ public final class SingleKeyGestureDetector { // Key code of current key down event, reset when key up. private int mDownKeyCode = KeyEvent.KEYCODE_UNKNOWN; private volatile boolean mHandledByLongPress = false; private volatile boolean mHandledByMultiPress = false; private final Handler mHandler; private long mLastDownTime = 0; private static final long MULTI_PRESS_TIMEOUT = ViewConfiguration.getMultiPressTimeout(); Loading Loading @@ -271,6 +272,7 @@ public final class SingleKeyGestureDetector { mKeyPressCounter + 1, mActiveRule); msg.setAsynchronous(true); mHandler.sendMessage(msg); mHandledByMultiPress = true; mKeyPressCounter = 0; } } Loading @@ -284,8 +286,9 @@ public final class SingleKeyGestureDetector { return false; } if (mHandledByLongPress) { if (mHandledByLongPress || mHandledByMultiPress) { mHandledByLongPress = false; mHandledByMultiPress = false; mKeyPressCounter = 0; return true; } Loading Loading @@ -339,6 +342,7 @@ public final class SingleKeyGestureDetector { } mHandledByLongPress = false; mHandledByMultiPress = false; mDownKeyCode = KeyEvent.KEYCODE_UNKNOWN; } Loading services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java +4 −0 Original line number Diff line number Diff line Loading @@ -19,6 +19,7 @@ package com.android.server.wm; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.UserIdInt; import android.app.ActivityManager; import android.app.AppProtoEnums; import android.app.IActivityManager; import android.app.IApplicationThread; Loading Loading @@ -688,4 +689,7 @@ public abstract class ActivityTaskManagerInternal { public abstract void registerActivityStartInterceptor( @ActivityInterceptorCallback.OrderedId int id, ActivityInterceptorCallback callback); /** Get the most recent task excluding the first running task (the one on the front most). */ public abstract ActivityManager.RecentTaskInfo getMostRecentTaskFromBackground(); } Loading
core/res/res/values/config.xml +33 −0 Original line number Diff line number Diff line Loading @@ -1051,6 +1051,39 @@ --> <integer name="config_shortPressOnSleepBehavior">0</integer> <!-- Control the behavior when the user long presses the stem primary button. Stem primary button is only used on watch form factor. If a device is not a watch, setting this config is no-op. 0 - Nothing 1 - Launch voice assistant --> <integer name="config_longPressOnStemPrimaryBehavior">0</integer> <!-- Control the behavior when the user double presses the stem primary button. Stem primary button is only used on watch form factor. If a device is not a watch, setting this config is no-op. 0 - Nothing 1 - Switch to the recent app --> <integer name="config_doublePressOnStemPrimaryBehavior">0</integer> <!-- Control the behavior when the user triple presses the stem primary button. Stem primary button is only used on watch form factor. If a device is not a watch, setting this config is no-op. 0 - Nothing 1 - Toggle accessibility --> <integer name="config_triplePressOnStemPrimaryBehavior">0</integer> <!-- Control the behavior when the user short presses the stem primary button. Stem primary button is only used on watch form factor. If a device is not a watch, setting this config is no-op. 0 - Nothing 1 - Go to launch all apps --> <integer name="config_shortPressOnStemPrimaryBehavior">0</integer> <!-- Time to wait while a button is pressed before triggering a very long press. --> <integer name="config_veryLongPressTimeout">3500</integer> Loading
core/res/res/values/symbols.xml +4 −0 Original line number Diff line number Diff line Loading @@ -459,6 +459,10 @@ <java-symbol type="integer" name="config_toastDefaultGravity" /> <java-symbol type="integer" name="config_triplePressOnPowerBehavior" /> <java-symbol type="integer" name="config_shortPressOnSleepBehavior" /> <java-symbol type="integer" name="config_longPressOnStemPrimaryBehavior" /> <java-symbol type="integer" name="config_shortPressOnStemPrimaryBehavior" /> <java-symbol type="integer" name="config_doublePressOnStemPrimaryBehavior" /> <java-symbol type="integer" name="config_triplePressOnStemPrimaryBehavior" /> <java-symbol type="integer" name="config_windowOutsetBottom" /> <java-symbol type="integer" name="db_connection_pool_size" /> <java-symbol type="integer" name="db_journal_size_limit" /> Loading
services/core/java/com/android/server/policy/PhoneWindowManager.java +306 −0 Original line number Diff line number Diff line Loading @@ -93,8 +93,10 @@ import static com.android.server.wm.WindowManagerPolicyProto.ROTATION_MODE; import static com.android.server.wm.WindowManagerPolicyProto.SCREEN_ON_FULLY; import static com.android.server.wm.WindowManagerPolicyProto.WINDOW_MANAGER_DRAW_COMPLETE; import android.accessibilityservice.AccessibilityServiceInfo; import android.annotation.Nullable; import android.app.ActivityManager; import android.app.ActivityManager.RecentTaskInfo; import android.app.ActivityManagerInternal; import android.app.ActivityTaskManager; import android.app.AppOpsManager; Loading @@ -105,6 +107,7 @@ import android.app.SearchManager; import android.app.UiModeManager; import android.content.ActivityNotFoundException; import android.content.BroadcastReceiver; import android.content.ComponentName; import android.content.ContentResolver; import android.content.Context; import android.content.Intent; Loading @@ -113,6 +116,7 @@ import android.content.pm.ActivityInfo; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.content.pm.ServiceInfo; import android.content.res.CompatibilityInfo; import android.content.res.Configuration; import android.content.res.Resources; Loading Loading @@ -191,6 +195,7 @@ import android.view.autofill.AutofillManagerInternal; import com.android.internal.R; import com.android.internal.accessibility.AccessibilityShortcutController; import com.android.internal.accessibility.util.AccessibilityUtils; import com.android.internal.app.AssistUtils; import com.android.internal.inputmethod.SoftInputShowHideReason; import com.android.internal.logging.MetricsLogger; Loading Loading @@ -230,6 +235,7 @@ import java.io.IOException; import java.io.PrintWriter; import java.util.HashSet; import java.util.List; import java.util.Set; /** * WindowManagerPolicy implementation for the Android phone UI. This Loading Loading @@ -308,6 +314,22 @@ public class PhoneWindowManager implements WindowManagerPolicy { static final int PENDING_KEY_NULL = -1; // Must match: config_shortPressOnStemPrimaryBehavior in config.xml static final int SHORT_PRESS_PRIMARY_NOTHING = 0; static final int SHORT_PRESS_PRIMARY_LAUNCH_ALL_APPS = 1; // Must match: config_longPressOnStemPrimaryBehavior in config.xml static final int LONG_PRESS_PRIMARY_NOTHING = 0; static final int LONG_PRESS_PRIMARY_LAUNCH_VOICE_ASSISTANT = 1; // Must match: config_doublePressOnStemPrimaryBehavior in config.xml static final int DOUBLE_PRESS_PRIMARY_NOTHING = 0; static final int DOUBLE_PRESS_PRIMARY_SWITCH_RECENT_APP = 1; // Must match: config_triplePressOnStemPrimaryBehavior in config.xml static final int TRIPLE_PRESS_PRIMARY_NOTHING = 0; static final int TRIPLE_PRESS_PRIMARY_TOGGLE_ACCESSIBILITY = 1; static public final String SYSTEM_DIALOG_REASON_KEY = "reason"; static public final String SYSTEM_DIALOG_REASON_GLOBAL_ACTIONS = "globalactions"; static public final String SYSTEM_DIALOG_REASON_RECENT_APPS = "recentapps"; Loading @@ -315,6 +337,8 @@ public class PhoneWindowManager implements WindowManagerPolicy { static public final String SYSTEM_DIALOG_REASON_ASSIST = "assist"; static public final String SYSTEM_DIALOG_REASON_SCREENSHOT = "screenshot"; private static final String TALKBACK_LABEL = "TalkBack"; private static final int POWER_BUTTON_SUPPRESSION_DELAY_DEFAULT_MILLIS = 800; private static final AudioAttributes VIBRATION_ATTRIBUTES = new AudioAttributes.Builder() .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION) Loading Loading @@ -487,6 +511,10 @@ public class PhoneWindowManager implements WindowManagerPolicy { int mShortPressOnSleepBehavior; int mShortPressOnWindowBehavior; int mPowerVolUpBehavior; int mShortPressOnStemPrimaryBehavior; int mDoublePressOnStemPrimaryBehavior; int mTriplePressOnStemPrimaryBehavior; int mLongPressOnStemPrimaryBehavior; boolean mHasSoftInput = false; boolean mHapticTextHandleEnabled; boolean mUseTvRouting; Loading Loading @@ -1192,6 +1220,170 @@ public class PhoneWindowManager implements WindowManagerPolicy { return mLongPressOnPowerBehavior; } private void stemPrimaryPress(int count) { if (DEBUG_INPUT) { Slog.d(TAG, "stemPrimaryPress: " + count); } if (count == 3) { stemPrimaryTriplePressAction(mTriplePressOnStemPrimaryBehavior); } else if (count == 2) { stemPrimaryDoublePressAction(mDoublePressOnStemPrimaryBehavior); } else if (count == 1) { stemPrimarySinglePressAction(mShortPressOnStemPrimaryBehavior); } } private void stemPrimarySinglePressAction(int behavior) { switch (behavior) { case SHORT_PRESS_PRIMARY_NOTHING: break; case SHORT_PRESS_PRIMARY_LAUNCH_ALL_APPS: if (DEBUG_INPUT) { Slog.d(TAG, "Executing stem primary short press action behavior."); } final boolean keyguardActive = mKeyguardDelegate != null && mKeyguardDelegate.isShowing(); if (!keyguardActive) { Intent intent = new Intent(Intent.ACTION_ALL_APPS); intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED); startActivityAsUser(intent, UserHandle.CURRENT_OR_SELF); } break; } } private void stemPrimaryDoublePressAction(int behavior) { switch (behavior) { case DOUBLE_PRESS_PRIMARY_NOTHING: break; case DOUBLE_PRESS_PRIMARY_SWITCH_RECENT_APP: if (DEBUG_INPUT) { Slog.d(TAG, "Executing stem primary double press action behavior."); } final boolean keyguardActive = mKeyguardDelegate == null ? false : mKeyguardDelegate.isShowing(); if (!keyguardActive) { switchRecentTask(); } break; } } private void stemPrimaryTriplePressAction(int behavior) { switch (behavior) { case TRIPLE_PRESS_PRIMARY_NOTHING: break; case TRIPLE_PRESS_PRIMARY_TOGGLE_ACCESSIBILITY: if (DEBUG_INPUT) { Slog.d(TAG, "Executing stem primary triple press action behavior."); } toggleTalkBack(); break; } } private void stemPrimaryLongPress() { if (DEBUG_INPUT) { Slog.d(TAG, "Executing stem primary long press action behavior."); } switch (mLongPressOnStemPrimaryBehavior) { case LONG_PRESS_PRIMARY_NOTHING: break; case LONG_PRESS_PRIMARY_LAUNCH_VOICE_ASSISTANT: launchVoiceAssist(/* allowDuringSetup= */false); break; } } private void toggleTalkBack() { final ComponentName componentName = getTalkbackComponent(); if (componentName == null) { return; } final Set<ComponentName> enabledServices = AccessibilityUtils.getEnabledServicesFromSettings(mContext, mCurrentUserId); AccessibilityUtils.setAccessibilityServiceState(mContext, componentName, !enabledServices.contains(componentName)); } private ComponentName getTalkbackComponent() { AccessibilityManager accessibilityManager = mContext.getSystemService( AccessibilityManager.class); List<AccessibilityServiceInfo> serviceInfos = accessibilityManager.getInstalledAccessibilityServiceList(); for (AccessibilityServiceInfo service : serviceInfos) { final ServiceInfo serviceInfo = service.getResolveInfo().serviceInfo; if (isTalkback(serviceInfo)) { return new ComponentName(serviceInfo.packageName, serviceInfo.name); } } return null; } private boolean isTalkback(ServiceInfo info) { String label = info.loadLabel(mPackageManager).toString(); return label.equals(TALKBACK_LABEL); } /** * Load most recent task (expect current task) and bring it to the front. */ private void switchRecentTask() { RecentTaskInfo targetTask = mActivityTaskManagerInternal.getMostRecentTaskFromBackground(); if (targetTask == null) { if (DEBUG_INPUT) { Slog.w(TAG, "No recent task available! Show watch face."); } goHome(); return; } if (DEBUG_INPUT) { Slog.d( TAG, "Starting task from recents. id=" + targetTask.id + ", persistentId=" + targetTask.persistentId + ", topActivity=" + targetTask.topActivity + ", baseIntent=" + targetTask.baseIntent); } try { ActivityManager.getService().startActivityFromRecents(targetTask.persistentId, null); } catch (RemoteException e) { Slog.e(TAG, "Failed to start task " + targetTask.persistentId + " from recents", e); } } private int getMaxMultiPressStemPrimaryCount() { switch (mTriplePressOnStemPrimaryBehavior) { case TRIPLE_PRESS_PRIMARY_NOTHING: break; case TRIPLE_PRESS_PRIMARY_TOGGLE_ACCESSIBILITY: if (Settings.System.getIntForUser( mContext.getContentResolver(), Settings.System.WEAR_ACCESSIBILITY_GESTURE_ENABLED, /* def= */ 0, UserHandle.USER_CURRENT) == 1) { return 3; } break; } if (mDoublePressOnStemPrimaryBehavior != DOUBLE_PRESS_PRIMARY_NOTHING) { return 2; } return 1; } private boolean hasLongPressOnPowerBehavior() { return getResolvedLongPressOnPowerBehavior() != LONG_PRESS_POWER_NOTHING; } Loading @@ -1204,6 +1396,16 @@ public class PhoneWindowManager implements WindowManagerPolicy { return mLongPressOnBackBehavior != LONG_PRESS_BACK_NOTHING; } private boolean hasLongPressOnStemPrimaryBehavior() { return mLongPressOnStemPrimaryBehavior != LONG_PRESS_PRIMARY_NOTHING; } private boolean hasStemPrimaryBehavior() { return getMaxMultiPressStemPrimaryCount() > 1 || hasLongPressOnStemPrimaryBehavior() || mShortPressOnStemPrimaryBehavior != SHORT_PRESS_PRIMARY_NOTHING; } private void interceptScreenshotChord() { mHandler.removeCallbacks(mScreenshotRunnable); mScreenshotRunnable.setScreenshotType(TAKE_SCREENSHOT_FULLSCREEN); Loading Loading @@ -2037,6 +2239,35 @@ public class PhoneWindowManager implements WindowManagerPolicy { } } /** * Rule for single stem primary key gesture. */ private final class StemPrimaryKeyRule extends SingleKeyGestureDetector.SingleKeyRule { StemPrimaryKeyRule(int gestures) { super(mContext, KeyEvent.KEYCODE_STEM_PRIMARY, gestures); } @Override int getMaxMultiPressCount() { return getMaxMultiPressStemPrimaryCount(); } @Override void onPress(long downTime) { stemPrimaryPress(1 /*count*/); } @Override void onLongPress(long eventTime) { stemPrimaryLongPress(); } @Override void onMultiPress(long downTime, int count) { stemPrimaryPress(count); } } private void initSingleKeyGestureRules() { mSingleKeyGestureDetector = new SingleKeyGestureDetector(); Loading @@ -2052,6 +2283,13 @@ public class PhoneWindowManager implements WindowManagerPolicy { if (hasLongPressOnBackBehavior()) { mSingleKeyGestureDetector.addRule(new BackKeyRule(KEY_LONGPRESS)); } if (hasStemPrimaryBehavior()) { int stemPrimaryKeyGestures = 0; if (hasLongPressOnStemPrimaryBehavior()) { stemPrimaryKeyGestures |= KEY_LONGPRESS; } mSingleKeyGestureDetector.addRule(new StemPrimaryKeyRule(stemPrimaryKeyGestures)); } } /** Loading Loading @@ -2080,6 +2318,14 @@ public class PhoneWindowManager implements WindowManagerPolicy { if (mPackageManager.hasSystemFeature(FEATURE_PICTURE_IN_PICTURE)) { mShortPressOnWindowBehavior = SHORT_PRESS_WINDOW_PICTURE_IN_PICTURE; } mShortPressOnStemPrimaryBehavior = mContext.getResources().getInteger( com.android.internal.R.integer.config_shortPressOnStemPrimaryBehavior); mLongPressOnStemPrimaryBehavior = mContext.getResources().getInteger( com.android.internal.R.integer.config_longPressOnStemPrimaryBehavior); mDoublePressOnStemPrimaryBehavior = mContext.getResources().getInteger( com.android.internal.R.integer.config_doublePressOnStemPrimaryBehavior); mTriplePressOnStemPrimaryBehavior = mContext.getResources().getInteger( com.android.internal.R.integer.config_triplePressOnStemPrimaryBehavior); } public void updateSettings() { Loading Loading @@ -5380,6 +5626,22 @@ public class PhoneWindowManager implements WindowManagerPolicy { pw.print(prefix); pw.print("mShortPressOnWindowBehavior="); pw.println(shortPressOnWindowBehaviorToString(mShortPressOnWindowBehavior)); pw.print(prefix); pw.print("mShortPressOnStemPrimaryBehavior="); pw.println(shortPressOnStemPrimaryBehaviorToString( mShortPressOnStemPrimaryBehavior)); pw.print(prefix); pw.print("mDoublePressOnStemPrimaryBehavior="); pw.println(doublePressOnStemPrimaryBehaviorToString( mDoublePressOnStemPrimaryBehavior)); pw.print(prefix); pw.print("mTriplePressOnStemPrimaryBehavior="); pw.println(triplePressOnStemPrimaryBehaviorToString( mTriplePressOnStemPrimaryBehavior)); pw.print(prefix); pw.print("mLongPressOnStemPrimaryBehavior="); pw.println(longPressOnStemPrimaryBehaviorToString( mLongPressOnStemPrimaryBehavior)); pw.print(prefix); pw.print("mAllowStartActivityForLongPressOnPowerDuringSetup="); pw.println(mAllowStartActivityForLongPressOnPowerDuringSetup); Loading Loading @@ -5596,6 +5858,50 @@ public class PhoneWindowManager implements WindowManagerPolicy { } } private static String shortPressOnStemPrimaryBehaviorToString(int behavior) { switch (behavior) { case SHORT_PRESS_PRIMARY_NOTHING: return "SHORT_PRESS_PRIMARY_NOTHING"; case SHORT_PRESS_PRIMARY_LAUNCH_ALL_APPS: return "SHORT_PRESS_PRIMARY_LAUNCH_ALL_APPS"; default: return Integer.toString(behavior); } } private static String doublePressOnStemPrimaryBehaviorToString(int behavior) { switch (behavior) { case DOUBLE_PRESS_PRIMARY_NOTHING: return "DOUBLE_PRESS_PRIMARY_NOTHING"; case DOUBLE_PRESS_PRIMARY_SWITCH_RECENT_APP: return "DOUBLE_PRESS_PRIMARY_SWITCH_RECENT_APP"; default: return Integer.toString(behavior); } } private static String triplePressOnStemPrimaryBehaviorToString(int behavior) { switch (behavior) { case TRIPLE_PRESS_PRIMARY_NOTHING: return "TRIPLE_PRESS_PRIMARY_NOTHING"; case TRIPLE_PRESS_PRIMARY_TOGGLE_ACCESSIBILITY: return "TRIPLE_PRESS_PRIMARY_TOGGLE_ACCESSIBILITY"; default: return Integer.toString(behavior); } } private static String longPressOnStemPrimaryBehaviorToString(int behavior) { switch (behavior) { case LONG_PRESS_PRIMARY_NOTHING: return "LONG_PRESS_PRIMARY_NOTHING"; case LONG_PRESS_PRIMARY_LAUNCH_VOICE_ASSISTANT: return "LONG_PRESS_PRIMARY_LAUNCH_VOICE_ASSISTANT"; default: return Integer.toString(behavior); } } private static String lidBehaviorToString(int behavior) { switch (behavior) { case LID_BEHAVIOR_LOCK: Loading
services/core/java/com/android/server/policy/SingleKeyGestureDetector.java +5 −1 Original line number Diff line number Diff line Loading @@ -53,6 +53,7 @@ public final class SingleKeyGestureDetector { // Key code of current key down event, reset when key up. private int mDownKeyCode = KeyEvent.KEYCODE_UNKNOWN; private volatile boolean mHandledByLongPress = false; private volatile boolean mHandledByMultiPress = false; private final Handler mHandler; private long mLastDownTime = 0; private static final long MULTI_PRESS_TIMEOUT = ViewConfiguration.getMultiPressTimeout(); Loading Loading @@ -271,6 +272,7 @@ public final class SingleKeyGestureDetector { mKeyPressCounter + 1, mActiveRule); msg.setAsynchronous(true); mHandler.sendMessage(msg); mHandledByMultiPress = true; mKeyPressCounter = 0; } } Loading @@ -284,8 +286,9 @@ public final class SingleKeyGestureDetector { return false; } if (mHandledByLongPress) { if (mHandledByLongPress || mHandledByMultiPress) { mHandledByLongPress = false; mHandledByMultiPress = false; mKeyPressCounter = 0; return true; } Loading Loading @@ -339,6 +342,7 @@ public final class SingleKeyGestureDetector { } mHandledByLongPress = false; mHandledByMultiPress = false; mDownKeyCode = KeyEvent.KEYCODE_UNKNOWN; } Loading
services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java +4 −0 Original line number Diff line number Diff line Loading @@ -19,6 +19,7 @@ package com.android.server.wm; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.UserIdInt; import android.app.ActivityManager; import android.app.AppProtoEnums; import android.app.IActivityManager; import android.app.IApplicationThread; Loading Loading @@ -688,4 +689,7 @@ public abstract class ActivityTaskManagerInternal { public abstract void registerActivityStartInterceptor( @ActivityInterceptorCallback.OrderedId int id, ActivityInterceptorCallback callback); /** Get the most recent task excluding the first running task (the one on the front most). */ public abstract ActivityManager.RecentTaskInfo getMostRecentTaskFromBackground(); }