2
votes

In my app, I already granted the permission for PHONE_STATE and it is detecting receiving/offhook/idle stats smoothly.

I need the mobile to ring if the incoming call is from respecified number even if the mobile is silent, so i'm changing the AudioManager status as below, but the app is crash once it is trying to change the ringermode!!

class PhoneStateReceiver : BroadcastReceiver() {
    override fun onReceive(context: Context, intent: Intent) {

        val state = intent.getStringExtra(TelephonyManager.EXTRA_STATE)
        val incomingNumber = intent.getStringExtra(TelephonyManager.EXTRA_INCOMING_NUMBER)

        val audio = context.getSystemService(Context.AUDIO_SERVICE) as AudioManager
        if (incomingNumber == "(650) 555-1212" && state == TelephonyManager.EXTRA_STATE_RINGING) {
            Toast.makeText(context, "Ringing ${audio.ringerMode}", Toast.LENGTH_SHORT).show()
            if(audio.ringerMode == AudioManager.RINGER_MODE_SILENT)
            audio.apply {    // The app crash here!!
                ringerMode = AudioManager.RINGER_MODE_NORMAL
                setStreamVolume(AudioManager.STREAM_RING,
                        audio.getStreamMaxVolume(AudioManager.STREAM_RING),
                        AudioManager.FLAG_ALLOW_RINGER_MODES or AudioManager.FLAG_PLAY_SOUND)
            }
            val ring = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_RINGTONE)
            val r = RingtoneManager.getRingtone(context, ring)
            r.play()
        }
        if (state == TelephonyManager.EXTRA_STATE_OFFHOOK) {
             audio.ringerMode = AudioManager.RINGER_MODE_SILENT
            Toast.makeText(context, "On Call ", Toast.LENGTH_SHORT).show()
        }
        if (state == TelephonyManager.EXTRA_STATE_IDLE) {
            Toast.makeText(context, "IDLE", Toast.LENGTH_SHORT).show()
        }
    }
}

And in AndroidManifest.xml:

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

<receiver
    android:name=".broadcasts.PhoneStateReceiver">
    <intent-filter>
        <action android:name="android.intent.action.PHONE_STATE" />
    </intent-filter>
</receiver> 

UPDATE

This is the Logcat error:

04-26 04:55:04.422 1406-2091/? W/audio_hw_generic: Not supplying enough data to HAL, expected position 1097356 , only wrote 1097280 04-26 04:55:04.434 5065-5065/? D/AndroidRuntime: Shutting down VM 04-26 04:55:04.446 5065-5065/? E/AndroidRuntime: FATAL EXCEPTION: main Process: com.example.hasan.ringer, PID: 5065 java.lang.SecurityException: Not allowed to change Do Not Disturb state at android.os.Parcel.createException(Parcel.java:1942) at android.os.Parcel.readException(Parcel.java:1865) at android.media.IAudioService$Stub$Proxy.setRingerModeExternal(IAudioService.java:1161) at android.media.AudioManager.setRingerMode(AudioManager.java:1099) at com.example.hasan.ringer.MainActivity$onCreate$1.onClick(MainActivity.kt:20) at android.view.View.performClick(View.java:6579) at android.view.View.performClickInternal(View.java:6556) at android.view.View.access$3100(View.java:777) at android.view.View$PerformClick.run(View.java:25660) at android.os.Handler.handleCallback(Handler.java:819) at android.os.Handler.dispatchMessage(Handler.java:99) at android.os.Looper.loop(Looper.java:164) at android.app.ActivityThread.main(ActivityThread.java:6656) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:438) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:823) Caused by: android.os.RemoteException: Remote stack trace: at com.android.server.audio.AudioService.setRingerModeExternal(AudioService.java:2333) at android.media.IAudioService$Stub.onTransact(IAudioService.java:199) at android.os.Binder.execTransact(Binder.java:726) 04-26 04:55:04.453 1680-4664/system_process W/ActivityManager: Force finishing activity com.example.hasan.ringer/.MainActivity

2
You need to include the error logs in your question. Perhaps the intent parameter needs to be Intent? rather than Intent. - Michael
@Michael I added the error. - Hasan A Yousef
have you set setRingerMode(AudioManager.RINGER_MODE_NORMAL) before setting setStreamVolume ? - Upendra Shah

2 Answers

1
votes

I found the answer, permission of ACCESS_NOTIFICATION_POLICY is required, in the manifest below line required:

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

And the permission is granted from the ACTION_NOTIFICATION_POLICY_ACCESS_SETTINGS as below:

val notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && !notificationManager.isNotificationPolicyAccessGranted) {

        val intent = Intent(
                android.provider.Settings
                        .ACTION_NOTIFICATION_POLICY_ACCESS_SETTINGS)

        startActivity(intent)
}
0
votes

This is the java version of the answer from Hasan (see the code below) even if Kotlin do it better! :)

I found the answer, permission of ACCESS_NOTIFICATION_POLICY is required, in the manifest below line required:

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

And the permission is granted from the ACTION_NOTIFICATION_POLICY_ACCESS_SETTINGS as below:

    NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && !notificationManager.isNotificationPolicyAccessGranted()) {
        Intent intent = new Intent(android.provider.Settings.ACTION_NOTIFICATION_POLICY_ACCESS_SETTINGS);
        startActivity(intent);
    }