diff --git a/Android.mk b/Android.mk index ac72dc6966366..77a4d83cc33e0 100644 --- a/Android.mk +++ b/Android.mk @@ -502,8 +502,8 @@ LOCAL_SRC_FILES += \ telecomm/java/com/android/internal/telecom/IInCallService.aidl \ telecomm/java/com/android/internal/telecom/ITelecomService.aidl \ telecomm/java/com/android/internal/telecom/RemoteServiceCallback.aidl \ - telephony/java/android/telephony/mbms/IMbmsDownloadManagerCallback.aidl \ - telephony/java/android/telephony/mbms/IMbmsStreamingManagerCallback.aidl \ + telephony/java/android/telephony/mbms/IMbmsDownloadSessionCallback.aidl \ + telephony/java/android/telephony/mbms/IMbmsStreamingSessionCallback.aidl \ telephony/java/android/telephony/mbms/IDownloadStateCallback.aidl \ telephony/java/android/telephony/mbms/IStreamingServiceCallback.aidl \ telephony/java/android/telephony/mbms/vendor/IMbmsDownloadService.aidl \ diff --git a/telephony/java/android/telephony/MbmsDownloadManager.java b/telephony/java/android/telephony/MbmsDownloadSession.java similarity index 59% rename from telephony/java/android/telephony/MbmsDownloadManager.java rename to telephony/java/android/telephony/MbmsDownloadSession.java index f0665396f9df2..01ed69084d1c0 100644 --- a/telephony/java/android/telephony/MbmsDownloadManager.java +++ b/telephony/java/android/telephony/MbmsDownloadSession.java @@ -34,11 +34,11 @@ import android.os.RemoteException; import android.telephony.mbms.DownloadStateCallback; import android.telephony.mbms.FileInfo; import android.telephony.mbms.DownloadRequest; -import android.telephony.mbms.InternalDownloadManagerCallback; +import android.telephony.mbms.InternalDownloadSessionCallback; import android.telephony.mbms.InternalDownloadStateCallback; -import android.telephony.mbms.MbmsDownloadManagerCallback; +import android.telephony.mbms.MbmsDownloadSessionCallback; import android.telephony.mbms.MbmsDownloadReceiver; -import android.telephony.mbms.MbmsException; +import android.telephony.mbms.MbmsErrors; import android.telephony.mbms.MbmsTempFileProvider; import android.telephony.mbms.MbmsUtils; import android.telephony.mbms.vendor.IMbmsDownloadService; @@ -48,7 +48,10 @@ import java.io.File; import java.io.IOException; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; +import java.util.Collections; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicReference; @@ -58,8 +61,8 @@ import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID; * This class provides functionality for file download over MBMS. * @hide */ -public class MbmsDownloadManager { - private static final String LOG_TAG = MbmsDownloadManager.class.getSimpleName(); +public class MbmsDownloadSession implements AutoCloseable { + private static final String LOG_TAG = MbmsDownloadSession.class.getSimpleName(); /** * Service action which must be handled by the middleware implementing the MBMS file download @@ -95,16 +98,28 @@ public class MbmsDownloadManager { /** * {@link Uri} extra that Android will attach to the intent supplied via * {@link android.telephony.mbms.DownloadRequest.Builder#setAppIntent(Intent)} - * Indicates the location of the successfully - * downloaded file. Will always be set to a non-null value if + * Indicates the location of the successfully downloaded file within the temp file root set + * via {@link #setTempFileRootDirectory(File)}. + * While you may use this file in-place, it is highly encouraged that you move + * this file to a different location after receiving the download completion intent, as this + * file resides within the temp file directory. + * + * Will always be set to a non-null value if * {@link #EXTRA_MBMS_DOWNLOAD_RESULT} is set to {@link #RESULT_SUCCESSFUL}. */ public static final String EXTRA_MBMS_COMPLETED_FILE_URI = "android.telephony.extra.MBMS_COMPLETED_FILE_URI"; + /** + * Extra containing the {@link DownloadRequest} for which the download result or file + * descriptor request is for. Must not be null. + */ + public static final String EXTRA_MBMS_DOWNLOAD_REQUEST = + "android.telephony.extra.MBMS_DOWNLOAD_REQUEST"; + /** * The default directory name for all MBMS temp files. If you call - * {@link #download(DownloadRequest, DownloadStateCallback, Handler)} without first calling + * {@link #download(DownloadRequest)} without first calling * {@link #setTempFileRootDirectory(File)}, this directory will be created for you under the * path returned by {@link Context#getFilesDir()}. */ @@ -173,98 +188,88 @@ public class MbmsDownloadManager { private IBinder.DeathRecipient mDeathRecipient = new IBinder.DeathRecipient() { @Override public void binderDied() { - sendErrorToApp(MbmsException.ERROR_MIDDLEWARE_LOST, "Received death notification"); + sendErrorToApp(MbmsErrors.ERROR_MIDDLEWARE_LOST, "Received death notification"); } }; private AtomicReference mService = new AtomicReference<>(null); - private final InternalDownloadManagerCallback mInternalCallback; + private final InternalDownloadSessionCallback mInternalCallback; + private final Map + mInternalDownloadCallbacks = new HashMap<>(); - private MbmsDownloadManager(Context context, MbmsDownloadManagerCallback callback, + private MbmsDownloadSession(Context context, MbmsDownloadSessionCallback callback, int subscriptionId, Handler handler) { mContext = context; mSubscriptionId = subscriptionId; if (handler == null) { - handler = new Handler(Looper.myLooper()); + handler = new Handler(Looper.getMainLooper()); } - mInternalCallback = new InternalDownloadManagerCallback(callback, handler); + mInternalCallback = new InternalDownloadSessionCallback(callback, handler); } /** - * Create a new MbmsDownloadManager using the system default data subscription ID and default - * {@link Handler} - * See {@link #create(Context, MbmsDownloadManagerCallback, int, Handler)} + * Create a new {@link MbmsDownloadSession} using the system default data subscription ID. + * See {@link #create(Context, MbmsDownloadSessionCallback, int, Handler)} */ - public static MbmsDownloadManager create(Context context, - MbmsDownloadManagerCallback callback) - throws MbmsException { - return create(context, callback, SubscriptionManager.getDefaultSubscriptionId(), null); - } - - /** - * Create a new MbmsDownloadManager using the system default data subscription ID. - * See {@link #create(Context, MbmsDownloadManagerCallback, int, Handler)} - */ - public static MbmsDownloadManager create(Context context, - MbmsDownloadManagerCallback callback, Handler handler) - throws MbmsException { + public static MbmsDownloadSession create(@NonNull Context context, + @NonNull MbmsDownloadSessionCallback callback, @NonNull Handler handler) { return create(context, callback, SubscriptionManager.getDefaultSubscriptionId(), handler); } - /** - * Create a new MbmsDownloadManager using the default {@link Handler} - * See {@link #create(Context, MbmsDownloadManagerCallback, int, Handler)} - */ - public static MbmsDownloadManager create(Context context, - MbmsDownloadManagerCallback callback, int subscriptionId) - throws MbmsException { - return create(context, callback, subscriptionId, null); - } - /** * Create a new MbmsDownloadManager using the given subscription ID. * * 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 MbmsDownloadManagerCallback#onMiddlewareReady()} is called on the provided callback. - * If you attempt to use the manager before it is ready, a {@link MbmsException} will be thrown. + * {@link MbmsDownloadSession} that is returned will not be ready for use until + * {@link MbmsDownloadSessionCallback#onMiddlewareReady()} is called on the provided callback. + * If you attempt to use the instance before it is ready, an {@link IllegalStateException} + * will be thrown or an error will be delivered through + * {@link MbmsDownloadSessionCallback#onError(int, String)}. * - * This also may throw an {@link IllegalArgumentException} or an {@link IllegalStateException}. + * This also may throw an {@link IllegalArgumentException}. * - * 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 + * You may only have one instance of {@link MbmsDownloadSession} per UID. If you call this + * method while there is an active instance of {@link MbmsDownloadSession} in your process + * (in other words, one that has not had {@link #close()} called on it), this method will + * throw an {@link IllegalStateException}. If you call this method in a different process * running under the same UID, an error will be indicated via - * {@link MbmsDownloadManagerCallback#onError(int, String)}. + * {@link MbmsDownloadSessionCallback#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 MbmsDownloadManager} that you received before calling this method again. + * receive such an asynchronous error, you must call {@link #close()} on the instance of + * {@link MbmsDownloadSession} that you received before calling this method again. * * @param context The instance of {@link Context} to use - * @param listener A callback to get asynchronous error messages and file service updates. + * @param callback A callback to get asynchronous error messages and file service updates. * @param subscriptionId The data subscription ID to use + * @param handler The {@link Handler} on which callbacks should be enqueued. + * @return A new instance of {@link MbmsDownloadSession}, or null if an error occurred during + * setup. */ - public static MbmsDownloadManager create(Context context, - MbmsDownloadManagerCallback listener, int subscriptionId, Handler handler) - throws MbmsException { + public static @Nullable MbmsDownloadSession create(@NonNull Context context, + final @NonNull MbmsDownloadSessionCallback callback, + int subscriptionId, @NonNull Handler handler) { if (!sIsInitialized.compareAndSet(false, true)) { - throw new MbmsException(MbmsException.InitializationErrors.ERROR_DUPLICATE_INITIALIZE); + throw new IllegalStateException("Cannot have two active instances"); } - MbmsDownloadManager mdm = - new MbmsDownloadManager(context, listener, subscriptionId, handler); - try { - mdm.bindAndInitialize(); - } catch (MbmsException e) { + MbmsDownloadSession session = + new MbmsDownloadSession(context, callback, subscriptionId, handler); + final int result = session.bindAndInitialize(); + if (result != MbmsErrors.SUCCESS) { sIsInitialized.set(false); - throw e; + handler.post(new Runnable() { + @Override + public void run() { + callback.onError(result, null); + } + }); + return null; } - return mdm; + return session; } - private void bindAndInitialize() throws MbmsException { - MbmsUtils.startBinding(mContext, MBMS_DOWNLOAD_SERVICE_ACTION, + private int bindAndInitialize() { + return MbmsUtils.startBinding(mContext, MBMS_DOWNLOAD_SERVICE_ACTION, new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { @@ -280,12 +285,12 @@ public class MbmsDownloadManager { } catch (RuntimeException e) { Log.e(LOG_TAG, "Runtime exception during initialization"); sendErrorToApp( - MbmsException.InitializationErrors.ERROR_UNABLE_TO_INITIALIZE, + MbmsErrors.InitializationErrors.ERROR_UNABLE_TO_INITIALIZE, e.toString()); sIsInitialized.set(false); return; } - if (result != MbmsException.SUCCESS) { + if (result != MbmsErrors.SUCCESS) { sendErrorToApp(result, "Error returned during initialization"); sIsInitialized.set(false); return; @@ -293,7 +298,7 @@ public class MbmsDownloadManager { try { downloadService.asBinder().linkToDeath(mDeathRecipient, 0); } catch (RemoteException e) { - sendErrorToApp(MbmsException.ERROR_MIDDLEWARE_LOST, + sendErrorToApp(MbmsErrors.ERROR_MIDDLEWARE_LOST, "Middleware lost during initialization"); sIsInitialized.set(false); return; @@ -313,39 +318,35 @@ public class MbmsDownloadManager { * An inspection API to retrieve the list of available * {@link android.telephony.mbms.FileServiceInfo}s currently being advertised. * The results are returned asynchronously via a call to - * {@link MbmsDownloadManagerCallback#onFileServicesUpdated(List)} + * {@link MbmsDownloadSessionCallback#onFileServicesUpdated(List)} * - * The serviceClasses argument lets the app filter on types of programming and is opaque data - * negotiated beforehand between the app and the carrier. + * Asynchronous error codes via the {@link MbmsDownloadSessionCallback#onError(int, String)} + * callback may include any of the errors that are not specific to the streaming use-case. * - * This may throw an {@link MbmsException} containing one of the following errors: - * {@link MbmsException#ERROR_MIDDLEWARE_NOT_BOUND} - * {@link MbmsException#ERROR_MIDDLEWARE_LOST} - * - * Asynchronous error codes via the {@link MbmsDownloadManagerCallback#onError(int, String)} - * callback can include any of the errors except: - * {@link MbmsException.StreamingErrors#ERROR_UNABLE_TO_START_SERVICE} + * May throw an {@link IllegalStateException} or {@link IllegalArgumentException}. * * @param classList A list of service classes which the app wishes to receive - * {@link MbmsDownloadManagerCallback#onFileServicesUpdated(List)} callbacks + * {@link MbmsDownloadSessionCallback#onFileServicesUpdated(List)} callbacks * about. Subsequent calls to this method will replace this list of service * classes (i.e. the middleware will no longer send updates for services * matching classes only in the old list). + * Values in this list should be negotiated with the wireless carrier prior + * to using this API. */ - public void getFileServices(List classList) throws MbmsException { + public void requestUpdateFileServices(@NonNull List classList) { IMbmsDownloadService downloadService = mService.get(); if (downloadService == null) { - throw new MbmsException(MbmsException.ERROR_MIDDLEWARE_NOT_BOUND); + throw new IllegalStateException("Middleware not yet bound"); } try { - int returnCode = downloadService.getFileServices(mSubscriptionId, classList); - if (returnCode != MbmsException.SUCCESS) { - throw new MbmsException(returnCode); + int returnCode = downloadService.requestUpdateFileServices(mSubscriptionId, classList); + if (returnCode != MbmsErrors.SUCCESS) { + sendErrorToApp(returnCode, null); } } catch (RemoteException e) { Log.w(LOG_TAG, "Remote process died"); mService.set(null); - throw new MbmsException(MbmsException.ERROR_MIDDLEWARE_LOST); + sendErrorToApp(MbmsErrors.ERROR_MIDDLEWARE_LOST, null); } } @@ -357,31 +358,32 @@ public class MbmsDownloadManager { * local instance of {@link android.content.SharedPreferences} and by the middleware. * * If this method is not called at least once before calling - * {@link #download(DownloadRequest, DownloadStateCallback, Handler)}, the framework + * {@link #download(DownloadRequest)}, the framework * will default to a directory formed by the concatenation of the app's files directory and - * {@link MbmsDownloadManager#DEFAULT_TOP_LEVEL_TEMP_DIRECTORY}. + * {@link MbmsDownloadSession#DEFAULT_TOP_LEVEL_TEMP_DIRECTORY}. * * Before calling this method, the app must cancel all of its pending * {@link DownloadRequest}s via {@link #cancelDownload(DownloadRequest)}. If this is not done, - * an {@link MbmsException} will be thrown with code - * {@link MbmsException.DownloadErrors#ERROR_CANNOT_CHANGE_TEMP_FILE_ROOT} unless the + * you will receive an asynchronous error with code + * {@link MbmsErrors.DownloadErrors#ERROR_CANNOT_CHANGE_TEMP_FILE_ROOT} unless the * provided directory is the same as what has been previously configured. * * The {@link File} supplied as a root temp file directory must already exist. If not, an - * {@link IllegalArgumentException} will be thrown. + * {@link IllegalArgumentException} will be thrown. In addition, as an additional sanity + * check, an {@link IllegalArgumentException} will be thrown if you attempt to set the temp + * file root directory to one of your data roots (the value of {@link Context#getDataDir()}, + * {@link Context#getFilesDir()}, or {@link Context#getCacheDir()}). * @param tempFileRootDirectory A directory to place temp files in. */ - public void setTempFileRootDirectory(@NonNull File tempFileRootDirectory) - throws MbmsException { + public void setTempFileRootDirectory(@NonNull File tempFileRootDirectory) { IMbmsDownloadService downloadService = mService.get(); if (downloadService == null) { - throw new MbmsException(MbmsException.ERROR_MIDDLEWARE_NOT_BOUND); + throw new IllegalStateException("Middleware not yet bound"); } - if (!tempFileRootDirectory.exists()) { - throw new IllegalArgumentException("Provided directory does not exist"); - } - if (!tempFileRootDirectory.isDirectory()) { - throw new IllegalArgumentException("Provided File is not a directory"); + try { + validateTempFileRootSanity(tempFileRootDirectory); + } catch (IOException e) { + throw new IllegalStateException("Got IOException checking directory sanity"); } String filePath; try { @@ -392,12 +394,13 @@ public class MbmsDownloadManager { try { int result = downloadService.setTempFileRootDirectory(mSubscriptionId, filePath); - if (result != MbmsException.SUCCESS) { - throw new MbmsException(result); + if (result != MbmsErrors.SUCCESS) { + sendErrorToApp(result, null); } } catch (RemoteException e) { mService.set(null); - throw new MbmsException(MbmsException.ERROR_MIDDLEWARE_LOST); + sendErrorToApp(MbmsErrors.ERROR_MIDDLEWARE_LOST, null); + return; } SharedPreferences prefs = mContext.getSharedPreferences( @@ -405,10 +408,28 @@ public class MbmsDownloadManager { prefs.edit().putString(MbmsTempFileProvider.TEMP_FILE_ROOT_PREF_NAME, filePath).apply(); } + private void validateTempFileRootSanity(File tempFileRootDirectory) throws IOException { + if (!tempFileRootDirectory.exists()) { + throw new IllegalArgumentException("Provided directory does not exist"); + } + if (!tempFileRootDirectory.isDirectory()) { + throw new IllegalArgumentException("Provided File is not a directory"); + } + String canonicalTempFilePath = tempFileRootDirectory.getCanonicalPath(); + if (mContext.getDataDir().getCanonicalPath().equals(canonicalTempFilePath)) { + throw new IllegalArgumentException("Temp file root cannot be your data dir"); + } + if (mContext.getCacheDir().getCanonicalPath().equals(canonicalTempFilePath)) { + throw new IllegalArgumentException("Temp file root cannot be your cache dir"); + } + if (mContext.getFilesDir().getCanonicalPath().equals(canonicalTempFilePath)) { + throw new IllegalArgumentException("Temp file root cannot be your files dir"); + } + } /** * Retrieves the currently configured temp file root directory. Returns the file that was * configured via {@link #setTempFileRootDirectory(File)} or the default directory - * {@link #download(DownloadRequest, DownloadStateCallback, Handler)} was called without ever + * {@link #download(DownloadRequest)} was called without ever * setting the temp file root. If neither method has been called since the last time the app's * shared preferences were reset, returns {@code null}. * @@ -426,31 +447,24 @@ public class MbmsDownloadManager { } /** - * Requests a download of a file that is available via multicast. + * Requests the download of a file or set of files that the carrier has indicated to be + * available. * * May throw an {@link IllegalArgumentException} * * If {@link #setTempFileRootDirectory(File)} has not called after the app has been installed, * this method will create a directory at the default location defined at - * {@link MbmsDownloadManager#DEFAULT_TOP_LEVEL_TEMP_DIRECTORY} and store that as the temp + * {@link MbmsDownloadSession#DEFAULT_TOP_LEVEL_TEMP_DIRECTORY} and store that as the temp * file root directory. * - * Asynchronous errors through the listener include any of the errors - * - * @param request The request that specifies what should be downloaded - * @param stateCallback Optional listener that will be provided progress updates - * if the app is running. If {@code null}, no callbacks will be - * provided. - * @param handler A handler that calls to {@code stateCallback} should be called on. If - * null, defaults to the handler provided via - * {@link #create(Context, MbmsDownloadManagerCallback, int, Handler)} + * Asynchronous errors through the callback may include any error not specific to the + * streaming use-case. + * @param request The request that specifies what should be downloaded. */ - public void download(DownloadRequest request, @Nullable DownloadStateCallback stateCallback, - Handler handler) - throws MbmsException { + public void download(@NonNull DownloadRequest request) { IMbmsDownloadService downloadService = mService.get(); if (downloadService == null) { - throw new MbmsException(MbmsException.ERROR_MIDDLEWARE_NOT_BOUND); + throw new IllegalStateException("Middleware not yet bound"); } // Check to see whether the app's set a temp root dir yet, and set it if not. @@ -462,67 +476,151 @@ public class MbmsDownloadManager { tempRootDirectory.mkdirs(); setTempFileRootDirectory(tempRootDirectory); } - InternalDownloadStateCallback internalCallback = null; - if (stateCallback != null) { - internalCallback = new InternalDownloadStateCallback(stateCallback, - handler == null ? mInternalCallback.getHandler() : handler); - } - checkValidDownloadDestination(request); writeDownloadRequestToken(request); try { - downloadService.download(request, internalCallback); + downloadService.download(request); } catch (RemoteException e) { mService.set(null); - throw new MbmsException(MbmsException.ERROR_MIDDLEWARE_LOST); + sendErrorToApp(MbmsErrors.ERROR_MIDDLEWARE_LOST, null); } } /** * Returns a list of pending {@link DownloadRequest}s that originated from this application. * A pending request is one that was issued via - * {@link #download(DownloadRequest, DownloadStateCallback, Handler)} but not cancelled through + * {@link #download(DownloadRequest)} but not cancelled through * {@link #cancelDownload(DownloadRequest)}. * @return A list, possibly empty, of {@link DownloadRequest}s */ - public @NonNull List listPendingDownloads() throws MbmsException { + public @NonNull List listPendingDownloads() { IMbmsDownloadService downloadService = mService.get(); if (downloadService == null) { - throw new MbmsException(MbmsException.ERROR_MIDDLEWARE_NOT_BOUND); + throw new IllegalStateException("Middleware not yet bound"); } try { return downloadService.listPendingDownloads(mSubscriptionId); } catch (RemoteException e) { mService.set(null); - throw new MbmsException(MbmsException.ERROR_MIDDLEWARE_LOST); + sendErrorToApp(MbmsErrors.ERROR_MIDDLEWARE_LOST, null); + return Collections.emptyList(); + } + } + + /** + * Registers a callback for a {@link DownloadRequest} previously requested via + * {@link #download(DownloadRequest)}. This callback will only be called as long as both this + * app and the middleware are both running -- if either one stops, no further calls on the + * provided {@link DownloadStateCallback} will be enqueued. + * + * If the middleware is not aware of the specified download request, + * this method will throw an {@link IllegalArgumentException}. + * + * @param request The {@link DownloadRequest} that you want updates on. + * @param callback The callback that should be called when the middleware has information to + * share on the download. + * @param handler The {@link Handler} on which calls to {@code callback} should be enqueued on. + */ + public void registerStateCallback(@NonNull DownloadRequest request, + @NonNull DownloadStateCallback callback, + @NonNull Handler handler) { + IMbmsDownloadService downloadService = mService.get(); + if (downloadService == null) { + throw new IllegalStateException("Middleware not yet bound"); + } + + InternalDownloadStateCallback internalCallback = + new InternalDownloadStateCallback(callback, handler); + + try { + int result = downloadService.registerStateCallback(request, internalCallback); + if (result != MbmsErrors.SUCCESS) { + if (result == MbmsErrors.DownloadErrors.ERROR_UNKNOWN_DOWNLOAD_REQUEST) { + throw new IllegalArgumentException("Unknown download request."); + } + sendErrorToApp(result, null); + return; + } + } catch (RemoteException e) { + mService.set(null); + sendErrorToApp(MbmsErrors.ERROR_MIDDLEWARE_LOST, null); + return; + } + mInternalDownloadCallbacks.put(callback, internalCallback); + } + + /** + * Un-register a callback previously registered via + * {@link #registerStateCallback(DownloadRequest, DownloadStateCallback, Handler)}. After + * this method is called, no further callbacks will be enqueued on the {@link Handler} + * provided upon registration, even if this method throws an exception. + * + * If the middleware is not aware of the specified download request, + * this method will throw an {@link IllegalArgumentException}. + * + * @param request The {@link DownloadRequest} provided during registration + * @param callback The callback provided during registration. + */ + public void unregisterStateCallback(@NonNull DownloadRequest request, + @NonNull DownloadStateCallback callback) { + try { + IMbmsDownloadService downloadService = mService.get(); + if (downloadService == null) { + throw new IllegalStateException("Middleware not yet bound"); + } + + InternalDownloadStateCallback internalCallback = + mInternalDownloadCallbacks.get(callback); + + try { + int result = downloadService.unregisterStateCallback(request, internalCallback); + if (result != MbmsErrors.SUCCESS) { + if (result == MbmsErrors.DownloadErrors.ERROR_UNKNOWN_DOWNLOAD_REQUEST) { + throw new IllegalArgumentException("Unknown download request."); + } + sendErrorToApp(result, null); + } + } catch (RemoteException e) { + mService.set(null); + sendErrorToApp(MbmsErrors.ERROR_MIDDLEWARE_LOST, null); + } + } finally { + InternalDownloadStateCallback internalCallback = + mInternalDownloadCallbacks.remove(callback); + if (internalCallback != null) { + internalCallback.stop(); + } } } /** * Attempts to cancel the specified {@link DownloadRequest}. * - * If the middleware is not aware of the specified download request, an MbmsException will be - * thrown with error code {@link MbmsException.DownloadErrors#ERROR_UNKNOWN_DOWNLOAD_REQUEST}. + * If the middleware is not aware of the specified download request, + * this method will throw an {@link IllegalArgumentException}. * - * If this method returns without throwing an exception, you may assume that cancellation - * was successful. * @param downloadRequest The download request that you wish to cancel. */ - public void cancelDownload(DownloadRequest downloadRequest) throws MbmsException { + public void cancelDownload(@NonNull DownloadRequest downloadRequest) { IMbmsDownloadService downloadService = mService.get(); if (downloadService == null) { - throw new MbmsException(MbmsException.ERROR_MIDDLEWARE_NOT_BOUND); + throw new IllegalStateException("Middleware not yet bound"); } try { int result = downloadService.cancelDownload(downloadRequest); - if (result != MbmsException.SUCCESS) { - throw new MbmsException(result); + if (result != MbmsErrors.SUCCESS) { + if (result == MbmsErrors.DownloadErrors.ERROR_UNKNOWN_DOWNLOAD_REQUEST) { + throw new IllegalArgumentException("Unknown download request."); + } + sendErrorToApp(result, null); + return; } } catch (RemoteException e) { mService.set(null); - throw new MbmsException(MbmsException.ERROR_MIDDLEWARE_LOST); + sendErrorToApp(MbmsErrors.ERROR_MIDDLEWARE_LOST, null); + return; } deleteDownloadRequestToken(downloadRequest); } @@ -530,7 +628,7 @@ public class MbmsDownloadManager { /** * Gets information about the status of a file pending download. * - * If the middleware has not yet been properly initialized or if it has no records of the + * If there was a problem communicating with the middleware or if it has no records of the * file indicated by {@code fileInfo} being associated with {@code downloadRequest}, * {@link #STATUS_UNKNOWN} will be returned. * @@ -539,18 +637,18 @@ public class MbmsDownloadManager { * @return The status of the download. */ @DownloadStatus - public int getDownloadStatus(DownloadRequest downloadRequest, FileInfo fileInfo) - throws MbmsException { + public int getDownloadStatus(DownloadRequest downloadRequest, FileInfo fileInfo) { IMbmsDownloadService downloadService = mService.get(); if (downloadService == null) { - throw new MbmsException(MbmsException.ERROR_MIDDLEWARE_NOT_BOUND); + throw new IllegalStateException("Middleware not yet bound"); } try { return downloadService.getDownloadStatus(downloadRequest, fileInfo); } catch (RemoteException e) { mService.set(null); - throw new MbmsException(MbmsException.ERROR_MIDDLEWARE_LOST); + sendErrorToApp(MbmsErrors.ERROR_MIDDLEWARE_LOST, null); + return STATUS_UNKNOWN; } } @@ -566,30 +664,50 @@ public class MbmsDownloadManager { * when available. * This will not interrupt in-progress downloads. * - * If the middleware is not aware of the specified download request, an MbmsException will be - * thrown with error code {@link MbmsException.DownloadErrors#ERROR_UNKNOWN_DOWNLOAD_REQUEST}. + * This is distinct from cancelling and re-issuing the download request -- if you cancel and + * re-issue, the middleware will not clear its cache of download state information. + * + * If the middleware is not aware of the specified download request, an + * {@link IllegalArgumentException} will be thrown. * - * May throw a {@link MbmsException} with error code * @param downloadRequest The request to re-download files for. */ - public void resetDownloadKnowledge(DownloadRequest downloadRequest) throws MbmsException { + public void resetDownloadKnowledge(DownloadRequest downloadRequest) { IMbmsDownloadService downloadService = mService.get(); if (downloadService == null) { - throw new MbmsException(MbmsException.ERROR_MIDDLEWARE_NOT_BOUND); + throw new IllegalStateException("Middleware not yet bound"); } try { int result = downloadService.resetDownloadKnowledge(downloadRequest); - if (result != MbmsException.SUCCESS) { - throw new MbmsException(result); + if (result != MbmsErrors.SUCCESS) { + if (result == MbmsErrors.DownloadErrors.ERROR_UNKNOWN_DOWNLOAD_REQUEST) { + throw new IllegalArgumentException("Unknown download request."); + } + sendErrorToApp(result, null); } } catch (RemoteException e) { mService.set(null); - throw new MbmsException(MbmsException.ERROR_MIDDLEWARE_LOST); + sendErrorToApp(MbmsErrors.ERROR_MIDDLEWARE_LOST, null); } } - public void dispose() { + /** + * Terminates this instance. + * + * After this method returns, + * no further callbacks originating from the middleware will be enqueued on the provided + * instance of {@link MbmsDownloadSessionCallback}, but callbacks that have already been + * enqueued will still be delivered. + * + * It is safe to call {@link #create(Context, MbmsDownloadSessionCallback, int, Handler)} to + * obtain another instance of {@link MbmsDownloadSession} immediately after this method + * returns. + * + * May throw an {@link IllegalStateException} + */ + @Override + public void close() { try { IMbmsDownloadService downloadService = mService.get(); if (downloadService == null) { @@ -603,6 +721,7 @@ public class MbmsDownloadManager { } finally { mService.set(null); sIsInitialized.set(false); + mInternalCallback.stop(); } } @@ -645,35 +764,9 @@ public class MbmsDownloadManager { return new File(tempFileLocation, downloadTokenFileName); } - /** - * Verifies the following: - * If a request is multi-part, - * 1. Destination Uri must exist and be a directory - * 2. Directory specified must contain no files. - * Otherwise - * 1. The file specified by the destination Uri must not exist. - */ - private void checkValidDownloadDestination(DownloadRequest request) { - File toFile = new File(request.getDestinationUri().getSchemeSpecificPart()); - if (request.isMultipartDownload()) { - if (!toFile.isDirectory()) { - throw new IllegalArgumentException("Multipart download must specify valid " + - "destination directory."); - } - if (toFile.listFiles().length > 0) { - throw new IllegalArgumentException("Destination directory must be clear of all " + - "files."); - } - } else { - if (toFile.exists()) { - throw new IllegalArgumentException("Destination file must not exist."); - } - } - } - private void sendErrorToApp(int errorCode, String message) { try { - mInternalCallback.error(errorCode, message); + mInternalCallback.onError(errorCode, message); } catch (RemoteException e) { // Ignore, should not happen locally. } diff --git a/telephony/java/android/telephony/MbmsStreamingManager.java b/telephony/java/android/telephony/MbmsStreamingSession.java similarity index 58% rename from telephony/java/android/telephony/MbmsStreamingManager.java rename to telephony/java/android/telephony/MbmsStreamingSession.java index 7a6631a3d90c9..efb6055e1d6a4 100644 --- a/telephony/java/android/telephony/MbmsStreamingManager.java +++ b/telephony/java/android/telephony/MbmsStreamingSession.java @@ -16,6 +16,8 @@ package android.telephony; +import android.annotation.NonNull; +import android.annotation.Nullable; import android.annotation.SdkConstant; import android.annotation.SystemApi; import android.content.ComponentName; @@ -25,18 +27,20 @@ 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.InternalStreamingSessionCallback; import android.telephony.mbms.InternalStreamingServiceCallback; -import android.telephony.mbms.MbmsException; -import android.telephony.mbms.MbmsStreamingManagerCallback; +import android.telephony.mbms.MbmsErrors; +import android.telephony.mbms.MbmsStreamingSessionCallback; import android.telephony.mbms.MbmsUtils; import android.telephony.mbms.StreamingService; import android.telephony.mbms.StreamingServiceCallback; import android.telephony.mbms.StreamingServiceInfo; import android.telephony.mbms.vendor.IMbmsStreamingService; +import android.util.ArraySet; import android.util.Log; import java.util.List; +import java.util.Set; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicReference; @@ -46,8 +50,8 @@ import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID; * This class provides functionality for streaming media over MBMS. * @hide */ -public class MbmsStreamingManager { - private static final String LOG_TAG = "MbmsStreamingManager"; +public class MbmsStreamingSession implements AutoCloseable { + private static final String LOG_TAG = "MbmsStreamingSession"; /** * Service action which must be handled by the middleware implementing the MBMS streaming @@ -66,98 +70,98 @@ public class MbmsStreamingManager { @Override public void binderDied() { sIsInitialized.set(false); - sendErrorToApp(MbmsException.ERROR_MIDDLEWARE_LOST, "Received death notification"); + sendErrorToApp(MbmsErrors.ERROR_MIDDLEWARE_LOST, "Received death notification"); } }; - private InternalStreamingManagerCallback mInternalCallback; + private InternalStreamingSessionCallback mInternalCallback; + private Set mKnownActiveStreamingServices = new ArraySet<>(); private final Context mContext; private int mSubscriptionId = INVALID_SUBSCRIPTION_ID; /** @hide */ - private MbmsStreamingManager(Context context, MbmsStreamingManagerCallback callback, + private MbmsStreamingSession(Context context, MbmsStreamingSessionCallback callback, int subscriptionId, Handler handler) { mContext = context; mSubscriptionId = subscriptionId; if (handler == null) { handler = new Handler(Looper.getMainLooper()); } - mInternalCallback = new InternalStreamingManagerCallback(callback, handler); + mInternalCallback = new InternalStreamingSessionCallback(callback, handler); } /** - * Create a new MbmsStreamingManager using the given subscription ID. + * Create a new {@link MbmsStreamingSession} using the given subscription ID. * * Note that this call will bind a remote service. You may not call this method on your app's - * main thread. This may throw an {@link MbmsException}, indicating errors that may happen - * during the initialization or binding process. + * main thread. * - * - * 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 + * You may only have one instance of {@link MbmsStreamingSession} per UID. If you call this + * method while there is an active instance of {@link MbmsStreamingSession} in your process + * (in other words, one that has not had {@link #close()} called on it), this method will + * throw an {@link IllegalStateException}. 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)}. + * {@link MbmsStreamingSessionCallback#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. + * receive such an asynchronous error, you must call {@link #close()} on the instance of + * {@link MbmsStreamingSession} that you received before calling this method again. * * @param context The {@link Context} to use. * @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()}). + * @param handler The handler you wish to receive callbacks on. + * @return An instance of {@link MbmsStreamingSession}, or null if an error occurred. */ - public static MbmsStreamingManager create(Context context, - MbmsStreamingManagerCallback callback, int subscriptionId, Handler handler) - throws MbmsException { + public static @Nullable MbmsStreamingSession create(@NonNull Context context, + final @NonNull MbmsStreamingSessionCallback callback, int subscriptionId, + @NonNull Handler handler) { if (!sIsInitialized.compareAndSet(false, true)) { - throw new MbmsException(MbmsException.InitializationErrors.ERROR_DUPLICATE_INITIALIZE); + throw new IllegalStateException("Cannot create two instances of MbmsStreamingSession"); } - MbmsStreamingManager manager = new MbmsStreamingManager(context, callback, + MbmsStreamingSession session = new MbmsStreamingSession(context, callback, subscriptionId, handler); - try { - manager.bindAndInitialize(); - } catch (MbmsException e) { + + final int result = session.bindAndInitialize(); + if (result != MbmsErrors.SUCCESS) { sIsInitialized.set(false); - throw e; + handler.post(new Runnable() { + @Override + public void run() { + callback.onError(result, null); + } + }); + return null; } - return manager; + return session; } /** - * Create a new MbmsStreamingManager using the system default data subscription ID. - * See {@link #create(Context, MbmsStreamingManagerCallback, int, Handler)}. + * Create a new {@link MbmsStreamingSession} using the system default data subscription ID. + * See {@link #create(Context, MbmsStreamingSessionCallback, int, Handler)}. */ - public static MbmsStreamingManager create(Context context, - MbmsStreamingManagerCallback callback, Handler handler) - throws MbmsException { + public static MbmsStreamingSession create(@NonNull Context context, + @NonNull MbmsStreamingSessionCallback callback, @NonNull Handler handler) { 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(), null); - } - - /** - * Terminates this instance, ending calls to the registered listener. Also terminates - * any streaming services spawned from this instance. + * Terminates this instance. Also terminates + * any streaming services spawned from this instance as if + * {@link StreamingService#stopStreaming()} had been called on them. After this method returns, + * no further callbacks originating from the middleware will be enqueued on the provided + * instance of {@link MbmsStreamingSessionCallback}, but callbacks that have already been + * enqueued will still be delivered. + * + * It is safe to call {@link #create(Context, MbmsStreamingSessionCallback, int, Handler)} to + * obtain another instance of {@link MbmsStreamingSession} immediately after this method + * returns. * * May throw an {@link IllegalStateException} */ - public void dispose() { + public void close() { try { IMbmsStreamingService streamingService = mService.get(); if (streamingService == null) { @@ -165,47 +169,49 @@ public class MbmsStreamingManager { return; } streamingService.dispose(mSubscriptionId); + for (StreamingService s : mKnownActiveStreamingServices) { + s.getCallback().stop(); + } + mKnownActiveStreamingServices.clear(); } catch (RemoteException e) { // Ignore for now } finally { mService.set(null); sIsInitialized.set(false); + mInternalCallback.stop(); } } /** * An inspection API to retrieve the list of streaming media currently be advertised. - * The results are returned asynchronously through the previously registered callback. - * serviceClasses lets the app filter on types of programming and is opaque data between - * the app and the carrier. + * The results are returned asynchronously via + * {@link MbmsStreamingSessionCallback#onStreamingServicesUpdated(List)} on the callback + * provided upon creation. * - * Multiple calls replace the list of serviceClasses of interest. + * Multiple calls replace the list of service classes of interest. * - * This may throw an {@link MbmsException} containing any error in - * {@link android.telephony.mbms.MbmsException.GeneralErrors}, - * {@link MbmsException#ERROR_MIDDLEWARE_NOT_BOUND}, or - * {@link MbmsException#ERROR_MIDDLEWARE_LOST}. + * May throw an {@link IllegalArgumentException} or an {@link IllegalStateException}. * - * May also throw an unchecked {@link IllegalArgumentException} or an - * {@link IllegalStateException} - * - * @param classList A list of streaming service classes that the app would like updates on. + * @param serviceClassList A list of streaming service classes that the app would like updates + * on. The exact names of these classes should be negotiated with the + * wireless carrier separately. */ - public void getStreamingServices(List classList) throws MbmsException { + public void requestUpdateStreamingServices(List serviceClassList) { IMbmsStreamingService streamingService = mService.get(); if (streamingService == null) { - throw new MbmsException(MbmsException.ERROR_MIDDLEWARE_NOT_BOUND); + throw new IllegalStateException("Middleware not yet bound"); } try { - int returnCode = streamingService.getStreamingServices(mSubscriptionId, classList); - if (returnCode != MbmsException.SUCCESS) { - throw new MbmsException(returnCode); + int returnCode = streamingService.requestUpdateStreamingServices( + mSubscriptionId, serviceClassList); + if (returnCode != MbmsErrors.SUCCESS) { + sendErrorToApp(returnCode, null); } } catch (RemoteException e) { Log.w(LOG_TAG, "Remote process died"); mService.set(null); sIsInitialized.set(false); - throw new MbmsException(MbmsException.ERROR_MIDDLEWARE_LOST); + sendErrorToApp(MbmsErrors.ERROR_MIDDLEWARE_LOST, null); } } @@ -216,56 +222,57 @@ public class MbmsStreamingManager { * reported via * {@link android.telephony.mbms.StreamingServiceCallback#onStreamStateUpdated(int, int)} * - * May throw an - * {@link MbmsException} containing any of the error codes in - * {@link android.telephony.mbms.MbmsException.GeneralErrors}, - * {@link MbmsException#ERROR_MIDDLEWARE_NOT_BOUND}, or - * {@link MbmsException#ERROR_MIDDLEWARE_LOST}. - * - * May also throw an {@link IllegalArgumentException} or an {@link IllegalStateException} + * May throw an {@link IllegalArgumentException} or an {@link IllegalStateException} * * Asynchronous errors through the callback include any of the errors in - * {@link android.telephony.mbms.MbmsException.GeneralErrors} or - * {@link android.telephony.mbms.MbmsException.StreamingErrors}. + * {@link MbmsErrors.GeneralErrors} or + * {@link MbmsErrors.StreamingErrors}. * * @param serviceInfo The information about the service to stream. * @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)}. + * @param handler A handler that calls to {@code callback} should be called on. * @return An instance of {@link StreamingService} through which the stream can be controlled. + * May be {@code null} if an error occurred. */ - public StreamingService startStreaming(StreamingServiceInfo serviceInfo, - StreamingServiceCallback callback, Handler handler) throws MbmsException { + public @Nullable StreamingService startStreaming(StreamingServiceInfo serviceInfo, + StreamingServiceCallback callback, @NonNull Handler handler) { IMbmsStreamingService streamingService = mService.get(); if (streamingService == null) { - throw new MbmsException(MbmsException.ERROR_MIDDLEWARE_NOT_BOUND); + throw new IllegalStateException("Middleware not yet bound"); } InternalStreamingServiceCallback serviceCallback = new InternalStreamingServiceCallback( - callback, handler == null ? mInternalCallback.getHandler() : handler); + callback, handler); StreamingService serviceForApp = new StreamingService( - mSubscriptionId, streamingService, serviceInfo, serviceCallback); + mSubscriptionId, streamingService, this, serviceInfo, serviceCallback); + mKnownActiveStreamingServices.add(serviceForApp); try { int returnCode = streamingService.startStreaming( mSubscriptionId, serviceInfo.getServiceId(), serviceCallback); - if (returnCode != MbmsException.SUCCESS) { - throw new MbmsException(returnCode); + if (returnCode != MbmsErrors.SUCCESS) { + sendErrorToApp(returnCode, null); + return null; } } catch (RemoteException e) { Log.w(LOG_TAG, "Remote process died"); mService.set(null); sIsInitialized.set(false); - throw new MbmsException(MbmsException.ERROR_MIDDLEWARE_LOST); + sendErrorToApp(MbmsErrors.ERROR_MIDDLEWARE_LOST, null); + return null; } return serviceForApp; } - private void bindAndInitialize() throws MbmsException { - MbmsUtils.startBinding(mContext, MBMS_STREAMING_SERVICE_ACTION, + /** @hide */ + public void onStreamingServiceStopped(StreamingService service) { + mKnownActiveStreamingServices.remove(service); + } + + private int bindAndInitialize() { + return MbmsUtils.startBinding(mContext, MBMS_STREAMING_SERVICE_ACTION, new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { @@ -278,19 +285,19 @@ public class MbmsStreamingManager { } catch (RemoteException e) { Log.e(LOG_TAG, "Service died before initialization"); sendErrorToApp( - MbmsException.InitializationErrors.ERROR_UNABLE_TO_INITIALIZE, + MbmsErrors.InitializationErrors.ERROR_UNABLE_TO_INITIALIZE, e.toString()); sIsInitialized.set(false); return; } catch (RuntimeException e) { Log.e(LOG_TAG, "Runtime exception during initialization"); sendErrorToApp( - MbmsException.InitializationErrors.ERROR_UNABLE_TO_INITIALIZE, + MbmsErrors.InitializationErrors.ERROR_UNABLE_TO_INITIALIZE, e.toString()); sIsInitialized.set(false); return; } - if (result != MbmsException.SUCCESS) { + if (result != MbmsErrors.SUCCESS) { sendErrorToApp(result, "Error returned during initialization"); sIsInitialized.set(false); return; @@ -298,7 +305,7 @@ public class MbmsStreamingManager { try { streamingService.asBinder().linkToDeath(mDeathRecipient, 0); } catch (RemoteException e) { - sendErrorToApp(MbmsException.ERROR_MIDDLEWARE_LOST, + sendErrorToApp(MbmsErrors.ERROR_MIDDLEWARE_LOST, "Middleware lost during initialization"); sIsInitialized.set(false); return; @@ -316,7 +323,7 @@ public class MbmsStreamingManager { private void sendErrorToApp(int errorCode, String message) { try { - mInternalCallback.error(errorCode, message); + mInternalCallback.onError(errorCode, message); } catch (RemoteException e) { // Ignore, should not happen locally. } diff --git a/telephony/java/android/telephony/mbms/DownloadRequest.java b/telephony/java/android/telephony/mbms/DownloadRequest.java index 8c3f71da57122..a5f256eab5dce 100644 --- a/telephony/java/android/telephony/mbms/DownloadRequest.java +++ b/telephony/java/android/telephony/mbms/DownloadRequest.java @@ -56,12 +56,10 @@ public final class DownloadRequest implements Parcelable { /** @hide */ private static class OpaqueDataContainer implements Serializable { - private final String destinationUri; private final String appIntent; private final int version; - public OpaqueDataContainer(String destinationUri, String appIntent, int version) { - this.destinationUri = destinationUri; + public OpaqueDataContainer(String appIntent, int version) { this.appIntent = appIntent; this.version = version; } @@ -70,7 +68,6 @@ public final class DownloadRequest implements Parcelable { public static class Builder { private String fileServiceId; private Uri source; - private Uri dest; private int subscriptionId; private String appIntent; private int version = CURRENT_VERSION; @@ -104,21 +101,6 @@ public final class DownloadRequest implements Parcelable { 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. - */ - public Builder setDest(Uri dest) { - if (dest.toString().length() > MAX_DESTINATION_URI_SIZE) { - throw new IllegalArgumentException("Destination uri must not exceed length " + - MAX_DESTINATION_URI_SIZE); - } - this.dest = dest; - return this; - } - /** * Set the subscription ID on which the file(s) should be downloaded. * @param subscriptionId @@ -160,7 +142,6 @@ public final class DownloadRequest implements Parcelable { OpaqueDataContainer dataContainer = (OpaqueDataContainer) stream.readObject(); version = dataContainer.version; appIntent = dataContainer.appIntent; - dest = Uri.parse(dataContainer.destinationUri); } catch (IOException e) { // Really should never happen Log.e(LOG_TAG, "Got IOException trying to parse opaque data"); @@ -173,24 +154,21 @@ public final class DownloadRequest implements Parcelable { } public DownloadRequest build() { - return new DownloadRequest(fileServiceId, source, dest, - subscriptionId, appIntent, version); + return new DownloadRequest(fileServiceId, source, subscriptionId, appIntent, version); } } private final String fileServiceId; private final Uri sourceUri; - private final Uri destinationUri; private final int subscriptionId; private final String serializedResultIntentForApp; private final int version; private DownloadRequest(String fileServiceId, - Uri source, Uri dest, - int sub, String appIntent, int version) { + Uri source, int sub, + String appIntent, int version) { this.fileServiceId = fileServiceId; sourceUri = source; - destinationUri = dest; subscriptionId = sub; serializedResultIntentForApp = appIntent; this.version = version; @@ -203,7 +181,6 @@ public final class DownloadRequest implements Parcelable { private DownloadRequest(DownloadRequest dr) { fileServiceId = dr.fileServiceId; sourceUri = dr.sourceUri; - destinationUri = dr.destinationUri; subscriptionId = dr.subscriptionId; serializedResultIntentForApp = dr.serializedResultIntentForApp; version = dr.version; @@ -212,7 +189,6 @@ public final class DownloadRequest implements Parcelable { private DownloadRequest(Parcel in) { fileServiceId = in.readString(); sourceUri = in.readParcelable(getClass().getClassLoader()); - destinationUri = in.readParcelable(getClass().getClassLoader()); subscriptionId = in.readInt(); serializedResultIntentForApp = in.readString(); version = in.readInt(); @@ -225,7 +201,6 @@ public final class DownloadRequest implements Parcelable { public void writeToParcel(Parcel out, int flags) { out.writeString(fileServiceId); out.writeParcelable(sourceUri, flags); - out.writeParcelable(destinationUri, flags); out.writeInt(subscriptionId); out.writeString(serializedResultIntentForApp); out.writeInt(version); @@ -245,14 +220,6 @@ public final class DownloadRequest implements Parcelable { return sourceUri; } - /** - * For use by the client app only. - * @return The URI of the final destination of the download. - */ - public Uri getDestinationUri() { - return destinationUri; - } - /** * @return The subscription ID on which to perform MBMS operations. */ @@ -286,7 +253,7 @@ public final class DownloadRequest implements Parcelable { ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); ObjectOutputStream stream = new ObjectOutputStream(byteArrayOutputStream); OpaqueDataContainer container = new OpaqueDataContainer( - destinationUri.toString(), serializedResultIntentForApp, version); + serializedResultIntentForApp, version); stream.writeObject(container); stream.flush(); return byteArrayOutputStream.toByteArray(); @@ -352,7 +319,6 @@ public final class DownloadRequest implements Parcelable { if (version >= 1) { // Hash the source URI, destination URI, and the app intent digest.update(sourceUri.toString().getBytes(StandardCharsets.UTF_8)); - digest.update(destinationUri.toString().getBytes(StandardCharsets.UTF_8)); digest.update(serializedResultIntentForApp.getBytes(StandardCharsets.UTF_8)); } // Add updates for future versions here @@ -373,13 +339,12 @@ public final class DownloadRequest implements Parcelable { version == request.version && Objects.equals(fileServiceId, request.fileServiceId) && Objects.equals(sourceUri, request.sourceUri) && - Objects.equals(destinationUri, request.destinationUri) && Objects.equals(serializedResultIntentForApp, request.serializedResultIntentForApp); } @Override public int hashCode() { - return Objects.hash(fileServiceId, sourceUri, destinationUri, + return Objects.hash(fileServiceId, sourceUri, subscriptionId, serializedResultIntentForApp, version); } } diff --git a/telephony/java/android/telephony/mbms/DownloadStateCallback.java b/telephony/java/android/telephony/mbms/DownloadStateCallback.java index 9530641e03519..26d6879c425b4 100644 --- a/telephony/java/android/telephony/mbms/DownloadStateCallback.java +++ b/telephony/java/android/telephony/mbms/DownloadStateCallback.java @@ -16,14 +16,12 @@ package android.telephony.mbms; -import android.os.Handler; -import android.telephony.MbmsDownloadManager; +import android.telephony.MbmsDownloadSession; /** * A optional listener class used by download clients to track progress. Apps should extend this * class and pass an instance into - * {@link android.telephony.MbmsDownloadManager#download( - * DownloadRequest, DownloadStateCallback, Handler)} + * {@link MbmsDownloadSession#download(DownloadRequest)} * * This is optionally specified when requesting a download and will only be called while the app * is running. @@ -59,7 +57,7 @@ public class DownloadStateCallback { * may not have been able to get a list of them in advance. * @param state The current state of the download. */ - public void onStateChanged(DownloadRequest request, FileInfo fileInfo, - @MbmsDownloadManager.DownloadStatus int state) { + public void onStateUpdated(DownloadRequest request, FileInfo fileInfo, + @MbmsDownloadSession.DownloadStatus int state) { } } diff --git a/telephony/java/android/telephony/mbms/FileServiceInfo.java b/telephony/java/android/telephony/mbms/FileServiceInfo.java index b2e80abde48ce..51e20a3b617a3 100644 --- a/telephony/java/android/telephony/mbms/FileServiceInfo.java +++ b/telephony/java/android/telephony/mbms/FileServiceInfo.java @@ -59,7 +59,7 @@ public final class FileServiceInfo extends ServiceInfo implements Parcelable { FileServiceInfo(Parcel in) { super(in); files = new ArrayList(); - in.readList(files, null); + in.readList(files, FileInfo.class.getClassLoader()); } @Override diff --git a/telephony/java/android/telephony/mbms/IDownloadStateCallback.aidl b/telephony/java/android/telephony/mbms/IDownloadStateCallback.aidl index d62247be127de..cebc70d3e884e 100755 --- a/telephony/java/android/telephony/mbms/IDownloadStateCallback.aidl +++ b/telephony/java/android/telephony/mbms/IDownloadStateCallback.aidl @@ -29,8 +29,9 @@ interface IDownloadStateCallback * Gives progress callbacks for a given DownloadRequest. Includes a FileInfo * as the list of files may not have been known at request-time. */ - void progress(in DownloadRequest request, in FileInfo fileInfo, int currentDownloadSize, - int fullDownloadSize, int currentDecodedSize, int fullDecodedSize); + void onProgressUpdated(in DownloadRequest request, in FileInfo fileInfo, + int currentDownloadSize, int fullDownloadSize, + int currentDecodedSize, int fullDecodedSize); - void state(in DownloadRequest request, in FileInfo fileInfo, int state); + void onStateUpdated(in DownloadRequest request, in FileInfo fileInfo, int state); } diff --git a/telephony/java/android/telephony/mbms/IMbmsDownloadManagerCallback.aidl b/telephony/java/android/telephony/mbms/IMbmsDownloadSessionCallback.aidl similarity index 81% rename from telephony/java/android/telephony/mbms/IMbmsDownloadManagerCallback.aidl rename to telephony/java/android/telephony/mbms/IMbmsDownloadSessionCallback.aidl index ac2f202438966..0d813a7ceea01 100755 --- a/telephony/java/android/telephony/mbms/IMbmsDownloadManagerCallback.aidl +++ b/telephony/java/android/telephony/mbms/IMbmsDownloadSessionCallback.aidl @@ -24,11 +24,11 @@ import java.util.List; * The interface the clients top-level file download listener will satisfy. * @hide */ -oneway interface IMbmsDownloadManagerCallback +oneway interface IMbmsDownloadSessionCallback { - void error(int errorCode, String message); + void onError(int errorCode, String message); - void fileServicesUpdated(in List services); + void onFileServicesUpdated(in List services); - void middlewareReady(); + void onMiddlewareReady(); } diff --git a/telephony/java/android/telephony/mbms/IMbmsStreamingManagerCallback.aidl b/telephony/java/android/telephony/mbms/IMbmsStreamingSessionCallback.aidl similarity index 80% rename from telephony/java/android/telephony/mbms/IMbmsStreamingManagerCallback.aidl rename to telephony/java/android/telephony/mbms/IMbmsStreamingSessionCallback.aidl index 007aee7cf3f2b..0bf0ebc484ea2 100755 --- a/telephony/java/android/telephony/mbms/IMbmsStreamingManagerCallback.aidl +++ b/telephony/java/android/telephony/mbms/IMbmsStreamingSessionCallback.aidl @@ -24,11 +24,11 @@ import java.util.List; * The interface the clients top-level streaming listener will satisfy. * @hide */ -oneway interface IMbmsStreamingManagerCallback +oneway interface IMbmsStreamingSessionCallback { - void error(int errorCode, String message); + void onError(int errorCode, String message); - void streamingServicesUpdated(in List services); + void onStreamingServicesUpdated(in List services); - void middlewareReady(); + void onMiddlewareReady(); } diff --git a/telephony/java/android/telephony/mbms/IStreamingServiceCallback.aidl b/telephony/java/android/telephony/mbms/IStreamingServiceCallback.aidl index 0952fbea881d3..164cefb2d5ef8 100755 --- a/telephony/java/android/telephony/mbms/IStreamingServiceCallback.aidl +++ b/telephony/java/android/telephony/mbms/IStreamingServiceCallback.aidl @@ -20,9 +20,9 @@ package android.telephony.mbms; * @hide */ oneway interface IStreamingServiceCallback { - void error(int errorCode, String message); - void streamStateUpdated(int state, int reason); - void mediaDescriptionUpdated(); - void broadcastSignalStrengthUpdated(int signalStrength); - void streamMethodUpdated(int methodType); + void onError(int errorCode, String message); + void onStreamStateUpdated(int state, int reason); + void onMediaDescriptionUpdated(); + void onBroadcastSignalStrengthUpdated(int signalStrength); + void onStreamMethodUpdated(int methodType); } diff --git a/telephony/java/android/telephony/mbms/InternalDownloadManagerCallback.java b/telephony/java/android/telephony/mbms/InternalDownloadSessionCallback.java similarity index 67% rename from telephony/java/android/telephony/mbms/InternalDownloadManagerCallback.java rename to telephony/java/android/telephony/mbms/InternalDownloadSessionCallback.java index fe2d719893822..a7a5958fff567 100644 --- a/telephony/java/android/telephony/mbms/InternalDownloadManagerCallback.java +++ b/telephony/java/android/telephony/mbms/InternalDownloadSessionCallback.java @@ -22,19 +22,24 @@ import android.os.RemoteException; import java.util.List; /** @hide */ -public class InternalDownloadManagerCallback extends IMbmsDownloadManagerCallback.Stub { +public class InternalDownloadSessionCallback extends IMbmsDownloadSessionCallback.Stub { private final Handler mHandler; - private final MbmsDownloadManagerCallback mAppCallback; + private final MbmsDownloadSessionCallback mAppCallback; + private volatile boolean mIsStopped = false; - public InternalDownloadManagerCallback(MbmsDownloadManagerCallback appCallback, + public InternalDownloadSessionCallback(MbmsDownloadSessionCallback appCallback, Handler handler) { mAppCallback = appCallback; mHandler = handler; } @Override - public void error(final int errorCode, final String message) throws RemoteException { + public void onError(final int errorCode, final String message) throws RemoteException { + if (mIsStopped) { + return; + } + mHandler.post(new Runnable() { @Override public void run() { @@ -44,7 +49,11 @@ public class InternalDownloadManagerCallback extends IMbmsDownloadManagerCallbac } @Override - public void fileServicesUpdated(final List services) throws RemoteException { + public void onFileServicesUpdated(final List services) throws RemoteException { + if (mIsStopped) { + return; + } + mHandler.post(new Runnable() { @Override public void run() { @@ -54,7 +63,11 @@ public class InternalDownloadManagerCallback extends IMbmsDownloadManagerCallbac } @Override - public void middlewareReady() throws RemoteException { + public void onMiddlewareReady() throws RemoteException { + if (mIsStopped) { + return; + } + mHandler.post(new Runnable() { @Override public void run() { @@ -66,4 +79,8 @@ public class InternalDownloadManagerCallback extends IMbmsDownloadManagerCallbac public Handler getHandler() { return mHandler; } + + public void stop() { + mIsStopped = true; + } } diff --git a/telephony/java/android/telephony/mbms/InternalDownloadStateCallback.java b/telephony/java/android/telephony/mbms/InternalDownloadStateCallback.java index 32be16b5bdd98..8702952cf06bc 100644 --- a/telephony/java/android/telephony/mbms/InternalDownloadStateCallback.java +++ b/telephony/java/android/telephony/mbms/InternalDownloadStateCallback.java @@ -25,6 +25,7 @@ import android.os.RemoteException; public class InternalDownloadStateCallback extends IDownloadStateCallback.Stub { private final Handler mHandler; private final DownloadStateCallback mAppCallback; + private volatile boolean mIsStopped = false; public InternalDownloadStateCallback(DownloadStateCallback appCallback, Handler handler) { mAppCallback = appCallback; @@ -32,9 +33,13 @@ public class InternalDownloadStateCallback extends IDownloadStateCallback.Stub { } @Override - public void progress(final DownloadRequest request, final FileInfo fileInfo, + public void onProgressUpdated(final DownloadRequest request, final FileInfo fileInfo, final int currentDownloadSize, final int fullDownloadSize, final int currentDecodedSize, final int fullDecodedSize) throws RemoteException { + if (mIsStopped) { + return; + } + mHandler.post(new Runnable() { @Override public void run() { @@ -45,13 +50,21 @@ public class InternalDownloadStateCallback extends IDownloadStateCallback.Stub { } @Override - public void state(final DownloadRequest request, final FileInfo fileInfo, final int state) - throws RemoteException { + public void onStateUpdated(final DownloadRequest request, final FileInfo fileInfo, + final int state) throws RemoteException { + if (mIsStopped) { + return; + } + mHandler.post(new Runnable() { @Override public void run() { - mAppCallback.onStateChanged(request, fileInfo, state); + mAppCallback.onStateUpdated(request, fileInfo, state); } }); } + + public void stop() { + mIsStopped = true; + } } diff --git a/telephony/java/android/telephony/mbms/InternalStreamingServiceCallback.java b/telephony/java/android/telephony/mbms/InternalStreamingServiceCallback.java index bb337b271cf0a..eb6579cec4713 100644 --- a/telephony/java/android/telephony/mbms/InternalStreamingServiceCallback.java +++ b/telephony/java/android/telephony/mbms/InternalStreamingServiceCallback.java @@ -23,6 +23,7 @@ import android.os.RemoteException; public class InternalStreamingServiceCallback extends IStreamingServiceCallback.Stub { private final StreamingServiceCallback mAppCallback; private final Handler mHandler; + private volatile boolean mIsStopped = false; public InternalStreamingServiceCallback(StreamingServiceCallback appCallback, Handler handler) { mAppCallback = appCallback; @@ -30,7 +31,11 @@ public class InternalStreamingServiceCallback extends IStreamingServiceCallback. } @Override - public void error(int errorCode, String message) throws RemoteException { + public void onError(final int errorCode, final String message) throws RemoteException { + if (mIsStopped) { + return; + } + mHandler.post(new Runnable() { @Override public void run() { @@ -40,7 +45,11 @@ public class InternalStreamingServiceCallback extends IStreamingServiceCallback. } @Override - public void streamStateUpdated(int state, int reason) throws RemoteException { + public void onStreamStateUpdated(final int state, final int reason) throws RemoteException { + if (mIsStopped) { + return; + } + mHandler.post(new Runnable() { @Override public void run() { @@ -50,7 +59,11 @@ public class InternalStreamingServiceCallback extends IStreamingServiceCallback. } @Override - public void mediaDescriptionUpdated() throws RemoteException { + public void onMediaDescriptionUpdated() throws RemoteException { + if (mIsStopped) { + return; + } + mHandler.post(new Runnable() { @Override public void run() { @@ -60,7 +73,11 @@ public class InternalStreamingServiceCallback extends IStreamingServiceCallback. } @Override - public void broadcastSignalStrengthUpdated(int signalStrength) throws RemoteException { + public void onBroadcastSignalStrengthUpdated(final int signalStrength) throws RemoteException { + if (mIsStopped) { + return; + } + mHandler.post(new Runnable() { @Override public void run() { @@ -70,7 +87,11 @@ public class InternalStreamingServiceCallback extends IStreamingServiceCallback. } @Override - public void streamMethodUpdated(int methodType) throws RemoteException { + public void onStreamMethodUpdated(final int methodType) throws RemoteException { + if (mIsStopped) { + return; + } + mHandler.post(new Runnable() { @Override public void run() { @@ -78,4 +99,8 @@ public class InternalStreamingServiceCallback extends IStreamingServiceCallback. } }); } + + public void stop() { + mIsStopped = true; + } } diff --git a/telephony/java/android/telephony/mbms/InternalStreamingManagerCallback.java b/telephony/java/android/telephony/mbms/InternalStreamingSessionCallback.java similarity index 68% rename from telephony/java/android/telephony/mbms/InternalStreamingManagerCallback.java rename to telephony/java/android/telephony/mbms/InternalStreamingSessionCallback.java index b52df8c0dd84f..d782d12c00d6d 100644 --- a/telephony/java/android/telephony/mbms/InternalStreamingManagerCallback.java +++ b/telephony/java/android/telephony/mbms/InternalStreamingSessionCallback.java @@ -18,25 +18,27 @@ 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 { +public class InternalStreamingSessionCallback extends IMbmsStreamingSessionCallback.Stub { private final Handler mHandler; - private final MbmsStreamingManagerCallback mAppCallback; + private final MbmsStreamingSessionCallback mAppCallback; + private volatile boolean mIsStopped = false; - public InternalStreamingManagerCallback(MbmsStreamingManagerCallback appCallback, + public InternalStreamingSessionCallback(MbmsStreamingSessionCallback appCallback, Handler handler) { mAppCallback = appCallback; mHandler = handler; } @Override - public void error(int errorCode, String message) throws RemoteException { + public void onError(final int errorCode, final String message) throws RemoteException { + if (mIsStopped) { + return; + } + mHandler.post(new Runnable() { @Override public void run() { @@ -46,8 +48,12 @@ public class InternalStreamingManagerCallback extends IMbmsStreamingManagerCallb } @Override - public void streamingServicesUpdated(List services) + public void onStreamingServicesUpdated(final List services) throws RemoteException { + if (mIsStopped) { + return; + } + mHandler.post(new Runnable() { @Override public void run() { @@ -57,7 +63,11 @@ public class InternalStreamingManagerCallback extends IMbmsStreamingManagerCallb } @Override - public void middlewareReady() throws RemoteException { + public void onMiddlewareReady() throws RemoteException { + if (mIsStopped) { + return; + } + mHandler.post(new Runnable() { @Override public void run() { @@ -69,4 +79,8 @@ public class InternalStreamingManagerCallback extends IMbmsStreamingManagerCallb public Handler getHandler() { return mHandler; } + + public void stop() { + mIsStopped = true; + } } diff --git a/telephony/java/android/telephony/mbms/MbmsDownloadReceiver.java b/telephony/java/android/telephony/mbms/MbmsDownloadReceiver.java index 7ee337a899346..93a7cad10dea1 100644 --- a/telephony/java/android/telephony/mbms/MbmsDownloadReceiver.java +++ b/telephony/java/android/telephony/mbms/MbmsDownloadReceiver.java @@ -25,7 +25,7 @@ import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.net.Uri; import android.os.Bundle; -import android.telephony.MbmsDownloadManager; +import android.telephony.MbmsDownloadSession; import android.telephony.mbms.vendor.VendorUtils; import android.util.Log; @@ -36,8 +36,10 @@ import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; +import java.nio.file.FileSystems; +import java.nio.file.Files; +import java.nio.file.Path; import java.util.ArrayList; -import java.util.Iterator; import java.util.List; import java.util.Objects; import java.util.UUID; @@ -115,8 +117,19 @@ public class MbmsDownloadReceiver extends BroadcastReceiver { //@SystemApi public static final int RESULT_TEMP_FILE_GENERATION_ERROR = 5; + /** + * Indicates that the manager was unable to notify the app of the completed download. + * This is a fatal result code and no result extras should be expected. + * @hide + */ + @SystemApi + public static final int RESULT_APP_NOTIFICATION_ERROR = 6; + + private static final String LOG_TAG = "MbmsDownloadReceiver"; private static final String TEMP_FILE_SUFFIX = ".embms.temp"; + private static final String TEMP_FILE_STAGING_LOCATION = "staged_completed_files"; + private static final int MAX_TEMP_FILE_RETRIES = 5; private String mFileProviderAuthorityCache = null; @@ -149,11 +162,11 @@ public class MbmsDownloadReceiver extends BroadcastReceiver { private boolean verifyIntentContents(Context context, Intent intent) { if (VendorUtils.ACTION_DOWNLOAD_RESULT_INTERNAL.equals(intent.getAction())) { - if (!intent.hasExtra(MbmsDownloadManager.EXTRA_MBMS_DOWNLOAD_RESULT)) { + if (!intent.hasExtra(MbmsDownloadSession.EXTRA_MBMS_DOWNLOAD_RESULT)) { Log.w(LOG_TAG, "Download result did not include a result code. Ignoring."); return false; } - if (!intent.hasExtra(VendorUtils.EXTRA_REQUEST)) { + if (!intent.hasExtra(MbmsDownloadSession.EXTRA_MBMS_DOWNLOAD_REQUEST)) { Log.w(LOG_TAG, "Download result did not include the associated request. Ignoring."); return false; } @@ -161,7 +174,7 @@ public class MbmsDownloadReceiver extends BroadcastReceiver { Log.w(LOG_TAG, "Download result did not include the temp file root. Ignoring."); return false; } - if (!intent.hasExtra(MbmsDownloadManager.EXTRA_MBMS_FILE_INFO)) { + if (!intent.hasExtra(MbmsDownloadSession.EXTRA_MBMS_FILE_INFO)) { Log.w(LOG_TAG, "Download result did not include the associated file info. " + "Ignoring."); return false; @@ -171,7 +184,8 @@ public class MbmsDownloadReceiver extends BroadcastReceiver { "temp file. Ignoring."); return false; } - DownloadRequest request = intent.getParcelableExtra(VendorUtils.EXTRA_REQUEST); + DownloadRequest request = intent.getParcelableExtra( + MbmsDownloadSession.EXTRA_MBMS_DOWNLOAD_REQUEST); String expectedTokenFileName = request.getHash() + DOWNLOAD_TOKEN_SUFFIX; File expectedTokenFile = new File( MbmsUtils.getEmbmsTempFileDirForService(context, request.getFileServiceId()), @@ -211,20 +225,25 @@ public class MbmsDownloadReceiver extends BroadcastReceiver { } private void moveDownloadedFile(Context context, Intent intent) { - DownloadRequest request = intent.getParcelableExtra(VendorUtils.EXTRA_REQUEST); + DownloadRequest request = intent.getParcelableExtra( + MbmsDownloadSession.EXTRA_MBMS_DOWNLOAD_REQUEST); Intent intentForApp = request.getIntentForApp(); + if (intentForApp == null) { + Log.i(LOG_TAG, "Malformed app notification intent"); + setResultCode(RESULT_APP_NOTIFICATION_ERROR); + return; + } - int result = intent.getIntExtra(MbmsDownloadManager.EXTRA_MBMS_DOWNLOAD_RESULT, - MbmsDownloadManager.RESULT_CANCELLED); - intentForApp.putExtra(MbmsDownloadManager.EXTRA_MBMS_DOWNLOAD_RESULT, result); + int result = intent.getIntExtra(MbmsDownloadSession.EXTRA_MBMS_DOWNLOAD_RESULT, + MbmsDownloadSession.RESULT_CANCELLED); + intentForApp.putExtra(MbmsDownloadSession.EXTRA_MBMS_DOWNLOAD_RESULT, result); - if (result != MbmsDownloadManager.RESULT_SUCCESSFUL) { + if (result != MbmsDownloadSession.RESULT_SUCCESSFUL) { Log.i(LOG_TAG, "Download request indicated a failed download. Aborting."); context.sendBroadcast(intentForApp); return; } - Uri destinationUri = request.getDestinationUri(); Uri finalTempFile = intent.getParcelableExtra(VendorUtils.EXTRA_FINAL_URI); if (!verifyTempFilePath(context, request.getFileServiceId(), finalTempFile)) { Log.w(LOG_TAG, "Download result specified an invalid temp file " + finalTempFile); @@ -233,24 +252,31 @@ public class MbmsDownloadReceiver extends BroadcastReceiver { } FileInfo completedFileInfo = - (FileInfo) intent.getParcelableExtra(MbmsDownloadManager.EXTRA_MBMS_FILE_INFO); - String relativePath = calculateDestinationFileRelativePath(request, completedFileInfo); + (FileInfo) intent.getParcelableExtra(MbmsDownloadSession.EXTRA_MBMS_FILE_INFO); + Path stagingDirectory = FileSystems.getDefault().getPath( + MbmsTempFileProvider.getEmbmsTempFileDir(context).getPath(), + TEMP_FILE_STAGING_LOCATION); - Uri finalFileLocation = moveTempFile(finalTempFile, destinationUri, relativePath); - if (finalFileLocation == null) { + Uri stagedFileLocation; + try { + stagedFileLocation = stageTempFile(finalTempFile, stagingDirectory); + } catch (IOException e) { Log.w(LOG_TAG, "Failed to move temp file to final destination"); setResultCode(RESULT_DOWNLOAD_FINALIZATION_ERROR); return; } - intentForApp.putExtra(MbmsDownloadManager.EXTRA_MBMS_COMPLETED_FILE_URI, finalFileLocation); - intentForApp.putExtra(MbmsDownloadManager.EXTRA_MBMS_FILE_INFO, completedFileInfo); + intentForApp.putExtra(MbmsDownloadSession.EXTRA_MBMS_COMPLETED_FILE_URI, + stagedFileLocation); + intentForApp.putExtra(MbmsDownloadSession.EXTRA_MBMS_FILE_INFO, completedFileInfo); + intentForApp.putExtra(MbmsDownloadSession.EXTRA_MBMS_DOWNLOAD_REQUEST, request); context.sendBroadcast(intentForApp); setResultCode(RESULT_OK); } private void cleanupPostMove(Context context, Intent intent) { - DownloadRequest request = intent.getParcelableExtra(VendorUtils.EXTRA_REQUEST); + DownloadRequest request = intent.getParcelableExtra( + MbmsDownloadSession.EXTRA_MBMS_DOWNLOAD_REQUEST); if (request == null) { Log.w(LOG_TAG, "Intent does not include a DownloadRequest. Ignoring."); return; @@ -404,63 +430,22 @@ public class MbmsDownloadReceiver extends BroadcastReceiver { } } - private static String calculateDestinationFileRelativePath(DownloadRequest request, - FileInfo info) { - List filePathComponents = info.getUri().getPathSegments(); - List requestPathComponents = request.getSourceUri().getPathSegments(); - Iterator filePathIter = filePathComponents.iterator(); - Iterator requestPathIter = requestPathComponents.iterator(); - - StringBuilder pathBuilder = new StringBuilder(); - // Iterate through the segments of the carrier's URI to the file, along with the segments - // of the source URI specified in the download request. The relative path is calculated - // as the tail of the file's URI that does not match the path segments in the source URI. - while (filePathIter.hasNext()) { - String currFilePathComponent = filePathIter.next(); - if (requestPathIter.hasNext()) { - String requestFilePathComponent = requestPathIter.next(); - if (requestFilePathComponent.equals(currFilePathComponent)) { - continue; - } - } - pathBuilder.append(currFilePathComponent); - pathBuilder.append('/'); - } - // remove the trailing slash - if (pathBuilder.length() > 0) { - pathBuilder.deleteCharAt(pathBuilder.length() - 1); - } - return pathBuilder.toString(); - } - /* - * Moves a tempfile located at fromPath to a new location at toPath. If - * toPath is a directory, the destination file will be located at relativePath - * underneath toPath. + * Moves a tempfile located at fromPath to a new location in the staging directory. */ - private static Uri moveTempFile(Uri fromPath, Uri toPath, String relativePath) { + private static Uri stageTempFile(Uri fromPath, Path stagingDirectory) throws IOException { if (!ContentResolver.SCHEME_FILE.equals(fromPath.getScheme())) { Log.w(LOG_TAG, "Moving source uri " + fromPath+ " does not have a file scheme"); return null; } - if (!ContentResolver.SCHEME_FILE.equals(toPath.getScheme())) { - Log.w(LOG_TAG, "Moving destination uri " + toPath + " does not have a file scheme"); - return null; - } - File fromFile = new File(fromPath.getSchemeSpecificPart()); - File toFile = new File(toPath.getSchemeSpecificPart()); - if (toFile.isDirectory()) { - toFile = new File(toFile, relativePath); + Path fromFile = FileSystems.getDefault().getPath(fromPath.getPath()); + if (!Files.isDirectory(stagingDirectory)) { + Files.createDirectory(stagingDirectory); } - toFile.getParentFile().mkdirs(); + Path result = Files.move(fromFile, stagingDirectory.resolve(fromFile.getFileName())); - if (fromFile.renameTo(toFile)) { - return Uri.fromFile(toFile); - } else if (manualMove(fromFile, toFile)) { - return Uri.fromFile(toFile); - } - return null; + return Uri.fromFile(result.toFile()); } private static boolean verifyTempFilePath(Context context, String serviceId, @@ -512,7 +497,7 @@ public class MbmsDownloadReceiver extends BroadcastReceiver { private String getMiddlewarePackageCached(Context context) { if (mMiddlewarePackageNameCache == null) { mMiddlewarePackageNameCache = MbmsUtils.getMiddlewareServiceInfo(context, - MbmsDownloadManager.MBMS_DOWNLOAD_SERVICE_ACTION).packageName; + MbmsDownloadSession.MBMS_DOWNLOAD_SERVICE_ACTION).packageName; } return mMiddlewarePackageNameCache; } diff --git a/telephony/java/android/telephony/mbms/MbmsDownloadManagerCallback.java b/telephony/java/android/telephony/mbms/MbmsDownloadSessionCallback.java similarity index 75% rename from telephony/java/android/telephony/mbms/MbmsDownloadManagerCallback.java rename to telephony/java/android/telephony/mbms/MbmsDownloadSessionCallback.java index 14598443d61d7..42bc7759688cc 100644 --- a/telephony/java/android/telephony/mbms/MbmsDownloadManagerCallback.java +++ b/telephony/java/android/telephony/mbms/MbmsDownloadSessionCallback.java @@ -16,7 +16,7 @@ package android.telephony.mbms; -import android.telephony.MbmsDownloadManager; +import android.telephony.MbmsDownloadSession; import java.util.List; @@ -25,11 +25,11 @@ import java.util.List; * cell-broadcast. * @hide */ -public class MbmsDownloadManagerCallback { +public class MbmsDownloadSessionCallback { /** * Indicates that the middleware has encountered an asynchronous error. - * @param errorCode Any error code listed in {@link MbmsException} + * @param errorCode Any error code listed in {@link MbmsErrors} * @param message A message, intended for debugging purposes, describing the error in further * detail. */ @@ -42,8 +42,9 @@ public class MbmsDownloadManagerCallback { * * This will only be called after the application has requested a list of file services and * specified a service class list of interest via - * {@link MbmsDownloadManager#getFileServices(List)}. If there are subsequent calls to - * {@link MbmsDownloadManager#getFileServices(List)}, this method may not be called again if + * {@link MbmsDownloadSession#requestUpdateFileServices(List)}. If there are subsequent calls to + * {@link MbmsDownloadSession#requestUpdateFileServices(List)}, + * this method may not be called again if * the list of service classes would remain the same. * * @param services The most recently updated list of available file services. @@ -56,9 +57,9 @@ public class MbmsDownloadManagerCallback { * Called to indicate that the middleware has been initialized and is ready. * * Before this method is called, calling any method on an instance of - * {@link android.telephony.MbmsDownloadManager} will result in an {@link MbmsException} - * being thrown with error code {@link MbmsException#ERROR_MIDDLEWARE_NOT_BOUND} - * or {@link MbmsException.GeneralErrors#ERROR_MIDDLEWARE_NOT_YET_READY} + * {@link MbmsDownloadSession} will result in an {@link IllegalStateException} + * being thrown or {@link #onError(int, String)} being called with error code + * {@link MbmsErrors.GeneralErrors#ERROR_MIDDLEWARE_NOT_YET_READY} */ public void onMiddlewareReady() { // default implementation empty diff --git a/telephony/java/android/telephony/mbms/MbmsException.java b/telephony/java/android/telephony/mbms/MbmsErrors.java similarity index 88% rename from telephony/java/android/telephony/mbms/MbmsException.java rename to telephony/java/android/telephony/mbms/MbmsErrors.java index 144a8a0eeab07..01958699b6b8b 100644 --- a/telephony/java/android/telephony/mbms/MbmsException.java +++ b/telephony/java/android/telephony/mbms/MbmsErrors.java @@ -16,8 +16,10 @@ package android.telephony.mbms; +import android.telephony.MbmsStreamingSession; + /** @hide */ -public class MbmsException extends Exception { +public class MbmsErrors { /** Indicates that the operation was successful. */ public static final int SUCCESS = 0; @@ -31,8 +33,8 @@ public class MbmsException extends Exception { /** * Indicates that the app attempted to perform an operation on an instance of - * TODO link android.telephony.MbmsDownloadManager or - * {@link android.telephony.MbmsStreamingManager} without being bound to the middleware. + * {@link android.telephony.MbmsDownloadSession} or + * {@link MbmsStreamingSession} without being bound to the middleware. */ public static final int ERROR_MIDDLEWARE_NOT_BOUND = 2; @@ -47,8 +49,7 @@ public class MbmsException extends Exception { private InitializationErrors() {} /** * Indicates that the app tried to create more than one instance each of - * {@link android.telephony.MbmsStreamingManager} or - * TODO link android.telephony.MbmsDownloadManager + * {@link MbmsStreamingSession} or {@link android.telephony.MbmsDownloadSession}. */ public static final int ERROR_DUPLICATE_INITIALIZE = 101; /** Indicates that the app is not authorized to access media via MBMS.*/ @@ -65,8 +66,8 @@ public class MbmsException extends Exception { private GeneralErrors() {} /** * Indicates that the app attempted to perform an operation before receiving notification - * that the middleware is ready via {@link MbmsStreamingManagerCallback#onMiddlewareReady()} - * or TODO: link MbmsDownloadManagerCallback#middlewareReady + * that the middleware is ready via {@link MbmsStreamingSessionCallback#onMiddlewareReady()} + * or {@link MbmsDownloadSessionCallback#onMiddlewareReady()}. */ public static final int ERROR_MIDDLEWARE_NOT_YET_READY = 201; /** @@ -108,7 +109,7 @@ public class MbmsException extends Exception { /** * Indicates that the app called - * {@link android.telephony.MbmsStreamingManager#startStreaming( + * {@link MbmsStreamingSession#startStreaming( * StreamingServiceInfo, StreamingServiceCallback, android.os.Handler)} * more than once for the same {@link StreamingServiceInfo}. */ @@ -130,15 +131,5 @@ public class MbmsException extends Exception { public static final int ERROR_UNKNOWN_DOWNLOAD_REQUEST = 402; } - private final int mErrorCode; - - /** @hide */ - public MbmsException(int errorCode) { - super(); - mErrorCode = errorCode; - } - - public int getErrorCode() { - return mErrorCode; - } + private MbmsErrors() {} } diff --git a/telephony/java/android/telephony/mbms/MbmsStreamingManagerCallback.java b/telephony/java/android/telephony/mbms/MbmsStreamingSessionCallback.java similarity index 75% rename from telephony/java/android/telephony/mbms/MbmsStreamingManagerCallback.java rename to telephony/java/android/telephony/mbms/MbmsStreamingSessionCallback.java index 831050efdd477..d714927af97be 100644 --- a/telephony/java/android/telephony/mbms/MbmsStreamingManagerCallback.java +++ b/telephony/java/android/telephony/mbms/MbmsStreamingSessionCallback.java @@ -16,26 +16,27 @@ package android.telephony.mbms; +import android.annotation.Nullable; import android.content.Context; -import android.os.RemoteException; -import android.telephony.MbmsStreamingManager; +import android.os.Handler; +import android.telephony.MbmsStreamingSession; import java.util.List; /** * A callback class that is used to receive information from the middleware on MBMS streaming * services. An instance of this object should be passed into - * {@link android.telephony.MbmsStreamingManager#create(Context, MbmsStreamingManagerCallback)}. + * {@link MbmsStreamingSession#create(Context, MbmsStreamingSessionCallback, int, Handler)}. * @hide */ -public class MbmsStreamingManagerCallback { +public class MbmsStreamingSessionCallback { /** * Called by the middleware when it has detected an error condition. The possible error codes - * are listed in {@link MbmsException}. + * are listed in {@link MbmsErrors}. * @param errorCode The error code. * @param message A human-readable message generated by the middleware for debugging purposes. */ - public void onError(int errorCode, String message) { + public void onError(int errorCode, @Nullable String message) { // default implementation empty } @@ -48,8 +49,7 @@ public class MbmsStreamingManagerCallback { * call with the same service class list would return different * results. * - * @param services a List of StreamingServiceInfos - * + * @param services The list of available services. */ public void onStreamingServicesUpdated(List services) { // default implementation empty @@ -59,9 +59,9 @@ public class MbmsStreamingManagerCallback { * Called to indicate that the middleware has been initialized and is ready. * * Before this method is called, calling any method on an instance of - * {@link android.telephony.MbmsStreamingManager} will result in an {@link MbmsException} - * being thrown with error code {@link MbmsException#ERROR_MIDDLEWARE_NOT_BOUND} - * or {@link MbmsException.GeneralErrors#ERROR_MIDDLEWARE_NOT_YET_READY} + * {@link MbmsStreamingSession} will result in an {@link IllegalStateException} or an error + * delivered via {@link #onError(int, String)} with error code + * {@link MbmsErrors.GeneralErrors#ERROR_MIDDLEWARE_NOT_YET_READY}. */ public void onMiddlewareReady() { // default implementation empty diff --git a/telephony/java/android/telephony/mbms/MbmsTempFileProvider.java b/telephony/java/android/telephony/mbms/MbmsTempFileProvider.java index 190ec8b6c0692..689becd7169a7 100644 --- a/telephony/java/android/telephony/mbms/MbmsTempFileProvider.java +++ b/telephony/java/android/telephony/mbms/MbmsTempFileProvider.java @@ -27,7 +27,7 @@ import android.content.pm.ProviderInfo; import android.database.Cursor; import android.net.Uri; import android.os.ParcelFileDescriptor; -import android.telephony.MbmsDownloadManager; +import android.telephony.MbmsDownloadSession; import java.io.File; import java.io.FileNotFoundException; @@ -181,7 +181,7 @@ public class MbmsTempFileProvider extends ContentProvider { return new File(storedTempFileRoot).getCanonicalFile(); } else { return new File(context.getFilesDir(), - MbmsDownloadManager.DEFAULT_TOP_LEVEL_TEMP_DIRECTORY).getCanonicalFile(); + MbmsDownloadSession.DEFAULT_TOP_LEVEL_TEMP_DIRECTORY).getCanonicalFile(); } } catch (IOException e) { throw new RuntimeException("Unable to canonicalize temp file root path " + e); diff --git a/telephony/java/android/telephony/mbms/MbmsUtils.java b/telephony/java/android/telephony/mbms/MbmsUtils.java index 4b913f8252317..d38d8a712c736 100644 --- a/telephony/java/android/telephony/mbms/MbmsUtils.java +++ b/telephony/java/android/telephony/mbms/MbmsUtils.java @@ -68,19 +68,20 @@ public class MbmsUtils { return downloadServices.get(0).serviceInfo; } - public static void startBinding(Context context, String serviceAction, - ServiceConnection serviceConnection) throws MbmsException { + public static int startBinding(Context context, String serviceAction, + ServiceConnection serviceConnection) { Intent bindIntent = new Intent(); ServiceInfo mbmsServiceInfo = MbmsUtils.getMiddlewareServiceInfo(context, serviceAction); if (mbmsServiceInfo == null) { - throw new MbmsException(MbmsException.ERROR_NO_UNIQUE_MIDDLEWARE); + return MbmsErrors.ERROR_NO_UNIQUE_MIDDLEWARE; } bindIntent.setComponent(MbmsUtils.toComponentName(mbmsServiceInfo)); context.bindService(bindIntent, serviceConnection, Context.BIND_AUTO_CREATE); + return MbmsErrors.SUCCESS; } /** diff --git a/telephony/java/android/telephony/mbms/ServiceInfo.java b/telephony/java/android/telephony/mbms/ServiceInfo.java index 57f34954206fa..3b9cc0e762eb7 100644 --- a/telephony/java/android/telephony/mbms/ServiceInfo.java +++ b/telephony/java/android/telephony/mbms/ServiceInfo.java @@ -16,6 +16,8 @@ package android.telephony.mbms; +import android.annotation.NonNull; +import android.annotation.Nullable; import android.os.Parcel; import android.os.Parcelable; import android.text.TextUtils; @@ -26,12 +28,13 @@ import java.util.HashMap; import java.util.List; import java.util.Locale; import java.util.Map; +import java.util.NoSuchElementException; import java.util.Objects; import java.util.Set; /** * Describes a cell-broadcast service. This class should not be instantiated directly -- use - * {@link StreamingServiceInfo} or TODO link FileServiceInfo + * {@link StreamingServiceInfo} or {@link FileServiceInfo} * @hide */ public class ServiceInfo { @@ -59,6 +62,13 @@ public class ServiceInfo { if (newLocales.size() > MAP_LIMIT) { throw new RuntimeException("bad locales length " + newLocales.size()); } + + for (Locale l : newLocales) { + if (!newNames.containsKey(l)) { + throw new IllegalArgumentException("A name must be provided for each locale"); + } + } + names = new HashMap(newNames.size()); names.putAll(newNames); className = newClassName; @@ -115,16 +125,25 @@ public class ServiceInfo { } /** - * User displayable names listed by language. Do not modify the map returned from this method. + * Get the user-displayable name for this cell-broadcast service corresponding to the + * provided {@link Locale}. + * @param locale The {@link Locale} in which you want the name of the service. This must be a + * value from the list returned by {@link #getLocales()} -- an + * {@link java.util.NoSuchElementException} may be thrown otherwise. + * @return The {@link CharSequence} providing the name of the service in the given + * {@link Locale} */ - public Map getNames() { - return names; + public @NonNull CharSequence getNameForLocale(@NonNull Locale locale) { + if (!names.containsKey(locale)) { + throw new NoSuchElementException("Locale not supported"); + } + return names.get(locale); } /** * The class name for this service - used to categorize and filter */ - public String getClassName() { + public String getServiceClassName() { return className; } diff --git a/telephony/java/android/telephony/mbms/StreamingService.java b/telephony/java/android/telephony/mbms/StreamingService.java index 5c4b7862289f7..ea9d70ab0bc84 100644 --- a/telephony/java/android/telephony/mbms/StreamingService.java +++ b/telephony/java/android/telephony/mbms/StreamingService.java @@ -17,8 +17,10 @@ package android.telephony.mbms; import android.annotation.IntDef; +import android.annotation.Nullable; import android.net.Uri; import android.os.RemoteException; +import android.telephony.MbmsStreamingSession; import android.telephony.mbms.vendor.IMbmsStreamingService; import android.util.Log; @@ -27,7 +29,7 @@ import java.lang.annotation.RetentionPolicy; /** * Class used to represent a single MBMS stream. After a stream has been started with - * {@link android.telephony.MbmsStreamingManager#startStreaming(StreamingServiceInfo, + * {@link MbmsStreamingSession#startStreaming(StreamingServiceInfo, * StreamingServiceCallback, android.os.Handler)}, * this class is used to hold information about the stream and control it. * @hide @@ -64,7 +66,7 @@ public class StreamingService { /** * State changed due to a call to {@link #stopStreaming()} or - * {@link android.telephony.MbmsStreamingManager#startStreaming(StreamingServiceInfo, + * {@link MbmsStreamingSession#startStreaming(StreamingServiceInfo, * StreamingServiceCallback, android.os.Handler)} */ public static final int REASON_BY_USER_REQUEST = 1; @@ -102,6 +104,7 @@ public class StreamingService { public final static int UNICAST_METHOD = 2; private final int mSubscriptionId; + private final MbmsStreamingSession mParentSession; private final StreamingServiceInfo mServiceInfo; private final InternalStreamingServiceCallback mCallback; @@ -112,25 +115,25 @@ public class StreamingService { */ public StreamingService(int subscriptionId, IMbmsStreamingService service, + MbmsStreamingSession session, StreamingServiceInfo streamingServiceInfo, InternalStreamingServiceCallback callback) { mSubscriptionId = subscriptionId; + mParentSession = session; mService = service; mServiceInfo = streamingServiceInfo; mCallback = callback; } /** - * Retreive the Uri used to play this stream. + * Retrieve the Uri used to play this stream. * - * This may throw a {@link MbmsException} with the error code - * {@link MbmsException#ERROR_MIDDLEWARE_LOST} + * May throw an {@link IllegalArgumentException} or an {@link IllegalStateException}. * - * May also throw an {@link IllegalArgumentException} or an {@link IllegalStateException} - * - * @return The {@link Uri} to pass to the streaming client. + * @return The {@link Uri} to pass to the streaming client, or {@code null} if an error + * occurred. */ - public Uri getPlaybackUri() throws MbmsException { + public @Nullable Uri getPlaybackUri() { if (mService == null) { throw new IllegalStateException("No streaming service attached"); } @@ -140,25 +143,26 @@ public class StreamingService { } catch (RemoteException e) { Log.w(LOG_TAG, "Remote process died"); mService = null; - throw new MbmsException(MbmsException.ERROR_MIDDLEWARE_LOST); + mParentSession.onStreamingServiceStopped(this); + sendErrorToApp(MbmsErrors.ERROR_MIDDLEWARE_LOST, null); + return null; } } /** - * Retreive the info for this StreamingService. + * Retrieve the {@link StreamingServiceInfo} corresponding to this stream. */ public StreamingServiceInfo getInfo() { return mServiceInfo; } /** - * Stop streaming this service. - * This may throw a {@link MbmsException} with the error code - * {@link MbmsException#ERROR_MIDDLEWARE_LOST} + * Stop streaming this service. Further operations on this object will fail with an + * {@link IllegalStateException}. * - * May also throw an {@link IllegalArgumentException} or an {@link IllegalStateException} + * May throw an {@link IllegalArgumentException} or an {@link IllegalStateException} */ - public void stopStreaming() throws MbmsException { + public void stopStreaming() { if (mService == null) { throw new IllegalStateException("No streaming service attached"); } @@ -168,32 +172,22 @@ public class StreamingService { } catch (RemoteException e) { Log.w(LOG_TAG, "Remote process died"); mService = null; - throw new MbmsException(MbmsException.ERROR_MIDDLEWARE_LOST); + sendErrorToApp(MbmsErrors.ERROR_MIDDLEWARE_LOST, null); + } finally { + mParentSession.onStreamingServiceStopped(this); } } - /** - * Disposes of this stream. Further operations on this object will fail with an - * {@link IllegalStateException}. - * - * This may throw a {@link MbmsException} with the error code - * {@link MbmsException#ERROR_MIDDLEWARE_LOST} - * May also throw an {@link IllegalStateException} - */ - public void dispose() throws MbmsException { - if (mService == null) { - throw new IllegalStateException("No streaming service attached"); - } + /** @hide */ + public InternalStreamingServiceCallback getCallback() { + return mCallback; + } + private void sendErrorToApp(int errorCode, String message) { try { - mService.disposeStream(mSubscriptionId, mServiceInfo.getServiceId()); + mCallback.onError(errorCode, message); } catch (RemoteException e) { - Log.w(LOG_TAG, "Remote process died"); - throw new MbmsException(MbmsException.ERROR_MIDDLEWARE_LOST); - } catch (IllegalArgumentException e) { - throw new IllegalStateException("StreamingService state inconsistent with middleware"); - } finally { - mService = null; + // Ignore, should not happen locally. } } } diff --git a/telephony/java/android/telephony/mbms/StreamingServiceCallback.java b/telephony/java/android/telephony/mbms/StreamingServiceCallback.java index eeef8bcab04fa..3c079613cce8f 100644 --- a/telephony/java/android/telephony/mbms/StreamingServiceCallback.java +++ b/telephony/java/android/telephony/mbms/StreamingServiceCallback.java @@ -16,6 +16,8 @@ package android.telephony.mbms; +import android.annotation.Nullable; + /** * 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. @@ -34,11 +36,11 @@ public class StreamingServiceCallback { /** * Called by the middleware when it has detected an error condition in this stream. The - * possible error codes are listed in {@link MbmsException}. + * possible error codes are listed in {@link MbmsErrors}. * @param errorCode The error code. * @param message A human-readable message generated by the middleware for debugging purposes. */ - public void onError(int errorCode, String message) { + public void onError(int errorCode, @Nullable String message) { // default implementation empty } diff --git a/telephony/java/android/telephony/mbms/vendor/IMbmsDownloadService.aidl b/telephony/java/android/telephony/mbms/vendor/IMbmsDownloadService.aidl index f29499d9cb311..ed5e8268fc773 100755 --- a/telephony/java/android/telephony/mbms/vendor/IMbmsDownloadService.aidl +++ b/telephony/java/android/telephony/mbms/vendor/IMbmsDownloadService.aidl @@ -20,7 +20,7 @@ import android.app.PendingIntent; import android.net.Uri; import android.telephony.mbms.DownloadRequest; import android.telephony.mbms.FileInfo; -import android.telephony.mbms.IMbmsDownloadManagerCallback; +import android.telephony.mbms.IMbmsDownloadSessionCallback; import android.telephony.mbms.IDownloadStateCallback; /** @@ -28,13 +28,18 @@ import android.telephony.mbms.IDownloadStateCallback; */ interface IMbmsDownloadService { - int initialize(int subId, IMbmsDownloadManagerCallback listener); + int initialize(int subId, IMbmsDownloadSessionCallback listener); - int getFileServices(int subId, in List serviceClasses); + int requestUpdateFileServices(int subId, in List serviceClasses); int setTempFileRootDirectory(int subId, String rootDirectoryPath); - int download(in DownloadRequest downloadRequest, IDownloadStateCallback listener); + int download(in DownloadRequest downloadRequest); + + int registerStateCallback(in DownloadRequest downloadRequest, IDownloadStateCallback listener); + + int unregisterStateCallback(in DownloadRequest downloadRequest, + IDownloadStateCallback listener); List listPendingDownloads(int subscriptionId); diff --git a/telephony/java/android/telephony/mbms/vendor/IMbmsStreamingService.aidl b/telephony/java/android/telephony/mbms/vendor/IMbmsStreamingService.aidl index 4dd42924ab054..c90ffc7726e43 100755 --- a/telephony/java/android/telephony/mbms/vendor/IMbmsStreamingService.aidl +++ b/telephony/java/android/telephony/mbms/vendor/IMbmsStreamingService.aidl @@ -17,7 +17,7 @@ package android.telephony.mbms.vendor; import android.net.Uri; -import android.telephony.mbms.IMbmsStreamingManagerCallback; +import android.telephony.mbms.IMbmsStreamingSessionCallback; import android.telephony.mbms.IStreamingServiceCallback; import android.telephony.mbms.StreamingServiceInfo; @@ -26,18 +26,16 @@ import android.telephony.mbms.StreamingServiceInfo; */ interface IMbmsStreamingService { - int initialize(IMbmsStreamingManagerCallback listener, int subId); + int initialize(IMbmsStreamingSessionCallback callback, int subId); - int getStreamingServices(int subId, in List serviceClasses); + int requestUpdateStreamingServices(int subId, in List serviceClasses); int startStreaming(int subId, String serviceId, - IStreamingServiceCallback listener); + IStreamingServiceCallback callback); Uri getPlaybackUri(int subId, String serviceId); void stopStreaming(int subId, String serviceId); - void disposeStream(int subId, String serviceId); - void dispose(int subId); } diff --git a/telephony/java/android/telephony/mbms/vendor/MbmsDownloadServiceBase.java b/telephony/java/android/telephony/mbms/vendor/MbmsDownloadServiceBase.java index 84ff53324b137..be686eec274bd 100644 --- a/telephony/java/android/telephony/mbms/vendor/MbmsDownloadServiceBase.java +++ b/telephony/java/android/telephony/mbms/vendor/MbmsDownloadServiceBase.java @@ -20,17 +20,21 @@ import android.annotation.NonNull; import android.annotation.SystemApi; import android.content.Intent; import android.os.Binder; +import android.os.IBinder; import android.os.RemoteException; -import android.telephony.mbms.DownloadStateCallback; +import android.telephony.MbmsDownloadSession; import android.telephony.mbms.DownloadRequest; +import android.telephony.mbms.DownloadStateCallback; import android.telephony.mbms.FileInfo; import android.telephony.mbms.FileServiceInfo; import android.telephony.mbms.IDownloadStateCallback; -import android.telephony.mbms.IMbmsDownloadManagerCallback; -import android.telephony.mbms.MbmsDownloadManagerCallback; -import android.telephony.mbms.MbmsException; +import android.telephony.mbms.IMbmsDownloadSessionCallback; +import android.telephony.mbms.MbmsDownloadSessionCallback; +import android.telephony.mbms.MbmsErrors; +import java.util.HashMap; import java.util.List; +import java.util.Map; /** * Base class for MbmsDownloadService. The middleware should return an instance of this object from @@ -39,21 +43,24 @@ import java.util.List; */ //@SystemApi public class MbmsDownloadServiceBase extends IMbmsDownloadService.Stub { + private final Map mDownloadCallbackBinderMap = new HashMap<>(); + private final Map mDownloadCallbackDeathRecipients = new HashMap<>(); + /** * Initialize the download service for this app and subId, registering the listener. * * May throw an {@link IllegalArgumentException} or an {@link IllegalStateException}, which * will be intercepted and passed to the app as - * {@link android.telephony.mbms.MbmsException.InitializationErrors#ERROR_UNABLE_TO_INITIALIZE} + * {@link MbmsErrors.InitializationErrors#ERROR_UNABLE_TO_INITIALIZE} * - * May return any value from {@link android.telephony.mbms.MbmsException.InitializationErrors} - * or {@link MbmsException#SUCCESS}. Non-successful error codes will be passed to the app via - * {@link IMbmsDownloadManagerCallback#error(int, String)}. + * May return any value from {@link MbmsErrors.InitializationErrors} + * or {@link MbmsErrors#SUCCESS}. Non-successful error codes will be passed to the app via + * {@link IMbmsDownloadSessionCallback#onError(int, String)}. * * @param callback The callback to use to communicate with the app. * @param subscriptionId The subscription ID to use. */ - public int initialize(int subscriptionId, MbmsDownloadManagerCallback callback) + public int initialize(int subscriptionId, MbmsDownloadSessionCallback callback) throws RemoteException { return 0; } @@ -64,7 +71,7 @@ public class MbmsDownloadServiceBase extends IMbmsDownloadService.Stub { */ @Override public final int initialize(final int subscriptionId, - final IMbmsDownloadManagerCallback callback) throws RemoteException { + final IMbmsDownloadSessionCallback callback) throws RemoteException { final int uid = Binder.getCallingUid(); callback.asBinder().linkToDeath(new DeathRecipient() { @Override @@ -73,11 +80,11 @@ public class MbmsDownloadServiceBase extends IMbmsDownloadService.Stub { } }, 0); - return initialize(subscriptionId, new MbmsDownloadManagerCallback() { + return initialize(subscriptionId, new MbmsDownloadSessionCallback() { @Override public void onError(int errorCode, String message) { try { - callback.error(errorCode, message); + callback.onError(errorCode, message); } catch (RemoteException e) { onAppCallbackDied(uid, subscriptionId); } @@ -86,7 +93,7 @@ public class MbmsDownloadServiceBase extends IMbmsDownloadService.Stub { @Override public void onFileServicesUpdated(List services) { try { - callback.fileServicesUpdated(services); + callback.onFileServicesUpdated(services); } catch (RemoteException e) { onAppCallbackDied(uid, subscriptionId); } @@ -95,7 +102,7 @@ public class MbmsDownloadServiceBase extends IMbmsDownloadService.Stub { @Override public void onMiddlewareReady() { try { - callback.middlewareReady(); + callback.onMiddlewareReady(); } catch (RemoteException e) { onAppCallbackDied(uid, subscriptionId); } @@ -106,7 +113,7 @@ public class MbmsDownloadServiceBase extends IMbmsDownloadService.Stub { /** * Registers serviceClasses of interest with the appName/subId key. * Starts async fetching data on streaming services of matching classes to be reported - * later via {@link IMbmsDownloadManagerCallback#fileServicesUpdated(List)} + * later via {@link IMbmsDownloadSessionCallback#onFileServicesUpdated(List)} * * Note that subsequent calls with the same uid and subId will replace * the service class list. @@ -117,11 +124,11 @@ public class MbmsDownloadServiceBase extends IMbmsDownloadService.Stub { * @param serviceClasses The service classes that the app wishes to get info on. The strings * may contain arbitrary data as negotiated between the app and the * carrier. - * @return One of {@link MbmsException#SUCCESS} or - * {@link MbmsException.GeneralErrors#ERROR_MIDDLEWARE_NOT_YET_READY}, + * @return One of {@link MbmsErrors#SUCCESS} or + * {@link MbmsErrors.GeneralErrors#ERROR_MIDDLEWARE_NOT_YET_READY}, */ @Override - public int getFileServices(int subscriptionId, List serviceClasses) + public int requestUpdateFileServices(int subscriptionId, List serviceClasses) throws RemoteException { return 0; } @@ -133,13 +140,13 @@ public class MbmsDownloadServiceBase extends IMbmsDownloadService.Stub { * * If the calling app (as identified by the calling UID) currently has any pending download * requests that have not been canceled, the middleware must return - * {@link MbmsException.DownloadErrors#ERROR_CANNOT_CHANGE_TEMP_FILE_ROOT} here. + * {@link MbmsErrors.DownloadErrors#ERROR_CANNOT_CHANGE_TEMP_FILE_ROOT} here. * * @param subscriptionId The subscription id the download is operating under. * @param rootDirectoryPath The path to the app's temp file root directory. - * @return {@link MbmsException#SUCCESS}, - * {@link MbmsException.GeneralErrors#ERROR_MIDDLEWARE_NOT_YET_READY} or - * {@link MbmsException.DownloadErrors#ERROR_CANNOT_CHANGE_TEMP_FILE_ROOT} + * @return {@link MbmsErrors#SUCCESS}, + * {@link MbmsErrors.GeneralErrors#ERROR_MIDDLEWARE_NOT_YET_READY} or + * {@link MbmsErrors.DownloadErrors#ERROR_CANNOT_CHANGE_TEMP_FILE_ROOT} */ @Override public int setTempFileRootDirectory(int subscriptionId, @@ -155,12 +162,32 @@ public class MbmsDownloadServiceBase extends IMbmsDownloadService.Stub { * this is not the case, an {@link IllegalStateException} may be thrown. * * @param downloadRequest An object describing the set of files to be downloaded. - * @param callback A callback through which the middleware can provide progress updates to - * the app while both are still running. - * @return Any error from {@link android.telephony.mbms.MbmsException.GeneralErrors} - * or {@link MbmsException#SUCCESS} + * @return Any error from {@link MbmsErrors.GeneralErrors} + * or {@link MbmsErrors#SUCCESS} */ - public int download(DownloadRequest downloadRequest, DownloadStateCallback callback) { + @Override + public int download(DownloadRequest downloadRequest) throws RemoteException { + return 0; + } + + /** + * Registers a download state callbacks for the provided {@link DownloadRequest}. + * + * This method is called by the app when it wants to request updates on the progress or + * status of the download. + * + * If the middleware is not aware of a download having been requested with the provided + * + * {@link DownloadRequest} in the past, + * {@link MbmsErrors.DownloadErrors#ERROR_UNKNOWN_DOWNLOAD_REQUEST} + * must be returned. + * + * @param downloadRequest The {@link DownloadRequest} that was used to initiate the download + * for which progress updates are being requested. + * @param callback The callback object to use. + */ + public int registerStateCallback(DownloadRequest downloadRequest, + DownloadStateCallback callback) throws RemoteException { return 0; } @@ -169,36 +196,101 @@ public class MbmsDownloadServiceBase extends IMbmsDownloadService.Stub { * @hide */ @Override - public final int download(DownloadRequest downloadRequest, IDownloadStateCallback callback) + public final int registerStateCallback( + final DownloadRequest downloadRequest, final IDownloadStateCallback callback) throws RemoteException { final int uid = Binder.getCallingUid(); - callback.asBinder().linkToDeath(new DeathRecipient() { + DeathRecipient deathRecipient = new DeathRecipient() { @Override public void binderDied() { onAppCallbackDied(uid, downloadRequest.getSubscriptionId()); + mDownloadCallbackBinderMap.remove(callback.asBinder()); + mDownloadCallbackDeathRecipients.remove(callback.asBinder()); } - }, 0); + }; + mDownloadCallbackDeathRecipients.put(callback.asBinder(), deathRecipient); + callback.asBinder().linkToDeath(deathRecipient, 0); - return download(downloadRequest, new DownloadStateCallback() { + DownloadStateCallback exposedCallback = new DownloadStateCallback() { @Override public void onProgressUpdated(DownloadRequest request, FileInfo fileInfo, int currentDownloadSize, int fullDownloadSize, int currentDecodedSize, int fullDecodedSize) { try { - callback.progress(request, fileInfo, currentDownloadSize, fullDownloadSize, + callback.onProgressUpdated(request, fileInfo, currentDownloadSize, + fullDownloadSize, currentDecodedSize, fullDecodedSize); } catch (RemoteException e) { onAppCallbackDied(uid, downloadRequest.getSubscriptionId()); } } - }); + + @Override + public void onStateUpdated(DownloadRequest request, FileInfo fileInfo, + @MbmsDownloadSession.DownloadStatus int state) { + try { + callback.onStateUpdated(request, fileInfo, state); + } catch (RemoteException e) { + onAppCallbackDied(uid, downloadRequest.getSubscriptionId()); + } + } + }; + + mDownloadCallbackBinderMap.put(callback.asBinder(), exposedCallback); + + return registerStateCallback(downloadRequest, exposedCallback); } + /** + * Un-registers a download state callbacks for the provided {@link DownloadRequest}. + * + * This method is called by the app when it no longer wants to request updates on the + * download. + * + * If the middleware is not aware of a download having been requested with the provided + * {@link DownloadRequest} in the past, + * {@link MbmsErrors.DownloadErrors#ERROR_UNKNOWN_DOWNLOAD_REQUEST} + * must be returned. + * + * @param downloadRequest The {@link DownloadRequest} that was used to register the callback + * @param callback The callback object that + * {@link #registerStateCallback(DownloadRequest, DownloadStateCallback)} + * was called with. + */ + public int unregisterStateCallback(DownloadRequest downloadRequest, + DownloadStateCallback callback) throws RemoteException { + return 0; + } + + /** + * Actual AIDL implementation -- hides the callback AIDL from the API. + * @hide + */ + @Override + public final int unregisterStateCallback( + final DownloadRequest downloadRequest, final IDownloadStateCallback callback) + throws RemoteException { + DeathRecipient deathRecipient = + mDownloadCallbackDeathRecipients.remove(callback.asBinder()); + if (deathRecipient == null) { + throw new IllegalArgumentException("Unknown callback"); + } + + callback.asBinder().unlinkToDeath(deathRecipient, 0); + + DownloadStateCallback exposedCallback = + mDownloadCallbackBinderMap.remove(callback.asBinder()); + if (exposedCallback == null) { + throw new IllegalArgumentException("Unknown callback"); + } + + return unregisterStateCallback(downloadRequest, exposedCallback); + } /** * 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 - * {@link #download(DownloadRequest, DownloadStateCallback)} but not cancelled through + * {@link #download(DownloadRequest)} but not cancelled through * {@link #cancelDownload(DownloadRequest)}. * The middleware must return a non-null result synchronously or throw an exception * inheriting from {@link RuntimeException}. @@ -214,13 +306,13 @@ public class MbmsDownloadServiceBase extends IMbmsDownloadService.Stub { * Issues a request to cancel the specified download request. * * If the middleware is unable to cancel the request for whatever reason, it should return - * synchronously with an error. If this method returns {@link MbmsException#SUCCESS}, the app + * synchronously with an error. If this method returns {@link MbmsErrors#SUCCESS}, the app * will no longer be expecting any more file-completed intents from the middleware for this * {@link DownloadRequest}. * @param downloadRequest The request to cancel - * @return {@link MbmsException#SUCCESS}, - * {@link MbmsException.DownloadErrors#ERROR_UNKNOWN_DOWNLOAD_REQUEST}, - * {@link MbmsException.GeneralErrors#ERROR_MIDDLEWARE_NOT_YET_READY} + * @return {@link MbmsErrors#SUCCESS}, + * {@link MbmsErrors.DownloadErrors#ERROR_UNKNOWN_DOWNLOAD_REQUEST}, + * {@link MbmsErrors.GeneralErrors#ERROR_MIDDLEWARE_NOT_YET_READY} */ @Override public int cancelDownload(DownloadRequest downloadRequest) throws RemoteException { @@ -232,7 +324,7 @@ public class MbmsDownloadServiceBase extends IMbmsDownloadService.Stub { * * If the middleware has not yet been properly initialized or if it has no records of the * file indicated by {@code fileInfo} being associated with {@code downloadRequest}, - * {@link android.telephony.MbmsDownloadManager#STATUS_UNKNOWN} must be returned. + * {@link MbmsDownloadSession#STATUS_UNKNOWN} must be returned. * * @param downloadRequest The download request to query. * @param fileInfo The particular file within the request to get information on. @@ -252,7 +344,7 @@ public class MbmsDownloadServiceBase extends IMbmsDownloadService.Stub { * In addition, current in-progress downloads must not be interrupted. * * If the middleware is not aware of the specified download request, return - * {@link MbmsException.DownloadErrors#ERROR_UNKNOWN_DOWNLOAD_REQUEST}. + * {@link MbmsErrors.DownloadErrors#ERROR_UNKNOWN_DOWNLOAD_REQUEST}. * * @param downloadRequest The request to re-download files for. */ @@ -266,7 +358,7 @@ public class MbmsDownloadServiceBase extends IMbmsDownloadService.Stub { * Signals that the app wishes to dispose of the session identified by the * {@code subscriptionId} argument and the caller's uid. No notification back to the * app is required for this operation, and the corresponding callback provided via - * {@link #initialize(int, IMbmsDownloadManagerCallback)} should no longer be used + * {@link #initialize(int, IMbmsDownloadSessionCallback)} should no longer be used * after this method has been called by the app. * * Any download requests issued by the app should remain in effect until the app calls diff --git a/telephony/java/android/telephony/mbms/vendor/MbmsStreamingServiceBase.java b/telephony/java/android/telephony/mbms/vendor/MbmsStreamingServiceBase.java index ecff62cc81907..f998f2ec8278d 100644 --- a/telephony/java/android/telephony/mbms/vendor/MbmsStreamingServiceBase.java +++ b/telephony/java/android/telephony/mbms/vendor/MbmsStreamingServiceBase.java @@ -22,10 +22,10 @@ import android.content.Intent; import android.net.Uri; import android.os.Binder; import android.os.RemoteException; -import android.telephony.mbms.IMbmsStreamingManagerCallback; +import android.telephony.mbms.IMbmsStreamingSessionCallback; import android.telephony.mbms.IStreamingServiceCallback; -import android.telephony.mbms.MbmsException; -import android.telephony.mbms.MbmsStreamingManagerCallback; +import android.telephony.mbms.MbmsErrors; +import android.telephony.mbms.MbmsStreamingSessionCallback; import android.telephony.mbms.StreamingService; import android.telephony.mbms.StreamingServiceCallback; import android.telephony.mbms.StreamingServiceInfo; @@ -44,16 +44,16 @@ public class MbmsStreamingServiceBase extends IMbmsStreamingService.Stub { * * May throw an {@link IllegalArgumentException} or a {@link SecurityException}, which * will be intercepted and passed to the app as - * {@link android.telephony.mbms.MbmsException.InitializationErrors#ERROR_UNABLE_TO_INITIALIZE} + * {@link MbmsErrors.InitializationErrors#ERROR_UNABLE_TO_INITIALIZE} * - * May return any value from {@link android.telephony.mbms.MbmsException.InitializationErrors} - * or {@link MbmsException#SUCCESS}. Non-successful error codes will be passed to the app via - * {@link IMbmsStreamingManagerCallback#error(int, String)}. + * May return any value from {@link MbmsErrors.InitializationErrors} + * or {@link MbmsErrors#SUCCESS}. Non-successful error codes will be passed to the app via + * {@link IMbmsStreamingSessionCallback#onError(int, String)}. * * @param callback The callback to use to communicate with the app. * @param subscriptionId The subscription ID to use. */ - public int initialize(MbmsStreamingManagerCallback callback, int subscriptionId) + public int initialize(MbmsStreamingSessionCallback callback, int subscriptionId) throws RemoteException { return 0; } @@ -63,7 +63,7 @@ public class MbmsStreamingServiceBase extends IMbmsStreamingService.Stub { * @hide */ @Override - public final int initialize(final IMbmsStreamingManagerCallback callback, + public final int initialize(final IMbmsStreamingSessionCallback callback, final int subscriptionId) throws RemoteException { final int uid = Binder.getCallingUid(); callback.asBinder().linkToDeath(new DeathRecipient() { @@ -73,20 +73,20 @@ public class MbmsStreamingServiceBase extends IMbmsStreamingService.Stub { } }, 0); - return initialize(new MbmsStreamingManagerCallback() { + return initialize(new MbmsStreamingSessionCallback() { @Override - public void onError(int errorCode, String message) { + public void onError(final int errorCode, final String message) { try { - callback.error(errorCode, message); + callback.onError(errorCode, message); } catch (RemoteException e) { onAppCallbackDied(uid, subscriptionId); } } @Override - public void onStreamingServicesUpdated(List services) { + public void onStreamingServicesUpdated(final List services) { try { - callback.streamingServicesUpdated(services); + callback.onStreamingServicesUpdated(services); } catch (RemoteException e) { onAppCallbackDied(uid, subscriptionId); } @@ -95,7 +95,7 @@ public class MbmsStreamingServiceBase extends IMbmsStreamingService.Stub { @Override public void onMiddlewareReady() { try { - callback.middlewareReady(); + callback.onMiddlewareReady(); } catch (RemoteException e) { onAppCallbackDied(uid, subscriptionId); } @@ -107,7 +107,7 @@ public class MbmsStreamingServiceBase extends IMbmsStreamingService.Stub { /** * Registers serviceClasses of interest with the appName/subId key. * Starts async fetching data on streaming services of matching classes to be reported - * later via {@link IMbmsStreamingManagerCallback#streamingServicesUpdated(List)} + * later via {@link IMbmsStreamingSessionCallback#onStreamingServicesUpdated(List)} * * Note that subsequent calls with the same uid and subId will replace * the service class list. @@ -118,11 +118,11 @@ public class MbmsStreamingServiceBase extends IMbmsStreamingService.Stub { * @param serviceClasses The service classes that the app wishes to get info on. The strings * may contain arbitrary data as negotiated between the app and the * carrier. - * @return {@link MbmsException#SUCCESS} or any of the errors in - * {@link android.telephony.mbms.MbmsException.GeneralErrors} + * @return {@link MbmsErrors#SUCCESS} or any of the errors in + * {@link MbmsErrors.GeneralErrors} */ @Override - public int getStreamingServices(int subscriptionId, + public int requestUpdateStreamingServices(int subscriptionId, List serviceClasses) throws RemoteException { return 0; } @@ -130,14 +130,14 @@ public class MbmsStreamingServiceBase extends IMbmsStreamingService.Stub { /** * Starts streaming on a particular service. This method may perform asynchronous work. When * the middleware is ready to send bits to the frontend, it should inform the app via - * {@link IStreamingServiceCallback#streamStateUpdated(int, int)}. + * {@link IStreamingServiceCallback#onStreamStateUpdated(int, int)}. * * May throw an {@link IllegalArgumentException} or an {@link IllegalStateException} * * @param subscriptionId The subscription id to use. * @param serviceId The ID of the streaming service that the app has requested. * @param callback The callback object on which the app wishes to receive updates. - * @return Any error in {@link android.telephony.mbms.MbmsException.GeneralErrors} + * @return Any error in {@link MbmsErrors.GeneralErrors} */ public int startStreaming(int subscriptionId, String serviceId, StreamingServiceCallback callback) throws RemoteException { @@ -150,8 +150,8 @@ public class MbmsStreamingServiceBase extends IMbmsStreamingService.Stub { * @hide */ @Override - public int startStreaming(int subscriptionId, String serviceId, - IStreamingServiceCallback callback) throws RemoteException { + public int startStreaming(final int subscriptionId, String serviceId, + final IStreamingServiceCallback callback) throws RemoteException { final int uid = Binder.getCallingUid(); callback.asBinder().linkToDeath(new DeathRecipient() { @Override @@ -162,19 +162,19 @@ public class MbmsStreamingServiceBase extends IMbmsStreamingService.Stub { return startStreaming(subscriptionId, serviceId, new StreamingServiceCallback() { @Override - public void onError(int errorCode, String message) { + public void onError(final int errorCode, final String message) { try { - callback.error(errorCode, message); + callback.onError(errorCode, message); } catch (RemoteException e) { onAppCallbackDied(uid, subscriptionId); } } @Override - public void onStreamStateUpdated(@StreamingService.StreamingState int state, - @StreamingService.StreamingStateChangeReason int reason) { + public void onStreamStateUpdated(@StreamingService.StreamingState final int state, + @StreamingService.StreamingStateChangeReason final int reason) { try { - callback.streamStateUpdated(state, reason); + callback.onStreamStateUpdated(state, reason); } catch (RemoteException e) { onAppCallbackDied(uid, subscriptionId); } @@ -183,25 +183,25 @@ public class MbmsStreamingServiceBase extends IMbmsStreamingService.Stub { @Override public void onMediaDescriptionUpdated() { try { - callback.mediaDescriptionUpdated(); + callback.onMediaDescriptionUpdated(); } catch (RemoteException e) { onAppCallbackDied(uid, subscriptionId); } } @Override - public void onBroadcastSignalStrengthUpdated(int signalStrength) { + public void onBroadcastSignalStrengthUpdated(final int signalStrength) { try { - callback.broadcastSignalStrengthUpdated(signalStrength); + callback.onBroadcastSignalStrengthUpdated(signalStrength); } catch (RemoteException e) { onAppCallbackDied(uid, subscriptionId); } } @Override - public void onStreamMethodUpdated(int methodType) { + public void onStreamMethodUpdated(final int methodType) { try { - callback.streamMethodUpdated(methodType); + callback.onStreamMethodUpdated(methodType); } catch (RemoteException e) { onAppCallbackDied(uid, subscriptionId); } @@ -228,7 +228,11 @@ public class MbmsStreamingServiceBase extends IMbmsStreamingService.Stub { /** * Stop streaming the stream identified by {@code serviceId}. Notification of the resulting * stream state change should be reported to the app via - * {@link IStreamingServiceCallback#streamStateUpdated(int, int)}. + * {@link IStreamingServiceCallback#onStreamStateUpdated(int, int)}. + * + * In addition, the callback provided via + * {@link #startStreaming(int, String, IStreamingServiceCallback)} should no longer be + * used after this method has called by the app. * * May throw an {@link IllegalArgumentException} or an {@link IllegalStateException} * @@ -240,28 +244,11 @@ public class MbmsStreamingServiceBase extends IMbmsStreamingService.Stub { throws RemoteException { } - /** - * Dispose of the stream identified by {@code serviceId} for the app identified by the - * {@code appName} and {@code subscriptionId} arguments along with the caller's uid. - * No notification back to the app is required for this operation, and the callback provided via - * {@link #startStreaming(int, String, IStreamingServiceCallback)} should no longer be - * used after this method has called by the app. - * - * May throw an {@link IllegalArgumentException} or an {@link IllegalStateException} - * - * @param subscriptionId The subscription id to use. - * @param serviceId The ID of the streaming service that the app wishes to dispose of. - */ - @Override - public void disposeStream(int subscriptionId, String serviceId) - throws RemoteException { - } - /** * Signals that the app wishes to dispose of the session identified by the * {@code subscriptionId} argument and the caller's uid. No notification back to the * app is required for this operation, and the corresponding callback provided via - * {@link #initialize(IMbmsStreamingManagerCallback, int)} should no longer be used + * {@link #initialize(IMbmsStreamingSessionCallback, int)} should no longer be used * after this method has been called by the app. * * May throw an {@link IllegalStateException} diff --git a/telephony/java/android/telephony/mbms/vendor/VendorUtils.java b/telephony/java/android/telephony/mbms/vendor/VendorUtils.java index e66723771c024..7bab734397ee7 100644 --- a/telephony/java/android/telephony/mbms/vendor/VendorUtils.java +++ b/telephony/java/android/telephony/mbms/vendor/VendorUtils.java @@ -22,7 +22,7 @@ import android.content.Context; import android.content.Intent; import android.content.pm.ResolveInfo; import android.net.Uri; -import android.telephony.mbms.DownloadRequest; +import android.telephony.MbmsDownloadSession; import android.telephony.mbms.MbmsDownloadReceiver; import java.io.File; @@ -39,9 +39,9 @@ public class VendorUtils { /** * The MBMS middleware should send this when a download of single file has completed or * failed. Mandatory extras are - * {@link android.telephony.MbmsDownloadManager#EXTRA_MBMS_DOWNLOAD_RESULT} - * {@link android.telephony.MbmsDownloadManager#EXTRA_MBMS_FILE_INFO} - * {@link #EXTRA_REQUEST} + * {@link MbmsDownloadSession#EXTRA_MBMS_DOWNLOAD_RESULT} + * {@link MbmsDownloadSession#EXTRA_MBMS_FILE_INFO} + * {@link MbmsDownloadSession#EXTRA_MBMS_DOWNLOAD_REQUEST} * {@link #EXTRA_TEMP_LIST} * {@link #EXTRA_FINAL_URI} */ @@ -120,12 +120,6 @@ public class VendorUtils { public static final String EXTRA_TEMP_FILES_IN_USE = "android.telephony.mbms.extra.TEMP_FILES_IN_USE"; - /** - * Extra containing the {@link DownloadRequest} for which the download result or file - * descriptor request is for. Must not be null. - */ - public static final String EXTRA_REQUEST = "android.telephony.mbms.extra.REQUEST"; - /** * Extra containing a single {@link Uri} indicating the path to the temp file in which the * decoded downloaded file resides. Must not be null.