Merge "Propagate elapsed time of conference to Telecom."
diff --git a/res/values/strings.xml b/res/values/strings.xml
index a294e22..7a7156f 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -1378,6 +1378,14 @@
         Wi-Fi connection lost.  Call ended.
     </string>
 
+    <!-- Call failure reason displayed when the user's outgoing call cannot be placed due to a low
+         battery. -->
+    <string name="dialFailed_low_battery">Your video call cannot be placed due to low battery.</string>
+
+    <!-- Call failure reason displayed when the user's call is ended due to a low battery. This
+         message is shown when an in-progress call is ended due to the battery being low. -->
+    <string name="callFailed_low_battery">Video call ended due to low battery.</string>
+
     <!-- The title for the change voicemail PIN activity -->
     <string name="change_pin_title">Change Voicemail PIN</string>
     <!-- The label for the continue button in change voicemail PIN activity -->
diff --git a/src/com/android/services/telephony/DisconnectCauseUtil.java b/src/com/android/services/telephony/DisconnectCauseUtil.java
index 6731dbd..26690b9 100644
--- a/src/com/android/services/telephony/DisconnectCauseUtil.java
+++ b/src/com/android/services/telephony/DisconnectCauseUtil.java
@@ -114,6 +114,8 @@
             case android.telephony.DisconnectCause.OUT_OF_NETWORK:
             case android.telephony.DisconnectCause.OUT_OF_SERVICE:
             case android.telephony.DisconnectCause.POWER_OFF:
+            case android.telephony.DisconnectCause.LOW_BATTERY:
+            case android.telephony.DisconnectCause.DIAL_LOW_BATTERY:
             case android.telephony.DisconnectCause.SERVER_ERROR:
             case android.telephony.DisconnectCause.SERVER_UNREACHABLE:
             case android.telephony.DisconnectCause.TIMED_OUT:
@@ -213,6 +215,14 @@
                 resourceId = R.string.callFailed_powerOff;
                 break;
 
+            case android.telephony.DisconnectCause.LOW_BATTERY:
+                resourceId = R.string.callFailed_low_battery;
+                break;
+
+            case android.telephony.DisconnectCause.DIAL_LOW_BATTERY:
+                resourceId = R.string.dialFailed_low_battery;
+                break;
+
             case android.telephony.DisconnectCause.ICC_ERROR:
                 resourceId = R.string.callFailed_simError;
                 break;
@@ -320,6 +330,14 @@
                 }
                 break;
 
+            case android.telephony.DisconnectCause.LOW_BATTERY:
+                resourceId = R.string.callFailed_low_battery;
+                break;
+
+            case android.telephony.DisconnectCause.DIAL_LOW_BATTERY:
+                resourceId = R.string.dialFailed_low_battery;
+                break;
+
             case android.telephony.DisconnectCause.CDMA_NOT_EMERGENCY:
                 // Only emergency calls are allowed when in emergency callback mode.
                 resourceId = R.string.incall_error_ecm_emergency_only;
diff --git a/src/com/android/services/telephony/TelephonyConnection.java b/src/com/android/services/telephony/TelephonyConnection.java
index 6aa4b97..064d1f1 100644
--- a/src/com/android/services/telephony/TelephonyConnection.java
+++ b/src/com/android/services/telephony/TelephonyConnection.java
@@ -151,9 +151,10 @@
                     notifyConferenceMergeFailed();
                     break;
                 case MSG_SUPP_SERVICE_NOTIFY:
