Embms API adjustments for 7/21

* Enforce that only one instance of each manager can be active.
* Add a death receipient for both managers to notify the app of binder
death
* Add documentation informing the app that it may not call create()
multiple times
* Fix a collision in streaming state reason codes
* Add documentation in DownloadRequest to indicate which methods should
be called by the middleware.

Bug: 30981736
Test: testapps
Change-Id: Ie15283b5c34fee736e8023dbd4f889c2ca95299e
This commit is contained in:
Hall Liu
2017-07-20 15:32:51 -07:00
parent 4f306dedc5
commit 0bd7a6058c
8 changed files with 233 additions and 49 deletions

View File

@@ -30,7 +30,6 @@ import android.os.RemoteException;
import android.telephony.mbms.FileInfo; import android.telephony.mbms.FileInfo;
import android.telephony.mbms.DownloadRequest; import android.telephony.mbms.DownloadRequest;
import android.telephony.mbms.IDownloadProgressListener; import android.telephony.mbms.IDownloadProgressListener;
import android.telephony.mbms.IMbmsDownloadManagerCallback;
import android.telephony.mbms.MbmsDownloadManagerCallback; import android.telephony.mbms.MbmsDownloadManagerCallback;
import android.telephony.mbms.MbmsDownloadReceiver; import android.telephony.mbms.MbmsDownloadReceiver;
import android.telephony.mbms.MbmsException; import android.telephony.mbms.MbmsException;
@@ -44,6 +43,7 @@ import java.io.IOException;
import java.lang.annotation.Retention; import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy; import java.lang.annotation.RetentionPolicy;
import java.util.List; import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicReference; import java.util.concurrent.atomic.AtomicReference;
import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID; import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID;
@@ -207,8 +207,16 @@ public class MbmsDownloadManager {
public static final int STATUS_PENDING_REPAIR = 3; public static final int STATUS_PENDING_REPAIR = 3;
public static final int STATUS_PENDING_DOWNLOAD_WINDOW = 4; public static final int STATUS_PENDING_DOWNLOAD_WINDOW = 4;
private static AtomicBoolean sIsInitialized = new AtomicBoolean(false);
private final Context mContext; private final Context mContext;
private int mSubscriptionId = INVALID_SUBSCRIPTION_ID; private int mSubscriptionId = INVALID_SUBSCRIPTION_ID;
private IBinder.DeathRecipient mDeathRecipient = new IBinder.DeathRecipient() {
@Override
public void binderDied() {
sendErrorToApp(MbmsException.ERROR_MIDDLEWARE_LOST, "Received death notification");
}
};
private AtomicReference<IMbmsDownloadService> mService = new AtomicReference<>(null); private AtomicReference<IMbmsDownloadService> mService = new AtomicReference<>(null);
private final MbmsDownloadManagerCallback mCallback; private final MbmsDownloadManagerCallback mCallback;
@@ -236,10 +244,21 @@ public class MbmsDownloadManager {
* *
* Note that this call will bind a remote service and that may take a bit. The instance of * Note that this call will bind a remote service and that may take a bit. The instance of
* {@link MbmsDownloadManager} that is returned will not be ready for use until * {@link MbmsDownloadManager} that is returned will not be ready for use until
* {@link IMbmsDownloadManagerCallback#middlewareReady()} is called on the provided callback. * {@link MbmsDownloadManagerCallback#middlewareReady()} is called on the provided callback.
* If you attempt to use the manager before it is ready, a {@link MbmsException} will be thrown. * If you attempt to use the manager before it is ready, a {@link MbmsException} will be thrown.
* *
* This also may throw an {@link IllegalArgumentException} or a {@link MbmsException}. * This also may throw an {@link IllegalArgumentException} or an {@link IllegalStateException}.
*
* You may only have one instance of {@link MbmsDownloadManager} per UID. If you call this
* method while there is an active instance of {@link MbmsDownloadManager} in your process
* (in other words, one that has not had {@link #dispose()} called on it), this method will
* throw an {@link MbmsException}. If you call this method in a different process
* running under the same UID, an error will be indicated via
* {@link MbmsDownloadManagerCallback#error(int, String)}.
*
* Note that initialization may fail asynchronously. If you wish to try again after you
* receive such an asynchronous error, you must call dispose() on the instance of
* {@link MbmsDownloadManager} that you received before calling this method again.
* *
* @param context The instance of {@link Context} to use * @param context The instance of {@link Context} to use
* @param listener A callback to get asynchronous error messages and file service updates. * @param listener A callback to get asynchronous error messages and file service updates.
@@ -249,8 +268,16 @@ public class MbmsDownloadManager {
public static MbmsDownloadManager create(Context context, public static MbmsDownloadManager create(Context context,
MbmsDownloadManagerCallback listener, int subscriptionId) MbmsDownloadManagerCallback listener, int subscriptionId)
throws MbmsException { throws MbmsException {
if (!sIsInitialized.compareAndSet(false, true)) {
throw new MbmsException(MbmsException.InitializationErrors.ERROR_DUPLICATE_INITIALIZE);
}
MbmsDownloadManager mdm = new MbmsDownloadManager(context, listener, subscriptionId); MbmsDownloadManager mdm = new MbmsDownloadManager(context, listener, subscriptionId);
try {
mdm.bindAndInitialize(); mdm.bindAndInitialize();
} catch (MbmsException e) {
sIsInitialized.set(false);
throw e;
}
return mdm; return mdm;
} }
@@ -266,16 +293,27 @@ public class MbmsDownloadManager {
result = downloadService.initialize(mSubscriptionId, mCallback); result = downloadService.initialize(mSubscriptionId, mCallback);
} catch (RemoteException e) { } catch (RemoteException e) {
Log.e(LOG_TAG, "Service died before initialization"); Log.e(LOG_TAG, "Service died before initialization");
sIsInitialized.set(false);
return; return;
} catch (RuntimeException e) { } catch (RuntimeException e) {
Log.e(LOG_TAG, "Runtime exception during initialization"); Log.e(LOG_TAG, "Runtime exception during initialization");
mCallback.error( sendErrorToApp(
MbmsException.InitializationErrors.ERROR_UNABLE_TO_INITIALIZE, MbmsException.InitializationErrors.ERROR_UNABLE_TO_INITIALIZE,
e.toString()); e.toString());
sIsInitialized.set(false);
return; return;
} }
if (result != MbmsException.SUCCESS) { if (result != MbmsException.SUCCESS) {
mCallback.error(result, "Error returned during initialization"); sendErrorToApp(result, "Error returned during initialization");
sIsInitialized.set(false);
return;
}
try {
downloadService.asBinder().linkToDeath(mDeathRecipient, 0);
} catch (RemoteException e) {
sendErrorToApp(MbmsException.ERROR_MIDDLEWARE_LOST,
"Middleware lost during initialization");
sIsInitialized.set(false);
return; return;
} }
mService.set(downloadService); mService.set(downloadService);
@@ -283,6 +321,7 @@ public class MbmsDownloadManager {
@Override @Override
public void onServiceDisconnected(ComponentName name) { public void onServiceDisconnected(ComponentName name) {
sIsInitialized.set(false);
mService.set(null); mService.set(null);
} }
}); });
@@ -292,7 +331,7 @@ public class MbmsDownloadManager {
* An inspection API to retrieve the list of available * An inspection API to retrieve the list of available
* {@link android.telephony.mbms.FileServiceInfo}s currently being advertised. * {@link android.telephony.mbms.FileServiceInfo}s currently being advertised.
* The results are returned asynchronously via a call to * The results are returned asynchronously via a call to
* {@link IMbmsDownloadManagerCallback#fileServicesUpdated(List)} * {@link MbmsDownloadManagerCallback#fileServicesUpdated(List)}
* *
* The serviceClasses argument lets the app filter on types of programming and is opaque data * The serviceClasses argument lets the app filter on types of programming and is opaque data
* negotiated beforehand between the app and the carrier. * negotiated beforehand between the app and the carrier.
@@ -306,7 +345,7 @@ public class MbmsDownloadManager {
* {@link MbmsException.StreamingErrors#ERROR_UNABLE_TO_START_SERVICE} * {@link MbmsException.StreamingErrors#ERROR_UNABLE_TO_START_SERVICE}
* *
* @param classList A list of service classes which the app wishes to receive * @param classList A list of service classes which the app wishes to receive
* {@link IMbmsDownloadManagerCallback#fileServicesUpdated(List)} callbacks * {@link MbmsDownloadManagerCallback#fileServicesUpdated(List)} callbacks
* about. Subsequent calls to this method will replace this list of service * about. Subsequent calls to this method will replace this list of service
* classes (i.e. the middleware will no longer send updates for services * classes (i.e. the middleware will no longer send updates for services
* matching classes only in the old list). * matching classes only in the old list).
@@ -336,7 +375,7 @@ public class MbmsDownloadManager {
* local instance of {@link android.content.SharedPreferences} and by the middleware. * local instance of {@link android.content.SharedPreferences} and by the middleware.
* *
* If this method is not called at least once before calling * If this method is not called at least once before calling
* {@link #download(DownloadRequest, IDownloadCallback)}, the framework * {@link #download(DownloadRequest, IDownloadProgressListener)}, the framework
* will default to a directory formed by the concatenation of the app's files directory and * will default to a directory formed by the concatenation of the app's files directory and
* {@link android.telephony.mbms.MbmsTempFileProvider#DEFAULT_TOP_LEVEL_TEMP_DIRECTORY}. * {@link android.telephony.mbms.MbmsTempFileProvider#DEFAULT_TOP_LEVEL_TEMP_DIRECTORY}.
* *
@@ -434,7 +473,7 @@ public class MbmsDownloadManager {
/** /**
* Returns a list of pending {@link DownloadRequest}s that originated from this application. * Returns a list of pending {@link DownloadRequest}s that originated from this application.
* A pending request is one that was issued via * A pending request is one that was issued via
* {@link #download(DownloadRequest, IDownloadCallback)} but not cancelled through * {@link #download(DownloadRequest, IDownloadProgressListener)} but not cancelled through
* {@link #cancelDownload(DownloadRequest)}. * {@link #cancelDownload(DownloadRequest)}.
* @return A list, possibly empty, of {@link DownloadRequest}s * @return A list, possibly empty, of {@link DownloadRequest}s
*/ */
@@ -550,10 +589,12 @@ public class MbmsDownloadManager {
return; return;
} }
downloadService.dispose(mSubscriptionId); downloadService.dispose(mSubscriptionId);
mService.set(null);
} catch (RemoteException e) { } catch (RemoteException e) {
// Ignore // Ignore
Log.i(LOG_TAG, "Remote exception while disposing of service"); Log.i(LOG_TAG, "Remote exception while disposing of service");
} finally {
mService.set(null);
sIsInitialized.set(false);
} }
} }
@@ -651,4 +692,12 @@ public class MbmsDownloadManager {
} }
} }
} }
private void sendErrorToApp(int errorCode, String message) {
try {
mCallback.error(errorCode, message);
} catch (RemoteException e) {
// Ignore, should not happen locally.
}
}
} }

