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