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