react-native-webrtc / react-native-callkeep

iOS CallKit framework and Android ConnectionService for React Native
ISC License
897 stars 437 forks source link

App crashing on registerPhoneAccount for Android 13 for selfManaged true mode #722

Open Aayushi-Mashru opened 1 year ago

Aayushi-Mashru commented 1 year ago

Bug report

Description

App is crashing during setup when trying to registerPhoneAccount in RNCallKeepModule for selfManaged true mode.

Steps to Reproduce

Setup RNCallKeep with selfManaged true.

Versions

- Callkeep: 4.3.1
- React Native: 0.62.3
- iOS:
- Android: 13
- Phone model: All

Logs

E/unknown:ReactNative: Exception in native call
    java.lang.IllegalArgumentException: Error, cannot change a self-managed phone account ComponentInfo{*app-package-id*/io.wazo.callkeep.VoiceConnectionService}, ***, UserHandle{0} to other kinds of phone account
        at android.os.Parcel.createExceptionOrNull(Parcel.java:3027)
        at android.os.Parcel.createException(Parcel.java:3007)
        at android.os.Parcel.readException(Parcel.java:2990)
        at android.os.Parcel.readException(Parcel.java:2932)
        at com.android.internal.telecom.ITelecomService$Stub$Proxy.registerPhoneAccount(ITelecomService.java:1738)
        at android.telecom.TelecomManager.registerPhoneAccount(TelecomManager.java:1612)
        at io.wazo.callkeep.RNCallKeepModule.registerPhoneAccount(RNCallKeepModule.java:853)
        at io.wazo.callkeep.RNCallKeepModule.registerPhoneAccount(RNCallKeepModule.java:243)
        at io.wazo.callkeep.RNCallKeepModule.setup(RNCallKeepModule.java:223)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.facebook.react.bridge.JavaMethodWrapper.invoke(JavaMethodWrapper.java:372)
        at com.facebook.react.bridge.JavaModuleWrapper.invoke(JavaModuleWrapper.java:151)
        at com.facebook.react.bridge.queue.NativeRunnable.run(Native Method)
        at android.os.Handler.handleCallback(Handler.java:942)
        at android.os.Handler.dispatchMessage(Handler.java:99)
        at com.facebook.react.bridge.queue.MessageQueueThreadHandler.dispatchMessage(MessageQueueThreadHandler.java:27)
        at android.os.Looper.loopOnce(Looper.java:226)
        at android.os.Looper.loop(Looper.java:313)
        at com.facebook.react.bridge.queue.MessageQueueThreadImpl$4.run(MessageQueueThreadImpl.java:226)
        at java.lang.Thread.run(Thread.java:1012)
     Caused by: android.os.RemoteException: Remote stack trace:
        at com.android.server.telecom.PhoneAccountRegistrar.enforceSelfManagedAccountUnmodified(PhoneAccountRegistrar.java:1000)
        at com.android.server.telecom.PhoneAccountRegistrar.addOrReplacePhoneAccount(PhoneAccountRegistrar.java:925)
        at com.android.server.telecom.PhoneAccountRegistrar.registerPhoneAccount(PhoneAccountRegistrar.java:905)
        at com.android.server.telecom.TelecomServiceImpl$1.registerPhoneAccount(TelecomServiceImpl.java:623)
        at com.android.internal.telecom.ITelecomService$Stub.onTransact(ITelecomService.java:857)
ibmmt commented 11 months ago
 const granted = await PermissionsAndroid.request(
    "android.permission.READ_PHONE_NUMBERS"
  );

    const options = {
    ios: {
      appName: "My app name",
    },
    android: {
      alertTitle: "Permissions required",
      alertDescription: "This application needs to access your phone accounts",
      cancelButton: "Cancel",
      okButton: "ok",
      selfManaged: true,
      additionalPermissions: [
        "android.permission.READ_PHONE_NUMBERS",
        "android.permission.READ_PHONE_STATE",
      ],
    },
  };

   RNCallKeep.setup(options)

    RNCallKeep.displayIncomingCall('uuidv4', "10086", "Caller Name");

Please try this one

badhrin commented 7 months ago

Same issue for me. RNCallKeep was working perfectly. I changed the mode to Self Managed with the intend of avoiding my calls from reaching the Call Logs of the phone. The first time it worked fine & I thought I was set. But next time, I started the app it started crashing with this same issue. Error, cannot change a self-managed phone account ComponentInfo{app-package-id/io.wazo.callkeep.VoiceConnectionService}, ***, UserHandle{0} to other kinds of phone account Tried reinstalling the app from start & similar behaviour. Worked fine for a couple of times & after that started crashing.

,@ibmmt 's suggestion above did not help. Any fix for this would be helpful ? Alternatively, if there's way to avoid our calls from reaching the Call Logs of the phone, that will be great for my use case too.

