All Downloads are FREE. Search and download functionalities are using the official Maven repository.

src.com.android.server.vibrator.AbstractVibratorStep Maven / Gradle / Ivy

/*
 * Copyright (C) 2022 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.os.SystemClock;
import android.os.VibrationEffect;
import android.util.Slog;

import java.util.Arrays;
import java.util.List;

/**
 * Represent a step on a single vibrator that plays one or more segments from a
 * {@link VibrationEffect.Composed} effect.
 */
abstract class AbstractVibratorStep extends Step {
    public final VibratorController controller;
    public final VibrationEffect.Composed effect;
    public final int segmentIndex;
    public final long previousStepVibratorOffTimeout;

    long mVibratorOnResult;
    boolean mVibratorCompleteCallbackReceived;

    /**
     * @param conductor          The VibrationStepConductor for these steps.
     * @param startTime          The time to schedule this step in the
     *                           {@link VibrationStepConductor}.
     * @param controller         The vibrator that is playing the effect.
     * @param effect             The effect being played in this step.
     * @param index              The index of the next segment to be played by this step
     * @param previousStepVibratorOffTimeout The time the vibrator is expected to complete any
     *                           previous vibration and turn off. This is used to allow this step to
     *                           be triggered when the completion callback is received, and can
     *                           be used to play effects back-to-back.
     */
    AbstractVibratorStep(VibrationStepConductor conductor, long startTime,
            VibratorController controller, VibrationEffect.Composed effect, int index,
            long previousStepVibratorOffTimeout) {
        super(conductor, startTime);
        this.controller = controller;
        this.effect = effect;
        this.segmentIndex = index;
        this.previousStepVibratorOffTimeout = previousStepVibratorOffTimeout;
    }

    public int getVibratorId() {
        return controller.getVibratorInfo().getId();
    }

    @Override
    public long getVibratorOnDuration() {
        return mVibratorOnResult;
    }

    @Override
    public boolean acceptVibratorCompleteCallback(int vibratorId) {
        boolean isSameVibrator = controller.getVibratorInfo().getId() == vibratorId;
        mVibratorCompleteCallbackReceived |= isSameVibrator;
        // Only activate this step if a timeout was set to wait for the vibration to complete,
        // otherwise we are waiting for the correct time to play the next step.
        return isSameVibrator && (previousStepVibratorOffTimeout > SystemClock.uptimeMillis());
    }

    @Override
    public List cancel() {
        return Arrays.asList(new CompleteEffectVibratorStep(conductor, SystemClock.uptimeMillis(),
                /* cancelled= */ true, controller, previousStepVibratorOffTimeout));
    }

    @Override
    public void cancelImmediately() {
        if (previousStepVibratorOffTimeout > SystemClock.uptimeMillis()) {
            // Vibrator might be running from previous steps, so turn it off while canceling.
            stopVibrating();
        }
    }

    protected void stopVibrating() {
        if (VibrationThread.DEBUG) {
            Slog.d(VibrationThread.TAG,
                    "Turning off vibrator " + getVibratorId());
        }
        controller.off();
    }

    protected void changeAmplitude(float amplitude) {
        if (VibrationThread.DEBUG) {
            Slog.d(VibrationThread.TAG,
                    "Amplitude changed on vibrator " + getVibratorId() + " to " + amplitude);
        }
        controller.setAmplitude(amplitude);
    }

    /**
     * Return the {@link VibrationStepConductor#nextVibrateStep} with same timings, only jumping
     * the segments.
     */
    protected List skipToNextSteps(int segmentsSkipped) {
        return nextSteps(startTime, previousStepVibratorOffTimeout, segmentsSkipped);
    }

    /**
     * Return the {@link VibrationStepConductor#nextVibrateStep} with same start and off timings
     * calculated from {@link #getVibratorOnDuration()}, jumping all played segments.
     *
     * 

This method has same behavior as {@link #skipToNextSteps(int)} when the vibrator * result is non-positive, meaning the vibrator has either ignored or failed to turn on. */ protected List nextSteps(int segmentsPlayed) { if (mVibratorOnResult <= 0) { // Vibration was not started, so just skip the played segments and keep timings. return skipToNextSteps(segmentsPlayed); } long nextStartTime = SystemClock.uptimeMillis() + mVibratorOnResult; long nextVibratorOffTimeout = nextStartTime + VibrationStepConductor.CALLBACKS_EXTRA_TIMEOUT; return nextSteps(nextStartTime, nextVibratorOffTimeout, segmentsPlayed); } /** * Return the {@link VibrationStepConductor#nextVibrateStep} with given start and off timings, * which might be calculated independently, jumping all played segments. * *

This should be used when the vibrator on/off state is not responsible for the steps * execution timings, e.g. while playing the vibrator amplitudes. */ protected List nextSteps(long nextStartTime, long vibratorOffTimeout, int segmentsPlayed) { int nextSegmentIndex = segmentIndex + segmentsPlayed; int effectSize = effect.getSegments().size(); int repeatIndex = effect.getRepeatIndex(); if (nextSegmentIndex >= effectSize && repeatIndex >= 0) { // Count the loops that were played. int loopSize = effectSize - repeatIndex; nextSegmentIndex = repeatIndex + ((nextSegmentIndex - effectSize) % loopSize); } Step nextStep = conductor.nextVibrateStep(nextStartTime, controller, effect, nextSegmentIndex, vibratorOffTimeout); return nextStep == null ? VibrationStepConductor.EMPTY_STEP_LIST : Arrays.asList(nextStep); } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy