blob: 3fbbc03f0c670f42e853b29a5edf42e585457fbe [file] [log] [blame]
Robert Greenwalt4dded7a2016-12-05 16:33:32 -08001/*
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 android.telephony;
18
Hall Liu17449f92018-03-28 15:54:07 -070019import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID;
20
Hall Liud666a892017-08-28 14:10:46 -070021import android.annotation.NonNull;
22import android.annotation.Nullable;
Hall Liu23989212017-07-18 11:30:27 -070023import android.annotation.SdkConstant;
24import android.annotation.SystemApi;
Hall Liu64e22af2017-10-20 11:30:16 -070025import android.annotation.TestApi;
Hall Liufa2115e2017-04-27 13:20:09 -070026import android.content.ComponentName;
Robert Greenwalt4dded7a2016-12-05 16:33:32 -080027import android.content.Context;
Hall Liufa2115e2017-04-27 13:20:09 -070028import android.content.ServiceConnection;
Hall Liufa2115e2017-04-27 13:20:09 -070029import android.os.IBinder;
Hall Liu563e150c2017-04-25 15:04:26 -070030import android.os.RemoteException;
Hall Liuee19cfc2017-08-03 18:26:39 -070031import android.telephony.mbms.InternalStreamingServiceCallback;
Hall Liu17449f92018-03-28 15:54:07 -070032import android.telephony.mbms.InternalStreamingSessionCallback;
Hall Liue373ee52017-09-08 18:02:38 -070033import android.telephony.mbms.MbmsErrors;
Hall Liud666a892017-08-28 14:10:46 -070034import android.telephony.mbms.MbmsStreamingSessionCallback;
Hall Liu08428312017-05-19 15:28:09 -070035import android.telephony.mbms.MbmsUtils;
Robert Greenwalt4dded7a2016-12-05 16:33:32 -080036import android.telephony.mbms.StreamingService;
Hall Liufb1ee0e2017-05-11 13:32:32 -070037import android.telephony.mbms.StreamingServiceCallback;
Robert Greenwalt4dded7a2016-12-05 16:33:32 -080038import android.telephony.mbms.StreamingServiceInfo;
Hall Liu563e150c2017-04-25 15:04:26 -070039import android.telephony.mbms.vendor.IMbmsStreamingService;
Hall Liud666a892017-08-28 14:10:46 -070040import android.util.ArraySet;
Robert Greenwalt4dded7a2016-12-05 16:33:32 -080041import android.util.Log;
42
43import java.util.List;
Hall Liud666a892017-08-28 14:10:46 -070044import java.util.Set;
Hall Liu5b844872018-02-06 11:36:17 -080045import java.util.concurrent.Executor;
Hall Liud5c955f2017-07-20 15:32:51 -070046import java.util.concurrent.atomic.AtomicBoolean;
Hall Liu727a05b2017-06-16 14:59:57 -070047import java.util.concurrent.atomic.AtomicReference;
Robert Greenwalt4dded7a2016-12-05 16:33:32 -080048
Hall Liu46cbcd12017-07-07 13:33:16 -070049/**
50 * This class provides functionality for streaming media over MBMS.
Hall Liu46cbcd12017-07-07 13:33:16 -070051 */
Hall Liud666a892017-08-28 14:10:46 -070052public class MbmsStreamingSession implements AutoCloseable {
53 private static final String LOG_TAG = "MbmsStreamingSession";
Hall Liu23989212017-07-18 11:30:27 -070054
55 /**
56 * Service action which must be handled by the middleware implementing the MBMS streaming
57 * interface.
58 * @hide
59 */
60 @SystemApi
61 @SdkConstant(SdkConstant.SdkConstantType.SERVICE_ACTION)
Hall Liufa2115e2017-04-27 13:20:09 -070062 public static final String MBMS_STREAMING_SERVICE_ACTION =
63 "android.telephony.action.EmbmsStreaming";
64
Hall Liu64e22af2017-10-20 11:30:16 -070065 /**
66 * Metadata key that specifies the component name of the service to bind to for file-download.
67 * @hide
68 */
69 @TestApi
70 public static final String MBMS_STREAMING_SERVICE_OVERRIDE_METADATA =
71 "mbms-streaming-service-override";
72
Hall Liud5c955f2017-07-20 15:32:51 -070073 private static AtomicBoolean sIsInitialized = new AtomicBoolean(false);
74
Hall Liu727a05b2017-06-16 14:59:57 -070075 private AtomicReference<IMbmsStreamingService> mService = new AtomicReference<>(null);
Hall Liud5c955f2017-07-20 15:32:51 -070076 private IBinder.DeathRecipient mDeathRecipient = new IBinder.DeathRecipient() {
77 @Override
78 public void binderDied() {
79 sIsInitialized.set(false);
Hall Liue373ee52017-09-08 18:02:38 -070080 sendErrorToApp(MbmsErrors.ERROR_MIDDLEWARE_LOST, "Received death notification");
Hall Liud5c955f2017-07-20 15:32:51 -070081 }
82 };
83
Hall Liud666a892017-08-28 14:10:46 -070084 private InternalStreamingSessionCallback mInternalCallback;
Hall Liu718986d2019-08-29 15:42:47 -070085 private ServiceConnection mServiceConnection;
Hall Liud666a892017-08-28 14:10:46 -070086 private Set<StreamingService> mKnownActiveStreamingServices = new ArraySet<>();
Robert Greenwalt4dded7a2016-12-05 16:33:32 -080087
88 private final Context mContext;
Hall Liu563e150c2017-04-25 15:04:26 -070089 private int mSubscriptionId = INVALID_SUBSCRIPTION_ID;
Robert Greenwalt4dded7a2016-12-05 16:33:32 -080090
Hall Liu563e150c2017-04-25 15:04:26 -070091 /** @hide */
Hall Liu5b844872018-02-06 11:36:17 -080092 private MbmsStreamingSession(Context context, Executor executor, int subscriptionId,
93 MbmsStreamingSessionCallback callback) {
Robert Greenwalt4dded7a2016-12-05 16:33:32 -080094 mContext = context;
Hall Liu563e150c2017-04-25 15:04:26 -070095 mSubscriptionId = subscriptionId;
Hall Liu5b844872018-02-06 11:36:17 -080096 mInternalCallback = new InternalStreamingSessionCallback(callback, executor);
Robert Greenwalt4dded7a2016-12-05 16:33:32 -080097 }
98
99 /**
Hall Liud666a892017-08-28 14:10:46 -0700100 * Create a new {@link MbmsStreamingSession} using the given subscription ID.
Robert Greenwalt4dded7a2016-12-05 16:33:32 -0800101 *
Hall Liu80233322017-05-02 15:06:29 -0700102 * Note that this call will bind a remote service. You may not call this method on your app's
Hall Liud666a892017-08-28 14:10:46 -0700103 * main thread.
Hall Liu563e150c2017-04-25 15:04:26 -0700104 *
Hall Liud666a892017-08-28 14:10:46 -0700105 * You may only have one instance of {@link MbmsStreamingSession} per UID. If you call this
106 * method while there is an active instance of {@link MbmsStreamingSession} in your process
107 * (in other words, one that has not had {@link #close()} called on it), this method will
108 * throw an {@link IllegalStateException}. If you call this method in a different process
Hall Liud5c955f2017-07-20 15:32:51 -0700109 * running under the same UID, an error will be indicated via
Hall Liud666a892017-08-28 14:10:46 -0700110 * {@link MbmsStreamingSessionCallback#onError(int, String)}.
Hall Liud5c955f2017-07-20 15:32:51 -0700111 *
112 * Note that initialization may fail asynchronously. If you wish to try again after you
Hall Liud666a892017-08-28 14:10:46 -0700113 * receive such an asynchronous error, you must call {@link #close()} on the instance of
114 * {@link MbmsStreamingSession} that you received before calling this method again.
Hall Liud5c955f2017-07-20 15:32:51 -0700115 *
Hall Liu80233322017-05-02 15:06:29 -0700116 * @param context The {@link Context} to use.
Hall Liu5b844872018-02-06 11:36:17 -0800117 * @param executor The executor on which you wish to execute callbacks.
118 * @param subscriptionId The subscription ID to use.
Hall Liu64a98f92017-07-14 13:39:54 -0700119 * @param callback A callback object on which you wish to receive results of asynchronous
Hall Liu80233322017-05-02 15:06:29 -0700120 * operations.
Hall Liud666a892017-08-28 14:10:46 -0700121 * @return An instance of {@link MbmsStreamingSession}, or null if an error occurred.
Robert Greenwalt4dded7a2016-12-05 16:33:32 -0800122 */
Hall Liud666a892017-08-28 14:10:46 -0700123 public static @Nullable MbmsStreamingSession create(@NonNull Context context,
Hall Liu5b844872018-02-06 11:36:17 -0800124 @NonNull Executor executor, int subscriptionId,
125 final @NonNull MbmsStreamingSessionCallback callback) {
Hall Liud5c955f2017-07-20 15:32:51 -0700126 if (!sIsInitialized.compareAndSet(false, true)) {
Hall Liud666a892017-08-28 14:10:46 -0700127 throw new IllegalStateException("Cannot create two instances of MbmsStreamingSession");
Hall Liud5c955f2017-07-20 15:32:51 -0700128 }
Hall Liu5b844872018-02-06 11:36:17 -0800129 MbmsStreamingSession session = new MbmsStreamingSession(context, executor,
130 subscriptionId, callback);
Hall Liud666a892017-08-28 14:10:46 -0700131
Hall Liu23d80af2017-09-01 17:59:15 -0700132 final int result = session.bindAndInitialize();
Hall Liue373ee52017-09-08 18:02:38 -0700133 if (result != MbmsErrors.SUCCESS) {
Hall Liud5c955f2017-07-20 15:32:51 -0700134 sIsInitialized.set(false);
Hall Liu5b844872018-02-06 11:36:17 -0800135 executor.execute(new Runnable() {
Hall Liud666a892017-08-28 14:10:46 -0700136 @Override
137 public void run() {
138 callback.onError(result, null);
139 }
140 });
141 return null;
Hall Liud5c955f2017-07-20 15:32:51 -0700142 }
Hall Liud666a892017-08-28 14:10:46 -0700143 return session;
Hall Liu563e150c2017-04-25 15:04:26 -0700144 }
145
146 /**
Hall Liud666a892017-08-28 14:10:46 -0700147 * Create a new {@link MbmsStreamingSession} using the system default data subscription ID.
Hall Liu5b844872018-02-06 11:36:17 -0800148 * See {@link #create(Context, Executor, int, MbmsStreamingSessionCallback)}.
Hall Liuee19cfc2017-08-03 18:26:39 -0700149 */
Hall Liud666a892017-08-28 14:10:46 -0700150 public static MbmsStreamingSession create(@NonNull Context context,
Hall Liu5b844872018-02-06 11:36:17 -0800151 @NonNull Executor executor, @NonNull MbmsStreamingSessionCallback callback) {
152 return create(context, executor, SubscriptionManager.getDefaultSubscriptionId(), callback);
Hall Liuee19cfc2017-08-03 18:26:39 -0700153 }
154
155 /**
Hall Liud666a892017-08-28 14:10:46 -0700156 * Terminates this instance. Also terminates
157 * any streaming services spawned from this instance as if
Hall Liu5b844872018-02-06 11:36:17 -0800158 * {@link StreamingService#close()} had been called on them. After this method returns,
Hall Liud666a892017-08-28 14:10:46 -0700159 * no further callbacks originating from the middleware will be enqueued on the provided
160 * instance of {@link MbmsStreamingSessionCallback}, but callbacks that have already been
161 * enqueued will still be delivered.
162 *
Hall Liu5b844872018-02-06 11:36:17 -0800163 * It is safe to call {@link #create(Context, Executor, int, MbmsStreamingSessionCallback)} to
Hall Liud666a892017-08-28 14:10:46 -0700164 * obtain another instance of {@link MbmsStreamingSession} immediately after this method
165 * returns.
Hall Liu46cbcd12017-07-07 13:33:16 -0700166 *
167 * May throw an {@link IllegalStateException}
Robert Greenwalt4dded7a2016-12-05 16:33:32 -0800168 */
Hall Liud666a892017-08-28 14:10:46 -0700169 public void close() {
Hall Liufa2115e2017-04-27 13:20:09 -0700170 try {
Hall Liud5c955f2017-07-20 15:32:51 -0700171 IMbmsStreamingService streamingService = mService.get();
Hall Liu718986d2019-08-29 15:42:47 -0700172 if (streamingService == null || mServiceConnection == null) {
Hall Liud5c955f2017-07-20 15:32:51 -0700173 // Ignore and return, assume already disposed.
174 return;
175 }
Hall Liu9f116ef2017-06-23 16:32:30 -0700176 streamingService.dispose(mSubscriptionId);
Hall Liud666a892017-08-28 14:10:46 -0700177 for (StreamingService s : mKnownActiveStreamingServices) {
178 s.getCallback().stop();
179 }
180 mKnownActiveStreamingServices.clear();
Hall Liu718986d2019-08-29 15:42:47 -0700181 mContext.unbindService(mServiceConnection);
Hall Liufa2115e2017-04-27 13:20:09 -0700182 } catch (RemoteException e) {
183 // Ignore for now
Hall Liud5c955f2017-07-20 15:32:51 -0700184 } finally {
185 mService.set(null);
186 sIsInitialized.set(false);
Hall Liu718986d2019-08-29 15:42:47 -0700187 mServiceConnection = null;
Hall Liud666a892017-08-28 14:10:46 -0700188 mInternalCallback.stop();
Hall Liufa2115e2017-04-27 13:20:09 -0700189 }
Robert Greenwalt4dded7a2016-12-05 16:33:32 -0800190 }
191
192 /**
193 * An inspection API to retrieve the list of streaming media currently be advertised.
Hall Liud666a892017-08-28 14:10:46 -0700194 * The results are returned asynchronously via
195 * {@link MbmsStreamingSessionCallback#onStreamingServicesUpdated(List)} on the callback
196 * provided upon creation.
Robert Greenwalt4dded7a2016-12-05 16:33:32 -0800197 *
Hall Liud666a892017-08-28 14:10:46 -0700198 * Multiple calls replace the list of service classes of interest.
Robert Greenwaltd447cea2017-04-21 20:30:14 -0700199 *
Hall Liud666a892017-08-28 14:10:46 -0700200 * May throw an {@link IllegalArgumentException} or an {@link IllegalStateException}.
Robert Greenwaltd447cea2017-04-21 20:30:14 -0700201 *
Hall Liud666a892017-08-28 14:10:46 -0700202 * @param serviceClassList A list of streaming service classes that the app would like updates
203 * on. The exact names of these classes should be negotiated with the
204 * wireless carrier separately.
Robert Greenwalt4dded7a2016-12-05 16:33:32 -0800205 */
Hall Liud666a892017-08-28 14:10:46 -0700206 public void requestUpdateStreamingServices(List<String> serviceClassList) {
Hall Liu727a05b2017-06-16 14:59:57 -0700207 IMbmsStreamingService streamingService = mService.get();
208 if (streamingService == null) {
Hall Liud666a892017-08-28 14:10:46 -0700209 throw new IllegalStateException("Middleware not yet bound");
Hall Liu80233322017-05-02 15:06:29 -0700210 }
211 try {
Hall Liud666a892017-08-28 14:10:46 -0700212 int returnCode = streamingService.requestUpdateStreamingServices(
213 mSubscriptionId, serviceClassList);
Hall Liu17449f92018-03-28 15:54:07 -0700214 if (returnCode == MbmsErrors.UNKNOWN) {
215 // Unbind and throw an obvious error
216 close();
217 throw new IllegalStateException("Middleware must not return an unknown error code");
218 }
Hall Liue373ee52017-09-08 18:02:38 -0700219 if (returnCode != MbmsErrors.SUCCESS) {
Hall Liud666a892017-08-28 14:10:46 -0700220 sendErrorToApp(returnCode, null);
Hall Liu80233322017-05-02 15:06:29 -0700221 }
Hall Liu80a86872017-05-26 15:49:32 -0700222 } catch (RemoteException e) {
Hall Liuedbd4562017-05-17 18:15:27 -0700223 Log.w(LOG_TAG, "Remote process died");
Hall Liu727a05b2017-06-16 14:59:57 -0700224 mService.set(null);
Hall Liud5c955f2017-07-20 15:32:51 -0700225 sIsInitialized.set(false);
Hall Liue373ee52017-09-08 18:02:38 -0700226 sendErrorToApp(MbmsErrors.ERROR_MIDDLEWARE_LOST, null);
Hall Liu80233322017-05-02 15:06:29 -0700227 }
Robert Greenwalt4dded7a2016-12-05 16:33:32 -0800228 }
229
230 /**
Hall Liuee19cfc2017-08-03 18:26:39 -0700231 * Starts streaming a requested service, reporting status to the indicated callback.
Hall Liufb1ee0e2017-05-11 13:32:32 -0700232 * Returns an object used to control that stream. The stream may not be ready for consumption
233 * immediately upon return from this method -- wait until the streaming state has been
Hall Liu6e1d2fee2017-06-30 14:37:30 -0700234 * reported via
Hall Liuee19cfc2017-08-03 18:26:39 -0700235 * {@link android.telephony.mbms.StreamingServiceCallback#onStreamStateUpdated(int, int)}
Robert Greenwalt4dded7a2016-12-05 16:33:32 -0800236 *
Hall Liud666a892017-08-28 14:10:46 -0700237 * May throw an {@link IllegalArgumentException} or an {@link IllegalStateException}
Robert Greenwaltd447cea2017-04-21 20:30:14 -0700238 *
Hall Liuee19cfc2017-08-03 18:26:39 -0700239 * Asynchronous errors through the callback include any of the errors in
Hall Liue373ee52017-09-08 18:02:38 -0700240 * {@link MbmsErrors.GeneralErrors} or
241 * {@link MbmsErrors.StreamingErrors}.
Hall Liu46cbcd12017-07-07 13:33:16 -0700242 *
243 * @param serviceInfo The information about the service to stream.
Hall Liu5b844872018-02-06 11:36:17 -0800244 * @param executor The executor on which you wish to execute callbacks for this stream.
Hall Liuee19cfc2017-08-03 18:26:39 -0700245 * @param callback A callback that'll be called when something about the stream changes.
Hall Liu46cbcd12017-07-07 13:33:16 -0700246 * @return An instance of {@link StreamingService} through which the stream can be controlled.
Hall Liud666a892017-08-28 14:10:46 -0700247 * May be {@code null} if an error occurred.
Robert Greenwalt4dded7a2016-12-05 16:33:32 -0800248 */
Hall Liud666a892017-08-28 14:10:46 -0700249 public @Nullable StreamingService startStreaming(StreamingServiceInfo serviceInfo,
Hall Liu5b844872018-02-06 11:36:17 -0800250 @NonNull Executor executor, StreamingServiceCallback callback) {
Hall Liu727a05b2017-06-16 14:59:57 -0700251 IMbmsStreamingService streamingService = mService.get();
252 if (streamingService == null) {
Hall Liud666a892017-08-28 14:10:46 -0700253 throw new IllegalStateException("Middleware not yet bound");
Hall Liufb1ee0e2017-05-11 13:32:32 -0700254 }
Robert Greenwalt4dded7a2016-12-05 16:33:32 -0800255
Hall Liuee19cfc2017-08-03 18:26:39 -0700256 InternalStreamingServiceCallback serviceCallback = new InternalStreamingServiceCallback(
Hall Liu5b844872018-02-06 11:36:17 -0800257 callback, executor);
Hall Liuee19cfc2017-08-03 18:26:39 -0700258
259 StreamingService serviceForApp = new StreamingService(
Hall Liud666a892017-08-28 14:10:46 -0700260 mSubscriptionId, streamingService, this, serviceInfo, serviceCallback);
261 mKnownActiveStreamingServices.add(serviceForApp);
Hall Liuee19cfc2017-08-03 18:26:39 -0700262
Hall Liufb1ee0e2017-05-11 13:32:32 -0700263 try {
Hall Liu727a05b2017-06-16 14:59:57 -0700264 int returnCode = streamingService.startStreaming(
Hall Liuee19cfc2017-08-03 18:26:39 -0700265 mSubscriptionId, serviceInfo.getServiceId(), serviceCallback);
Hall Liu17449f92018-03-28 15:54:07 -0700266 if (returnCode == MbmsErrors.UNKNOWN) {
267 // Unbind and throw an obvious error
268 close();
269 throw new IllegalStateException("Middleware must not return an unknown error code");
270 }
Hall Liue373ee52017-09-08 18:02:38 -0700271 if (returnCode != MbmsErrors.SUCCESS) {
Hall Liud666a892017-08-28 14:10:46 -0700272 sendErrorToApp(returnCode, null);
273 return null;
Hall Liufb1ee0e2017-05-11 13:32:32 -0700274 }
Hall Liu80a86872017-05-26 15:49:32 -0700275 } catch (RemoteException e) {
Hall Liuedbd4562017-05-17 18:15:27 -0700276 Log.w(LOG_TAG, "Remote process died");
Hall Liu727a05b2017-06-16 14:59:57 -0700277 mService.set(null);
Hall Liud5c955f2017-07-20 15:32:51 -0700278 sIsInitialized.set(false);
Hall Liue373ee52017-09-08 18:02:38 -0700279 sendErrorToApp(MbmsErrors.ERROR_MIDDLEWARE_LOST, null);
Hall Liud666a892017-08-28 14:10:46 -0700280 return null;
Hall Liufb1ee0e2017-05-11 13:32:32 -0700281 }
282
Hall Liuee19cfc2017-08-03 18:26:39 -0700283 return serviceForApp;
Robert Greenwalt4dded7a2016-12-05 16:33:32 -0800284 }
285
Hall Liud666a892017-08-28 14:10:46 -0700286 /** @hide */
287 public void onStreamingServiceStopped(StreamingService service) {
288 mKnownActiveStreamingServices.remove(service);
289 }
290
291 private int bindAndInitialize() {
Hall Liu718986d2019-08-29 15:42:47 -0700292 mServiceConnection = new ServiceConnection() {
293 @Override
294 public void onServiceConnected(ComponentName name, IBinder service) {
295 IMbmsStreamingService streamingService =
296 IMbmsStreamingService.Stub.asInterface(service);
297 int result;
298 try {
299 result = streamingService.initialize(mInternalCallback,
300 mSubscriptionId);
301 } catch (RemoteException e) {
302 Log.e(LOG_TAG, "Service died before initialization");
303 sendErrorToApp(
304 MbmsErrors.InitializationErrors.ERROR_UNABLE_TO_INITIALIZE,
305 e.toString());
306 sIsInitialized.set(false);
307 return;
308 } catch (RuntimeException e) {
309 Log.e(LOG_TAG, "Runtime exception during initialization");
310 sendErrorToApp(
311 MbmsErrors.InitializationErrors.ERROR_UNABLE_TO_INITIALIZE,
312 e.toString());
313 sIsInitialized.set(false);
314 return;
315 }
316 if (result == MbmsErrors.UNKNOWN) {
317 // Unbind and throw an obvious error
318 close();
319 throw new IllegalStateException("Middleware must not return"
320 + " an unknown error code");
321 }
322 if (result != MbmsErrors.SUCCESS) {
323 sendErrorToApp(result, "Error returned during initialization");
324 sIsInitialized.set(false);
325 return;
326 }
327 try {
328 streamingService.asBinder().linkToDeath(mDeathRecipient, 0);
329 } catch (RemoteException e) {
330 sendErrorToApp(MbmsErrors.ERROR_MIDDLEWARE_LOST,
331 "Middleware lost during initialization");
332 sIsInitialized.set(false);
333 return;
334 }
335 mService.set(streamingService);
336 }
Hall Liufa2115e2017-04-27 13:20:09 -0700337
Hall Liu718986d2019-08-29 15:42:47 -0700338 @Override
339 public void onServiceDisconnected(ComponentName name) {
340 sIsInitialized.set(false);
341 mService.set(null);
342 }
343
344 @Override
345 public void onNullBinding(ComponentName name) {
346 Log.w(LOG_TAG, "bindAndInitialize: Remote service returned null");
347 sendErrorToApp(MbmsErrors.ERROR_MIDDLEWARE_LOST,
348 "Middleware service binding returned null");
349 sIsInitialized.set(false);
350 mService.set(null);
351 mContext.unbindService(this);
352 }
353 };
354 return MbmsUtils.startBinding(mContext, MBMS_STREAMING_SERVICE_ACTION, mServiceConnection);
Hall Liufa2115e2017-04-27 13:20:09 -0700355 }
Hall Liud5c955f2017-07-20 15:32:51 -0700356
357 private void sendErrorToApp(int errorCode, String message) {
358 try {
Hall Liud666a892017-08-28 14:10:46 -0700359 mInternalCallback.onError(errorCode, message);
Hall Liud5c955f2017-07-20 15:32:51 -0700360 } catch (RemoteException e) {
361 // Ignore, should not happen locally.
362 }
363 }
Robert Greenwalt4dded7a2016-12-05 16:33:32 -0800364}