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

Commit 1e372ba1 authored by Ahmad Khalil's avatar Ahmad Khalil Committed by Android (Google) Code Review
Browse files

Merge "Add adaptive haptics scaling to external vibrations" into main

parents 4acc4d35 7619c599
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -126,6 +126,7 @@ filegroup {
    srcs: [
        "android/os/IExternalVibrationController.aidl",
        "android/os/IExternalVibratorService.aidl",
        "android/os/ExternalVibrationScale.aidl",
    ],
}

+45 −0
Original line number Diff line number Diff line
/**
 * Copyright (c) 2018, 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 android.os;

/**
 * ExternalVibrationScale holds the vibration scale level and adaptive haptics scale. These
 * can be used to scale external vibrations.
 *
 * @hide
 */
parcelable ExternalVibrationScale {
    @Backing(type="int")
    enum ScaleLevel {
        SCALE_MUTE = -100,
        SCALE_VERY_LOW = -2,
        SCALE_LOW = -1,
        SCALE_NONE = 0,
        SCALE_HIGH = 1,
        SCALE_VERY_HIGH = 2
    }

    /**
     * The scale level that will be applied to external vibrations.
     */
    ScaleLevel scaleLevel = ScaleLevel.SCALE_NONE;

    /**
     * The adaptive haptics scale that will be applied to external vibrations.
     */
    float adaptiveHapticsScale = 1f;
}
+11 −15
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@
package android.os;

import android.os.ExternalVibration;
import android.os.ExternalVibrationScale;

/**
 * The communication channel by which an external system that wants to control the system
@@ -32,29 +33,24 @@ import android.os.ExternalVibration;
 * {@hide}
 */
interface IExternalVibratorService {
    const int SCALE_MUTE = -100;
    const int SCALE_VERY_LOW = -2;
    const int SCALE_LOW = -1;
    const int SCALE_NONE = 0;
    const int SCALE_HIGH = 1;
    const int SCALE_VERY_HIGH = 2;

    /**
     * A method called by the external system to start a vibration.
     *
     * If this returns {@code SCALE_MUTE}, then the vibration should <em>not</em> play. If this
     * returns any other scale level, then any currently playing vibration controlled by the
     * requesting system must be muted and this vibration can begin playback.
     * This returns an {@link ExternalVibrationScale} which includes the vibration scale level and
     * the adaptive haptics scale.
     *
     * If the returned scale level is {@link ExternalVibrationScale.ScaleLevel#SCALE_MUTE}, then
     * the vibration should <em>not</em> play. If it returns any other scale level, then
     * any currently playing vibration controlled by the requesting system must be muted and this
     * vibration can begin playback.
     *
     * Note that the IExternalVibratorService implementation will not call mute on any currently
     * playing external vibrations in order to avoid re-entrancy with the system on the other side.
     *
     * @param vibration An ExternalVibration
     *
     * @return {@code SCALE_MUTE} if the external vibration should not play, and any other scale
     *         level if it should.
     * @param vib The external vibration starting.
     * @return {@link ExternalVibrationScale} including scale level and adaptive haptics scale.
     */
    int onExternalVibrationStart(in ExternalVibration vib);
    ExternalVibrationScale onExternalVibrationStart(in ExternalVibration vib);

