[Android]InCallService详解

官网地址
注:本文写作时,安卓发布的最新版本为Android 10 (Q)
正文:

  1. 这个接口在Android 6.0之后添加,就是说如果是使用这个接口,应用支持的最低版本api为23
  2. 根据官网介绍,这个类的作用只有一个:替换默认通话应用
  3. 使用RoleManager这个类来实现替换默认通话应用(Android 8.0以上)
  4. 应用要在通话状态时提供UI界面(驾驶模式除外)
  5. 应用必须满足以下条件:
    1. 必须接受Intent#ACTION_DIALIntent,就是说,应用必须提供拨号盘界面以便拨打电话
    2. 必须继承实现InCallService,并且同时提供接电话和通话中的UI

注意:如果应用成为了默认的通话应用,然后在通话过程中崩溃了(crash),系统会自动切换上一个默认通话应用,同时会通知用户你的应用崩溃了。然后从此以后系统会使用上一个默认通话应用来拨打紧急电话

如何替换?

1、如何接受Intent#ACTION_DIAL的Intent

创建一个Activity接受Intent

<activity android:name="your.package.YourDialerActivity"
           android:label="@string/yourDialerActivityLabel">
      <intent-filter>
           <action android:name="android.intent.action.DIAL" />
           <category android:name="android.intent.category.DEFAULT" />
      </intent-filter>
      <intent-filter>
           <action android:name="android.intent.action.DIAL" />
           <category android:name="android.intent.category.DEFAULT" />
           <data android:scheme="tel" />
      </intent-filter>
 </activity>
2、如何继承InCallService

创建一个Service继承它

class
public class MyService extends InCallService{}  

/********************************************************************************/
Manifest.xml
<service android:name="your.package.YourInCallServiceImplementation"
       android:permission="android.permission.BIND_INCALL_SERVICE">
      <meta-data android:name="android.telecom.IN_CALL_SERVICE_UI" android:value="true" />
      <meta-data android:name="android.telecom.IN_CALL_SERVICE_RINGING"
          android:value="true" />
      <intent-filter>
          <action android:name="android.telecom.InCallService"/>
      </intent-filter>
 </service>

android.telecom.IN_CALL_SERVICE_UI:表明会替换内置的默认UI(测试发现,如果设置为false,这不会调用自己的Service)
android.telecom.IN_CALL_SERVICE_RINGING:表明来电时会播放铃声(经测试,若设置为false,会调用自己的Service,会调用系统播放铃声的功能)

3、如何使用RoleManager
 private static final int REQUEST_ID = 1;

 public void requestRole() {
     RoleManager roleManager = (RoleManager) getSystemService(ROLE_SERVICE);
     Intent intent = roleManager.createRequestRoleIntent(RoleManager.ROLE_DIALER);
     startActivityForResult(intent, REQUEST_ID);
 }

 @Override
 public void onActivityResult(int requestCode, int resultCode, Intent data) {
     if (requestCode == REQUEST_ID) {
         if (resultCode == android.app.Activity.RESULT_OK) {
             // Your app is now the default dialer app
         } else {
             // Your app is not the default dialer app
         }
     }
 }

上面的代码会弹出一个Dialog询问用户是否替换


替换后要怎么做

来电时
  1. 通过InCallSevice#onCallAdded(Call)接收来电时,你需要展示来电的UI——通过NotificationManager接口展示一个来电通知

  2. 如果你的应用声明了android.telecom.IN_CALL_SERVICE_RINGING,来电时你还要播放铃声,通过创建一个NotificationChannel来指定播放的铃声,例如:

NotificationChannel channel = new NotificationChannel(YOUR_CHANNEL_ID, "Incoming Calls",
          NotificationManager.IMPORTANCE_MAX);
 // other channel setup stuff goes here.

 // We'll use the default system ringtone for our incoming call notification channel.  You can
 // use your own audio resource here.
 Uri ringtoneUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_RINGTONE);
 channel.setSound(ringtoneUri, new AudioAttributes.Builder()
          // Setting the AudioAttributes is important as it identifies the purpose of your
          // notification sound.
          .setUsage(AudioAttributes.USAGE_NOTIFICATION_RINGTONE)
          .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
      .build());

 NotificationManager mgr = getSystemService(NotificationManager.class);
 mgr.createNotificationChannel(channel);

来电时,创建一个通知,并且把它和你创建的通知渠道关联起来

  1. 您可以在通知上指定一个PendingContent,该通知将启动你提供的全屏来电UI,例如:
// Create an intent which triggers your fullscreen incoming call user interface.
 Intent intent = new Intent(Intent.ACTION_MAIN, null);
 intent.setFlags(Intent.FLAG_ACTIVITY_NO_USER_ACTION | Intent.FLAG_ACTIVITY_NEW_TASK);
 intent.setClass(context, YourIncomingCallActivity.class);
 PendingIntent pendingIntent = PendingIntent.getActivity(context, 1, intent, 0);

 // Build the notification as an ongoing high priority item; this ensures it will show as
 // a heads up notification which slides down over top of the current content.
 final Notification.Builder builder = new Notification.Builder(context);
 builder.setOngoing(true);
 builder.setPriority(Notification.PRIORITY_HIGH);

 // Set notification content intent to take user to the fullscreen UI if user taps on the
 // notification body.
 builder.setContentIntent(pendingIntent);
 // Set full screen intent to trigger display of the fullscreen UI when the notification
 // manager deems it appropriate.
 builder.setFullScreenIntent(pendingIntent, true);

 // Setup notification content.
 builder.setSmallIcon( yourIconResourceId );
 builder.setContentTitle("Your notification title");
 builder.setContentText("Your notification content.");

 // Use builder.addAction(..) to add buttons to answer or reject the call.

 NotificationManager notificationManager = mContext.getSystemService(
     NotificationManager.class);
 notificationManager.notify(YOUR_CHANNEL_ID, YOUR_TAG, YOUR_ID, builder.build());
  1. 如果用户正在使用手机,系统会展示一个通知,如果用户没有在使用手机,系统会展示你提供的全屏来电UI

官网就这么多,更多的大家自己挖掘吧