Defines flag to disable touch feedback on display

Define FLAG_TOUCH_FEEDBACK_DISABLED to disable touch sound and haptic feedback when creating virtual display.

Bug: 185558698
Test: atest FrameworksCoreTests:ViewRootImplTest, manual testing
Change-Id: Ida67f4027f2636e004218595b3bf088c06194522
This commit is contained in:
yuanjiahsu
2021-08-12 16:45:38 +08:00
committed by Yuanjia Hsu
parent d1263fb5ce
commit fc06fc5cb1
8 changed files with 98 additions and 1 deletions

View File

@@ -122,7 +122,8 @@ public final class DisplayManager {
VIRTUAL_DISPLAY_FLAG_SHOULD_SHOW_SYSTEM_DECORATIONS,
VIRTUAL_DISPLAY_FLAG_TRUSTED,
VIRTUAL_DISPLAY_FLAG_OWN_DISPLAY_GROUP,
VIRTUAL_DISPLAY_FLAG_ALWAYS_UNLOCKED
VIRTUAL_DISPLAY_FLAG_ALWAYS_UNLOCKED,
VIRTUAL_DISPLAY_FLAG_TOUCH_FEEDBACK_DISABLED
})
@Retention(RetentionPolicy.SOURCE)
public @interface VirtualDisplayFlag {}
@@ -379,6 +380,15 @@ public final class DisplayManager {
*/
public static final int VIRTUAL_DISPLAY_FLAG_ALWAYS_UNLOCKED = 1 << 12;
/**
* Virtual display flags: Indicates that the display should not play sound effects or perform
* haptic feedback when the user touches the screen.
*
* @see #createVirtualDisplay
* @hide
*/
public static final int VIRTUAL_DISPLAY_FLAG_TOUCH_FEEDBACK_DISABLED = 1 << 13;
/** @hide */
@IntDef(prefix = {"MATCH_CONTENT_FRAMERATE_"}, value = {
MATCH_CONTENT_FRAMERATE_UNKNOWN,

View File

@@ -308,6 +308,15 @@ public final class Display {
*/
public static final int FLAG_ALWAYS_UNLOCKED = 1 << 9;
/**
* Flag: Indicates that the display should not play sound effects or perform haptic feedback
* when the user touches the screen.
*
* @hide
* @see #getFlags()
*/
public static final int FLAG_TOUCH_FEEDBACK_DISABLED = 1 << 10;
/**
* Display flag: Indicates that the contents of the display should not be scaled
* to fit the physical screen dimensions. Used for development only to emulate

View File

@@ -865,6 +865,9 @@ public final class DisplayInfo implements Parcelable {
if ((flags & Display.FLAG_ALWAYS_UNLOCKED) != 0) {
result.append(", FLAG_ALWAYS_UNLOCKED");
}
if ((flags & Display.FLAG_TOUCH_FEEDBACK_DISABLED) != 0) {
result.append(", FLAG_TOUCH_FEEDBACK_DISABLED");
}
return result.toString();
}
}

View File

@@ -8200,6 +8200,10 @@ public final class ViewRootImpl implements ViewParent,
*/
@Override
public void playSoundEffect(@SoundEffectConstants.SoundEffect int effectId) {
if ((mDisplay.getFlags() & Display.FLAG_TOUCH_FEEDBACK_DISABLED) != 0) {
return;
}
checkThread();
try {
@@ -8248,6 +8252,10 @@ public final class ViewRootImpl implements ViewParent,
*/
@Override
public boolean performHapticFeedback(int effectId, boolean always) {
if ((mDisplay.getFlags() & Display.FLAG_TOUCH_FEEDBACK_DISABLED) != 0) {
return false;
}
try {
return mWindowSession.performHapticFeedback(effectId, always);
} catch (RemoteException e) {

View File

@@ -35,16 +35,19 @@ import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.Truth.assertWithMessage;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThrows;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import android.app.Instrumentation;
import android.content.Context;
import android.hardware.display.DisplayManagerGlobal;
import android.os.Binder;
import android.platform.test.annotations.Presubmit;
import android.view.WindowInsets.Side;
import android.view.WindowInsets.Type;
import androidx.test.annotation.UiThreadTest;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import androidx.test.platform.app.InstrumentationRegistry;
@@ -334,6 +337,55 @@ public class ViewRootImplTest {
}, false /*shouldReceiveKey*/);
}
@UiThreadTest
@Test
public void playSoundEffect_wrongEffectId_throwException() {
ViewRootImpl viewRootImpl = new ViewRootImpl(sContext,
sContext.getDisplayNoVerify());
View view = new View(sContext);
WindowManager.LayoutParams layoutParams = new WindowManager.LayoutParams(
TYPE_APPLICATION_OVERLAY);
layoutParams.token = new Binder();
view.setLayoutParams(layoutParams);
viewRootImpl.setView(view, layoutParams, /* panelParentView= */ null);
assertThrows(IllegalArgumentException.class,
() -> viewRootImpl.playSoundEffect(/* effectId= */ -1));
}
@UiThreadTest
@Test
public void playSoundEffect_wrongEffectId_touchFeedbackDisabled_doNothing() {
DisplayInfo displayInfo = new DisplayInfo();
displayInfo.flags = Display.FLAG_TOUCH_FEEDBACK_DISABLED;
Display display = new Display(DisplayManagerGlobal.getInstance(), /* displayId= */
0, displayInfo, new DisplayAdjustments());
ViewRootImpl viewRootImpl = new ViewRootImpl(sContext, display);
View view = new View(sContext);
WindowManager.LayoutParams layoutParams = new WindowManager.LayoutParams(
TYPE_APPLICATION_OVERLAY);
layoutParams.token = new Binder();
view.setLayoutParams(layoutParams);
viewRootImpl.setView(view, layoutParams, /* panelParentView= */ null);
viewRootImpl.playSoundEffect(/* effectId= */ -1);
}
@UiThreadTest
@Test
public void performHapticFeedback_touchFeedbackDisabled_doNothing() {
DisplayInfo displayInfo = new DisplayInfo();
displayInfo.flags = Display.FLAG_TOUCH_FEEDBACK_DISABLED;
Display display = new Display(DisplayManagerGlobal.getInstance(), /* displayId= */
0, displayInfo, new DisplayAdjustments());
ViewRootImpl viewRootImpl = new ViewRootImpl(sContext, display);
boolean result = viewRootImpl.performHapticFeedback(
HapticFeedbackConstants.CONTEXT_CLICK, true);
assertThat(result).isFalse();
}
class KeyView extends View {
KeyView(Context context) {
super(context);

View File

@@ -149,6 +149,13 @@ final class DisplayDeviceInfo {
*/
public static final int FLAG_ALWAYS_UNLOCKED = 1 << 15;
/**
* Flag: Indicates that the display should not play sound effects or perform haptic feedback
* when the user touches the screen.
*
* @hide
*/
public static final int FLAG_TOUCH_FEEDBACK_DISABLED = 1 << 16;
/**
* Touch attachment: Display does not receive touch.

View File

@@ -381,6 +381,9 @@ final class LogicalDisplay {
if ((deviceInfo.flags & DisplayDeviceInfo.FLAG_ALWAYS_UNLOCKED) != 0) {
mBaseDisplayInfo.flags |= Display.FLAG_ALWAYS_UNLOCKED;
}
if ((deviceInfo.flags & DisplayDeviceInfo.FLAG_TOUCH_FEEDBACK_DISABLED) != 0) {
mBaseDisplayInfo.flags |= Display.FLAG_TOUCH_FEEDBACK_DISABLED;
}
Rect maskingInsets = getMaskingInsets(deviceInfo);
int maskedWidth = deviceInfo.width - maskingInsets.left - maskingInsets.right;
int maskedHeight = deviceInfo.height - maskingInsets.top - maskingInsets.bottom;

View File

@@ -27,10 +27,12 @@ import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_ROTAT
import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_SECURE;
import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_SHOULD_SHOW_SYSTEM_DECORATIONS;
import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_SUPPORTS_TOUCH;
import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_TOUCH_FEEDBACK_DISABLED;
import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_TRUSTED;
import static com.android.server.display.DisplayDeviceInfo.FLAG_ALWAYS_UNLOCKED;
import static com.android.server.display.DisplayDeviceInfo.FLAG_OWN_DISPLAY_GROUP;
import static com.android.server.display.DisplayDeviceInfo.FLAG_TOUCH_FEEDBACK_DISABLED;
import static com.android.server.display.DisplayDeviceInfo.FLAG_TRUSTED;
import android.content.Context;
@@ -457,6 +459,9 @@ public class VirtualDisplayAdapter extends DisplayAdapter {
&& (mInfo.flags & DisplayDeviceInfo.FLAG_OWN_DISPLAY_GROUP) != 0) {
mInfo.flags |= FLAG_ALWAYS_UNLOCKED;
}
if ((mFlags & VIRTUAL_DISPLAY_FLAG_TOUCH_FEEDBACK_DISABLED) != 0) {
mInfo.flags |= FLAG_TOUCH_FEEDBACK_DISABLED;
}
mInfo.type = Display.TYPE_VIRTUAL;
mInfo.touch = ((mFlags & VIRTUAL_DISPLAY_FLAG_SUPPORTS_TOUCH) == 0) ?