    /**
     * A method called by the external system when a vibration no longer wants to play.
+31 −11
Original line number Diff line number Diff line
@@ -19,7 +19,7 @@ package com.android.server.vibrator;
import android.annotation.NonNull;
import android.content.Context;
import android.hardware.vibrator.V1_0.EffectStrength;
import android.os.IExternalVibratorService;
import android.os.ExternalVibrationScale;
import android.os.VibrationAttributes;
import android.os.VibrationEffect;
import android.os.Vibrator;
@@ -37,11 +37,13 @@ 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_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
    private static final int SCALE_HIGH = IExternalVibratorService.SCALE_HIGH; // 1
    private static final int SCALE_VERY_HIGH = IExternalVibratorService.SCALE_VERY_HIGH; // 2
    private static final int SCALE_VERY_LOW =
            ExternalVibrationScale.ScaleLevel.SCALE_VERY_LOW; // -2
    private static final int SCALE_LOW = ExternalVibrationScale.ScaleLevel.SCALE_LOW; // -1
    private static final int SCALE_NONE = ExternalVibrationScale.ScaleLevel.SCALE_NONE; // 0
    private static final int SCALE_HIGH = ExternalVibrationScale.ScaleLevel.SCALE_HIGH; // 1
    private static final int SCALE_VERY_HIGH =
            ExternalVibrationScale.ScaleLevel.SCALE_VERY_HIGH; // 2

    // Scale factors for each level.
    private static final float SCALE_FACTOR_VERY_LOW = 0.6f;
@@ -83,9 +85,9 @@ final class VibrationScaler {
     * Calculates the scale to be applied to external vibration with given usage.
     *
     * @param usageHint one of VibrationAttributes.USAGE_*
     * @return one of IExternalVibratorService.SCALE_*
     * @return one of ExternalVibrationScale.ScaleLevel.SCALE_*
     */
    public int getExternalVibrationScale(int usageHint) {
    public int getExternalVibrationScaleLevel(int usageHint) {
        int defaultIntensity = mSettingsController.getDefaultIntensity(usageHint);
        int currentIntensity = mSettingsController.getCurrentIntensity(usageHint);

@@ -106,6 +108,22 @@ final class VibrationScaler {
        }
    }

    /**
     * Returns the adaptive haptics scale that should be applied to the vibrations with
     * the given usage. When no adaptive scales are available for the usages, then returns 1
     * indicating no scaling will be applied
     *
     * @param usageHint one of VibrationAttributes.USAGE_*
     * @return The adaptive haptics scale.
     */
    public float getAdaptiveHapticsScale(int usageHint) {
        if (shouldApplyAdaptiveHapticsScale(usageHint)) {
            return mAdaptiveHapticsScales.get(usageHint);
        }

        return 1f; // no scaling
    }

    /**
     * Scale a {@link VibrationEffect} based on the given usage hint for this vibration.
     *
@@ -152,9 +170,7 @@ final class VibrationScaler {
            }

            // If adaptive haptics scaling is available for this usage, apply it to the segment.
            if (Flags.adaptiveHapticsEnabled()
                    && mAdaptiveHapticsScales.size() > 0
                    && mAdaptiveHapticsScales.contains(usageHint)) {
            if (shouldApplyAdaptiveHapticsScale(usageHint)) {
                float adaptiveScale = mAdaptiveHapticsScales.get(usageHint);
                segment = segment.scaleLinearly(adaptiveScale);
            }
@@ -224,6 +240,10 @@ final class VibrationScaler {
        mAdaptiveHapticsScales.clear();
    }

    private boolean shouldApplyAdaptiveHapticsScale(int usageHint) {
        return Flags.adaptiveHapticsEnabled() && mAdaptiveHapticsScales.contains(usageHint);
    }

    /** Mapping of Vibrator.VIBRATION_INTENSITY_* values to {@link EffectStrength}. */
    private static int intensityToEffectStrength(int intensity) {
        switch (intensity) {
+24 −10
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@

package com.android.server.vibrator;

import static android.os.ExternalVibrationScale.ScaleLevel.SCALE_MUTE;
import static android.os.VibrationEffect.VibrationParameter.targetAmplitude;
import static android.os.VibrationEffect.VibrationParameter.targetFrequency;

@@ -35,6 +36,7 @@ import android.os.Binder;
import android.os.Build;
import android.os.CombinedVibration;
import android.os.ExternalVibration;
import android.os.ExternalVibrationScale;
import android.os.Handler;
import android.os.IBinder;
import android.os.IExternalVibratorService;
@@ -277,7 +279,7 @@ public class VibratorManagerService extends IVibratorManagerService.Stub {
        context.registerReceiver(mIntentReceiver, filter, Context.RECEIVER_NOT_EXPORTED);

        injector.addService(EXTERNAL_VIBRATOR_SERVICE, new ExternalVibratorService());
        if (ServiceManager.isDeclared(VIBRATOR_CONTROL_SERVICE)) {
        if (injector.isServiceDeclared(VIBRATOR_CONTROL_SERVICE)) {
            injector.addService(VIBRATOR_CONTROL_SERVICE, mVibratorControlService);
        }

@@ -1427,6 +1429,10 @@ public class VibratorManagerService extends IVibratorManagerService.Stub {
        VibratorControllerHolder createVibratorControllerHolder() {
            return new VibratorControllerHolder();
        }

        boolean isServiceDeclared(String name) {
            return ServiceManager.isDeclared(name);
        }
    }

    /**
@@ -1594,7 +1600,7 @@ public class VibratorManagerService extends IVibratorManagerService.Stub {
            IBinder.DeathRecipient {

        public final ExternalVibration externalVibration;
        public int scale;
        public ExternalVibrationScale scale = new ExternalVibrationScale();

        private Vibration.Status mStatus;

@@ -1605,7 +1611,6 @@ public class VibratorManagerService extends IVibratorManagerService.Stub {
                    // instead of using DEVICE_ID_INVALID here and relying on the UID checks.
                    Context.DEVICE_ID_INVALID, externalVibration.getPackage(), null));
            this.externalVibration = externalVibration;
            this.scale = IExternalVibratorService.SCALE_NONE;
            mStatus = Vibration.Status.RUNNING;
        }

@@ -1658,7 +1663,7 @@ public class VibratorManagerService extends IVibratorManagerService.Stub {

        public Vibration.DebugInfo getDebugInfo() {
            return new Vibration.DebugInfo(mStatus, stats, /* playedEffect= */ null,
                    /* originalEffect= */ null, scale, callerInfo);
                    /* originalEffect= */ null, scale.scaleLevel, callerInfo);
        }

        public VibrationStats.StatsInfo getStatsInfo(long completionUptimeMillis) {
@@ -1988,11 +1993,17 @@ public class VibratorManagerService extends IVibratorManagerService.Stub {
    /** Implementation of {@link IExternalVibratorService} to be triggered on external control. */
    @VisibleForTesting
    final class ExternalVibratorService extends IExternalVibratorService.Stub {
        private static final ExternalVibrationScale SCALE_MUTE = new ExternalVibrationScale();

        static {
            SCALE_MUTE.scaleLevel = ExternalVibrationScale.ScaleLevel.SCALE_MUTE;
        }

        @Override
        public int onExternalVibrationStart(ExternalVibration vib) {
        public ExternalVibrationScale onExternalVibrationStart(ExternalVibration vib) {

            if (!hasExternalControlCapability()) {
                return IExternalVibratorService.SCALE_MUTE;
                return SCALE_MUTE;
            }
            if (ActivityManager.checkComponentPermission(android.Manifest.permission.VIBRATE,
                    vib.getUid(), -1 /*owningUid*/, true /*exported*/)
@@ -2000,7 +2011,7 @@ public class VibratorManagerService extends IVibratorManagerService.Stub {
                Slog.w(TAG, "pkg=" + vib.getPackage() + ", uid=" + vib.getUid()
                        + " tried to play externally controlled vibration"
                        + " without VIBRATE permission, ignoring.");
                return IExternalVibratorService.SCALE_MUTE;
                return SCALE_MUTE;
            }

            // Create Vibration.Stats as close to the received request as possible, for tracking.
@@ -2033,7 +2044,7 @@ public class VibratorManagerService extends IVibratorManagerService.Stub {
                }

                if (vibrationEndInfo != null) {
                    vibHolder.scale = IExternalVibratorService.SCALE_MUTE;
                    vibHolder.scale = SCALE_MUTE;
                    // Failed to start the vibration, end it and report metrics right away.
                    endVibrationAndWriteStatsLocked(vibHolder, vibrationEndInfo);
                    return vibHolder.scale;
@@ -2074,7 +2085,10 @@ public class VibratorManagerService extends IVibratorManagerService.Stub {
                }
                mCurrentExternalVibration = vibHolder;
                vibHolder.linkToDeath();
                vibHolder.scale = mVibrationScaler.getExternalVibrationScale(attrs.getUsage());
                vibHolder.scale.scaleLevel = mVibrationScaler.getExternalVibrationScaleLevel(
                        attrs.getUsage());
                vibHolder.scale.adaptiveHapticsScale = mVibrationScaler.getAdaptiveHapticsScale(
                        attrs.getUsage());
            }

            if (waitForCompletion) {
@@ -2086,7 +2100,7 @@ public class VibratorManagerService extends IVibratorManagerService.Stub {
                                new Vibration.EndInfo(Vibration.Status.IGNORED_ERROR_CANCELLING),
                                /* continueExternalControl= */ false);
                    }
                    return IExternalVibratorService.SCALE_MUTE;
                    return SCALE_MUTE;
                }
            }
            if (!alreadyUnderExternalControl) {
Loading