Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit b5114929 authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Extract Vibration class to vibrator package."

parents eb778956 0694afac
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -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("");
            }
+139 −353

File changed.

Preview size limit exceeded, changes collapsed.

+287 −0
Original line number Diff line number Diff line
/*
 * 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);
        }
    }
}
+0 −1
Original line number Diff line number Diff line
@@ -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