View File

@@ -37,6 +37,7 @@ import android.telephony.mbms.vendor.IMbmsStreamingService;
import android.util.Log; import android.util.Log;
import java.util.List; import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicReference; import java.util.concurrent.atomic.AtomicReference;
import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID; import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID;
@@ -58,7 +59,17 @@ public class MbmsStreamingManager {
public static final String MBMS_STREAMING_SERVICE_ACTION = public static final String MBMS_STREAMING_SERVICE_ACTION =
"android.telephony.action.EmbmsStreaming"; "android.telephony.action.EmbmsStreaming";
private static AtomicBoolean sIsInitialized = new AtomicBoolean(false);
private AtomicReference<IMbmsStreamingService> mService = new AtomicReference<>(null); private AtomicReference<IMbmsStreamingService> mService = new AtomicReference<>(null);
private IBinder.DeathRecipient mDeathRecipient = new IBinder.DeathRecipient() {
@Override
public void binderDied() {
sIsInitialized.set(false);
sendErrorToApp(MbmsException.ERROR_MIDDLEWARE_LOST, "Received death notification");
}
};
private InternalStreamingManagerCallback mInternalCallback; private InternalStreamingManagerCallback mInternalCallback;
private final Context mContext; private final Context mContext;
@@ -82,6 +93,18 @@ public class MbmsStreamingManager {
* main thread. This may throw an {@link MbmsException}, indicating errors that may happen * main thread. This may throw an {@link MbmsException}, indicating errors that may happen
* during the initialization or binding process. * during the initialization or binding process.
* *
*
* You may only have one instance of {@link MbmsStreamingManager} per UID. If you call this
* method while there is an active instance of {@link MbmsStreamingManager} in your process
* (in other words, one that has not had {@link #dispose()} called on it), this method will
* throw an {@link MbmsException}. If you call this method in a different process
* running under the same UID, an error will be indicated via
* {@link MbmsStreamingManagerCallback#onError(int, String)}.
*
* Note that initialization may fail asynchronously. If you wish to try again after you
* receive such an asynchronous error, you must call dispose() on the instance of
* {@link MbmsStreamingManager} that you received before calling this method again.
*
* @param context The {@link Context} to use. * @param context The {@link Context} to use.
* @param callback A callback object on which you wish to receive results of asynchronous * @param callback A callback object on which you wish to receive results of asynchronous
* operations. * operations.
@@ -93,9 +116,17 @@ public class MbmsStreamingManager {
public static MbmsStreamingManager create(Context context, public static MbmsStreamingManager create(Context context,
MbmsStreamingManagerCallback callback, int subscriptionId, Handler handler) MbmsStreamingManagerCallback callback, int subscriptionId, Handler handler)
throws MbmsException { throws MbmsException {
if (!sIsInitialized.compareAndSet(false, true)) {
throw new MbmsException(MbmsException.InitializationErrors.ERROR_DUPLICATE_INITIALIZE);
}
MbmsStreamingManager manager = new MbmsStreamingManager(context, callback, MbmsStreamingManager manager = new MbmsStreamingManager(context, callback,
subscriptionId, handler); subscriptionId, handler);
try {
manager.bindAndInitialize(); manager.bindAndInitialize();
} catch (MbmsException e) {
sIsInitialized.set(false);
throw e;
}
return manager; return manager;
} }
@@ -127,17 +158,19 @@ public class MbmsStreamingManager {
* May throw an {@link IllegalStateException} * May throw an {@link IllegalStateException}
*/ */
public void dispose() { public void dispose() {
try {
IMbmsStreamingService streamingService = mService.get(); IMbmsStreamingService streamingService = mService.get();
if (streamingService == null) { if (streamingService == null) {
// Ignore and return, assume already disposed. // Ignore and return, assume already disposed.
return; return;
} }
try {
streamingService.dispose(mSubscriptionId); streamingService.dispose(mSubscriptionId);
} catch (RemoteException e) { } catch (RemoteException e) {
// Ignore for now // Ignore for now
} } finally {
mService.set(null); mService.set(null);
sIsInitialized.set(false);
}
} }
/** /**
@@ -171,6 +204,7 @@ public class MbmsStreamingManager {
} catch (RemoteException e) { } catch (RemoteException e) {
Log.w(LOG_TAG, "Remote process died"); Log.w(LOG_TAG, "Remote process died");
mService.set(null); mService.set(null);
sIsInitialized.set(false);
throw new MbmsException(MbmsException.ERROR_MIDDLEWARE_LOST); throw new MbmsException(MbmsException.ERROR_MIDDLEWARE_LOST);
} }
} }
@@ -223,6 +257,7 @@ public class MbmsStreamingManager {
} catch (RemoteException e) { } catch (RemoteException e) {
Log.w(LOG_TAG, "Remote process died"); Log.w(LOG_TAG, "Remote process died");
mService.set(null); mService.set(null);
sIsInitialized.set(false);
throw new MbmsException(MbmsException.ERROR_MIDDLEWARE_LOST); throw new MbmsException(MbmsException.ERROR_MIDDLEWARE_LOST);
} }
@@ -242,26 +277,30 @@ public class MbmsStreamingManager {
mSubscriptionId); mSubscriptionId);
} catch (RemoteException e) { } catch (RemoteException e) {
Log.e(LOG_TAG, "Service died before initialization"); Log.e(LOG_TAG, "Service died before initialization");
sendErrorToApp(
MbmsException.InitializationErrors.ERROR_UNABLE_TO_INITIALIZE,
e.toString());
sIsInitialized.set(false);
return; return;
} catch (RuntimeException e) { } catch (RuntimeException e) {
Log.e(LOG_TAG, "Runtime exception during initialization"); Log.e(LOG_TAG, "Runtime exception during initialization");
try { sendErrorToApp(
mInternalCallback.error( MbmsException.InitializationErrors.ERROR_UNABLE_TO_INITIALIZE,
MbmsException.InitializationErrors
.ERROR_UNABLE_TO_INITIALIZE,
e.toString()); e.toString());
} catch (RemoteException e1) { sIsInitialized.set(false);
// ignore
}
return; return;
} }
if (result != MbmsException.SUCCESS) { if (result != MbmsException.SUCCESS) {
try { sendErrorToApp(result, "Error returned during initialization");
mInternalCallback.error( sIsInitialized.set(false);
result, "Error returned during initialization"); return;
} catch (RemoteException e) {
// ignore
} }
try {
streamingService.asBinder().linkToDeath(mDeathRecipient, 0);
} catch (RemoteException e) {
sendErrorToApp(MbmsException.ERROR_MIDDLEWARE_LOST,
"Middleware lost during initialization");
sIsInitialized.set(false);
return; return;
} }
mService.set(streamingService); mService.set(streamingService);
@@ -269,8 +308,17 @@ public class MbmsStreamingManager {
@Override @Override
public void onServiceDisconnected(ComponentName name) { public void onServiceDisconnected(ComponentName name) {
sIsInitialized.set(false);
mService.set(null); mService.set(null);
} }
}); });
} }
private void sendErrorToApp(int errorCode, String message) {
try {
mInternalCallback.error(errorCode, message);
} catch (RemoteException e) {
// Ignore, should not happen locally.
}
}
} }

View File

@@ -25,6 +25,7 @@ import android.util.Log;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.io.ObjectInputStream; import java.io.ObjectInputStream;
import java.io.ObjectOutputStream; import java.io.ObjectOutputStream;
@@ -77,12 +78,18 @@ public class DownloadRequest implements Parcelable {
private String appIntent; private String appIntent;
private int version = CURRENT_VERSION; private int version = CURRENT_VERSION;
/**
* Sets the service from which the download request to be built will download from.
* @param serviceInfo
* @return
*/
public Builder setServiceInfo(FileServiceInfo serviceInfo) { public Builder setServiceInfo(FileServiceInfo serviceInfo) {
fileServiceId = serviceInfo.getServiceId(); fileServiceId = serviceInfo.getServiceId();
return this; return this;
} }
/** /**
* Set the service ID for the download request. For use by the middleware only.
* @hide * @hide
* TODO: systemapi * TODO: systemapi
*/ */
@@ -91,11 +98,23 @@ public class DownloadRequest implements Parcelable {
return this; return this;
} }
/**
* Sets the source URI for the download request to be built.
* @param source
* @return
*/
public Builder setSource(Uri source) { public Builder setSource(Uri source) {
this.source = source; this.source = source;
return this; return this;
} }
/**
* Sets the destination URI for the download request to be built. The middleware should
* not set this directly.
* @param dest A URI obtained from {@link Uri#fromFile(File)}, denoting the requested
* final destination of the download.
* @return
*/
public Builder setDest(Uri dest) { public Builder setDest(Uri dest) {
if (dest.toString().length() > MAX_DESTINATION_URI_SIZE) { if (dest.toString().length() > MAX_DESTINATION_URI_SIZE) {
throw new IllegalArgumentException("Destination uri must not exceed length " + throw new IllegalArgumentException("Destination uri must not exceed length " +
@@ -105,11 +124,25 @@ public class DownloadRequest implements Parcelable {
return this; return this;
} }
public Builder setSubscriptionId(int sub) { /**
this.subscriptionId = sub; * Set the subscription ID on which the file(s) should be downloaded.
* @param subscriptionId
* @return
*/
public Builder setSubscriptionId(int subscriptionId) {
this.subscriptionId = subscriptionId;
return this; return this;
} }
/**
* Set the {@link Intent} that should be sent when the download completes or fails. This
* should be an intent with a explicit {@link android.content.ComponentName} targeted to a
* {@link android.content.BroadcastReceiver} in the app's package.
*
* The middleware should not use this method.
* @param intent
* @return
*/
public Builder setAppIntent(Intent intent) { public Builder setAppIntent(Intent intent) {
this.appIntent = intent.toUri(0); this.appIntent = intent.toUri(0);
if (this.appIntent.length() > MAX_APP_INTENT_SIZE) { if (this.appIntent.length() > MAX_APP_INTENT_SIZE) {
@@ -120,7 +153,12 @@ public class DownloadRequest implements Parcelable {
} }
/** /**
* For use by middleware only * For use by the middleware to set the byte array of opaque data. The opaque data
* includes information about the download request that is used by the client app and the
* manager code, but is irrelevant to the middleware.
* @param data A byte array, the contents of which should have been originally obtained
* from {@link DownloadRequest#getOpaqueData()}.
* @return
* TODO: systemapi * TODO: systemapi
* @hide * @hide
*/ */
@@ -201,22 +239,40 @@ public class DownloadRequest implements Parcelable {
out.writeInt(version); out.writeInt(version);
} }
/**
* @return The ID of the file service to download from.
*/
public String getFileServiceId() { public String getFileServiceId() {
return fileServiceId; return fileServiceId;
} }
/**
* @return The source URI to download from
*/
public Uri getSourceUri() { public Uri getSourceUri() {
return sourceUri; return sourceUri;
} }
/**
* For use by the client app only.
* @return The URI of the final destination of the download.
*/
public Uri getDestinationUri() { public Uri getDestinationUri() {
return destinationUri; return destinationUri;
} }
/**
* @return The subscription ID on which to perform MBMS operations.
*/
public int getSubscriptionId() { public int getSubscriptionId() {
return subscriptionId; return subscriptionId;
} }
/**
* For internal use -- returns the intent to send to the app after download completion or
* failure.
* @hide
*/
public Intent getIntentForApp() { public Intent getIntentForApp() {
try { try {
return Intent.parseUri(serializedResultIntentForApp, 0); return Intent.parseUri(serializedResultIntentForApp, 0);
@@ -226,6 +282,10 @@ public class DownloadRequest implements Parcelable {
} }
/** /**
* For use by the middleware only. The byte array returned from this method should be
* persisted and sent back to the app upon download completion or failure by passing it into
* {@link Builder#setOpaqueData(byte[])}.
* @return A byte array of opaque data to persist.
* @hide * @hide
* TODO: systemapi * TODO: systemapi
*/ */

View File

@@ -16,6 +16,9 @@
package android.telephony.mbms; package android.telephony.mbms;
import android.os.RemoteException;
import android.telephony.MbmsDownloadManager;
import java.util.List; import java.util.List;
/** /**
@@ -24,12 +27,8 @@ import java.util.List;
*/ */
public class MbmsDownloadManagerCallback extends IMbmsDownloadManagerCallback.Stub { public class MbmsDownloadManagerCallback extends IMbmsDownloadManagerCallback.Stub {
public final static int ERROR_CARRIER_NOT_SUPPORTED = 1; @Override
public final static int ERROR_UNABLE_TO_INITIALIZE = 2; public void error(int errorCode, String message) throws RemoteException {
public final static int ERROR_UNABLE_TO_ALLOCATE_MEMORY = 3;
public void error(int errorCode, String message) {
// default implementation empty // default implementation empty
} }
@@ -45,7 +44,8 @@ public class MbmsDownloadManagerCallback extends IMbmsDownloadManagerCallback.St
* @param services a List of FileServiceInfos * @param services a List of FileServiceInfos
* *
*/ */
public void fileServicesUpdated(List<FileServiceInfo> services) { @Override
public void fileServicesUpdated(List<FileServiceInfo> services) throws RemoteException {
// default implementation empty // default implementation empty
} }
@@ -58,7 +58,7 @@ public class MbmsDownloadManagerCallback extends IMbmsDownloadManagerCallback.St
* or {@link MbmsException.GeneralErrors#ERROR_MIDDLEWARE_NOT_YET_READY} * or {@link MbmsException.GeneralErrors#ERROR_MIDDLEWARE_NOT_YET_READY}
*/ */
@Override @Override
public void middlewareReady() { public void middlewareReady() throws RemoteException {
// default implementation empty // default implementation empty
} }
} }

View File

@@ -18,6 +18,7 @@ package android.telephony.mbms;
import android.content.Context; import android.content.Context;
import android.os.RemoteException; import android.os.RemoteException;
import android.telephony.MbmsStreamingManager;
import java.util.List; import java.util.List;

View File

@@ -92,7 +92,7 @@ public class StreamingService {
/** /**
* State changed due to the device leaving the where this stream is being broadcast. * State changed due to the device leaving the where this stream is being broadcast.
*/ */
public static final int REASON_LEFT_MBMS_BROADCAST_AREA = 5; public static final int REASON_LEFT_MBMS_BROADCAST_AREA = 6;
/** /**
* The method of transmission currently used for a stream, * The method of transmission currently used for a stream,

View File

@@ -20,8 +20,10 @@ import android.annotation.NonNull;
import android.os.RemoteException; import android.os.RemoteException;
import android.telephony.mbms.DownloadRequest; import android.telephony.mbms.DownloadRequest;
import android.telephony.mbms.FileInfo; import android.telephony.mbms.FileInfo;
import android.telephony.mbms.FileServiceInfo;
import android.telephony.mbms.IDownloadProgressListener; import android.telephony.mbms.IDownloadProgressListener;
import android.telephony.mbms.IMbmsDownloadManagerCallback; import android.telephony.mbms.IMbmsDownloadManagerCallback;
import android.telephony.mbms.MbmsDownloadManagerCallback;
import android.telephony.mbms.MbmsException; import android.telephony.mbms.MbmsException;
import java.util.List; import java.util.List;
@@ -44,13 +46,37 @@ public class MbmsDownloadServiceBase extends IMbmsDownloadService.Stub {
* or {@link MbmsException#SUCCESS}. Non-successful error codes will be passed to the app via * or {@link MbmsException#SUCCESS}. Non-successful error codes will be passed to the app via
* {@link IMbmsDownloadManagerCallback#error(int, String)}. * {@link IMbmsDownloadManagerCallback#error(int, String)}.
* *
* @param listener The callback to use to communicate with the app. * @param callback The callback to use to communicate with the app.
* @param subscriptionId The subscription ID to use. * @param subscriptionId The subscription ID to use.
*/ */
public int initialize(int subscriptionId, MbmsDownloadManagerCallback callback)
throws RemoteException {
return 0;
}
/**
* Actual AIDL implementation -- hides the callback AIDL from the API.
* @hide
*/
@Override @Override
public int initialize(int subscriptionId, public int initialize(int subscriptionId,
IMbmsDownloadManagerCallback listener) throws RemoteException { IMbmsDownloadManagerCallback callback) throws RemoteException {
return 0; return initialize(subscriptionId, new MbmsDownloadManagerCallback() {
@Override
public void error(int errorCode, String message) throws RemoteException {
callback.error(errorCode, message);
}
@Override
public void fileServicesUpdated(List<FileServiceInfo> services) throws RemoteException {
callback.fileServicesUpdated(services);
}
@Override
public void middlewareReady() throws RemoteException {
callback.middlewareReady();
}
});
} }
/** /**
@@ -119,7 +145,7 @@ public class MbmsDownloadServiceBase extends IMbmsDownloadService.Stub {
/** /**
* Returns a list of pending {@link DownloadRequest}s that originated from the calling * Returns a list of pending {@link DownloadRequest}s that originated from the calling
* application, identified by its uid. A pending request is one that was issued via * application, identified by its uid. A pending request is one that was issued via
* {@link #download(DownloadRequest, IDownloadCallback)} but not cancelled through * {@link #download(DownloadRequest, IDownloadProgressListener)} but not cancelled through
* {@link #cancelDownload(DownloadRequest)}. * {@link #cancelDownload(DownloadRequest)}.
* The middleware must return a non-null result synchronously or throw an exception * The middleware must return a non-null result synchronously or throw an exception
* inheriting from {@link RuntimeException}. * inheriting from {@link RuntimeException}.

View File

@@ -39,7 +39,7 @@ public class MbmsStreamingServiceBase extends IMbmsStreamingService.Stub {
/** /**
* Initialize streaming service for this app and subId, registering the listener. * Initialize streaming service for this app and subId, registering the listener.
* *
* May throw an {@link IllegalArgumentException} or an {@link IllegalStateException}, which * May throw an {@link IllegalArgumentException} or a {@link SecurityException}, which
* will be intercepted and passed to the app as * will be intercepted and passed to the app as
* {@link android.telephony.mbms.MbmsException.InitializationErrors#ERROR_UNABLE_TO_INITIALIZE} * {@link android.telephony.mbms.MbmsException.InitializationErrors#ERROR_UNABLE_TO_INITIALIZE}
* *