• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2013 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 
17 package android.telecom;
18 
19 import android.annotation.SystemApi;
20 import android.annotation.UnsupportedAppUsage;
21 import android.bluetooth.BluetoothDevice;
22 import android.os.Build;
23 import android.os.Bundle;
24 import android.os.RemoteException;
25 import android.util.ArrayMap;
26 
27 import java.util.Collections;
28 import java.util.List;
29 import java.util.Map;
30 import java.util.Objects;
31 import java.util.concurrent.CopyOnWriteArrayList;
32 
33 /**
34  * A unified virtual device providing a means of voice (and other) communication on a device.
35  *
36  * @hide
37  * @deprecated Use {@link InCallService} directly instead of using this class.
38  */
39 @SystemApi
40 @Deprecated
41 public final class Phone {
42 
43     public abstract static class Listener {
44         /**
45          * Called when the audio state changes.
46          *
47          * @param phone The {@code Phone} calling this method.
48          * @param audioState The new {@link AudioState}.
49          *
50          * @deprecated Use {@link #onCallAudioStateChanged(Phone, CallAudioState)} instead.
51          */
52         @Deprecated
onAudioStateChanged(Phone phone, AudioState audioState)53         public void onAudioStateChanged(Phone phone, AudioState audioState) { }
54 
55         /**
56          * Called when the audio state changes.
57          *
58          * @param phone The {@code Phone} calling this method.
59          * @param callAudioState The new {@link CallAudioState}.
60          */
onCallAudioStateChanged(Phone phone, CallAudioState callAudioState)61         public void onCallAudioStateChanged(Phone phone, CallAudioState callAudioState) { }
62 
63         /**
64          * Called to bring the in-call screen to the foreground. The in-call experience should
65          * respond immediately by coming to the foreground to inform the user of the state of
66          * ongoing {@code Call}s.
67          *
68          * @param phone The {@code Phone} calling this method.
69          * @param showDialpad If true, put up the dialpad when the screen is shown.
70          */
onBringToForeground(Phone phone, boolean showDialpad)71         public void onBringToForeground(Phone phone, boolean showDialpad) { }
72 
73         /**
74          * Called when a {@code Call} has been added to this in-call session. The in-call user
75          * experience should add necessary state listeners to the specified {@code Call} and
76          * immediately start to show the user information about the existence
77          * and nature of this {@code Call}. Subsequent invocations of {@link #getCalls()} will
78          * include this {@code Call}.
79          *
80          * @param phone The {@code Phone} calling this method.
81          * @param call A newly added {@code Call}.
82          */
onCallAdded(Phone phone, Call call)83         public void onCallAdded(Phone phone, Call call) { }
84 
85         /**
86          * Called when a {@code Call} has been removed from this in-call session. The in-call user
87          * experience should remove any state listeners from the specified {@code Call} and
88          * immediately stop displaying any information about this {@code Call}.
89          * Subsequent invocations of {@link #getCalls()} will no longer include this {@code Call}.
90          *
91          * @param phone The {@code Phone} calling this method.
92          * @param call A newly removed {@code Call}.
93          */
onCallRemoved(Phone phone, Call call)94         public void onCallRemoved(Phone phone, Call call) { }
95 
96         /**
97          * Called when the {@code Phone} ability to add more calls changes.  If the phone cannot
98          * support more calls then {@code canAddCall} is set to {@code false}.  If it can, then it
99          * is set to {@code true}.
100          *
101          * @param phone The {@code Phone} calling this method.
102          * @param canAddCall Indicates whether an additional call can be added.
103          */
onCanAddCallChanged(Phone phone, boolean canAddCall)104         public void onCanAddCallChanged(Phone phone, boolean canAddCall) { }
105 
106         /**
107          * Called to silence the ringer if a ringing call exists.
108          *
109          * @param phone The {@code Phone} calling this method.
110          */
onSilenceRinger(Phone phone)111         public void onSilenceRinger(Phone phone) { }
112     }
113 
114     // A Map allows us to track each Call by its Telecom-specified call ID
115     private final Map<String, Call> mCallByTelecomCallId = new ArrayMap<>();
116 
117     // A List allows us to keep the Calls in a stable iteration order so that casually developed
118     // user interface components do not incur any spurious jank
119     private final List<Call> mCalls = new CopyOnWriteArrayList<>();
120 
121     // An unmodifiable view of the above List can be safely shared with subclass implementations
122     private final List<Call> mUnmodifiableCalls = Collections.unmodifiableList(mCalls);
123 
124     private final InCallAdapter mInCallAdapter;
125 
126     private CallAudioState mCallAudioState;
127 
128     private final List<Listener> mListeners = new CopyOnWriteArrayList<>();
129 
130     private boolean mCanAddCall = true;
131 
132     private final String mCallingPackage;
133 
134     /**
135      * The Target SDK version of the InCallService implementation.
136      */
137     private final int mTargetSdkVersion;
138 
Phone(InCallAdapter adapter, String callingPackage, int targetSdkVersion)139     Phone(InCallAdapter adapter, String callingPackage, int targetSdkVersion) {
140         mInCallAdapter = adapter;
141         mCallingPackage = callingPackage;
142         mTargetSdkVersion = targetSdkVersion;
143     }
144 
internalAddCall(ParcelableCall parcelableCall)145     final void internalAddCall(ParcelableCall parcelableCall) {
146         Call call = new Call(this, parcelableCall.getId(), mInCallAdapter,
147                 parcelableCall.getState(), mCallingPackage, mTargetSdkVersion);
148         mCallByTelecomCallId.put(parcelableCall.getId(), call);
149         mCalls.add(call);
150         checkCallTree(parcelableCall);
151         call.internalUpdate(parcelableCall, mCallByTelecomCallId);
152         fireCallAdded(call);
153      }
154 
internalRemoveCall(Call call)155     final void internalRemoveCall(Call call) {
156         mCallByTelecomCallId.remove(call.internalGetCallId());
157         mCalls.remove(call);
158 
159         InCallService.VideoCall videoCall = call.getVideoCall();
160         if (videoCall != null) {
161             videoCall.destroy();
162         }
163         fireCallRemoved(call);
164     }
165 
internalUpdateCall(ParcelableCall parcelableCall)166     final void internalUpdateCall(ParcelableCall parcelableCall) {
167          Call call = mCallByTelecomCallId.get(parcelableCall.getId());
168          if (call != null) {
169              checkCallTree(parcelableCall);
170              call.internalUpdate(parcelableCall, mCallByTelecomCallId);
171          }
172      }
173 
internalSetPostDialWait(String telecomId, String remaining)174     final void internalSetPostDialWait(String telecomId, String remaining) {
175         Call call = mCallByTelecomCallId.get(telecomId);
176         if (call != null) {
177             call.internalSetPostDialWait(remaining);
178         }
179     }
180 
internalCallAudioStateChanged(CallAudioState callAudioState)181     final void internalCallAudioStateChanged(CallAudioState callAudioState) {
182         if (!Objects.equals(mCallAudioState, callAudioState)) {
183             mCallAudioState = callAudioState;
184             fireCallAudioStateChanged(callAudioState);
185         }
186     }
187 
internalGetCallByTelecomId(String telecomId)188     final Call internalGetCallByTelecomId(String telecomId) {
189         return mCallByTelecomCallId.get(telecomId);
190     }
191 
internalBringToForeground(boolean showDialpad)192     final void internalBringToForeground(boolean showDialpad) {
193         fireBringToForeground(showDialpad);
194     }
195 
internalSetCanAddCall(boolean canAddCall)196     final void internalSetCanAddCall(boolean canAddCall) {
197         if (mCanAddCall != canAddCall) {
198             mCanAddCall = canAddCall;
199             fireCanAddCallChanged(canAddCall);
200         }
201     }
202 
internalSilenceRinger()203     final void internalSilenceRinger() {
204         fireSilenceRinger();
205     }
206 
internalOnConnectionEvent(String telecomId, String event, Bundle extras)207     final void internalOnConnectionEvent(String telecomId, String event, Bundle extras) {
208         Call call = mCallByTelecomCallId.get(telecomId);
209         if (call != null) {
210             call.internalOnConnectionEvent(event, extras);
211         }
212     }
213 
internalOnRttUpgradeRequest(String callId, int requestId)214     final void internalOnRttUpgradeRequest(String callId, int requestId) {
215         Call call = mCallByTelecomCallId.get(callId);
216         if (call != null) {
217             call.internalOnRttUpgradeRequest(requestId);
218         }
219     }
220 
internalOnRttInitiationFailure(String callId, int reason)221     final void internalOnRttInitiationFailure(String callId, int reason) {
222         Call call = mCallByTelecomCallId.get(callId);
223         if (call != null) {
224             call.internalOnRttInitiationFailure(reason);
225         }
226     }
227 
internalOnHandoverFailed(String callId, int error)228     final void internalOnHandoverFailed(String callId, int error) {
229         Call call = mCallByTelecomCallId.get(callId);
230         if (call != null) {
231             call.internalOnHandoverFailed(error);
232         }
233     }
234 
internalOnHandoverComplete(String callId)235     final void internalOnHandoverComplete(String callId) {
236         Call call = mCallByTelecomCallId.get(callId);
237         if (call != null) {
238             call.internalOnHandoverComplete();
239         }
240     }
241 
242     /**
243      * Called to destroy the phone and cleanup any lingering calls.
244      */
destroy()245     final void destroy() {
246         for (Call call : mCalls) {
247             InCallService.VideoCall videoCall = call.getVideoCall();
248             if (videoCall != null) {
249                 videoCall.destroy();
250             }
251             if (call.getState() != Call.STATE_DISCONNECTED) {
252                 call.internalSetDisconnected();
253             }
254         }
255     }
256 
257     /**
258      * Adds a listener to this {@code Phone}.
259      *
260      * @param listener A {@code Listener} object.
261      */
addListener(Listener listener)262     public final void addListener(Listener listener) {
263         mListeners.add(listener);
264     }
265 
266     /**
267      * Removes a listener from this {@code Phone}.
268      *
269      * @param listener A {@code Listener} object.
270      */
removeListener(Listener listener)271     public final void removeListener(Listener listener) {
272         if (listener != null) {
273             mListeners.remove(listener);
274         }
275     }
276 
277     /**
278      * Obtains the current list of {@code Call}s to be displayed by this in-call experience.
279      *
280      * @return A list of the relevant {@code Call}s.
281      */
getCalls()282     public final List<Call> getCalls() {
283         return mUnmodifiableCalls;
284     }
285 
286     /**
287      * Returns if the {@code Phone} can support additional calls.
288      *
289      * @return Whether the phone supports adding more calls.
290      */
canAddCall()291     public final boolean canAddCall() {
292         return mCanAddCall;
293     }
294 
295     /**
296      * Sets the microphone mute state. When this request is honored, there will be change to
297      * the {@link #getAudioState()}.
298      *
299      * @param state {@code true} if the microphone should be muted; {@code false} otherwise.
300      */
setMuted(boolean state)301     public final void setMuted(boolean state) {
302         mInCallAdapter.mute(state);
303     }
304 
305     /**
306      * Sets the audio route (speaker, bluetooth, etc...).  When this request is honored, there will
307      * be change to the {@link #getAudioState()}.
308      *
309      * @param route The audio route to use.
310      */
setAudioRoute(int route)311     public final void setAudioRoute(int route) {
312         mInCallAdapter.setAudioRoute(route);
313     }
314 
315     /**
316      * Request audio routing to a specific bluetooth device. Calling this method may result in
317      * the device routing audio to a different bluetooth device than the one specified. A list of
318      * available devices can be obtained via {@link CallAudioState#getSupportedBluetoothDevices()}
319      *
320      * @param bluetoothAddress The address of the bluetooth device to connect to, as returned by
321      * {@link BluetoothDevice#getAddress()}, or {@code null} if no device is preferred.
322      */
requestBluetoothAudio(String bluetoothAddress)323     public void requestBluetoothAudio(String bluetoothAddress) {
324         mInCallAdapter.requestBluetoothAudio(bluetoothAddress);
325     }
326 
327     /**
328      * Turns the proximity sensor on. When this request is made, the proximity sensor will
329      * become active, and the touch screen and display will be turned off when the user's face
330      * is detected to be in close proximity to the screen. This operation is a no-op on devices
331      * that do not have a proximity sensor.
332      * <p>
333      * This API does not actually turn on the proximity sensor; apps should do this on their own if
334      * required.
335      * @hide
336      */
337     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 127403196)
setProximitySensorOn()338     public final void setProximitySensorOn() {
339         mInCallAdapter.turnProximitySensorOn();
340     }
341 
342     /**
343      * Turns the proximity sensor off. When this request is made, the proximity sensor will
344      * become inactive, and no longer affect the touch screen and display. This operation is a
345      * no-op on devices that do not have a proximity sensor.
346      *
347      * @param screenOnImmediately If true, the screen will be turned on immediately if it was
348      * previously off. Otherwise, the screen will only be turned on after the proximity sensor
349      * is no longer triggered.
350      * <p>
351      * This API does not actually turn of the proximity sensor; apps should do this on their own if
352      * required.
353      * @hide
354      */
355     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 127403196)
setProximitySensorOff(boolean screenOnImmediately)356     public final void setProximitySensorOff(boolean screenOnImmediately) {
357         mInCallAdapter.turnProximitySensorOff(screenOnImmediately);
358     }
359 
360     /**
361      * Obtains the current phone call audio state of the {@code Phone}.
362      *
363      * @return An object encapsulating the audio state.
364      * @deprecated Use {@link #getCallAudioState()} instead.
365      */
366     @Deprecated
getAudioState()367     public final AudioState getAudioState() {
368         return new AudioState(mCallAudioState);
369     }
370 
371     /**
372      * Obtains the current phone call audio state of the {@code Phone}.
373      *
374      * @return An object encapsulating the audio state.
375      */
getCallAudioState()376     public final CallAudioState getCallAudioState() {
377         return mCallAudioState;
378     }
379 
fireCallAdded(Call call)380     private void fireCallAdded(Call call) {
381         for (Listener listener : mListeners) {
382             listener.onCallAdded(this, call);
383         }
384     }
385 
fireCallRemoved(Call call)386     private void fireCallRemoved(Call call) {
387         for (Listener listener : mListeners) {
388             listener.onCallRemoved(this, call);
389         }
390     }
391 
fireCallAudioStateChanged(CallAudioState audioState)392     private void fireCallAudioStateChanged(CallAudioState audioState) {
393         for (Listener listener : mListeners) {
394             listener.onCallAudioStateChanged(this, audioState);
395             listener.onAudioStateChanged(this, new AudioState(audioState));
396         }
397     }
398 
fireBringToForeground(boolean showDialpad)399     private void fireBringToForeground(boolean showDialpad) {
400         for (Listener listener : mListeners) {
401             listener.onBringToForeground(this, showDialpad);
402         }
403     }
404 
fireCanAddCallChanged(boolean canAddCall)405     private void fireCanAddCallChanged(boolean canAddCall) {
406         for (Listener listener : mListeners) {
407             listener.onCanAddCallChanged(this, canAddCall);
408         }
409     }
410 
fireSilenceRinger()411     private void fireSilenceRinger() {
412         for (Listener listener : mListeners) {
413             listener.onSilenceRinger(this);
414         }
415     }
416 
checkCallTree(ParcelableCall parcelableCall)417     private void checkCallTree(ParcelableCall parcelableCall) {
418         if (parcelableCall.getChildCallIds() != null) {
419             for (int i = 0; i < parcelableCall.getChildCallIds().size(); i++) {
420                 if (!mCallByTelecomCallId.containsKey(parcelableCall.getChildCallIds().get(i))) {
421                     Log.wtf(this, "ParcelableCall %s has nonexistent child %s",
422                             parcelableCall.getId(), parcelableCall.getChildCallIds().get(i));
423                 }
424             }
425         }
426     }
427 }
428