Home | History | Annotate | Download | only in cts
      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 
     17 package android.telecom.cts;
     18 
     19 import static org.junit.Assert.assertFalse;
     20 
     21 import android.content.Intent;
     22 import android.telecom.Call;
     23 import android.telecom.CallAudioState;
     24 import android.telecom.InCallService;
     25 import android.util.ArrayMap;
     26 import android.util.Log;
     27 
     28 import java.util.ArrayList;
     29 import java.util.List;
     30 import java.util.Map;
     31 import java.util.concurrent.Semaphore;
     32 
     33 public class MockInCallService extends InCallService {
     34     private static String LOG_TAG = "MockInCallService";
     35     private ArrayList<Call> mCalls = new ArrayList<>();
     36     private ArrayList<Call> mConferenceCalls = new ArrayList<>();
     37     private static InCallServiceCallbacks sCallbacks;
     38     private Map<Call, MockVideoCallCallback> mVideoCallCallbacks =
     39             new ArrayMap<Call, MockVideoCallCallback>();
     40 
     41     private static final Object sLock = new Object();
     42     private static boolean mIsServiceUnbound;
     43 
     44     public static abstract class InCallServiceCallbacks {
     45         private MockInCallService mService;
     46         public Semaphore lock = new Semaphore(0);
     47 
     48         public void onCallAdded(Call call, int numCalls) {};
     49         public void onCallRemoved(Call call, int numCalls) {};
     50         public void onCallStateChanged(Call call, int state) {};
     51         public void onParentChanged(Call call, Call parent) {};
     52         public void onChildrenChanged(Call call, List<Call> children) {};
     53         public void onConferenceableCallsChanged(Call call, List<Call> conferenceableCalls) {};
     54         public void onCallDestroyed(Call call) {};
     55         public void onDetailsChanged(Call call, Call.Details details) {};
     56         public void onCanAddCallsChanged(boolean canAddCalls) {}
     57         public void onBringToForeground(boolean showDialpad) {}
     58         public void onCallAudioStateChanged(CallAudioState audioState) {}
     59         public void onPostDialWait(Call call, String remainingPostDialSequence) {}
     60         public void onCannedTextResponsesLoaded(Call call, List<String> cannedTextResponses) {}
     61 
     62         final public MockInCallService getService() {
     63             return mService;
     64         }
     65 
     66         final public void setService(MockInCallService service) {
     67             mService = service;
     68         }
     69     }
     70 
     71     /**
     72      * Note that the super implementations of the callback methods are all no-ops, but we call
     73      * them anyway to make sure that the CTS coverage tool detects that we are testing them.
     74      */
     75     private Call.Callback mCallCallback = new Call.Callback() {
     76         @Override
     77         public void onStateChanged(Call call, int state) {
     78             super.onStateChanged(call, state);
     79             if (getCallbacks() != null) {
     80                 getCallbacks().onCallStateChanged(call, state);
     81             }
     82         }
     83 
     84         @Override
     85         public void onVideoCallChanged(Call call, InCallService.VideoCall videoCall) {
     86             super.onVideoCallChanged(call, videoCall);
     87             saveVideoCall(call, videoCall);
     88         }
     89 
     90         @Override
     91         public void onParentChanged(Call call, Call parent) {
     92             super.onParentChanged(call, parent);
     93             if (getCallbacks() != null) {
     94                 getCallbacks().onParentChanged(call, parent);
     95             }
     96         }
     97 
     98         @Override
     99         public void onChildrenChanged(Call call, List<Call> children) {
    100             super.onChildrenChanged(call, children);
    101             if (getCallbacks() != null) {
    102                 getCallbacks().onChildrenChanged(call, children);
    103             }
    104         }
    105 
    106         @Override
    107         public void onConferenceableCallsChanged(Call call, List<Call> conferenceableCalls) {
    108             super.onConferenceableCallsChanged(call, conferenceableCalls);
    109             if (getCallbacks() != null) {
    110                 getCallbacks().onConferenceableCallsChanged(call, conferenceableCalls);
    111             }
    112         }
    113 
    114         @Override
    115         public void onCallDestroyed(Call call) {
    116             super.onCallDestroyed(call);
    117             if (getCallbacks() != null) {
    118                 getCallbacks().onCallDestroyed(call);
    119             }
    120         }
    121 
    122         @Override
    123         public void onDetailsChanged(Call call, Call.Details details) {
    124             super.onDetailsChanged(call, details);
    125             if (getCallbacks() != null) {
    126                 getCallbacks().onDetailsChanged(call, details);
    127             }
    128         }
    129 
    130         @Override
    131         public void onPostDialWait(Call call, String remainingPostDialSequence) {
    132             super.onPostDialWait(call, remainingPostDialSequence);
    133             if (getCallbacks() != null) {
    134                 getCallbacks().onPostDialWait(call, remainingPostDialSequence);
    135             }
    136         }
    137 
    138         @Override
    139         public void onCannedTextResponsesLoaded(Call call, List<String> cannedTextResponses) {
    140             super.onCannedTextResponsesLoaded(call, cannedTextResponses);
    141             if (getCallbacks() != null) {
    142                 getCallbacks().onCannedTextResponsesLoaded(call, cannedTextResponses);
    143             }
    144         }
    145     };
    146 
    147     private void saveVideoCall(Call call, VideoCall videoCall) {
    148         if (videoCall != null) {
    149             if (!mVideoCallCallbacks.containsKey(call)) {
    150                 MockVideoCallCallback listener = new MockVideoCallCallback(call);
    151                 videoCall.registerCallback(listener);
    152                 mVideoCallCallbacks.put(call, listener);
    153             }
    154         } else {
    155             mVideoCallCallbacks.remove(call);
    156         }
    157     }
    158 
    159     @Override
    160     public android.os.IBinder onBind(android.content.Intent intent) {
    161         Log.i(LOG_TAG, "Service bounded");
    162         if (getCallbacks() != null) {
    163             getCallbacks().setService(this);
    164         }
    165         mIsServiceUnbound = false;
    166         return super.onBind(intent);
    167     }
    168 
    169     @Override
    170     public void onCallAdded(Call call) {
    171         super.onCallAdded(call);
    172         if (call.getDetails().hasProperty(Call.Details.PROPERTY_CONFERENCE) == true) {
    173             if (!mConferenceCalls.contains(call)) {
    174                 mConferenceCalls.add(call);
    175                 call.registerCallback(mCallCallback);
    176             }
    177         } else {
    178             if (!mCalls.contains(call)) {
    179                 mCalls.add(call);
    180                 call.registerCallback(mCallCallback);
    181                 VideoCall videoCall = call.getVideoCall();
    182                 if (videoCall != null) {
    183                     saveVideoCall(call, videoCall);
    184                 }
    185             }
    186         }
    187         if (getCallbacks() != null) {
    188             getCallbacks().onCallAdded(call, mCalls.size() + mConferenceCalls.size());
    189         }
    190     }
    191 
    192     @Override
    193     public void onCallRemoved(Call call) {
    194         super.onCallRemoved(call);
    195         if (call.getDetails().hasProperty(Call.Details.PROPERTY_CONFERENCE) == true) {
    196             mConferenceCalls.remove(call);
    197         } else {
    198             mCalls.remove(call);
    199         }
    200         if (getCallbacks() != null) {
    201             getCallbacks().onCallRemoved(call, mCalls.size() + mConferenceCalls.size());
    202             saveVideoCall(call, null /* remove videoCall */);
    203         }
    204     }
    205 
    206     @Override
    207     public void onCanAddCallChanged(boolean canAddCall) {
    208         super.onCanAddCallChanged(canAddCall);
    209         if (getCallbacks() != null) {
    210             getCallbacks().onCanAddCallsChanged(canAddCall);
    211         }
    212     }
    213 
    214     @Override
    215     public void onBringToForeground(boolean showDialpad) {
    216         super.onBringToForeground(showDialpad);
    217         if (getCallbacks() != null) {
    218             getCallbacks().onBringToForeground(showDialpad);
    219         }
    220     }
    221 
    222     @Override
    223     public void onCallAudioStateChanged(CallAudioState audioState) {
    224         super.onCallAudioStateChanged(audioState);
    225         if (getCallbacks() != null) {
    226             getCallbacks().onCallAudioStateChanged(audioState);
    227         }
    228     }
    229 
    230     /**
    231      * @return the number of calls currently added to the {@code InCallService}.
    232      */
    233     public int getCallCount() {
    234         return mCalls.size();
    235     }
    236 
    237     /**
    238      * @return the number of conference calls currently added to the {@code InCallService}.
    239      */
    240     public int getConferenceCallCount() {
    241         return mConferenceCalls.size();
    242     }
    243 
    244     /**
    245      * @return the most recently added call that exists inside the {@code InCallService}
    246      */
    247     public Call getLastCall() {
    248         if (!mCalls.isEmpty()) {
    249             return mCalls.get(mCalls.size() - 1);
    250         }
    251         return null;
    252     }
    253 
    254     /**
    255      * @return the most recently added conference call that exists inside the {@code InCallService}
    256      */
    257     public Call getLastConferenceCall() {
    258         if (!mConferenceCalls.isEmpty()) {
    259             return mConferenceCalls.get(mConferenceCalls.size() - 1);
    260         }
    261         return null;
    262     }
    263 
    264     public void disconnectLastCall() {
    265         final Call call = getLastCall();
    266         if (call != null) {
    267             call.disconnect();
    268         }
    269     }
    270 
    271     public void disconnectLastConferenceCall() {
    272         final Call call = getLastConferenceCall();
    273         if (call != null) {
    274             call.disconnect();
    275         }
    276     }
    277 
    278     public void disconnectAllCalls() {
    279         for (final Call call: mCalls) {
    280             call.disconnect();
    281         }
    282     }
    283 
    284     public void disconnectAllConferenceCalls() {
    285         for (final Call call: mConferenceCalls) {
    286             call.disconnect();
    287         }
    288     }
    289 
    290     public static void setCallbacks(InCallServiceCallbacks callbacks) {
    291         synchronized (sLock) {
    292             sCallbacks = callbacks;
    293         }
    294     }
    295 
    296     private InCallServiceCallbacks getCallbacks() {
    297         synchronized (sLock) {
    298             if (sCallbacks != null) {
    299                 sCallbacks.setService(this);
    300             }
    301             return sCallbacks;
    302         }
    303     }
    304 
    305     /**
    306      * Determines if a video callback has been registered for the passed in call.
    307      *
    308      * @param call The call.
    309      * @return {@code true} if a video callback has been registered.
    310      */
    311     public boolean isVideoCallbackRegistered(Call call) {
    312         return mVideoCallCallbacks.containsKey(call);
    313     }
    314 
    315     /**
    316      * Retrieves the video callbacks associated with a call.
    317      * @param call The call.
    318      * @return The {@link MockVideoCallCallback} instance associated with the call.
    319      */
    320     public MockVideoCallCallback getVideoCallCallback(Call call) {
    321         return mVideoCallCallbacks.get(call);
    322     }
    323 
    324     @Override
    325     public boolean onUnbind(Intent intent) {
    326         Log.i(LOG_TAG, "Service unbounded");
    327         assertFalse(mIsServiceUnbound);
    328         mIsServiceUnbound = true;
    329         return super.onUnbind(intent);
    330     }
    331 
    332     public static boolean isServiceUnbound() {
    333         return mIsServiceUnbound;
    334     }
    335 }
    336