Merge "Register VibrationSettings as a listener to: 1) virtual displays creation and removal. 2) App Uids running on virtual displays. These will be used in combination to ignore vibration initiated from a virtual display." into tm-qpr-dev
This commit is contained in:
@@ -30,7 +30,7 @@ interface IVibratorManagerService {
|
||||
boolean unregisterVibratorStateListener(int vibratorId, in IVibratorStateListener listener);
|
||||
boolean setAlwaysOnEffect(int uid, String opPkg, int alwaysOnId,
|
||||
in CombinedVibration vibration, in VibrationAttributes attributes);
|
||||
void vibrate(int uid, String opPkg, in CombinedVibration vibration,
|
||||
void vibrate(int uid, int displayId, String opPkg, in CombinedVibration vibration,
|
||||
in VibrationAttributes attributes, String reason, IBinder token);
|
||||
void cancelVibrate(int usageFilter, IBinder token);
|
||||
}
|
||||
|
||||
@@ -137,7 +137,8 @@ public class SystemVibratorManager extends VibratorManager {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
mService.vibrate(uid, opPkg, effect, attributes, reason, mToken);
|
||||
mService.vibrate(uid, mContext.getAssociatedDisplayId(), opPkg, effect, attributes,
|
||||
reason, mToken);
|
||||
} catch (RemoteException e) {
|
||||
Log.w(TAG, "Failed to vibrate.", e);
|
||||
}
|
||||
|
||||
@@ -127,6 +127,7 @@ message VibrationProto {
|
||||
IGNORED_FOR_RINGER_MODE = 23;
|
||||
IGNORED_FOR_SETTINGS = 24;
|
||||
IGNORED_SUPERSEDED = 25;
|
||||
IGNORED_FROM_VIRTUAL_DEVICE = 26;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -71,7 +71,8 @@ final class Vibration {
|
||||
IGNORED_FOR_POWER(VibrationProto.IGNORED_FOR_POWER),
|
||||
IGNORED_FOR_RINGER_MODE(VibrationProto.IGNORED_FOR_RINGER_MODE),
|
||||
IGNORED_FOR_SETTINGS(VibrationProto.IGNORED_FOR_SETTINGS),
|
||||
IGNORED_SUPERSEDED(VibrationProto.IGNORED_SUPERSEDED);
|
||||
IGNORED_SUPERSEDED(VibrationProto.IGNORED_SUPERSEDED),
|
||||
IGNORED_FROM_VIRTUAL_DEVICE(VibrationProto.IGNORED_FROM_VIRTUAL_DEVICE);
|
||||
|
||||
private final int mProtoEnumValue;
|
||||
|
||||
@@ -87,6 +88,7 @@ final class Vibration {
|
||||
public final VibrationAttributes attrs;
|
||||
public final long id;
|
||||
public final int uid;
|
||||
public final int displayId;
|
||||
public final String opPkg;
|
||||
public final String reason;
|
||||
public final IBinder token;
|
||||
@@ -113,12 +115,13 @@ final class Vibration {
|
||||
private final CountDownLatch mCompletionLatch = new CountDownLatch(1);
|
||||
|
||||
Vibration(IBinder token, int id, CombinedVibration effect,
|
||||
VibrationAttributes attrs, int uid, String opPkg, String reason) {
|
||||
VibrationAttributes attrs, int uid, int displayId, String opPkg, String reason) {
|
||||
this.token = token;
|
||||
this.mEffect = effect;
|
||||
this.id = id;
|
||||
this.attrs = attrs;
|
||||
this.uid = uid;
|
||||
this.displayId = displayId;
|
||||
this.opPkg = opPkg;
|
||||
this.reason = reason;
|
||||
mStatus = Vibration.Status.RUNNING;
|
||||
@@ -236,7 +239,7 @@ final class Vibration {
|
||||
/** Return {@link Vibration.DebugInfo} with read-only debug information about this vibration. */
|
||||
public Vibration.DebugInfo getDebugInfo() {
|
||||
return new Vibration.DebugInfo(mStatus, mStats, mEffect, mOriginalEffect, /* scale= */ 0,
|
||||
attrs, uid, opPkg, reason);
|
||||
attrs, uid, displayId, opPkg, reason);
|
||||
}
|
||||
|
||||
/** Return {@link VibrationStats.StatsInfo} with read-only metrics about this vibration. */
|
||||
@@ -304,13 +307,14 @@ final class Vibration {
|
||||
private final float mScale;
|
||||
private final VibrationAttributes mAttrs;
|
||||
private final int mUid;
|
||||
private final int mDisplayId;
|
||||
private final String mOpPkg;
|
||||
private final String mReason;
|
||||
private final Status mStatus;
|
||||
|
||||
DebugInfo(Status status, VibrationStats stats, @Nullable CombinedVibration effect,
|
||||
@Nullable CombinedVibration originalEffect, float scale, VibrationAttributes attrs,
|
||||
int uid, String opPkg, String reason) {
|
||||
int uid, int displayId, String opPkg, String reason) {
|
||||
mCreateTime = stats.getCreateTimeDebug();
|
||||
mStartTime = stats.getStartTimeDebug();
|
||||
mEndTime = stats.getEndTimeDebug();
|
||||
@@ -320,6 +324,7 @@ final class Vibration {
|
||||
mScale = scale;
|
||||
mAttrs = attrs;
|
||||
mUid = uid;
|
||||
mDisplayId = displayId;
|
||||
mOpPkg = opPkg;
|
||||
mReason = reason;
|
||||
mStatus = status;
|
||||
@@ -349,6 +354,8 @@ final class Vibration {
|
||||
.append(mAttrs)
|
||||
.append(", uid: ")
|
||||
.append(mUid)
|
||||
.append(", displayId: ")
|
||||
.append(mDisplayId)
|
||||
.append(", opPkg: ")
|
||||
.append(mOpPkg)
|
||||
.append(", reason: ")
|
||||
|
||||
@@ -56,10 +56,12 @@ import android.util.Slog;
|
||||
import android.util.SparseArray;
|
||||
import android.util.SparseIntArray;
|
||||
import android.util.proto.ProtoOutputStream;
|
||||
import android.view.Display;
|
||||
|
||||
import com.android.internal.annotations.GuardedBy;
|
||||
import com.android.internal.annotations.VisibleForTesting;
|
||||
import com.android.server.LocalServices;
|
||||
import com.android.server.companion.virtual.VirtualDeviceManagerInternal;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
@@ -157,6 +159,7 @@ final class VibrationSettings {
|
||||
final UidObserver mUidObserver;
|
||||
@VisibleForTesting
|
||||
final SettingsBroadcastReceiver mSettingChangeReceiver;
|
||||
final VirtualDeviceListener mVirtualDeviceListener;
|
||||
|
||||
@GuardedBy("mLock")
|
||||
private final List<OnVibratorSettingsChanged> mListeners = new ArrayList<>();
|
||||
@@ -193,6 +196,7 @@ final class VibrationSettings {
|
||||
mSettingObserver = new SettingsContentObserver(handler);
|
||||
mUidObserver = new UidObserver();
|
||||
mSettingChangeReceiver = new SettingsBroadcastReceiver();
|
||||
mVirtualDeviceListener = new VirtualDeviceListener();
|
||||
|
||||
mSystemUiPackage = LocalServices.getService(PackageManagerInternal.class)
|
||||
.getSystemUiServiceComponent().getPackageName();
|
||||
@@ -257,6 +261,13 @@ final class VibrationSettings {
|
||||
}
|
||||
});
|
||||
|
||||
VirtualDeviceManagerInternal vdm = LocalServices.getService(
|
||||
VirtualDeviceManagerInternal.class);
|
||||
if (vdm != null) {
|
||||
vdm.registerVirtualDisplayListener(mVirtualDeviceListener);
|
||||
vdm.registerAppsOnVirtualDeviceListener(mVirtualDeviceListener);
|
||||
}
|
||||
|
||||
registerSettingsChangeReceiver(USER_SWITCHED_INTENT_FILTER);
|
||||
registerSettingsChangeReceiver(INTERNAL_RINGER_MODE_CHANGED_INTENT_FILTER);
|
||||
|
||||
@@ -364,13 +375,17 @@ final class VibrationSettings {
|
||||
* null otherwise.
|
||||
*/
|
||||
@Nullable
|
||||
public Vibration.Status shouldIgnoreVibration(int uid, VibrationAttributes attrs) {
|
||||
public Vibration.Status shouldIgnoreVibration(int uid, int displayId,
|
||||
VibrationAttributes attrs) {
|
||||
final int usage = attrs.getUsage();
|
||||
synchronized (mLock) {
|
||||
if (!mUidObserver.isUidForeground(uid)
|
||||
&& !BACKGROUND_PROCESS_USAGE_ALLOWLIST.contains(usage)) {
|
||||
return Vibration.Status.IGNORED_BACKGROUND;
|
||||
}
|
||||
if (mVirtualDeviceListener.isAppOrDisplayOnAnyVirtualDevice(uid, displayId)) {
|
||||
return Vibration.Status.IGNORED_FROM_VIRTUAL_DEVICE;
|
||||
}
|
||||
|
||||
if (mBatterySaverMode && !BATTERY_SAVER_USAGE_ALLOWLIST.contains(usage)) {
|
||||
return Vibration.Status.IGNORED_FOR_POWER;
|
||||
@@ -741,4 +756,73 @@ final class VibrationSettings {
|
||||
public void onUidProcAdjChanged(int uid) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of Virtual Device listeners for the changes of virtual displays and of apps
|
||||
* running on any virtual device.
|
||||
*/
|
||||
final class VirtualDeviceListener implements
|
||||
VirtualDeviceManagerInternal.VirtualDisplayListener,
|
||||
VirtualDeviceManagerInternal.AppsOnVirtualDeviceListener {
|
||||
@GuardedBy("mLock")
|
||||
private final Set<Integer> mVirtualDisplays = new HashSet<>();
|
||||
@GuardedBy("mLock")
|
||||
private final Set<Integer> mAppsOnVirtualDevice = new HashSet<>();
|
||||
|
||||
|
||||
@Override
|
||||
public void onVirtualDisplayCreated(int displayId) {
|
||||
synchronized (mLock) {
|
||||
mVirtualDisplays.add(displayId);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onVirtualDisplayRemoved(int displayId) {
|
||||
synchronized (mLock) {
|
||||
mVirtualDisplays.remove(displayId);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void onAppsOnAnyVirtualDeviceChanged(Set<Integer> allRunningUids) {
|
||||
synchronized (mLock) {
|
||||
mAppsOnVirtualDevice.clear();
|
||||
mAppsOnVirtualDevice.addAll(allRunningUids);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param uid: uid of the calling app.
|
||||
* @param displayId: the id of a Display.
|
||||
* @return Returns true if:
|
||||
* <ul>
|
||||
* <li> the displayId is valid, and it's owned by a virtual device.</li>
|
||||
* <li> the displayId is invalid, and the calling app (uid) is running on a virtual
|
||||
* device.</li>
|
||||
* </ul>
|
||||
*/
|
||||
public boolean isAppOrDisplayOnAnyVirtualDevice(int uid, int displayId) {
|
||||
if (displayId == Display.DEFAULT_DISPLAY) {
|
||||
// The default display is the primary physical display on the phone.
|
||||
return false;
|
||||
}
|
||||
|
||||
synchronized (mLock) {
|
||||
if (displayId == Display.INVALID_DISPLAY) {
|
||||
// There is no Display object associated with the Context of calling
|
||||
// {@link SystemVibratorManager}, checking the calling UID instead.
|
||||
return mAppsOnVirtualDevice.contains(uid);
|
||||
} else {
|
||||
// Other valid display IDs representing valid logical displays will be
|
||||
// checked
|
||||
// against the active virtual displays set built with the registered
|
||||
// {@link VirtualDisplayListener}.
|
||||
return mVirtualDisplays.contains(displayId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -58,6 +58,7 @@ import android.text.TextUtils;
|
||||
import android.util.Slog;
|
||||
import android.util.SparseArray;
|
||||
import android.util.proto.ProtoOutputStream;
|
||||
import android.view.Display;
|
||||
|
||||
import com.android.internal.annotations.GuardedBy;
|
||||
import com.android.internal.annotations.VisibleForTesting;
|
||||
@@ -378,9 +379,9 @@ public class VibratorManagerService extends IVibratorManagerService.Stub {
|
||||
}
|
||||
|
||||
@Override // Binder call
|
||||
public void vibrate(int uid, String opPkg, @NonNull CombinedVibration effect,
|
||||
public void vibrate(int uid, int displayId, String opPkg, @NonNull CombinedVibration effect,
|
||||
@Nullable VibrationAttributes attrs, String reason, IBinder token) {
|
||||
vibrateInternal(uid, opPkg, effect, attrs, reason, token);
|
||||
vibrateInternal(uid, displayId, opPkg, effect, attrs, reason, token);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -389,8 +390,9 @@ public class VibratorManagerService extends IVibratorManagerService.Stub {
|
||||
*/
|
||||
@Nullable
|
||||
@VisibleForTesting
|
||||
Vibration vibrateInternal(int uid, String opPkg, @NonNull CombinedVibration effect,
|
||||
@Nullable VibrationAttributes attrs, String reason, IBinder token) {
|
||||
Vibration vibrateInternal(int uid, int displayId, String opPkg,
|
||||
@NonNull CombinedVibration effect, @Nullable VibrationAttributes attrs,
|
||||
String reason, IBinder token) {
|
||||
Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "vibrate, reason = " + reason);
|
||||
try {
|
||||
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.VIBRATE, "vibrate");
|
||||
@@ -406,7 +408,7 @@ public class VibratorManagerService extends IVibratorManagerService.Stub {
|
||||
attrs = fixupVibrationAttributes(attrs, effect);
|
||||
// Create Vibration.Stats as close to the received request as possible, for tracking.
|
||||
Vibration vib = new Vibration(token, mNextVibrationId.getAndIncrement(), effect, attrs,
|
||||
uid, opPkg, reason);
|
||||
uid, displayId, opPkg, reason);
|
||||
fillVibrationFallbacks(vib, effect);
|
||||
|
||||
if (attrs.isFlagSet(VibrationAttributes.FLAG_INVALIDATE_SETTINGS_CACHE)) {
|
||||
@@ -424,7 +426,7 @@ public class VibratorManagerService extends IVibratorManagerService.Stub {
|
||||
Vibration.Status status = null;
|
||||
|
||||
// Check if user settings or DnD is set to ignore this vibration.
|
||||
status = shouldIgnoreVibrationLocked(vib.uid, vib.opPkg, vib.attrs);
|
||||
status = shouldIgnoreVibrationLocked(vib.uid, vib.displayId, vib.opPkg, vib.attrs);
|
||||
|
||||
// Check if something has external control, assume it's more important.
|
||||
if ((status == null) && (mCurrentExternalVibration != null)) {
|
||||
@@ -629,7 +631,7 @@ public class VibratorManagerService extends IVibratorManagerService.Stub {
|
||||
|
||||
Vibration vib = mCurrentVibration.getVibration();
|
||||
Vibration.Status ignoreStatus = shouldIgnoreVibrationLocked(
|
||||
vib.uid, vib.opPkg, vib.attrs);
|
||||
vib.uid, vib.displayId, vib.opPkg, vib.attrs);
|
||||
|
||||
if (inputDevicesChanged || (ignoreStatus != null)) {
|
||||
if (DEBUG) {
|
||||
@@ -659,7 +661,7 @@ public class VibratorManagerService extends IVibratorManagerService.Stub {
|
||||
continue;
|
||||
}
|
||||
Vibration.Status ignoreStatus = shouldIgnoreVibrationLocked(
|
||||
vib.uid, vib.opPkg, vib.attrs);
|
||||
vib.uid, Display.DEFAULT_DISPLAY, vib.opPkg, vib.attrs);
|
||||
if (ignoreStatus == null) {
|
||||
effect = mVibrationScaler.scale(effect, vib.attrs.getUsage());
|
||||
} else {
|
||||
@@ -780,6 +782,12 @@ public class VibratorManagerService extends IVibratorManagerService.Stub {
|
||||
+ attrs);
|
||||
}
|
||||
break;
|
||||
case IGNORED_FROM_VIRTUAL_DEVICE:
|
||||
if (DEBUG) {
|
||||
Slog.d(TAG, "Ignoring incoming vibration because it came from a virtual"
|
||||
+ " device, attrs= " + attrs);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if (DEBUG) {
|
||||
Slog.d(TAG, "Vibration for uid=" + uid + " and with attrs=" + attrs
|
||||
@@ -894,9 +902,10 @@ public class VibratorManagerService extends IVibratorManagerService.Stub {
|
||||
*/
|
||||
@GuardedBy("mLock")
|
||||
@Nullable
|
||||
private Vibration.Status shouldIgnoreVibrationLocked(int uid, String opPkg,
|
||||
private Vibration.Status shouldIgnoreVibrationLocked(int uid, int displayId, String opPkg,
|
||||
VibrationAttributes attrs) {
|
||||
Vibration.Status statusFromSettings = mVibrationSettings.shouldIgnoreVibration(uid, attrs);
|
||||
Vibration.Status statusFromSettings = mVibrationSettings.shouldIgnoreVibration(uid,
|
||||
displayId, attrs);
|
||||
if (statusFromSettings != null) {
|
||||
return statusFromSettings;
|
||||
}
|
||||
@@ -1442,6 +1451,9 @@ public class VibratorManagerService extends IVibratorManagerService.Stub {
|
||||
return new Vibration.DebugInfo(
|
||||
mStatus, stats, /* effect= */ null, /* originalEffect= */ null, scale,
|
||||
externalVibration.getVibrationAttributes(), externalVibration.getUid(),
|
||||
// TODO(b/243604888): propagating displayID from IExternalVibration instead of
|
||||
// using INVALID_DISPLAY for all external vibrations.
|
||||
Display.INVALID_DISPLAY,
|
||||
externalVibration.getPackage(), /* reason= */ null);
|
||||
}
|
||||
|
||||
@@ -1647,8 +1659,10 @@ public class VibratorManagerService extends IVibratorManagerService.Stub {
|
||||
boolean alreadyUnderExternalControl = false;
|
||||
boolean waitForCompletion = false;
|
||||
synchronized (mLock) {
|
||||
// TODO(b/243604888): propagating displayID from IExternalVibration instead of
|
||||
// using INVALID_DISPLAY for all external vibrations.
|
||||
Vibration.Status ignoreStatus = shouldIgnoreVibrationLocked(
|
||||
vib.getUid(), vib.getPackage(), attrs);
|
||||
vib.getUid(), Display.INVALID_DISPLAY, vib.getPackage(), attrs);
|
||||
if (ignoreStatus != null) {
|
||||
vibHolder.scale = IExternalVibratorService.SCALE_MUTE;
|
||||
// Failed to start the vibration, end it and report metrics right away.
|
||||
@@ -1840,8 +1854,8 @@ public class VibratorManagerService extends IVibratorManagerService.Stub {
|
||||
// only cancel background vibrations.
|
||||
IBinder deathBinder = commonOptions.background ? VibratorManagerService.this
|
||||
: mShellCallbacksToken;
|
||||
Vibration vib = vibrateInternal(Binder.getCallingUid(), SHELL_PACKAGE_NAME, combined,
|
||||
attrs, commonOptions.description, deathBinder);
|
||||
Vibration vib = vibrateInternal(Binder.getCallingUid(), Display.DEFAULT_DISPLAY,
|
||||
SHELL_PACKAGE_NAME, combined, attrs, commonOptions.description, deathBinder);
|
||||
if (vib != null && !commonOptions.background) {
|
||||
try {
|
||||
vib.waitForEnd();
|
||||
|
||||
@@ -66,12 +66,15 @@ import android.os.test.TestLooper;
|
||||
import android.os.vibrator.VibrationConfig;
|
||||
import android.platform.test.annotations.Presubmit;
|
||||
import android.provider.Settings;
|
||||
import android.util.ArraySet;
|
||||
import android.view.Display;
|
||||
|
||||
import androidx.test.InstrumentationRegistry;
|
||||
|
||||
import com.android.internal.util.test.FakeSettingsProvider;
|
||||
import com.android.internal.util.test.FakeSettingsProviderRule;
|
||||
import com.android.server.LocalServices;
|
||||
import com.android.server.companion.virtual.VirtualDeviceManagerInternal;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
@@ -95,6 +98,7 @@ import java.util.Set;
|
||||
public class VibrationSettingsTest {
|
||||
|
||||
private static final int UID = 1;
|
||||
private static final int VIRTUAL_DISPLAY_ID = 1;
|
||||
private static final String SYSUI_PACKAGE_NAME = "sysui";
|
||||
private static final PowerSaveState NORMAL_POWER_STATE = new PowerSaveState.Builder().build();
|
||||
private static final PowerSaveState LOW_POWER_STATE = new PowerSaveState.Builder()
|
||||
@@ -117,15 +121,23 @@ public class VibrationSettingsTest {
|
||||
@Rule public FakeSettingsProviderRule mSettingsProviderRule = FakeSettingsProvider.rule();
|
||||
|
||||
@Mock private VibrationSettings.OnVibratorSettingsChanged mListenerMock;
|
||||
@Mock private PowerManagerInternal mPowerManagerInternalMock;
|
||||
@Mock private PackageManagerInternal mPackageManagerInternalMock;
|
||||
@Mock private VibrationConfig mVibrationConfigMock;
|
||||
@Mock
|
||||
private PowerManagerInternal mPowerManagerInternalMock;
|
||||
@Mock
|
||||
private VirtualDeviceManagerInternal mVirtualDeviceManagerInternalMock;
|
||||
@Mock
|
||||
private PackageManagerInternal mPackageManagerInternalMock;
|
||||
@Mock
|
||||
private VibrationConfig mVibrationConfigMock;
|
||||
|
||||
private TestLooper mTestLooper;
|
||||
private ContextWrapper mContextSpy;
|
||||
private AudioManager mAudioManager;
|
||||
private VibrationSettings mVibrationSettings;
|
||||
private PowerManagerInternal.LowPowerModeListener mRegisteredPowerModeListener;
|
||||
private VirtualDeviceManagerInternal.VirtualDisplayListener mRegisteredVirtualDisplayListener;
|
||||
private VirtualDeviceManagerInternal.AppsOnVirtualDeviceListener
|
||||
mRegisteredAppsOnVirtualDeviceListener;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
@@ -140,11 +152,17 @@ public class VibrationSettingsTest {
|
||||
}).when(mPowerManagerInternalMock).registerLowPowerModeObserver(any());
|
||||
when(mPackageManagerInternalMock.getSystemUiServiceComponent())
|
||||
.thenReturn(new ComponentName(SYSUI_PACKAGE_NAME, ""));
|
||||
doAnswer(invocation -> {
|
||||
mRegisteredVirtualDisplayListener = invocation.getArgument(0);
|
||||
return null;
|
||||
}).when(mVirtualDeviceManagerInternalMock).registerVirtualDisplayListener(any());
|
||||
doAnswer(invocation -> {
|
||||
mRegisteredAppsOnVirtualDeviceListener = invocation.getArgument(0);
|
||||
return null;
|
||||
}).when(mVirtualDeviceManagerInternalMock).registerAppsOnVirtualDeviceListener(any());
|
||||
|
||||
LocalServices.removeServiceForTest(PowerManagerInternal.class);
|
||||
LocalServices.addService(PowerManagerInternal.class, mPowerManagerInternalMock);
|
||||
LocalServices.removeServiceForTest(PackageManagerInternal.class);
|
||||
LocalServices.addService(PackageManagerInternal.class, mPackageManagerInternalMock);
|
||||
removeServicesForTest();
|
||||
addServicesForTest();
|
||||
|
||||
setDefaultIntensity(VIBRATION_INTENSITY_MEDIUM);
|
||||
mAudioManager = mContextSpy.getSystemService(AudioManager.class);
|
||||
@@ -167,6 +185,18 @@ public class VibrationSettingsTest {
|
||||
LocalServices.removeServiceForTest(PowerManagerInternal.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void create_withOnlyRequiredSystemServices() {
|
||||
// The only core services that we depend on are PowerManager and PackageManager
|
||||
removeServicesForTest();
|
||||
LocalServices.addService(PowerManagerInternal.class, mPowerManagerInternalMock);
|
||||
LocalServices.addService(PackageManagerInternal.class, mPackageManagerInternalMock);
|
||||
|
||||
VibrationSettings minimalVibrationSettings = new VibrationSettings(mContextSpy,
|
||||
new Handler(mTestLooper.getLooper()), mVibrationConfigMock);
|
||||
minimalVibrationSettings.onSystemReady();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void addListener_settingsChangeTriggerListener() {
|
||||
mVibrationSettings.addListener(mListenerMock);
|
||||
@@ -446,6 +476,65 @@ public class VibrationSettingsTest {
|
||||
assertVibrationIgnoredForUsage(USAGE_RINGTONE, Vibration.Status.IGNORED_FOR_RINGER_MODE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldIgnoreVibrationFromVirtualDisplays_displayNonVirtual_neverIgnored() {
|
||||
// Vibrations from the primary display is never ignored regardless of the creation and
|
||||
// removal of virtual displays and of the changes of apps running on virtual displays.
|
||||
mRegisteredVirtualDisplayListener.onVirtualDisplayCreated(VIRTUAL_DISPLAY_ID);
|
||||
mRegisteredAppsOnVirtualDeviceListener.onAppsOnAnyVirtualDeviceChanged(
|
||||
new ArraySet<>(Arrays.asList(UID)));
|
||||
for (int usage : ALL_USAGES) {
|
||||
assertVibrationNotIgnoredForUsageAndDisplay(usage, Display.DEFAULT_DISPLAY);
|
||||
}
|
||||
|
||||
mRegisteredVirtualDisplayListener.onVirtualDisplayRemoved(VIRTUAL_DISPLAY_ID);
|
||||
for (int usage : ALL_USAGES) {
|
||||
assertVibrationNotIgnoredForUsageAndDisplay(usage, Display.DEFAULT_DISPLAY);
|
||||
}
|
||||
|
||||
mRegisteredAppsOnVirtualDeviceListener.onAppsOnAnyVirtualDeviceChanged(new ArraySet<>());
|
||||
for (int usage : ALL_USAGES) {
|
||||
assertVibrationNotIgnoredForUsageAndDisplay(usage, Display.DEFAULT_DISPLAY);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldIgnoreVibrationFromVirtualDisplays_displayVirtual() {
|
||||
// Ignore the vibration when the coming display id represents a virtual display.
|
||||
mRegisteredVirtualDisplayListener.onVirtualDisplayCreated(VIRTUAL_DISPLAY_ID);
|
||||
|
||||
for (int usage : ALL_USAGES) {
|
||||
assertVibrationIgnoredForUsageAndDisplay(usage, VIRTUAL_DISPLAY_ID,
|
||||
Vibration.Status.IGNORED_FROM_VIRTUAL_DEVICE);
|
||||
}
|
||||
|
||||
// Stop ignoring when the virtual display is removed.
|
||||
mRegisteredVirtualDisplayListener.onVirtualDisplayRemoved(VIRTUAL_DISPLAY_ID);
|
||||
for (int usage : ALL_USAGES) {
|
||||
assertVibrationNotIgnoredForUsageAndDisplay(usage, VIRTUAL_DISPLAY_ID);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void shouldIgnoreVibrationFromVirtualDisplays_appsOnVirtualDisplay() {
|
||||
// Ignore when the passed-in display id is invalid and the calling uid is on a virtual
|
||||
// display.
|
||||
mRegisteredAppsOnVirtualDeviceListener.onAppsOnAnyVirtualDeviceChanged(
|
||||
new ArraySet<>(Arrays.asList(UID)));
|
||||
for (int usage : ALL_USAGES) {
|
||||
assertVibrationIgnoredForUsageAndDisplay(usage, Display.INVALID_DISPLAY,
|
||||
Vibration.Status.IGNORED_FROM_VIRTUAL_DEVICE);
|
||||
}
|
||||
|
||||
// Stop ignoring when the app is no longer on virtual display.
|
||||
mRegisteredAppsOnVirtualDeviceListener.onAppsOnAnyVirtualDeviceChanged(new ArraySet<>());
|
||||
for (int usage : ALL_USAGES) {
|
||||
assertVibrationNotIgnoredForUsageAndDisplay(usage, Display.INVALID_DISPLAY);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldVibrateInputDevices_returnsSettingsValue() {
|
||||
setUserSetting(Settings.System.VIBRATE_INPUT_DEVICES, 1);
|
||||
@@ -479,7 +568,7 @@ public class VibrationSettingsTest {
|
||||
@Test
|
||||
public void shouldCancelVibrationOnScreenOff_withSleepReasonInAllowlist_returnsAlwaysFalse() {
|
||||
long vibrateStartTime = 100;
|
||||
int[] allowedSleepReasons = new int[] {
|
||||
int[] allowedSleepReasons = new int[]{
|
||||
PowerManager.GO_TO_SLEEP_REASON_TIMEOUT,
|
||||
PowerManager.GO_TO_SLEEP_REASON_INATTENTIVE,
|
||||
};
|
||||
@@ -646,11 +735,29 @@ public class VibrationSettingsTest {
|
||||
assertNotNull(mVibrationSettings.getFallbackEffect(VibrationEffect.EFFECT_DOUBLE_CLICK));
|
||||
}
|
||||
|
||||
private void removeServicesForTest() {
|
||||
LocalServices.removeServiceForTest(PowerManagerInternal.class);
|
||||
LocalServices.removeServiceForTest(PackageManagerInternal.class);
|
||||
LocalServices.removeServiceForTest(VirtualDeviceManagerInternal.class);
|
||||
}
|
||||
|
||||
private void addServicesForTest() {
|
||||
LocalServices.addService(PowerManagerInternal.class, mPowerManagerInternalMock);
|
||||
LocalServices.addService(PackageManagerInternal.class, mPackageManagerInternalMock);
|
||||
LocalServices.addService(VirtualDeviceManagerInternal.class,
|
||||
mVirtualDeviceManagerInternalMock);
|
||||
}
|
||||
|
||||
private void assertVibrationIgnoredForUsage(@VibrationAttributes.Usage int usage,
|
||||
Vibration.Status expectedStatus) {
|
||||
assertVibrationIgnoredForUsageAndDisplay(usage, Display.DEFAULT_DISPLAY, expectedStatus);
|
||||
}
|
||||
|
||||
private void assertVibrationIgnoredForUsageAndDisplay(@VibrationAttributes.Usage int usage,
|
||||
int displayId, Vibration.Status expectedStatus) {
|
||||
assertEquals(errorMessageForUsage(usage),
|
||||
expectedStatus,
|
||||
mVibrationSettings.shouldIgnoreVibration(UID,
|
||||
mVibrationSettings.shouldIgnoreVibration(UID, displayId,
|
||||
VibrationAttributes.createForUsage(usage)));
|
||||
}
|
||||
|
||||
@@ -660,8 +767,20 @@ public class VibrationSettingsTest {
|
||||
|
||||
private void assertVibrationNotIgnoredForUsageAndFlags(@VibrationAttributes.Usage int usage,
|
||||
@VibrationAttributes.Flag int flags) {
|
||||
assertVibrationNotIgnoredForUsageAndFlagsAndDidsplay(usage, Display.DEFAULT_DISPLAY, flags);
|
||||
}
|
||||
|
||||
private void assertVibrationNotIgnoredForUsageAndDisplay(@VibrationAttributes.Usage int usage,
|
||||
int displayId) {
|
||||
assertVibrationNotIgnoredForUsageAndFlagsAndDidsplay(usage, displayId, /* flags= */ 0);
|
||||
}
|
||||
|
||||
private void assertVibrationNotIgnoredForUsageAndFlagsAndDidsplay(
|
||||
@VibrationAttributes.Usage int usage, int displayId,
|
||||
@VibrationAttributes.Flag int flags) {
|
||||
assertNull(errorMessageForUsage(usage),
|
||||
mVibrationSettings.shouldIgnoreVibration(UID,
|
||||
displayId,
|
||||
new VibrationAttributes.Builder()
|
||||
.setUsage(usage)
|
||||
.setFlags(flags)
|
||||
|
||||
@@ -94,6 +94,7 @@ public class VibrationThreadTest {
|
||||
|
||||
private static final int TEST_TIMEOUT_MILLIS = 900;
|
||||
private static final int UID = Process.ROOT_UID;
|
||||
private static final int DISPLAY_ID = 10;
|
||||
private static final int VIBRATOR_ID = 1;
|
||||
private static final String PACKAGE_NAME = "package";
|
||||
private static final VibrationAttributes ATTRS = new VibrationAttributes.Builder().build();
|
||||
@@ -1584,7 +1585,8 @@ public class VibrationThreadTest {
|
||||
}
|
||||
|
||||
private Vibration createVibration(long id, CombinedVibration effect) {
|
||||
return new Vibration(mVibrationToken, (int) id, effect, ATTRS, UID, PACKAGE_NAME, "reason");
|
||||
return new Vibration(mVibrationToken, (int) id, effect, ATTRS, UID, DISPLAY_ID,
|
||||
PACKAGE_NAME, "reason");
|
||||
}
|
||||
|
||||
private SparseArray<VibratorController> createVibratorControllers() {
|
||||
|
||||
@@ -76,7 +76,9 @@ import android.os.vibrator.VibrationConfig;
|
||||
import android.os.vibrator.VibrationEffectSegment;
|
||||
import android.platform.test.annotations.Presubmit;
|
||||
import android.provider.Settings;
|
||||
import android.util.ArraySet;
|
||||
import android.util.SparseBooleanArray;
|
||||
import android.view.Display;
|
||||
import android.view.InputDevice;
|
||||
|
||||
import androidx.test.InstrumentationRegistry;
|
||||
@@ -86,6 +88,7 @@ import com.android.internal.util.FrameworkStatsLog;
|
||||
import com.android.internal.util.test.FakeSettingsProvider;
|
||||
import com.android.internal.util.test.FakeSettingsProviderRule;
|
||||
import com.android.server.LocalServices;
|
||||
import com.android.server.companion.virtual.VirtualDeviceManagerInternal;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
@@ -115,6 +118,7 @@ public class VibratorManagerServiceTest {
|
||||
|
||||
private static final int TEST_TIMEOUT_MILLIS = 1_000;
|
||||
private static final int UID = Process.ROOT_UID;
|
||||
private static final int VIRTUAL_DISPLAY_ID = 1;
|
||||
private static final String PACKAGE_NAME = "package";
|
||||
private static final PowerSaveState NORMAL_POWER_STATE = new PowerSaveState.Builder().build();
|
||||
private static final PowerSaveState LOW_POWER_STATE = new PowerSaveState.Builder()
|
||||
@@ -153,6 +157,8 @@ public class VibratorManagerServiceTest {
|
||||
private IBatteryStats mBatteryStatsMock;
|
||||
@Mock
|
||||
private VibratorFrameworkStatsLogger mVibratorFrameworkStatsLoggerMock;
|
||||
@Mock
|
||||
private VirtualDeviceManagerInternal mVirtualDeviceManagerInternalMock;
|
||||
|
||||
private final Map<Integer, FakeVibratorControllerProvider> mVibratorProviders = new HashMap<>();
|
||||
|
||||
@@ -162,6 +168,9 @@ public class VibratorManagerServiceTest {
|
||||
private PowerManagerInternal.LowPowerModeListener mRegisteredPowerModeListener;
|
||||
private VibratorManagerService.ExternalVibratorService mExternalVibratorService;
|
||||
private VibrationConfig mVibrationConfig;
|
||||
private VirtualDeviceManagerInternal.VirtualDisplayListener mRegisteredVirtualDisplayListener;
|
||||
private VirtualDeviceManagerInternal.AppsOnVirtualDeviceListener
|
||||
mRegisteredAppsOnVirtualDeviceListener;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
@@ -186,6 +195,14 @@ public class VibratorManagerServiceTest {
|
||||
mRegisteredPowerModeListener = invocation.getArgument(0);
|
||||
return null;
|
||||
}).when(mPowerManagerInternalMock).registerLowPowerModeObserver(any());
|
||||
doAnswer(invocation -> {
|
||||
mRegisteredVirtualDisplayListener = invocation.getArgument(0);
|
||||
return null;
|
||||
}).when(mVirtualDeviceManagerInternalMock).registerVirtualDisplayListener(any());
|
||||
doAnswer(invocation -> {
|
||||
mRegisteredAppsOnVirtualDeviceListener = invocation.getArgument(0);
|
||||
return null;
|
||||
}).when(mVirtualDeviceManagerInternalMock).registerAppsOnVirtualDeviceListener(any());
|
||||
|
||||
setUserSetting(Settings.System.VIBRATE_WHEN_RINGING, 1);
|
||||
setUserSetting(Settings.System.HAPTIC_FEEDBACK_ENABLED, 1);
|
||||
@@ -202,6 +219,7 @@ public class VibratorManagerServiceTest {
|
||||
|
||||
addLocalServiceMock(PackageManagerInternal.class, mPackageManagerInternalMock);
|
||||
addLocalServiceMock(PowerManagerInternal.class, mPowerManagerInternalMock);
|
||||
addLocalServiceMock(VirtualDeviceManagerInternal.class, mVirtualDeviceManagerInternalMock);
|
||||
|
||||
mTestLooper.startAutoDispatch();
|
||||
}
|
||||
@@ -1166,6 +1184,64 @@ public class VibratorManagerServiceTest {
|
||||
assertFalse(waitUntil(s -> !s.isVibrating(1), service, 50));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void vibrate_withVitualDisplayChange_ignoreVibrationFromVirtualDisplay()
|
||||
throws Exception {
|
||||
mockVibrators(1);
|
||||
VibratorManagerService service = createSystemReadyService();
|
||||
mRegisteredVirtualDisplayListener.onVirtualDisplayCreated(VIRTUAL_DISPLAY_ID);
|
||||
|
||||
vibrateWithDisplay(service,
|
||||
VIRTUAL_DISPLAY_ID,
|
||||
CombinedVibration.startParallel()
|
||||
.addVibrator(1, VibrationEffect.createOneShot(1000, 100))
|
||||
.combine(),
|
||||
HAPTIC_FEEDBACK_ATTRS);
|
||||
|
||||
// Haptic feedback ignored when it's from a virtual display.
|
||||
assertFalse(waitUntil(s -> s.isVibrating(1), service, /* timeout= */ 50));
|
||||
|
||||
mRegisteredVirtualDisplayListener.onVirtualDisplayRemoved(VIRTUAL_DISPLAY_ID);
|
||||
vibrateWithDisplay(service,
|
||||
VIRTUAL_DISPLAY_ID,
|
||||
CombinedVibration.startParallel()
|
||||
.addVibrator(1, VibrationEffect.createOneShot(1000, 100))
|
||||
.combine(),
|
||||
HAPTIC_FEEDBACK_ATTRS);
|
||||
// Haptic feedback played normally when the virtual display is removed.
|
||||
assertTrue(waitUntil(s -> s.isVibrating(1), service, TEST_TIMEOUT_MILLIS));
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void vibrate_withAppsOnVitualDisplayChange_ignoreVibrationFromVirtualDisplay()
|
||||
throws Exception {
|
||||
mockVibrators(1);
|
||||
VibratorManagerService service = createSystemReadyService();
|
||||
mRegisteredAppsOnVirtualDeviceListener.onAppsOnAnyVirtualDeviceChanged(
|
||||
new ArraySet<>(Arrays.asList(UID)));
|
||||
vibrateWithDisplay(service,
|
||||
Display.INVALID_DISPLAY,
|
||||
CombinedVibration.startParallel()
|
||||
.addVibrator(1, VibrationEffect.createOneShot(1000, 100))
|
||||
.combine(),
|
||||
HAPTIC_FEEDBACK_ATTRS);
|
||||
|
||||
// Haptic feedback ignored when it's from an app running virtual display.
|
||||
assertFalse(waitUntil(s -> s.isVibrating(1), service, /* timeout= */ 50));
|
||||
|
||||
mRegisteredAppsOnVirtualDeviceListener.onAppsOnAnyVirtualDeviceChanged(new ArraySet<>());
|
||||
vibrateWithDisplay(service,
|
||||
Display.INVALID_DISPLAY,
|
||||
CombinedVibration.startParallel()
|
||||
.addVibrator(1, VibrationEffect.createOneShot(1000, 100))
|
||||
.combine(),
|
||||
HAPTIC_FEEDBACK_ATTRS);
|
||||
// Haptic feedback played normally when the same app no long runs on a virtual display.
|
||||
assertTrue(waitUntil(s -> s.isVibrating(1), service, TEST_TIMEOUT_MILLIS));
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void cancelVibrate_withoutUsageFilter_stopsVibrating() throws Exception {
|
||||
mockVibrators(1);
|
||||
@@ -1239,6 +1315,24 @@ public class VibratorManagerServiceTest {
|
||||
assertTrue(waitUntil(s -> !s.isVibrating(1), service, TEST_TIMEOUT_MILLIS));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onExternalVibration_ignoreVibrationFromVirtualDevices() throws Exception {
|
||||
mockVibrators(1);
|
||||
mVibratorProviders.get(1).setCapabilities(IVibrator.CAP_EXTERNAL_CONTROL);
|
||||
createSystemReadyService();
|
||||
|
||||
IBinder binderToken = mock(IBinder.class);
|
||||
ExternalVibration externalVibration = new ExternalVibration(UID, PACKAGE_NAME, AUDIO_ATTRS,
|
||||
mock(IExternalVibrationController.class), binderToken);
|
||||
int scale = mExternalVibratorService.onExternalVibrationStart(externalVibration);
|
||||
assertNotEquals(IExternalVibratorService.SCALE_MUTE, scale);
|
||||
|
||||
mRegisteredAppsOnVirtualDeviceListener.onAppsOnAnyVirtualDeviceChanged(
|
||||
new ArraySet<>(Arrays.asList(UID)));
|
||||
scale = mExternalVibratorService.onExternalVibrationStart(externalVibration);
|
||||
assertEquals(IExternalVibratorService.SCALE_MUTE, scale);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onExternalVibration_setsExternalControl() throws Exception {
|
||||
mockVibrators(1);
|
||||
@@ -1820,7 +1914,8 @@ public class VibratorManagerServiceTest {
|
||||
private void vibrateAndWaitUntilFinished(VibratorManagerService service,
|
||||
CombinedVibration effect, VibrationAttributes attrs) throws InterruptedException {
|
||||
Vibration vib =
|
||||
service.vibrateInternal(UID, PACKAGE_NAME, effect, attrs, "some reason", service);
|
||||
service.vibrateInternal(UID, Display.DEFAULT_DISPLAY, PACKAGE_NAME, effect, attrs,
|
||||
"some reason", service);
|
||||
if (vib != null) {
|
||||
vib.waitForEnd();
|
||||
}
|
||||
@@ -1833,7 +1928,12 @@ public class VibratorManagerServiceTest {
|
||||
|
||||
private void vibrate(VibratorManagerService service, CombinedVibration effect,
|
||||
VibrationAttributes attrs) {
|
||||
service.vibrate(UID, PACKAGE_NAME, effect, attrs, "some reason", service);
|
||||
vibrateWithDisplay(service, Display.DEFAULT_DISPLAY, effect, attrs);
|
||||
}
|
||||
|
||||
private void vibrateWithDisplay(VibratorManagerService service, int displayId,
|
||||
CombinedVibration effect, VibrationAttributes attrs) {
|
||||
service.vibrate(UID, displayId, PACKAGE_NAME, effect, attrs, "some reason", service);
|
||||
}
|
||||
|
||||
private boolean waitUntil(Predicate<VibratorManagerService> predicate,
|
||||
|
||||
@@ -50,6 +50,7 @@ import org.junit.runners.JUnit4;
|
||||
public class VibratorManagerServicePermissionTest {
|
||||
|
||||
private static final String PACKAGE_NAME = "com.android.framework.permission.tests";
|
||||
private static final int DISPLAY_ID = 1;
|
||||
private static final CombinedVibration EFFECT =
|
||||
CombinedVibration.createParallel(
|
||||
VibrationEffect.createOneShot(100, VibrationEffect.DEFAULT_AMPLITUDE));
|
||||
@@ -106,7 +107,8 @@ public class VibratorManagerServicePermissionTest {
|
||||
@Test
|
||||
public void testVibrateWithoutPermissionFails() throws RemoteException {
|
||||
expectSecurityException("VIBRATE");
|
||||
mVibratorService.vibrate(Process.myUid(), PACKAGE_NAME, EFFECT, ATTRS, "testVibrate",
|
||||
mVibratorService.vibrate(Process.myUid(), DISPLAY_ID, PACKAGE_NAME, EFFECT, ATTRS,
|
||||
"testVibrate",
|
||||
new Binder());
|
||||
}
|
||||
|
||||
@@ -115,7 +117,8 @@ public class VibratorManagerServicePermissionTest {
|
||||
throws RemoteException {
|
||||
getInstrumentation().getUiAutomation().adoptShellPermissionIdentity(
|
||||
Manifest.permission.VIBRATE);
|
||||
mVibratorService.vibrate(Process.myUid(), PACKAGE_NAME, EFFECT, ATTRS, "testVibrate",
|
||||
mVibratorService.vibrate(Process.myUid(), DISPLAY_ID, PACKAGE_NAME, EFFECT, ATTRS,
|
||||
"testVibrate",
|
||||
new Binder());
|
||||
}
|
||||
|
||||
@@ -124,7 +127,8 @@ public class VibratorManagerServicePermissionTest {
|
||||
expectSecurityException("UPDATE_APP_OPS_STATS");
|
||||
getInstrumentation().getUiAutomation().adoptShellPermissionIdentity(
|
||||
Manifest.permission.VIBRATE);
|
||||
mVibratorService.vibrate(Process.SYSTEM_UID, "android", EFFECT, ATTRS, "testVibrate",
|
||||
mVibratorService.vibrate(Process.SYSTEM_UID, DISPLAY_ID, "android", EFFECT, ATTRS,
|
||||
"testVibrate",
|
||||
new Binder());
|
||||
}
|
||||
|
||||
@@ -133,7 +137,8 @@ public class VibratorManagerServicePermissionTest {
|
||||
getInstrumentation().getUiAutomation().adoptShellPermissionIdentity(
|
||||
Manifest.permission.VIBRATE,
|
||||
Manifest.permission.UPDATE_APP_OPS_STATS);
|
||||
mVibratorService.vibrate(Process.SYSTEM_UID, "android", EFFECT, ATTRS, "testVibrate",
|
||||
mVibratorService.vibrate(Process.SYSTEM_UID, DISPLAY_ID, "android", EFFECT, ATTRS,
|
||||
"testVibrate",
|
||||
new Binder());
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user