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<CallAudioStateCallback> mCallAudioStateCallbacks = 41 new CopyOnWriteArrayList<>(); 42 43 private InCallRouter mInCallRouter; 44 45 /** Listens to active call list changes. Callbacks will be called on main thread. */ 46 public interface ActiveCallListChangedCallback { 47 48 /** 49 * Called when a new call is added. 50 * 51 * @return if the given call has been handled by this callback. 52 */ onTelecomCallAdded(Call telecomCall)53 boolean onTelecomCallAdded(Call telecomCall); 54 55 /** 56 * Called when an existing call is removed. 57 * 58 * @return if the given call has been handled by this callback. 59 */ onTelecomCallRemoved(Call telecomCall)60 boolean onTelecomCallRemoved(Call telecomCall); 61 } 62 63 /** Listens to call audio state changes. Callbacks will be called on the main thread. */ 64 public interface CallAudioStateCallback { 65 /** 66 * Called when the call audio state has changed. 67 */ onCallAudioStateChanged(CallAudioState callAudioState)68 void onCallAudioStateChanged(CallAudioState callAudioState); 69 } 70 71 @Override onCreate()72 public void onCreate() { 73 super.onCreate(); 74 mInCallRouter = new InCallRouter(getApplicationContext()); 75 mInCallRouter.start(); 76 } 77 78 @Override onDestroy()79 public void onDestroy() { 80 super.onDestroy(); 81 mInCallRouter.stop(); 82 mInCallRouter = null; 83 } 84 85 @Override onCallAdded(Call telecomCall)86 public void onCallAdded(Call telecomCall) { 87 L.d(TAG, "onCallAdded: %s", telecomCall); 88 mInCallRouter.onCallAdded(telecomCall); 89 } 90 91 @Override onCallRemoved(Call telecomCall)92 public void onCallRemoved(Call telecomCall) { 93 L.d(TAG, "onCallRemoved: %s", telecomCall); 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 (CallAudioStateCallback callback : mCallAudioStateCallbacks) { 117 callback.onCallAudioStateChanged(audioState); 118 } 119 } 120 121 @Override onBringToForeground(boolean showDialpad)122 public void onBringToForeground(boolean showDialpad) { 123 L.d(TAG, "onBringToForeground: %s", showDialpad); 124 mInCallRouter.routeToInCallPage(showDialpad); 125 } 126 addCallAudioStateChangedCallback(CallAudioStateCallback callback)127 public void addCallAudioStateChangedCallback(CallAudioStateCallback callback) { 128 mCallAudioStateCallbacks.add(callback); 129 } 130 removeCallAudioStateChangedCallback(CallAudioStateCallback callback)131 public void removeCallAudioStateChangedCallback(CallAudioStateCallback callback) { 132 mCallAudioStateCallbacks.remove(callback); 133 } 134 addActiveCallListChangedCallback(ActiveCallListChangedCallback callback)135 public void addActiveCallListChangedCallback(ActiveCallListChangedCallback callback) { 136 mInCallRouter.registerActiveCallListChangedCallback(callback); 137 } 138 removeActiveCallListChangedCallback(ActiveCallListChangedCallback callback)139 public void removeActiveCallListChangedCallback(ActiveCallListChangedCallback callback) { 140 mInCallRouter.unregisterActiveCallHandler(callback); 141 } 142 143 /** 144 * Local binder only available for Car Dialer package. 145 */ 146 public class LocalBinder extends Binder { 147 148 /** 149 * Returns a reference to {@link InCallServiceImpl}. Any process other than Dialer 150 * process won't be able to get a reference. 151 */ getService()152 public InCallServiceImpl getService() { 153 if (getCallingPid() == Process.myPid()) { 154 return InCallServiceImpl.this; 155 } 156 return null; 157 } 158 } 159 } 160