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 com.android.server.telecom; 18 19 import android.util.ArrayMap; 20 21 import java.util.Map; 22 23 /** Utility to map {@link Call} objects to unique IDs. IDs are generated when a call is added. */ 24 class CallIdMapper { 25 /** 26 * A very basic bidirectional map. 27 */ 28 static class BiMap<K, V> { 29 private Map<K, V> mPrimaryMap = new ArrayMap<>(); 30 private Map<V, K> mSecondaryMap = new ArrayMap<>(); 31 put(K key, V value)32 public boolean put(K key, V value) { 33 if (key == null || value == null || mPrimaryMap.containsKey(key) || 34 mSecondaryMap.containsKey(value)) { 35 return false; 36 } 37 38 mPrimaryMap.put(key, value); 39 mSecondaryMap.put(value, key); 40 return true; 41 } 42 remove(K key)43 public boolean remove(K key) { 44 if (key == null) { 45 return false; 46 } 47 if (mPrimaryMap.containsKey(key)) { 48 V value = getValue(key); 49 mPrimaryMap.remove(key); 50 mSecondaryMap.remove(value); 51 return true; 52 } 53 return false; 54 } 55 removeValue(V value)56 public boolean removeValue(V value) { 57 if (value == null) { 58 return false; 59 } 60 return remove(getKey(value)); 61 } 62 getValue(K key)63 public V getValue(K key) { 64 return mPrimaryMap.get(key); 65 } 66 getKey(V value)67 public K getKey(V value) { 68 return mSecondaryMap.get(value); 69 } 70 clear()71 public void clear() { 72 mPrimaryMap.clear(); 73 mSecondaryMap.clear(); 74 } 75 } 76 77 private final BiMap<String, Call> mCalls = new BiMap<>(); 78 private final String mCallIdPrefix; 79 private static int sIdCount; 80 CallIdMapper(String callIdPrefix)81 CallIdMapper(String callIdPrefix) { 82 mCallIdPrefix = callIdPrefix + "@"; 83 } 84 replaceCall(Call newCall, Call callToReplace)85 void replaceCall(Call newCall, Call callToReplace) { 86 // Use the old call's ID for the new call. 87 String callId = getCallId(callToReplace); 88 mCalls.put(callId, newCall); 89 } 90 addCall(Call call, String id)91 void addCall(Call call, String id) { 92 if (call == null) { 93 return; 94 } 95 mCalls.put(id, call); 96 } 97 addCall(Call call)98 void addCall(Call call) { 99 addCall(call, getNewId()); 100 } 101 removeCall(Call call)102 void removeCall(Call call) { 103 if (call == null) { 104 return; 105 } 106 mCalls.removeValue(call); 107 } 108 removeCall(String callId)109 void removeCall(String callId) { 110 mCalls.remove(callId); 111 } 112 getCallId(Call call)113 String getCallId(Call call) { 114 if (call == null) { 115 return null; 116 } 117 return mCalls.getKey(call); 118 } 119 getCall(Object objId)120 Call getCall(Object objId) { 121 String callId = null; 122 if (objId instanceof String) { 123 callId = (String) objId; 124 } 125 if (!isValidCallId(callId) && !isValidConferenceId(callId)) { 126 return null; 127 } 128 129 return mCalls.getValue(callId); 130 } 131 clear()132 void clear() { 133 mCalls.clear(); 134 } 135 isValidCallId(String callId)136 boolean isValidCallId(String callId) { 137 // Note, no need for thread check, this method is thread safe. 138 return callId != null && callId.startsWith(mCallIdPrefix); 139 } 140 isValidConferenceId(String callId)141 boolean isValidConferenceId(String callId) { 142 return callId != null; 143 } 144 getNewId()145 String getNewId() { 146 sIdCount++; 147 return mCallIdPrefix + sIdCount; 148 } 149 } 150