1 /* 2 * Copyright (C) 2023 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.server.vibrator; 18 19 import android.annotation.NonNull; 20 import android.os.CombinedVibration; 21 import android.os.VibrationEffect; 22 import android.os.VibratorInfo; 23 import android.os.vibrator.VibrationEffectSegment; 24 import android.util.SparseArray; 25 26 import java.util.ArrayList; 27 import java.util.Arrays; 28 import java.util.List; 29 30 /** 31 * Adapts a {@link CombinedVibration} to a device by transforming each {@link VibrationEffect} to 32 * the available device vibrator capabilities defined by {@link VibratorInfo}. 33 */ 34 final class DeviceAdapter implements CombinedVibration.VibratorAdapter { 35 private static final String TAG = "DeviceAdapter"; 36 37 /** 38 * The VibratorController.getInfo might trigger HAL method calls, so just keep a reference to 39 * the system controllers until the adaptor is triggered by the VibrationThread. 40 */ 41 private final SparseArray<VibratorController> mAvailableVibrators; 42 private final int[] mAvailableVibratorIds; 43 44 /** 45 * The actual adapters that can replace VibrationEffectSegment entries from a list based on the 46 * VibratorInfo. They can be applied in a chain to a mutable list before a new VibrationEffect 47 * instance is created with the final segment list. 48 */ 49 private final List<VibrationSegmentsAdapter> mSegmentAdapters; 50 /** 51 * The vibration segment validators that can validate VibrationEffectSegments entries based on 52 * the VibratorInfo. 53 */ 54 private final List<VibrationSegmentsValidator> mSegmentsValidators; 55 DeviceAdapter(VibrationSettings settings, SparseArray<VibratorController> vibrators)56 DeviceAdapter(VibrationSettings settings, SparseArray<VibratorController> vibrators) { 57 mSegmentAdapters = Arrays.asList( 58 // TODO(b/167947076): add filter that replaces unsupported prebaked with fallback 59 // Updates primitive delays to hardware supported pauses 60 new PrimitiveDelayAdapter(), 61 // Convert segments based on device capabilities 62 new RampToStepAdapter(settings.getRampStepDuration()), 63 new StepToRampAdapter(), 64 // Add extra ramp down segments as needed 65 new RampDownAdapter(settings.getRampDownDuration(), settings.getRampStepDuration()), 66 // Split segments based on their duration and device supported limits 67 new SplitSegmentsAdapter(), 68 // Clip amplitudes and frequencies of final segments based on device bandwidth curve 69 new ClippingAmplitudeAndFrequencyAdapter(), 70 // Convert BasicPwleSegments to PwleSegments based on device capabilities 71 new BasicToPwleSegmentAdapter(), 72 // Split Pwle segments based on their duration and device supported limits 73 new SplitPwleSegmentsAdapter() 74 ); 75 mSegmentsValidators = List.of( 76 // Validate Pwle segments base on the vibrators frequency range 77 new PwleSegmentsValidator(), 78 // Validate primitive segments based on device support 79 new PrimitiveSegmentsValidator() 80 ); 81 mAvailableVibrators = vibrators; 82 mAvailableVibratorIds = new int[vibrators.size()]; 83 for (int i = 0; i < vibrators.size(); i++) { 84 mAvailableVibratorIds[i] = vibrators.keyAt(i); 85 } 86 } 87 getAvailableVibrators()88 SparseArray<VibratorController> getAvailableVibrators() { 89 return mAvailableVibrators; 90 } 91 92 @Override getAvailableVibratorIds()93 public int[] getAvailableVibratorIds() { 94 return mAvailableVibratorIds; 95 } 96 97 @Override adaptToVibrator(int vibratorId, @NonNull VibrationEffect effect)98 public VibrationEffect adaptToVibrator(int vibratorId, @NonNull VibrationEffect effect) { 99 if (!(effect instanceof VibrationEffect.Composed composed)) { 100 // Segments adapters can only apply to Composed effects. 101 return effect; 102 } 103 104 VibratorController controller = mAvailableVibrators.get(vibratorId); 105 if (controller == null) { 106 // Effect mapped to nonexistent vibrator, skip adapter. 107 return effect; 108 } 109 110 VibratorInfo info = controller.getVibratorInfo(); 111 List<VibrationEffectSegment> newSegments = new ArrayList<>(composed.getSegments()); 112 int newRepeatIndex = composed.getRepeatIndex(); 113 114 int adapterCount = mSegmentAdapters.size(); 115 for (int i = 0; i < adapterCount; i++) { 116 newRepeatIndex = 117 mSegmentAdapters.get(i).adaptToVibrator(info, newSegments, newRepeatIndex); 118 } 119 120 // Validate the vibration segments. If a segment is not supported, ignore the entire 121 // vibration effect. 122 for (int i = 0; i < mSegmentsValidators.size(); i++) { 123 if (!mSegmentsValidators.get(i).hasValidSegments(info, newSegments)) { 124 return null; 125 } 126 } 127 128 return new VibrationEffect.Composed(newSegments, newRepeatIndex); 129 } 130 } 131