Android Android 10,API 29 更新后振动应用程序不再工作
Android vibration app doesn't work anymore after Android 10, API 29 update
所以几个月前我做了一个应用程序来帮助我改善睡眠。我有睡眠问题,这听起来很奇怪,但我会在上床睡觉时使用该应用程序振动我的 phone,让自己专注于入睡,这是目前我日常睡眠的一个重要方面.
但是,我昨天将 phone 更新为 Android 10,它完全破坏了应用程序。以前,当我点击开始按钮时,应用程序会振动,即使我使用后台服务、广播接收器和唤醒锁锁定 phone 后,应用程序仍会继续振动。不过现在,应用程序在我锁定 phone 后停止振动,并且控制台中没有任何内容说明它为什么这样做。
如果有人可以就我可以在代码中更改什么或其他内容提出建议,我将不胜感激,因为我完全不知道该做什么,我必须以某种方式让它工作。
代码如下:
MainActivity 中处理振动服务开始的函数:
// Event for when the VIBRATE button is pressed
public void beginVibration(View view) {
// Given either of the bars are not 0
if (durationBar.getProgress() != 0 || delayBar.getProgress() != 0) {
// Get the values for each bar and set them accordingly in the vibration value array
long[] pattern = {0, durationBar.getProgress(), delayBar.getProgress()};
// Setup the ServiceConnection to monitor the Vibrate service
c = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
m_service = ((Vibrate.MyBinder)service).getService();
}
@Override
public void onServiceDisconnected(ComponentName name) {
m_service = null;
}
};
// Bind the service to the connection
bindService(i, c, BIND_AUTO_CREATE);
// Insert the pattern into the intent itself
i.putExtra("pattern", pattern);
// Start the vibrate service
this.startService(i);
}
}
振动服务class:
public class Vibrate extends Service {
// Vibration object
private Vibrator v;
/*
THESE THREE ARE FOR PREVENTING THE VIBRATION FROM STOPPING AFTER THE PHONE IS PUT TO SLEEP
*/
// Wake Lock object
private PowerManager.WakeLock wl;
// Manager for the notifications
private NotificationManagerCompat m_notificationManager;
// BroadcastReceiver object
public BroadcastReceiver re;
public AudioAttributes audioAttributes;
// Not gonna lie, Idk what this does just know it is part of the binding process within MainActivity
public class MyBinder extends Binder {
public Vibrate getService() {
return Vibrate.this;
}
}
@Override
public void onCreate() {
super.onCreate();
// Acquire the Wake Lock
PowerManager pw = (PowerManager) getSystemService(POWER_SERVICE);
wl = pw.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "WL:");
wl.acquire();
// Get the vibration service
v = (Vibrator) getSystemService(VIBRATOR_SERVICE);
AudioAttributes audioAttributes = new AudioAttributes.Builder()
.setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
.setUsage(AudioAttributes.USAGE_ALARM)
.build();
}
@Override
public int onStartCommand(Intent i, int flags, int startId) {
// Ensure that an intent with a long array has been passed
if (i != null && i.getExtras() != null) {
// Get the array
final long[] pattern = i.getExtras().getLongArray("pattern");
// Begin the vibration
v.vibrate(pattern, 0);
// Intialize the BroadcastReceiver and set it to trigger when the screen is turned off,
// thus triggering the vibrations
re = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) {
Log.i("VIZZY: ", "VIBRATION STARTED");
v.vibrate(pattern, 0, audioAttributes);
Log.i("VIZZY: ", "VIBRATION BEGUn");
}
}
};
// Add a listener for when the screen turns off and register the receiver
IntentFilter filter = new IntentFilter(Intent.ACTION_SCREEN_OFF);
registerReceiver(re, filter);
}
return Service.START_STICKY;
}
@Override
public void onDestroy() {
// If the phone was put to sleep, cancel the notification keeping the vibration going
if (m_notificationManager != null) {
m_notificationManager.cancel(001);
}
// Release the Wake Lock, unregister the BroadcastReceiver, and stop the vibrations
wl.release();
unregisterReceiver(re);
v.cancel();
}
@Override
public IBinder onBind(Intent intent) {
return null;
}
private void addNotification() {
// create the notification
Notification.Builder m_notificationBuilder = new Notification.Builder(this)
.setContentTitle("VIZZY")
.setContentText("VIBRATING")
.setSmallIcon(R.mipmap.ic_launcher);
// create the pending intent and add to the notification
Intent intent = new Intent(this, Vibrate.class);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent, 0);
m_notificationBuilder.setContentIntent(pendingIntent);
m_notificationManager = NotificationManagerCompat.from(this);
// send the notification
m_notificationManager.notify(001, m_notificationBuilder.build());
}
}
提前感谢大家的帮助。
它可能不关心这些指令:
IntentFilter filter = new IntentFilter(Intent.ACTION_SCREEN_OFF);
registerReceiver(re, filter);
所以它可能应该是类似的东西:
if (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.Q){
IntentFilter filter = new IntentFilter(Intent.ACTION_SCREEN_OFF);
registerReceiver(re, filter);
} else {
/* whatever it takes to make it work >= API level 29 */
}
Intent.ACTION_SCREEN_ON
和Intent.ACTION_SCREEN_OFF
一般要求应用为运行。但是 Android 10 behavior changes do not mention something alike that, therefore it is difficult to tell. Also receiving broadcasts 并没有说明最近的变化。
我遇到了同样的问题。而且我发现,从目标 29 振动开始,只有在将适当的音频属性传递给方法的情况下,振动才会在后台工作:
public void vibrate(VibrationEffect vibe, AudioAttributes attributes);
你可以尝试这样使用它:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
vibrator.vibrate(VibrationEffect.createWaveform(pattern, 0),
new AudioAttributes.Builder()
.setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
.setUsage(AudioAttributes.USAGE_ALARM)
.build());
} else {
vibrator.vibrate(pattern, 0);
}
所以几个月前我做了一个应用程序来帮助我改善睡眠。我有睡眠问题,这听起来很奇怪,但我会在上床睡觉时使用该应用程序振动我的 phone,让自己专注于入睡,这是目前我日常睡眠的一个重要方面.
但是,我昨天将 phone 更新为 Android 10,它完全破坏了应用程序。以前,当我点击开始按钮时,应用程序会振动,即使我使用后台服务、广播接收器和唤醒锁锁定 phone 后,应用程序仍会继续振动。不过现在,应用程序在我锁定 phone 后停止振动,并且控制台中没有任何内容说明它为什么这样做。
如果有人可以就我可以在代码中更改什么或其他内容提出建议,我将不胜感激,因为我完全不知道该做什么,我必须以某种方式让它工作。
代码如下:
MainActivity 中处理振动服务开始的函数:
// Event for when the VIBRATE button is pressed
public void beginVibration(View view) {
// Given either of the bars are not 0
if (durationBar.getProgress() != 0 || delayBar.getProgress() != 0) {
// Get the values for each bar and set them accordingly in the vibration value array
long[] pattern = {0, durationBar.getProgress(), delayBar.getProgress()};
// Setup the ServiceConnection to monitor the Vibrate service
c = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
m_service = ((Vibrate.MyBinder)service).getService();
}
@Override
public void onServiceDisconnected(ComponentName name) {
m_service = null;
}
};
// Bind the service to the connection
bindService(i, c, BIND_AUTO_CREATE);
// Insert the pattern into the intent itself
i.putExtra("pattern", pattern);
// Start the vibrate service
this.startService(i);
}
}
振动服务class:
public class Vibrate extends Service {
// Vibration object
private Vibrator v;
/*
THESE THREE ARE FOR PREVENTING THE VIBRATION FROM STOPPING AFTER THE PHONE IS PUT TO SLEEP
*/
// Wake Lock object
private PowerManager.WakeLock wl;
// Manager for the notifications
private NotificationManagerCompat m_notificationManager;
// BroadcastReceiver object
public BroadcastReceiver re;
public AudioAttributes audioAttributes;
// Not gonna lie, Idk what this does just know it is part of the binding process within MainActivity
public class MyBinder extends Binder {
public Vibrate getService() {
return Vibrate.this;
}
}
@Override
public void onCreate() {
super.onCreate();
// Acquire the Wake Lock
PowerManager pw = (PowerManager) getSystemService(POWER_SERVICE);
wl = pw.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "WL:");
wl.acquire();
// Get the vibration service
v = (Vibrator) getSystemService(VIBRATOR_SERVICE);
AudioAttributes audioAttributes = new AudioAttributes.Builder()
.setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
.setUsage(AudioAttributes.USAGE_ALARM)
.build();
}
@Override
public int onStartCommand(Intent i, int flags, int startId) {
// Ensure that an intent with a long array has been passed
if (i != null && i.getExtras() != null) {
// Get the array
final long[] pattern = i.getExtras().getLongArray("pattern");
// Begin the vibration
v.vibrate(pattern, 0);
// Intialize the BroadcastReceiver and set it to trigger when the screen is turned off,
// thus triggering the vibrations
re = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) {
Log.i("VIZZY: ", "VIBRATION STARTED");
v.vibrate(pattern, 0, audioAttributes);
Log.i("VIZZY: ", "VIBRATION BEGUn");
}
}
};
// Add a listener for when the screen turns off and register the receiver
IntentFilter filter = new IntentFilter(Intent.ACTION_SCREEN_OFF);
registerReceiver(re, filter);
}
return Service.START_STICKY;
}
@Override
public void onDestroy() {
// If the phone was put to sleep, cancel the notification keeping the vibration going
if (m_notificationManager != null) {
m_notificationManager.cancel(001);
}
// Release the Wake Lock, unregister the BroadcastReceiver, and stop the vibrations
wl.release();
unregisterReceiver(re);
v.cancel();
}
@Override
public IBinder onBind(Intent intent) {
return null;
}
private void addNotification() {
// create the notification
Notification.Builder m_notificationBuilder = new Notification.Builder(this)
.setContentTitle("VIZZY")
.setContentText("VIBRATING")
.setSmallIcon(R.mipmap.ic_launcher);
// create the pending intent and add to the notification
Intent intent = new Intent(this, Vibrate.class);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent, 0);
m_notificationBuilder.setContentIntent(pendingIntent);
m_notificationManager = NotificationManagerCompat.from(this);
// send the notification
m_notificationManager.notify(001, m_notificationBuilder.build());
}
}
提前感谢大家的帮助。
它可能不关心这些指令:
IntentFilter filter = new IntentFilter(Intent.ACTION_SCREEN_OFF);
registerReceiver(re, filter);
所以它可能应该是类似的东西:
if (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.Q){
IntentFilter filter = new IntentFilter(Intent.ACTION_SCREEN_OFF);
registerReceiver(re, filter);
} else {
/* whatever it takes to make it work >= API level 29 */
}
Intent.ACTION_SCREEN_ON
和Intent.ACTION_SCREEN_OFF
一般要求应用为运行。但是 Android 10 behavior changes do not mention something alike that, therefore it is difficult to tell. Also receiving broadcasts 并没有说明最近的变化。
我遇到了同样的问题。而且我发现,从目标 29 振动开始,只有在将适当的音频属性传递给方法的情况下,振动才会在后台工作:
public void vibrate(VibrationEffect vibe, AudioAttributes attributes);
你可以尝试这样使用它:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
vibrator.vibrate(VibrationEffect.createWaveform(pattern, 0),
new AudioAttributes.Builder()
.setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
.setUsage(AudioAttributes.USAGE_ALARM)
.build());
} else {
vibrator.vibrate(pattern, 0);
}