Fix lint errors in the streaming API

Fix the errors that cropped up when trying to upload the unhide CL in
MR1.

Bug: 30981736
Test: manual, with testapps
Change-Id: I94e1bcccea4b9f50dae4c93f247ab78058d15bb5
diff --git a/api/current.txt b/api/current.txt
index 739e7f2..5168c6b 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -37822,11 +37822,12 @@
   }
 
   public class MbmsStreamingManager {
-    method public static android.telephony.MbmsStreamingManager create(android.content.Context, android.telephony.mbms.MbmsStreamingManagerCallback, int) throws android.telephony.mbms.MbmsException;
+    method public static android.telephony.MbmsStreamingManager create(android.content.Context, android.telephony.mbms.MbmsStreamingManagerCallback, int, android.os.Handler) throws android.telephony.mbms.MbmsException;
+    method public static android.telephony.MbmsStreamingManager create(android.content.Context, android.telephony.mbms.MbmsStreamingManagerCallback, android.os.Handler) throws android.telephony.mbms.MbmsException;
     method public static android.telephony.MbmsStreamingManager create(android.content.Context, android.telephony.mbms.MbmsStreamingManagerCallback) throws android.telephony.mbms.MbmsException;
     method public void dispose();
     method public void getStreamingServices(java.util.List<java.lang.String>) throws android.telephony.mbms.MbmsException;
-    method public android.telephony.mbms.StreamingService startStreaming(android.telephony.mbms.StreamingServiceInfo, android.telephony.mbms.StreamingServiceCallback) throws android.telephony.mbms.MbmsException;
+    method public android.telephony.mbms.StreamingService startStreaming(android.telephony.mbms.StreamingServiceInfo, android.telephony.mbms.StreamingServiceCallback, android.os.Handler) throws android.telephony.mbms.MbmsException;
   }
 
   public class NeighboringCellInfo implements android.os.Parcelable {
@@ -38452,7 +38453,6 @@
   }
 
   public static class MbmsException.GeneralErrors {
-    ctor public MbmsException.GeneralErrors();
     field public static final int ERROR_CARRIER_CHANGE_NOT_ALLOWED = 207; // 0xcf
     field public static final int ERROR_IN_E911 = 204; // 0xcc
     field public static final int ERROR_MIDDLEWARE_NOT_YET_READY = 201; // 0xc9
@@ -38463,36 +38463,31 @@
   }
 
   public static class MbmsException.InitializationErrors {
-    ctor public MbmsException.InitializationErrors();
     field public static final int ERROR_APP_PERMISSIONS_NOT_GRANTED = 102; // 0x66
     field public static final int ERROR_DUPLICATE_INITIALIZE = 101; // 0x65
     field public static final int ERROR_UNABLE_TO_INITIALIZE = 103; // 0x67
   }
 
   public static class MbmsException.StreamingErrors {
-    ctor public MbmsException.StreamingErrors();
     field public static final int ERROR_CONCURRENT_SERVICE_LIMIT_REACHED = 301; // 0x12d
     field public static final int ERROR_DUPLICATE_START_STREAM = 303; // 0x12f
     field public static final int ERROR_UNABLE_TO_START_SERVICE = 302; // 0x12e
   }
 
