androidwear-osandroid-wear-notification

Custom notification/Vibration - Firebase - wear OS - Android 8.0.0. API 26


What I have: a stand alone app on Wear OS (Android 8+), API 26 and within Firebase.

What I would achieve (first): I would to show a custom notification with custom vibration pattern.

What I would achieve (second): When my app is in background I would to open my app automatically or clicking on notification (but with custom vibration)

I am running a Foreground Service, with an on-going notification. That on-going notification works very well and has no feature from the Wear OS (so the code can work on standalone Android). I have some issues with notifications.

I can't change vibration notifications and Layout.

here my FirebaseMessagingService

public class MyfirebaseMessagingService extends FirebaseMessagingService {

    public static String TAG = "MyFirebaseMsgService";

    private LocalBroadcastManager broadcaster;

    Uri NOTIFICATION_SOUND_URI = Uri.parse(ContentResolver.SCHEME_ANDROID_RESOURCE + "://" + BuildConfig.APPLICATION_ID + "/" );
    long[] VIBRATE_PATTERN    = {0, 500};

    @Override
    public void onCreate() {
        super.onCreate();
        createNotificationChannel();

        broadcaster = LocalBroadcastManager.getInstance(this);
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
    }
    private void createNotificationChannel() {
        // Create the NotificationChannel, but only on API 26+ because
        // the NotificationChannel class is new and not in the support library
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            String channelId = getString(R.string.default_notification_channel_id);

            CharSequence name = getString(R.string.default_notification_channel_id);
            String description = getString(R.string.channel_description);
            int importance = NotificationManager.IMPORTANCE_DEFAULT;
            NotificationChannel channel = new NotificationChannel(channelId, name, importance);
            channel.setDescription(description);
            // Register the channel with the system; you can't change the importance
            // or other notification behaviors after this
            NotificationManager notificationManager = getSystemService(NotificationManager.class);
            notificationManager.createNotificationChannel(channel);
        }
    }


    @Override
    public void onMessageReceived(RemoteMessage remoteMessage) {


        Log.d(TAG, "From: " + remoteMessage.getFrom());
        Intent home = new Intent(getApplicationContext(), Splash.class);
        home.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK|Intent.FLAG_ACTIVITY_CLEAR_TASK);
        startActivity(home);

        // Check if message contains a data payload.
        if (remoteMessage.getData().size() > 0) {
            Log.d(TAG, "Message data payload: " + remoteMessage.getData());
        }

        // Check if message contains a notification payload.
        if (remoteMessage.getNotification() != null) {

            Log.d(TAG, "Message Notification Body: " + remoteMessage.getNotification().getBody());

            Intent intent = new Intent("Data");
            intent.putExtra("messageFromCloud", remoteMessage.getNotification().getBody());
            broadcaster.sendBroadcast(intent);
            if (intent.getExtras() != null)
            {
                MyNotificationManager notification =  MyNotificationManager.getInstance(this);
                notification.displayNotification("title",remoteMessage.getNotification().getBody());

                RemoteMessage.Builder builder = new RemoteMessage.Builder("MyFirebaseMessagingService");

                for (String key : intent.getExtras().keySet())
                {
                    builder.addData(key, Objects.requireNonNull(intent.getExtras().get(key)).toString());
                }
                if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
                    NotificationManager mNotificationManager =
                            (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
                    int importance = NotificationManager.IMPORTANCE_HIGH;
                    NotificationChannel mChannel = new NotificationChannel(Constants.CHANNEL_ID, Constants.CHANNEL_NAME, importance);
                    mChannel.setDescription(Constants.CHANNEL_DESCRIPTION);
                    mChannel.enableLights(true);
                    mChannel.setLightColor(Color.RED);
                    mChannel.enableVibration(true);
      //                    mChannel.setVibrationPattern(new long[]{100, 200, 300, 400, 500, 400, 300, 200, 400});
                    mNotificationManager.createNotificationChannel(mChannel);

                     Vibrator vibrator = (Vibrator) getSystemService(VIBRATOR_SERVICE);
                    long[] newvibrationPattern = {0, 1000, 500, 50,
                                0, 1000, 500, 50,
                                0, 1000, 500, 50,
                                0, 1000, 500, 50,
                                0, 1000, 500, 50,
                                0, 1000, 500, 50};
                     //-1 - don't repeat
                     final int indexInPatternToRepeat = -1;
                     vibrator.vibrate(newvibrationPattern, indexInPatternToRepeat);
                }
                onMessageReceived(builder.build());
            }
        }
    }
}

Solution

  • I finally managed to get around the custom vibration pattern. Your code is pretty messy DoctorWho. Like you, I also tried various combinations with the NotificationCompat.Builder and NotificationChannel but nothing worked. In order to get the custom vibrations working you have two options, do not show the notification and just play your custom vibration or you can show the notification, but you will have to implement it so that vibrations are disabled for that NotificationChannel you build the notification and include a 1 second delay after playing your custom vibration. Example:

    val notificationBuilder = NotificationCompat.Builder(this, "channelId")
    ...
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
                val chan = NotificationChannel(
                    "channelId",
                    "Default",
                    NotificationManager.IMPORTANCE_HIGH
                )
                chan.enableVibration(false)
                notificationManager.createNotificationChannel(chan)
            }
    

    and now you can run your vibration pattern after 1 second delay:

    Timer().schedule(1000) {
            vibrate(pattern)
    }
    private fun vibrate(pattern: LongArray) {
            val v = getSystemService(Context.VIBRATOR_SERVICE) as Vibrator
    
            if (v.hasVibrator()) {
    
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
                    v.vibrate(VibrationEffect.createWaveform(pattern, -1))
                } else {
                    //deprecated in API 26
                    @Suppress("DEPRECATION")
                    v.vibrate(pattern, -1)
                }
            }
        }
    

    And do not forget to set permission in the manifest:

    <uses-permission android:name="android.permission.VIBRATE" />
    

    All this except vibrate function goes into your override fun onMessageReceived(msg: RemoteMessage) function.