diff options
8 files changed, 137 insertions, 228 deletions
diff --git a/telephony/java/android/telephony/MbmsDownloadManager.java b/telephony/java/android/telephony/MbmsDownloadManager.java index 597756e7aaf3..79ee37a168d4 100644 --- a/telephony/java/android/telephony/MbmsDownloadManager.java +++ b/telephony/java/android/telephony/MbmsDownloadManager.java @@ -23,10 +23,8 @@ import android.content.Intent; import android.content.ServiceConnection; import android.content.SharedPreferences; import android.content.pm.ResolveInfo; -import android.content.pm.ServiceInfo; import android.net.Uri; import android.os.IBinder; -import android.os.Looper; import android.os.RemoteException; import android.telephony.mbms.IDownloadCallback; import android.telephony.mbms.DownloadRequest; @@ -43,7 +41,7 @@ import android.util.Log; import java.io.File; import java.io.IOException; import java.util.List; -import java.util.concurrent.CountDownLatch; +import java.util.concurrent.atomic.AtomicReference; import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID; @@ -183,12 +181,10 @@ public class MbmsDownloadManager { public static final int RESULT_EXPIRED = 3; // TODO - more results! - private static final long BIND_TIMEOUT_MS = 3000; - private final Context mContext; private int mSubscriptionId = INVALID_SUBSCRIPTION_ID; - private IMbmsDownloadService mService; + private AtomicReference<IMbmsDownloadService> mService = new AtomicReference<>(null); private final IMbmsDownloadManagerCallback mCallback; private final String mDownloadAppName; @@ -202,26 +198,24 @@ public class MbmsDownloadManager { /** * Create a new MbmsDownloadManager using the system default data subscription ID. - * See {@link #createManager(Context, IMbmsDownloadManagerCallback, String, int)} + * See {@link #create(Context, IMbmsDownloadManagerCallback, String, int)} * * @hide */ - public static MbmsDownloadManager createManager(Context context, + public static MbmsDownloadManager create(Context context, IMbmsDownloadManagerCallback listener, String downloadAppName) throws MbmsException { - MbmsDownloadManager mdm = new MbmsDownloadManager(context, listener, downloadAppName, + return create(context, listener, downloadAppName, SubscriptionManager.getDefaultSubscriptionId()); - mdm.bindAndInitialize(); - return mdm; } /** * Create a new MbmsDownloadManager using the given subscription ID. * - * Note that this call will bind a remote service and that may take a bit. Since the - * framework notifies us that binding is complete on the main thread, this method should - * never be called from the main thread of one's app, or else an - * {@link IllegalStateException} will be thrown. + * 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 IMbmsDownloadManagerCallback#middlewareReady()} is called on the provided callback. + * If you attempt to use the manager before it is ready, a {@link MbmsException} will be thrown. * * This also may throw an {@link IllegalArgumentException} or a {@link MbmsException}. * @@ -231,14 +225,9 @@ public class MbmsDownloadManager { * @param subscriptionId The data subscription ID to use * @hide */ - public static MbmsDownloadManager createManager(Context context, + public static MbmsDownloadManager create(Context context, IMbmsDownloadManagerCallback listener, String downloadAppName, int subscriptionId) throws MbmsException { - if (Looper.getMainLooper().isCurrentThread()) { - throw new IllegalStateException( - "createManager must not be called from the main thread."); - } - MbmsDownloadManager mdm = new MbmsDownloadManager(context, listener, downloadAppName, subscriptionId); mdm.bindAndInitialize(); @@ -246,50 +235,27 @@ public class MbmsDownloadManager { } private void bindAndInitialize() throws MbmsException { - // TODO: fold binding for download and streaming into a common utils class. - final CountDownLatch latch = new CountDownLatch(1); - ServiceConnection bindListener = new ServiceConnection() { - @Override - public void onServiceConnected(ComponentName name, IBinder service) { - mService = IMbmsDownloadService.Stub.asInterface(service); - latch.countDown(); - } - - @Override - public void onServiceDisconnected(ComponentName name) { - mService = null; - } - }; - - Intent bindIntent = new Intent(); - ServiceInfo mbmsServiceInfo = - MbmsUtils.getMiddlewareServiceInfo(mContext, MBMS_DOWNLOAD_SERVICE_ACTION); - - if (mbmsServiceInfo == null) { - throw new MbmsException(MbmsException.ERROR_NO_SERVICE_INSTALLED); - } - - bindIntent.setComponent(MbmsUtils.toComponentName(mbmsServiceInfo)); - - mContext.bindService(bindIntent, bindListener, Context.BIND_AUTO_CREATE); - - // Wait until binding is complete - MbmsUtils.waitOnLatchWithTimeout(latch, BIND_TIMEOUT_MS); - - // Call initialize after binding finishes - synchronized (this) { - if (mService == null) { - throw new MbmsException(MbmsException.ERROR_BIND_TIMEOUT_OR_FAILURE); - } - - try { - mService.initialize(mDownloadAppName, mSubscriptionId, mCallback); - } catch (RemoteException e) { - mService = null; - Log.e(LOG_TAG, "Service died before initialization"); - throw new MbmsException(MbmsException.ERROR_SERVICE_LOST); - } - } + MbmsUtils.startBinding(mContext, MBMS_DOWNLOAD_SERVICE_ACTION, + new ServiceConnection() { + @Override + public void onServiceConnected(ComponentName name, IBinder service) { + IMbmsDownloadService downloadService = + IMbmsDownloadService.Stub.asInterface(service); + try { + downloadService.initialize( + mDownloadAppName, mSubscriptionId, mCallback); + } catch (RemoteException e) { + Log.e(LOG_TAG, "Service died before initialization"); + return; + } + mService.set(downloadService); + } + + @Override + public void onServiceDisconnected(ComponentName name) { + mService.set(null); + } + }); } /** @@ -314,17 +280,19 @@ public class MbmsDownloadManager { * {@link MbmsException#ERROR_END_OF_SESSION} */ public void getFileServices(List<String> classList) throws MbmsException { - if (mService == null) { + IMbmsDownloadService downloadService = mService.get(); + if (downloadService == null) { throw new MbmsException(MbmsException.ERROR_MIDDLEWARE_NOT_BOUND); } try { - int returnCode = mService.getFileServices(mDownloadAppName, mSubscriptionId, classList); + int returnCode = downloadService.getFileServices( + mDownloadAppName, mSubscriptionId, classList); if (returnCode != MbmsException.SUCCESS) { throw new MbmsException(returnCode); } } catch (RemoteException e) { Log.w(LOG_TAG, "Remote process died"); - mService = null; + mService.set(null); throw new MbmsException(MbmsException.ERROR_SERVICE_LOST); } } @@ -351,7 +319,8 @@ public class MbmsDownloadManager { */ public void setTempFileRootDirectory(@NonNull File tempFileRootDirectory) throws MbmsException { - if (mService == null) { + IMbmsDownloadService downloadService = mService.get(); + if (downloadService == null) { throw new MbmsException(MbmsException.ERROR_MIDDLEWARE_NOT_BOUND); } if (!tempFileRootDirectory.exists()) { @@ -368,13 +337,13 @@ public class MbmsDownloadManager { } try { - int result = mService.setTempFileRootDirectory( + int result = downloadService.setTempFileRootDirectory( mDownloadAppName, mSubscriptionId, filePath); if (result != MbmsException.SUCCESS) { throw new MbmsException(result); } } catch (RemoteException e) { - mService = null; + mService.set(null); throw new MbmsException(MbmsException.ERROR_SERVICE_LOST); } @@ -405,7 +374,8 @@ public class MbmsDownloadManager { */ public void download(DownloadRequest request, IDownloadCallback callback) throws MbmsException { - if (mService == null) { + IMbmsDownloadService downloadService = mService.get(); + if (downloadService == null) { throw new MbmsException(MbmsException.ERROR_MIDDLEWARE_NOT_BOUND); } @@ -434,9 +404,9 @@ public class MbmsDownloadManager { // TODO: check to make sure destination is clear // TODO: write download request token try { - mService.download(request, callback); + downloadService.download(request, callback); } catch (RemoteException e) { - mService = null; + mService.set(null); } } @@ -536,11 +506,13 @@ public class MbmsDownloadManager { public void dispose() { try { - if (mService != null) { - mService.dispose(mDownloadAppName, mSubscriptionId); - } else { + IMbmsDownloadService downloadService = mService.get(); + if (downloadService == null) { Log.i(LOG_TAG, "Service already dead"); + return; } + downloadService.dispose(mDownloadAppName, mSubscriptionId); + mService.set(null); } catch (RemoteException e) { // Ignore Log.i(LOG_TAG, "Remote exception while disposing of service"); diff --git a/telephony/java/android/telephony/MbmsStreamingManager.java b/telephony/java/android/telephony/MbmsStreamingManager.java index f68e2439971f..af7f333390d8 100644 --- a/telephony/java/android/telephony/MbmsStreamingManager.java +++ b/telephony/java/android/telephony/MbmsStreamingManager.java @@ -18,11 +18,7 @@ package android.telephony; import android.content.ComponentName; import android.content.Context; -import android.content.Intent; import android.content.ServiceConnection; -import android.content.pm.PackageManager; -import android.content.pm.ResolveInfo; -import android.os.DeadObjectException; import android.os.IBinder; import android.os.RemoteException; import android.telephony.mbms.MbmsException; @@ -34,56 +30,18 @@ import android.telephony.mbms.StreamingServiceInfo; import android.telephony.mbms.vendor.IMbmsStreamingService; import android.util.Log; -import java.util.LinkedList; import java.util.List; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicReference; import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID; /** @hide */ public class MbmsStreamingManager { - private interface ServiceListener { - void onServiceConnected(); - void onServiceDisconnected(); - } - private static final String LOG_TAG = "MbmsStreamingManager"; public static final String MBMS_STREAMING_SERVICE_ACTION = "android.telephony.action.EmbmsStreaming"; - private static final boolean DEBUG = true; - private static final int BIND_TIMEOUT_MS = 3000; - - private IMbmsStreamingService mService; - private ServiceConnection mServiceConnection = new ServiceConnection() { - @Override - public void onServiceConnected(ComponentName name, IBinder service) { - if (service != null) { - Log.i(LOG_TAG, String.format("Connected to service %s", name)); - synchronized (MbmsStreamingManager.this) { - mService = IMbmsStreamingService.Stub.asInterface(service); - for (ServiceListener l : mServiceListeners) { - l.onServiceConnected(); - } - } - } - } - - @Override - public void onServiceDisconnected(ComponentName name) { - Log.i(LOG_TAG, String.format("Disconnected from service %s", name)); - synchronized (MbmsStreamingManager.this) { - mService = null; - for (ServiceListener l : mServiceListeners) { - l.onServiceDisconnected(); - } - } - } - }; - - private List<ServiceListener> mServiceListeners = new LinkedList<>(); - + private AtomicReference<IMbmsStreamingService> mService = new AtomicReference<>(null); private MbmsStreamingManagerCallback mCallbackToApp; private final String mAppName; @@ -128,28 +86,26 @@ public class MbmsStreamingManager { public static MbmsStreamingManager create(Context context, MbmsStreamingManagerCallback listener, String streamingAppName) throws MbmsException { - int subId = SubscriptionManager.getDefaultSubscriptionId(); - MbmsStreamingManager manager = new MbmsStreamingManager(context, listener, - streamingAppName, subId); - manager.bindAndInitialize(); - return manager; + return create(context, listener, streamingAppName, + SubscriptionManager.getDefaultSubscriptionId()); } /** * Terminates this instance, ending calls to the registered listener. Also terminates * any streaming services spawned from this instance. */ - public synchronized void dispose() { - if (mService == null) { + public void dispose() { + IMbmsStreamingService streamingService = mService.get(); + if (streamingService == null) { // Ignore and return, assume already disposed. return; } try { - mService.dispose(mAppName, mSubscriptionId); + streamingService.dispose(mAppName, mSubscriptionId); } catch (RemoteException e) { // Ignore for now } - mService = null; + mService.set(null); } /** @@ -171,17 +127,19 @@ public class MbmsStreamingManager { * {@link MbmsException#ERROR_END_OF_SESSION} */ public void getStreamingServices(List<String> classList) throws MbmsException { - if (mService == null) { + IMbmsStreamingService streamingService = mService.get(); + if (streamingService == null) { throw new MbmsException(MbmsException.ERROR_MIDDLEWARE_NOT_BOUND); } try { - int returnCode = mService.getStreamingServices(mAppName, mSubscriptionId, classList); + int returnCode = streamingService.getStreamingServices( + mAppName, mSubscriptionId, classList); if (returnCode != MbmsException.SUCCESS) { throw new MbmsException(returnCode); } } catch (RemoteException e) { Log.w(LOG_TAG, "Remote process died"); - mService = null; + mService.set(null); throw new MbmsException(MbmsException.ERROR_SERVICE_LOST); } } @@ -190,7 +148,7 @@ public class MbmsStreamingManager { * Starts streaming a requested service, reporting status to the indicated listener. * Returns an object used to control that stream. The stream may not be ready for consumption * immediately upon return from this method -- wait until the streaming state has been - * reported via {@link android.telephony.mbms.StreamingServiceCallback#streamStateChanged(int)}. + * reported via {@link android.telephony.mbms.StreamingServiceCallback#streamStateUpdated(int)} * * May throw an {@link MbmsException} containing any of the following error codes: * {@link MbmsException#ERROR_MIDDLEWARE_NOT_BOUND} @@ -203,71 +161,47 @@ public class MbmsStreamingManager { */ public StreamingService startStreaming(StreamingServiceInfo serviceInfo, StreamingServiceCallback listener) throws MbmsException { - if (mService == null) { + IMbmsStreamingService streamingService = mService.get(); + if (streamingService == null) { throw new MbmsException(MbmsException.ERROR_MIDDLEWARE_NOT_BOUND); } try { - int returnCode = mService.startStreaming( + int returnCode = streamingService.startStreaming( mAppName, mSubscriptionId, serviceInfo.getServiceId(), listener); if (returnCode != MbmsException.SUCCESS) { throw new MbmsException(returnCode); } } catch (RemoteException e) { Log.w(LOG_TAG, "Remote process died"); - mService = null; + mService.set(null); throw new MbmsException(MbmsException.ERROR_SERVICE_LOST); } return new StreamingService( - mAppName, mSubscriptionId, mService, serviceInfo, listener); + mAppName, mSubscriptionId, streamingService, serviceInfo, listener); } private void bindAndInitialize() throws MbmsException { - // Kick off the binding, and synchronously wait until binding is complete - final CountDownLatch latch = new CountDownLatch(1); - ServiceListener bindListener = new ServiceListener() { - @Override - public void onServiceConnected() { - latch.countDown(); - } - - @Override - public void onServiceDisconnected() { - } - }; - - synchronized (this) { - mServiceListeners.add(bindListener); - } - - Intent bindIntent = new Intent(); - bindIntent.setComponent(MbmsUtils.toComponentName( - MbmsUtils.getMiddlewareServiceInfo(mContext, MBMS_STREAMING_SERVICE_ACTION))); - - mContext.bindService(bindIntent, mServiceConnection, Context.BIND_AUTO_CREATE); - - MbmsUtils.waitOnLatchWithTimeout(latch, BIND_TIMEOUT_MS); - - // Remove the listener and call the initialization method through the interface. - synchronized (this) { - mServiceListeners.remove(bindListener); - - if (mService == null) { - throw new MbmsException(MbmsException.ERROR_BIND_TIMEOUT_OR_FAILURE); - } + MbmsUtils.startBinding(mContext, MBMS_STREAMING_SERVICE_ACTION, + new ServiceConnection() { + @Override + public void onServiceConnected(ComponentName name, IBinder service) { + IMbmsStreamingService streamingService = + IMbmsStreamingService.Stub.asInterface(service); + try { + streamingService.initialize(mCallbackToApp, mAppName, mSubscriptionId); + } catch (RemoteException e) { + Log.e(LOG_TAG, "Service died before initialization"); + return; + } + mService.set(null); + } - try { - int returnCode = mService.initialize(mCallbackToApp, mAppName, mSubscriptionId); - if (returnCode != MbmsException.SUCCESS) { - throw new MbmsException(returnCode); - } - } catch (RemoteException e) { - mService = null; - Log.e(LOG_TAG, "Service died before initialization"); - throw new MbmsException(MbmsException.ERROR_SERVICE_LOST); - } - } + @Override + public void onServiceDisconnected(ComponentName name) { + mService.set(null); + } + }); } - } diff --git a/telephony/java/android/telephony/mbms/IMbmsDownloadManagerCallback.aidl b/telephony/java/android/telephony/mbms/IMbmsDownloadManagerCallback.aidl index 03227d0d9f5a..ac2f20243896 100755 --- a/telephony/java/android/telephony/mbms/IMbmsDownloadManagerCallback.aidl +++ b/telephony/java/android/telephony/mbms/IMbmsDownloadManagerCallback.aidl @@ -24,19 +24,11 @@ import java.util.List; * The interface the clients top-level file download listener will satisfy. * @hide */ -interface IMbmsDownloadManagerCallback +oneway interface IMbmsDownloadManagerCallback { void error(int errorCode, String message); - /** - * Called to indicate published File Services have changed. - * - * This will only be called after the application has requested - * a list of file services and specified a service class list - * of interest AND the results of a subsequent getFileServices - * call with the same service class list would - * return different - * results. - */ void fileServicesUpdated(in List<FileServiceInfo> services); + + void middlewareReady(); } diff --git a/telephony/java/android/telephony/mbms/IMbmsStreamingManagerCallback.aidl b/telephony/java/android/telephony/mbms/IMbmsStreamingManagerCallback.aidl index cbf0fca461f0..8116a7f0b7c4 100755 --- a/telephony/java/android/telephony/mbms/IMbmsStreamingManagerCallback.aidl +++ b/telephony/java/android/telephony/mbms/IMbmsStreamingManagerCallback.aidl @@ -24,30 +24,13 @@ import java.util.List; * The interface the clients top-level streaming listener will satisfy. * @hide */ -interface IMbmsStreamingManagerCallback +oneway interface IMbmsStreamingManagerCallback { void error(int errorCode, String message); - /** - * Called to indicate published Streaming Services have changed. - * - * This will only be called after the application has requested - * a list of streaming services and specified a service class list - * of interest AND the results of a subsequent getStreamServices - * call with the same service class list would - * return different - * results. - */ void streamingServicesUpdated(in List<StreamingServiceInfo> services); - /** - * Called to indicate the active Streaming Services have changed. - * - * This will be caused whenever a new service starts streaming or whenever - * MbmsStreamServiceManager.getActiveStreamingServices is called. - * - * @param services a list of StreamingServiceInfos. May be empty if - * there are no active StreamingServices - */ void activeStreamingServicesUpdated(in List<StreamingServiceInfo> services); + + void middlewareReady(); } diff --git a/telephony/java/android/telephony/mbms/MbmsDownloadManagerCallback.java b/telephony/java/android/telephony/mbms/MbmsDownloadManagerCallback.java index 16fafe415b0f..5b22199bea1c 100644 --- a/telephony/java/android/telephony/mbms/MbmsDownloadManagerCallback.java +++ b/telephony/java/android/telephony/mbms/MbmsDownloadManagerCallback.java @@ -48,4 +48,17 @@ public class MbmsDownloadManagerCallback extends IMbmsDownloadManagerCallback.St public void fileServicesUpdated(List<FileServiceInfo> services) { // default implementation empty } + + /** + * 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#ERROR_MIDDLEWARE_NOT_YET_READY} + */ + @Override + public void middlewareReady() { + // default implementation empty + } } diff --git a/telephony/java/android/telephony/mbms/MbmsException.java b/telephony/java/android/telephony/mbms/MbmsException.java index c4611dc9dcd7..8260b728a52f 100644 --- a/telephony/java/android/telephony/mbms/MbmsException.java +++ b/telephony/java/android/telephony/mbms/MbmsException.java @@ -22,7 +22,7 @@ public class MbmsException extends Exception { public static final int ERROR_NO_SERVICE_INSTALLED = 1; public static final int ERROR_MULTIPLE_SERVICES_INSTALLED = 2; public static final int ERROR_BIND_TIMEOUT_OR_FAILURE = 3; - public static final int ERROR_UNABLE_TO_INITIALIZE = 4; + public static final int ERROR_MIDDLEWARE_NOT_YET_READY = 4; public static final int ERROR_ALREADY_INITIALIZED = 5; public static final int ERROR_CONCURRENT_SERVICE_LIMIT_REACHED = 6; public static final int ERROR_MIDDLEWARE_NOT_BOUND = 7; diff --git a/telephony/java/android/telephony/mbms/MbmsStreamingManagerCallback.java b/telephony/java/android/telephony/mbms/MbmsStreamingManagerCallback.java index b3bc8146275e..27d9878a1966 100644 --- a/telephony/java/android/telephony/mbms/MbmsStreamingManagerCallback.java +++ b/telephony/java/android/telephony/mbms/MbmsStreamingManagerCallback.java @@ -61,4 +61,17 @@ public class MbmsStreamingManagerCallback extends IMbmsStreamingManagerCallback. public void activeStreamingServicesUpdated(List<StreamingServiceInfo> services) { // default implementation empty } + + /** + * 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#ERROR_MIDDLEWARE_NOT_YET_READY} + */ + @Override + public void middlewareReady() { + // default implementation empty + } } diff --git a/telephony/java/android/telephony/mbms/MbmsUtils.java b/telephony/java/android/telephony/mbms/MbmsUtils.java index de308053df56..7d4727563eee 100644 --- a/telephony/java/android/telephony/mbms/MbmsUtils.java +++ b/telephony/java/android/telephony/mbms/MbmsUtils.java @@ -19,6 +19,7 @@ package android.telephony.mbms; import android.content.ComponentName; import android.content.Context; import android.content.Intent; +import android.content.ServiceConnection; import android.content.pm.*; import android.content.pm.ServiceInfo; import android.telephony.MbmsDownloadManager; @@ -46,20 +47,6 @@ public class MbmsUtils { } } - public static void waitOnLatchWithTimeout(CountDownLatch l, long timeoutMs) { - long endTime = System.currentTimeMillis() + timeoutMs; - while (System.currentTimeMillis() < endTime) { - try { - l.await(timeoutMs, TimeUnit.MILLISECONDS); - } catch (InterruptedException e) { - // keep waiting - } - if (l.getCount() <= 0) { - return; - } - } - } - public static ComponentName toComponentName(ComponentInfo ci) { return new ComponentName(ci.packageName, ci.name); } @@ -83,4 +70,19 @@ public class MbmsUtils { } return downloadServices.get(0).serviceInfo; } + + public static void startBinding(Context context, String serviceAction, + ServiceConnection serviceConnection) throws MbmsException { + Intent bindIntent = new Intent(); + ServiceInfo mbmsServiceInfo = + MbmsUtils.getMiddlewareServiceInfo(context, serviceAction); + + if (mbmsServiceInfo == null) { + throw new MbmsException(MbmsException.ERROR_NO_SERVICE_INSTALLED); + } + + bindIntent.setComponent(MbmsUtils.toComponentName(mbmsServiceInfo)); + + context.bindService(bindIntent, serviceConnection, Context.BIND_AUTO_CREATE); + } } |