summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com> 2019-12-18 06:35:31 +0000
committer Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com> 2019-12-18 06:35:31 +0000
commit197079ffdb5c7392baf23170091889faca25d522 (patch)
treef09fd8dd20a9b2199e934a509d2ae063a13424b5
parentbc75ee7a6a1734c6af8df65add783d6fc8a09dd2 (diff)
parent5d97061d0b9b1fe263d41183d027bb54945757c8 (diff)
Merge "vibrator: Support Always-On Effects" am: 65303aa385 am: 5d97061d0b
Change-Id: I1a83e4190a404b94653da68762c2c8acfa8078b9
-rw-r--r--core/java/android/os/IVibratorService.aidl1
-rw-r--r--core/java/android/os/SystemVibrator.java14
-rw-r--r--core/java/android/os/Vibrator.java19
-rw-r--r--core/res/AndroidManifest.xml7
-rw-r--r--services/core/java/com/android/server/VibratorService.java63
-rw-r--r--services/core/jni/com_android_server_VibratorService.cpp17
6 files changed, 121 insertions, 0 deletions
diff --git a/core/java/android/os/IVibratorService.aidl b/core/java/android/os/IVibratorService.aidl
index 1456ff7e6c5e..6b881fecad56 100644
--- a/core/java/android/os/IVibratorService.aidl
+++ b/core/java/android/os/IVibratorService.aidl
@@ -24,6 +24,7 @@ interface IVibratorService
{
boolean hasVibrator();
boolean hasAmplitudeControl();
+ boolean setAlwaysOnEffect(int id, in VibrationEffect effect, in AudioAttributes attributes);
void vibrate(int uid, String opPkg, in VibrationEffect effect, in AudioAttributes attributes,
String reason, IBinder token);
void cancelVibrate(IBinder token);
diff --git a/core/java/android/os/SystemVibrator.java b/core/java/android/os/SystemVibrator.java
index a5188e7cd58d..fbd11ca62a0c 100644
--- a/core/java/android/os/SystemVibrator.java
+++ b/core/java/android/os/SystemVibrator.java
@@ -70,6 +70,20 @@ public class SystemVibrator extends Vibrator {
}
@Override
+ public boolean setAlwaysOnEffect(int id, VibrationEffect effect, AudioAttributes attributes) {
+ if (mService == null) {
+ Log.w(TAG, "Failed to set always-on effect; no vibrator service.");
+ return false;
+ }
+ try {
+ return mService.setAlwaysOnEffect(id, effect, attributes);
+ } catch (RemoteException e) {
+ Log.w(TAG, "Failed to set always-on effect.", e);
+ }
+ return false;
+ }
+
+ @Override
public void vibrate(int uid, String opPkg, VibrationEffect effect,
String reason, AudioAttributes attributes) {
if (mService == null) {
diff --git a/core/java/android/os/Vibrator.java b/core/java/android/os/Vibrator.java
index 28909c88a734..6456d72a4a6f 100644
--- a/core/java/android/os/Vibrator.java
+++ b/core/java/android/os/Vibrator.java
@@ -17,6 +17,7 @@
package android.os;
import android.annotation.IntDef;
+import android.annotation.Nullable;
import android.annotation.RequiresPermission;
import android.annotation.SystemService;
import android.annotation.UnsupportedAppUsage;
@@ -152,6 +153,24 @@ public abstract class Vibrator {
public abstract boolean hasAmplitudeControl();
/**
+ * Configure an always-on haptics effect.
+ *
+ * @param id The board-specific always-on ID to configure.
+ * @param effect Vibration effect to assign to always-on id. Passing null will disable it.
+ * @param attributes {@link AudioAttributes} corresponding to the vibration. For example,
+ * specify {@link AudioAttributes#USAGE_ALARM} for alarm vibrations or
+ * {@link AudioAttributes#USAGE_NOTIFICATION_RINGTONE} for
+ * vibrations associated with incoming calls. May only be null when effect is null.
+ * @hide
+ */
+ @RequiresPermission(android.Manifest.permission.VIBRATE_ALWAYS_ON)
+ public boolean setAlwaysOnEffect(int id, @Nullable VibrationEffect effect,
+ @Nullable AudioAttributes attributes) {
+ Log.w(TAG, "Always-on effects aren't supported");
+ return false;
+ }
+
+ /**
* Vibrate constantly for the specified period of time.
*
* @param milliseconds The number of milliseconds to vibrate.
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 8dc84c804055..082424fa4a4f 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -1868,6 +1868,13 @@
android:description="@string/permdesc_vibrate"
android:protectionLevel="normal|instant" />
+ <!-- Allows access to the vibrator always-on settings.
+ <p>Protection level: signature
+ @hide
+ -->
+ <permission android:name="android.permission.VIBRATE_ALWAYS_ON"
+ android:protectionLevel="signature" />
+
<!-- Allows using PowerManager WakeLocks to keep processor from sleeping or screen
from dimming.
<p>Protection level: normal
diff --git a/services/core/java/com/android/server/VibratorService.java b/services/core/java/com/android/server/VibratorService.java
index 0db8495e9af9..a1480e305d9e 100644
--- a/services/core/java/com/android/server/VibratorService.java
+++ b/services/core/java/com/android/server/VibratorService.java
@@ -60,6 +60,7 @@ import android.provider.DeviceConfig;
import android.provider.Settings;
import android.provider.Settings.SettingNotFoundException;
import android.util.DebugUtils;
+import android.util.Pair;
import android.util.Slog;
import android.util.SparseArray;
import android.util.StatsLog;
@@ -161,6 +162,8 @@ public class VibratorService extends IVibratorService.Stub
private int mHapticFeedbackIntensity;
private int mNotificationIntensity;
private int mRingIntensity;
+ private SparseArray<Pair<VibrationEffect, AudioAttributes>> mAlwaysOnEffects =
+ new SparseArray<>();
static native boolean vibratorExists();
static native void vibratorInit();
@@ -172,6 +175,8 @@ public class VibratorService extends IVibratorService.Stub
static native boolean vibratorSupportsExternalControl();
static native void vibratorSetExternalControl(boolean enabled);
static native long vibratorGetCapabilities();
+ static native void vibratorAlwaysOnEnable(long id, long effect, long strength);
+ static native void vibratorAlwaysOnDisable(long id);
private final IUidObserver mUidObserver = new IUidObserver.Stub() {
@Override public void onUidStateChanged(int uid, int procState, long procStateSeq) {
@@ -518,6 +523,41 @@ public class VibratorService extends IVibratorService.Stub
}
}
+ @Override // Binder call
+ public boolean setAlwaysOnEffect(int id, VibrationEffect effect, AudioAttributes attrs) {
+ if (!hasPermission(android.Manifest.permission.VIBRATE_ALWAYS_ON)) {
+ throw new SecurityException("Requires VIBRATE_ALWAYS_ON permission");
+ }
+ if ((mCapabilities & IVibrator.CAP_ALWAYS_ON_CONTROL) == 0) {
+ Slog.e(TAG, "Always-on effects not supported.");
+ return false;
+ }
+ if (effect == null) {
+ synchronized (mLock) {
+ mAlwaysOnEffects.delete(id);
+ vibratorAlwaysOnDisable(id);
+ }
+ } else {
+ if (!verifyVibrationEffect(effect)) {
+ return false;
+ }
+ if (!(effect instanceof VibrationEffect.Prebaked)) {
+ Slog.e(TAG, "Only prebaked effects supported for always-on.");
+ return false;
+ }
+ if (attrs == null) {
+ attrs = new AudioAttributes.Builder()
+ .setUsage(AudioAttributes.USAGE_UNKNOWN)
+ .build();
+ }
+ synchronized (mLock) {
+ mAlwaysOnEffects.put(id, Pair.create(effect, attrs));
+ updateAlwaysOnLocked(id, effect, attrs);
+ }
+ }
+ return true;
+ }
+
private void verifyIncomingUid(int uid) {
if (uid == Binder.getCallingUid()) {
return;
@@ -988,6 +1028,8 @@ public class VibratorService extends IVibratorService.Stub
// If the state changes out from under us then just reset.
doCancelVibrateLocked();
}
+
+ updateAlwaysOnLocked();
}
}
@@ -1054,6 +1096,27 @@ public class VibratorService extends IVibratorService.Stub
mVibrator.getDefaultRingVibrationIntensity(), UserHandle.USER_CURRENT);
}
+ private void updateAlwaysOnLocked(int id, VibrationEffect effect, AudioAttributes attrs) {
+ // TODO: Check DND and LowPower settings
+ final Vibration vib = new Vibration(null, effect, attrs, 0, null, null);
+ final int intensity = getCurrentIntensityLocked(vib);
+ if (intensity == Vibrator.VIBRATION_INTENSITY_OFF) {
+ vibratorAlwaysOnDisable(id);
+ } else {
+ final VibrationEffect.Prebaked prebaked = (VibrationEffect.Prebaked) effect;
+ final int strength = intensityToEffectStrength(intensity);
+ vibratorAlwaysOnEnable(id, prebaked.getId(), strength);
+ }
+ }
+
+ private void updateAlwaysOnLocked() {
+ for (int i = 0; i < mAlwaysOnEffects.size(); i++) {
+ int id = mAlwaysOnEffects.keyAt(i);
+ Pair<VibrationEffect, AudioAttributes> pair = mAlwaysOnEffects.valueAt(i);
+ updateAlwaysOnLocked(id, pair.first, pair.second);
+ }
+ }
+
@Override
public void onInputDeviceAdded(int deviceId) {
updateVibrators();
diff --git a/services/core/jni/com_android_server_VibratorService.cpp b/services/core/jni/com_android_server_VibratorService.cpp
index dcff5a11aca0..6811e6d0e6f2 100644
--- a/services/core/jni/com_android_server_VibratorService.cpp
+++ b/services/core/jni/com_android_server_VibratorService.cpp
@@ -410,6 +410,21 @@ static jlong vibratorGetCapabilities(JNIEnv*, jclass) {
return 0;
}
+static void vibratorAlwaysOnEnable(JNIEnv* env, jclass, jlong id, jlong effect, jlong strength) {
+ auto status = halCall(&aidl::IVibrator::alwaysOnEnable, id,
+ static_cast<aidl::Effect>(effect), static_cast<aidl::EffectStrength>(strength));
+ if (!status.isOk()) {
+ ALOGE("vibratortAlwaysOnEnable command failed (%s).", status.toString8().string());
+ }
+}
+
+static void vibratorAlwaysOnDisable(JNIEnv* env, jclass, jlong id) {
+ auto status = halCall(&aidl::IVibrator::alwaysOnDisable, id);
+ if (!status.isOk()) {
+ ALOGE("vibratorAlwaysOnDisable command failed (%s).", status.toString8().string());
+ }
+}
+
static const JNINativeMethod method_table[] = {
{ "vibratorExists", "()Z", (void*)vibratorExists },
{ "vibratorInit", "()V", (void*)vibratorInit },
@@ -422,6 +437,8 @@ static const JNINativeMethod method_table[] = {
{ "vibratorSupportsExternalControl", "()Z", (void*)vibratorSupportsExternalControl},
{ "vibratorSetExternalControl", "(Z)V", (void*)vibratorSetExternalControl},
{ "vibratorGetCapabilities", "()J", (void*)vibratorGetCapabilities},
+ { "vibratorAlwaysOnEnable", "(JJJ)V", (void*)vibratorAlwaysOnEnable},
+ { "vibratorAlwaysOnDisable", "(J)V", (void*)vibratorAlwaysOnDisable},
};
int register_android_server_VibratorService(JNIEnv *env)