1/* 2 * Copyright (C) 2016 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 17package com.android.internal.telephony.imsphone; 18 19import com.android.internal.telephony.Call; 20import com.android.internal.telephony.CallStateException; 21import com.android.internal.telephony.Connection; 22import com.android.internal.telephony.Phone; 23import com.android.internal.telephony.PhoneConstants; 24import com.android.internal.telephony.UUSInfo; 25 26import android.telephony.Rlog; 27import android.util.Log; 28 29import java.util.Collections; 30import java.util.List; 31import java.util.Set; 32import java.util.concurrent.ConcurrentHashMap; 33 34/** 35 * Represents an IMS call external to the device. This class is used to represent a call which 36 * takes places on a secondary device associated with this one. Originates from a Dialog Event 37 * Package. 38 * 39 * Dialog event package information is received from the IMS framework via 40 * {@link com.android.ims.ImsExternalCallState} instances. 41 * 42 * @hide 43 */ 44public class ImsExternalConnection extends Connection { 45 46 public interface Listener { 47 void onPullExternalCall(ImsExternalConnection connection); 48 } 49 50 /** 51 * ConcurrentHashMap constructor params: 8 is initial table size, 0.9f is 52 * load factor before resizing, 1 means we only expect a single thread to 53 * access the map so make only a single shard 54 */ 55 private final Set<Listener> mListeners = Collections.newSetFromMap( 56 new ConcurrentHashMap<Listener, Boolean>(8, 0.9f, 1)); 57 58 /** 59 * The unqiue dialog event package specified ID associated with this external connection. 60 */ 61 private int mCallId; 62 63 /** 64 * A backing call associated with this external connection. 65 */ 66 private ImsExternalCall mCall; 67 68 /** 69 * Determines if the call is pullable. 70 */ 71 private boolean mIsPullable; 72 73 protected ImsExternalConnection(Phone phone, int callId, String address, boolean isPullable) { 74 super(phone.getPhoneType()); 75 mCall = new ImsExternalCall(phone, this); 76 mCallId = callId; 77 mAddress = address; 78 mNumberPresentation = PhoneConstants.PRESENTATION_ALLOWED; 79 mIsPullable = isPullable; 80 81 rebuildCapabilities(); 82 setActive(); 83 } 84 85 /** 86 * @return the unique ID of this connection from the dialog event package data. 87 */ 88 public int getCallId() { 89 return mCallId; 90 } 91 92 @Override 93 public Call getCall() { 94 return mCall; 95 } 96 97 @Override 98 public long getDisconnectTime() { 99 return 0; 100 } 101 102 @Override 103 public long getHoldDurationMillis() { 104 return 0; 105 } 106 107 @Override 108 public String getVendorDisconnectCause() { 109 return null; 110 } 111 112 @Override 113 public void hangup() throws CallStateException { 114 // No-op - Hangup is not supported for external calls. 115 } 116 117 @Override 118 public void separate() throws CallStateException { 119 // No-op - Separate is not supported for external calls. 120 } 121 122 @Override 123 public void proceedAfterWaitChar() { 124 // No-op - not supported for external calls. 125 } 126 127 @Override 128 public void proceedAfterWildChar(String str) { 129 // No-op - not supported for external calls. 130 } 131 132 @Override 133 public void cancelPostDial() { 134 // No-op - not supported for external calls. 135 } 136 137 @Override 138 public int getNumberPresentation() { 139 return mNumberPresentation; 140 } 141 142 @Override 143 public UUSInfo getUUSInfo() { 144 return null; 145 } 146 147 @Override 148 public int getPreciseDisconnectCause() { 149 return 0; 150 } 151 152 @Override 153 public boolean isMultiparty() { 154 return false; 155 } 156 157 /** 158 * Called by a {@link android.telecom.Connection} to indicate that this call should be pulled 159 * to the local device. 160 * 161 * Informs all listeners, in this case {@link ImsExternalCallTracker}, of the request to pull 162 * the call. 163 */ 164 @Override 165 public void pullExternalCall() { 166 for (Listener listener : mListeners) { 167 listener.onPullExternalCall(this); 168 } 169 } 170 171 /** 172 * Sets this external call as active. 173 */ 174 public void setActive() { 175 if (mCall == null) { 176 return; 177 } 178 mCall.setActive(); 179 } 180 181 /** 182 * Sets this external call as terminated. 183 */ 184 public void setTerminated() { 185 if (mCall == null) { 186 return; 187 } 188 189 mCall.setTerminated(); 190 } 191 192 /** 193 * Changes whether the call can be pulled or not. 194 * 195 * @param isPullable {@code true} if the call can be pulled, {@code false} otherwise. 196 */ 197 public void setIsPullable(boolean isPullable) { 198 mIsPullable = isPullable; 199 rebuildCapabilities(); 200 } 201 202 public void addListener(Listener listener) { 203 mListeners.add(listener); 204 } 205 206 public void removeListener(Listener listener) { 207 mListeners.remove(listener); 208 } 209 210 /** 211 * Build a human representation of a connection instance, suitable for debugging. 212 * Don't log personal stuff unless in debug mode. 213 * @return a string representing the internal state of this connection. 214 */ 215 public String toString() { 216 StringBuilder str = new StringBuilder(128); 217 str.append("[ImsExternalConnection dialogCallId:"); 218 str.append(mCallId); 219 str.append(" state:"); 220 if (mCall.getState() == Call.State.ACTIVE) { 221 str.append("Active"); 222 } else if (mCall.getState() == Call.State.DISCONNECTED) { 223 str.append("Disconnected"); 224 } 225 str.append("]"); 226 return str.toString(); 227 } 228 229 /** 230 * Rebuilds the connection capabilities. 231 */ 232 private void rebuildCapabilities() { 233 int capabilities = Capability.IS_EXTERNAL_CONNECTION; 234 if (mIsPullable) { 235 capabilities |= Capability.IS_PULLABLE; 236 } 237 238 setConnectionCapabilities(capabilities); 239 } 240} 241