Rexios80 / wear_ongoing_activity

Create and maintain ongoing activity notifications on Wear OS
https://pub.dev/packages/wear_ongoing_activity
BSD 3-Clause "New" or "Revised" License
3 stars 2 forks source link

Unknown nullpointer error when creating ongoing activity #2

Closed masus04 closed 7 months ago

masus04 commented 7 months ago

I configured an ongoing activity as follows:

AndroidManifest.xml

<service
    android:name="dev.rexios.wear_ongoing_activity.OngoingActivityService"
    android:exported="false"
    android:foregroundServiceType=""
    android:stopWithTask="true" />

notification_controller.dart

import 'package:permission_handler/permission_handler.dart';
import 'package:wear_ongoing_activity/wear_ongoing_activity.dart';

enum NotificationChannelIdentifier {
  channelKey(value: "base_channel"),
  channelName(value: "Base Notifications"),
  channelGroupKey(value: "base_channel_group"),
  channelGroupName(value: "Base Channel Group"),
  channelDescription(value: "Notification Channel for Base Notifications");

  const NotificationChannelIdentifier({
    required this.value,
  });

  final String value;
}

class NotificationController {
  static const timerId = 32;

  static Future<void> init() async {
    requestPermissions();
  }

  static requestPermissions() async {
    // // TODO: Show permission dialog
    await Permission.notification.request();
  }

  static startOngoingActivity({required Duration timeToStart}) {
    WearOngoingActivity.start(
      channelId: NotificationChannelIdentifier.channelKey.value,
      channelName: NotificationChannelIdentifier.channelName.value,
      notificationId: timerId,
      category: NotificationCategory.alarm,
      foregroundServiceTypes: {
        // Currently not required
        // ForegroundServiceType.location,
      },
      smallIcon: 'icons/regatta_timer_icon_only.png',
      staticIcon: 'icons/regatta_timer_icon_only.png',
      status: OngoingTimerActivityStatus(
        timeToStart: timeToStart,
      ),
    );
  }

  static updateOngoingActivity({required Duration timeToStart}) {
    WearOngoingActivity.update(
      OngoingTimerActivityStatus(
        timeToStart: timeToStart,
      ),
    );
  }

  static cancelTimerNotification() {
    // AwesomeNotifications().cancel(timerId);
    WearOngoingActivity.stop();
  }
}

class OngoingTimerActivityStatus extends OngoingActivityStatus {
  OngoingTimerActivityStatus({required Duration timeToStart})
      : super(
          templates: [
            "Starts in: #time#",
          ],
          parts: [
            TextPart(name: "time", text: "${-timeToStart.inMinutes}:${-timeToStart.inSeconds % 60}"),
          ],
        );
}

When I run it, the following error is thrown and no notification is shown:

