Merge "Extract Vibration class to vibrator package."
This commit is contained in:
committed by
Android (Google) Code Review
commit
b511492911
@@ -159,7 +159,7 @@ public class VibratorManagerService extends IVibratorManagerService.Stub {
|
||||
pw.println(" Prints this help text.");
|
||||
pw.println("");
|
||||
pw.println(" list");
|
||||
pw.println(" Prints the id of device vibrators. This do not include any ");
|
||||
pw.println(" Prints the id of device vibrators. This does not include any ");
|
||||
pw.println(" connected input device.");
|
||||
pw.println("");
|
||||
}
|
||||
|
||||
@@ -16,8 +16,6 @@
|
||||
|
||||
package com.android.server;
|
||||
|
||||
import static android.os.VibrationEffect.Composition.PrimitiveEffect;
|
||||
|
||||
import android.annotation.Nullable;
|
||||
import android.app.ActivityManager;
|
||||
import android.app.AppOpsManager;
|
||||
@@ -64,6 +62,7 @@ import com.android.internal.app.IBatteryStats;
|
||||
import com.android.internal.util.DumpUtils;
|
||||
import com.android.internal.util.FrameworkStatsLog;
|
||||
import com.android.server.vibrator.InputDeviceDelegate;
|
||||
import com.android.server.vibrator.Vibration;
|
||||
import com.android.server.vibrator.VibrationScaler;
|
||||
import com.android.server.vibrator.VibrationSettings;
|
||||
import com.android.server.vibrator.VibratorController;
|
||||
@@ -72,9 +71,7 @@ import com.android.server.vibrator.VibratorController.OnVibrationCompleteListene
|
||||
import java.io.FileDescriptor;
|
||||
import java.io.PrintWriter;
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
@@ -82,8 +79,6 @@ import java.util.concurrent.atomic.AtomicInteger;
|
||||
/** System implementation of {@link IVibratorService}. */
|
||||
public class VibratorService extends IVibratorService.Stub {
|
||||
private static final String TAG = "VibratorService";
|
||||
private static final SimpleDateFormat DEBUG_DATE_FORMAT =
|
||||
new SimpleDateFormat("MM-dd HH:mm:ss.SSS");
|
||||
private static final boolean DEBUG = false;
|
||||
private static final String EXTERNAL_VIBRATOR_SERVICE = "external_vibrator_service";
|
||||
|
||||
@@ -94,11 +89,11 @@ public class VibratorService extends IVibratorService.Stub {
|
||||
// Used to generate globally unique vibration ids.
|
||||
private final AtomicInteger mNextVibrationId = new AtomicInteger(1); // 0 = no callback
|
||||
|
||||
private final LinkedList<VibrationInfo> mPreviousRingVibrations;
|
||||
private final LinkedList<VibrationInfo> mPreviousNotificationVibrations;
|
||||
private final LinkedList<VibrationInfo> mPreviousAlarmVibrations;
|
||||
private final LinkedList<VibrationInfo> mPreviousExternalVibrations;
|
||||
private final LinkedList<VibrationInfo> mPreviousVibrations;
|
||||
private final LinkedList<Vibration.DebugInfo> mPreviousRingVibrations;
|
||||
private final LinkedList<Vibration.DebugInfo> mPreviousNotificationVibrations;
|
||||
private final LinkedList<Vibration.DebugInfo> mPreviousAlarmVibrations;
|
||||
private final LinkedList<Vibration.DebugInfo> mPreviousExternalVibrations;
|
||||
private final LinkedList<Vibration.DebugInfo> mPreviousVibrations;
|
||||
private final int mPreviousVibrationsLimit;
|
||||
private final SparseArray<Integer> mProcStatesCache = new SparseArray<>();
|
||||
private final WorkSource mTmpWorkSource = new WorkSource();
|
||||
@@ -120,6 +115,8 @@ public class VibratorService extends IVibratorService.Stub {
|
||||
|
||||
@GuardedBy("mLock")
|
||||
private Vibration mCurrentVibration;
|
||||
@GuardedBy("mLock")
|
||||
private VibrationDeathRecipient mCurrentVibrationDeathRecipient;
|
||||
private int mCurVibUid = -1;
|
||||
private ExternalVibrationHolder mCurrentExternalVibration;
|
||||
private boolean mLowPowerMode;
|
||||
@@ -167,101 +164,33 @@ public class VibratorService extends IVibratorService.Stub {
|
||||
}
|
||||
}
|
||||
|
||||
/** Holder for a {@link VibrationEffect}. */
|
||||
private final class Vibration implements IBinder.DeathRecipient {
|
||||
/** Death recipient to bind {@link Vibration}. */
|
||||
private final class VibrationDeathRecipient implements IBinder.DeathRecipient {
|
||||
|
||||
public final IBinder token;
|
||||
// Start time in CLOCK_BOOTTIME base.
|
||||
public final long startTime;
|
||||
public final VibrationAttributes attrs;
|
||||
public final long id;
|
||||
public final int uid;
|
||||
public final String opPkg;
|
||||
public final String reason;
|
||||
private final Vibration mVibration;
|
||||
|
||||
// The actual effect to be played.
|
||||
public VibrationEffect effect;
|
||||
// The original effect that was requested. Typically these two things differ because
|
||||
// the effect was scaled based on the users vibration intensity settings.
|
||||
public VibrationEffect originalEffect;
|
||||
// The scale applied to the original effect.
|
||||
public float scale;
|
||||
|
||||
// Start/end times in unix epoch time. Only to be used for debugging purposes and to
|
||||
// correlate with other system events, any duration calculations should be done use
|
||||
// startTime so as not to be affected by discontinuities created by RTC adjustments.
|
||||
private final long mStartTimeDebug;
|
||||
private long mEndTimeDebug;
|
||||
private VibrationInfo.Status mStatus;
|
||||
|
||||
private Vibration(IBinder token, VibrationEffect effect,
|
||||
VibrationAttributes attrs, int uid, String opPkg, String reason) {
|
||||
this.token = token;
|
||||
this.effect = effect;
|
||||
this.id = mNextVibrationId.getAndIncrement();
|
||||
this.startTime = SystemClock.elapsedRealtime();
|
||||
this.attrs = attrs;
|
||||
this.uid = uid;
|
||||
this.opPkg = opPkg;
|
||||
this.reason = reason;
|
||||
mStartTimeDebug = System.currentTimeMillis();
|
||||
mStatus = VibrationInfo.Status.RUNNING;
|
||||
private VibrationDeathRecipient(Vibration vibration) {
|
||||
mVibration = vibration;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void binderDied() {
|
||||
synchronized (mLock) {
|
||||
if (this == mCurrentVibration) {
|
||||
if (mVibration == mCurrentVibration) {
|
||||
if (DEBUG) {
|
||||
Slog.d(TAG, "Vibration finished because binder died, cleaning up");
|
||||
}
|
||||
doCancelVibrateLocked(VibrationInfo.Status.CANCELLED);
|
||||
doCancelVibrateLocked(Vibration.Status.CANCELLED);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void end(VibrationInfo.Status status) {
|
||||
if (hasEnded()) {
|
||||
// Vibration already ended, keep first ending status set and ignore this one.
|
||||
return;
|
||||
}
|
||||
mStatus = status;
|
||||
mEndTimeDebug = System.currentTimeMillis();
|
||||
private void linkToDeath() throws RemoteException {
|
||||
mVibration.token.linkToDeath(this, 0);
|
||||
}
|
||||
|
||||
public boolean hasEnded() {
|
||||
return mStatus != VibrationInfo.Status.RUNNING;
|
||||
}
|
||||
|
||||
public boolean hasTimeoutLongerThan(long millis) {
|
||||
final long duration = effect.getDuration();
|
||||
return duration >= 0 && duration > millis;
|
||||
}
|
||||
|
||||
public boolean isHapticFeedback() {
|
||||
return VibratorService.this.isHapticFeedback(attrs.getUsage());
|
||||
}
|
||||
|
||||
public boolean isNotification() {
|
||||
return VibratorService.this.isNotification(attrs.getUsage());
|
||||
}
|
||||
|
||||
public boolean isRingtone() {
|
||||
return VibratorService.this.isRingtone(attrs.getUsage());
|
||||
}
|
||||
|
||||
public boolean isAlarm() {
|
||||
return VibratorService.this.isAlarm(attrs.getUsage());
|
||||
}
|
||||
|
||||
public boolean isFromSystem() {
|
||||
return uid == Process.SYSTEM_UID || uid == 0 || mSystemUiPackage.equals(opPkg);
|
||||
}
|
||||
|
||||
public VibrationInfo toInfo() {
|
||||
return new VibrationInfo(
|
||||
mStartTimeDebug, mEndTimeDebug, effect, originalEffect, scale, attrs,
|
||||
uid, opPkg, reason, mStatus);
|
||||
private void unlinkToDeath() {
|
||||
mVibration.token.unlinkToDeath(this, 0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -273,17 +202,17 @@ public class VibratorService extends IVibratorService.Stub {
|
||||
|
||||
private final long mStartTimeDebug;
|
||||
private long mEndTimeDebug;
|
||||
private VibrationInfo.Status mStatus;
|
||||
private Vibration.Status mStatus;
|
||||
|
||||
private ExternalVibrationHolder(ExternalVibration externalVibration) {
|
||||
this.externalVibration = externalVibration;
|
||||
this.scale = IExternalVibratorService.SCALE_NONE;
|
||||
mStartTimeDebug = System.currentTimeMillis();
|
||||
mStatus = VibrationInfo.Status.RUNNING;
|
||||
mStatus = Vibration.Status.RUNNING;
|
||||
}
|
||||
|
||||
public void end(VibrationInfo.Status status) {
|
||||
if (mStatus != VibrationInfo.Status.RUNNING) {
|
||||
public void end(Vibration.Status status) {
|
||||
if (mStatus != Vibration.Status.RUNNING) {
|
||||
// Vibration already ended, keep first ending status set and ignore this one.
|
||||
return;
|
||||
}
|
||||
@@ -291,8 +220,8 @@ public class VibratorService extends IVibratorService.Stub {
|
||||
mEndTimeDebug = System.currentTimeMillis();
|
||||
}
|
||||
|
||||
public VibrationInfo toInfo() {
|
||||
return new VibrationInfo(
|
||||
public Vibration.DebugInfo getDebugInfo() {
|
||||
return new Vibration.DebugInfo(
|
||||
mStartTimeDebug, mEndTimeDebug, /* effect= */ null, /* originalEffect= */ null,
|
||||
scale, externalVibration.getVibrationAttributes(),
|
||||
externalVibration.getUid(), externalVibration.getPackage(),
|
||||
@@ -300,159 +229,6 @@ public class VibratorService extends IVibratorService.Stub {
|
||||
}
|
||||
}
|
||||
|
||||
/** Debug information about vibrations. */
|
||||
private static class VibrationInfo {
|
||||
|
||||
public enum Status {
|
||||
RUNNING,
|
||||
FINISHED,
|
||||
FORWARDED_TO_INPUT_DEVICES,
|
||||
CANCELLED,
|
||||
ERROR_APP_OPS,
|
||||
IGNORED,
|
||||
IGNORED_APP_OPS,
|
||||
IGNORED_BACKGROUND,
|
||||
IGNORED_RINGTONE,
|
||||
IGNORED_UNKNOWN_VIBRATION,
|
||||
IGNORED_UNSUPPORTED,
|
||||
IGNORED_FOR_ALARM,
|
||||
IGNORED_FOR_EXTERNAL,
|
||||
IGNORED_FOR_ONGOING,
|
||||
IGNORED_FOR_POWER,
|
||||
IGNORED_FOR_SETTINGS,
|
||||
}
|
||||
|
||||
private final long mStartTimeDebug;
|
||||
private final long mEndTimeDebug;
|
||||
private final VibrationEffect mEffect;
|
||||
private final VibrationEffect mOriginalEffect;
|
||||
private final float mScale;
|
||||
private final VibrationAttributes mAttrs;
|
||||
private final int mUid;
|
||||
private final String mOpPkg;
|
||||
private final String mReason;
|
||||
private final VibrationInfo.Status mStatus;
|
||||
|
||||
VibrationInfo(long startTimeDebug, long endTimeDebug, VibrationEffect effect,
|
||||
VibrationEffect originalEffect, float scale, VibrationAttributes attrs,
|
||||
int uid, String opPkg, String reason, VibrationInfo.Status status) {
|
||||
mStartTimeDebug = startTimeDebug;
|
||||
mEndTimeDebug = endTimeDebug;
|
||||
mEffect = effect;
|
||||
mOriginalEffect = originalEffect;
|
||||
mScale = scale;
|
||||
mAttrs = attrs;
|
||||
mUid = uid;
|
||||
mOpPkg = opPkg;
|
||||
mReason = reason;
|
||||
mStatus = status;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return new StringBuilder()
|
||||
.append("startTime: ")
|
||||
.append(DEBUG_DATE_FORMAT.format(new Date(mStartTimeDebug)))
|
||||
.append(", endTime: ")
|
||||
.append(mEndTimeDebug == 0 ? null
|
||||
: DEBUG_DATE_FORMAT.format(new Date(mEndTimeDebug)))
|
||||
.append(", status: ")
|
||||
.append(mStatus.name().toLowerCase())
|
||||
.append(", effect: ")
|
||||
.append(mEffect)
|
||||
.append(", originalEffect: ")
|
||||
.append(mOriginalEffect)
|
||||
.append(", scale: ")
|
||||
.append(String.format("%.2f", mScale))
|
||||
.append(", attrs: ")
|
||||
.append(mAttrs)
|
||||
.append(", uid: ")
|
||||
.append(mUid)
|
||||
.append(", opPkg: ")
|
||||
.append(mOpPkg)
|
||||
.append(", reason: ")
|
||||
.append(mReason)
|
||||
.toString();
|
||||
}
|
||||
|
||||
void dumpProto(ProtoOutputStream proto, long fieldId) {
|
||||
final long token = proto.start(fieldId);
|
||||
proto.write(VibrationProto.START_TIME, mStartTimeDebug);
|
||||
proto.write(VibrationProto.END_TIME, mEndTimeDebug);
|
||||
proto.write(VibrationProto.STATUS, mStatus.ordinal());
|
||||
|
||||
final long attrsToken = proto.start(VibrationProto.ATTRIBUTES);
|
||||
proto.write(VibrationAttributesProto.USAGE, mAttrs.getUsage());
|
||||
proto.write(VibrationAttributesProto.AUDIO_USAGE, mAttrs.getAudioUsage());
|
||||
proto.write(VibrationAttributesProto.FLAGS, mAttrs.getFlags());
|
||||
proto.end(attrsToken);
|
||||
|
||||
if (mEffect != null) {
|
||||
dumpEffect(proto, VibrationProto.EFFECT, mEffect);
|
||||
}
|
||||
if (mOriginalEffect != null) {
|
||||
dumpEffect(proto, VibrationProto.ORIGINAL_EFFECT, mOriginalEffect);
|
||||
}
|
||||
|
||||
proto.end(token);
|
||||
}
|
||||
|
||||
private void dumpEffect(ProtoOutputStream proto, long fieldId, VibrationEffect effect) {
|
||||
final long token = proto.start(fieldId);
|
||||
if (effect instanceof VibrationEffect.OneShot) {
|
||||
dumpEffect(proto, VibrationEffectProto.ONESHOT, (VibrationEffect.OneShot) effect);
|
||||
} else if (effect instanceof VibrationEffect.Waveform) {
|
||||
dumpEffect(proto, VibrationEffectProto.WAVEFORM, (VibrationEffect.Waveform) effect);
|
||||
} else if (effect instanceof VibrationEffect.Prebaked) {
|
||||
dumpEffect(proto, VibrationEffectProto.PREBAKED, (VibrationEffect.Prebaked) effect);
|
||||
} else if (effect instanceof VibrationEffect.Composed) {
|
||||
dumpEffect(proto, VibrationEffectProto.COMPOSED, (VibrationEffect.Composed) effect);
|
||||
}
|
||||
proto.end(token);
|
||||
}
|
||||
|
||||
private void dumpEffect(ProtoOutputStream proto, long fieldId,
|
||||
VibrationEffect.OneShot effect) {
|
||||
final long token = proto.start(fieldId);
|
||||
proto.write(OneShotProto.DURATION, (int) effect.getDuration());
|
||||
proto.write(OneShotProto.AMPLITUDE, effect.getAmplitude());
|
||||
proto.end(token);
|
||||
}
|
||||
|
||||
private void dumpEffect(ProtoOutputStream proto, long fieldId,
|
||||
VibrationEffect.Waveform effect) {
|
||||
final long token = proto.start(fieldId);
|
||||
for (long timing : effect.getTimings()) {
|
||||
proto.write(WaveformProto.TIMINGS, (int) timing);
|
||||
}
|
||||
for (int amplitude : effect.getAmplitudes()) {
|
||||
proto.write(WaveformProto.AMPLITUDES, amplitude);
|
||||
}
|
||||
proto.write(WaveformProto.REPEAT, effect.getRepeatIndex() >= 0);
|
||||
proto.end(token);
|
||||
}
|
||||
|
||||
private void dumpEffect(ProtoOutputStream proto, long fieldId,
|
||||
VibrationEffect.Prebaked effect) {
|
||||
final long token = proto.start(fieldId);
|
||||
proto.write(PrebakedProto.EFFECT_ID, effect.getId());
|
||||
proto.write(PrebakedProto.EFFECT_STRENGTH, effect.getEffectStrength());
|
||||
proto.write(PrebakedProto.FALLBACK, effect.shouldFallback());
|
||||
proto.end(token);
|
||||
}
|
||||
|
||||
private void dumpEffect(ProtoOutputStream proto, long fieldId,
|
||||
VibrationEffect.Composed effect) {
|
||||
final long token = proto.start(fieldId);
|
||||
for (PrimitiveEffect primitive : effect.getPrimitiveEffects()) {
|
||||
proto.write(ComposedProto.EFFECT_IDS, primitive.id);
|
||||
proto.write(ComposedProto.EFFECT_SCALES, primitive.scale);
|
||||
proto.write(ComposedProto.DELAYS, primitive.delay);
|
||||
}
|
||||
proto.end(token);
|
||||
}
|
||||
}
|
||||
|
||||
VibratorService(Context context) {
|
||||
this(context, new Injector());
|
||||
}
|
||||
@@ -546,7 +322,7 @@ public class VibratorService extends IVibratorService.Stub {
|
||||
if (DEBUG) {
|
||||
Slog.d(TAG, "Vibration finished by callback, cleaning up");
|
||||
}
|
||||
doCancelVibrateLocked(VibrationInfo.Status.FINISHED);
|
||||
doCancelVibrateLocked(Vibration.Status.FINISHED);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -639,7 +415,8 @@ public class VibratorService extends IVibratorService.Stub {
|
||||
}
|
||||
attrs = fixupVibrationAttributes(attrs);
|
||||
synchronized (mLock) {
|
||||
Vibration vib = new Vibration(null, effect, attrs, uid, opPkg, null);
|
||||
Vibration vib = new Vibration(null, mNextVibrationId.getAndIncrement(), effect,
|
||||
attrs, uid, opPkg, null);
|
||||
mAlwaysOnEffects.put(alwaysOnId, vib);
|
||||
updateAlwaysOnLocked(alwaysOnId, vib);
|
||||
}
|
||||
@@ -717,24 +494,26 @@ public class VibratorService extends IVibratorService.Stub {
|
||||
}
|
||||
|
||||
attrs = fixupVibrationAttributes(attrs);
|
||||
Vibration vib = new Vibration(token, effect, attrs, uid, opPkg, reason);
|
||||
Vibration vib = new Vibration(token, mNextVibrationId.getAndIncrement(), effect, attrs,
|
||||
uid, opPkg, reason);
|
||||
|
||||
// If our current vibration is longer than the new vibration and is the same amplitude,
|
||||
// then just let the current one finish.
|
||||
synchronized (mLock) {
|
||||
VibrationEffect currentEffect =
|
||||
mCurrentVibration == null ? null : mCurrentVibration.getEffect();
|
||||
if (effect instanceof VibrationEffect.OneShot
|
||||
&& mCurrentVibration != null
|
||||
&& mCurrentVibration.effect instanceof VibrationEffect.OneShot) {
|
||||
&& currentEffect instanceof VibrationEffect.OneShot) {
|
||||
VibrationEffect.OneShot newOneShot = (VibrationEffect.OneShot) effect;
|
||||
VibrationEffect.OneShot currentOneShot =
|
||||
(VibrationEffect.OneShot) mCurrentVibration.effect;
|
||||
if (mCurrentVibration.hasTimeoutLongerThan(newOneShot.getDuration())
|
||||
(VibrationEffect.OneShot) currentEffect;
|
||||
if (currentOneShot.getDuration() > newOneShot.getDuration()
|
||||
&& newOneShot.getAmplitude() == currentOneShot.getAmplitude()) {
|
||||
if (DEBUG) {
|
||||
Slog.d(TAG,
|
||||
"Ignoring incoming vibration in favor of current vibration");
|
||||
}
|
||||
endVibrationLocked(vib, VibrationInfo.Status.IGNORED_FOR_ONGOING);
|
||||
endVibrationLocked(vib, Vibration.Status.IGNORED_FOR_ONGOING);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -746,7 +525,7 @@ public class VibratorService extends IVibratorService.Stub {
|
||||
if (DEBUG) {
|
||||
Slog.d(TAG, "Ignoring incoming vibration for current external vibration");
|
||||
}
|
||||
endVibrationLocked(vib, VibrationInfo.Status.IGNORED_FOR_EXTERNAL);
|
||||
endVibrationLocked(vib, Vibration.Status.IGNORED_FOR_EXTERNAL);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -756,32 +535,32 @@ public class VibratorService extends IVibratorService.Stub {
|
||||
// alarms, in favor of one-shot vibrations that are likely quite short.
|
||||
if (!isRepeatingVibration(effect)
|
||||
&& mCurrentVibration != null
|
||||
&& isRepeatingVibration(mCurrentVibration.effect)) {
|
||||
&& isRepeatingVibration(currentEffect)) {
|
||||
if (DEBUG) {
|
||||
Slog.d(TAG, "Ignoring incoming vibration in favor of alarm vibration");
|
||||
}
|
||||
endVibrationLocked(vib, VibrationInfo.Status.IGNORED_FOR_ALARM);
|
||||
endVibrationLocked(vib, Vibration.Status.IGNORED_FOR_ALARM);
|
||||
return;
|
||||
}
|
||||
|
||||
if (mProcStatesCache.get(uid, ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND)
|
||||
> ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND
|
||||
&& !vib.isNotification() && !vib.isRingtone() && !vib.isAlarm()) {
|
||||
&& !isNotification(vib) && !isRingtone(vib) && !isAlarm(vib)) {
|
||||
Slog.e(TAG, "Ignoring incoming vibration as process with"
|
||||
+ " uid= " + uid + " is background,"
|
||||
+ " attrs= " + vib.attrs);
|
||||
endVibrationLocked(vib, VibrationInfo.Status.IGNORED_BACKGROUND);
|
||||
endVibrationLocked(vib, Vibration.Status.IGNORED_BACKGROUND);
|
||||
return;
|
||||
}
|
||||
linkVibration(vib);
|
||||
linkVibrationLocked(vib);
|
||||
final long ident = Binder.clearCallingIdentity();
|
||||
try {
|
||||
doCancelVibrateLocked(VibrationInfo.Status.CANCELLED);
|
||||
doCancelVibrateLocked(Vibration.Status.CANCELLED);
|
||||
startVibrationLocked(vib);
|
||||
|
||||
if (!vib.hasEnded() && mCurrentVibration.id != vib.id) {
|
||||
// Vibration was unexpectedly ignored: add to list for debugging
|
||||
endVibrationLocked(vib, VibrationInfo.Status.IGNORED);
|
||||
endVibrationLocked(vib, Vibration.Status.IGNORED);
|
||||
}
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(ident);
|
||||
@@ -801,13 +580,13 @@ public class VibratorService extends IVibratorService.Stub {
|
||||
return effect.getDuration() == Long.MAX_VALUE;
|
||||
}
|
||||
|
||||
private void endVibrationLocked(Vibration vib, VibrationInfo.Status status) {
|
||||
final LinkedList<VibrationInfo> previousVibrations;
|
||||
if (vib.isRingtone()) {
|
||||
private void endVibrationLocked(Vibration vib, Vibration.Status status) {
|
||||
final LinkedList<Vibration.DebugInfo> previousVibrations;
|
||||
if (isRingtone(vib)) {
|
||||
previousVibrations = mPreviousRingVibrations;
|
||||
} else if (vib.isNotification()) {
|
||||
} else if (isNotification(vib)) {
|
||||
previousVibrations = mPreviousNotificationVibrations;
|
||||
} else if (vib.isAlarm()) {
|
||||
} else if (isAlarm(vib)) {
|
||||
previousVibrations = mPreviousAlarmVibrations;
|
||||
} else {
|
||||
previousVibrations = mPreviousVibrations;
|
||||
@@ -817,15 +596,15 @@ public class VibratorService extends IVibratorService.Stub {
|
||||
previousVibrations.removeFirst();
|
||||
}
|
||||
vib.end(status);
|
||||
previousVibrations.addLast(vib.toInfo());
|
||||
previousVibrations.addLast(vib.getDebugInfo());
|
||||
}
|
||||
|
||||
private void endVibrationLocked(ExternalVibrationHolder vib, VibrationInfo.Status status) {
|
||||
private void endVibrationLocked(ExternalVibrationHolder vib, Vibration.Status status) {
|
||||
if (mPreviousExternalVibrations.size() > mPreviousVibrationsLimit) {
|
||||
mPreviousExternalVibrations.removeFirst();
|
||||
}
|
||||
vib.end(status);
|
||||
mPreviousExternalVibrations.addLast(vib.toInfo());
|
||||
mPreviousExternalVibrations.addLast(vib.getDebugInfo());
|
||||
}
|
||||
|
||||
@Override // Binder call
|
||||
@@ -841,7 +620,7 @@ public class VibratorService extends IVibratorService.Stub {
|
||||
}
|
||||
final long ident = Binder.clearCallingIdentity();
|
||||
try {
|
||||
doCancelVibrateLocked(VibrationInfo.Status.CANCELLED);
|
||||
doCancelVibrateLocked(Vibration.Status.CANCELLED);
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(ident);
|
||||
}
|
||||
@@ -850,7 +629,7 @@ public class VibratorService extends IVibratorService.Stub {
|
||||
}
|
||||
|
||||
@GuardedBy("mLock")
|
||||
private void doCancelVibrateLocked(VibrationInfo.Status status) {
|
||||
private void doCancelVibrateLocked(Vibration.Status status) {
|
||||
Trace.asyncTraceEnd(Trace.TRACE_TAG_VIBRATOR, "vibration", 0);
|
||||
Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "doCancelVibrateLocked");
|
||||
try {
|
||||
@@ -879,7 +658,7 @@ public class VibratorService extends IVibratorService.Stub {
|
||||
synchronized (mLock) {
|
||||
// Make sure the vibration is really done. This also reports that the vibration is
|
||||
// finished.
|
||||
doCancelVibrateLocked(VibrationInfo.Status.FINISHED);
|
||||
doCancelVibrateLocked(Vibration.Status.FINISHED);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -903,21 +682,22 @@ public class VibratorService extends IVibratorService.Stub {
|
||||
try {
|
||||
// Set current vibration before starting it, so callback will work.
|
||||
mCurrentVibration = vib;
|
||||
if (vib.effect instanceof VibrationEffect.OneShot) {
|
||||
VibrationEffect effect = vib.getEffect();
|
||||
if (effect instanceof VibrationEffect.OneShot) {
|
||||
Trace.asyncTraceBegin(Trace.TRACE_TAG_VIBRATOR, "vibration", 0);
|
||||
doVibratorOn(vib);
|
||||
} else if (vib.effect instanceof VibrationEffect.Waveform) {
|
||||
} else if (effect instanceof VibrationEffect.Waveform) {
|
||||
Trace.asyncTraceBegin(Trace.TRACE_TAG_VIBRATOR, "vibration", 0);
|
||||
doVibratorWaveformEffectLocked(vib);
|
||||
} else if (vib.effect instanceof VibrationEffect.Prebaked) {
|
||||
} else if (effect instanceof VibrationEffect.Prebaked) {
|
||||
Trace.asyncTraceBegin(Trace.TRACE_TAG_VIBRATOR, "vibration", 0);
|
||||
doVibratorPrebakedEffectLocked(vib);
|
||||
} else if (vib.effect instanceof VibrationEffect.Composed) {
|
||||
} else if (effect instanceof VibrationEffect.Composed) {
|
||||
Trace.asyncTraceBegin(Trace.TRACE_TAG_VIBRATOR, "vibration", 0);
|
||||
doVibratorComposedEffectLocked(vib);
|
||||
} else {
|
||||
Slog.e(TAG, "Unknown vibration type, ignoring");
|
||||
endVibrationLocked(vib, VibrationInfo.Status.IGNORED_UNKNOWN_VIBRATION);
|
||||
endVibrationLocked(vib, Vibration.Status.IGNORED_UNKNOWN_VIBRATION);
|
||||
// The set current vibration is not actually playing, so drop it.
|
||||
mCurrentVibration = null;
|
||||
}
|
||||
@@ -939,11 +719,7 @@ public class VibratorService extends IVibratorService.Stub {
|
||||
|
||||
/** Scale the vibration effect by the intensity as appropriate based its intent. */
|
||||
private void applyVibrationIntensityScalingLocked(Vibration vib) {
|
||||
VibrationEffect scaled = mVibrationScaler.scale(vib.effect, vib.attrs.getUsage());
|
||||
if (!scaled.equals(vib.effect)) {
|
||||
vib.originalEffect = vib.effect;
|
||||
vib.effect = scaled;
|
||||
}
|
||||
vib.updateEffect(mVibrationScaler.scale(vib.getEffect(), vib.attrs.getUsage()));
|
||||
}
|
||||
|
||||
private static boolean shouldBypassDnd(VibrationAttributes attrs) {
|
||||
@@ -969,21 +745,21 @@ public class VibratorService extends IVibratorService.Stub {
|
||||
|
||||
private boolean shouldVibrate(Vibration vib) {
|
||||
if (!shouldVibrateForPowerModeLocked(vib)) {
|
||||
endVibrationLocked(vib, VibrationInfo.Status.IGNORED_FOR_POWER);
|
||||
endVibrationLocked(vib, Vibration.Status.IGNORED_FOR_POWER);
|
||||
return false;
|
||||
}
|
||||
|
||||
int intensity = mVibrationSettings.getCurrentIntensity(vib.attrs.getUsage());
|
||||
if (intensity == Vibrator.VIBRATION_INTENSITY_OFF) {
|
||||
endVibrationLocked(vib, VibrationInfo.Status.IGNORED_FOR_SETTINGS);
|
||||
endVibrationLocked(vib, Vibration.Status.IGNORED_FOR_SETTINGS);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (vib.isRingtone() && !mVibrationSettings.shouldVibrateForRingtone()) {
|
||||
if (isRingtone(vib) && !mVibrationSettings.shouldVibrateForRingtone()) {
|
||||
if (DEBUG) {
|
||||
Slog.e(TAG, "Vibrate ignored, not vibrating for ringtones");
|
||||
}
|
||||
endVibrationLocked(vib, VibrationInfo.Status.IGNORED_RINGTONE);
|
||||
endVibrationLocked(vib, Vibration.Status.IGNORED_RINGTONE);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -993,9 +769,9 @@ public class VibratorService extends IVibratorService.Stub {
|
||||
// We might be getting calls from within system_server, so we don't actually
|
||||
// want to throw a SecurityException here.
|
||||
Slog.w(TAG, "Would be an error: vibrate from uid " + vib.uid);
|
||||
endVibrationLocked(vib, VibrationInfo.Status.ERROR_APP_OPS);
|
||||
endVibrationLocked(vib, Vibration.Status.ERROR_APP_OPS);
|
||||
} else {
|
||||
endVibrationLocked(vib, VibrationInfo.Status.IGNORED_APP_OPS);
|
||||
endVibrationLocked(vib, Vibration.Status.IGNORED_APP_OPS);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -1004,14 +780,14 @@ public class VibratorService extends IVibratorService.Stub {
|
||||
}
|
||||
|
||||
@GuardedBy("mLock")
|
||||
private void reportFinishVibrationLocked(VibrationInfo.Status status) {
|
||||
private void reportFinishVibrationLocked(Vibration.Status status) {
|
||||
Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "reportFinishVibrationLocked");
|
||||
try {
|
||||
if (mCurrentVibration != null) {
|
||||
endVibrationLocked(mCurrentVibration, status);
|
||||
mAppOps.finishOp(AppOpsManager.OP_VIBRATE, mCurrentVibration.uid,
|
||||
mCurrentVibration.opPkg);
|
||||
unlinkVibration(mCurrentVibration);
|
||||
unlinkVibrationLocked();
|
||||
mCurrentVibration = null;
|
||||
}
|
||||
} finally {
|
||||
@@ -1019,21 +795,27 @@ public class VibratorService extends IVibratorService.Stub {
|
||||
}
|
||||
}
|
||||
|
||||
private void linkVibration(Vibration vib) {
|
||||
@GuardedBy("mLock")
|
||||
private void linkVibrationLocked(Vibration vib) {
|
||||
// Unlink previously linked vibration, if any.
|
||||
unlinkVibrationLocked();
|
||||
// Only link against waveforms since they potentially don't have a finish if
|
||||
// they're repeating. Let other effects just play out until they're done.
|
||||
if (vib.effect instanceof VibrationEffect.Waveform) {
|
||||
if (vib.getEffect() instanceof VibrationEffect.Waveform) {
|
||||
try {
|
||||
vib.token.linkToDeath(vib, 0);
|
||||
mCurrentVibrationDeathRecipient = new VibrationDeathRecipient(vib);
|
||||
mCurrentVibrationDeathRecipient.linkToDeath();
|
||||
} catch (RemoteException e) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void unlinkVibration(Vibration vib) {
|
||||
if (vib.effect instanceof VibrationEffect.Waveform) {
|
||||
vib.token.unlinkToDeath(vib, 0);
|
||||
@GuardedBy("mLock")
|
||||
private void unlinkVibrationLocked() {
|
||||
if (mCurrentVibrationDeathRecipient != null) {
|
||||
mCurrentVibrationDeathRecipient.unlinkToDeath();
|
||||
mCurrentVibrationDeathRecipient = null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1045,7 +827,7 @@ public class VibratorService extends IVibratorService.Stub {
|
||||
|
||||
if (devicesUpdated || lowPowerModeUpdated) {
|
||||
// If the state changes out from under us then just reset.
|
||||
doCancelVibrateLocked(VibrationInfo.Status.CANCELLED);
|
||||
doCancelVibrateLocked(Vibration.Status.CANCELLED);
|
||||
}
|
||||
|
||||
updateAlwaysOnLocked();
|
||||
@@ -1067,7 +849,7 @@ public class VibratorService extends IVibratorService.Stub {
|
||||
if (!shouldVibrate(vib)) {
|
||||
effect = null;
|
||||
} else {
|
||||
effect = mVibrationScaler.scale(vib.effect, vib.attrs.getUsage());
|
||||
effect = mVibrationScaler.scale(vib.getEffect(), vib.attrs.getUsage());
|
||||
}
|
||||
mVibratorController.updateAlwaysOn(id, effect);
|
||||
}
|
||||
@@ -1083,7 +865,7 @@ public class VibratorService extends IVibratorService.Stub {
|
||||
private void doVibratorOn(Vibration vib) {
|
||||
Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "doVibratorOn");
|
||||
try {
|
||||
final VibrationEffect.OneShot oneShot = (VibrationEffect.OneShot) vib.effect;
|
||||
final VibrationEffect.OneShot oneShot = (VibrationEffect.OneShot) vib.getEffect();
|
||||
if (DEBUG) {
|
||||
Slog.d(TAG, "Turning vibrator on for " + oneShot.getDuration() + " ms"
|
||||
+ " with amplitude " + oneShot.getAmplitude() + ".");
|
||||
@@ -1093,7 +875,7 @@ public class VibratorService extends IVibratorService.Stub {
|
||||
if (inputDevicesAvailable) {
|
||||
// The set current vibration is no longer being played by this service, so drop it.
|
||||
mCurrentVibration = null;
|
||||
endVibrationLocked(vib, VibrationInfo.Status.FORWARDED_TO_INPUT_DEVICES);
|
||||
endVibrationLocked(vib, Vibration.Status.FORWARDED_TO_INPUT_DEVICES);
|
||||
} else {
|
||||
noteVibratorOnLocked(vib.uid, oneShot.getDuration());
|
||||
// Note: ordering is important here! Many haptic drivers will reset their
|
||||
@@ -1128,11 +910,11 @@ public class VibratorService extends IVibratorService.Stub {
|
||||
Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "doVibratorWaveformEffectLocked");
|
||||
try {
|
||||
boolean inputDevicesAvailable = mInputDeviceDelegate.vibrateIfAvailable(
|
||||
vib.uid, vib.opPkg, vib.effect, vib.reason, vib.attrs);
|
||||
vib.uid, vib.opPkg, vib.getEffect(), vib.reason, vib.attrs);
|
||||
if (inputDevicesAvailable) {
|
||||
// The set current vibration is no longer being played by this service, so drop it.
|
||||
mCurrentVibration = null;
|
||||
endVibrationLocked(vib, VibrationInfo.Status.FORWARDED_TO_INPUT_DEVICES);
|
||||
endVibrationLocked(vib, Vibration.Status.FORWARDED_TO_INPUT_DEVICES);
|
||||
} else {
|
||||
// mThread better be null here. doCancelVibrate should always be
|
||||
// called before startNextVibrationLocked or startVibrationLocked.
|
||||
@@ -1148,7 +930,7 @@ public class VibratorService extends IVibratorService.Stub {
|
||||
private void doVibratorPrebakedEffectLocked(Vibration vib) {
|
||||
Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "doVibratorPrebakedEffectLocked");
|
||||
try {
|
||||
final VibrationEffect.Prebaked prebaked = (VibrationEffect.Prebaked) vib.effect;
|
||||
final VibrationEffect.Prebaked prebaked = (VibrationEffect.Prebaked) vib.getEffect();
|
||||
// Input devices don't support prebaked effect, so skip trying it with them and allow
|
||||
// fallback to be attempted.
|
||||
if (!mInputDeviceDelegate.isAvailable()) {
|
||||
@@ -1158,7 +940,7 @@ public class VibratorService extends IVibratorService.Stub {
|
||||
return;
|
||||
}
|
||||
}
|
||||
endVibrationLocked(vib, VibrationInfo.Status.IGNORED_UNSUPPORTED);
|
||||
endVibrationLocked(vib, Vibration.Status.IGNORED_UNSUPPORTED);
|
||||
// The set current vibration is not actually playing, so drop it.
|
||||
mCurrentVibration = null;
|
||||
|
||||
@@ -1170,11 +952,11 @@ public class VibratorService extends IVibratorService.Stub {
|
||||
Slog.w(TAG, "Failed to play prebaked effect, no fallback");
|
||||
return;
|
||||
}
|
||||
Vibration fallbackVib = new Vibration(vib.token, effect, vib.attrs, vib.uid,
|
||||
vib.opPkg, vib.reason + " (fallback)");
|
||||
Vibration fallbackVib = new Vibration(vib.token, mNextVibrationId.getAndIncrement(),
|
||||
effect, vib.attrs, vib.uid, vib.opPkg, vib.reason + " (fallback)");
|
||||
// Set current vibration before starting it, so callback will work.
|
||||
mCurrentVibration = fallbackVib;
|
||||
linkVibration(fallbackVib);
|
||||
linkVibrationLocked(fallbackVib);
|
||||
applyVibrationIntensityScalingLocked(fallbackVib);
|
||||
startVibrationInnerLocked(fallbackVib);
|
||||
} finally {
|
||||
@@ -1187,18 +969,18 @@ public class VibratorService extends IVibratorService.Stub {
|
||||
Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "doVibratorComposedEffectLocked");
|
||||
|
||||
try {
|
||||
final VibrationEffect.Composed composed = (VibrationEffect.Composed) vib.effect;
|
||||
final VibrationEffect.Composed composed = (VibrationEffect.Composed) vib.getEffect();
|
||||
boolean inputDevicesAvailable = mInputDeviceDelegate.vibrateIfAvailable(
|
||||
vib.uid, vib.opPkg, composed, vib.reason, vib.attrs);
|
||||
if (inputDevicesAvailable) {
|
||||
// The set current vibration is no longer being played by this service, so drop it.
|
||||
mCurrentVibration = null;
|
||||
endVibrationLocked(vib, VibrationInfo.Status.FORWARDED_TO_INPUT_DEVICES);
|
||||
endVibrationLocked(vib, Vibration.Status.FORWARDED_TO_INPUT_DEVICES);
|
||||
return;
|
||||
} else if (!mVibratorController.hasCapability(IVibrator.CAP_COMPOSE_EFFECTS)) {
|
||||
// The set current vibration is not actually playing, so drop it.
|
||||
mCurrentVibration = null;
|
||||
endVibrationLocked(vib, VibrationInfo.Status.IGNORED_UNSUPPORTED);
|
||||
endVibrationLocked(vib, Vibration.Status.IGNORED_UNSUPPORTED);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1212,20 +994,24 @@ public class VibratorService extends IVibratorService.Stub {
|
||||
|
||||
}
|
||||
|
||||
private static boolean isNotification(int usageHint) {
|
||||
return usageHint == VibrationAttributes.USAGE_NOTIFICATION;
|
||||
private static boolean isNotification(Vibration vib) {
|
||||
return vib.attrs.getUsage() == VibrationAttributes.USAGE_NOTIFICATION;
|
||||
}
|
||||
|
||||
private static boolean isRingtone(int usageHint) {
|
||||
return usageHint == VibrationAttributes.USAGE_RINGTONE;
|
||||
private static boolean isRingtone(Vibration vib) {
|
||||
return vib.attrs.getUsage() == VibrationAttributes.USAGE_RINGTONE;
|
||||
}
|
||||
|
||||
private static boolean isHapticFeedback(int usageHint) {
|
||||
return usageHint == VibrationAttributes.USAGE_TOUCH;
|
||||
private static boolean isHapticFeedback(Vibration vib) {
|
||||
return vib.attrs.getUsage() == VibrationAttributes.USAGE_TOUCH;
|
||||
}
|
||||
|
||||
private static boolean isAlarm(int usageHint) {
|
||||
return usageHint == VibrationAttributes.USAGE_ALARM;
|
||||
private static boolean isAlarm(Vibration vib) {
|
||||
return vib.attrs.getUsage() == VibrationAttributes.USAGE_ALARM;
|
||||
}
|
||||
|
||||
private boolean isFromSystem(Vibration vib) {
|
||||
return vib.uid == Process.SYSTEM_UID || vib.uid == 0 || mSystemUiPackage.equals(vib.opPkg);
|
||||
}
|
||||
|
||||
private void noteVibratorOnLocked(int uid, long millis) {
|
||||
@@ -1254,13 +1040,13 @@ public class VibratorService extends IVibratorService.Stub {
|
||||
synchronized (mLock) {
|
||||
pw.print(" mCurrentVibration=");
|
||||
if (mCurrentVibration != null) {
|
||||
pw.println(mCurrentVibration.toInfo().toString());
|
||||
pw.println(mCurrentVibration.getDebugInfo().toString());
|
||||
} else {
|
||||
pw.println("null");
|
||||
}
|
||||
pw.print(" mCurrentExternalVibration=");
|
||||
if (mCurrentExternalVibration != null) {
|
||||
pw.println(mCurrentExternalVibration.toInfo().toString());
|
||||
pw.println(mCurrentExternalVibration.getDebugInfo().toString());
|
||||
} else {
|
||||
pw.println("null");
|
||||
}
|
||||
@@ -1269,28 +1055,28 @@ public class VibratorService extends IVibratorService.Stub {
|
||||
pw.println(" mVibrationSettings=" + mVibrationSettings);
|
||||
pw.println();
|
||||
pw.println(" Previous ring vibrations:");
|
||||
for (VibrationInfo info : mPreviousRingVibrations) {
|
||||
for (Vibration.DebugInfo info : mPreviousRingVibrations) {
|
||||
pw.print(" ");
|
||||
pw.println(info.toString());
|
||||
}
|
||||
|
||||
pw.println(" Previous notification vibrations:");
|
||||
for (VibrationInfo info : mPreviousNotificationVibrations) {
|
||||
for (Vibration.DebugInfo info : mPreviousNotificationVibrations) {
|
||||
pw.println(" " + info);
|
||||
}
|
||||
|
||||
pw.println(" Previous alarm vibrations:");
|
||||
for (VibrationInfo info : mPreviousAlarmVibrations) {
|
||||
for (Vibration.DebugInfo info : mPreviousAlarmVibrations) {
|
||||
pw.println(" " + info);
|
||||
}
|
||||
|
||||
pw.println(" Previous vibrations:");
|
||||
for (VibrationInfo info : mPreviousVibrations) {
|
||||
for (Vibration.DebugInfo info : mPreviousVibrations) {
|
||||
pw.println(" " + info);
|
||||
}
|
||||
|
||||
pw.println(" Previous external vibrations:");
|
||||
for (VibrationInfo info : mPreviousExternalVibrations) {
|
||||
for (Vibration.DebugInfo info : mPreviousExternalVibrations) {
|
||||
pw.println(" " + info);
|
||||
}
|
||||
}
|
||||
@@ -1301,11 +1087,11 @@ public class VibratorService extends IVibratorService.Stub {
|
||||
|
||||
synchronized (mLock) {
|
||||
if (mCurrentVibration != null) {
|
||||
mCurrentVibration.toInfo().dumpProto(proto,
|
||||
mCurrentVibration.getDebugInfo().dumpProto(proto,
|
||||
VibratorServiceDumpProto.CURRENT_VIBRATION);
|
||||
}
|
||||
if (mCurrentExternalVibration != null) {
|
||||
mCurrentExternalVibration.toInfo().dumpProto(proto,
|
||||
mCurrentExternalVibration.getDebugInfo().dumpProto(proto,
|
||||
VibratorServiceDumpProto.CURRENT_EXTERNAL_VIBRATION);
|
||||
}
|
||||
proto.write(VibratorServiceDumpProto.IS_VIBRATING, mVibratorController.isVibrating());
|
||||
@@ -1325,23 +1111,23 @@ public class VibratorService extends IVibratorService.Stub {
|
||||
proto.write(VibratorServiceDumpProto.RING_DEFAULT_INTENSITY,
|
||||
mVibrationSettings.getDefaultIntensity(VibrationAttributes.USAGE_RINGTONE));
|
||||
|
||||
for (VibrationInfo info : mPreviousRingVibrations) {
|
||||
for (Vibration.DebugInfo info : mPreviousRingVibrations) {
|
||||
info.dumpProto(proto, VibratorServiceDumpProto.PREVIOUS_RING_VIBRATIONS);
|
||||
}
|
||||
|
||||
for (VibrationInfo info : mPreviousNotificationVibrations) {
|
||||
for (Vibration.DebugInfo info : mPreviousNotificationVibrations) {
|
||||
info.dumpProto(proto, VibratorServiceDumpProto.PREVIOUS_NOTIFICATION_VIBRATIONS);
|
||||
}
|
||||
|
||||
for (VibrationInfo info : mPreviousAlarmVibrations) {
|
||||
for (Vibration.DebugInfo info : mPreviousAlarmVibrations) {
|
||||
info.dumpProto(proto, VibratorServiceDumpProto.PREVIOUS_ALARM_VIBRATIONS);
|
||||
}
|
||||
|
||||
for (VibrationInfo info : mPreviousVibrations) {
|
||||
for (Vibration.DebugInfo info : mPreviousVibrations) {
|
||||
info.dumpProto(proto, VibratorServiceDumpProto.PREVIOUS_VIBRATIONS);
|
||||
}
|
||||
|
||||
for (VibrationInfo info : mPreviousExternalVibrations) {
|
||||
for (Vibration.DebugInfo info : mPreviousExternalVibrations) {
|
||||
info.dumpProto(proto, VibratorServiceDumpProto.PREVIOUS_EXTERNAL_VIBRATIONS);
|
||||
}
|
||||
}
|
||||
@@ -1356,9 +1142,9 @@ public class VibratorService extends IVibratorService.Stub {
|
||||
private boolean mForceStop;
|
||||
|
||||
VibrateWaveformThread(Vibration vib) {
|
||||
mWaveform = (VibrationEffect.Waveform) vib.effect;
|
||||
mVibration = new Vibration(vib.token, /* effect= */ null, vib.attrs, vib.uid,
|
||||
vib.opPkg, vib.reason);
|
||||
mWaveform = (VibrationEffect.Waveform) vib.getEffect();
|
||||
mVibration = new Vibration(vib.token, /* id= */ 0, /* effect= */ null, vib.attrs,
|
||||
vib.uid, vib.opPkg, vib.reason);
|
||||
mTmpWorkSource.set(vib.uid);
|
||||
mWakeLock.setWorkSource(mTmpWorkSource);
|
||||
}
|
||||
@@ -1430,8 +1216,8 @@ public class VibratorService extends IVibratorService.Stub {
|
||||
// appropriate intervals.
|
||||
long onDuration = getTotalOnDuration(
|
||||
timings, amplitudes, index - 1, repeat);
|
||||
mVibration.effect = VibrationEffect.createOneShot(
|
||||
onDuration, amplitude);
|
||||
mVibration.updateEffect(
|
||||
VibrationEffect.createOneShot(onDuration, amplitude));
|
||||
doVibratorOn(mVibration);
|
||||
nextVibratorStopTime = now + onDuration;
|
||||
} else {
|
||||
@@ -1526,9 +1312,9 @@ public class VibratorService extends IVibratorService.Stub {
|
||||
// haptic feedback as part of the transition. So we don't cancel
|
||||
// system vibrations.
|
||||
if (mCurrentVibration != null
|
||||
&& !(mCurrentVibration.isHapticFeedback()
|
||||
&& mCurrentVibration.isFromSystem())) {
|
||||
doCancelVibrateLocked(VibrationInfo.Status.CANCELLED);
|
||||
&& !(isHapticFeedback(mCurrentVibration)
|
||||
&& isFromSystem(mCurrentVibration))) {
|
||||
doCancelVibrateLocked(Vibration.Status.CANCELLED);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1587,9 +1373,9 @@ public class VibratorService extends IVibratorService.Stub {
|
||||
vibHolder.scale = SCALE_MUTE;
|
||||
if (mode == AppOpsManager.MODE_ERRORED) {
|
||||
Slog.w(TAG, "Would be an error: external vibrate from uid " + vib.getUid());
|
||||
endVibrationLocked(vibHolder, VibrationInfo.Status.ERROR_APP_OPS);
|
||||
endVibrationLocked(vibHolder, Vibration.Status.ERROR_APP_OPS);
|
||||
} else {
|
||||
endVibrationLocked(vibHolder, VibrationInfo.Status.IGNORED_APP_OPS);
|
||||
endVibrationLocked(vibHolder, Vibration.Status.IGNORED_APP_OPS);
|
||||
}
|
||||
return IExternalVibratorService.SCALE_MUTE;
|
||||
}
|
||||
@@ -1607,10 +1393,10 @@ public class VibratorService extends IVibratorService.Stub {
|
||||
if (DEBUG) {
|
||||
Slog.d(TAG, "Vibrator going under external control.");
|
||||
}
|
||||
doCancelVibrateLocked(VibrationInfo.Status.CANCELLED);
|
||||
doCancelVibrateLocked(Vibration.Status.CANCELLED);
|
||||
mVibratorController.setExternalControl(true);
|
||||
} else {
|
||||
endVibrationLocked(mCurrentExternalVibration, VibrationInfo.Status.CANCELLED);
|
||||
endVibrationLocked(mCurrentExternalVibration, Vibration.Status.CANCELLED);
|
||||
}
|
||||
// At this point we either have an externally controlled vibration playing, or
|
||||
// no vibration playing. Since the interface defines that only one externally
|
||||
@@ -1640,12 +1426,12 @@ public class VibratorService extends IVibratorService.Stub {
|
||||
if (DEBUG) {
|
||||
Slog.e(TAG, "Stopping external vibration" + vib);
|
||||
}
|
||||
doCancelExternalVibrateLocked(VibrationInfo.Status.FINISHED);
|
||||
doCancelExternalVibrateLocked(Vibration.Status.FINISHED);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void doCancelExternalVibrateLocked(VibrationInfo.Status status) {
|
||||
private void doCancelExternalVibrateLocked(Vibration.Status status) {
|
||||
Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "doCancelExternalVibrateLocked");
|
||||
try {
|
||||
if (mCurrentExternalVibration == null) {
|
||||
@@ -1669,7 +1455,7 @@ public class VibratorService extends IVibratorService.Stub {
|
||||
if (DEBUG) {
|
||||
Slog.d(TAG, "External vibration finished because binder died");
|
||||
}
|
||||
doCancelExternalVibrateLocked(VibrationInfo.Status.CANCELLED);
|
||||
doCancelExternalVibrateLocked(Vibration.Status.CANCELLED);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
287
services/core/java/com/android/server/vibrator/Vibration.java
Normal file
287
services/core/java/com/android/server/vibrator/Vibration.java
Normal file
@@ -0,0 +1,287 @@
|
||||
/*
|
||||
* Copyright (C) 2020 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.server.vibrator;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.os.IBinder;
|
||||
import android.os.SystemClock;
|
||||
import android.os.VibrationAttributes;
|
||||
import android.os.VibrationEffect;
|
||||
import android.util.proto.ProtoOutputStream;
|
||||
|
||||
import com.android.server.ComposedProto;
|
||||
import com.android.server.OneShotProto;
|
||||
import com.android.server.PrebakedProto;
|
||||
import com.android.server.VibrationAttributesProto;
|
||||
import com.android.server.VibrationEffectProto;
|
||||
import com.android.server.VibrationProto;
|
||||
import com.android.server.WaveformProto;
|
||||
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
|
||||
/** Represents a vibration request to the vibrator service. */
|
||||
// TODO(b/159207608): Make this package-private once vibrator services are moved to this package
|
||||
public class Vibration {
|
||||
private static final String TAG = "Vibration";
|
||||
private static final SimpleDateFormat DEBUG_DATE_FORMAT =
|
||||
new SimpleDateFormat("MM-dd HH:mm:ss.SSS");
|
||||
|
||||
public enum Status {
|
||||
RUNNING,
|
||||
FINISHED,
|
||||
FORWARDED_TO_INPUT_DEVICES,
|
||||
CANCELLED,
|
||||
ERROR_APP_OPS,
|
||||
IGNORED,
|
||||
IGNORED_APP_OPS,
|
||||
IGNORED_BACKGROUND,
|
||||
IGNORED_RINGTONE,
|
||||
IGNORED_UNKNOWN_VIBRATION,
|
||||
IGNORED_UNSUPPORTED,
|
||||
IGNORED_FOR_ALARM,
|
||||
IGNORED_FOR_EXTERNAL,
|
||||
IGNORED_FOR_ONGOING,
|
||||
IGNORED_FOR_POWER,
|
||||
IGNORED_FOR_SETTINGS,
|
||||
}
|
||||
|
||||
/** Start time in CLOCK_BOOTTIME base. */
|
||||
public final long startTime;
|
||||
public final VibrationAttributes attrs;
|
||||
public final long id;
|
||||
public final int uid;
|
||||
public final String opPkg;
|
||||
public final String reason;
|
||||
public final IBinder token;
|
||||
|
||||
/** The actual effect to be played. */
|
||||
@Nullable
|
||||
private VibrationEffect mEffect;
|
||||
|
||||
/**
|
||||
* The original effect that was requested. Typically these two things differ because the effect
|
||||
* was scaled based on the users vibration intensity settings.
|
||||
*/
|
||||
@Nullable
|
||||
private VibrationEffect mOriginalEffect;
|
||||
|
||||
/**
|
||||
* Start/end times in unix epoch time. Only to be used for debugging purposes and to correlate
|
||||
* with other system events, any duration calculations should be done use {@link #startTime} so
|
||||
* as not to be affected by discontinuities created by RTC adjustments.
|
||||
*/
|
||||
private final long mStartTimeDebug;
|
||||
private long mEndTimeDebug;
|
||||
private Status mStatus;
|
||||
|
||||
public Vibration(IBinder token, int id, VibrationEffect effect,
|
||||
VibrationAttributes attrs, int uid, String opPkg, String reason) {
|
||||
this.token = token;
|
||||
this.mEffect = effect;
|
||||
this.id = id;
|
||||
this.startTime = SystemClock.elapsedRealtime();
|
||||
this.attrs = attrs;
|
||||
this.uid = uid;
|
||||
this.opPkg = opPkg;
|
||||
this.reason = reason;
|
||||
mStartTimeDebug = System.currentTimeMillis();
|
||||
mStatus = Status.RUNNING;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the {@link Status} of this vibration and the current system time as this
|
||||
* vibration end time, for debugging purposes.
|
||||
*
|
||||
* <p>This method will only accept given value if the current status is {@link
|
||||
* Status#RUNNING}.
|
||||
*/
|
||||
public void end(Status status) {
|
||||
if (hasEnded()) {
|
||||
// Vibration already ended, keep first ending status set and ignore this one.
|
||||
return;
|
||||
}
|
||||
mStatus = status;
|
||||
mEndTimeDebug = System.currentTimeMillis();
|
||||
}
|
||||
|
||||
/**
|
||||
* Replace this vibration effect if given {@code scaledEffect} is different, preserving the
|
||||
* original one for debug purposes.
|
||||
*/
|
||||
public void updateEffect(@NonNull VibrationEffect newEffect) {
|
||||
if (newEffect.equals(mEffect)) {
|
||||
return;
|
||||
}
|
||||
mOriginalEffect = mEffect;
|
||||
mEffect = newEffect;
|
||||
}
|
||||
|
||||
/** Return true is current status is different from {@link Status#RUNNING}. */
|
||||
public boolean hasEnded() {
|
||||
return mStatus != Status.RUNNING;
|
||||
}
|
||||
|
||||
/** Return the effect that should be played by this vibration. */
|
||||
@Nullable
|
||||
public VibrationEffect getEffect() {
|
||||
return mEffect;
|
||||
}
|
||||
|
||||
/** Return {@link Vibration.DebugInfo} with read-only debug information about this vibration. */
|
||||
public Vibration.DebugInfo getDebugInfo() {
|
||||
return new Vibration.DebugInfo(
|
||||
mStartTimeDebug, mEndTimeDebug, mEffect, mOriginalEffect, /* scale= */ 0, attrs,
|
||||
uid, opPkg, reason, mStatus);
|
||||
}
|
||||
|
||||
/** Debug information about vibrations. */
|
||||
public static final class DebugInfo {
|
||||
private final long mStartTimeDebug;
|
||||
private final long mEndTimeDebug;
|
||||
private final VibrationEffect mEffect;
|
||||
private final VibrationEffect mOriginalEffect;
|
||||
private final float mScale;
|
||||
private final VibrationAttributes mAttrs;
|
||||
private final int mUid;
|
||||
private final String mOpPkg;
|
||||
private final String mReason;
|
||||
private final Status mStatus;
|
||||
|
||||
public DebugInfo(long startTimeDebug, long endTimeDebug, VibrationEffect effect,
|
||||
VibrationEffect originalEffect, float scale, VibrationAttributes attrs,
|
||||
int uid, String opPkg, String reason, Status status) {
|
||||
mStartTimeDebug = startTimeDebug;
|
||||
mEndTimeDebug = endTimeDebug;
|
||||
mEffect = effect;
|
||||
mOriginalEffect = originalEffect;
|
||||
mScale = scale;
|
||||
mAttrs = attrs;
|
||||
mUid = uid;
|
||||
mOpPkg = opPkg;
|
||||
mReason = reason;
|
||||
mStatus = status;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return new StringBuilder()
|
||||
.append("startTime: ")
|
||||
.append(DEBUG_DATE_FORMAT.format(new Date(mStartTimeDebug)))
|
||||
.append(", endTime: ")
|
||||
.append(mEndTimeDebug == 0 ? null
|
||||
: DEBUG_DATE_FORMAT.format(new Date(mEndTimeDebug)))
|
||||
.append(", status: ")
|
||||
.append(mStatus.name().toLowerCase())
|
||||
.append(", effect: ")
|
||||
.append(mEffect)
|
||||
.append(", originalEffect: ")
|
||||
.append(mOriginalEffect)
|
||||
.append(", scale: ")
|
||||
.append(String.format("%.2f", mScale))
|
||||
.append(", attrs: ")
|
||||
.append(mAttrs)
|
||||
.append(", uid: ")
|
||||
.append(mUid)
|
||||
.append(", opPkg: ")
|
||||
.append(mOpPkg)
|
||||
.append(", reason: ")
|
||||
.append(mReason)
|
||||
.toString();
|
||||
}
|
||||
|
||||
/** Write this info into given {@code fieldId} on {@link ProtoOutputStream}. */
|
||||
public void dumpProto(ProtoOutputStream proto, long fieldId) {
|
||||
final long token = proto.start(fieldId);
|
||||
proto.write(VibrationProto.START_TIME, mStartTimeDebug);
|
||||
proto.write(VibrationProto.END_TIME, mEndTimeDebug);
|
||||
proto.write(VibrationProto.STATUS, mStatus.ordinal());
|
||||
|
||||
final long attrsToken = proto.start(VibrationProto.ATTRIBUTES);
|
||||
proto.write(VibrationAttributesProto.USAGE, mAttrs.getUsage());
|
||||
proto.write(VibrationAttributesProto.AUDIO_USAGE, mAttrs.getAudioUsage());
|
||||
proto.write(VibrationAttributesProto.FLAGS, mAttrs.getFlags());
|
||||
proto.end(attrsToken);
|
||||
|
||||
if (mEffect != null) {
|
||||
dumpEffect(proto, VibrationProto.EFFECT, mEffect);
|
||||
}
|
||||
if (mOriginalEffect != null) {
|
||||
dumpEffect(proto, VibrationProto.ORIGINAL_EFFECT, mOriginalEffect);
|
||||
}
|
||||
|
||||
proto.end(token);
|
||||
}
|
||||
|
||||
private void dumpEffect(ProtoOutputStream proto, long fieldId, VibrationEffect effect) {
|
||||
final long token = proto.start(fieldId);
|
||||
if (effect instanceof VibrationEffect.OneShot) {
|
||||
dumpEffect(proto, VibrationEffectProto.ONESHOT, (VibrationEffect.OneShot) effect);
|
||||
} else if (effect instanceof VibrationEffect.Waveform) {
|
||||
dumpEffect(proto, VibrationEffectProto.WAVEFORM, (VibrationEffect.Waveform) effect);
|
||||
} else if (effect instanceof VibrationEffect.Prebaked) {
|
||||
dumpEffect(proto, VibrationEffectProto.PREBAKED, (VibrationEffect.Prebaked) effect);
|
||||
} else if (effect instanceof VibrationEffect.Composed) {
|
||||
dumpEffect(proto, VibrationEffectProto.COMPOSED, (VibrationEffect.Composed) effect);
|
||||
}
|
||||
proto.end(token);
|
||||
}
|
||||
|
||||
private void dumpEffect(ProtoOutputStream proto, long fieldId,
|
||||
VibrationEffect.OneShot effect) {
|
||||
final long token = proto.start(fieldId);
|
||||
proto.write(OneShotProto.DURATION, (int) effect.getDuration());
|
||||
proto.write(OneShotProto.AMPLITUDE, effect.getAmplitude());
|
||||
proto.end(token);
|
||||
}
|
||||
|
||||
private void dumpEffect(ProtoOutputStream proto, long fieldId,
|
||||
VibrationEffect.Waveform effect) {
|
||||
final long token = proto.start(fieldId);
|
||||
for (long timing : effect.getTimings()) {
|
||||
proto.write(WaveformProto.TIMINGS, (int) timing);
|
||||
}
|
||||
for (int amplitude : effect.getAmplitudes()) {
|
||||
proto.write(WaveformProto.AMPLITUDES, amplitude);
|
||||
}
|
||||
proto.write(WaveformProto.REPEAT, effect.getRepeatIndex() >= 0);
|
||||
proto.end(token);
|
||||
}
|
||||
|
||||
private void dumpEffect(ProtoOutputStream proto, long fieldId,
|
||||
VibrationEffect.Prebaked effect) {
|
||||
final long token = proto.start(fieldId);
|
||||
proto.write(PrebakedProto.EFFECT_ID, effect.getId());
|
||||
proto.write(PrebakedProto.EFFECT_STRENGTH, effect.getEffectStrength());
|
||||
proto.write(PrebakedProto.FALLBACK, effect.shouldFallback());
|
||||
proto.end(token);
|
||||
}
|
||||
|
||||
private void dumpEffect(ProtoOutputStream proto, long fieldId,
|
||||
VibrationEffect.Composed effect) {
|
||||
final long token = proto.start(fieldId);
|
||||
for (VibrationEffect.Composition.PrimitiveEffect primitive :
|
||||
effect.getPrimitiveEffects()) {
|
||||
proto.write(ComposedProto.EFFECT_IDS, primitive.id);
|
||||
proto.write(ComposedProto.EFFECT_SCALES, primitive.scale);
|
||||
proto.write(ComposedProto.DELAYS, primitive.delay);
|
||||
}
|
||||
proto.end(token);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -31,7 +31,6 @@ public final class VibrationScaler {
|
||||
|
||||
// Scale levels. Each level, except MUTE, is defined as the delta between the current setting
|
||||
// and the default intensity for that type of vibration (i.e. current - default).
|
||||
private static final int SCALE_MUTE = IExternalVibratorService.SCALE_MUTE; // -100
|
||||
private static final int SCALE_VERY_LOW = IExternalVibratorService.SCALE_VERY_LOW; // -2
|
||||
private static final int SCALE_LOW = IExternalVibratorService.SCALE_LOW; // -1
|
||||
private static final int SCALE_NONE = IExternalVibratorService.SCALE_NONE; // 0
|
||||
|
||||
Reference in New Issue
Block a user