Implement cancelDownload and remove appName

Implements the cancelDownload call
Removes appName as an argument from all EMBMS-related apis
Implements the cross-filesystem move method in MbmsDownloadReceiver

Change-Id: I07b4f72e204b24e0af25baad3727515465117df9
diff --git a/testapps/EmbmsServiceTestApp/src/com/android/phone/testapps/embmsmw/EmbmsSampleDownloadService.java b/testapps/EmbmsServiceTestApp/src/com/android/phone/testapps/embmsmw/EmbmsSampleDownloadService.java
index 67083d7..a5a1327 100644
--- a/testapps/EmbmsServiceTestApp/src/com/android/phone/testapps/embmsmw/EmbmsSampleDownloadService.java
+++ b/testapps/EmbmsServiceTestApp/src/com/android/phone/testapps/embmsmw/EmbmsSampleDownloadService.java
@@ -68,7 +68,7 @@
 
     private final IMbmsDownloadService mBinder = new MbmsDownloadServiceBase() {
         @Override
-        public void initialize(String appName, int subId, IMbmsDownloadManagerCallback listener) {
+        public void initialize(int subId, IMbmsDownloadManagerCallback listener) {
             int packageUid = Binder.getCallingUid();
             String[] packageNames = getPackageManager().getPackagesForUid(packageUid);
             if (packageNames == null) {
@@ -82,8 +82,7 @@
 
             // Do initialization with a bit of a delay to simulate work being done.
             mHandler.postDelayed(() -> {
-                FrontendAppIdentifier appKey =
-                        new FrontendAppIdentifier(packageUid, appName, subId);
+                FrontendAppIdentifier appKey = new FrontendAppIdentifier(packageUid, subId);
                 if (!mAppCallbacks.containsKey(appKey)) {
                     mAppCallbacks.put(appKey, listener);
                     ComponentName appReceiver = MbmsDownloadManager.getAppReceiverFromUid(
@@ -106,10 +105,10 @@
         }
 
         @Override
-        public int getFileServices(String appName, int subscriptionId,
+        public int getFileServices(int subscriptionId,
                 List<String> serviceClasses) throws RemoteException {
             FrontendAppIdentifier appKey =
-                    new FrontendAppIdentifier(Binder.getCallingUid(), appName, subscriptionId);
+                    new FrontendAppIdentifier(Binder.getCallingUid(), subscriptionId);
             checkInitialized(appKey);
 
             List<FileServiceInfo> serviceInfos =
@@ -128,13 +127,13 @@
         }
 
         @Override
-        public int setTempFileRootDirectory(String appName, int subscriptionId,
+        public int setTempFileRootDirectory(int subscriptionId,
                 String rootDirectoryPath) throws RemoteException {
             FrontendAppIdentifier appKey =
-                    new FrontendAppIdentifier(Binder.getCallingUid(), appName, subscriptionId);
+                    new FrontendAppIdentifier(Binder.getCallingUid(), subscriptionId);
             checkInitialized(appKey);
 
-            if (mDoesAppHaveActiveDownload.getOrDefault(appKey, false)) {
+            if (mActiveDownloadRequests.getOrDefault(appKey, Collections.emptySet()).size() > 0) {
                 return MbmsException.ERROR_CANNOT_CHANGE_TEMP_FILE_ROOT;
             }
             mAppTempFileRoots.put(appKey, rootDirectoryPath);
@@ -144,13 +143,25 @@
         @Override
         public int download(DownloadRequest downloadRequest, IDownloadCallback listener) {
             FrontendAppIdentifier appKey = new FrontendAppIdentifier(
-                    Binder.getCallingUid(), downloadRequest.getAppName(),
-                    downloadRequest.getSubscriptionId());
+                    Binder.getCallingUid(), downloadRequest.getSubscriptionId());
             checkInitialized(appKey);
 
             mHandler.post(() -> sendFdRequest(downloadRequest, appKey));
             return MbmsException.SUCCESS;
         }
+
+        @Override
+        public int cancelDownload(DownloadRequest downloadRequest) {
+            FrontendAppIdentifier appKey = new FrontendAppIdentifier(
+                    Binder.getCallingUid(), downloadRequest.getSubscriptionId());
+            checkInitialized(appKey);
+            if (!mActiveDownloadRequests.getOrDefault(
+                    appKey, Collections.emptySet()).contains(downloadRequest)) {
+                return MbmsException.ERROR_UNKNOWN_DOWNLOAD_REQUEST;
+            }
+            mActiveDownloadRequests.get(appKey).remove(downloadRequest);
+            return MbmsException.SUCCESS;
+        }
     };
 
     private static EmbmsSampleDownloadService sInstance = null;
@@ -159,7 +170,7 @@
             new HashMap<>();
     private final Map<FrontendAppIdentifier, ComponentName> mAppReceivers = new HashMap<>();
     private final Map<FrontendAppIdentifier, String> mAppTempFileRoots = new HashMap<>();
-    private final Map<FrontendAppIdentifier, Boolean> mDoesAppHaveActiveDownload =
+    private final Map<FrontendAppIdentifier, Set<DownloadRequest>> mActiveDownloadRequests =
             new ConcurrentHashMap<>();
     // A map of app-identifiers to (maps of service-ids to sets of temp file uris in use)
     private final Map<FrontendAppIdentifier, Map<String, Set<Uri>>> mTempFilesInUse =
@@ -281,9 +292,13 @@
             Log.w(LOG_TAG, "Different numbers of temp files and files to download...");
         }
 
+        if (!mActiveDownloadRequests.containsKey(appKey)) {
+            mActiveDownloadRequests.put(appKey, Collections.synchronizedSet(new HashSet<>()));
+        }
+        mActiveDownloadRequests.get(appKey).add(request);
+
         // Go through the files one-by-one and send them to the frontend app with a delay between
         // each one.
-        mDoesAppHaveActiveDownload.put(appKey, true);
         for (int i = 0; i < tempFiles.size(); i++) {
             if (i >= filesToDownload.size()) {
                 break;
@@ -292,14 +307,14 @@
             addTempFileInUse(appKey, request.getFileServiceInfo().getServiceId(),
                     tempFile.getFilePathUri());
             FileInfo fileToDownload = filesToDownload.get(i);
-            final boolean isLastFile = i == tempFiles.size() - 1;
             mHandler.postDelayed(() -> {
+                if (mActiveDownloadRequests.get(appKey) == null ||
+                        !mActiveDownloadRequests.get(appKey).contains(request)) {
+                    return;
+                }
                 downloadSingleFile(appKey, request, tempFile, fileToDownload);
                 removeTempFileInUse(appKey, request.getFileServiceInfo().getServiceId(),
                         tempFile.getFilePathUri());
-                if (isLastFile) {
-                    mDoesAppHaveActiveDownload.put(appKey, false);
-                }
             }, FILE_SEPARATION_DELAY * i * mDownloadDelayFactor);
         }
     }
diff --git a/testapps/EmbmsServiceTestApp/src/com/android/phone/testapps/embmsmw/EmbmsTestStreamingService.java b/testapps/EmbmsServiceTestApp/src/com/android/phone/testapps/embmsmw/EmbmsTestStreamingService.java
index 313512f..1205e68 100644
--- a/testapps/EmbmsServiceTestApp/src/com/android/phone/testapps/embmsmw/EmbmsTestStreamingService.java
+++ b/testapps/EmbmsServiceTestApp/src/com/android/phone/testapps/embmsmw/EmbmsTestStreamingService.java
@@ -81,7 +81,7 @@
 
     private final IMbmsStreamingService.Stub mBinder = new MbmsStreamingServiceBase() {
         @Override
-        public int initialize(IMbmsStreamingManagerCallback listener, String appName, int subId) {
+        public int initialize(IMbmsStreamingManagerCallback listener, int subId) {
             int packageUid = Binder.getCallingUid();
             String[] packageNames = getPackageManager().getPackagesForUid(packageUid);
             if (packageNames == null) {
@@ -94,8 +94,7 @@
             }
 
             mHandler.postDelayed(() -> {
-                FrontendAppIdentifier appKey =
-                        new FrontendAppIdentifier(packageUid, appName, subId);
+                FrontendAppIdentifier appKey = new FrontendAppIdentifier(packageUid, subId);
                 if (!mAppCallbacks.containsKey(appKey)) {
                     mAppCallbacks.put(appKey, listener);
                 } else {
@@ -117,10 +116,9 @@
         }
 
         @Override
-        public int getStreamingServices(String appName, int subscriptionId,
-                List<String> serviceClasses) {
+        public int getStreamingServices(int subscriptionId, List<String> serviceClasses) {
             FrontendAppIdentifier appKey =
-                    new FrontendAppIdentifier(Binder.getCallingUid(), appName, subscriptionId);
+                    new FrontendAppIdentifier(Binder.getCallingUid(), subscriptionId);
             checkInitialized(appKey);
 
             List<StreamingServiceInfo> serviceInfos =
@@ -138,10 +136,10 @@
         }
 
         @Override
-        public int startStreaming(String appName, int subscriptionId, String serviceId,
+        public int startStreaming(int subscriptionId, String serviceId,
                 IStreamingServiceCallback callback) {
             FrontendAppIdentifier appKey =
-                    new FrontendAppIdentifier(Binder.getCallingUid(), appName, subscriptionId);
+                    new FrontendAppIdentifier(Binder.getCallingUid(), subscriptionId);
             checkInitialized(appKey);
             checkServiceExists(serviceId);
 
@@ -157,9 +155,9 @@
         }
 
         @Override
-        public Uri getPlaybackUri(String appName, int subscriptionId, String serviceId) {
+        public Uri getPlaybackUri(int subscriptionId, String serviceId) {
             FrontendAppIdentifier appKey =
-                    new FrontendAppIdentifier(Binder.getCallingUid(), appName, subscriptionId);
+                    new FrontendAppIdentifier(Binder.getCallingUid(), subscriptionId);
             checkInitialized(appKey);
             checkServiceExists(serviceId);
 
@@ -171,9 +169,9 @@
         }
 
         @Override
-        public void stopStreaming(String appName, int subscriptionId, String serviceId) {
+        public void stopStreaming(int subscriptionId, String serviceId) {
             FrontendAppIdentifier appKey =
-                    new FrontendAppIdentifier(Binder.getCallingUid(), appName, subscriptionId);
+                    new FrontendAppIdentifier(Binder.getCallingUid(), subscriptionId);
             checkInitialized(appKey);
             checkServiceExists(serviceId);
 
@@ -181,9 +179,9 @@
         }
 
         @Override
-        public void disposeStream(String appName, int subscriptionId, String serviceId) {
+        public void disposeStream(int subscriptionId, String serviceId) {
             FrontendAppIdentifier appKey =
-                    new FrontendAppIdentifier(Binder.getCallingUid(), appName, subscriptionId);
+                    new FrontendAppIdentifier(Binder.getCallingUid(), subscriptionId);
             checkInitialized(appKey);
             checkServiceExists(serviceId);
 
@@ -192,12 +190,12 @@
         }
 
         @Override
-        public void dispose(String appName, int subscriptionId) {
+        public void dispose(int subscriptionId) {
             FrontendAppIdentifier appKey =
-                    new FrontendAppIdentifier(Binder.getCallingUid(), appName, subscriptionId);
+                    new FrontendAppIdentifier(Binder.getCallingUid(), subscriptionId);
             checkInitialized(appKey);
 
-            Log.i(TAG, "Disposing app " + appName);
+            Log.i(TAG, "Disposing app with uid " + Binder.getCallingUid());
             StreamStateTracker.disposeAll(appKey);
             mAppCallbacks.remove(appKey);
         }
diff --git a/testapps/EmbmsServiceTestApp/src/com/android/phone/testapps/embmsmw/FrontendAppIdentifier.java b/testapps/EmbmsServiceTestApp/src/com/android/phone/testapps/embmsmw/FrontendAppIdentifier.java
index 4fb46aa..53237ac 100644
--- a/testapps/EmbmsServiceTestApp/src/com/android/phone/testapps/embmsmw/FrontendAppIdentifier.java
+++ b/testapps/EmbmsServiceTestApp/src/com/android/phone/testapps/embmsmw/FrontendAppIdentifier.java
@@ -18,12 +18,10 @@
 
 public class FrontendAppIdentifier {
     private final int uid;
-    private final String appName;
     private final int subscriptionId;
 
-    public FrontendAppIdentifier(int uid, String appName, int subscriptionId) {
+    public FrontendAppIdentifier(int uid, int subscriptionId) {
         this.uid = uid;
-        this.appName = appName;
         this.subscriptionId = subscriptionId;
     }
 
@@ -31,10 +29,6 @@
         return uid;
     }
 
-    public String getAppName() {
-        return appName;
-    }
-
     public int getSubscriptionId() {
         return subscriptionId;
     }
@@ -53,16 +47,12 @@
         if (uid != that.uid) {
             return false;
         }
-        if (subscriptionId != that.subscriptionId) {
-            return false;
-        }
-        return appName.equals(that.appName);
+        return this.subscriptionId == that.subscriptionId;
     }
 
     @Override
     public int hashCode() {
         int result = uid;
-        result = 31 * result + (appName != null ? appName.hashCode() : 0);
         result = 31 * result + subscriptionId;
         return result;
     }
diff --git a/testapps/EmbmsTestDownloadApp/res/layout/activity_main.xml b/testapps/EmbmsTestDownloadApp/res/layout/activity_main.xml
index bee6b5d..076bc37 100644
--- a/testapps/EmbmsTestDownloadApp/res/layout/activity_main.xml
+++ b/testapps/EmbmsTestDownloadApp/res/layout/activity_main.xml
@@ -15,88 +15,107 @@
   ~ limitations under the License
   -->
 
-<LinearLayout
+<ScrollView
     xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/scrolling_container"
     android:layout_width="match_parent"
-    android:layout_height="match_parent"
-    android:orientation="vertical" >
-
-    <TextView
-        android:id="@+id/progress_window"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"/>
-    <android.support.v7.widget.RecyclerView
-        android:id="@+id/downloaded_images"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:scrollbars="horizontal"
-        android:horizontalSpacing="10dp"
-        android:gravity="center"/>
-    <GridLayout
+    android:layout_height="wrap_content">
+    <LinearLayout
         xmlns:android="http://schemas.android.com/apk/res/android"
         android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:columnCount="2"
+        android:layout_height="match_parent"
         android:orientation="vertical" >
-        <Button
-            android:id="@+id/bind_button"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:layout_row="0"
-            android:layout_column="0"
-            android:text="@string/bind_button" />
-        <Button
-            android:id="@+id/set_temp_root_button"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:layout_row="0"
-            android:layout_column="1"
-            android:text="@string/set_temp_root_button" />
-        <Button
-            android:id="@+id/get_file_services_button"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:layout_row="1"
-            android:layout_column="0"
-            android:text="@string/get_file_services_button" />
-        <Button
-            android:id="@+id/request_dl_button"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:layout_row="1"
-            android:layout_column="1"
-            android:text="@string/request_dl_button" />
-        <Button
-            android:id="@+id/request_cleanup_button"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:layout_row="2"
-            android:layout_column="0"
-            android:text="@string/request_cleanup_button" />
-        <Button
-            android:id="@+id/request_spurious_temp_files_button"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:layout_row="2"
-            android:layout_column="1"
-            android:text="@string/request_spurious_temp_files_button" />
-        <Button
-            android:id="@+id/delay_download_button"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:layout_row="3"
-            android:layout_column="0"
-            android:text="@string/delay_download_button" />
-        <NumberPicker
-            android:id="@+id/delay_factor"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:layout_row="3"
-            android:layout_column="1"/>
-    </GridLayout>
 
-    <Spinner
-        android:id="@+id/available_file_services"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"/>
-</LinearLayout>
+        <TextView
+            android:id="@+id/progress_window"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"/>
+        <android.support.v7.widget.RecyclerView
+            android:id="@+id/downloaded_images"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:scrollbars="horizontal"
+            android:horizontalSpacing="10dp"
+            android:gravity="center"/>
+        <GridLayout
+            xmlns:android="http://schemas.android.com/apk/res/android"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:columnCount="2"
+            android:orientation="vertical" >
+            <Button
+                android:id="@+id/bind_button"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_row="0"
+                android:layout_column="0"
+                android:text="@string/bind_button" />
+            <Button
+                android:id="@+id/set_temp_root_button"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_row="0"
+                android:layout_column="1"
+                android:text="@string/set_temp_root_button" />
+            <Button
+                android:id="@+id/get_file_services_button"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_row="1"
+                android:layout_column="0"
+                android:text="@string/get_file_services_button" />
+            <Button
+                android:id="@+id/request_dl_button"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_row="1"
+                android:layout_column="1"
+                android:text="@string/request_dl_button" />
+            <Button
+                android:id="@+id/request_cleanup_button"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_row="2"
+                android:layout_column="0"
+                android:text="@string/request_cleanup_button" />
+            <Button
+                android:id="@+id/request_spurious_temp_files_button"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_row="2"
+                android:layout_column="1"
+                android:text="@string/request_spurious_temp_files_button" />
+            <Button
+                android:id="@+id/delay_download_button"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_row="3"
+                android:layout_column="0"
+                android:text="@string/delay_download_button" />
+            <NumberPicker
+                android:id="@+id/delay_factor"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_row="3"
+                android:layout_column="1"/>
+            <Button
+                android:id="@+id/cancel_download_button"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_row="4"
+                android:layout_column="0"
+                android:text="@string/cancel_download_button" />
+            <Spinner
+                android:id="@+id/active_downloads"
+                android:layout_row="4"
+                android:layout_column="1"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"/>
+        </GridLayout>
+
+        <Spinner
+            android:id="@+id/available_file_services"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"/>
+    </LinearLayout>
+</ScrollView>
\ No newline at end of file
diff --git a/testapps/EmbmsTestDownloadApp/res/values/donottranslate_strings.xml b/testapps/EmbmsTestDownloadApp/res/values/donottranslate_strings.xml
index 7459591..13d9fc2 100644
--- a/testapps/EmbmsTestDownloadApp/res/values/donottranslate_strings.xml
+++ b/testapps/EmbmsTestDownloadApp/res/values/donottranslate_strings.xml
@@ -23,4 +23,5 @@
     <string name="request_cleanup_button">Cleanup</string>
     <string name="request_spurious_temp_files_button">Request more temp files</string>
     <string name="delay_download_button">Delay download</string>
+    <string name="cancel_download_button">Cancel download</string>
 </resources>
\ No newline at end of file
diff --git a/testapps/EmbmsTestDownloadApp/src/com/android/phone/testapps/embmsdownload/EmbmsTestDownloadApp.java b/testapps/EmbmsTestDownloadApp/src/com/android/phone/testapps/embmsdownload/EmbmsTestDownloadApp.java
index fd7deee..890cc1a 100644
--- a/testapps/EmbmsTestDownloadApp/src/com/android/phone/testapps/embmsdownload/EmbmsTestDownloadApp.java
+++ b/testapps/EmbmsTestDownloadApp/src/com/android/phone/testapps/embmsdownload/EmbmsTestDownloadApp.java
@@ -27,7 +27,6 @@
 import android.support.v7.widget.RecyclerView;
 import android.telephony.MbmsDownloadManager;
 import android.telephony.SubscriptionManager;
-import android.telephony.mbms.DownloadCallback;
 import android.telephony.mbms.DownloadRequest;
 import android.telephony.mbms.FileServiceInfo;
 import android.telephony.mbms.MbmsDownloadManagerCallback;
@@ -55,7 +54,6 @@
     public static final String DOWNLOAD_DONE_ACTION =
             "com.android.phone.testapps.embmsdownload.DOWNLOAD_DONE";
 
-    private static final String APP_NAME = "SampleAppName";
     private static final String CUSTOM_EMBMS_TEMP_FILE_LOCATION = "customEmbmsTempFiles";
 
     private static final String FILE_AUTHORITY = "com.android.phone.testapps";
@@ -103,6 +101,7 @@
             extends ArrayAdapter<FileServiceInfo> {
         public FileServiceInfoAdapter(Context context) {
             super(context, android.R.layout.simple_spinner_item);
+            setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
         }
 
         @Override
@@ -132,6 +131,28 @@
         }
     }
 
+    private final class DownloadRequestAdapter
+            extends ArrayAdapter<DownloadRequest> {
+        public DownloadRequestAdapter(Context context) {
+            super(context, android.R.layout.simple_spinner_item);
+            setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
+        }
+
+        @Override
+        public View getView(int position, View convertView, ViewGroup parent) {
+            DownloadRequest request = getItem(position);
+            TextView result = new TextView(EmbmsTestDownloadApp.this);
+            result.setText(request.getSourceUri().toSafeString());
+            return result;
+        }
+
+        @Override
+        public View getDropDownView(int position, View convertView, ViewGroup parent) {
+            return getView(position, convertView, parent);
+        }
+    }
+
+
     private MbmsDownloadManagerCallback mCallback = new MbmsDownloadManagerCallback() {
         @Override
         public void error(int errorCode, String message) {
@@ -159,6 +180,7 @@
     private Handler mHandler;
     private HandlerThread mHandlerThread;
     private FileServiceInfoAdapter mFileServiceInfoAdapter;
+    private DownloadRequestAdapter mDownloadRequestAdapter;
     private ImageAdapter mImageAdapter;
 
     @Override
@@ -171,6 +193,7 @@
         mHandlerThread.start();
         mHandler = new Handler(mHandlerThread.getLooper());
         mFileServiceInfoAdapter = new FileServiceInfoAdapter(this);
+        mDownloadRequestAdapter = new DownloadRequestAdapter(this);
 
         RecyclerView downloadedImages = (RecyclerView) findViewById(R.id.downloaded_images);
         downloadedImages.setLayoutManager(
@@ -181,7 +204,7 @@
         Button bindButton = (Button) findViewById(R.id.bind_button);
         bindButton.setOnClickListener((view) -> {
             try {
-                mDownloadManager = MbmsDownloadManager.create(this, mCallback, APP_NAME);
+                mDownloadManager = MbmsDownloadManager.create(this, mCallback);
             } catch (MbmsException e) {
                 Toast.makeText(EmbmsTestDownloadApp.this,
                         "caught MbmsException: " + e.getErrorCode(), Toast.LENGTH_SHORT).show();
@@ -214,8 +237,6 @@
         }));
 
         final Spinner serviceSelector = (Spinner) findViewById(R.id.available_file_services);
-        mFileServiceInfoAdapter.setDropDownViewResource(
-                android.R.layout.simple_spinner_dropdown_item);
         serviceSelector.setAdapter(mFileServiceInfoAdapter);
 
         Button requestDlButton = (Button) findViewById(R.id.request_dl_button);
@@ -254,6 +275,27 @@
         delayDownloadButton.setOnClickListener((view) ->
                 SideChannel.delayDownloads(EmbmsTestDownloadApp.this,
                         downloadDelayPicker.getValue()));
+
+        final Spinner downloadRequestSpinner = (Spinner) findViewById(R.id.active_downloads);
+        downloadRequestSpinner.setAdapter(mDownloadRequestAdapter);
+
+        Button cancelDownloadButton = (Button) findViewById(R.id.cancel_download_button);
+        cancelDownloadButton.setOnClickListener((view) -> {
+            if (mDownloadManager == null) {
+                Toast.makeText(EmbmsTestDownloadApp.this,
+                        "No download service bound", Toast.LENGTH_SHORT).show();
+                return;
+            }
+            try {
+                DownloadRequest request =
+                        (DownloadRequest) downloadRequestSpinner.getSelectedItem();
+                mDownloadManager.cancelDownload(request);
+                mDownloadRequestAdapter.remove(request);
+            } catch (MbmsException e) {
+                runOnUiThread(() -> Toast.makeText(EmbmsTestDownloadApp.this,
+                        "caught MbmsException: " + e.getErrorCode(), Toast.LENGTH_SHORT).show());
+            }
+        });
     }
 
     @Override
@@ -322,6 +364,7 @@
 
         try {
             mDownloadManager.download(request, null);
+            mDownloadRequestAdapter.add(request);
         } catch (MbmsException e) {
             Toast.makeText(EmbmsTestDownloadApp.this,
                     "caught MbmsException: " + e.getErrorCode(), Toast.LENGTH_SHORT).show();
diff --git a/testapps/EmbmsTestStreamingApp/src/com/android/phone/testapps/embmsfrontend/EmbmsTestStreamingApp.java b/testapps/EmbmsTestStreamingApp/src/com/android/phone/testapps/embmsfrontend/EmbmsTestStreamingApp.java
index c3be6ef..b19e004 100644
--- a/testapps/EmbmsTestStreamingApp/src/com/android/phone/testapps/embmsfrontend/EmbmsTestStreamingApp.java
+++ b/testapps/EmbmsTestStreamingApp/src/com/android/phone/testapps/embmsfrontend/EmbmsTestStreamingApp.java
@@ -43,8 +43,6 @@
 import java.util.Map;
 
 public class EmbmsTestStreamingApp extends Activity {
-    private static final String APP_NAME = "StreamingApp1";
-
     private MbmsStreamingManagerCallback mStreamingListener = new MbmsStreamingManagerCallback() {
         @Override
         public void streamingServicesUpdated(List<StreamingServiceInfo> services) {
@@ -160,7 +158,7 @@
         bindButton.setOnClickListener((view) -> {
             try {
                 mStreamingManager = MbmsStreamingManager.create(
-                        EmbmsTestStreamingApp.this, mStreamingListener, APP_NAME);
+                        EmbmsTestStreamingApp.this, mStreamingListener);
             } catch (MbmsException e) {
                 Toast.makeText(EmbmsTestStreamingApp.this,
                         "Init error: " + e.getErrorCode(), Toast.LENGTH_SHORT).show();