E/MethodChannel#wear_ongoing_activity( 3941): Failed to handle method call
E/MethodChannel#wear_ongoing_activity( 3941): java.lang.NullPointerException
E/MethodChannel#wear_ongoing_activity( 3941):   at dev.rexios.wear_ongoing_activity.OngoingActivityService.update(WearOngoingActivityPlugin.kt:187)
E/MethodChannel#wear_ongoing_activity( 3941):   at dev.rexios.wear_ongoing_activity.WearOngoingActivityPlugin.onMethodCall(WearOngoingActivityPlugin.kt:58)
E/MethodChannel#wear_ongoing_activity( 3941):   at io.flutter.plugin.common.MethodChannel$IncomingMethodCallHandler.onMessage(MethodChannel.java:267)
E/MethodChannel#wear_ongoing_activity( 3941):   at io.flutter.embedding.engine.dart.DartMessenger.invokeHandler(DartMessenger.java:292)
E/MethodChannel#wear_ongoing_activity( 3941):   at io.flutter.embedding.engine.dart.DartMessenger.lambda$dispatchMessageToQueue$0$io-flutter-embedding-engine-dart-DartMessenger(DartMessenger.java:319)
E/MethodChannel#wear_ongoing_activity( 3941):   at io.flutter.embedding.engine.dart.DartMessenger$$ExternalSyntheticLambda0.run(Unknown Source:12)
E/MethodChannel#wear_ongoing_activity( 3941):   at android.os.Handler.handleCallback(Handler.java:942)
E/MethodChannel#wear_ongoing_activity( 3941):   at android.os.Handler.dispatchMessage(Handler.java:99)
E/MethodChannel#wear_ongoing_activity( 3941):   at android.os.Looper.loopOnce(Looper.java:201)
E/MethodChannel#wear_ongoing_activity( 3941):   at android.os.Looper.loop(Looper.java:288)
E/MethodChannel#wear_ongoing_activity( 3941):   at android.app.ActivityThread.main(ActivityThread.java:7898)
E/MethodChannel#wear_ongoing_activity( 3941):   at java.lang.reflect.Method.invoke(Native Method)
E/MethodChannel#wear_ongoing_activity( 3941):   at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:548)
E/MethodChannel#wear_ongoing_activity( 3941):   at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:936)
E/flutter ( 3941): [ERROR:flutter/runtime/dart_vm_initializer.cc(41)] Unhandled Exception: PlatformException(error, null, null, java.lang.NullPointerException
E/flutter ( 3941):  at dev.rexios.wear_ongoing_activity.OngoingActivityService.update(WearOngoingActivityPlugin.kt:187)
E/flutter ( 3941):  at dev.rexios.wear_ongoing_activity.WearOngoingActivityPlugin.onMethodCall(WearOngoingActivityPlugin.kt:58)
E/flutter ( 3941):  at io.flutter.plugin.common.MethodChannel$IncomingMethodCallHandler.onMessage(MethodChannel.java:267)
E/flutter ( 3941):  at io.flutter.embedding.engine.dart.DartMessenger.invokeHandler(DartMessenger.java:292)
E/flutter ( 3941):  at io.flutter.embedding.engine.dart.DartMessenger.lambda$dispatchMessageToQueue$0$io-flutter-embedding-engine-dart-DartMessenger(DartMessenger.java:319)
E/flutter ( 3941):  at io.flutter.embedding.engine.dart.DartMessenger$$ExternalSyntheticLambda0.run(Unknown Source:12)
E/flutter ( 3941):  at android.os.Handler.handleCallback(Handler.java:942)
E/flutter ( 3941):  at android.os.Handler.dispatchMessage(Handler.java:99)
E/flutter ( 3941):  at android.os.Looper.loopOnce(Looper.java:201)
E/flutter ( 3941):  at android.os.Looper.loop(Looper.java:288)
E/flutter ( 3941):  at android.app.ActivityThread.main(ActivityThread.java:7898)
E/flutter ( 3941):  at java.lang.reflect.Method.invoke(Native Method)
E/flutter ( 3941):  at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:548)
E/flutter ( 3941):  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:936)
E/flutter ( 3941): )
E/flutter ( 3941): #0      StandardMethodCodec.decodeEnvelope (package:flutter/src/services/message_codecs.dart:651:7)
E/flutter ( 3941): #1      MethodChannel._invokeMethod (package:flutter/src/services/platform_channel.dart:334:18)
E/flutter ( 3941): <asynchronous suspension>

Any idea what this could be about?

DanielMartini commented 7 months ago

I can confirm that happens also on my side, eventhough that despite the error it keeps working on my app and the ongoing activity is ok.

I was able to reproduce it, not in a constant way, but seems that is when the app is unexpected closed (like stopping the debugger or forcing the exit without calling the WearOngoingActivity.stop() function. On the further launchments of the app after making the init, if we WearOngoingActivity.update() I have the same error, it doesn't find the initialized ongoing activity.

my implementation:

import 'package:wear_ongoing_activity/wear_ongoing_activity.dart';

class OngoingActivityService {

  /// Initialize the ongoing activity
  static Future<void> init(String message) async {
      return WearOngoingActivity.start(
        channelId: 'ongoing_activity',
        channelName: 'Ongoing Activity',
        notificationId: 12345,
        category: NotificationCategory.status,
        foregroundServiceTypes: {
          ForegroundServiceType.dataSync,
        },
        smallIcon: 'ic_notification',
        staticIcon: 'ic_notification',
        animatedIcon: 'ic_notification',
        status: OngoingActivityStatus(
          templates: [
            '#type#',
          ],
          parts: [
            TextPart(name: 'type', text: message),
          ],
        ),
      );
  }

  /// Update the ongoing activity text
  static Future<void> update(String message) async {
    return WearOngoingActivity.update(
      OngoingActivityStatus(
        templates: [
          '#type#',
        ],
        parts: [
          TextPart(
              name: 'type',
              text: message
          ),
        ],
      ),
    );
  }

  /// Dispose the ongoing activity
  static Future<void> dispose() {
    return WearOngoingActivity.stop();
  }
}
Rexios80 commented 7 months ago

The icons are supposed to be Android resource IDs, not Flutter assets. That's probably why the first code example isn't working

Rexios80 commented 7 months ago

I'm going to need a code sample that reliable reproduces this in order to look into it

masus04 commented 7 months ago

Ok, while trying to reproduce the error in an example project, I figured out that I had never called the WearOngoingActivity.start method, and therefore calling the WearOngoingActivity.update method resulted in an error.

Thanks for your support :+1:

Rexios80 commented 7 months ago

This was probably caused by calling update too soon after calling start. I pushed a new version 0.1.4 that adds an isOngoing method so that you can check if the activity is running before attempting to update it.