Merge changes from topic "wear_stem_upstream" into main
* changes:
Use status bar to launch assistant.
Add a new button behavior for STEM short press
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 23336d4..281053b 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -1210,13 +1210,16 @@
<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
+ 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
+ 2 - Launch target activity defined by config_primaryShortPressTargetActivity if available
-->
<integer name="config_shortPressOnStemPrimaryBehavior">0</integer>
+ <!-- Activity name for the default target activity to be launched. [DO NOT TRANSLATE] -->
+ <string name="config_primaryShortPressTargetActivity" translatable="false"></string>
<!-- Control the behavior of the search key.
0 - Launch default search activity
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 8330f7b..aa0cbfa 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -466,6 +466,7 @@
<java-symbol type="integer" name="config_shortPressOnSleepBehavior" />
<java-symbol type="integer" name="config_longPressOnStemPrimaryBehavior" />
<java-symbol type="integer" name="config_shortPressOnStemPrimaryBehavior" />
+ <java-symbol type="string" name="config_primaryShortPressTargetActivity" />
<java-symbol type="integer" name="config_doublePressOnStemPrimaryBehavior" />
<java-symbol type="integer" name="config_triplePressOnStemPrimaryBehavior" />
<java-symbol type="string" name="config_doublePressOnPowerTargetActivity" />
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 2f68021..b3aa09b 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -29,6 +29,7 @@
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.os.Build.VERSION_CODES.M;
import static android.os.Build.VERSION_CODES.O;
+import static android.os.IInputConstants.INVALID_INPUT_DEVICE_ID;
import static android.provider.Settings.Secure.VOLUME_HUSH_OFF;
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.Display.INVALID_DISPLAY;
@@ -338,6 +339,7 @@
// The config value can be overridden using Settings.Global.STEM_PRIMARY_BUTTON_SHORT_PRESS
static final int SHORT_PRESS_PRIMARY_NOTHING = 0;
static final int SHORT_PRESS_PRIMARY_LAUNCH_ALL_APPS = 1;
+ static final int SHORT_PRESS_PRIMARY_LAUNCH_TARGET_ACTIVITY = 2;
// Must match: config_longPressOnStemPrimaryBehavior in config.xml
// The config value can be overridden using Settings.Global.STEM_PRIMARY_BUTTON_LONG_PRESS
@@ -609,6 +611,9 @@
// What we do when the user double-taps on home
private int mDoubleTapOnHomeBehavior;
+ // Must match config_primaryShortPressTargetActivity in config.xml
+ ComponentName mPrimaryShortPressTargetActivity;
+
// Whether to lock the device after the next dreaming transition has finished.
private boolean mLockAfterDreamingTransitionFinished;
@@ -1374,7 +1379,7 @@
mPowerKeyHandled = true;
performHapticFeedback(HapticFeedbackConstants.ASSISTANT_BUTTON, false,
"Power - Long Press - Go To Assistant");
- final int powerKeyDeviceId = Integer.MIN_VALUE;
+ final int powerKeyDeviceId = INVALID_INPUT_DEVICE_ID;
launchAssistAction(null, powerKeyDeviceId, eventTime,
AssistUtils.INVOCATION_TYPE_POWER_BUTTON_LONG_PRESS);
break;
@@ -1461,23 +1466,59 @@
}
private void stemPrimarySinglePressAction(int behavior) {
+ if (DEBUG_INPUT) {
+ Slog.d(TAG, "stemPrimarySinglePressAction: behavior=" + behavior);
+ }
+ if (behavior == SHORT_PRESS_PRIMARY_NOTHING) return;
+
+ final boolean keyguardActive = mKeyguardDelegate != null && mKeyguardDelegate.isShowing();
+ if (keyguardActive) {
+ // If keyguarded then notify the keyguard.
+ mKeyguardDelegate.onSystemKeyPressed(KeyEvent.KEYCODE_STEM_PRIMARY);
+ return;
+ }
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);
+ Intent allAppsIntent = new Intent(Intent.ACTION_ALL_APPS);
+ allAppsIntent.addFlags(
+ Intent.FLAG_ACTIVITY_NEW_TASK
+ | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
+ startActivityAsUser(allAppsIntent, UserHandle.CURRENT_OR_SELF);
+ break;
+ case SHORT_PRESS_PRIMARY_LAUNCH_TARGET_ACTIVITY:
+ if (DEBUG_INPUT) {
+ Slog.d(
+ TAG,
+ "Executing stem primary short press action behavior for launching "
+ + "target activity.");
+ }
+ if (mPrimaryShortPressTargetActivity != null) {
+ Intent targetActivityIntent = new Intent();
+ targetActivityIntent.setComponent(mPrimaryShortPressTargetActivity);
+ ResolveInfo resolveInfo =
+ mContext.getPackageManager()
+ .resolveActivity(targetActivityIntent, /* flags= */ 0);
+ if (resolveInfo != null) {
+ targetActivityIntent.addFlags(
+ Intent.FLAG_ACTIVITY_NEW_TASK
+ | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
+ | Intent.FLAG_ACTIVITY_TASK_ON_HOME);
+ startActivityAsUser(targetActivityIntent, UserHandle.CURRENT_OR_SELF);
+ } else {
+ Slog.wtf(
+ TAG,
+ "Could not resolve activity with : "
+ + mPrimaryShortPressTargetActivity.flattenToString()
+ + " name.");
+ }
} else {
- // If keyguarded then notify the keyguard.
- mKeyguardDelegate.onSystemKeyPressed(KeyEvent.KEYCODE_STEM_PRIMARY);
+ Slog.wtf(
+ TAG,
+ "mPrimaryShortPressTargetActivity must not be null and correctly"
+ + " specified");
}
break;
}
@@ -1527,7 +1568,7 @@
}
}
- private void stemPrimaryLongPress() {
+ private void stemPrimaryLongPress(long eventTime) {
if (DEBUG_INPUT) {
Slog.d(TAG, "Executing stem primary long press action behavior.");
}
@@ -1536,7 +1577,12 @@
case LONG_PRESS_PRIMARY_NOTHING:
break;
case LONG_PRESS_PRIMARY_LAUNCH_VOICE_ASSISTANT:
- launchVoiceAssist(/* allowDuringSetup= */false);
+ final int stemPrimaryKeyDeviceId = INVALID_INPUT_DEVICE_ID;
+ launchAssistAction(
+ null,
+ stemPrimaryKeyDeviceId,
+ eventTime,
+ AssistUtils.INVOCATION_TYPE_UNKNOWN);
break;
}
}
@@ -2159,6 +2205,7 @@
mPowerManagerInternal = LocalServices.getService(PowerManagerInternal.class);
mAppOpsManager = mContext.getSystemService(AppOpsManager.class);
mSensorPrivacyManager = mContext.getSystemService(SensorPrivacyManager.class);
+ mSearchManager = mContext.getSystemService(SearchManager.class);
mDisplayManager = mContext.getSystemService(DisplayManager.class);
mDisplayManagerInternal = LocalServices.getService(DisplayManagerInternal.class);
mUserManagerInternal = LocalServices.getService(UserManagerInternal.class);
@@ -2295,6 +2342,9 @@
mPowerDoublePressTargetActivity = ComponentName.unflattenFromString(
mContext.getResources().getString(
com.android.internal.R.string.config_doublePressOnPowerTargetActivity));
+ mPrimaryShortPressTargetActivity = ComponentName.unflattenFromString(
+ mContext.getResources().getString(
+ com.android.internal.R.string.config_primaryShortPressTargetActivity));
mShortPressOnSleepBehavior = mContext.getResources().getInteger(
com.android.internal.R.integer.config_shortPressOnSleepBehavior);
mAllowStartActivityForLongPressOnPowerDuringSetup = mContext.getResources().getBoolean(
@@ -2658,7 +2708,7 @@
@Override
void onLongPress(long eventTime) {
- stemPrimaryLongPress();
+ stemPrimaryLongPress(eventTime);
}
@Override
@@ -3905,7 +3955,7 @@
// Add Intent Extra data.
Bundle args = null;
args = new Bundle();
- if (deviceId > Integer.MIN_VALUE) {
+ if (deviceId != INVALID_INPUT_DEVICE_ID) {
args.putInt(Intent.EXTRA_ASSIST_INPUT_DEVICE_ID, deviceId);
}
if (hint != null) {
@@ -3914,8 +3964,15 @@
args.putLong(Intent.EXTRA_TIME, eventTime);
args.putInt(AssistUtils.INVOCATION_TYPE_KEY, invocationType);
- ((SearchManager) mContext.createContextAsUser(UserHandle.of(mCurrentUserId), 0)
- .getSystemService(Context.SEARCH_SERVICE)).launchAssist(args);
+ if (mSearchManager != null) {
+ mSearchManager.launchAssist(args);
+ } else {
+ // Fallback to status bar if search manager doesn't exist (e.g. on wear).
+ StatusBarManagerInternal statusBar = getStatusBarManagerInternal();
+ if (statusBar != null) {
+ statusBar.startAssist(args);
+ }
+ }
}
/**
@@ -3926,39 +3983,16 @@
final boolean keyguardActive =
mKeyguardDelegate != null && mKeyguardDelegate.isShowing();
if (!keyguardActive) {
- if (mHasFeatureWatch && isInRetailMode()) {
- launchRetailVoiceAssist(allowDuringSetup);
- } else {
- startVoiceAssistIntent(allowDuringSetup);
- }
+ startActivityAsUser(
+ new Intent(Intent.ACTION_VOICE_ASSIST),
+ /* bundle= */ null,
+ UserHandle.CURRENT_OR_SELF,
+ allowDuringSetup);
} else {
mKeyguardDelegate.dismissKeyguardToLaunch(new Intent(Intent.ACTION_VOICE_ASSIST));
}
}
- private void launchRetailVoiceAssist(boolean allowDuringSetup) {
- Intent retailIntent = new Intent(ACTION_VOICE_ASSIST_RETAIL);
- ResolveInfo resolveInfo = mContext.getPackageManager().resolveActivity(
- retailIntent, /* flags= */0);
- if (resolveInfo != null) {
- retailIntent.setComponent(
- new ComponentName(resolveInfo.activityInfo.packageName,
- resolveInfo.activityInfo.name));
- startActivityAsUser(retailIntent, null, UserHandle.CURRENT_OR_SELF,
- allowDuringSetup);
- } else {
- Slog.w(TAG, "Couldn't find an app to process " + ACTION_VOICE_ASSIST_RETAIL
- + ". Fall back to start " + Intent.ACTION_VOICE_ASSIST);
- startVoiceAssistIntent(allowDuringSetup);
- }
- }
-
- private void startVoiceAssistIntent(boolean allowDuringSetup) {
- Intent intent = new Intent(Intent.ACTION_VOICE_ASSIST);
- startActivityAsUser(intent, null, UserHandle.CURRENT_OR_SELF,
- allowDuringSetup);
- }
-
private boolean isInRetailMode() {
return Settings.Global.getInt(mContext.getContentResolver(),
Settings.Global.DEVICE_DEMO_MODE, 0) == 1;
@@ -3981,13 +4015,6 @@
}
}
- private SearchManager getSearchManager() {
- if (mSearchManager == null) {
- mSearchManager = (SearchManager) mContext.getSystemService(Context.SEARCH_SERVICE);
- }
- return mSearchManager;
- }
-
private void preloadRecentApps() {
mPreloadedRecentApps = true;
StatusBarManagerInternal statusbar = getStatusBarManagerInternal();
@@ -6471,6 +6498,8 @@
return "SHORT_PRESS_PRIMARY_NOTHING";
case SHORT_PRESS_PRIMARY_LAUNCH_ALL_APPS:
return "SHORT_PRESS_PRIMARY_LAUNCH_ALL_APPS";
+ case SHORT_PRESS_PRIMARY_LAUNCH_TARGET_ACTIVITY:
+ return "SHORT_PRESS_PRIMARY_LAUNCH_TARGET_ACTIVITY";
default:
return Integer.toString(behavior);
}
diff --git a/services/tests/wmtests/src/com/android/server/policy/PowerKeyGestureTests.java b/services/tests/wmtests/src/com/android/server/policy/PowerKeyGestureTests.java
index 6f65406..05a1482 100644
--- a/services/tests/wmtests/src/com/android/server/policy/PowerKeyGestureTests.java
+++ b/services/tests/wmtests/src/com/android/server/policy/PowerKeyGestureTests.java
@@ -112,7 +112,7 @@
// Show assistant.
mPhoneWindowManager.overrideLongPressOnPower(LONG_PRESS_POWER_ASSISTANT);
sendKey(KEYCODE_POWER, true);
- mPhoneWindowManager.assertAssistLaunch();
+ mPhoneWindowManager.assertSearchManagerLaunchAssist();
// Show global actions.
mPhoneWindowManager.overrideLongPressOnPower(LONG_PRESS_POWER_GLOBAL_ACTIONS);
diff --git a/services/tests/wmtests/src/com/android/server/policy/StemKeyGestureTests.java b/services/tests/wmtests/src/com/android/server/policy/StemKeyGestureTests.java
index c433e64..eab8757 100644
--- a/services/tests/wmtests/src/com/android/server/policy/StemKeyGestureTests.java
+++ b/services/tests/wmtests/src/com/android/server/policy/StemKeyGestureTests.java
@@ -16,11 +16,15 @@
package com.android.server.policy;
+import static android.provider.Settings.Global.STEM_PRIMARY_BUTTON_LONG_PRESS;
import static android.provider.Settings.Global.STEM_PRIMARY_BUTTON_SHORT_PRESS;
import static android.view.KeyEvent.KEYCODE_STEM_PRIMARY;
+import static com.android.server.policy.PhoneWindowManager.LONG_PRESS_PRIMARY_LAUNCH_VOICE_ASSISTANT;
import static com.android.server.policy.PhoneWindowManager.SHORT_PRESS_PRIMARY_LAUNCH_ALL_APPS;
+import static com.android.server.policy.PhoneWindowManager.SHORT_PRESS_PRIMARY_LAUNCH_TARGET_ACTIVITY;
+import android.content.ComponentName;
import android.provider.Settings;
import org.junit.Test;
@@ -32,6 +36,9 @@
* atest WmTests:StemKeyGestureTests
*/
public class StemKeyGestureTests extends ShortcutKeyTestBase {
+
+ private static final String TEST_TARGET_ACTIVITY = "com.android.server.policy/.TestActivity";
+
/**
* Stem single key should not launch behavior during set up.
*/
@@ -63,6 +70,57 @@
mPhoneWindowManager.assertOpenAllAppView();
}
+ /**
+ * Stem single key should not launch behavior during set up.
+ */
+ @Test
+ public void stemSingleKey_launchTargetActivity() {
+ overrideBehavior(
+ STEM_PRIMARY_BUTTON_SHORT_PRESS,
+ SHORT_PRESS_PRIMARY_LAUNCH_TARGET_ACTIVITY);
+ setUpPhoneWindowManager(/* supportSettingsUpdate= */ true);
+ mPhoneWindowManager.overrideStartActivity();
+ mPhoneWindowManager.setKeyguardServiceDelegateIsShowing(false);
+ mPhoneWindowManager.overrideIsUserSetupComplete(true);
+ mPhoneWindowManager.assumeResolveActivityNotNull();
+
+ ComponentName targetComponent = ComponentName.unflattenFromString(TEST_TARGET_ACTIVITY);
+ mPhoneWindowManager.overrideStemPressTargetActivity(targetComponent);
+
+ sendKey(KEYCODE_STEM_PRIMARY);
+
+ mPhoneWindowManager.assertActivityTargetLaunched(targetComponent);
+ }
+
+ @Test
+ public void stemLongKey_triggerSearchServiceToLaunchAssist() {
+ overrideBehavior(
+ STEM_PRIMARY_BUTTON_LONG_PRESS,
+ LONG_PRESS_PRIMARY_LAUNCH_VOICE_ASSISTANT);
+ setUpPhoneWindowManager(/* supportSettingsUpdate= */ true);
+ mPhoneWindowManager.setupAssistForLaunch();
+ mPhoneWindowManager.overrideIsUserSetupComplete(true);
+
+ sendKey(KEYCODE_STEM_PRIMARY, /* longPress= */ true);
+ mPhoneWindowManager.assertSearchManagerLaunchAssist();
+ }
+
+ @Test
+ public void stemLongKey_whenNoSearchService_triggerStatusBarToStartAssist() {
+ overrideBehavior(
+ STEM_PRIMARY_BUTTON_LONG_PRESS,
+ LONG_PRESS_PRIMARY_LAUNCH_VOICE_ASSISTANT);
+ setUpPhoneWindowManager(/* supportSettingsUpdate= */ true);
+ mPhoneWindowManager.setupAssistForLaunch();
+ mPhoneWindowManager.overrideSearchManager(null);
+ mPhoneWindowManager.overrideStatusBarManagerInternal();
+ mPhoneWindowManager.overrideIsUserSetupComplete(true);
+
+ sendKey(KEYCODE_STEM_PRIMARY, /* longPress= */ true);
+ mPhoneWindowManager.assertStatusBarStartAssist();
+ }
+
+
private void overrideBehavior(String key, int expectedBehavior) {
Settings.Global.putLong(mContext.getContentResolver(), key, expectedBehavior);
}
diff --git a/services/tests/wmtests/src/com/android/server/policy/TestPhoneWindowManager.java b/services/tests/wmtests/src/com/android/server/policy/TestPhoneWindowManager.java
index ef3a6ed..bc8f06a 100644
--- a/services/tests/wmtests/src/com/android/server/policy/TestPhoneWindowManager.java
+++ b/services/tests/wmtests/src/com/android/server/policy/TestPhoneWindowManager.java
@@ -59,9 +59,11 @@
import android.app.AppOpsManager;
import android.app.NotificationManager;
import android.app.SearchManager;
+import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
import android.hardware.SensorPrivacyManager;
import android.hardware.display.DisplayManager;
import android.hardware.display.DisplayManagerInternal;
@@ -230,6 +232,7 @@
doReturn(mPackageManager).when(mContext).getPackageManager();
doReturn(mSensorPrivacyManager).when(mContext).getSystemService(
eq(SensorPrivacyManager.class));
+ doReturn(mSearchManager).when(mContext).getSystemService(eq(SearchManager.class));
doReturn(false).when(mPackageManager).hasSystemFeature(any());
try {
doThrow(new PackageManager.NameNotFoundException("test")).when(mPackageManager)
@@ -355,11 +358,7 @@
case LONG_PRESS_POWER_GO_TO_VOICE_ASSIST:
break;
case LONG_PRESS_POWER_ASSISTANT:
- doNothing().when(mPhoneWindowManager).sendCloseSystemWindows();
- doReturn(true).when(mPhoneWindowManager).isUserSetupComplete();
- doReturn(mContext).when(mContext).createContextAsUser(any(), anyInt());
- doReturn(mSearchManager).when(mContext)
- .getSystemService(eq(Context.SEARCH_SERVICE));
+ setupAssistForLaunch();
mPhoneWindowManager.mLongPressOnPowerAssistantTimeoutMs = 500;
break;
}
@@ -433,6 +432,22 @@
doReturn(isShowing).when(mKeyguardServiceDelegate).isShowing();
}
+ void setupAssistForLaunch() {
+ doNothing().when(mPhoneWindowManager).sendCloseSystemWindows();
+ doReturn(true).when(mPhoneWindowManager).isUserSetupComplete();
+ doReturn(mContext).when(mContext).createContextAsUser(any(), anyInt());
+ }
+
+ void overrideSearchManager(SearchManager searchManager) {
+ mPhoneWindowManager.mSearchManager = searchManager;
+ }
+
+ void assumeResolveActivityNotNull() {
+ ResolveInfo resolveInfo = new ResolveInfo();
+ doReturn(resolveInfo).when(mPackageManager).resolveActivity(any(), anyInt());
+ doReturn(mPackageManager).when(mContext).getPackageManager();
+ }
+
void overrideKeyEventSource(int vendorId, int productId) {
InputDevice device = new InputDevice.Builder().setId(1).setVendorId(vendorId).setProductId(
productId).setSources(InputDevice.SOURCE_KEYBOARD).setKeyboardType(
@@ -458,6 +473,10 @@
doReturn(true).when(mPhoneWindowManager).isUserSetupComplete();
}
+ void overrideStemPressTargetActivity(ComponentName component) {
+ mPhoneWindowManager.mPrimaryShortPressTargetActivity = component;
+ }
+
/**
* Below functions will check the policy behavior could be invoked.
*/
@@ -517,7 +536,7 @@
.interceptPowerKeyDown(any(), anyBoolean(), any());
}
- void assertAssistLaunch() {
+ void assertSearchManagerLaunchAssist() {
waitForIdle();
verify(mSearchManager, timeout(SHORTCUT_KEY_DELAY_MILLIS)).launchAssist(any());
}
@@ -540,6 +559,11 @@
verify(mStatusBarManagerInternal).showRecentApps(anyBoolean());
}
+ void assertStatusBarStartAssist() {
+ waitForIdle();
+ verify(mStatusBarManagerInternal).startAssist(any());
+ }
+
void assertSwitchKeyboardLayout(int direction) {
waitForIdle();
if (FeatureFlagUtils.isEnabled(mContext, FeatureFlagUtils.SETTINGS_NEW_KEYBOARD_UI)) {
@@ -613,6 +637,14 @@
.startActivityAsUser(any(Intent.class), any(), any(UserHandle.class));
}
+ void assertActivityTargetLaunched(ComponentName targetActivity) {
+ waitForIdle();
+ ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class);
+ verify(mContext, timeout(TEST_SINGLE_KEY_DELAY_MILLIS))
+ .startActivityAsUser(intentCaptor.capture(), isNull(), any(UserHandle.class));
+ Assert.assertEquals(targetActivity, intentCaptor.getValue().getComponent());
+ }
+
void assertShortcutLogged(int vendorId, int productId, KeyboardLogEvent logEvent,
int expectedKey, int expectedModifierState, String errorMsg) {
waitForIdle();