Home | History | Annotate | Download | only in call
      1 /*
      2  * Copyright (C) 2017 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 com.android.incallui.call;
     18 
     19 import android.os.Handler;
     20 import android.os.Looper;
     21 import android.support.annotation.NonNull;
     22 import android.telecom.Call;
     23 import android.util.ArraySet;
     24 import com.android.contacts.common.compat.CallCompat;
     25 import com.android.dialer.common.LogUtil;
     26 import java.util.Collections;
     27 import java.util.Set;
     28 import java.util.concurrent.ConcurrentHashMap;
     29 
     30 /**
     31  * Tracks the external calls known to the InCall UI.
     32  *
     33  * <p>External calls are those with {@code android.telecom.Call.Details#PROPERTY_IS_EXTERNAL_CALL}.
     34  */
     35 public class ExternalCallList {
     36 
     37   private final Set<Call> mExternalCalls = new ArraySet<>();
     38   private final Set<ExternalCallListener> mExternalCallListeners =
     39       Collections.newSetFromMap(new ConcurrentHashMap<ExternalCallListener, Boolean>(8, 0.9f, 1));
     40   /** Handles {@link android.telecom.Call.Callback} callbacks. */
     41   private final Call.Callback mTelecomCallCallback =
     42       new Call.Callback() {
     43         @Override
     44         public void onDetailsChanged(Call call, Call.Details details) {
     45           notifyExternalCallUpdated(call);
     46         }
     47       };
     48 
     49   /** Begins tracking an external call and notifies listeners of the new call. */
     50   public void onCallAdded(Call telecomCall) {
     51     if (!telecomCall.getDetails().hasProperty(CallCompat.Details.PROPERTY_IS_EXTERNAL_CALL)) {
     52       throw new IllegalArgumentException();
     53     }
     54     mExternalCalls.add(telecomCall);
     55     telecomCall.registerCallback(mTelecomCallCallback, new Handler(Looper.getMainLooper()));
     56     notifyExternalCallAdded(telecomCall);
     57   }
     58 
     59   /** Stops tracking an external call and notifies listeners of the removal of the call. */
     60   public void onCallRemoved(Call telecomCall) {
     61     if (!mExternalCalls.contains(telecomCall)) {
     62       // This can happen on M for external calls from blocked numbers
     63       LogUtil.i("ExternalCallList.onCallRemoved", "attempted to remove unregistered call");
     64       return;
     65     }
     66     mExternalCalls.remove(telecomCall);
     67     telecomCall.unregisterCallback(mTelecomCallCallback);
     68     notifyExternalCallRemoved(telecomCall);
     69   }
     70 
     71   /** Adds a new listener to external call events. */
     72   public void addExternalCallListener(@NonNull ExternalCallListener listener) {
     73     mExternalCallListeners.add(listener);
     74   }
     75 
     76   /** Removes a listener to external call events. */
     77   public void removeExternalCallListener(@NonNull ExternalCallListener listener) {
     78     if (!mExternalCallListeners.contains(listener)) {
     79       LogUtil.i(
     80           "ExternalCallList.removeExternalCallListener",
     81           "attempt to remove unregistered listener.");
     82     }
     83     mExternalCallListeners.remove(listener);
     84   }
     85 
     86   public boolean isCallTracked(@NonNull android.telecom.Call telecomCall) {
     87     return mExternalCalls.contains(telecomCall);
     88   }
     89 
     90   /** Notifies listeners of the addition of a new external call. */
     91   private void notifyExternalCallAdded(Call call) {
     92     for (ExternalCallListener listener : mExternalCallListeners) {
     93       listener.onExternalCallAdded(call);
     94     }
     95   }
     96 
     97   /** Notifies listeners of the removal of an external call. */
     98   private void notifyExternalCallRemoved(Call call) {
     99     for (ExternalCallListener listener : mExternalCallListeners) {
    100       listener.onExternalCallRemoved(call);
    101     }
    102   }
    103 
    104   /** Notifies listeners of changes to an external call. */
    105   private void notifyExternalCallUpdated(Call call) {
    106     if (!call.getDetails().hasProperty(CallCompat.Details.PROPERTY_IS_EXTERNAL_CALL)) {
    107       // A previous external call has been pulled and is now a regular call, so we will remove
    108       // it from the external call listener and ensure that the CallList is informed of the
    109       // change.
    110       onCallRemoved(call);
    111 
    112       for (ExternalCallListener listener : mExternalCallListeners) {
    113         listener.onExternalCallPulled(call);
    114       }
    115     } else {
    116       for (ExternalCallListener listener : mExternalCallListeners) {
    117         listener.onExternalCallUpdated(call);
    118       }
    119     }
    120   }
    121 
    122   /**
    123    * Defines events which the {@link ExternalCallList} exposes to interested components (e.g. {@link
    124    * com.android.incallui.ExternalCallNotifier ExternalCallNotifier}).
    125    */
    126   public interface ExternalCallListener {
    127 
    128     void onExternalCallAdded(Call call);
    129 
    130     void onExternalCallRemoved(Call call);
    131 
    132     void onExternalCallUpdated(Call call);
    133 
    134     void onExternalCallPulled(Call call);
    135   }
    136 }
    137