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

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

Merge "Support multi-channel FF vibration effect for input device."

parents 9d9c8e72 28f00f87
Loading
Loading
Loading
Loading
+29 −0
Original line number Diff line number Diff line
@@ -34862,6 +34862,27 @@ package android.os {
    method public void onCancel();
  }
  public abstract class CombinedVibrationEffect implements android.os.Parcelable {
    method @NonNull public static android.os.CombinedVibrationEffect createSynced(@NonNull android.os.VibrationEffect);
    method public int describeContents();
    method @NonNull public static android.os.CombinedVibrationEffect.SequentialCombination startSequential();
    method @NonNull public static android.os.CombinedVibrationEffect.SyncedCombination startSynced();
    field @NonNull public static final android.os.Parcelable.Creator<android.os.CombinedVibrationEffect> CREATOR;
  }
  public static final class CombinedVibrationEffect.SequentialCombination {
    method @NonNull public android.os.CombinedVibrationEffect.SequentialCombination addNext(int, @NonNull android.os.VibrationEffect);
    method @NonNull public android.os.CombinedVibrationEffect.SequentialCombination addNext(int, @NonNull android.os.VibrationEffect, int);
    method @NonNull public android.os.CombinedVibrationEffect.SequentialCombination addNext(@NonNull android.os.CombinedVibrationEffect);
    method @NonNull public android.os.CombinedVibrationEffect.SequentialCombination addNext(@NonNull android.os.CombinedVibrationEffect, int);
    method @NonNull public android.os.CombinedVibrationEffect combine();
  }
  public static final class CombinedVibrationEffect.SyncedCombination {
    method @NonNull public android.os.CombinedVibrationEffect.SyncedCombination addVibrator(int, @NonNull android.os.VibrationEffect);
    method @NonNull public android.os.CombinedVibrationEffect combine();
  }
  public class ConditionVariable {
    ctor public ConditionVariable();
    ctor public ConditionVariable(boolean);
@@ -36088,6 +36109,13 @@ package android.os {
    field public static final int VIBRATION_EFFECT_SUPPORT_YES = 1; // 0x1
  }
  public abstract class VibratorManager {
    method @NonNull public abstract android.os.Vibrator getDefaultVibrator();
    method @NonNull public abstract android.os.Vibrator getVibrator(int);
    method @NonNull public abstract int[] getVibratorIds();
    method public abstract void vibrate(@NonNull android.os.CombinedVibrationEffect);
  }
  public class WorkSource implements android.os.Parcelable {
    ctor public WorkSource();
    ctor public WorkSource(android.os.WorkSource);
@@ -51337,6 +51365,7 @@ package android.view {
    method public int getSources();
    method public int getVendorId();
    method public android.os.Vibrator getVibrator();
    method @NonNull public android.os.VibratorManager getVibratorManager();
    method public boolean[] hasKeys(int...);
    method public boolean hasMicrophone();
    method public boolean isEnabled();
+4 −0
Original line number Diff line number Diff line
@@ -22,6 +22,7 @@ import android.hardware.input.KeyboardLayout;
import android.hardware.input.IInputDevicesChangedListener;
import android.hardware.input.ITabletModeChangedListener;
import android.hardware.input.TouchCalibration;
import android.os.CombinedVibrationEffect;
import android.os.IBinder;
import android.os.VibrationEffect;
import android.view.InputDevice;
@@ -85,7 +86,10 @@ interface IInputManager {

    // Input device vibrator control.
    void vibrate(int deviceId, in VibrationEffect effect, IBinder token);
    void vibrateCombined(int deviceId, in CombinedVibrationEffect effect, IBinder token);
    void cancelVibrate(int deviceId, IBinder token);
    int[] getVibratorIds(int deviceId);
    boolean isVibrating(int deviceId);

    void setPointerIconType(int typeId);
    void setCustomPointerIcon(in PointerIcon icon);
+94 −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 android.hardware.input;

import android.annotation.CallbackExecutor;
import android.annotation.NonNull;
import android.os.Binder;
import android.os.VibrationAttributes;
import android.os.VibrationEffect;
import android.os.Vibrator;

import java.util.concurrent.Executor;

/**
 * Vibrator implementation that communicates with the input device vibrators.
 */
final class InputDeviceVibrator extends Vibrator {
    // mDeviceId represents InputDevice ID the vibrator belongs to
    private final int mDeviceId;
    private final int mVibratorId;
    private final Binder mToken;
    private final InputManager mInputManager;

    InputDeviceVibrator(InputManager inputManager, int deviceId, int vibratorId) {
        mInputManager = inputManager;
        mDeviceId = deviceId;
        mVibratorId = vibratorId;
        mToken = new Binder();
    }

    @Override
    public boolean hasVibrator() {
        return true;
    }

    @Override
    public boolean isVibrating() {
        return mInputManager.isVibrating(mDeviceId);
    }

    /* TODO: b/161634264 Support Vibrator listener API in input devices */
    @Override
    public void addVibratorStateListener(@NonNull OnVibratorStateChangedListener listener) {
        throw new UnsupportedOperationException(
            "addVibratorStateListener not supported in InputDeviceVibrator");
    }

    @Override
    public void addVibratorStateListener(
            @NonNull @CallbackExecutor Executor executor,
            @NonNull OnVibratorStateChangedListener listener) {
        throw new UnsupportedOperationException(
            "addVibratorStateListener not supported in InputDeviceVibrator");
    }

    @Override
    public void removeVibratorStateListener(@NonNull OnVibratorStateChangedListener listener) {
        throw new UnsupportedOperationException(
            "removeVibratorStateListener not supported in InputDeviceVibrator");
    }

    @Override
    public boolean hasAmplitudeControl() {
        return true;
    }

    /**
     * @hide
     */
    @Override
    public void vibrate(int uid, String opPkg, @NonNull VibrationEffect effect,
            String reason, @NonNull VibrationAttributes attributes) {
        mInputManager.vibrate(mDeviceId, effect, mToken);
    }

    @Override
    public void cancel() {
        mInputManager.cancelVibrate(mDeviceId, mToken);
    }
}
+125 −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 android.hardware.input;

import android.os.Binder;
import android.os.CombinedVibrationEffect;
import android.os.NullVibrator;
import android.os.Vibrator;
import android.os.VibratorManager;
import android.util.SparseArray;
import android.view.InputDevice;

import com.android.internal.annotations.GuardedBy;

/**
 * Vibrator manager implementation that communicates with the input device vibrators.
 *
 * @hide
 */
public class InputDeviceVibratorManager extends VibratorManager
        implements InputManager.InputDeviceListener {
    private static final String TAG = "InputDeviceVibratorManager";
    private static final boolean DEBUG = false;

    private final Binder mToken;
    private final InputManager mInputManager;

    // The input device Id.
    private final int mDeviceId;
    // Vibrator map from Vibrator Id to Vibrator
    @GuardedBy("mVibrators")
    private final SparseArray<Vibrator> mVibrators = new SparseArray<>();

    public InputDeviceVibratorManager(InputManager inputManager, int deviceId) {
        mInputManager = inputManager;
        mDeviceId = deviceId;
        mToken = new Binder();

        initializeVibrators();
    }

    private void initializeVibrators() {
        synchronized (mVibrators) {
            mVibrators.clear();
            InputDevice inputDevice = InputDevice.getDevice(mDeviceId);
            final int[] vibratorIds =
                    mInputManager.getVibratorIds(mDeviceId);
            for (int i = 0; i < vibratorIds.length; i++) {
                mVibrators.put(vibratorIds[i],
                        new InputDeviceVibrator(mInputManager, mDeviceId, vibratorIds[i]));
            }
        }
    }

    @Override
    public void onInputDeviceAdded(int deviceId) {
    }

    @Override
    public void onInputDeviceRemoved(int deviceId) {
        synchronized (mVibrators) {
            if (deviceId == mDeviceId) {
                mVibrators.clear();
            }
        }
    }

    @Override
    public void onInputDeviceChanged(int deviceId) {
        if (deviceId == mDeviceId) {
            initializeVibrators();
        }
    }

    @Override
    public int[] getVibratorIds() {
        synchronized (mVibrators) {
            int[] vibratorIds = new int[mVibrators.size()];
            for (int idx = 0; idx < mVibrators.size(); idx++) {
                vibratorIds[idx++] = mVibrators.keyAt(idx);
            }
            return vibratorIds;
        }
    }

    @Override
    public Vibrator getVibrator(int vibratorId) {
        synchronized (mVibrators) {
            if (mVibrators.contains(vibratorId)) {
                return mVibrators.get(vibratorId);
            }
        }
        return NullVibrator.getInstance();
    }

    @Override
    public Vibrator getDefaultVibrator() {
        // Returns vibrator ID 0
        synchronized (mVibrators) {
            if (mVibrators.size() > 0) {
                return mVibrators.valueAt(0);
            }
        }
        return NullVibrator.getInstance();
    }

    @Override
    public void vibrate(CombinedVibrationEffect effect) {
        mInputManager.vibrate(mDeviceId, effect, mToken);
    }
}
+71 −74
Original line number Diff line number Diff line
@@ -17,7 +17,6 @@
package android.hardware.input;

import android.Manifest;
import android.annotation.CallbackExecutor;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -29,9 +28,9 @@ import android.annotation.TestApi;
import android.compat.annotation.ChangeId;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.Context;
import android.os.Binder;
import android.os.BlockUntrustedTouchesMode;
import android.os.Build;
import android.os.CombinedVibrationEffect;
import android.os.Handler;
import android.os.IBinder;
import android.os.InputEventInjectionSync;
@@ -41,9 +40,9 @@ import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.ServiceManager.ServiceNotFoundException;
import android.os.SystemClock;
import android.os.VibrationAttributes;
import android.os.VibrationEffect;
import android.os.Vibrator;
import android.os.VibratorManager;
import android.provider.Settings;
import android.provider.Settings.SettingNotFoundException;
import android.util.Log;
@@ -64,7 +63,6 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Executor;

/**
 * Provides information about input devices and available key layouts.
@@ -1287,8 +1285,75 @@ public final class InputManager {
     * @return The vibrator, never null.
     * @hide
     */
    public Vibrator getInputDeviceVibrator(int deviceId) {
        return new InputDeviceVibrator(deviceId);
    public Vibrator getInputDeviceVibrator(int deviceId, int vibratorId) {
        return new InputDeviceVibrator(this, deviceId, vibratorId);
    }

    /**
     * Gets a vibrator manager service associated with an input device, always create a new
     * instance.
     * @return The vibrator manager, never null.
     * @hide
     */
    @NonNull
    public VibratorManager getInputDeviceVibratorManager(int deviceId) {
        return new InputDeviceVibratorManager(InputManager.this, deviceId);
    }

    /*
     * Get the list of device vibrators
     * @return The list of vibrators IDs
     */
    int[] getVibratorIds(int deviceId) {
        try {
            return mIm.getVibratorIds(deviceId);
        } catch (RemoteException ex) {
            throw ex.rethrowFromSystemServer();
        }
    }

    /*
     * Perform vibration effect
     */
    void vibrate(int deviceId, VibrationEffect effect, IBinder token) {
        try {
            mIm.vibrate(deviceId, effect, token);
        } catch (RemoteException ex) {
            throw ex.rethrowFromSystemServer();
        }
    }

    /*
     * Perform combined vibration effect
     */
    void vibrate(int deviceId, CombinedVibrationEffect effect, IBinder token) {
        try {
            mIm.vibrateCombined(deviceId, effect, token);
        } catch (RemoteException ex) {
            throw ex.rethrowFromSystemServer();
        }
    }

    /*
     * Cancel an ongoing vibration
     */
    void cancelVibrate(int deviceId, IBinder token) {
        try {
            mIm.cancelVibrate(deviceId, token);
        } catch (RemoteException ex) {
            throw ex.rethrowFromSystemServer();
        }
    }

    /*
     * Check if input device is vibrating
     */
    boolean isVibrating(int deviceId)  {
        try {
            return mIm.isVibrating(deviceId);
        } catch (RemoteException ex) {
            throw ex.rethrowFromSystemServer();
        }
    }

    /**
@@ -1401,72 +1466,4 @@ public final class InputManager {
            }
        }
    }

    private final class InputDeviceVibrator extends Vibrator {
        private final int mDeviceId;
        private final Binder mToken;

        public InputDeviceVibrator(int deviceId) {
            mDeviceId = deviceId;
            mToken = new Binder();
        }

        @Override
        public boolean hasVibrator() {
            return true;
        }

        @Override
        public boolean isVibrating() {
            throw new UnsupportedOperationException(
                "isVibrating not supported in InputDeviceVibrator");
        }

        @Override
        public void addVibratorStateListener(@NonNull OnVibratorStateChangedListener listener) {
            throw new UnsupportedOperationException(
                "addVibratorStateListener not supported in InputDeviceVibrator");
        }

        @Override
        public void addVibratorStateListener(
                @NonNull @CallbackExecutor Executor executor,
                @NonNull OnVibratorStateChangedListener listener) {
            throw new UnsupportedOperationException(
                "addVibratorStateListener not supported in InputDeviceVibrator");
        }

        @Override
        public void removeVibratorStateListener(@NonNull OnVibratorStateChangedListener listener) {
            throw new UnsupportedOperationException(
                "removeVibratorStateListener not supported in InputDeviceVibrator");
        }

        @Override
        public boolean hasAmplitudeControl() {
            return true;
        }

        /**
         * @hide
         */
        @Override
        public void vibrate(int uid, String opPkg, @NonNull VibrationEffect effect,
                String reason, @NonNull VibrationAttributes attributes) {
            try {
                mIm.vibrate(mDeviceId, effect, mToken);
            } catch (RemoteException ex) {
                throw ex.rethrowFromSystemServer();
            }
        }

        @Override
        public void cancel() {
            try {
                mIm.cancelVibrate(mDeviceId, mToken);
            } catch (RemoteException ex) {
                throw ex.rethrowFromSystemServer();
            }
        }
    }
}
Loading