Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 727a05b2 authored by Hall Liu's avatar Hall Liu
Browse files

Add callback for initialization done

Add callback for initialization done in the framework, and listen to it
in the testapps. Make initialization asynchronous as well for both
download and streaming.

Change-Id: Iea7f803df9d2752401b2eca9f6c7375007cac35e
parent fcbf2407
Loading
Loading
Loading
Loading
+49 −77
Original line number Diff line number Diff line
@@ -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() {
        MbmsUtils.startBinding(mContext, MBMS_DOWNLOAD_SERVICE_ACTION,
                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);
            }

                        IMbmsDownloadService downloadService =
                                IMbmsDownloadService.Stub.asInterface(service);
                        try {
                mService.initialize(mDownloadAppName, mSubscriptionId, mCallback);
                            downloadService.initialize(
                                    mDownloadAppName, mSubscriptionId, mCallback);
                        } catch (RemoteException e) {
                mService = null;
                            Log.e(LOG_TAG, "Service died before initialization");
                throw new MbmsException(MbmsException.ERROR_SERVICE_LOST);
                            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");
+39 −105
Original line number Diff line number Diff line
@@ -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();
            }

        MbmsUtils.startBinding(mContext, MBMS_STREAMING_SERVICE_ACTION,
                new ServiceConnection() {
                    @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);
            }

                    public void onServiceConnected(ComponentName name, IBinder service) {
                        IMbmsStreamingService streamingService =
                                IMbmsStreamingService.Stub.asInterface(service);
                        try {
                int returnCode = mService.initialize(mCallbackToApp, mAppName, mSubscriptionId);
                if (returnCode != MbmsException.SUCCESS) {
                    throw new MbmsException(returnCode);
                }
                            streamingService.initialize(mCallbackToApp, mAppName, mSubscriptionId);
                        } catch (RemoteException e) {
                mService = null;
                            Log.e(LOG_TAG, "Service died before initialization");
                throw new MbmsException(MbmsException.ERROR_SERVICE_LOST);
            }
                            return;
                        }
                        mService.set(null);
                    }

                    @Override
                    public void onServiceDisconnected(ComponentName name) {
                        mService.set(null);
                    }
                });
    }
}
+3 −11
Original line number Diff line number Diff line
@@ -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();
}
+3 −20
Original line number Diff line number Diff line
@@ -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();
}
+13 −0
Original line number Diff line number Diff line
@@ -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
    }
}
Loading