1 /* 2 * Copyright (C) 2015 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 package com.android.car.dialer.telecom; 17 18 import android.content.Intent; 19 import android.os.Binder; 20 import android.os.IBinder; 21 import android.os.Process; 22 import android.telecom.Call; 23 import android.telecom.CallAudioState; 24 import android.telecom.InCallService; 25 26 import com.android.car.dialer.log.L; 27 28 import java.util.concurrent.CopyOnWriteArrayList; 29 30 /** 31 * An implementation of {@link InCallService}. This service is bounded by android telecom and 32 * {@link UiCallManager}. For incoming calls it will launch Dialer app. 33 */ 34 public class InCallServiceImpl extends InCallService { 35 private static final String TAG = "CD.InCallService"; 36 37 /** An action which indicates a bind is from local component. */ 38 public static final String ACTION_LOCAL_BIND = "local_bind"; 39 40 private CopyOnWriteArrayList<Callback> mCallbacks = new CopyOnWriteArrayList<>(); 41 42 private InCallRouter mInCallRouter; 43 44 /** Listens to active call list changes. Callbacks will be called on main thread. */ 45 public interface ActiveCallListChangedCallback { 46 47 /** 48 * Called when a new call is added. 49 * 50 * @return if the given call has been handled by this callback. 51 */ onTelecomCallAdded(Call telecomCall)52 boolean onTelecomCallAdded(Call telecomCall); 53 54 /** 55 * Called when an existing call is removed. 56 * 57 * @return if the given call has been handled by this callback. 58 */ onTelecomCallRemoved(Call telecomCall)59 boolean onTelecomCallRemoved(Call telecomCall); 60 } 61 62 @Override onCreate()63 public void onCreate() { 64 super.onCreate(); 65 mInCallRouter = new InCallRouter(getApplicationContext()); 66 mInCallRouter.start(); 67 } 68 69 @Override onDestroy()70 public void onDestroy() { 71 super.onDestroy(); 72 mInCallRouter.stop(); 73 mInCallRouter = null; 74 } 75 76 @Override onCallAdded(Call telecomCall)77 public void onCallAdded(Call telecomCall) { 78 L.d(TAG, "onCallAdded: %s", telecomCall); 79 80 for (Callback callback : mCallbacks) { 81 callback.onTelecomCallAdded(telecomCall); 82 } 83 84 mInCallRouter.onCallAdded(telecomCall); 85 } 86 87 @Override onCallRemoved(Call telecomCall)88 public void onCallRemoved(Call telecomCall) { 89 L.d(TAG, "onCallRemoved: %s", telecomCall); 90 for (Callback callback : mCallbacks) { 91 callback.onTelecomCallRemoved(telecomCall); 92 } 93 94 mInCallRouter.onCallRemoved(telecomCall); 95 } 96 97 @Override onBind(Intent intent)98 public IBinder onBind(Intent intent) { 99 L.d(TAG, "onBind: %s", intent); 100 return ACTION_LOCAL_BIND.equals(intent.getAction()) 101 ? new LocalBinder() 102 : super.onBind(intent); 103 } 104 105 @Override onUnbind(Intent intent)106 public boolean onUnbind(Intent intent) { 107 L.d(TAG, "onUnbind, intent: %s", intent); 108 if (ACTION_LOCAL_BIND.equals(intent.getAction())) { 109 return false; 110 } 111 return super.onUnbind(intent); 112 } 113 114 @Override onCallAudioStateChanged(CallAudioState audioState)115 public void onCallAudioStateChanged(CallAudioState audioState) { 116 for (Callback callback : mCallbacks) { 117 callback.onCallAudioStateChanged(audioState); 118 } 119 } 120 registerCallback(Callback callback)121 public void registerCallback(Callback callback) { 122 mCallbacks.add(callback); 123 } 124 unregisterCallback(Callback callback)125 public void unregisterCallback(Callback callback) { 126 mCallbacks.remove(callback); 127 } 128 addActiveCallListChangedCallback(ActiveCallListChangedCallback callback)129 public void addActiveCallListChangedCallback(ActiveCallListChangedCallback callback) { 130 mInCallRouter.registerActiveCallListChangedCallback(callback); 131 } 132 removeActiveCallListChangedCallback(ActiveCallListChangedCallback callback)133 public void removeActiveCallListChangedCallback(ActiveCallListChangedCallback callback) { 134 mInCallRouter.unregisterActiveCallHandler(callback); 135 } 136 137 @Deprecated 138 interface Callback { onTelecomCallAdded(Call telecomCall)139 void onTelecomCallAdded(Call telecomCall); 140 onTelecomCallRemoved(Call telecomCall)141 void onTelecomCallRemoved(Call telecomCall); 142 onCallAudioStateChanged(CallAudioState audioState)143 void onCallAudioStateChanged(CallAudioState audioState); 144 } 145 146 /** 147 * Local binder only available for Car Dialer package. 148 */ 149 public class LocalBinder extends Binder { 150 151 /** 152 * Returns a reference to {@link InCallServiceImpl}. Any process other than Dialer 153 * process won't be able to get a reference. 154 */ getService()155 public InCallServiceImpl getService() { 156 if (getCallingPid() == Process.myPid()) { 157 return InCallServiceImpl.this; 158 } 159 return null; 160 } 161 } 162 } 163