-  public class MbmsStreamingManagerCallback extends android.os.Binder {
+  public class MbmsStreamingManagerCallback {
     ctor public MbmsStreamingManagerCallback();
-    method public void error(int, java.lang.String) throws android.os.RemoteException;
-    method public void middlewareReady() throws android.os.RemoteException;
-    method public void streamingServicesUpdated(java.util.List<android.telephony.mbms.StreamingServiceInfo>) throws android.os.RemoteException;
+    method public void onError(int, java.lang.String);
+    method public void onMiddlewareReady();
+    method public void onStreamingServicesUpdated(java.util.List<android.telephony.mbms.StreamingServiceInfo>);
   }
 
-  public class ServiceInfo implements android.os.Parcelable {
-    method public int describeContents();
+  public class ServiceInfo {
     method public java.lang.String getClassName();
     method public java.util.List<java.util.Locale> getLocales();
     method public java.util.Map<java.util.Locale, java.lang.String> getNames();
     method public java.lang.String getServiceId();
     method public java.util.Date getSessionEndTime();
     method public java.util.Date getSessionStartTime();
-    method public void writeToParcel(android.os.Parcel, int);
-    field public static final android.os.Parcelable.Creator<android.telephony.mbms.ServiceInfo> CREATOR;
   }
 
   public class StreamingService {
@@ -38514,17 +38509,19 @@
     field public static final int UNICAST_METHOD = 2; // 0x2
   }
 
-  public class StreamingServiceCallback extends android.os.Binder {
+  public class StreamingServiceCallback {
     ctor public StreamingServiceCallback();
-    method public void broadcastSignalStrengthUpdated(int) throws android.os.RemoteException;
-    method public void error(int, java.lang.String) throws android.os.RemoteException;
-    method public void mediaDescriptionUpdated() throws android.os.RemoteException;
-    method public void streamMethodUpdated(int) throws android.os.RemoteException;
-    method public void streamStateUpdated(int, int) throws android.os.RemoteException;
+    method public void onBroadcastSignalStrengthUpdated(int);
+    method public void onError(int, java.lang.String);
+    method public void onMediaDescriptionUpdated();
+    method public void onStreamMethodUpdated(int);
+    method public void onStreamStateUpdated(int, int);
     field public static final int SIGNAL_STRENGTH_UNAVAILABLE = -1; // 0xffffffff
   }
 
-  public class StreamingServiceInfo extends android.telephony.mbms.ServiceInfo implements android.os.Parcelable {
+  public final class StreamingServiceInfo extends android.telephony.mbms.ServiceInfo implements android.os.Parcelable {
+    method public int describeContents();
+    method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.telephony.mbms.StreamingServiceInfo> CREATOR;
   }
 
diff --git a/api/system-current.txt b/api/system-current.txt
index 0aa5d58..a7205c8 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -40993,11 +40993,12 @@
   }
 
   public class MbmsStreamingManager {
-    method public static android.telephony.MbmsStreamingManager create(android.content.Context, android.telephony.mbms.MbmsStreamingManagerCallback, int) throws android.telephony.mbms.MbmsException;
+    method public static android.telephony.MbmsStreamingManager create(android.content.Context, android.telephony.mbms.MbmsStreamingManagerCallback, int, android.os.Handler) throws android.telephony.mbms.MbmsException;
+    method public static android.telephony.MbmsStreamingManager create(android.content.Context, android.telephony.mbms.MbmsStreamingManagerCallback, android.os.Handler) throws android.telephony.mbms.MbmsException;
     method public static android.telephony.MbmsStreamingManager create(android.content.Context, android.telephony.mbms.MbmsStreamingManagerCallback) throws android.telephony.mbms.MbmsException;
     method public void dispose();
     method public void getStreamingServices(java.util.List<java.lang.String>) throws android.telephony.mbms.MbmsException;
-    method public android.telephony.mbms.StreamingService startStreaming(android.telephony.mbms.StreamingServiceInfo, android.telephony.mbms.StreamingServiceCallback) throws android.telephony.mbms.MbmsException;
+    method public android.telephony.mbms.StreamingService startStreaming(android.telephony.mbms.StreamingServiceInfo, android.telephony.mbms.StreamingServiceCallback, android.os.Handler) throws android.telephony.mbms.MbmsException;
     field public static final java.lang.String MBMS_STREAMING_SERVICE_ACTION = "android.telephony.action.EmbmsStreaming";
   }
 
@@ -41707,7 +41708,6 @@
   }
 
   public static class MbmsException.GeneralErrors {
-    ctor public MbmsException.GeneralErrors();
     field public static final int ERROR_CARRIER_CHANGE_NOT_ALLOWED = 207; // 0xcf
     field public static final int ERROR_IN_E911 = 204; // 0xcc
     field public static final int ERROR_MIDDLEWARE_NOT_YET_READY = 201; // 0xc9
@@ -41718,36 +41718,31 @@
   }
 
   public static class MbmsException.InitializationErrors {
-    ctor public MbmsException.InitializationErrors();
     field public static final int ERROR_APP_PERMISSIONS_NOT_GRANTED = 102; // 0x66
     field public static final int ERROR_DUPLICATE_INITIALIZE = 101; // 0x65
     field public static final int ERROR_UNABLE_TO_INITIALIZE = 103; // 0x67
   }
 
   public static class MbmsException.StreamingErrors {
-    ctor public MbmsException.StreamingErrors();
     field public static final int ERROR_CONCURRENT_SERVICE_LIMIT_REACHED = 301; // 0x12d
     field public static final int ERROR_DUPLICATE_START_STREAM = 303; // 0x12f
     field public static final int ERROR_UNABLE_TO_START_SERVICE = 302; // 0x12e
   }
 
-  public class MbmsStreamingManagerCallback extends android.os.Binder {
+  public class MbmsStreamingManagerCallback {
     ctor public MbmsStreamingManagerCallback();
-    method public void error(int, java.lang.String) throws android.os.RemoteException;
-    method public void middlewareReady() throws android.os.RemoteException;
-    method public void streamingServicesUpdated(java.util.List<android.telephony.mbms.StreamingServiceInfo>) throws android.os.RemoteException;
+    method public void onError(int, java.lang.String);
+    method public void onMiddlewareReady();
+    method public void onStreamingServicesUpdated(java.util.List<android.telephony.mbms.StreamingServiceInfo>);
   }
 
-  public class ServiceInfo implements android.os.Parcelable {
-    method public int describeContents();
+  public class ServiceInfo {
     method public java.lang.String getClassName();
     method public java.util.List<java.util.Locale> getLocales();
     method public java.util.Map<java.util.Locale, java.lang.String> getNames();
     method public java.lang.String getServiceId();
     method public java.util.Date getSessionEndTime();
     method public java.util.Date getSessionStartTime();
-    method public void writeToParcel(android.os.Parcel, int);
-    field public static final android.os.Parcelable.Creator<android.telephony.mbms.ServiceInfo> CREATOR;
   }
 
   public class StreamingService {
@@ -41769,18 +41764,20 @@
     field public static final int UNICAST_METHOD = 2; // 0x2
   }
 
-  public class StreamingServiceCallback extends android.os.Binder {
+  public class StreamingServiceCallback {
     ctor public StreamingServiceCallback();
-    method public void broadcastSignalStrengthUpdated(int) throws android.os.RemoteException;
-    method public void error(int, java.lang.String) throws android.os.RemoteException;
-    method public void mediaDescriptionUpdated() throws android.os.RemoteException;
-    method public void streamMethodUpdated(int) throws android.os.RemoteException;
-    method public void streamStateUpdated(int, int) throws android.os.RemoteException;
+    method public void onBroadcastSignalStrengthUpdated(int);
+    method public void onError(int, java.lang.String);
+    method public void onMediaDescriptionUpdated();
+    method public void onStreamMethodUpdated(int);
+    method public void onStreamStateUpdated(int, int);
     field public static final int SIGNAL_STRENGTH_UNAVAILABLE = -1; // 0xffffffff
   }
 
-  public class StreamingServiceInfo extends android.telephony.mbms.ServiceInfo implements android.os.Parcelable {
+  public final class StreamingServiceInfo extends android.telephony.mbms.ServiceInfo implements android.os.Parcelable {
     ctor public StreamingServiceInfo(java.util.Map<java.util.Locale, java.lang.String>, java.lang.String, java.util.List<java.util.Locale>, java.lang.String, java.util.Date, java.util.Date);
+    method public int describeContents();
+    method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.telephony.mbms.StreamingServiceInfo> CREATOR;
   }
 
@@ -41795,6 +41792,7 @@
     method public android.net.Uri getPlaybackUri(int, java.lang.String) throws android.os.RemoteException;
     method public int getStreamingServices(int, java.util.List<java.lang.String>) throws android.os.RemoteException;
     method public int initialize(android.telephony.mbms.MbmsStreamingManagerCallback, int) throws android.os.RemoteException;
+    method public void onAppCallbackDied(int, int);
     method public int startStreaming(int, java.lang.String, android.telephony.mbms.StreamingServiceCallback) throws android.os.RemoteException;
     method public void stopStreaming(int, java.lang.String) throws android.os.RemoteException;
   }
diff --git a/api/test-current.txt b/api/test-current.txt
index 93c9768..da1d5ee 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -37921,11 +37921,12 @@
   }
 
   public class MbmsStreamingManager {
-    method public static android.telephony.MbmsStreamingManager create(android.content.Context, android.telephony.mbms.MbmsStreamingManagerCallback, int) throws android.telephony.mbms.MbmsException;
+    method public static android.telephony.MbmsStreamingManager create(android.content.Context, android.telephony.mbms.MbmsStreamingManagerCallback, int, android.os.Handler) throws android.telephony.mbms.MbmsException;
+    method public static android.telephony.MbmsStreamingManager create(android.content.Context, android.telephony.mbms.MbmsStreamingManagerCallback, android.os.Handler) throws android.telephony.mbms.MbmsException;
     method public static android.telephony.MbmsStreamingManager create(android.content.Context, android.telephony.mbms.MbmsStreamingManagerCallback) throws android.telephony.mbms.MbmsException;
     method public void dispose();
     method public void getStreamingServices(java.util.List<java.lang.String>) throws android.telephony.mbms.MbmsException;
-    method public android.telephony.mbms.StreamingService startStreaming(android.telephony.mbms.StreamingServiceInfo, android.telephony.mbms.StreamingServiceCallback) throws android.telephony.mbms.MbmsException;
+    method public android.telephony.mbms.StreamingService startStreaming(android.telephony.mbms.StreamingServiceInfo, android.telephony.mbms.StreamingServiceCallback, android.os.Handler) throws android.telephony.mbms.MbmsException;
   }
 
   public class NeighboringCellInfo implements android.os.Parcelable {
@@ -38551,7 +38552,6 @@
   }
 
   public static class MbmsException.GeneralErrors {
-    ctor public MbmsException.GeneralErrors();
     field public static final int ERROR_CARRIER_CHANGE_NOT_ALLOWED = 207; // 0xcf
     field public static final int ERROR_IN_E911 = 204; // 0xcc
     field public static final int ERROR_MIDDLEWARE_NOT_YET_READY = 201; // 0xc9
@@ -38562,36 +38562,31 @@
   }
 
   public static class MbmsException.InitializationErrors {
-    ctor public MbmsException.InitializationErrors();
     field public static final int ERROR_APP_PERMISSIONS_NOT_GRANTED = 102; // 0x66
     field public static final int ERROR_DUPLICATE_INITIALIZE = 101; // 0x65
     field public static final int ERROR_UNABLE_TO_INITIALIZE = 103; // 0x67
   }
 
   public static class MbmsException.StreamingErrors {
-    ctor public MbmsException.StreamingErrors();
     field public static final int ERROR_CONCURRENT_SERVICE_LIMIT_REACHED = 301; // 0x12d
     field public static final int ERROR_DUPLICATE_START_STREAM = 303; // 0x12f
     field public static final int ERROR_UNABLE_TO_START_SERVICE = 302; // 0x12e
   }
 
-  public class MbmsStreamingManagerCallback extends android.os.Binder {
+  public class MbmsStreamingManagerCallback {
     ctor public MbmsStreamingManagerCallback();
-    method public void error(int, java.lang.String) throws android.os.RemoteException;
-    method public void middlewareReady() throws android.os.RemoteException;
-    method public void streamingServicesUpdated(java.util.List<android.telephony.mbms.StreamingServiceInfo>) throws android.os.RemoteException;
+    method public void onError(int, java.lang.String);
+    method public void onMiddlewareReady();
+    method public void onStreamingServicesUpdated(java.util.List<android.telephony.mbms.StreamingServiceInfo>);
   }
 
-  public class ServiceInfo implements android.os.Parcelable {
-    method public int describeContents();
+  public class ServiceInfo {
     method public java.lang.String getClassName();
     method public java.util.List<java.util.Locale> getLocales();
     method public java.util.Map<java.util.Locale, java.lang.String> getNames();
     method public java.lang.String getServiceId();
     method public java.util.Date getSessionEndTime();
     method public java.util.Date getSessionStartTime();
-    method public void writeToParcel(android.os.Parcel, int);
-    field public static final android.os.Parcelable.Creator<android.telephony.mbms.ServiceInfo> CREATOR;
   }
 
   public class StreamingService {
@@ -38613,17 +38608,19 @@
     field public static final int UNICAST_METHOD = 2; // 0x2
   }
 
-  public class StreamingServiceCallback extends android.os.Binder {
+  public class StreamingServiceCallback {
     ctor public StreamingServiceCallback();
-    method public void broadcastSignalStrengthUpdated(int) throws android.os.RemoteException;
-    method public void error(int, java.lang.String) throws android.os.RemoteException;
-    method public void mediaDescriptionUpdated() throws android.os.RemoteException;
-    method public void streamMethodUpdated(int) throws android.os.RemoteException;
-    method public void streamStateUpdated(int, int) throws android.os.RemoteException;
+    method public void onBroadcastSignalStrengthUpdated(int);
+    method public void onError(int, java.lang.String);
+    method public void onMediaDescriptionUpdated();
+    method public void onStreamMethodUpdated(int);
+    method public void onStreamStateUpdated(int, int);
     field public static final int SIGNAL_STRENGTH_UNAVAILABLE = -1; // 0xffffffff
   }
 
-  public class StreamingServiceInfo extends android.telephony.mbms.ServiceInfo implements android.os.Parcelable {
+  public final class StreamingServiceInfo extends android.telephony.mbms.ServiceInfo implements android.os.Parcelable {
+    method public int describeContents();
+    method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.telephony.mbms.StreamingServiceInfo> CREATOR;
   }
 
diff --git a/telephony/java/android/telephony/MbmsStreamingManager.java b/telephony/java/android/telephony/MbmsStreamingManager.java
index d69562c..c6cc568 100644
--- a/telephony/java/android/telephony/MbmsStreamingManager.java
+++ b/telephony/java/android/telephony/MbmsStreamingManager.java
@@ -21,8 +21,12 @@
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.ServiceConnection;
+import android.os.Handler;
 import android.os.IBinder;
+import android.os.Looper;
 import android.os.RemoteException;
+import android.telephony.mbms.InternalStreamingManagerCallback;
+import android.telephony.mbms.InternalStreamingServiceCallback;
 import android.telephony.mbms.MbmsException;
 import android.telephony.mbms.MbmsStreamingManagerCallback;
 import android.telephony.mbms.MbmsUtils;
@@ -54,17 +58,20 @@
             "android.telephony.action.EmbmsStreaming";
 
     private AtomicReference<IMbmsStreamingService> mService = new AtomicReference<>(null);
-    private MbmsStreamingManagerCallback mCallbackToApp;
+    private InternalStreamingManagerCallback mInternalCallback;
 
     private final Context mContext;
     private int mSubscriptionId = INVALID_SUBSCRIPTION_ID;
 
     /** @hide */
     private MbmsStreamingManager(Context context, MbmsStreamingManagerCallback callback,
-                    int subscriptionId) {
+                    int subscriptionId, Handler handler) {
         mContext = context;
-        mCallbackToApp = callback;
         mSubscriptionId = subscriptionId;
+        if (handler == null) {
+            handler = new Handler(Looper.getMainLooper());
+        }
+        mInternalCallback = new InternalStreamingManagerCallback(callback, handler);
     }
 
     /**
@@ -78,23 +85,38 @@
      * @param callback A callback object on which you wish to receive results of asynchronous
      *                 operations.
      * @param subscriptionId The subscription ID to use.
+     * @param handler The handler you wish to receive callbacks on. If null, callbacks will be
+     *                processed on the main looper (in other words, the looper returned from
+     *                {@link Looper#getMainLooper()}).
      */
     public static MbmsStreamingManager create(Context context,
-            MbmsStreamingManagerCallback callback, int subscriptionId)
+            MbmsStreamingManagerCallback callback, int subscriptionId, Handler handler)
             throws MbmsException {
-        MbmsStreamingManager manager = new MbmsStreamingManager(context, callback, subscriptionId);
+        MbmsStreamingManager manager = new MbmsStreamingManager(context, callback,
+                subscriptionId, handler);
         manager.bindAndInitialize();
         return manager;
     }
 
     /**
      * Create a new MbmsStreamingManager using the system default data subscription ID.
-     * See {@link #create(Context, MbmsStreamingManagerCallback, int)}.
+     * See {@link #create(Context, MbmsStreamingManagerCallback, int, Handler)}.
+     */
+    public static MbmsStreamingManager create(Context context,
+            MbmsStreamingManagerCallback callback, Handler handler)
+            throws MbmsException {
+        return create(context, callback, SubscriptionManager.getDefaultSubscriptionId(), handler);
+    }
+
+    /**
+     * Create a new MbmsStreamingManager using the system default data subscription ID and
+     * default {@link Handler}.
+     * See {@link #create(Context, MbmsStreamingManagerCallback, int, Handler)}.
      */
     public static MbmsStreamingManager create(Context context,
             MbmsStreamingManagerCallback callback)
             throws MbmsException {
-        return create(context, callback, SubscriptionManager.getDefaultSubscriptionId());
+        return create(context, callback, SubscriptionManager.getDefaultSubscriptionId(), null);
     }
 
     /**
@@ -153,11 +175,11 @@
     }
 
     /**
-     * Starts streaming a requested service, reporting status to the indicated listener.
+     * Starts streaming a requested service, reporting status to the indicated callback.
      * Returns an object used to control that stream. The stream may not be ready for consumption
      * immediately upon return from this method -- wait until the streaming state has been
      * reported via
-     * {@link android.telephony.mbms.StreamingServiceCallback#streamStateUpdated(int, int)}
+     * {@link android.telephony.mbms.StreamingServiceCallback#onStreamStateUpdated(int, int)}
      *
      * May throw an
      * {@link MbmsException} containing any of the error codes in
@@ -167,24 +189,33 @@
      *
      * May also throw an {@link IllegalArgumentException} or an {@link IllegalStateException}
      *
-     * Asynchronous errors through the listener include any of the errors in
+     * Asynchronous errors through the callback include any of the errors in
      * {@link android.telephony.mbms.MbmsException.GeneralErrors} or
      * {@link android.telephony.mbms.MbmsException.StreamingErrors}.
      *
      * @param serviceInfo The information about the service to stream.
-     * @param listener A listener that'll be called when something about the stream changes.
+     * @param callback A callback that'll be called when something about the stream changes.
+     * @param handler A handler that calls to {@code callback} should be called on. If null,
+     *                defaults to the handler provided via
+     *                {@link #create(Context, MbmsStreamingManagerCallback, int, Handler)}.
      * @return An instance of {@link StreamingService} through which the stream can be controlled.
      */
     public StreamingService startStreaming(StreamingServiceInfo serviceInfo,
-            StreamingServiceCallback listener) throws MbmsException {
+            StreamingServiceCallback callback, Handler handler) throws MbmsException {
         IMbmsStreamingService streamingService = mService.get();
         if (streamingService == null) {
             throw new MbmsException(MbmsException.ERROR_MIDDLEWARE_NOT_BOUND);
         }
 
+        InternalStreamingServiceCallback serviceCallback = new InternalStreamingServiceCallback(
+                callback, handler == null ? mInternalCallback.getHandler() : handler);
+
+        StreamingService serviceForApp = new StreamingService(
+                mSubscriptionId, streamingService, serviceInfo, serviceCallback);
+
         try {
             int returnCode = streamingService.startStreaming(
-                    mSubscriptionId, serviceInfo.getServiceId(), listener);
+                    mSubscriptionId, serviceInfo.getServiceId(), serviceCallback);
             if (returnCode != MbmsException.SUCCESS) {
                 throw new MbmsException(returnCode);
             }
@@ -194,7 +225,7 @@
             throw new MbmsException(MbmsException.ERROR_MIDDLEWARE_LOST);
         }
 
-        return new StreamingService(mSubscriptionId, streamingService, serviceInfo, listener);
+        return serviceForApp;
     }
 
     private void bindAndInitialize() throws MbmsException {
@@ -206,14 +237,15 @@
                                 IMbmsStreamingService.Stub.asInterface(service);
                         int result;
                         try {
-                            result = streamingService.initialize(mCallbackToApp, mSubscriptionId);
+                            result = streamingService.initialize(mInternalCallback,
+                                    mSubscriptionId);
                         } catch (RemoteException e) {
                             Log.e(LOG_TAG, "Service died before initialization");
                             return;
                         } catch (RuntimeException e) {
                             Log.e(LOG_TAG, "Runtime exception during initialization");
                             try {
-                                mCallbackToApp.error(
+                                mInternalCallback.error(
                                         MbmsException.InitializationErrors
                                                 .ERROR_UNABLE_TO_INITIALIZE,
                                         e.toString());
@@ -224,7 +256,7 @@
                         }
                         if (result != MbmsException.SUCCESS) {
                             try {
-                                mCallbackToApp.error(
+                                mInternalCallback.error(
                                         result, "Error returned during initialization");
                             } catch (RemoteException e) {
                                 // ignore
diff --git a/telephony/java/android/telephony/mbms/InternalStreamingManagerCallback.java b/telephony/java/android/telephony/mbms/InternalStreamingManagerCallback.java
new file mode 100644
index 0000000..b52df8c
--- /dev/null
+++ b/telephony/java/android/telephony/mbms/InternalStreamingManagerCallback.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package android.telephony.mbms;
+
+import android.os.Handler;
+import android.os.RemoteException;
+import android.telephony.mbms.IMbmsStreamingManagerCallback;
+import android.telephony.mbms.MbmsStreamingManagerCallback;
+import android.telephony.mbms.StreamingServiceInfo;
+
+import java.util.List;
+
+/** @hide */
+public class InternalStreamingManagerCallback extends IMbmsStreamingManagerCallback.Stub {
+    private final Handler mHandler;
+    private final MbmsStreamingManagerCallback mAppCallback;
+
+    public InternalStreamingManagerCallback(MbmsStreamingManagerCallback appCallback,
+            Handler handler) {
+        mAppCallback = appCallback;
+        mHandler = handler;
+    }
+
+    @Override
+    public void error(int errorCode, String message) throws RemoteException {
+        mHandler.post(new Runnable() {
+            @Override
+            public void run() {
+                mAppCallback.onError(errorCode, message);
+            }
+        });
+    }
+
+    @Override
+    public void streamingServicesUpdated(List<StreamingServiceInfo> services)
+            throws RemoteException {
+        mHandler.post(new Runnable() {
+            @Override
+            public void run() {
+                mAppCallback.onStreamingServicesUpdated(services);
+            }
+        });
+    }
+
+    @Override
+    public void middlewareReady() throws RemoteException {
+        mHandler.post(new Runnable() {
+            @Override
+            public void run() {
+                mAppCallback.onMiddlewareReady();
+            }
+        });
+    }
+
+    public Handler getHandler() {
+        return mHandler;
+    }
+}
diff --git a/telephony/java/android/telephony/mbms/InternalStreamingServiceCallback.java b/telephony/java/android/telephony/mbms/InternalStreamingServiceCallback.java
new file mode 100644
index 0000000..bb337b2
--- /dev/null
+++ b/telephony/java/android/telephony/mbms/InternalStreamingServiceCallback.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package android.telephony.mbms;
+
+import android.os.Handler;
+import android.os.RemoteException;
+
+/** @hide */
+public class InternalStreamingServiceCallback extends IStreamingServiceCallback.Stub {
+    private final StreamingServiceCallback mAppCallback;
+    private final Handler mHandler;
+
+    public InternalStreamingServiceCallback(StreamingServiceCallback appCallback, Handler handler) {
+        mAppCallback = appCallback;
+        mHandler = handler;
+    }
+
+    @Override
+    public void error(int errorCode, String message) throws RemoteException {
+        mHandler.post(new Runnable() {
+            @Override
+            public void run() {
+                mAppCallback.onError(errorCode, message);
+            }
+        });
+    }
+
+    @Override
+    public void streamStateUpdated(int state, int reason) throws RemoteException {
+        mHandler.post(new Runnable() {
+            @Override
+            public void run() {
+                mAppCallback.onStreamStateUpdated(state, reason);
+            }
+        });
+    }
+
+    @Override
+    public void mediaDescriptionUpdated() throws RemoteException {
+        mHandler.post(new Runnable() {
+            @Override
+            public void run() {
+                mAppCallback.onMediaDescriptionUpdated();
+            }
+        });
+    }
+
+    @Override
+    public void broadcastSignalStrengthUpdated(int signalStrength) throws RemoteException {
+        mHandler.post(new Runnable() {
+            @Override
+            public void run() {
+                mAppCallback.onBroadcastSignalStrengthUpdated(signalStrength);
+            }
+        });
+    }
+
+    @Override
+    public void streamMethodUpdated(int methodType) throws RemoteException {
+        mHandler.post(new Runnable() {
+            @Override
+            public void run() {
+                mAppCallback.onStreamMethodUpdated(methodType);
+            }
+        });
+    }
+}
diff --git a/telephony/java/android/telephony/mbms/MbmsException.java b/telephony/java/android/telephony/mbms/MbmsException.java
index f51563a..6de5a18 100644
--- a/telephony/java/android/telephony/mbms/MbmsException.java
+++ b/telephony/java/android/telephony/mbms/MbmsException.java
@@ -43,6 +43,7 @@
      * middleware. They are applicable to both streaming and file-download use-cases.
      */
     public static class InitializationErrors {
+        private InitializationErrors() {}
         /**
          * Indicates that the app tried to create more than one instance each of
          * {@link android.telephony.MbmsStreamingManager} or
@@ -60,9 +61,10 @@
      * streaming and file-download.
      */
     public static class GeneralErrors {
+        private GeneralErrors() {}
         /**
          * Indicates that the app attempted to perform an operation before receiving notification
-         * that the middleware is ready via {@link MbmsStreamingManagerCallback#middlewareReady()}
+         * that the middleware is ready via {@link MbmsStreamingManagerCallback#onMiddlewareReady()}
          * or TODO: link MbmsDownloadManagerCallback#middlewareReady
          */
         public static final int ERROR_MIDDLEWARE_NOT_YET_READY = 201;
@@ -96,6 +98,7 @@
      * Indicates the errors that are applicable only to the streaming use-case
      */
     public static class StreamingErrors {
+        private StreamingErrors() {}
         /** Indicates that the middleware cannot start a stream due to too many ongoing streams */
         public static final int ERROR_CONCURRENT_SERVICE_LIMIT_REACHED = 301;
 
@@ -104,7 +107,8 @@
 
         /**
          * Indicates that the app called
-         * {@link android.telephony.MbmsStreamingManager#startStreaming(StreamingServiceInfo, StreamingServiceCallback)}
+         * {@link android.telephony.MbmsStreamingManager#startStreaming(
+         * StreamingServiceInfo, StreamingServiceCallback, android.os.Handler)}
          * more than once for the same {@link StreamingServiceInfo}.
          */
         public static final int ERROR_DUPLICATE_START_STREAM = 303;
diff --git a/telephony/java/android/telephony/mbms/MbmsStreamingManagerCallback.java b/telephony/java/android/telephony/mbms/MbmsStreamingManagerCallback.java
index f67d6e4..a92e02f 100644
--- a/telephony/java/android/telephony/mbms/MbmsStreamingManagerCallback.java
+++ b/telephony/java/android/telephony/mbms/MbmsStreamingManagerCallback.java
@@ -26,14 +26,14 @@
  * services. An instance of this object should be passed into
  * {@link android.telephony.MbmsStreamingManager#create(Context, MbmsStreamingManagerCallback)}.
  */
-public class MbmsStreamingManagerCallback extends IMbmsStreamingManagerCallback.Stub {
+public class MbmsStreamingManagerCallback {
     /**
      * Called by the middleware when it has detected an error condition. The possible error codes
      * are listed in {@link MbmsException}.
      * @param errorCode The error code.
      * @param message A human-readable message generated by the middleware for debugging purposes.
      */
-    public void error(int errorCode, String message) throws RemoteException {
+    public void onError(int errorCode, String message) {
         // default implementation empty
     }
 
@@ -49,8 +49,7 @@
      * @param services a List of StreamingServiceInfos
      *
      */
-    public void streamingServicesUpdated(List<StreamingServiceInfo> services)
-            throws RemoteException {
+    public void onStreamingServicesUpdated(List<StreamingServiceInfo> services) {
         // default implementation empty
     }
 
@@ -62,8 +61,7 @@
      * being thrown with error code {@link MbmsException#ERROR_MIDDLEWARE_NOT_BOUND}
      * or {@link MbmsException.GeneralErrors#ERROR_MIDDLEWARE_NOT_YET_READY}
      */
-    @Override
-    public void middlewareReady() throws RemoteException {
+    public void onMiddlewareReady() {
         // default implementation empty
     }
 }
diff --git a/telephony/java/android/telephony/mbms/ServiceInfo.java b/telephony/java/android/telephony/mbms/ServiceInfo.java
index e1ccd43..c01604b 100644
--- a/telephony/java/android/telephony/mbms/ServiceInfo.java
+++ b/telephony/java/android/telephony/mbms/ServiceInfo.java
@@ -33,7 +33,7 @@
  * Describes a cell-broadcast service. This class should not be instantiated directly -- use
  * {@link StreamingServiceInfo} or FileServiceInfo TODO: add link once that's unhidden
  */
-public class ServiceInfo implements Parcelable {
+public class ServiceInfo {
     // arbitrary limit on the number of locale -> name pairs we support
     final static int MAP_LIMIT = 1000;
 
@@ -67,19 +67,6 @@
         sessionEndTime = (Date)end.clone();
     }
 
-    public static final Parcelable.Creator<ServiceInfo> CREATOR =
-            new Parcelable.Creator<ServiceInfo>() {
-        @Override
-        public ServiceInfo createFromParcel(Parcel source) {
-            return new ServiceInfo(source);
-        }
-
-        @Override
-        public ServiceInfo[] newArray(int size) {
-            return new ServiceInfo[size];
-        }
-    };
-
     /** @hide */
     protected ServiceInfo(Parcel in) {
         int mapCount = in.readInt();
@@ -107,7 +94,7 @@
         sessionEndTime = (java.util.Date) in.readSerializable();
     }
 
-    @Override
+    /** @hide */
     public void writeToParcel(Parcel dest, int flags) {
         Set<Locale> keySet = names.keySet();
         dest.writeInt(keySet.size());
@@ -126,11 +113,6 @@
         dest.writeSerializable(sessionEndTime);
     }
 
-    @Override
-    public int describeContents() {
-        return 0;
-    }
-
     /**
      * User displayable names listed by language. Do not modify the map returned from this method.
      */
diff --git a/telephony/java/android/telephony/mbms/StreamingService.java b/telephony/java/android/telephony/mbms/StreamingService.java
index 42c78c3..78ddf77 100644
--- a/telephony/java/android/telephony/mbms/StreamingService.java
+++ b/telephony/java/android/telephony/mbms/StreamingService.java
@@ -28,14 +28,14 @@
 /**
  * Class used to represent a single MBMS stream. After a stream has been started with
  * {@link android.telephony.MbmsStreamingManager#startStreaming(StreamingServiceInfo,
- * StreamingServiceCallback)},
+ * StreamingServiceCallback, android.os.Handler)},
  * this class is used to hold information about the stream and control it.
  */
 public class StreamingService {
     private static final String LOG_TAG = "MbmsStreamingService";
 
     /**
-     * The state of a stream, reported via {@link StreamingServiceCallback#streamStateUpdated}
+     * The state of a stream, reported via {@link StreamingServiceCallback#onStreamStateUpdated}
      * @hide
      */
     @Retention(RetentionPolicy.SOURCE)
@@ -47,7 +47,7 @@
 
     /**
      * The reason for a stream state change, reported via
-     * {@link StreamingServiceCallback#streamStateUpdated}
+     * {@link StreamingServiceCallback#onStreamStateUpdated}
      * @hide
      */
     @Retention(RetentionPolicy.SOURCE)
@@ -64,7 +64,7 @@
     /**
      * State changed due to a call to {@link #stopStreaming()} or
      * {@link android.telephony.MbmsStreamingManager#startStreaming(StreamingServiceInfo,
-     * StreamingServiceCallback)}
+     * StreamingServiceCallback, android.os.Handler)}
      */
     public static final int REASON_BY_USER_REQUEST = 1;
 
@@ -95,23 +95,24 @@
 
     /**
      * The method of transmission currently used for a stream,
-     * reported via {@link StreamingServiceCallback#streamMethodUpdated}
+     * reported via {@link StreamingServiceCallback#onStreamMethodUpdated}
      */
     public final static int BROADCAST_METHOD = 1;
     public final static int UNICAST_METHOD   = 2;
 
     private final int mSubscriptionId;
     private final StreamingServiceInfo mServiceInfo;
-    private final IStreamingServiceCallback mCallback;
+    private final InternalStreamingServiceCallback mCallback;
 
     private IMbmsStreamingService mService;
+
     /**
      * @hide
      */
     public StreamingService(int subscriptionId,
             IMbmsStreamingService service,
             StreamingServiceInfo streamingServiceInfo,
-            IStreamingServiceCallback callback) {
+            InternalStreamingServiceCallback callback) {
         mSubscriptionId = subscriptionId;
         mService = service;
         mServiceInfo = streamingServiceInfo;
diff --git a/telephony/java/android/telephony/mbms/StreamingServiceCallback.java b/telephony/java/android/telephony/mbms/StreamingServiceCallback.java
index 6a1ff9c..b72c715 100644
--- a/telephony/java/android/telephony/mbms/StreamingServiceCallback.java
+++ b/telephony/java/android/telephony/mbms/StreamingServiceCallback.java
@@ -16,13 +16,11 @@
 
 package android.telephony.mbms;
 
-import android.os.RemoteException;
-
 /**
  * A callback class for use when the application is actively streaming content. The middleware
  * will provide updates on the status of the stream via this callback.
  */
-public class StreamingServiceCallback extends IStreamingServiceCallback.Stub {
+public class StreamingServiceCallback {
 
     /**
      * Indicates broadcast signal strength is not available for this service.
@@ -39,8 +37,7 @@
      * @param errorCode The error code.
      * @param message A human-readable message generated by the middleware for debugging purposes.
      */
-    @Override
-    public void error(int errorCode, String message) throws RemoteException {
+    public void onError(int errorCode, String message) {
         // default implementation empty
     }
 
@@ -50,9 +47,8 @@
      * See {@link StreamingService#STATE_STOPPED}, {@link StreamingService#STATE_STARTED}
      * and {@link StreamingService#STATE_STALLED}.
      */
-    @Override
-    public void streamStateUpdated(@StreamingService.StreamingState int state,
-            @StreamingService.StreamingStateChangeReason int reason) throws RemoteException {
+    public void onStreamStateUpdated(@StreamingService.StreamingState int state,
+            @StreamingService.StreamingStateChangeReason int reason) {
         // default implementation empty
     }
 
@@ -66,8 +62,7 @@
      * This may be called when a looping stream hits the end or
      * when parameters have changed to account for time drift.
      */
-    @Override
-    public void mediaDescriptionUpdated() throws RemoteException {
+    public void onMediaDescriptionUpdated() {
         // default implementation empty
     }
 
@@ -81,8 +76,7 @@
      * {@link #SIGNAL_STRENGTH_UNAVAILABLE} if broadcast is not available
      * for this service due to timing, geography or popularity.
      */
-    @Override
-    public void broadcastSignalStrengthUpdated(int signalStrength) throws RemoteException {
+    public void onBroadcastSignalStrengthUpdated(int signalStrength) {
         // default implementation empty
     }
 
@@ -102,8 +96,7 @@
      * See {@link StreamingService#BROADCAST_METHOD} and
      * {@link StreamingService#UNICAST_METHOD}
      */
-    @Override
-    public void streamMethodUpdated(int methodType) throws RemoteException {
+    public void onStreamMethodUpdated(int methodType) {
         // default implementation empty
     }
 }
diff --git a/telephony/java/android/telephony/mbms/StreamingServiceInfo.java b/telephony/java/android/telephony/mbms/StreamingServiceInfo.java
index 58df24d..c704f34 100644
--- a/telephony/java/android/telephony/mbms/StreamingServiceInfo.java
+++ b/telephony/java/android/telephony/mbms/StreamingServiceInfo.java
@@ -28,7 +28,7 @@
 /**
  * Describes a single MBMS streaming service.
  */
-public class StreamingServiceInfo extends ServiceInfo implements Parcelable {
+public final class StreamingServiceInfo extends ServiceInfo implements Parcelable {
 
     /**
      * @param names User displayable names listed by language.
diff --git a/telephony/java/android/telephony/mbms/vendor/MbmsStreamingServiceBase.java b/telephony/java/android/telephony/mbms/vendor/MbmsStreamingServiceBase.java
index b2200c3..05ba4dd 100644
--- a/telephony/java/android/telephony/mbms/vendor/MbmsStreamingServiceBase.java
+++ b/telephony/java/android/telephony/mbms/vendor/MbmsStreamingServiceBase.java
@@ -19,6 +19,7 @@
 import android.annotation.Nullable;
 import android.annotation.SystemApi;
 import android.net.Uri;
+import android.os.Binder;
 import android.os.RemoteException;
 import android.telephony.mbms.IMbmsStreamingManagerCallback;
 import android.telephony.mbms.IStreamingServiceCallback;
@@ -59,23 +60,42 @@
      * @hide
      */
     @Override
-    public final int initialize(IMbmsStreamingManagerCallback listener, int subscriptionId)
+    public final int initialize(IMbmsStreamingManagerCallback listener, final int subscriptionId)
             throws RemoteException {
+        final int uid = Binder.getCallingUid();
+        listener.asBinder().linkToDeath(new DeathRecipient() {
+            @Override
+            public void binderDied() {
+                onAppCallbackDied(uid, subscriptionId);
+            }
+        }, 0);
+
         return initialize(new MbmsStreamingManagerCallback() {
             @Override
-            public void error(int errorCode, String message) throws RemoteException {
-                listener.error(errorCode, message);
+            public void onError(int errorCode, String message) {
+                try {
+                    listener.error(errorCode, message);
+                } catch (RemoteException e) {
+                    onAppCallbackDied(uid, subscriptionId);
+                }
             }
 
             @Override
-            public void streamingServicesUpdated(List<StreamingServiceInfo> services) throws
-                    RemoteException {
-                listener.streamingServicesUpdated(services);
+            public void onStreamingServicesUpdated(List<StreamingServiceInfo> services) {
+                try {
+                    listener.streamingServicesUpdated(services);
+                } catch (RemoteException e) {
+                    onAppCallbackDied(uid, subscriptionId);
+                }
             }
 
             @Override
-            public void middlewareReady() throws RemoteException {
-                listener.middlewareReady();
+            public void onMiddlewareReady() {
+                try {
+                    listener.middlewareReady();
+                } catch (RemoteException e) {
+                    onAppCallbackDied(uid, subscriptionId);
+                }
             }
         }, subscriptionId);
     }
@@ -129,32 +149,59 @@
     @Override
     public int startStreaming(int subscriptionId, String serviceId,
             IStreamingServiceCallback listener) throws RemoteException {
+        final int uid = Binder.getCallingUid();
+        listener.asBinder().linkToDeath(new DeathRecipient() {
+            @Override
+            public void binderDied() {
+                onAppCallbackDied(uid, subscriptionId);
+            }
+        }, 0);
+
         return startStreaming(subscriptionId, serviceId, new StreamingServiceCallback() {
             @Override
-            public void error(int errorCode, String message) throws RemoteException {
-                listener.error(errorCode, message);
+            public void onError(int errorCode, String message) {
+                try {
+                    listener.error(errorCode, message);
+                } catch (RemoteException e) {
+                    onAppCallbackDied(uid, subscriptionId);
+                }
             }
 
             @Override
-            public void streamStateUpdated(@StreamingService.StreamingState int state,
-                    @StreamingService.StreamingStateChangeReason int reason)
-                    throws RemoteException {
-                listener.streamStateUpdated(state, reason);
+            public void onStreamStateUpdated(@StreamingService.StreamingState int state,
+                    @StreamingService.StreamingStateChangeReason int reason) {
+                try {
+                    listener.streamStateUpdated(state, reason);
+                } catch (RemoteException e) {
+                    onAppCallbackDied(uid, subscriptionId);
+                }
             }
 
             @Override
-            public void mediaDescriptionUpdated() throws RemoteException {
-                listener.mediaDescriptionUpdated();
+            public void onMediaDescriptionUpdated() {
+                try {
+                    listener.mediaDescriptionUpdated();
+                } catch (RemoteException e) {
+                    onAppCallbackDied(uid, subscriptionId);
+                }
             }
 
             @Override
-            public void broadcastSignalStrengthUpdated(int signalStrength) throws RemoteException {
-                listener.broadcastSignalStrengthUpdated(signalStrength);
+            public void onBroadcastSignalStrengthUpdated(int signalStrength) {
+                try {
+                    listener.broadcastSignalStrengthUpdated(signalStrength);
+                } catch (RemoteException e) {
+                    onAppCallbackDied(uid, subscriptionId);
+                }
             }
 
             @Override
-            public void streamMethodUpdated(int methodType) throws RemoteException {
-                listener.streamMethodUpdated(methodType);
+            public void onStreamMethodUpdated(int methodType) {
+                try {
+                    listener.streamMethodUpdated(methodType);
+                } catch (RemoteException e) {
+                    onAppCallbackDied(uid, subscriptionId);
+                }
             }
         });
     }
@@ -221,4 +268,12 @@
     @Override
     public void dispose(int subscriptionId) throws RemoteException {
     }
+
+    /**
+     * Indicates that the app identified by the given UID and subscription ID has died.
+     * @param uid the UID of the app, as returned by {@link Binder#getCallingUid()}.
+     * @param subscriptionId The subscription ID the app is using.
+     */
+    public void onAppCallbackDied(int uid, int subscriptionId) {
+    }
 }