替换默认手机APP

时间:2018-01-08 15:40:59

标签: android android-manifest

我试图更换默认的Android手机通话应用。更具体地说,我希望每次执行呼叫操作时都启动我的自定义电话呼叫屏幕。

我知道这可能是因为Android的API 24(版本7.0 - Nougat),但我没有找到关于如何实现这一点的参考。为了清楚起见,我不想显示呼叫屏幕的叠加布局。我想将我的通话应用设置为默认值。

我在这里找到了一个类似的短信应用问题:Stackoverflow - replace default sms app。答案清楚地表明,您需要列出sms应用程序的所有组件,以便能够将其设置为android设置中的默认应用程序。但我无法找到任何有关电话组件的参考资料。

我怎样才能做到这一点?

作为参考,这是我的清单文件:

<?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>

3 个答案:

答案 0 :(得分:2)

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

在清单中设置此内容。

答案 1 :(得分:2)

我搜索了整个谷歌,最后找到了解决方案。现在我可以用自定义创建的应用程序替换默认电话(呼叫)应用程序 如果您在清单文件中添加这些权限,则可以将您的应用更改为默认呼叫应用 - &gt;电话菜单 - &gt;设置 - &gt;应用 - &gt;默认应用(右上角的菜单项) - &gt;默认调用应用程序,最后选择您的应用程序。

这是权限列表

<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" />

答案 2 :(得分:0)

因为有API 23的可能,请参见Replacing default Phone app on Android 6 and 7 with InCallService arekolek

科特琳版本:Simple Phone

Java版本:Simple Phone Dialer

它发布在最简单的Java版本下面。有关更多详细信息,请访问上面的链接。

下面显示的是清单和所需的intent-filter

<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>

MainActivity 仅有一个Button,其中一个Intent重定向到DialerActivity

下面是DialerActivity。在本活动中,您将把应用程序设置为默认应用程序,以便使用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;
        }
    }

}

这里是实现InCallService来管理呼叫的方式。

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);
    }

}

这里是对象的实现方式。

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();
        }
    }
}

最后,在CallActivity中启动用户界面。

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);
    }

}

以下是DialerActivity xml 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>

以下是CallActivity xml 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>

希望对您有帮助!