Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Replace default phone APP

I'm trying to replace the default android phone call app. More specifically I want to launch my custom phone call screen everytime a call action is performed.

I understand this is possible since Android's API 24 (Version 7.0 - Nougat) but I found no references on how to achieve this. Just to be clear, I do not want to show an overlay layout for the call screen. I want to set my call app as default.

I found a similar question for the sms app here: Stackoverflow - replace default sms app. The answer made it clear that you need to list all the components for the sms app in order to be able to set it as the default application in android's settings. But I can't find any reference for the phone call components.

How can I achieve this?

For reference this is my manifest file:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.mynumbers">
    <uses-permission android:name="android.permission.CALL_PHONE" />
    <uses-permission android:name="android.permission.READ_PHONE_STATE" />
    <uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS"/>
    <uses-permission android:name="android.permission.ANSWER_PHONE_CALLS"/>
    <uses-permission android:name="android.permission.INTERNET" />
    <application
        android:label="">

        <activity
            android:name=".MainActivity"
            android:theme="@style/Theme.AppCompat.Light.NoActionBar">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <action android:name="android.intent.action.DIAL" />
                <action android:name="android.intent.action.CALL_BUTTON" />
                <action android:name="android.intent.action.CALL_PRIVILEGED" />
                <category android:name="android.intent.category.DEFAULT" />
                <category android:name="android.intent.category.BROWSABLE" />
                <category android:name="android.intent.category.LAUNCHER" />
                <data android:scheme="tel"/>
            </intent-filter>
        </activity>

        <activity
            android:name=".NumberManagementActivity"
            android:parentActivityName=".MainActivity">
            <meta-data
                android:name="android.support.PARENT_ACTIVITY"
                android:value=".MainActivity" />
        </activity>

        <activity
        android:name=".CallActivity"
            android:parentActivityName=".MainDialerActivity"
            android:theme="@style/Theme.AppCompat.Light.NoActionBar">
            <meta-data
                android:name="android.support.PARENT_ACTIVITY"
                android:value=".MainDialerActivity" />
            <intent-filter>
                <action android:name="android.permission.CALL_PHONE" />
                <action android:name="android.intent.action.PHONE_STATE" />
            </intent-filter>
        </activity>

        <activity
            android:name=".MainDialerActivity"
            android:parentActivityName=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.DIAL" />
                <action android:name="android.intent.action.CALL_BUTTON"/>
                <action android:name="android.intent.action.CALL_PRIVILEGED" />
                <action android:name="android.permission.CALL_PHONE"/>
                <data android:scheme="tel"/>
            </intent-filter>
        </activity>

        <receiver
            android:name=".PhoneCallListener">
            <intent-filter android:priority="1">
                <action android:name="android.intent.action.PHONE_STATE" />
                <action android:name="android.intent.action.NEW_OUTGOING_CALL" />
            </intent-filter>
        </receiver>
        <!-- Incoming call activity -->
        <activity
            android:name=".IncomingCallActivity"
            android:configChanges="orientation"
            android:label="@string/title_activity_fullscreen"
            android:theme="@style/IncomingCallTheme">
            <intent-filter>
                <action android:name="android.intent.action.ANSWER" />
                <category android:name="android.intent.category.DEFAULT" />
            </intent-filter>
        </activity>

        <activity
            android:name=".DefaultConfigurationActivity"
            android:parentActivityName=".MainActivity">
        </activity>
    </application>
</manifest>
like image 572
Daniel André Avatar asked Jan 08 '18 15:01

Daniel André


People also ask

Can I change default phone app?

Open your phone's Settings app. Default apps. Tap the default that you want to change. Tap the app that you want to use by default.

What is the default phone app on Android?

With Android, you can configure the following default apps: Browser (default is Chrome) Caller ID & Spam App (default is Phone) Digital Assistant App (default is Google Assistant)

What does default phone app mean?

Your computer, your phone and your tablet all have default apps, the preloaded software that springs into action whenever a specific task needs doing. Click an image you've just received over email, for example, and it opens in your default image viewer.


2 Answers

I have searched all over the google, and finally find a solution. now I can replace the default phone(calling) app with my custom created app If you add those permissions in your manifest file you will able to change your app as default calling app in -> Phone Menu -> Settings -> Apps -> Default Apps (Menu item in right top corner) -> Default Calling apps and finally select your app.

