How to end an incoming call programmatically on Android 8.0 Oreo
Asked Answered
N

5

15

Up to Android 7.1 it was possible to end an incoming call by using the ITelephony.endCall() method and giving your app the permissions android.permission.CALL_PHONE and android.permission.READ_PHONE_STATE.

When doing the same on Android 8.0 Oreo (API 26), i get this error

12-09 18:11:25.195 16833-16833/li.doerf.leavemealone E/TelephonyServiceCallHangup: Missing permission MODIFY_PHONE_STATE, cannot hangup call

Since MODIFY_PHONE_STATE is a protected permission, my app cannot get it. Is there a way to programmatically end an incoming call on Android 8.0+?

Nannienanning answered 9/12, 2017 at 18:21 Comment(4)
See this Answer, Hope this will help: End Incoming Call AndroidArticle
I tried with that solution.Not working. But my problem is not disconnecting from 8.0 Oreo versionEelpout
Unfortunatly this does no longer work in Android 8.0+ (Oreo). Does anyone know alternatives to this that work in Oreo+?Nannienanning
Anyone found the solution?Blender
B
3

Changed App Target and Compile level to 28.

And following permissions.

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

Add the following code on onCallStateChanged method of MyPhoneStateListener class.

public void endCall() {
        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.P) {
            TelecomManager tm = (TelecomManager) mcontext.getSystemService(Context.TELECOM_SERVICE);
            if (tm != null) {
                boolean success = tm.endCall();
            }
            // success == true if call was terminated.
        } else {
            if (mcontext != null) {
                TelephonyManager telephony = (TelephonyManager) mcontext
                        .getSystemService(Context.TELEPHONY_SERVICE);
                try {
                    Class c = Class.forName(telephony.getClass().getName());
                    Method m = c.getDeclaredMethod("getITelephony");
                    m.setAccessible(true);
                    telephonyService = (ITelephony) m.invoke(telephony);
                    // telephonyService.silenceRinger();
                    telephonyService.endCall();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    }
Bentwood answered 5/8, 2019 at 10:40 Comment(0)
M
1

Please check below 2 link which is helpful to you:

Permission is only granted to system app, in Manifest

https://source.android.com/devices/tech/config/perms-whitelist

above link is used for white-list your MODIFY_PHONE_STATE permission. This is for security purpose so if you want to access this kind of permission at that time to white-list your permission after you will call your operations.

I think as per android oreo latest update you can receive phone call in your activity using inbuilt method implementation but those are not providing developer to handle end of call. Also get(read) phone number of receiving call but you need to define permission of it. I think my above description is enough to understand

Hope you understand and closed this question.

Mostly answered 18/12, 2017 at 6:28 Comment(3)
This solution only works for phones that are rooted or run aosp, which is not an option for a regular market app.Nannienanning
Then we cannot do anything into it @doerfli.Mostly
@jyubinpatel Please check this app play.google.com/store/apps/…. Its working in Android Oreo. But Its app has to be set as Default Phone App.Blender
J
1

There is a solution that I found. It requires registering as a NotificationListenerService, then parsing the actions and and sending the proper PendingIntents:

public class NotificationListener extends NotificationListenerService {
    private static final String TAG = "NotificationListener";
    private PendingIntent answerIntent;
    private PendingIntent hangupIntent;

    @Override
    public void onNotificationPosted(StatusBarNotification sbn) {
        String packageName = sbn.getPackageName();
        if ("com.google.android.dialer".equals(packageName)) {
            Notification notification = sbn.getNotification();
            for (Notification.Action action : notification.actions) {
                String title = String.valueOf(action.title);
                if ("hang up".equalsIgnoreCase(title) || "decline".equalsIgnoreCase(title)) {
                    hangupIntent = action.actionIntent;
                } else if ("answer".equalsIgnoreCase(title)) {
                    answerIntent = action.actionIntent;
                }
            }
        }
    }

    @Override
    public void onListenerConnected() {
        Log.i(TAG, "Listener connected");
        for (StatusBarNotification sbn : getActiveNotifications()) {
            onNotificationPosted(sbn);
        }
    }

    public void answerCall() {
        try {
            answerIntent.send();
        } catch (PendingIntent.CanceledException e) {
            e.printStackTrace();
        }
    }

    public void endCall() {
        try {
            hangupIntent.send();
        } catch (PendingIntent.CanceledException e) {
            e.printStackTrace();
        }
    }
}

Then declare the following in AndroidManifest.xml:

    <service
        android:name=".NotificationListener"
        android:label="@string/app_name"
        android:permission="android.permission.BIND_NOTIFICATION_LISTENER_SERVICE">
        <intent-filter>
            <action android:name="android.service.notification.NotificationListenerService" />
        </intent-filter>
    </service>

There is one more step: The user has to manually enable your app as a notification listener. You can present a dialog with instructions, then send the user to the settings page using this code:

Intent intent = new Intent(android.provider.Settings.ACTION_NOTIFICATION_LISTENER_SETTINGS);
startActivity(intent);
Jarad answered 26/10, 2018 at 1:24 Comment(5)
This is not a viable solution. It only reacts when hangup, decline or answer actions happened. The solution i am looking must be able to execute these actions.Nannienanning
It does in fact execute those actions. Trust me, I've used it in my call-blocking app. Calling endCall() does decline an incoming call or hang up an ongoing call.Jarad
This doesn't seem to work. If there's a way to make this solution work, the answer requires more information than what's currently given.Gnotobiotics
I don't know what is wrong with your code. Are you able to debug it and verify that the notification service is connected and onNotificationPosted is being called? I will provide an example app soon.Jarad
He just forgot something : You should call endCall() or answerCall() depending if you want to reject or answer the call. Nice idea. Congrat, working fineKatelyn
H
0

Try using reflection like in the answer provded here.

It works with READ_PHONE_STATE and CALL_PHONE permissions. Those permissions are available to non-system applications, according to android docs

Heavyfooted answered 20/12, 2017 at 11:10 Comment(1)
This answer is incorrect. As of Android Oreo, the method described in the linked answer requires the MODIFY_PHONE_STATE permission, which isn't available to third-party developers.Gnotobiotics
H
0

Add these permissions:

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

Also ask for runtime permission for ANSWER_PHONE_CALLS and READ_CALL_LOG permissions (as they are Dangerous Permissions).

For android oreo and below:

Create package com.android.internal.telephony in your project, and put this in a file called "ITelephony.aidl":

package com.android.internal.telephony; 
interface ITelephony {      
    boolean endCall();     
}

For above android oreo:

TelecomManager class provides direct method to end call(provided in code).

After above steps add method provided below: (Before this make sure to initialize TelecomManager and TelephonyManager).

@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
    telephonyManager = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
    telecomManager = (TelecomManager) getSystemService(Context.TELECOM_SERVICE);
}

private boolean declinePhone() {
    if (telecomManager.isInCall()) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
            if (telecomManager != null) {
                boolean success = telecomManager.endCall();
                return success;
            }
        } else {
            try {
                Class classTelephony = Class.forName(telephonyManager.getClass().getName());
                Method methodGetITelephony = classTelephony.getDeclaredMethod("getITelephony");
                methodGetITelephony.setAccessible(true);
                ITelephony telephonyService = (ITelephony) methodGetITelephony.invoke(telephonyManager);
                if (telephonyService != null) {
                    return telephonyService.endCall();
                }
            } catch (Exception e) {
                e.printStackTrace();
                Log.d("LOG", "Cant disconnect call");
                return false;
            }
        }
    }
    return false;
}
Halle answered 31/5, 2020 at 15:35 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.