Loading Android.bp +3 −2 Original line number Diff line number Diff line Loading @@ -670,8 +670,9 @@ java_library { "android.hardware.tv.input-V1.0-java-constants", "android.hardware.usb-V1.0-java-constants", "android.hardware.usb-V1.1-java-constants", "android.hardware.vibrator-V1.0-java-constants", "android.hardware.vibrator-V1.1-java-constants", "android.hardware.vibrator-V1.0-java", "android.hardware.vibrator-V1.1-java", "android.hardware.vibrator-V1.2-java", "android.hardware.wifi-V1.0-java-constants", "android.hardware.radio-V1.0-java", "android.hardware.usb.gadget-V1.0-java", Loading core/java/android/os/VibrationEffect.java +96 −7 Original line number Diff line number Diff line Loading @@ -16,10 +16,15 @@ package android.os; import android.hardware.vibrator.V1_0.Constants.EffectStrength; import android.hardware.vibrator.V1_1.Constants.Effect_1_1; import android.annotation.Nullable; import android.content.Context; import android.hardware.vibrator.V1_0.EffectStrength; import android.hardware.vibrator.V1_2.Effect; import android.net.Uri; import android.util.MathUtils; import com.android.internal.annotations.VisibleForTesting; import java.util.Arrays; /** Loading Loading @@ -49,7 +54,7 @@ public abstract class VibrationEffect implements Parcelable { * @see #get(int) * @hide */ public static final int EFFECT_CLICK = Effect_1_1.CLICK; public static final int EFFECT_CLICK = Effect.CLICK; /** * A double click effect. Loading @@ -57,14 +62,62 @@ public abstract class VibrationEffect implements Parcelable { * @see #get(int) * @hide */ public static final int EFFECT_DOUBLE_CLICK = Effect_1_1.DOUBLE_CLICK; public static final int EFFECT_DOUBLE_CLICK = Effect.DOUBLE_CLICK; /** * A tick effect. * @see #get(int) * @hide */ public static final int EFFECT_TICK = Effect_1_1.TICK; public static final int EFFECT_TICK = Effect.TICK; /** * A thud effect. * @see #get(int) * @hide */ public static final int EFFECT_THUD = Effect.THUD; /** * A pop effect. * @see #get(int) * @hide */ public static final int EFFECT_POP = Effect.POP; /** * A heavy click effect. * @see #get(int) * @hide */ public static final int EFFECT_HEAVY_CLICK = Effect.HEAVY_CLICK; /** * Ringtone patterns. They may correspond with the device's ringtone audio, or may just be a * pattern that can be played as a ringtone with any audio, depending on the device. * * @see #get(Uri, Context) * @hide */ @VisibleForTesting public static final int[] RINGTONES = { Effect.RINGTONE_1, Effect.RINGTONE_2, Effect.RINGTONE_3, Effect.RINGTONE_4, Effect.RINGTONE_5, Effect.RINGTONE_6, Effect.RINGTONE_7, Effect.RINGTONE_8, Effect.RINGTONE_9, Effect.RINGTONE_10, Effect.RINGTONE_11, Effect.RINGTONE_12, Effect.RINGTONE_13, Effect.RINGTONE_14, Effect.RINGTONE_15 }; /** @hide to prevent subclassing from outside of the framework */ public VibrationEffect() { } Loading Loading @@ -198,6 +251,37 @@ public abstract class VibrationEffect implements Parcelable { return effect; } /** * Get a predefined vibration effect associated with a given URI. * * Predefined effects are a set of common vibration effects that should be identical, regardless * of the app they come from, in order to provide a cohesive experience for users across * the entire device. They also may be custom tailored to the device hardware in order to * provide a better experience than you could otherwise build using the generic building * blocks. * * @param uri The URI associated with the haptic effect. * @param context The context used to get the URI to haptic effect association. * * @return The desired effect, or {@code null} if there's no associated effect. * * @hide */ @Nullable public static VibrationEffect get(Uri uri, Context context) { String[] uris = context.getResources().getStringArray( com.android.internal.R.array.config_ringtoneEffectUris); for (int i = 0; i < uris.length && i < RINGTONES.length; i++) { if (uris[i] == null) { continue; } if (Uri.parse(uris[i]).equals(uri)) { return get(RINGTONES[i]); } } return null; } @Override public int describeContents() { return 0; Loading Loading @@ -548,11 +632,16 @@ public abstract class VibrationEffect implements Parcelable { case EFFECT_CLICK: case EFFECT_DOUBLE_CLICK: case EFFECT_TICK: case EFFECT_THUD: case EFFECT_POP: case EFFECT_HEAVY_CLICK: break; default: if (mEffectId < RINGTONES[0] || mEffectId > RINGTONES[RINGTONES.length - 1]) { throw new IllegalArgumentException( "Unknown prebaked effect type (value=" + mEffectId + ")"); } } if (!isValidEffectStrength(mEffectStrength)) { throw new IllegalArgumentException( "Unknown prebaked effect strength (value=" + mEffectStrength + ")"); Loading core/res/res/values/config.xml +8 −0 Original line number Diff line number Diff line Loading @@ -1075,6 +1075,14 @@ <item>10</item> </integer-array> <!-- The URI to associate with each ringtone effect constant, intended to be used with the android.os.VibrationEffect#get(Uri, Context) API. The position of the string in the string-array determines which ringtone effect is chosen. For example, if the URI passed into get match the third string in the string-array, then RINGTONE_3 will be the returned effect --> <string-array translatable="false" name="config_ringtoneEffectUris"> </string-array> <bool name="config_use_strict_phone_number_comparation">false</bool> <!-- Display low battery warning when battery level dips to this value. Loading core/res/res/values/symbols.xml +2 −0 Original line number Diff line number Diff line Loading @@ -3252,4 +3252,6 @@ <java-symbol type="string" name="screenshot_edit" /> <java-symbol type="bool" name="config_keepRestrictedProfilesInBackground" /> <java-symbol type="array" name="config_ringtoneEffectUris" /> </resources> core/tests/coretests/src/android/os/VibrationEffectTest.java 0 → 100644 +90 −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; import static junit.framework.Assert.assertEquals; import static junit.framework.Assert.assertNotNull; import static junit.framework.Assert.assertNull; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; import android.content.Context; import android.content.res.Resources; import android.net.Uri; import com.android.internal.R; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.junit.MockitoJUnitRunner; @RunWith(MockitoJUnitRunner.class) public class VibrationEffectTest { private static final String RINGTONE_URI_1 = "content://test/system/ringtone_1"; private static final String RINGTONE_URI_2 = "content://test/system/ringtone_2"; private static final String RINGTONE_URI_3 = "content://test/system/ringtone_3"; private static final String UNKNOWN_URI = "content://test/system/other_audio"; @Test public void getRingtones_noPrebakedRingtones() { Resources r = mockRingtoneResources(new String[0]); Context context = mockContext(r); VibrationEffect effect = VibrationEffect.get(Uri.parse(RINGTONE_URI_1), context); assertNull(effect); } @Test public void getRingtones_noPrebakedRingtoneForUri() { Resources r = mockRingtoneResources(); Context context = mockContext(r); VibrationEffect effect = VibrationEffect.get(Uri.parse(UNKNOWN_URI), context); assertNull(effect); } @Test public void getRingtones_getPrebakedRingtone() { Resources r = mockRingtoneResources(); Context context = mockContext(r); VibrationEffect effect = VibrationEffect.get(Uri.parse(RINGTONE_URI_2), context); VibrationEffect expectedEffect = VibrationEffect.get(VibrationEffect.RINGTONES[1]); assertNotNull(expectedEffect); assertEquals(expectedEffect, effect); } private Resources mockRingtoneResources() { return mockRingtoneResources(new String[] { RINGTONE_URI_1, RINGTONE_URI_2, RINGTONE_URI_3 }); } private Resources mockRingtoneResources(String[] ringtoneUris) { Resources mockResources = mock(Resources.class); when(mockResources.getStringArray(R.array.config_ringtoneEffectUris)) .thenReturn(ringtoneUris); return mockResources; } private Context mockContext(Resources r) { Context ctx = mock(Context.class); when(ctx.getResources()).thenReturn(r); return ctx; } } Loading
Android.bp +3 −2 Original line number Diff line number Diff line Loading @@ -670,8 +670,9 @@ java_library { "android.hardware.tv.input-V1.0-java-constants", "android.hardware.usb-V1.0-java-constants", "android.hardware.usb-V1.1-java-constants", "android.hardware.vibrator-V1.0-java-constants", "android.hardware.vibrator-V1.1-java-constants", "android.hardware.vibrator-V1.0-java", "android.hardware.vibrator-V1.1-java", "android.hardware.vibrator-V1.2-java", "android.hardware.wifi-V1.0-java-constants", "android.hardware.radio-V1.0-java", "android.hardware.usb.gadget-V1.0-java", Loading
core/java/android/os/VibrationEffect.java +96 −7 Original line number Diff line number Diff line Loading @@ -16,10 +16,15 @@ package android.os; import android.hardware.vibrator.V1_0.Constants.EffectStrength; import android.hardware.vibrator.V1_1.Constants.Effect_1_1; import android.annotation.Nullable; import android.content.Context; import android.hardware.vibrator.V1_0.EffectStrength; import android.hardware.vibrator.V1_2.Effect; import android.net.Uri; import android.util.MathUtils; import com.android.internal.annotations.VisibleForTesting; import java.util.Arrays; /** Loading Loading @@ -49,7 +54,7 @@ public abstract class VibrationEffect implements Parcelable { * @see #get(int) * @hide */ public static final int EFFECT_CLICK = Effect_1_1.CLICK; public static final int EFFECT_CLICK = Effect.CLICK; /** * A double click effect. Loading @@ -57,14 +62,62 @@ public abstract class VibrationEffect implements Parcelable { * @see #get(int) * @hide */ public static final int EFFECT_DOUBLE_CLICK = Effect_1_1.DOUBLE_CLICK; public static final int EFFECT_DOUBLE_CLICK = Effect.DOUBLE_CLICK; /** * A tick effect. * @see #get(int) * @hide */ public static final int EFFECT_TICK = Effect_1_1.TICK; public static final int EFFECT_TICK = Effect.TICK; /** * A thud effect. * @see #get(int) * @hide */ public static final int EFFECT_THUD = Effect.THUD; /** * A pop effect. * @see #get(int) * @hide */ public static final int EFFECT_POP = Effect.POP; /** * A heavy click effect. * @see #get(int) * @hide */ public static final int EFFECT_HEAVY_CLICK = Effect.HEAVY_CLICK; /** * Ringtone patterns. They may correspond with the device's ringtone audio, or may just be a * pattern that can be played as a ringtone with any audio, depending on the device. * * @see #get(Uri, Context) * @hide */ @VisibleForTesting public static final int[] RINGTONES = { Effect.RINGTONE_1, Effect.RINGTONE_2, Effect.RINGTONE_3, Effect.RINGTONE_4, Effect.RINGTONE_5, Effect.RINGTONE_6, Effect.RINGTONE_7, Effect.RINGTONE_8, Effect.RINGTONE_9, Effect.RINGTONE_10, Effect.RINGTONE_11, Effect.RINGTONE_12, Effect.RINGTONE_13, Effect.RINGTONE_14, Effect.RINGTONE_15 }; /** @hide to prevent subclassing from outside of the framework */ public VibrationEffect() { } Loading Loading @@ -198,6 +251,37 @@ public abstract class VibrationEffect implements Parcelable { return effect; } /** * Get a predefined vibration effect associated with a given URI. * * Predefined effects are a set of common vibration effects that should be identical, regardless * of the app they come from, in order to provide a cohesive experience for users across * the entire device. They also may be custom tailored to the device hardware in order to * provide a better experience than you could otherwise build using the generic building * blocks. * * @param uri The URI associated with the haptic effect. * @param context The context used to get the URI to haptic effect association. * * @return The desired effect, or {@code null} if there's no associated effect. * * @hide */ @Nullable public static VibrationEffect get(Uri uri, Context context) { String[] uris = context.getResources().getStringArray( com.android.internal.R.array.config_ringtoneEffectUris); for (int i = 0; i < uris.length && i < RINGTONES.length; i++) { if (uris[i] == null) { continue; } if (Uri.parse(uris[i]).equals(uri)) { return get(RINGTONES[i]); } } return null; } @Override public int describeContents() { return 0; Loading Loading @@ -548,11 +632,16 @@ public abstract class VibrationEffect implements Parcelable { case EFFECT_CLICK: case EFFECT_DOUBLE_CLICK: case EFFECT_TICK: case EFFECT_THUD: case EFFECT_POP: case EFFECT_HEAVY_CLICK: break; default: if (mEffectId < RINGTONES[0] || mEffectId > RINGTONES[RINGTONES.length - 1]) { throw new IllegalArgumentException( "Unknown prebaked effect type (value=" + mEffectId + ")"); } } if (!isValidEffectStrength(mEffectStrength)) { throw new IllegalArgumentException( "Unknown prebaked effect strength (value=" + mEffectStrength + ")"); Loading
core/res/res/values/config.xml +8 −0 Original line number Diff line number Diff line Loading @@ -1075,6 +1075,14 @@ <item>10</item> </integer-array> <!-- The URI to associate with each ringtone effect constant, intended to be used with the android.os.VibrationEffect#get(Uri, Context) API. The position of the string in the string-array determines which ringtone effect is chosen. For example, if the URI passed into get match the third string in the string-array, then RINGTONE_3 will be the returned effect --> <string-array translatable="false" name="config_ringtoneEffectUris"> </string-array> <bool name="config_use_strict_phone_number_comparation">false</bool> <!-- Display low battery warning when battery level dips to this value. Loading
core/res/res/values/symbols.xml +2 −0 Original line number Diff line number Diff line Loading @@ -3252,4 +3252,6 @@ <java-symbol type="string" name="screenshot_edit" /> <java-symbol type="bool" name="config_keepRestrictedProfilesInBackground" /> <java-symbol type="array" name="config_ringtoneEffectUris" /> </resources>
core/tests/coretests/src/android/os/VibrationEffectTest.java 0 → 100644 +90 −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; import static junit.framework.Assert.assertEquals; import static junit.framework.Assert.assertNotNull; import static junit.framework.Assert.assertNull; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; import android.content.Context; import android.content.res.Resources; import android.net.Uri; import com.android.internal.R; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.junit.MockitoJUnitRunner; @RunWith(MockitoJUnitRunner.class) public class VibrationEffectTest { private static final String RINGTONE_URI_1 = "content://test/system/ringtone_1"; private static final String RINGTONE_URI_2 = "content://test/system/ringtone_2"; private static final String RINGTONE_URI_3 = "content://test/system/ringtone_3"; private static final String UNKNOWN_URI = "content://test/system/other_audio"; @Test public void getRingtones_noPrebakedRingtones() { Resources r = mockRingtoneResources(new String[0]); Context context = mockContext(r); VibrationEffect effect = VibrationEffect.get(Uri.parse(RINGTONE_URI_1), context); assertNull(effect); } @Test public void getRingtones_noPrebakedRingtoneForUri() { Resources r = mockRingtoneResources(); Context context = mockContext(r); VibrationEffect effect = VibrationEffect.get(Uri.parse(UNKNOWN_URI), context); assertNull(effect); } @Test public void getRingtones_getPrebakedRingtone() { Resources r = mockRingtoneResources(); Context context = mockContext(r); VibrationEffect effect = VibrationEffect.get(Uri.parse(RINGTONE_URI_2), context); VibrationEffect expectedEffect = VibrationEffect.get(VibrationEffect.RINGTONES[1]); assertNotNull(expectedEffect); assertEquals(expectedEffect, effect); } private Resources mockRingtoneResources() { return mockRingtoneResources(new String[] { RINGTONE_URI_1, RINGTONE_URI_2, RINGTONE_URI_3 }); } private Resources mockRingtoneResources(String[] ringtoneUris) { Resources mockResources = mock(Resources.class); when(mockResources.getStringArray(R.array.config_ringtoneEffectUris)) .thenReturn(ringtoneUris); return mockResources; } private Context mockContext(Resources r) { Context ctx = mock(Context.class); when(ctx.getResources()).thenReturn(r); return ctx; } }