here are the permissions list

<uses-permission
    android:name="android.permission.CALL_PRIVILEGED"
    tools:ignore="ProtectedPermissions" />
<uses-permission android:name="android.permission.READ_CONTACTS" />
<uses-permission android:name="android.permission.WRITE_CONTACTS" />
<uses-permission android:name="android.permission.READ_CALL_LOG" />
<uses-permission android:name="android.permission.WRITE_CALL_LOG" />
<uses-permission android:name="android.permission.READ_PROFILE" />
<uses-permission android:name="android.permission.MANAGE_ACCOUNTS" />
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS" />
<uses-permission android:name="android.permission.NFC" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
<uses-permission
    android:name="android.permission.MODIFY_PHONE_STATE"
    tools:ignore="ProtectedPermissions" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_SETTINGS" />
<uses-permission android:name="android.permission.USE_CREDENTIALS" />
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.READ_SYNC_SETTINGS" />
<uses-permission android:name="com.android.voicemail.permission.ADD_VOICEMAIL" />
<uses-permission android:name="com.android.voicemail.permission.READ_WRITE_ALL_VOICEMAIL" />
<uses-permission
    android:name="android.permission.ALLOW_ANY_CODEC_FOR_PLAYBACK"
    tools:ignore="ProtectedPermissions" />
<uses-permission android:name="com.android.launcher.permission.INSTALL_SHORTCUT" />
<!-- allow broadcasting secret code intents that reboot the phone -->
<uses-permission
    android:name="android.permission.REBOOT"
    tools:ignore="ProtectedPermissions" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<!--
 This tells the activity manager to not delay any of our activity
 start requests, even if they happen immediately after the user
 presses home.
-->
<uses-permission
    android:name="android.permission.STOP_APP_SWITCHES"
    tools:ignore="ProtectedPermissions" />
like image 88
Rob Avatar answered Nov 15 '22 18:11

Rob


since API 23 it is possible, see Replacing default Phone app on Android 6 and 7 with InCallService arekolek.

Kotlin version: Simple Phone

Java version: Simple Phone Dialer

It is posted below the simplest java version. For more details, access the links above.

Below is shown the Manifest with the intent-filter needed.

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.aliton.customphonecall">

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

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <activity
            android:name=".DialerActivity" >
            <intent-filter>

                <!-- Handle links from other applications -->
                <action android:name="android.intent.action.VIEW" />
                <action android:name="android.intent.action.DIAL" />
                <!-- Populate the system chooser -->
                <category android:name="android.intent.category.DEFAULT" />
                <!-- Handle links in browsers -->
                <category android:name="android.intent.category.BROWSABLE" />

                <data android:scheme="tel" />
            </intent-filter>
            <intent-filter>
                <action android:name="android.intent.action.DIAL" />

                <category android:name="android.intent.category.DEFAULT" />
            </intent-filter>
        </activity>

        <service
            android:name=".CallService"
            android:permission="android.permission.BIND_INCALL_SERVICE">
            <meta-data
                android:name="android.telecom.IN_CALL_SERVICE_UI"
                android:value="true" />

            <intent-filter>
                <action android:name="android.telecom.InCallService" />
            </intent-filter>
        </service>

        <activity android:name=".CallActivity"></activity>
    </application>

</manifest>

The MainActivity just have a Button with an Intent redirecting to the DialerActivity.

Below is the DialerActivity. In this Activity, you will set your app as default in order to make call with your UI.

public class DialerActivity extends AppCompatActivity {

    private static final int REQUEST_CALL_PHONE = 10;

