更换默认手机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);
这是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_
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>
这是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_
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的主要内容,如果未能解决你的问题,请参考以下文章