更换默认手机APP

Posted

技术标签:

【中文标题】更换默认手机APP【英文标题】:Replace default phone APP 【发布时间】:2018-06-17 14:55:39 【问题描述】:

我正在尝试替换默认的 android 电话应用程序。更具体地说,我想在每次执行呼叫操作时启动我的自定义电话呼叫屏幕。

我知道这是可能的,因为 Android 的 API 24(版本 7.0 - Nougat)但我没有找到关于如何实现这一点的参考资料。需要明确的是,我不想显示呼叫屏幕的覆盖布局。我想将我的通话应用设置为默认应用。

我在这里找到了关于短信应用的类似问题:*** - 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>

【问题讨论】:

你知道我的应用程序是否是默认呼叫应用程序,我想从我的默认应用程序将来电切换到系统默认应用程序,请问你知道吗? 【参考方案1】:

由于 API 23 是可能的,请参阅 Replacing default Phone app on Android 6 and 7 with InCallService arekolek

Kotlin 版本:Simple Phone

Java 版本:Simple Phone Dialer

下面贴出最简单的java版本。有关更多详细信息,请访问上面的链接。

下面显示了 Manifest,其中需要 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。在此 Activity 中,您将应用设置为默认应用,以便使用您的 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 是您启动 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);
    


这是DialerActivityxmlactivity_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_
    android:layout_
    tools:context=".DialerActivity">

    <EditText
        android:id="@+id/etNumber"
        android:layout_
        android:layout_
        android:hint="Tel number"/>

    <Button
        android:id="@+id/btnCall"
        android:layout_
        android:layout_
        android:layout_marginTop="8dp"
        android:text="CallActivity"
        android:layout_below="@+id/etNumber" />

</RelativeLayout>

这是CallActivityxmlactivity_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_
    android:layout_
    tools:context=".CallActivity">

    <TextView
        android:id="@+id/callInfo"
        android:layout_
        android:layout_
        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_
        android:layout_
        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_
        android:layout_
        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>

希望对你有帮助!

【讨论】:

我认为从 API 29 (Q) 开始,您应该使用 (RoleManager) context.getSystemService(Context.ROLE_SERVICE).createRequestRoleIntent(RoleManager.ROLE_DIALER) 来请求成为默认手机应用的 Intent。可能需要更多的改变。不确定。【参考方案2】:

我在google上搜遍了,终于找到了解决办法。现在我可以用我自定义的应用程序替换默认的电话(通话)应用程序 如果您在清单文件中添加这些权限,您将能够将您的应用程序更改为默认呼叫应用程序 -> 电话菜单 -> 设置 -> 应用程序 -> 默认应用程序(右上角的菜单项) -> 默认呼叫应用程序,最后选择您的应用。

这里是权限列表

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

【讨论】:

Rob 添加了您上面列出的所有权限,但仍然无法在默认手机应用列表下看到我的应用。请指导。 ***.com/questions/42838222/… 很好地引导它现在在电话应用列表中可见。【参考方案3】:
<intent-filter>
    <action android:name="android.intent.action.DIAL" />
    <category android:name="android.intent.category.DEFAULT" />
</intent-filter>

在你的清单中设置它。

【讨论】:

BHARADWAJ,您是否有示例工作代码,可以打开拨号器其余代码,我将从文档中自行开发。

以上是关于更换默认手机APP的主要内容,如果未能解决你的问题,请参考以下文章

手机浏览器ip代理设置在哪

苹果手机QQ空间怎么上传照片?

苹果手机怎么上传照片到qq空间

怎么换苹果app图标

苹果手机下载东西,老是显示无法下载app。。请问这是怎么回事

exchange更换证书以后手机邮箱无法登陆