    EditText phoneNumber;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_dialer);

        phoneNumber = (EditText) findViewById(R.id.etNumber);
        Button bCall = (Button) findViewById(R.id.btnCall);

        offerReplacingDefaultDialer();

        bCall.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                makeCall();
            }
        });
    }

    private void makeCall() {
        if (ActivityCompat.checkSelfPermission(this, Manifest.permission.CALL_PHONE) == PackageManager.PERMISSION_GRANTED) {
            Uri uri = Uri.parse("tel:"+phoneNumber.getText().toString().trim());
            Intent Call = new Intent(Intent.ACTION_CALL, uri);
            //Toast.makeText(this, "Entered makeCall()", Toast.LENGTH_SHORT).show();
            Log.i("debinf Dialer", "Entered makeCall()");
            startActivity(Call);

        } else {
            ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.CALL_PHONE}, REQUEST_CALL_PHONE);
        }
    }

    private void offerReplacingDefaultDialer() {
        if (getSystemService(TelecomManager.class).getDefaultDialerPackage() != getPackageName()) {
            Intent ChangeDialer = new Intent(TelecomManager.ACTION_CHANGE_DEFAULT_DIALER);
            ChangeDialer.putExtra(TelecomManager.EXTRA_CHANGE_DEFAULT_DIALER_PACKAGE_NAME, getPackageName());
            startActivity(ChangeDialer);
        }

    }

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);

        if (requestCode == REQUEST_CALL_PHONE) {
            if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                makeCall();
            } else {
                Toast.makeText(this, "calling permission denied", Toast.LENGTH_LONG).show();
            }
            //return;
        }
    }

}

Here is how InCallService is implemented to manage the calls.

public class CallService extends InCallService {

    OngoingCallObject ongoingCallObject;

    @Override
    public void onCallAdded(Call call) {
        super.onCallAdded(call);
        new OngoingCallObject().setCall(call);

        //Intent CallAct = new Intent(this, CallActivity.class);
        //startActivity(CallAct);

        CallActivity.start(this, call);
    }

    @Override
    public void onCallRemoved(Call call) {
        super.onCallRemoved(call);
        new OngoingCallObject().setCall(null);
    }

}

Here is how the Object is implemented.

public class OngoingCallObject {

    private static Call call;

    private Object callback = new Callback() {
        @Override
        public void onStateChanged(Call call, int state) {
            super.onStateChanged(call, state);
            Log.i("debinf OngoingObj", "state is "+state);
        }
    };

    public void setCall(Call call) {
        if (this.call != null) {
            this.call.unregisterCallback((Call.Callback)callback);
        }

        if (call != null) {
            call.registerCallback((Call.Callback)callback);
            Log.i("debinf OngoingObj", "call.getState() is "+call.getState());
        }

        this.call = call;
    }

    public void answer() {
        //assert this.call != null;
        if (this.call != null) {
            this.call.answer(VideoProfile.STATE_AUDIO_ONLY);
        }
    }

    public void hangup() {
        //assert this.call != null;
        if (this.call != null) {
            this.call.disconnect();
        }
    }
}

And finally, the CallActivity where you launch your UI.

public class CallActivity extends AppCompatActivity {

    TextView callInfo;
    Button answer, hangup;

    private String number;
    private OngoingCallObject ongoingCall;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_call);

        ongoingCall = new OngoingCallObject();

        answer = (Button) findViewById(R.id.answer);
        hangup = (Button) findViewById(R.id.hangup);
        callInfo = (TextView) findViewById(R.id.callInfo);

        number = Objects.requireNonNull(getIntent().getData().getSchemeSpecificPart());

        callInfo.setText("Calling number : "+number);

        answer.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                //Toast.makeText(CallActivity.this, "Answer button", Toast.LENGTH_SHORT).show();
                ongoingCall.answer();
            }
        });

        hangup.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                ongoingCall.hangup();
            }
        });


    }

    public static void start(Context context, Call call) {
        Intent intent = new Intent(context, CallActivity.class);
        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        intent.setData(call.getDetails().getHandle());
        context.startActivity(intent);
    }

}

Here is the xml for DialerActivity: activity_dialer.xml

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".DialerActivity">

    <EditText
        android:id="@+id/etNumber"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="Tel number"/>

    <Button
        android:id="@+id/btnCall"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="8dp"
        android:text="CallActivity"
        android:layout_below="@+id/etNumber" />

</RelativeLayout>

Here is the xml for CallActivity: activity_call.xml

<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".CallActivity">

    <TextView
        android:id="@+id/callInfo"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:gravity="center"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintVertical_bias="0.3"
        tools:text="Hello World!" />

    <Button
        android:id="@+id/answer"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Answer"
        app:layout_constraintBaseline_toBaselineOf="@+id/hangup"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toEndOf="@+id/hangup" />

    <Button
        android:id="@+id/hangup"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Hang up"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toStartOf="@+id/answer"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/callInfo" />


</android.support.constraint.ConstraintLayout>

I hope it helps!

like image 36
Aliton Oliveira Avatar answered Nov 15 '22 18:11

Aliton Oliveira