Thanks !

jikseyres16 commented 6 months ago

Having this issue on some our clients with ViVo phone. Any insights?

Aayushi-Mashru commented 6 months ago

Hello, We applied some changes to unregister the PhoneAccount by calling unregisterPhoneAccount method before trying to create or register it, and it fixed the issue. Here are the changes we have made.

File: RNCallKeepModule.java

[Change 1]

private void registerPhoneAccount(Context appContext) {
        if (!isConnectionServiceAvailable()) {
            Log.w(TAG, "[RNCallKeepModule] registerPhoneAccount ignored due to no ConnectionService");
            return;
        }

        this.initializeTelecomManager();
        Context context = this.getAppContext();
        if (context == null) {
            Log.w(TAG, "[RNCallKeepModule][registerPhoneAccount] no react context found.");
            return;
        }
        String appName = this.getApplicationName(context);

        PhoneAccount.Builder builder = new PhoneAccount.Builder(handle, appName);
        if (isSelfManaged()) {
            builder.setCapabilities(PhoneAccount.CAPABILITY_SELF_MANAGED);
        }
        else {
            builder.setCapabilities(PhoneAccount.CAPABILITY_CALL_PROVIDER);
        }

        if (_settings != null && _settings.hasKey("imageName")) {
            int identifier = appContext.getResources().getIdentifier(_settings.getString("imageName"), "drawable", appContext.getPackageName());
            Icon icon = Icon.createWithResource(appContext, identifier);
            builder.setIcon(icon);
        }

        PhoneAccount account = builder.build();

        telephonyManager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
        //Custom change start
        telecomManager.unregisterPhoneAccount(handle);
        //Custom change end
        telecomManager.registerPhoneAccount(account);
    }

[Change 2]

public void initializeTelecomManager() {
        Context context = this.getAppContext();
        if (context == null) {
            Log.w(TAG, "[RNCallKeepModule][initializeTelecomManager] no react context found.");
            return;
        }
        ComponentName cName = new ComponentName(context, VoiceConnectionService.class);
        String appName = this.getApplicationName(context);
        //Custom change start
        if (handle != null && telecomManager != null) {
            telecomManager.unregisterPhoneAccount(handle);
        }
        //Custom change end
        handle = new PhoneAccountHandle(cName, appName);
        telecomManager = (TelecomManager) context.getSystemService(Context.TELECOM_SERVICE);
    }

Hope this helps.

alepmustaqim03 commented 3 months ago

Hello, We applied some changes to unregister the PhoneAccount by calling unregisterPhoneAccount method before trying to create or register it, and it fixed the issue. Here are the changes we have made.

File: RNCallKeepModule.java

[Change 1]

private void registerPhoneAccount(Context appContext) {
        if (!isConnectionServiceAvailable()) {
            Log.w(TAG, "[RNCallKeepModule] registerPhoneAccount ignored due to no ConnectionService");
            return;
        }

        this.initializeTelecomManager();
        Context context = this.getAppContext();
        if (context == null) {
            Log.w(TAG, "[RNCallKeepModule][registerPhoneAccount] no react context found.");
            return;
        }
        String appName = this.getApplicationName(context);

        PhoneAccount.Builder builder = new PhoneAccount.Builder(handle, appName);
        if (isSelfManaged()) {
            builder.setCapabilities(PhoneAccount.CAPABILITY_SELF_MANAGED);
        }
        else {
            builder.setCapabilities(PhoneAccount.CAPABILITY_CALL_PROVIDER);
        }

        if (_settings != null && _settings.hasKey("imageName")) {
            int identifier = appContext.getResources().getIdentifier(_settings.getString("imageName"), "drawable", appContext.getPackageName());
            Icon icon = Icon.createWithResource(appContext, identifier);
            builder.setIcon(icon);
        }

        PhoneAccount account = builder.build();

        telephonyManager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
        //Custom change start
        telecomManager.unregisterPhoneAccount(handle);
        //Custom change end
        telecomManager.registerPhoneAccount(account);
    }

[Change 2]

public void initializeTelecomManager() {
        Context context = this.getAppContext();
        if (context == null) {
            Log.w(TAG, "[RNCallKeepModule][initializeTelecomManager] no react context found.");
            return;
        }
        ComponentName cName = new ComponentName(context, VoiceConnectionService.class);
        String appName = this.getApplicationName(context);
        //Custom change start
        if (handle != null && telecomManager != null) {
            telecomManager.unregisterPhoneAccount(handle);
        }
        //Custom change end
        handle = new PhoneAccountHandle(cName, appName);
        telecomManager = (TelecomManager) context.getSystemService(Context.TELECOM_SERVICE);
    }

Hope this helps.

Its working on me thanks ! 😄 👍