+                    Phone phone = getPhone();
                     Log.v(TelephonyConnection.this, "MSG_SUPP_SERVICE_NOTIFY on phoneId : "
-                            + getPhone() != null ? Integer.toString(getPhone().getPhoneId())
-                            : "null");
+                            + (phone != null ? Integer.toString(phone.getPhoneId())
+                            : "null"));
                     SuppServiceNotification mSsNotification = null;
                     if (msg.obj != null && ((AsyncResult) msg.obj).result != null) {
                         mSsNotification =
@@ -1751,6 +1752,15 @@
     private void refreshConferenceSupported() {
         boolean isVideoCall = VideoProfile.isVideo(getVideoState());
         Phone phone = getPhone();
+        if (phone == null) {
+            Log.w(this, "refreshConferenceSupported = false; phone is null");
+            if (isConferenceSupported()) {
+                setConferenceSupported(false);
+                notifyConferenceSupportedChanged(false);
+            }
+            return;
+        }
+
         boolean isIms = phone.getPhoneType() == PhoneConstants.PHONE_TYPE_IMS;
         boolean isVoWifiEnabled = false;
         if (isIms) {
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 afac316..f1060e3 100644
--- a/testapps/EmbmsServiceTestApp/src/com/android/phone/testapps/embmsmw/EmbmsSampleDownloadService.java
+++ b/testapps/EmbmsServiceTestApp/src/com/android/phone/testapps/embmsmw/EmbmsSampleDownloadService.java
@@ -31,15 +31,18 @@
 import android.os.ParcelFileDescriptor;
 import android.os.RemoteException;
 import android.telephony.MbmsDownloadManager;
+import android.telephony.mbms.DownloadProgressListener;
 import android.telephony.mbms.DownloadRequest;
 import android.telephony.mbms.FileInfo;
 import android.telephony.mbms.FileServiceInfo;
 import android.telephony.mbms.IDownloadProgressListener;
 import android.telephony.mbms.IMbmsDownloadManagerCallback;
+import android.telephony.mbms.MbmsDownloadManagerCallback;
 import android.telephony.mbms.MbmsException;
 import android.telephony.mbms.UriPathPair;
 import android.telephony.mbms.vendor.IMbmsDownloadService;
 import android.telephony.mbms.vendor.MbmsDownloadServiceBase;
+import android.telephony.mbms.vendor.VendorIntents;
 import android.util.Log;
 
 import java.io.IOException;
@@ -68,7 +71,7 @@
 
     private final IMbmsDownloadService mBinder = new MbmsDownloadServiceBase() {
         @Override
-        public int initialize(int subId, IMbmsDownloadManagerCallback listener) {
+        public int initialize(int subId, MbmsDownloadManagerCallback callback) {
             int packageUid = Binder.getCallingUid();
             String[] packageNames = getPackageManager().getPackagesForUid(packageUid);
             if (packageNames == null) {
@@ -83,13 +86,13 @@
             mHandler.postDelayed(() -> {
                 FrontendAppIdentifier appKey = new FrontendAppIdentifier(packageUid, subId);
                 if (!mAppCallbacks.containsKey(appKey)) {
-                    mAppCallbacks.put(appKey, listener);
-                    ComponentName appReceiver = MbmsDownloadManager.getAppReceiverFromUid(
+                    mAppCallbacks.put(appKey, callback);
+                    ComponentName appReceiver = VendorIntents.getAppReceiverFromUid(
                             EmbmsSampleDownloadService.this, packageUid);
                     mAppReceivers.put(appKey, appReceiver);
                 } else {
                     try {
-                        listener.error(
+                        callback.error(
                                 MbmsException.InitializationErrors.ERROR_DUPLICATE_INITIALIZE, "");
                     } catch (RemoteException e) {
                         // ignore, it was an error anyway
@@ -97,7 +100,7 @@
                     return;
                 }
                 try {
-                    listener.middlewareReady();
+                    callback.middlewareReady();
                 } catch (RemoteException e) {
                     // TODO: call dispose
                 }
@@ -143,7 +146,7 @@
         }
 
         @Override
-        public int download(DownloadRequest downloadRequest, IDownloadProgressListener listener) {
+        public int download(DownloadRequest downloadRequest, DownloadProgressListener listener) {
             FrontendAppIdentifier appKey = new FrontendAppIdentifier(
                     Binder.getCallingUid(), downloadRequest.getSubscriptionId());
             checkInitialized(appKey);
@@ -201,15 +204,15 @@
         ComponentName appReceiver = mAppReceivers.values().iterator().next();
         for (FileServiceInfo fileServiceInfo :
                 FileServiceRepository.getInstance(this).getAllFileServices()) {
-            Intent cleanupIntent = new Intent(MbmsDownloadManager.ACTION_CLEANUP);
+            Intent cleanupIntent = new Intent(VendorIntents.ACTION_CLEANUP);
             cleanupIntent.setComponent(appReceiver);
-            cleanupIntent.putExtra(MbmsDownloadManager.EXTRA_SERVICE_INFO, fileServiceInfo);
-            cleanupIntent.putExtra(MbmsDownloadManager.EXTRA_TEMP_FILE_ROOT,
+            cleanupIntent.putExtra(VendorIntents.EXTRA_SERVICE_INFO, fileServiceInfo);
+            cleanupIntent.putExtra(VendorIntents.EXTRA_TEMP_FILE_ROOT,
                     mAppTempFileRoots.get(registeredAppId));
             Set<Uri> tempFilesInUse =
                     mTempFilesInUse.getOrDefault(registeredAppId, Collections.emptyMap())
                             .getOrDefault(fileServiceInfo.getServiceId(), Collections.emptySet());
-            cleanupIntent.putExtra(MbmsDownloadManager.EXTRA_TEMP_FILES_IN_USE,
+            cleanupIntent.putExtra(VendorIntents.EXTRA_TEMP_FILES_IN_USE,
                     new ArrayList<>(tempFilesInUse));
             sendBroadcast(cleanupIntent);
         }
@@ -219,10 +222,10 @@
         // Assume one app, and do it for the specified service.
         FrontendAppIdentifier registeredAppId = mAppReceivers.keySet().iterator().next();
         ComponentName appReceiver = mAppReceivers.values().iterator().next();
-        Intent fdRequestIntent = new Intent(MbmsDownloadManager.ACTION_FILE_DESCRIPTOR_REQUEST);
-        fdRequestIntent.putExtra(MbmsDownloadManager.EXTRA_SERVICE_INFO, serviceInfo);
-        fdRequestIntent.putExtra(MbmsDownloadManager.EXTRA_FD_COUNT, 10);
-        fdRequestIntent.putExtra(MbmsDownloadManager.EXTRA_TEMP_FILE_ROOT,
+        Intent fdRequestIntent = new Intent(VendorIntents.ACTION_FILE_DESCRIPTOR_REQUEST);
+        fdRequestIntent.putExtra(VendorIntents.EXTRA_SERVICE_INFO, serviceInfo);
+        fdRequestIntent.putExtra(VendorIntents.EXTRA_FD_COUNT, 10);
+        fdRequestIntent.putExtra(VendorIntents.EXTRA_TEMP_FILE_ROOT,
                 mAppTempFileRoots.get(registeredAppId));
         fdRequestIntent.setComponent(appReceiver);
 
@@ -237,7 +240,7 @@
                         if (extras != null) {
                             Log.i(LOG_TAG, "Got "
                                     + extras.getParcelableArrayList(
-                                    MbmsDownloadManager.EXTRA_FREE_URI_LIST).size()
+                                    VendorIntents.EXTRA_FREE_URI_LIST).size()
                                     + " fds");
                         }
                     }
@@ -255,12 +258,12 @@
     private void sendFdRequest(DownloadRequest request, FrontendAppIdentifier appKey) {
         int numFds = getNumFdsNeededForRequest(request);
         // Compose the FILE_DESCRIPTOR_REQUEST_INTENT
-        Intent requestIntent = new Intent(MbmsDownloadManager.ACTION_FILE_DESCRIPTOR_REQUEST);
-        requestIntent.putExtra(MbmsDownloadManager.EXTRA_SERVICE_INFO,
+        Intent requestIntent = new Intent(VendorIntents.ACTION_FILE_DESCRIPTOR_REQUEST);
+        requestIntent.putExtra(VendorIntents.EXTRA_SERVICE_INFO,
                 FileServiceRepository.getInstance(this)
                         .getFileServiceInfoForId(request.getFileServiceId()));
-        requestIntent.putExtra(MbmsDownloadManager.EXTRA_FD_COUNT, numFds);
-        requestIntent.putExtra(MbmsDownloadManager.EXTRA_TEMP_FILE_ROOT,
+        requestIntent.putExtra(VendorIntents.EXTRA_FD_COUNT, numFds);
+        requestIntent.putExtra(VendorIntents.EXTRA_TEMP_FILE_ROOT,
                 mAppTempFileRoots.get(appKey));
         requestIntent.setComponent(mAppReceivers.get(appKey));
 
@@ -288,7 +291,7 @@
     private void performDownload(DownloadRequest request, FrontendAppIdentifier appKey,
             Bundle extras) {
         List<UriPathPair> tempFiles = extras.getParcelableArrayList(
-                MbmsDownloadManager.EXTRA_FREE_URI_LIST);
+                VendorIntents.EXTRA_FREE_URI_LIST);
         List<FileInfo> filesToDownload = FileServiceRepository.getInstance(this)
                 .getFileServiceInfoForId(request.getFileServiceId())
                 .getFiles();
@@ -360,17 +363,17 @@
                 .build();
 
         Intent downloadResultIntent =
-                new Intent(MbmsDownloadManager.ACTION_DOWNLOAD_RESULT_INTERNAL);
-        downloadResultIntent.putExtra(MbmsDownloadManager.EXTRA_REQUEST, request1);
-        downloadResultIntent.putExtra(MbmsDownloadManager.EXTRA_FINAL_URI,
+                new Intent(VendorIntents.ACTION_DOWNLOAD_RESULT_INTERNAL);
+        downloadResultIntent.putExtra(VendorIntents.EXTRA_REQUEST, request1);
+        downloadResultIntent.putExtra(VendorIntents.EXTRA_FINAL_URI,
                 tempFile.getFilePathUri());
         downloadResultIntent.putExtra(MbmsDownloadManager.EXTRA_FILE_INFO, fileToDownload);
-        downloadResultIntent.putExtra(MbmsDownloadManager.EXTRA_TEMP_FILE_ROOT,
+        downloadResultIntent.putExtra(VendorIntents.EXTRA_TEMP_FILE_ROOT,
                 mAppTempFileRoots.get(appKey));
         ArrayList<Uri> tempFileList = new ArrayList<>(1);
         tempFileList.add(tempFile.getFilePathUri());
         downloadResultIntent.getExtras().putParcelableArrayList(
-                MbmsDownloadManager.EXTRA_TEMP_LIST, tempFileList);
+                VendorIntents.EXTRA_TEMP_LIST, tempFileList);
         downloadResultIntent.putExtra(MbmsDownloadManager.EXTRA_RESULT, result);
         downloadResultIntent.setComponent(mAppReceivers.get(appKey));
 
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 7a9dd03..3428e38 100644
--- a/testapps/EmbmsServiceTestApp/src/com/android/phone/testapps/embmsmw/EmbmsTestStreamingService.java
+++ b/testapps/EmbmsServiceTestApp/src/com/android/phone/testapps/embmsmw/EmbmsTestStreamingService.java
@@ -78,7 +78,7 @@
 
     private final MbmsStreamingServiceBase mBinder = new MbmsStreamingServiceBase() {
         @Override
-        public int initialize(MbmsStreamingManagerCallback listener, int subId) {
+        public int initialize(MbmsStreamingManagerCallback callback, int subId) {
             int packageUid = Binder.getCallingUid();
             String[] packageNames = getPackageManager().getPackagesForUid(packageUid);
             if (packageNames == null) {
@@ -92,13 +92,13 @@
             mHandler.postDelayed(() -> {
                 FrontendAppIdentifier appKey = new FrontendAppIdentifier(packageUid, subId);
                 if (!mAppCallbacks.containsKey(appKey)) {
-                    mAppCallbacks.put(appKey, listener);
+                    mAppCallbacks.put(appKey, callback);
                 } else {
-                    listener.onError(
+                    callback.onError(
                             MbmsException.InitializationErrors.ERROR_DUPLICATE_INITIALIZE, "");
                     return;
                 }
-                listener.onMiddlewareReady();
+                callback.onMiddlewareReady();
             }, INITIALIZATION_DELAY);
             return MbmsException.SUCCESS;
         }
diff --git a/testapps/EmbmsServiceTestApp/src/com/android/phone/testapps/embmsmw/FileServiceRepository.java b/testapps/EmbmsServiceTestApp/src/com/android/phone/testapps/embmsmw/FileServiceRepository.java
index a771a1a..7b8cbd5 100644
--- a/testapps/EmbmsServiceTestApp/src/com/android/phone/testapps/embmsmw/FileServiceRepository.java
+++ b/testapps/EmbmsServiceTestApp/src/com/android/phone/testapps/embmsmw/FileServiceRepository.java
@@ -119,23 +119,6 @@
             return null;
         }
 
-        InputStream fileIn = mContext.getResources().openRawResource(mFileUriToResource.get(uri));
-        int fileSize;
-        byte[] buffer;
-        byte[] md5Sum;
-        try {
-            fileSize = fileIn.available();
-            buffer = new byte[fileIn.available()];
-            fileIn.read(buffer);
-        } catch (IOException e) {
-            // ignore and just return null
-            return null;
-        }
-        try {
-            md5Sum = MessageDigest.getInstance("MD5").digest(buffer);
-        } catch (NoSuchAlgorithmException e) {
-            return null;
-        }
-        return new FileInfo(uri, "application/octet-stream", fileSize, md5Sum);
+        return new FileInfo(uri, "application/octet-stream");
     }
 }