Merge "Add OWNERS in packages/services/Telephony"
diff --git a/src/com/android/phone/EmergencyDialer.java b/src/com/android/phone/EmergencyDialer.java
index 53f6f7e..e7b05ce 100644
--- a/src/com/android/phone/EmergencyDialer.java
+++ b/src/com/android/phone/EmergencyDialer.java
@@ -513,11 +513,12 @@
*/
private void placeCall() {
mLastNumber = mDigits.getText().toString();
- // Convert into emergency number if necessary
- // This is required in some regions (e.g. Taiwan).
- if (PhoneNumberUtils.isConvertToEmergencyNumberEnabled()) {
- mLastNumber = PhoneNumberUtils.convertToEmergencyNumber(mLastNumber);
- }
+
+ // Convert into emergency number according to emergency conversion map.
+ // If conversion map is not defined (this is default), this method does
+ // nothing and just returns input number.
+ mLastNumber = PhoneNumberUtils.convertToEmergencyNumber(this, mLastNumber);
+
if (PhoneNumberUtils.isLocalEmergencyNumber(this, mLastNumber)) {
if (DBG) Log.d(LOG_TAG, "placing call to " + mLastNumber);
diff --git a/src/com/android/phone/PhoneInterfaceManager.java b/src/com/android/phone/PhoneInterfaceManager.java
index a7d0205..f51422c 100644
--- a/src/com/android/phone/PhoneInterfaceManager.java
+++ b/src/com/android/phone/PhoneInterfaceManager.java
@@ -19,7 +19,6 @@
import static com.android.internal.telephony.PhoneConstants.SUBSCRIPTION_KEY;
import android.Manifest.permission;
-import android.annotation.Nullable;
import android.app.ActivityManager;
import android.app.AppOpsManager;
import android.app.PendingIntent;
@@ -29,6 +28,7 @@
import android.content.SharedPreferences;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
+import android.net.NetworkStats;
import android.net.Uri;
import android.os.AsyncResult;
import android.os.Binder;
@@ -59,8 +59,8 @@
import android.telephony.NetworkScanRequest;
import android.telephony.RadioAccessFamily;
import android.telephony.ServiceState;
-import android.telephony.SmsManager;
import android.telephony.SignalStrength;
+import android.telephony.SmsManager;
import android.telephony.SubscriptionInfo;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyHistogram;
@@ -3649,27 +3649,25 @@
}
/**
- * Get aggregated video call data usage from all subscriptions since boot.
- * @return total data usage in bytes
+ * Get aggregated video call data usage since boot.
+ *
+ * @param perUidStats True if requesting data usage per uid, otherwise overall usage.
+ * @return Snapshot of video call data usage
* {@hide}
*/
@Override
- public long getVtDataUsage() {
+ public NetworkStats getVtDataUsage(int subId, boolean perUidStats) {
mApp.enforceCallingOrSelfPermission(android.Manifest.permission.READ_NETWORK_USAGE_HISTORY,
null);
- // NetworkStatsService keeps tracking the active network interface and identity. It will
- // record the delta with the corresponding network identity. What we need to do here is
- // returning total video call data usage from all subscriptions since boot.
-
- // TODO: Add sub id support in the future. We'll need it when we support DSDA and
- // simultaneous VT calls.
- final Phone[] phones = PhoneFactory.getPhones();
- long total = 0;
- for (Phone phone : phones) {
- total += phone.getVtDataUsage();
+ // NetworkStatsService keeps tracking the active network interface and identity. It
+ // records the delta with the corresponding network identity. We just return the total video
+ // call data usage snapshot since boot.
+ Phone phone = getPhone(subId);
+ if (phone != null) {
+ return phone.getVtDataUsage(perUidStats);
}
- return total;
+ return null;
}
/**
diff --git a/src/com/android/services/telephony/DisconnectCauseUtil.java b/src/com/android/services/telephony/DisconnectCauseUtil.java
index fcc37f4..727907f 100644
--- a/src/com/android/services/telephony/DisconnectCauseUtil.java
+++ b/src/com/android/services/telephony/DisconnectCauseUtil.java
@@ -20,9 +20,9 @@
import android.media.ToneGenerator;
import android.telecom.DisconnectCause;
+import com.android.phone.ImsUtil;
import com.android.phone.PhoneGlobals;
import com.android.phone.common.R;
-import com.android.phone.ImsUtil;
public class DisconnectCauseUtil {
@@ -130,6 +130,7 @@
case android.telephony.DisconnectCause.DIALED_CALL_FORWARDING_WHILE_ROAMING:
case android.telephony.DisconnectCause.IMEI_NOT_ACCEPTED:
case android.telephony.DisconnectCause.WIFI_LOST:
+ case android.telephony.DisconnectCause.IMS_ACCESS_BLOCKED:
return DisconnectCause.ERROR;
case android.telephony.DisconnectCause.DIALED_MMI:
diff --git a/src/com/android/services/telephony/TelephonyConnection.java b/src/com/android/services/telephony/TelephonyConnection.java
index 9ac40fd..a403d1f 100644
--- a/src/com/android/services/telephony/TelephonyConnection.java
+++ b/src/com/android/services/telephony/TelephonyConnection.java
@@ -152,7 +152,8 @@
break;
case MSG_SUPP_SERVICE_NOTIFY:
Log.v(TelephonyConnection.this, "MSG_SUPP_SERVICE_NOTIFY on phoneId : "
- +getPhone().getPhoneId());
+ + getPhone() != null ? Integer.toString(getPhone().getPhoneId())
+ : "null");
SuppServiceNotification mSsNotification = null;
if (msg.obj != null && ((AsyncResult) msg.obj).result != null) {
mSsNotification =
@@ -1741,7 +1742,7 @@
boolean isVoWifiEnabled = false;
if (isIms) {
ImsPhone imsPhone = (ImsPhone) phone;
- isVoWifiEnabled = imsPhone.isWifiCallingEnabled();
+ isVoWifiEnabled = ImsUtil.isWfcEnabled(phone.getContext());
}
PhoneAccountHandle phoneAccountHandle = isIms ? PhoneUtils
.makePstnPhoneAccountHandle(phone.getDefaultPhone())
diff --git a/src/com/android/services/telephony/TelephonyConnectionService.java b/src/com/android/services/telephony/TelephonyConnectionService.java
index 0148df6..148759e 100644
--- a/src/com/android/services/telephony/TelephonyConnectionService.java
+++ b/src/com/android/services/telephony/TelephonyConnectionService.java
@@ -196,8 +196,7 @@
// Convert into emergency number if necessary
// This is required in some regions (e.g. Taiwan).
- if (!PhoneNumberUtils.isLocalEmergencyNumber(this, number) &&
- PhoneNumberUtils.isConvertToEmergencyNumberEnabled()) {
+ if (!PhoneNumberUtils.isLocalEmergencyNumber(this, number)) {
final Phone phone = getPhoneForAccount(request.getAccountHandle(), false);
// We only do the conversion if the phone is not in service. The un-converted
// emergency numbers will go to the correct destination when the phone is in-service,
@@ -205,7 +204,7 @@
// service.
if (phone == null || phone.getServiceState().getState()
!= ServiceState.STATE_IN_SERVICE) {
- String convertedNumber = PhoneNumberUtils.convertToEmergencyNumber(number);
+ String convertedNumber = PhoneNumberUtils.convertToEmergencyNumber(this, number);
if (!TextUtils.equals(convertedNumber, number)) {
Log.i(this, "onCreateOutgoingConnection, converted to emergency number");
number = convertedNumber;
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 */);
+ }
+}
diff --git a/testapps/EmbmsTestDownloadApp/Android.mk b/testapps/EmbmsTestDownloadApp/Android.mk
new file mode 100644
index 0000000..66ca25b
--- /dev/null
+++ b/testapps/EmbmsTestDownloadApp/Android.mk
@@ -0,0 +1,17 @@
+LOCAL_PATH:= $(call my-dir)
+
+# Build the Sample Embms Download frontend
+include $(CLEAR_VARS)
+
+src_dirs := src
+res_dirs := res
+
+LOCAL_SRC_FILES := $(call all-java-files-under, $(src_dirs))
+LOCAL_RESOURCE_DIR := $(addprefix $(LOCAL_PATH)/, $(res_dirs))
+
+LOCAL_PACKAGE_NAME := EmbmsTestDownloadApp
+
+LOCAL_CERTIFICATE := platform
+LOCAL_MODULE_TAGS := tests
+
+include $(BUILD_PACKAGE)
diff --git a/testapps/EmbmsTestDownloadApp/AndroidManifest.xml b/testapps/EmbmsTestDownloadApp/AndroidManifest.xml
new file mode 100644
index 0000000..b81b928
--- /dev/null
+++ b/testapps/EmbmsTestDownloadApp/AndroidManifest.xml
@@ -0,0 +1,71 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.phone.testapps.embmsdownload">
+ <application android:label="EmbmsTestDownloadApp">
+ <activity
+ android:name=".EmbmsTestDownloadApp"
+ android:label="EmbmsDownloadFrontend">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.DEFAULT" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+
+ <!-- This is the receiver defined by the MBMS api. -->
+ <!-- TODO: protect this with a permission -->
+ <receiver
+ android:name="android.telephony.mbms.MbmsDownloadReceiver"
+ android:enabled="true"
+ android:exported="true">
+ </receiver>
+
+ <!-- This is the receiver defined by app to receive the download-done intent that was
+ passed into DownloadRequest. -->
+ <receiver
+ android:name="com.android.phone.testapps.embmsdownload.DownloadCompletionReceiver"
+ android:enabled="true">
+ </receiver>
+
+ <!-- This is the provider that apps must declare in their manifest. It allows the
+ middleware to obtain file descriptors to temp files in the app's file space -->
+ <!-- grantUriPermissions must be set to true -->
+ <provider
+ android:name="android.telephony.mbms.MbmsTempFileProvider"
+ android:authorities="com.android.phone.testapps.embmsdownload"
+ android:exported="false"
+ android:grantUriPermissions="true">
+ <!-- This is a mandatory piece of metadata that contains the directory where temp
+ files should be put. It should be a relative path from Context.getFilesDir() or from
+ Context.getExternalStorageDir(null), depending on the value of the
+ use-external-storage metadata. -->
+ <meta-data android:name="temp-file-path" android:value="/mbms-temp/"/>
+
+ <!-- This tells the provider whether to use the sdcard partition for the temp files or
+ not. -->
+ <meta-data android:name="use-external-storage" android:value="false"/>
+ </provider>
+
+ <!-- This is a mandatory piece of metadata that contains the authority string for the
+ provider declared above -->
+ <meta-data
+ android:name="mbms-file-provider-authority"
+ android:value="com.android.phone.testapps.embmsdownload"/>
+ </application>
+</manifest>
+
diff --git a/testapps/EmbmsTestDownloadApp/res/layout/activity_main.xml b/testapps/EmbmsTestDownloadApp/res/layout/activity_main.xml
new file mode 100644
index 0000000..092a08a
--- /dev/null
+++ b/testapps/EmbmsTestDownloadApp/res/layout/activity_main.xml
@@ -0,0 +1,53 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ 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
+ -->
+
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ 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"/>
+ <ImageView
+ android:id="@+id/sample_picture"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center"/>
+
+ <Button
+ android:id="@+id/bind_button"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/bind_button" />
+
+ <Button
+ android:id="@+id/request_dl_button"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/request_dl_button" />
+
+ <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" >
+ </GridLayout>
+</LinearLayout>
diff --git a/testapps/EmbmsTestDownloadApp/res/values/donottranslate_strings.xml b/testapps/EmbmsTestDownloadApp/res/values/donottranslate_strings.xml
new file mode 100644
index 0000000..4683fa2
--- /dev/null
+++ b/testapps/EmbmsTestDownloadApp/res/values/donottranslate_strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ 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
+ -->
+
+<resources>
+ <string name="bind_button">Bind</string>
+ <string name="request_dl_button">Request DL</string>
+</resources>
\ No newline at end of file
diff --git a/testapps/EmbmsTestDownloadApp/src/com/android/phone/testapps/embmsdownload/DownloadCompletionReceiver.java b/testapps/EmbmsTestDownloadApp/src/com/android/phone/testapps/embmsdownload/DownloadCompletionReceiver.java
new file mode 100644
index 0000000..b4cf1d4
--- /dev/null
+++ b/testapps/EmbmsTestDownloadApp/src/com/android/phone/testapps/embmsdownload/DownloadCompletionReceiver.java
@@ -0,0 +1,30 @@
+/*
+ * 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.embmsdownload;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+
+public class DownloadCompletionReceiver extends BroadcastReceiver {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (EmbmsTestDownloadApp.DOWNLOAD_DONE_ACTION.equals(intent.getAction())) {
+ EmbmsTestDownloadApp.getInstance().onDownloadDone();
+ }
+ }
+}
diff --git a/testapps/EmbmsTestDownloadApp/src/com/android/phone/testapps/embmsdownload/EmbmsTestDownloadApp.java b/testapps/EmbmsTestDownloadApp/src/com/android/phone/testapps/embmsdownload/EmbmsTestDownloadApp.java
new file mode 100644
index 0000000..51e3a66
--- /dev/null
+++ b/testapps/EmbmsTestDownloadApp/src/com/android/phone/testapps/embmsdownload/EmbmsTestDownloadApp.java
@@ -0,0 +1,122 @@
+/*
+ * 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.embmsdownload;
+
+import android.app.Activity;
+import android.content.ComponentName;
+import android.content.Intent;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.telephony.MbmsDownloadManager;
+import android.telephony.mbms.DownloadCallback;
+import android.telephony.mbms.DownloadRequest;
+import android.telephony.mbms.MbmsDownloadManagerCallback;
+import android.telephony.mbms.MbmsException;
+import android.widget.Button;
+import android.widget.ImageView;
+import android.widget.Toast;
+
+import java.io.File;
+import java.io.IOException;
+
+public class EmbmsTestDownloadApp extends Activity {
+ public static final String DOWNLOAD_DONE_ACTION =
+ "com.android.phone.testapps.embmsdownload.DOWNLOAD_DONE";
+
+ private static final String TRIGGER_DOWNLOAD_ACTION =
+ "com.android.phone.testapps.embmsmw.TRIGGER_DOWNLOAD";
+ private static final String EXTRA_DOWNLOAD_REQUEST =
+ "com.android.phone.testapps.embmsmw.EXTRA_DOWNLOAD_REQUEST";
+ private static final String APP_NAME = "SampleAppName";
+
+ private static EmbmsTestDownloadApp sInstance;
+
+ private MbmsDownloadManagerCallback mCallback = new MbmsDownloadManagerCallback() {};
+
+ private MbmsDownloadManager mDownloadManager;
+ private Handler mHandler;
+ private HandlerThread mHandlerThread;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_main);
+
+ sInstance = this;
+ mHandlerThread = new HandlerThread("EmbmsDownloadWorker");
+ mHandlerThread.start();
+ mHandler = new Handler(mHandlerThread.getLooper());
+
+ File destination = null;
+ try {
+ destination = new File(getFilesDir(), "image.png").getCanonicalFile();
+ } catch (IOException e) {
+ // ignore, this is temp code
+ }
+
+ Intent completionIntent = new Intent(DOWNLOAD_DONE_ACTION);
+ completionIntent.setClass(this, DownloadCompletionReceiver.class);
+
+ DownloadRequest request = new DownloadRequest.Builder()
+ .setId(0)
+ .setServiceInfo(null) // TODO: this isn't supposed to be null, but not yet used
+ .setSource(null) // ditto
+ .setDest(Uri.fromFile(destination))
+ .setAppIntent(completionIntent)
+ .build();
+
+ Button bindButton = (Button) findViewById(R.id.bind_button);
+ bindButton.setOnClickListener((view) -> mHandler.post(() -> {
+ try {
+ mDownloadManager = MbmsDownloadManager.createManager(this, mCallback, APP_NAME);
+ } catch (MbmsException e) {
+ Toast.makeText(EmbmsTestDownloadApp.this,
+ "caught MbmsException: " + e.getErrorCode(), Toast.LENGTH_SHORT).show();
+ }
+ }));
+
+ Button requestDlButton = (Button) findViewById(R.id.request_dl_button);
+ requestDlButton.setOnClickListener((view) -> {
+ mDownloadManager.download(request, new DownloadCallback());
+ });
+ }
+
+ @Override
+ protected void onDestroy() {
+ super.onDestroy();
+ mHandlerThread.quit();
+ sInstance = null;
+ }
+
+ public static EmbmsTestDownloadApp getInstance() {
+ return sInstance;
+ }
+
+ // TODO: assumes that process does not get killed. Replace with more robust alternative
+ public void onDownloadDone() {
+ ImageView picture = (ImageView) findViewById(R.id.sample_picture);
+ File imageFile = new File(getFilesDir(), "image.png");
+ if (!imageFile.exists()) {
+ Toast.makeText(this, "Download done but destination doesn't exist", Toast.LENGTH_SHORT)
+ .show();
+ return;
+ }
+ runOnUiThread(() -> picture.setImageURI(Uri.fromFile(imageFile)));
+ }
+}