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 android.telephony.cts.embmstestapp; 18 19 import android.app.Service; 20 import android.content.ComponentName; 21 import android.content.Intent; 22 import android.net.Uri; 23 import android.os.Binder; 24 import android.os.Handler; 25 import android.os.HandlerThread; 26 import android.os.IBinder; 27 import android.os.RemoteException; 28 import android.telephony.mbms.GroupCall; 29 import android.telephony.mbms.MbmsErrors; 30 import android.telephony.mbms.MbmsGroupCallSessionCallback; 31 import android.telephony.mbms.GroupCallCallback; 32 import android.telephony.mbms.vendor.MbmsGroupCallServiceBase; 33 import android.util.Log; 34 35 import java.util.Arrays; 36 import java.util.Collections; 37 import java.util.LinkedList; 38 import java.util.List; 39 import java.util.Set; 40 41 public class CtsGroupCallService extends MbmsGroupCallServiceBase { 42 private static final Set<String> ALLOWED_PACKAGES = Set.of("android.telephony.cts"); 43 private static final String TAG = "EmbmsTestGroupCall"; 44 45 public static final String METHOD_INITIALIZE = "initialize"; 46 public static final String METHOD_START_GROUP_CALL = "startGroupCall"; 47 public static final String METHOD_UPDATE_GROUP_CALL = "updateGroupCall"; 48 public static final String METHOD_STOP_GROUP_CALL = "stopGroupCall"; 49 public static final String METHOD_CLOSE = "close"; 50 51 public static final String CONTROL_INTERFACE_ACTION = 52 "android.telephony.cts.embmstestapp.ACTION_CONTROL_MIDDLEWARE"; 53 public static final ComponentName CONTROL_INTERFACE_COMPONENT = 54 ComponentName.unflattenFromString( 55 "android.telephony.cts.embmstestapp/.CtsGroupCallService"); 56 57 private MbmsGroupCallSessionCallback mAppCallback; 58 private GroupCallCallback mGroupCallCallback; 59 60 private HandlerThread mHandlerThread; 61 private Handler mHandler; 62 private List<List> mReceivedCalls = new LinkedList<>(); 63 private int mErrorCodeOverride = MbmsErrors.SUCCESS; 64 65 @Override initialize(MbmsGroupCallSessionCallback callback, int subId)66 public int initialize(MbmsGroupCallSessionCallback callback, int subId) { 67 mReceivedCalls.add(Arrays.asList(METHOD_INITIALIZE, subId)); 68 if (mErrorCodeOverride != MbmsErrors.SUCCESS) { 69 return mErrorCodeOverride; 70 } 71 72 int packageUid = Binder.getCallingUid(); 73 String[] packageNames = getPackageManager().getPackagesForUid(packageUid); 74 if (packageNames == null) { 75 return MbmsErrors.InitializationErrors.ERROR_APP_PERMISSIONS_NOT_GRANTED; 76 } 77 boolean isUidAllowed = Arrays.stream(packageNames).anyMatch(ALLOWED_PACKAGES::contains); 78 if (!isUidAllowed) { 79 return MbmsErrors.InitializationErrors.ERROR_APP_PERMISSIONS_NOT_GRANTED; 80 } 81 82 mHandler.post(() -> { 83 if (mAppCallback == null) { 84 mAppCallback = callback; 85 } else { 86 callback.onError( 87 MbmsErrors.InitializationErrors.ERROR_DUPLICATE_INITIALIZE, ""); 88 return; 89 } 90 callback.onMiddlewareReady(); 91 }); 92 return MbmsErrors.SUCCESS; 93 } 94 95 @Override startGroupCall(final int subscriptionId, final long tmgi, final List<Integer> saiArray, final List<Integer> frequencyArray, final GroupCallCallback callback)96 public int startGroupCall(final int subscriptionId, final long tmgi, 97 final List<Integer> saiArray, final List<Integer> frequencyArray, 98 final GroupCallCallback callback) { 99 mReceivedCalls.add(Arrays.asList(METHOD_START_GROUP_CALL, subscriptionId, tmgi, saiArray, 100 frequencyArray)); 101 if (mErrorCodeOverride != MbmsErrors.SUCCESS) { 102 return mErrorCodeOverride; 103 } 104 105 mGroupCallCallback = callback; 106 mHandler.post(() -> callback.onGroupCallStateChanged(GroupCall.STATE_STARTED, 107 GroupCall.REASON_BY_USER_REQUEST)); 108 return MbmsErrors.SUCCESS; 109 } 110 111 @Override updateGroupCall(int subscriptionId, long tmgi, List<Integer> saiArray, List<Integer> frequencyArray)112 public void updateGroupCall(int subscriptionId, long tmgi, 113 List<Integer> saiArray, List<Integer> frequencyArray) { 114 mReceivedCalls.add(Arrays.asList(METHOD_UPDATE_GROUP_CALL, 115 subscriptionId, tmgi, saiArray, frequencyArray)); 116 } 117 118 @Override stopGroupCall(int subscriptionId, long tmgi)119 public void stopGroupCall(int subscriptionId, long tmgi) { 120 mReceivedCalls.add(Arrays.asList(METHOD_STOP_GROUP_CALL, subscriptionId, tmgi)); 121 } 122 123 @Override dispose(int subscriptionId)124 public void dispose(int subscriptionId) { 125 mReceivedCalls.add(Arrays.asList(METHOD_CLOSE, subscriptionId)); 126 } 127 128 @Override onAppCallbackDied(int uid, int subscriptionId)129 public void onAppCallbackDied(int uid, int subscriptionId) { 130 mAppCallback = null; 131 } 132 133 private final IBinder mControlInterface = new ICtsGroupCallMiddlewareControl.Stub() { 134 @Override 135 public void reset() { 136 mReceivedCalls.clear(); 137 mHandler.removeCallbacksAndMessages(null); 138 mAppCallback = null; 139 mErrorCodeOverride = MbmsErrors.SUCCESS; 140 } 141 142 @Override 143 public List getGroupCallSessionCalls() { 144 return mReceivedCalls; 145 } 146 147 @Override 148 public void forceErrorCode(int error) { 149 mErrorCodeOverride = error; 150 } 151 152 @Override 153 public void fireErrorOnGroupCall(int errorCode, String message) { 154 mHandler.post(() -> mGroupCallCallback.onError(errorCode, message)); 155 } 156 157 @Override 158 public void fireErrorOnSession(int errorCode, String message) { 159 mHandler.post(() -> mAppCallback.onError(errorCode, message)); 160 } 161 162 @Override 163 public void fireGroupCallStateChanged(int state, int reason) { 164 mHandler.post(() -> mGroupCallCallback.onGroupCallStateChanged(state, reason)); 165 } 166 167 @Override 168 public void fireBroadcastSignalStrengthUpdated(int signalStrength) { 169 mHandler.post( 170 () -> mGroupCallCallback.onBroadcastSignalStrengthUpdated(signalStrength)); 171 } 172 173 @Override 174 public void fireAvailableSaisUpdated(List currentSais, List availableSais) { 175 mHandler.post(() -> mAppCallback.onAvailableSaisUpdated(currentSais, availableSais)); 176 } 177 178 @Override 179 public void fireServiceInterfaceAvailable(String interfaceName, int index) { 180 mHandler.post(() -> mAppCallback.onServiceInterfaceAvailable(interfaceName, index)); 181 } 182 }; 183 184 @Override onDestroy()185 public void onDestroy() { 186 mHandlerThread.quitSafely(); 187 logd("CtsGroupCallService onDestroy"); 188 super.onDestroy(); 189 } 190 191 @Override onBind(Intent intent)192 public IBinder onBind(Intent intent) { 193 logd("CtsGroupCallService onBind"); 194 if (CONTROL_INTERFACE_ACTION.equals(intent.getAction())) { 195 logd("CtsGroupCallService control interface bind"); 196 return mControlInterface; 197 } 198 IBinder binder = super.onBind(intent); 199 200 if (mHandlerThread != null && mHandlerThread.isAlive()) { 201 return binder; 202 } 203 204 mHandlerThread = new HandlerThread("CtsGroupCallServiceWorker"); 205 mHandlerThread.start(); 206 mHandler = new Handler(mHandlerThread.getLooper()); 207 return binder; 208 } 209 logd(String s)210 private static void logd(String s) { 211 Log.d(TAG, s); 212 } 213 checkInitialized()214 private void checkInitialized() { 215 if (mAppCallback == null) { 216 throw new IllegalStateException("Not yet initialized"); 217 } 218 } 219 } 220