1 /* 2 * Copyright (C) 2018 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.mbms; 18 19 import android.annotation.IntDef; 20 import android.annotation.NonNull; 21 import android.os.RemoteException; 22 import android.telephony.MbmsGroupCallSession; 23 import android.telephony.mbms.vendor.IMbmsGroupCallService; 24 import android.util.Log; 25 26 import java.lang.annotation.Retention; 27 import java.lang.annotation.RetentionPolicy; 28 import java.util.List; 29 30 /** 31 * Class used to represent a single MBMS group call. After a call has been started with 32 * {@link MbmsGroupCallSession#startGroupCall}, 33 * this class is used to hold information about the call and control it. 34 */ 35 public class GroupCall implements AutoCloseable { 36 private static final String LOG_TAG = "MbmsGroupCall"; 37 38 /** 39 * The state of a group call, reported via 40 * {@link GroupCallCallback#onGroupCallStateChanged(int, int)} 41 * @hide 42 */ 43 @Retention(RetentionPolicy.SOURCE) 44 @IntDef(prefix = { "STATE_" }, value = {STATE_STOPPED, STATE_STARTED, STATE_STALLED}) 45 public @interface GroupCallState {} 46 47 /** 48 * Indicates that the group call is in a stopped state 49 * 50 * This can be reported after network action or after calling {@link #close}. 51 */ 52 public static final int STATE_STOPPED = 1; 53 54 /** 55 * Indicates that the group call is started. 56 * 57 * Data can be transmitted and received in this state. 58 */ 59 public static final int STATE_STARTED = 2; 60 61 /** 62 * Indicates that the group call is stalled. 63 * 64 * This may be due to a network issue or the device being temporarily out of range. 65 */ 66 public static final int STATE_STALLED = 3; 67 68 /** 69 * The reason for a call state change, reported via 70 * {@link GroupCallCallback#onGroupCallStateChanged(int, int)} 71 * @hide 72 */ 73 @Retention(RetentionPolicy.SOURCE) 74 @IntDef(prefix = { "REASON_" }, 75 value = {REASON_BY_USER_REQUEST, REASON_FREQUENCY_CONFLICT, 76 REASON_OUT_OF_MEMORY, REASON_NOT_CONNECTED_TO_HOMECARRIER_LTE, 77 REASON_LEFT_MBMS_BROADCAST_AREA, REASON_NONE}) 78 public @interface GroupCallStateChangeReason {} 79 80 /** 81 * Indicates that the middleware does not have a reason to provide for the state change. 82 */ 83 public static final int REASON_NONE = 0; 84 85 /** 86 * State changed due to a call to {@link #close()} or 87 * {@link MbmsGroupCallSession#startGroupCall} 88 */ 89 public static final int REASON_BY_USER_REQUEST = 1; 90 91 // 2 is unused to match up with streaming. 92 93 /** 94 * State changed due to a frequency conflict with another requested call. 95 */ 96 public static final int REASON_FREQUENCY_CONFLICT = 3; 97 98 /** 99 * State changed due to the middleware running out of memory 100 */ 101 public static final int REASON_OUT_OF_MEMORY = 4; 102 103 /** 104 * State changed due to the device leaving the home carrier's LTE network. 105 */ 106 public static final int REASON_NOT_CONNECTED_TO_HOMECARRIER_LTE = 5; 107 108 /** 109 * State changed due to the device leaving the area where this call is being broadcast. 110 */ 111 public static final int REASON_LEFT_MBMS_BROADCAST_AREA = 6; 112 113 private final int mSubscriptionId; 114 private final long mTmgi; 115 private final MbmsGroupCallSession mParentSession; 116 private final InternalGroupCallCallback mCallback; 117 private IMbmsGroupCallService mService; 118 119 /** 120 * @hide 121 */ GroupCall(int subscriptionId, IMbmsGroupCallService service, MbmsGroupCallSession session, long tmgi, InternalGroupCallCallback callback)122 public GroupCall(int subscriptionId, 123 IMbmsGroupCallService service, 124 MbmsGroupCallSession session, 125 long tmgi, 126 InternalGroupCallCallback callback) { 127 mSubscriptionId = subscriptionId; 128 mParentSession = session; 129 mService = service; 130 mTmgi = tmgi; 131 mCallback = callback; 132 } 133 134 /** 135 * Retrieve the TMGI (Temporary Mobile Group Identity) corresponding to this call. 136 */ getTmgi()137 public long getTmgi() { 138 return mTmgi; 139 } 140 141 /** 142 * Send an update to the middleware when the SAI (Service Area Identifier) list and frequency 143 * information of the group call has * changed. Callers must obtain this information from the 144 * wireless carrier independently. 145 * @param saiList New list of SAIs that the call is available on. 146 * @param frequencyList New list of frequencies that the call is available on. 147 */ updateGroupCall(@onNull List<Integer> saiList, @NonNull List<Integer> frequencyList)148 public void updateGroupCall(@NonNull List<Integer> saiList, 149 @NonNull List<Integer> frequencyList) { 150 if (mService == null) { 151 throw new IllegalStateException("No group call service attached"); 152 } 153 154 try { 155 mService.updateGroupCall(mSubscriptionId, mTmgi, saiList, frequencyList); 156 } catch (RemoteException e) { 157 Log.w(LOG_TAG, "Remote process died"); 158 mService = null; 159 sendErrorToApp(MbmsErrors.ERROR_MIDDLEWARE_LOST, null); 160 } finally { 161 mParentSession.onGroupCallStopped(this); 162 } 163 } 164 165 /** 166 * Stop this group call. Further operations on this object will fail with an 167 * {@link IllegalStateException}. 168 * 169 * May throw an {@link IllegalStateException} 170 */ 171 @Override close()172 public void close() { 173 if (mService == null) { 174 throw new IllegalStateException("No group call service attached"); 175 } 176 177 try { 178 mService.stopGroupCall(mSubscriptionId, mTmgi); 179 } catch (RemoteException e) { 180 Log.w(LOG_TAG, "Remote process died"); 181 mService = null; 182 sendErrorToApp(MbmsErrors.ERROR_MIDDLEWARE_LOST, null); 183 } finally { 184 mParentSession.onGroupCallStopped(this); 185 } 186 } 187 188 /** @hide */ getCallback()189 public InternalGroupCallCallback getCallback() { 190 return mCallback; 191 } 192 sendErrorToApp(int errorCode, String message)193 private void sendErrorToApp(int errorCode, String message) { 194 mCallback.onError(errorCode, message); 195 } 196 } 197 198