androidandroid-10.0android-vibration

Android vibration app doesn't work anymore after Android 10, API 29 update


so I made an app a couple months back that helped me improve my sleep. I have sleeping issues and, it sounds odd, but I use the app to vibrate my phone when I go to bed to give myself something to focus on to go to sleep, it is currently a vital aspect of my sleep routine.

However, I updated my phone to Android 10 yesterday and it completely broke the app. Before, the app would vibrate when I click the start button and continue to vibrate even after I lock the phone by using a background service, broadcast receiver, and wake lock. Now though, the app stops vibrating after I lock the phone and nothing in the console gives any reason as to why it is doing this.

If anyone could give advice on what I could change in the code or something, it would be much appreciated as I'm completely lost as to what to do and I have to get this to work somehow.

Here is the code:

Function in MainActivity that handles the beginning of the service Vibrate:

// 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);
    }
}

Vibrate Service 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());
}

}

Thank you for anyone's help in advance.


Solution

  • It might not care about these instructions:

    IntentFilter filter = new IntentFilter(Intent.ACTION_SCREEN_OFF);
    registerReceiver(re, filter);
    

    So it probably should be something alike:

    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 and Intent.ACTION_SCREEN_OFF generally require the app to be running. But the Android 10 behavior changes do not mention something alike that, therefore it is difficult to tell. Also receiving broadcasts does not tell anything about a recent change.