Embms Download setup

Adds the EmbmsTestDownloadApp as a frontend for the download flow
Add a EmbmsDownloadService to EmbmsServiceTestApp

Test: testapps
Change-Id: Ic5e7323ca217dbb4323eac00861788fa19c5f2ef
diff --git a/testapps/EmbmsServiceTestApp/AndroidManifest.xml b/testapps/EmbmsServiceTestApp/AndroidManifest.xml
index 3adab28..526d3af 100644
--- a/testapps/EmbmsServiceTestApp/AndroidManifest.xml
+++ b/testapps/EmbmsServiceTestApp/AndroidManifest.xml
@@ -23,7 +23,14 @@
             android:launchMode="singleInstance"
             androidprv:systemUserOnly="true">
       <intent-filter>
-          <action android:name="android.telephony.action.EmbmsStreaming" />
+        <action android:name="android.telephony.action.EmbmsStreaming" />
+      </intent-filter>
+    </service>
+    <service android:name="com.android.phone.testapps.embmsmw.EmbmsSampleDownloadService"
+             android:launchMode="singleInstance"
+             androidprv:systemUserOnly="true">
+      <intent-filter>
+        <action android:name="android.telephony.action.EmbmsDownload" />
       </intent-filter>
     </service>
   </application>
diff --git a/testapps/EmbmsServiceTestApp/res/raw/s1.png b/testapps/EmbmsServiceTestApp/res/raw/s1.png
new file mode 100644
index 0000000..353e1b5
--- /dev/null
+++ b/testapps/EmbmsServiceTestApp/res/raw/s1.png
Binary files differ
diff --git a/testapps/EmbmsServiceTestApp/src/com/android/phone/testapps/embmsmw/EmbmsSampleDownloadService.java b/testapps/EmbmsServiceTestApp/src/com/android/phone/testapps/embmsmw/EmbmsSampleDownloadService.java
new file mode 100644
index 0000000..360dd15
--- /dev/null
+++ b/testapps/EmbmsServiceTestApp/src/com/android/phone/testapps/embmsmw/EmbmsSampleDownloadService.java
@@ -0,0 +1,172 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.phone.testapps.embmsmw;
+
+import android.app.Activity;
+import android.app.Service;
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.net.Uri;
+import android.os.Binder;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.IBinder;
+import android.os.ParcelFileDescriptor;
+import android.telephony.MbmsDownloadManager;
+import android.telephony.mbms.DownloadRequest;
+import android.telephony.mbms.IDownloadCallback;
+import android.telephony.mbms.MbmsDownloadReceiver;
+import android.telephony.mbms.MbmsException;
+import android.telephony.mbms.UriPathPair;
+import android.telephony.mbms.vendor.IMbmsDownloadService;
+import android.telephony.mbms.vendor.MbmsDownloadServiceBase;
+import android.util.Log;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+public class EmbmsSampleDownloadService extends Service {
+    private static final String LOG_TAG = "EmbmsSampleDownload";
+    private static final long DOWNLOAD_DELAY_MS = 1000;
+
+    private final IMbmsDownloadService mBinder = new MbmsDownloadServiceBase() {
+        @Override
+        public int download(DownloadRequest downloadRequest, IDownloadCallback listener) {
+            // TODO: move this package name finding logic to initialize()
+            String[] packageNames = getPackageManager().getPackagesForUid(Binder.getCallingUid());
+            if (packageNames == null) {
+                throw new SecurityException("No matching packages found for your UID");
+            }
+
+            if (packageNames.length != 1) {
+                throw new IllegalStateException("More than one package found for your UID");
+            }
+
+            String packageName = packageNames[0];
+
+            mHandler.post(() -> sendFdRequest(downloadRequest, packageName, 1));
+            return MbmsException.SUCCESS;
+        }
+    };
+
+    private HandlerThread mHandlerThread;
+    private Handler mHandler;
+
+    @Override
+    public IBinder onBind(Intent intent) {
+        mHandlerThread = new HandlerThread("EmbmsTestDownloadServiceWorker");
+        mHandlerThread.start();
+        mHandler = new Handler(mHandlerThread.getLooper());
+        return mBinder.asBinder();
+    }
+
+    private void sendFdRequest(DownloadRequest request, String packageName, int numFds) {
+        // Compose the FILE_DESCRIPTOR_REQUEST_INTENT
+        Intent requestIntent = new Intent(MbmsDownloadManager.ACTION_FILE_DESCRIPTOR_REQUEST);
+        requestIntent.putExtra(MbmsDownloadManager.EXTRA_REQUEST, request);
+        requestIntent.putExtra(MbmsDownloadManager.EXTRA_FD_COUNT, numFds);
+        ComponentName mbmsReceiverComponent = new ComponentName(packageName,
+                MbmsDownloadReceiver.class.getCanonicalName());
+        requestIntent.setComponent(mbmsReceiverComponent);
+
+        // Send as an ordered broadcast, using a BroadcastReceiver to capture the result
+        // containing UriPathPairs.
+        sendOrderedBroadcast(requestIntent,
+                null, // receiverPermission
+                new BroadcastReceiver() {
+                    @Override
+                    public void onReceive(Context context, Intent intent) {
+                        Bundle resultExtras = getResultExtras(false);
+                        // This delay is to emulate the time it'd usually take to fetch the file
+                        // off the network.
+                        mHandler.postDelayed(
+                                () -> performDownload(request, packageName, resultExtras),
+                                DOWNLOAD_DELAY_MS);
+                    }
+                },
+                null, // scheduler
+                Activity.RESULT_OK,
+                null, // initialData
+                null /* initialExtras */);
+    }
+
+    private void performDownload(DownloadRequest request, String packageName, Bundle extras) {
+        int result = MbmsDownloadManager.RESULT_SUCCESSFUL;
+        List<UriPathPair> tempFiles = extras.getParcelableArrayList(
+                MbmsDownloadManager.EXTRA_FREE_URI_LIST);
+        Uri tempFilePathUri = tempFiles.get(0).getFilePathUri();
+        Uri freeTempFileUri = tempFiles.get(0).getContentUri();
+
+        try {
+            // Get the ParcelFileDescriptor for the single temp file we requested
+            ParcelFileDescriptor tempFile = getContentResolver().openFileDescriptor(
+                    freeTempFileUri, "rw");
+            OutputStream destinationStream =
+                    new ParcelFileDescriptor.AutoCloseOutputStream(tempFile);
+
+            // This is how you get the native fd
+            Log.i(LOG_TAG, "Native fd: " + tempFile.getFd());
+
+            // Open the picture we have in our res/raw directory
+            InputStream image = getResources().openRawResource(R.raw.s1);
+
+            // Copy it into the temp file in the app's file space (crudely)
+            byte[] imageBuffer = new byte[image.available()];
+            image.read(imageBuffer);
+            destinationStream.write(imageBuffer);
+            destinationStream.flush();
+        } catch (IOException e) {
+            result = MbmsDownloadManager.RESULT_CANCELLED;
+        }
+
+        Intent downloadResultIntent =
+                new Intent(MbmsDownloadManager.ACTION_DOWNLOAD_RESULT_INTERNAL);
+        downloadResultIntent.putExtra(MbmsDownloadManager.EXTRA_REQUEST, request);
+        downloadResultIntent.putExtra(MbmsDownloadManager.EXTRA_FINAL_URI, tempFilePathUri);
+        ArrayList<Uri> tempFileList = new ArrayList<>(1);
+        tempFileList.add(tempFilePathUri);
+        downloadResultIntent.getExtras().putParcelableArrayList(
+                MbmsDownloadManager.EXTRA_TEMP_LIST, tempFileList);
+        downloadResultIntent.putExtra(MbmsDownloadManager.EXTRA_RESULT, result);
+
+        ComponentName mbmsReceiverComponent = new ComponentName(packageName,
+                MbmsDownloadReceiver.class.getCanonicalName());
+        downloadResultIntent.setComponent(mbmsReceiverComponent);
+
+        sendOrderedBroadcast(downloadResultIntent,
+                null, // receiverPermission
+                new BroadcastReceiver() {
+                    @Override
+                    public void onReceive(Context context, Intent intent) {
+                        int resultCode = getResultCode();
+                        Log.i(LOG_TAG, "Download result ack: " + resultCode);
+                    }
+                },
+                null, // scheduler
+                Activity.RESULT_OK,
+                null, // initialData
+                null /* initialExtras */);
+    }
+}