Home | History | Annotate | Download | only in telecom
      1 /*
      2  * Copyright (C) 2014 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.net.Uri;
     20 import android.os.Bundle;
     21 import android.os.IBinder.DeathRecipient;
     22 import android.os.RemoteException;
     23 
     24 import com.android.internal.telecom.IConnectionServiceAdapter;
     25 import com.android.internal.telecom.RemoteServiceCallback;
     26 
     27 import java.util.Collections;
     28 import java.util.Iterator;
     29 import java.util.List;
     30 import java.util.Set;
     31 import java.util.concurrent.ConcurrentHashMap;
     32 
     33 /**
     34  * Provides methods for IConnectionService implementations to interact with the system phone app.
     35  *
     36  * @hide
     37  */
     38 final class ConnectionServiceAdapter implements DeathRecipient {
     39     /**
     40      * ConcurrentHashMap constructor params: 8 is initial table size, 0.9f is
     41      * load factor before resizing, 1 means we only expect a single thread to
     42      * access the map so make only a single shard
     43      */
     44     private final Set<IConnectionServiceAdapter> mAdapters = Collections.newSetFromMap(
     45             new ConcurrentHashMap<IConnectionServiceAdapter, Boolean>(8, 0.9f, 1));
     46 
     47     ConnectionServiceAdapter() {
     48     }
     49 
     50     void addAdapter(IConnectionServiceAdapter adapter) {
     51         for (IConnectionServiceAdapter it : mAdapters) {
     52             if (it.asBinder() == adapter.asBinder()) {
     53                 Log.w(this, "Ignoring duplicate adapter addition.");
     54                 return;
     55             }
     56         }
     57         if (mAdapters.add(adapter)) {
     58             try {
     59                 adapter.asBinder().linkToDeath(this, 0);
     60             } catch (RemoteException e) {
     61                 mAdapters.remove(adapter);
     62             }
     63         }
     64     }
     65 
     66     void removeAdapter(IConnectionServiceAdapter adapter) {
     67         if (adapter != null) {
     68             for (IConnectionServiceAdapter it : mAdapters) {
     69                 if (it.asBinder() == adapter.asBinder() && mAdapters.remove(it)) {
     70                     adapter.asBinder().unlinkToDeath(this, 0);
     71                     break;
     72                 }
     73             }
     74         }
     75     }
     76 
     77     /** ${inheritDoc} */
     78     @Override
     79     public void binderDied() {
     80         Iterator<IConnectionServiceAdapter> it = mAdapters.iterator();
     81         while (it.hasNext()) {
     82             IConnectionServiceAdapter adapter = it.next();
     83             if (!adapter.asBinder().isBinderAlive()) {
     84                 it.remove();
     85                 adapter.asBinder().unlinkToDeath(this, 0);
     86             }
     87         }
     88     }
     89 
     90     void handleCreateConnectionComplete(
     91             String id,
     92             ConnectionRequest request,
     93             ParcelableConnection connection) {
     94         for (IConnectionServiceAdapter adapter : mAdapters) {
     95             try {
     96                 adapter.handleCreateConnectionComplete(id, request, connection,
     97                         Log.getExternalSession());
     98             } catch (RemoteException e) {
     99             }
    100         }
    101     }
    102 
    103     /**
    104      * Sets a call's state to active (e.g., an ongoing call where two parties can actively
    105      * communicate).
    106      *
    107      * @param callId The unique ID of the call whose state is changing to active.
    108      */
    109     void setActive(String callId) {
    110         for (IConnectionServiceAdapter adapter : mAdapters) {
    111             try {
    112                 adapter.setActive(callId, Log.getExternalSession());
    113             } catch (RemoteException e) {
    114             }
    115         }
    116     }
    117 
    118     /**
    119      * Sets a call's state to ringing (e.g., an inbound ringing call).
    120      *
    121      * @param callId The unique ID of the call whose state is changing to ringing.
    122      */
    123     void setRinging(String callId) {
    124         for (IConnectionServiceAdapter adapter : mAdapters) {
    125             try {
    126                 adapter.setRinging(callId, Log.getExternalSession());
    127             } catch (RemoteException e) {
    128             }
    129         }
    130     }
    131 
    132     /**
    133      * Sets a call's state to dialing (e.g., dialing an outbound call).
    134      *
    135      * @param callId The unique ID of the call whose state is changing to dialing.
    136      */
    137     void setDialing(String callId) {
    138         for (IConnectionServiceAdapter adapter : mAdapters) {
    139             try {
    140                 adapter.setDialing(callId, Log.getExternalSession());
    141             } catch (RemoteException e) {
    142             }
    143         }
    144     }
    145 
    146     /**
    147      * Sets a call's state to pulling (e.g. a call with {@link Connection#PROPERTY_IS_EXTERNAL_CALL}
    148      * is being pulled to the local device.
    149      *
    150      * @param callId The unique ID of the call whose state is changing to dialing.
    151      */
    152     void setPulling(String callId) {
    153         for (IConnectionServiceAdapter adapter : mAdapters) {
    154             try {
    155                 adapter.setPulling(callId, Log.getExternalSession());
    156             } catch (RemoteException e) {
    157             }
    158         }
    159     }
    160 
    161     /**
    162      * Sets a call's state to disconnected.
    163      *
    164      * @param callId The unique ID of the call whose state is changing to disconnected.
    165      * @param disconnectCause The reason for the disconnection, as described by
    166      *            {@link android.telecomm.DisconnectCause}.
    167      */
    168     void setDisconnected(String callId, DisconnectCause disconnectCause) {
    169         for (IConnectionServiceAdapter adapter : mAdapters) {
    170             try {
    171                 adapter.setDisconnected(callId, disconnectCause, Log.getExternalSession());
    172             } catch (RemoteException e) {
    173             }
    174         }
    175     }
    176 
    177     /**
    178      * Sets a call's state to be on hold.
    179      *
    180      * @param callId - The unique ID of the call whose state is changing to be on hold.
    181      */
    182     void setOnHold(String callId) {
    183         for (IConnectionServiceAdapter adapter : mAdapters) {
    184             try {
    185                 adapter.setOnHold(callId, Log.getExternalSession());
    186             } catch (RemoteException e) {
    187             }
    188         }
    189     }
    190 
    191     /**
    192      * Asks Telecom to start or stop a ringback tone for a call.
    193      *
    194      * @param callId The unique ID of the call whose ringback is being changed.
    195      * @param ringback Whether Telecom should start playing a ringback tone.
    196      */
    197     void setRingbackRequested(String callId, boolean ringback) {
    198         for (IConnectionServiceAdapter adapter : mAdapters) {
    199             try {
    200                 adapter.setRingbackRequested(callId, ringback, Log.getExternalSession());
    201             } catch (RemoteException e) {
    202             }
    203         }
    204     }
    205 
    206     void setConnectionCapabilities(String callId, int capabilities) {
    207         for (IConnectionServiceAdapter adapter : mAdapters) {
    208             try {
    209                 adapter.setConnectionCapabilities(callId, capabilities, Log.getExternalSession());
    210             } catch (RemoteException ignored) {
    211             }
    212         }
    213     }
    214 
    215     void setConnectionProperties(String callId, int properties) {
    216         for (IConnectionServiceAdapter adapter : mAdapters) {
    217             try {
    218                 adapter.setConnectionProperties(callId, properties, Log.getExternalSession());
    219             } catch (RemoteException ignored) {
    220             }
    221         }
    222     }
    223 
    224     /**
    225      * Indicates whether or not the specified call is currently conferenced into the specified
    226      * conference call.
    227      *
    228      * @param callId The unique ID of the call being conferenced.
    229      * @param conferenceCallId The unique ID of the conference call. Null if call is not
    230      *            conferenced.
    231      */
    232     void setIsConferenced(String callId, String conferenceCallId) {
    233         for (IConnectionServiceAdapter adapter : mAdapters) {
    234             try {
    235                 Log.d(this, "sending connection %s with conference %s", callId, conferenceCallId);
    236                 adapter.setIsConferenced(callId, conferenceCallId, Log.getExternalSession());
    237             } catch (RemoteException ignored) {
    238             }
    239         }
    240     }
    241 
    242     /**
    243      * Indicates that the merge request on this call has failed.
    244      *
    245      * @param callId The unique ID of the call being conferenced.
    246      */
    247     void onConferenceMergeFailed(String callId) {
    248         for (IConnectionServiceAdapter adapter : mAdapters) {
    249             try {
    250                 Log.d(this, "merge failed for call %s", callId);
    251                 adapter.setConferenceMergeFailed(callId, Log.getExternalSession());
    252             } catch (RemoteException ignored) {
    253             }
    254         }
    255     }
    256 
    257     /**
    258      * Indicates that the call no longer exists. Can be used with either a call or a conference
    259      * call.
    260      *
    261      * @param callId The unique ID of the call.
    262      */
    263     void removeCall(String callId) {
    264         for (IConnectionServiceAdapter adapter : mAdapters) {
    265             try {
    266                 adapter.removeCall(callId, Log.getExternalSession());
    267             } catch (RemoteException ignored) {
    268             }
    269         }
    270     }
    271 
    272     void onPostDialWait(String callId, String remaining) {
    273         for (IConnectionServiceAdapter adapter : mAdapters) {
    274             try {
    275                 adapter.onPostDialWait(callId, remaining, Log.getExternalSession());
    276             } catch (RemoteException ignored) {
    277             }
    278         }
    279     }
    280 
    281     void onPostDialChar(String callId, char nextChar) {
    282         for (IConnectionServiceAdapter adapter : mAdapters) {
    283             try {
    284                 adapter.onPostDialChar(callId, nextChar, Log.getExternalSession());
    285             } catch (RemoteException ignored) {
    286             }
    287         }
    288     }
    289 
    290     /**
    291      * Indicates that a new conference call has been created.
    292      *
    293      * @param callId The unique ID of the conference call.
    294      */
    295     void addConferenceCall(String callId, ParcelableConference parcelableConference) {
    296         for (IConnectionServiceAdapter adapter : mAdapters) {
    297             try {
    298                 adapter.addConferenceCall(callId, parcelableConference, Log.getExternalSession());
    299             } catch (RemoteException ignored) {
    300             }
    301         }
    302     }
    303 
    304     /**
    305      * Retrieves a list of remote connection services usable to place calls.
    306      */
    307     void queryRemoteConnectionServices(RemoteServiceCallback callback) {
    308         // Only supported when there is only one adapter.
    309         if (mAdapters.size() == 1) {
    310             try {
    311                 mAdapters.iterator().next().queryRemoteConnectionServices(callback,
    312                         Log.getExternalSession());
    313             } catch (RemoteException e) {
    314                 Log.e(this, e, "Exception trying to query for remote CSs");
    315             }
    316         }
    317     }
    318 
    319     /**
    320      * Sets the call video provider for a call.
    321      *
    322      * @param callId The unique ID of the call to set with the given call video provider.
    323      * @param videoProvider The call video provider instance to set on the call.
    324      */
    325     void setVideoProvider(
    326             String callId, Connection.VideoProvider videoProvider) {
    327         for (IConnectionServiceAdapter adapter : mAdapters) {
    328             try {
    329                 adapter.setVideoProvider(
    330                         callId,
    331                         videoProvider == null ? null : videoProvider.getInterface(),
    332                         Log.getExternalSession());
    333             } catch (RemoteException e) {
    334             }
    335         }
    336     }
    337 
    338     /**
    339      * Requests that the framework use VOIP audio mode for this connection.
    340      *
    341      * @param callId The unique ID of the call to set with the given call video provider.
    342      * @param isVoip True if the audio mode is VOIP.
    343      */
    344     void setIsVoipAudioMode(String callId, boolean isVoip) {
    345         for (IConnectionServiceAdapter adapter : mAdapters) {
    346             try {
    347                 adapter.setIsVoipAudioMode(callId, isVoip, Log.getExternalSession());
    348             } catch (RemoteException e) {
    349             }
    350         }
    351     }
    352 
    353     void setStatusHints(String callId, StatusHints statusHints) {
    354         for (IConnectionServiceAdapter adapter : mAdapters) {
    355             try {
    356                 adapter.setStatusHints(callId, statusHints, Log.getExternalSession());
    357             } catch (RemoteException e) {
    358             }
    359         }
    360     }
    361 
    362     void setAddress(String callId, Uri address, int presentation) {
    363         for (IConnectionServiceAdapter adapter : mAdapters) {
    364             try {
    365                 adapter.setAddress(callId, address, presentation, Log.getExternalSession());
    366             } catch (RemoteException e) {
    367             }
    368         }
    369     }
    370 
    371     void setCallerDisplayName(String callId, String callerDisplayName, int presentation) {
    372         for (IConnectionServiceAdapter adapter : mAdapters) {
    373             try {
    374                 adapter.setCallerDisplayName(callId, callerDisplayName, presentation,
    375                         Log.getExternalSession());
    376             } catch (RemoteException e) {
    377             }
    378         }
    379     }
    380 
    381     /**
    382      * Sets the video state associated with a call.
    383      *
    384      * Valid values: {@link VideoProfile#STATE_BIDIRECTIONAL},
    385      * {@link VideoProfile#STATE_AUDIO_ONLY},
    386      * {@link VideoProfile#STATE_TX_ENABLED},
    387      * {@link VideoProfile#STATE_RX_ENABLED}.
    388      *
    389      * @param callId The unique ID of the call to set the video state for.
    390      * @param videoState The video state.
    391      */
    392     void setVideoState(String callId, int videoState) {
    393         Log.v(this, "setVideoState: %d", videoState);
    394         for (IConnectionServiceAdapter adapter : mAdapters) {
    395             try {
    396                 adapter.setVideoState(callId, videoState, Log.getExternalSession());
    397             } catch (RemoteException ignored) {
    398             }
    399         }
    400     }
    401 
    402     void setConferenceableConnections(String callId, List<String> conferenceableCallIds) {
    403         Log.v(this, "setConferenceableConnections: %s, %s", callId, conferenceableCallIds);
    404         for (IConnectionServiceAdapter adapter : mAdapters) {
    405             try {
    406                 adapter.setConferenceableConnections(callId, conferenceableCallIds,
    407                         Log.getExternalSession());
    408             } catch (RemoteException ignored) {
    409             }
    410         }
    411     }
    412 
    413     /**
    414      * Informs telecom of an existing connection which was added by the {@link ConnectionService}.
    415      *
    416      * @param callId The unique ID of the call being added.
    417      * @param connection The connection.
    418      */
    419     void addExistingConnection(String callId, ParcelableConnection connection) {
    420         Log.v(this, "addExistingConnection: %s", callId);
    421         for (IConnectionServiceAdapter adapter : mAdapters) {
    422             try {
    423                 adapter.addExistingConnection(callId, connection, Log.getExternalSession());
    424             } catch (RemoteException ignored) {
    425             }
    426         }
    427     }
    428 
    429     /**
    430      * Adds some extras associated with a {@code Connection}.
    431      *
    432      * @param callId The unique ID of the call.
    433      * @param extras The extras to add.
    434      */
    435     void putExtras(String callId, Bundle extras) {
    436         Log.v(this, "putExtras: %s", callId);
    437         for (IConnectionServiceAdapter adapter : mAdapters) {
    438             try {
    439                 adapter.putExtras(callId, extras, Log.getExternalSession());
    440             } catch (RemoteException ignored) {
    441             }
    442         }
    443     }
    444 
    445     /**
    446      * Adds an extra associated with a {@code Connection}.
    447      *
    448      * @param callId The unique ID of the call.
    449      * @param key The extra key.
    450      * @param value The extra value.
    451      */
    452     void putExtra(String callId, String key, boolean value) {
    453         Log.v(this, "putExtra: %s %s=%b", callId, key, value);
    454         for (IConnectionServiceAdapter adapter : mAdapters) {
    455             try {
    456                 Bundle bundle = new Bundle();
    457                 bundle.putBoolean(key, value);
    458                 adapter.putExtras(callId, bundle, Log.getExternalSession());
    459             } catch (RemoteException ignored) {
    460             }
    461         }
    462     }
    463 
    464     /**
    465      * Adds an extra associated with a {@code Connection}.
    466      *
    467      * @param callId The unique ID of the call.
    468      * @param key The extra key.
    469      * @param value The extra value.
    470      */
    471     void putExtra(String callId, String key, int value) {
    472         Log.v(this, "putExtra: %s %s=%d", callId, key, value);
    473         for (IConnectionServiceAdapter adapter : mAdapters) {
    474             try {
    475                 Bundle bundle = new Bundle();
    476                 bundle.putInt(key, value);
    477                 adapter.putExtras(callId, bundle, Log.getExternalSession());
    478             } catch (RemoteException ignored) {
    479             }
    480         }
    481     }
    482 
    483     /**
    484      * Adds an extra associated with a {@code Connection}.
    485      *
    486      * @param callId The unique ID of the call.
    487      * @param key The extra key.
    488      * @param value The extra value.
    489      */
    490     void putExtra(String callId, String key, String value) {
    491         Log.v(this, "putExtra: %s %s=%s", callId, key, value);
    492         for (IConnectionServiceAdapter adapter : mAdapters) {
    493             try {
    494                 Bundle bundle = new Bundle();
    495                 bundle.putString(key, value);
    496                 adapter.putExtras(callId, bundle, Log.getExternalSession());
    497             } catch (RemoteException ignored) {
    498             }
    499         }
    500     }
    501 
    502     /**
    503      * Removes extras associated with a {@code Connection}.
    504      *  @param callId The unique ID of the call.
    505      * @param keys The extra keys to remove.
    506      */
    507     void removeExtras(String callId, List<String> keys) {
    508         Log.v(this, "removeExtras: %s %s", callId, keys);
    509         for (IConnectionServiceAdapter adapter : mAdapters) {
    510             try {
    511                 adapter.removeExtras(callId, keys, Log.getExternalSession());
    512             } catch (RemoteException ignored) {
    513             }
    514         }
    515     }
    516 
    517     /**
    518      * Sets the audio route associated with a {@link Connection}.
    519      *
    520      * @param callId The unique ID of the call.
    521      * @param audioRoute The new audio route (see {@code CallAudioState#ROUTE_*}).
    522      */
    523     void setAudioRoute(String callId, int audioRoute, String bluetoothAddress) {
    524         Log.v(this, "setAudioRoute: %s %s %s", callId,
    525                 CallAudioState.audioRouteToString(audioRoute),
    526                 bluetoothAddress);
    527         for (IConnectionServiceAdapter adapter : mAdapters) {
    528             try {
    529                 adapter.setAudioRoute(callId, audioRoute,
    530                         bluetoothAddress, Log.getExternalSession());
    531             } catch (RemoteException ignored) {
    532             }
    533         }
    534     }
    535 
    536 
    537     /**
    538      * Informs Telecom of a connection level event.
    539      *
    540      * @param callId The unique ID of the call.
    541      * @param event The event.
    542      * @param extras Extras associated with the event.
    543      */
    544     void onConnectionEvent(String callId, String event, Bundle extras) {
    545         Log.v(this, "onConnectionEvent: %s", event);
    546         for (IConnectionServiceAdapter adapter : mAdapters) {
    547             try {
    548                 adapter.onConnectionEvent(callId, event, extras, Log.getExternalSession());
    549             } catch (RemoteException ignored) {
    550             }
    551         }
    552     }
    553 
    554     /**
    555      * Notifies Telecom that an RTT session was successfully established.
    556      *
    557      * @param callId The unique ID of the call.
    558      */
    559     void onRttInitiationSuccess(String callId) {
    560         Log.v(this, "onRttInitiationSuccess: %s", callId);
    561         for (IConnectionServiceAdapter adapter : mAdapters) {
    562             try {
    563                 adapter.onRttInitiationSuccess(callId, Log.getExternalSession());
    564             } catch (RemoteException ignored) {
    565             }
    566         }
    567     }
    568 
    569     /**
    570      * Notifies Telecom that a requested RTT session failed to be established.
    571      *
    572      * @param callId The unique ID of the call.
    573      */
    574     void onRttInitiationFailure(String callId, int reason) {
    575         Log.v(this, "onRttInitiationFailure: %s", callId);
    576         for (IConnectionServiceAdapter adapter : mAdapters) {
    577             try {
    578                 adapter.onRttInitiationFailure(callId, reason, Log.getExternalSession());
    579             } catch (RemoteException ignored) {
    580             }
    581         }
    582     }
    583 
    584     /**
    585      * Notifies Telecom that an established RTT session was terminated by the remote user on
    586      * the call.
    587      *
    588      * @param callId The unique ID of the call.
    589      */
    590     void onRttSessionRemotelyTerminated(String callId) {
    591         Log.v(this, "onRttSessionRemotelyTerminated: %s", callId);
    592         for (IConnectionServiceAdapter adapter : mAdapters) {
    593             try {
    594                 adapter.onRttSessionRemotelyTerminated(callId, Log.getExternalSession());
    595             } catch (RemoteException ignored) {
    596             }
    597         }
    598     }
    599 
    600     /**
    601      * Notifies Telecom that the remote user on the call has requested an upgrade to an RTT
    602      * session for this call.
    603      *
    604      * @param callId The unique ID of the call.
    605      */
    606     void onRemoteRttRequest(String callId) {
    607         Log.v(this, "onRemoteRttRequest: %s", callId);
    608         for (IConnectionServiceAdapter adapter : mAdapters) {
    609             try {
    610                 adapter.onRemoteRttRequest(callId, Log.getExternalSession());
    611             } catch (RemoteException ignored) {
    612             }
    613         }
    614     }
    615 
    616     /**
    617      * Notifies Telecom that a call's PhoneAccountHandle has changed.
    618      *
    619      * @param callId The unique ID of the call.
    620      * @param pHandle The new PhoneAccountHandle associated with the call.
    621      */
    622     void onPhoneAccountChanged(String callId, PhoneAccountHandle pHandle) {
    623         for (IConnectionServiceAdapter adapter : mAdapters) {
    624             try {
    625                 Log.d(this, "onPhoneAccountChanged %s", callId);
    626                 adapter.onPhoneAccountChanged(callId, pHandle, Log.getExternalSession());
    627             } catch (RemoteException ignored) {
    628             }
    629         }
    630     }
    631 
    632     /**
    633      * Notifies Telecom that the {@link ConnectionService} has released the call resource.
    634      */
    635     void onConnectionServiceFocusReleased() {
    636         for (IConnectionServiceAdapter adapter : mAdapters) {
    637             try {
    638                 Log.d(this, "onConnectionServiceFocusReleased");
    639                 adapter.onConnectionServiceFocusReleased(Log.getExternalSession());
    640             } catch (RemoteException ignored) {
    641             }
    642         }
    643     }
    644 }
    645