Merge "Cleanup deprecated or removed telephony methods."
diff --git a/Android.bp b/Android.bp
index b2b3dff..e2b432c 100644
--- a/Android.bp
+++ b/Android.bp
@@ -506,11 +506,14 @@
         "telephony/java/android/telephony/ims/aidl/IImsSmsListener.aidl",
         "telephony/java/android/telephony/mbms/IMbmsDownloadSessionCallback.aidl",
         "telephony/java/android/telephony/mbms/IMbmsStreamingSessionCallback.aidl",
+        "telephony/java/android/telephony/mbms/IMbmsGroupCallSessionCallback.aidl",
         "telephony/java/android/telephony/mbms/IDownloadStatusListener.aidl",
         "telephony/java/android/telephony/mbms/IDownloadProgressListener.aidl",
         "telephony/java/android/telephony/mbms/IStreamingServiceCallback.aidl",
+        "telephony/java/android/telephony/mbms/IGroupCallCallback.aidl",
         "telephony/java/android/telephony/mbms/vendor/IMbmsDownloadService.aidl",
         "telephony/java/android/telephony/mbms/vendor/IMbmsStreamingService.aidl",
+        "telephony/java/android/telephony/mbms/vendor/IMbmsGroupCallService.aidl",
         "telephony/java/android/telephony/INetworkService.aidl",
         "telephony/java/android/telephony/INetworkServiceCallback.aidl",
         "telephony/java/com/android/ims/internal/IImsCallSession.aidl",
@@ -795,7 +798,7 @@
 java_library {
     name: "ext",
     installable: true,
-    no_framework_libs: true,
+    sdk_version: "core_current",
     static_libs: [
         "libphonenumber-platform",
         "nist-sip",
@@ -1267,6 +1270,9 @@
 }
 
 droiddoc {
+    // Please sync with android-api-council@ before making any changes for the name property below.
+    // Since there's cron jobs that fetch offline-sdk-referenceonly-docs-docs.zip periodically.
+    // See b/116221385 for reference.
     name: "offline-sdk-referenceonly-docs",
     defaults: ["framework-docs-default"],
     srcs: [
@@ -1283,6 +1289,9 @@
 }
 
 droiddoc {
+    // Please sync with android-api-council@ before making any changes for the name property below.
+    // Since there's cron jobs that fetch offline-system-sdk-referenceonly-docs-docs.zip periodically.
+    // See b/116221385 for reference.
     name: "offline-system-sdk-referenceonly-docs",
     defaults: ["framework-docs-default"],
     srcs: [
diff --git a/api/current.txt b/api/current.txt
index a254610..b5c23f1 100755
--- a/api/current.txt
+++ b/api/current.txt
@@ -41035,6 +41035,7 @@
     field public static final int PROPERTY_HAS_CDMA_VOICE_PRIVACY = 128; // 0x80
     field public static final int PROPERTY_HIGH_DEF_AUDIO = 16; // 0x10
     field public static final int PROPERTY_IS_EXTERNAL_CALL = 64; // 0x40
+    field public static final int PROPERTY_NETWORK_IDENTIFIED_EMERGENCY_CALL = 2048; // 0x800
     field public static final int PROPERTY_RTT = 1024; // 0x400
     field public static final int PROPERTY_SELF_MANAGED = 256; // 0x100
     field public static final int PROPERTY_WIFI = 8; // 0x8
@@ -41988,6 +41989,7 @@
     field public static final deprecated java.lang.String KEY_RESTART_RADIO_ON_PDP_FAIL_REGULAR_DEACTIVATION_BOOL = "restart_radio_on_pdp_fail_regular_deactivation_bool";
     field public static final java.lang.String KEY_RTT_SUPPORTED_BOOL = "rtt_supported_bool";
     field public static final java.lang.String KEY_SHOW_APN_SETTING_CDMA_BOOL = "show_apn_setting_cdma_bool";
+    field public static final java.lang.String KEY_SHOW_CALL_BLOCKING_DISABLED_NOTIFICATION_ALWAYS_BOOL = "show_call_blocking_disabled_notification_always_bool";
     field public static final java.lang.String KEY_SHOW_CDMA_CHOICES_BOOL = "show_cdma_choices_bool";
     field public static final java.lang.String KEY_SHOW_ICCID_IN_SIM_STATUS_BOOL = "show_iccid_in_sim_status_bool";
     field public static final java.lang.String KEY_SHOW_ONSCREEN_DIAL_BUTTON_BOOL = "show_onscreen_dial_button_bool";
@@ -42249,6 +42251,13 @@
     field public static final int STATUS_UNKNOWN = 0; // 0x0
   }
 
+  public class MbmsGroupCallSession implements java.lang.AutoCloseable {
+    method public void close();
+    method public static android.telephony.MbmsGroupCallSession create(android.content.Context, java.util.concurrent.Executor, int, android.telephony.mbms.MbmsGroupCallSessionCallback);
+    method public static android.telephony.MbmsGroupCallSession create(android.content.Context, java.util.concurrent.Executor, android.telephony.mbms.MbmsGroupCallSessionCallback);
+    method public android.telephony.mbms.GroupCall startGroupCall(java.util.concurrent.Executor, long, int[], int[], android.telephony.mbms.GroupCallCallback);
+  }
+
   public class MbmsStreamingSession implements java.lang.AutoCloseable {
     method public void close();
     method public static android.telephony.MbmsStreamingSession create(android.content.Context, java.util.concurrent.Executor, int, android.telephony.mbms.MbmsStreamingSessionCallback);
@@ -42628,6 +42637,7 @@
     method public static int getDefaultVoiceSubscriptionId();
     method public static int[] getSubscriptionIds(int);
     method public java.util.List<android.telephony.SubscriptionPlan> getSubscriptionPlans(int);
+    method public boolean isActiveSubscriptionId(int);
     method public boolean isNetworkRoaming(int);
     method public static boolean isValidSubscriptionId(int);
     method public void removeOnOpportunisticSubscriptionsChangedListener(android.telephony.SubscriptionManager.OnOpportunisticSubscriptionsChangedListener);
@@ -43194,6 +43204,29 @@
     field public static final android.os.Parcelable.Creator<android.telephony.mbms.FileServiceInfo> CREATOR;
   }
 
+  public class GroupCall implements java.lang.AutoCloseable {
+    method public void close();
+    method public long getTmgi();
+    method public void updateGroupCall(int[], int[]);
+    field public static final int REASON_BY_USER_REQUEST = 1; // 0x1
+    field public static final int REASON_FREQUENCY_CONFLICT = 3; // 0x3
+    field public static final int REASON_LEFT_MBMS_BROADCAST_AREA = 6; // 0x6
+    field public static final int REASON_NONE = 0; // 0x0
+    field public static final int REASON_NOT_CONNECTED_TO_HOMECARRIER_LTE = 5; // 0x5
+    field public static final int REASON_OUT_OF_MEMORY = 4; // 0x4
+    field public static final int STATE_STALLED = 3; // 0x3
+    field public static final int STATE_STARTED = 2; // 0x2
+    field public static final int STATE_STOPPED = 1; // 0x1
+  }
+
+  public class GroupCallCallback {
+    ctor public GroupCallCallback();
+    method public void onBroadcastSignalStrengthUpdated(int);
+    method public void onError(int, java.lang.String);
+    method public void onGroupCallStateChanged(int, int);
+    field public static final int SIGNAL_STRENGTH_UNAVAILABLE = -1; // 0xffffffff
+  }
+
   public class MbmsDownloadReceiver extends android.content.BroadcastReceiver {
     ctor public MbmsDownloadReceiver();
     method public void onReceive(android.content.Context, android.content.Intent);
@@ -43242,6 +43275,14 @@
     field public static final int ERROR_UNABLE_TO_START_SERVICE = 302; // 0x12e
   }
 
+  public class MbmsGroupCallSessionCallback {
+    ctor public MbmsGroupCallSessionCallback();
+    method public void onAvailableSaisUpdated(java.util.List<java.lang.Integer>, java.util.List<java.util.List<java.lang.Integer>>);
+    method public void onError(int, java.lang.String);
+    method public void onMiddlewareReady();
+    method public void onServiceInterfaceAvailable(java.lang.String, int);
+  }
+
   public class MbmsStreamingSessionCallback {
     ctor public MbmsStreamingSessionCallback();
     method public void onError(int, java.lang.String);
diff --git a/api/system-current.txt b/api/system-current.txt
index 4328681..6eb6448d 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -5048,6 +5048,7 @@
     method public deprecated android.content.ComponentName getDefaultPhoneApp();
     method public java.util.List<android.telecom.PhoneAccountHandle> getPhoneAccountsForPackage();
     method public java.util.List<android.telecom.PhoneAccountHandle> getPhoneAccountsSupportingScheme(java.lang.String);
+    method public boolean isInEmergencyCall();
     method public boolean isRinging();
     method public boolean isTtySupported();
     field public static final java.lang.String EXTRA_CALL_BACK_INTENT = "android.telecom.extra.CALL_BACK_INTENT";
@@ -5074,6 +5075,10 @@
     field public static final java.lang.String MBMS_DOWNLOAD_SERVICE_ACTION = "android.telephony.action.EmbmsDownload";
   }
 
+  public class MbmsGroupCallSession implements java.lang.AutoCloseable {
+    field public static final java.lang.String MBMS_GROUP_CALL_SERVICE_ACTION = "android.telephony.action.EmbmsGroupCall";
+  }
+
   public class MbmsStreamingSession implements java.lang.AutoCloseable {
     field public static final java.lang.String MBMS_STREAMING_SERVICE_ACTION = "android.telephony.action.EmbmsStreaming";
   }
@@ -5237,6 +5242,7 @@
     method public boolean disableDataConnectivity();
     method public boolean enableDataConnectivity();
     method public void enableVideoCalling(boolean);
+    method public java.lang.String getAidForAppType(int);
     method public java.util.List<android.service.carrier.CarrierIdentifier> getAllowedCarriers(int);
     method public java.util.List<java.lang.String> getCarrierPackageNamesForIntent(android.content.Intent);
     method public java.util.List<java.lang.String> getCarrierPackageNamesForIntentAndPhone(android.content.Intent, int);
@@ -5251,6 +5257,7 @@
     method public deprecated boolean getDataEnabled();
     method public deprecated boolean getDataEnabled(int);
     method public boolean getEmergencyCallbackMode();
+    method public java.lang.String getIsimDomain();
     method public int getSimApplicationState();
     method public int getSimCardState();
     method public java.util.List<android.telephony.TelephonyHistogram> getTelephonyHistograms();
@@ -5626,6 +5633,7 @@
     field public static final java.lang.String EXTRA_CODEC = "Codec";
     field public static final java.lang.String EXTRA_DIALSTRING = "dialstring";
     field public static final java.lang.String EXTRA_DISPLAY_TEXT = "DisplayText";
+    field public static final java.lang.String EXTRA_E_CALL = "e_call";
     field public static final java.lang.String EXTRA_IS_CALL_PULL = "CallPull";
     field public static final java.lang.String EXTRA_OI = "oi";
     field public static final java.lang.String EXTRA_OIR = "oir";
@@ -6369,6 +6377,17 @@
     method public int setTempFileRootDirectory(int, java.lang.String) throws android.os.RemoteException;
   }
 
+  public class MbmsGroupCallServiceBase extends android.app.Service {
+    ctor public MbmsGroupCallServiceBase();
+    method public void dispose(int) throws android.os.RemoteException;
+    method public int initialize(android.telephony.mbms.MbmsGroupCallSessionCallback, int) throws android.os.RemoteException;
+    method public void onAppCallbackDied(int, int);
+    method public android.os.IBinder onBind(android.content.Intent);
+    method public int startGroupCall(int, long, int[], int[], android.telephony.mbms.GroupCallCallback);
+    method public void stopGroupCall(int, long);
+    method public void updateGroupCall(int, long, int[], int[]);
+  }
+
   public class MbmsStreamingServiceBase extends android.os.Binder {
     ctor public MbmsStreamingServiceBase();
     method public void dispose(int) throws android.os.RemoteException;
diff --git a/api/test-current.txt b/api/test-current.txt
index 634293a..a7bb467 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -966,6 +966,10 @@
     field public static final java.lang.String MBMS_DOWNLOAD_SERVICE_OVERRIDE_METADATA = "mbms-download-service-override";
   }
 
+  public class MbmsGroupCallSession implements java.lang.AutoCloseable {
+    field public static final java.lang.String MBMS_GROUP_CALL_SERVICE_OVERRIDE_METADATA = "mbms-group-call-service-override";
+  }
+
   public class MbmsStreamingSession implements java.lang.AutoCloseable {
     field public static final java.lang.String MBMS_STREAMING_SERVICE_OVERRIDE_METADATA = "mbms-streaming-service-override";
   }
@@ -1035,6 +1039,17 @@
     method public int setTempFileRootDirectory(int, java.lang.String) throws android.os.RemoteException;
   }
 
+  public class MbmsGroupCallServiceBase extends android.app.Service {
+    ctor public MbmsGroupCallServiceBase();
+    method public void dispose(int) throws android.os.RemoteException;
+    method public int initialize(android.telephony.mbms.MbmsGroupCallSessionCallback, int) throws android.os.RemoteException;
+    method public void onAppCallbackDied(int, int);
+    method public android.os.IBinder onBind(android.content.Intent);
+    method public int startGroupCall(int, long, int[], int[], android.telephony.mbms.GroupCallCallback);
+    method public void stopGroupCall(int, long);
+    method public void updateGroupCall(int, long, int[], int[]);
+  }
+
   public class MbmsStreamingServiceBase extends android.os.Binder {
     ctor public MbmsStreamingServiceBase();
     method public void dispose(int) throws android.os.RemoteException;
diff --git a/core/java/android/bluetooth/BluetoothMapClient.java b/core/java/android/bluetooth/BluetoothMapClient.java
index 183be5f..559a59b 100644
--- a/core/java/android/bluetooth/BluetoothMapClient.java
+++ b/core/java/android/bluetooth/BluetoothMapClient.java
@@ -73,6 +73,8 @@
     /** Connection canceled before completion. */
     public static final int RESULT_CANCELED = 2;
 
+    private static final int UPLOADING_FEATURE_BITMASK = 0x08;
+
     private final IBluetoothStateChangeCallback mBluetoothStateChangeCallback =
             new IBluetoothStateChangeCallback.Stub() {
                 public void onBluetoothStateChange(boolean up) {
@@ -395,6 +397,23 @@
         return false;
     }
 
+    /**
+     * Returns the "Uploading" feature bit value from the SDP record's
+     * MapSupportedFeatures field (see Bluetooth MAP 1.4 spec, page 114).
+     * @param device The Bluetooth device to get this value for.
+     * @return Returns true if the Uploading bit value in SDP record's
+     *         MapSupportedFeatures field is set. False is returned otherwise.
+     */
+    public boolean isUploadingSupported(BluetoothDevice device) {
+        try {
+            return (mService != null && isEnabled() && isValidDevice(device))
+                && ((mService.getSupportedFeatures(device) & UPLOADING_FEATURE_BITMASK) > 0);
+        } catch (RemoteException e) {
+            Log.e(TAG, e.getMessage());
+        }
+        return false;
+    }
+
     private final ServiceConnection mConnection = new ServiceConnection() {
         public void onServiceConnected(ComponentName className, IBinder service) {
             if (DBG) Log.d(TAG, "Proxy object connected");
diff --git a/core/java/android/security/net/config/DirectoryCertificateSource.java b/core/java/android/security/net/config/DirectoryCertificateSource.java
index 119f5d0..4f4d62a 100644
--- a/core/java/android/security/net/config/DirectoryCertificateSource.java
+++ b/core/java/android/security/net/config/DirectoryCertificateSource.java
@@ -16,26 +16,23 @@
 
 package android.security.net.config;
 
-import android.os.Environment;
-import android.os.UserHandle;
 import android.util.ArraySet;
 import android.util.Log;
-import android.util.Pair;
+
+import libcore.io.IoUtils;
+
 import java.io.BufferedInputStream;
 import java.io.File;
 import java.io.FileInputStream;
-import java.io.InputStream;
 import java.io.IOException;
-import java.security.cert.Certificate;
+import java.io.InputStream;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
 import java.security.cert.CertificateException;
 import java.security.cert.CertificateFactory;
 import java.security.cert.X509Certificate;
 import java.util.Collections;
 import java.util.Set;
-import libcore.io.IoUtils;
-
-import com.android.org.conscrypt.Hex;
-import com.android.org.conscrypt.NativeCrypto;
 
 import javax.security.auth.x500.X500Principal;
 
@@ -192,8 +189,36 @@
     }
 
     private String getHash(X500Principal name) {
-        int hash = NativeCrypto.X509_NAME_hash_old(name);
-        return Hex.intToHexString(hash, 8);
+        int hash = hashName(name);
+        return intToHexString(hash, 8);
+    }
+
+    private static final char[] DIGITS = {
+            '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
+
+    private static String intToHexString(int i, int minWidth) {
+        int bufLen = 8;  // Max number of hex digits in an int
+        char[] buf = new char[bufLen];
+        int cursor = bufLen;
+
+        do {
+            buf[--cursor] = DIGITS[i & 0xf];
+        } while ((i >>>= 4) != 0 || (bufLen - cursor < minWidth));
+
+        return new String(buf, cursor, bufLen - cursor);
+    }
+
+    // This code matches the code in X509_NAME_hash_old() in Conscrypt, which in turn matches
+    // the names of certificate files.  It must be kept in sync.
+    private static int hashName(X500Principal principal) {
+        try {
+            byte[] digest = MessageDigest.getInstance("MD5").digest(principal.getEncoded());
+            int offset = 0;
+            return (((digest[offset++] & 0xff) << 0) | ((digest[offset++] & 0xff) << 8)
+                    | ((digest[offset++] & 0xff) << 16) | ((digest[offset] & 0xff) << 24));
+        } catch (NoSuchAlgorithmException e) {
+            throw new AssertionError(e);
+        }
     }
 
     private X509Certificate readCertificate(String file) {
diff --git a/core/java/com/android/internal/content/FileSystemProvider.java b/core/java/com/android/internal/content/FileSystemProvider.java
index b591163..f90eab1 100644
--- a/core/java/com/android/internal/content/FileSystemProvider.java
+++ b/core/java/com/android/internal/content/FileSystemProvider.java
@@ -236,6 +236,7 @@
         displayName = FileUtils.buildValidFatFilename(displayName);
 
         final File before = getFileForDocId(docId);
+        final File beforeVisibleFile = getFileForDocId(docId, true);
         final File after = FileUtils.buildUniqueFile(before.getParentFile(), displayName);
         if (!before.renameTo(after)) {
             throw new IllegalStateException("Failed to rename to " + after);
@@ -245,7 +246,6 @@
         onDocIdChanged(docId);
         onDocIdChanged(afterDocId);
 
-        final File beforeVisibleFile = getFileForDocId(docId, true);
         final File afterVisibleFile = getFileForDocId(afterDocId, true);
         moveInMediaStore(beforeVisibleFile, afterVisibleFile);
 
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpProfile.java
index 541877c..3c58160 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpProfile.java
@@ -105,7 +105,7 @@
                 BluetoothProfile.A2DP);
     }
 
-    public boolean isConnectable() {
+    public boolean accessProfileEnabled() {
         return true;
     }
 
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpSinkProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpSinkProfile.java
index 0e0f63c..656f23f 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpSinkProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpSinkProfile.java
@@ -99,7 +99,7 @@
                 BluetoothProfile.A2DP_SINK);
     }
 
-    public boolean isConnectable() {
+    public boolean accessProfileEnabled() {
         return true;
     }
 
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
index e96c44d..8fa9597 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
@@ -250,7 +250,7 @@
 
         int preferredProfiles = 0;
         for (LocalBluetoothProfile profile : mProfiles) {
-            if (connectAllProfiles ? profile.isConnectable() : profile.isAutoConnectable()) {
+            if (connectAllProfiles ? profile.accessProfileEnabled() : profile.isAutoConnectable()) {
                 if (profile.isPreferred(mDevice)) {
                     ++preferredProfiles;
                     connectInt(profile);
@@ -736,7 +736,7 @@
         List<LocalBluetoothProfile> connectableProfiles =
                 new ArrayList<LocalBluetoothProfile>();
         for (LocalBluetoothProfile profile : mProfiles) {
-            if (profile.isConnectable()) {
+            if (profile.accessProfileEnabled()) {
                 connectableProfiles.add(profile);
             }
         }
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HeadsetProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HeadsetProfile.java
index 7f83860..3bb8450 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HeadsetProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HeadsetProfile.java
@@ -106,7 +106,7 @@
                 BluetoothProfile.HEADSET);
     }
 
-    public boolean isConnectable() {
+    public boolean accessProfileEnabled() {
         return true;
     }
 
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidProfile.java
index 1d2fda9..06d60e6 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidProfile.java
@@ -103,7 +103,7 @@
                 BluetoothProfile.HEARING_AID);
     }
 
-    public boolean isConnectable() {
+    public boolean accessProfileEnabled() {
         return false;
     }
 
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HfpClientProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HfpClientProfile.java
index 0857b01..4ae9b32 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HfpClientProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HfpClientProfile.java
@@ -107,7 +107,7 @@
     }
 
     @Override
-    public boolean isConnectable() {
+    public boolean accessProfileEnabled() {
         return true;
     }
 
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HidDeviceProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HidDeviceProfile.java
index af78c6f..1c04e83 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HidDeviceProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HidDeviceProfile.java
@@ -97,7 +97,7 @@
     }
 
     @Override
-    public boolean isConnectable() {
+    public boolean accessProfileEnabled() {
         return true;
     }
 
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HidProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HidProfile.java
index dc17e44..1e06481 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HidProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HidProfile.java
@@ -95,7 +95,7 @@
                 BluetoothProfile.HID_HOST);
     }
 
-    public boolean isConnectable() {
+    public boolean accessProfileEnabled() {
         return true;
     }
 
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfile.java
index 0447f37..4b0ca74 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfile.java
@@ -26,9 +26,9 @@
 public interface LocalBluetoothProfile {
 
     /**
-     * Returns true if the user can initiate a connection, false otherwise.
+     * Return {@code true} if the user can initiate a connection for this profile in UI.
      */
-    boolean isConnectable();
+    boolean accessProfileEnabled();
 
     /**
      * Returns true if the user can enable auto connection for this profile.
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/MapClientProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/MapClientProfile.java
index e9fcc11..57712e3 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/MapClientProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/MapClientProfile.java
@@ -108,7 +108,7 @@
                 BluetoothProfile.MAP_CLIENT);
     }
 
-    public boolean isConnectable() {
+    public boolean accessProfileEnabled() {
         return true;
     }
 
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/MapProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/MapProfile.java
index 511c4ce..e59a036 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/MapProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/MapProfile.java
@@ -107,7 +107,7 @@
                 BluetoothProfile.MAP);
     }
 
-    public boolean isConnectable() {
+    public boolean accessProfileEnabled() {
         return true;
     }
 
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/OppProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/OppProfile.java
index dfd1622..e1e5dbe 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/OppProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/OppProfile.java
@@ -32,7 +32,7 @@
     // Order of this profile in device profiles list
     private static final int ORDINAL = 2;
 
-    public boolean isConnectable() {
+    public boolean accessProfileEnabled() {
         return false;
     }
 
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/PanProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/PanProfile.java
index b18b19b..0d566c7 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/PanProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/PanProfile.java
@@ -80,7 +80,7 @@
             BluetoothProfile.PAN);
     }
 
-    public boolean isConnectable() {
+    public boolean accessProfileEnabled() {
         return true;
     }
 
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/PbapClientProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/PbapClientProfile.java
index fc54775..c83ff35 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/PbapClientProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/PbapClientProfile.java
@@ -110,7 +110,7 @@
                 BluetoothProfile.PBAP_CLIENT);
     }
 
-    public boolean isConnectable() {
+    public boolean accessProfileEnabled() {
         return true;
     }
 
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/PbapServerProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/PbapServerProfile.java
index e9d8cb5..adef0841 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/PbapServerProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/PbapServerProfile.java
@@ -80,7 +80,7 @@
         BluetoothPbap pbap = new BluetoothPbap(context, new PbapServiceListener());
     }
 
-    public boolean isConnectable() {
+    public boolean accessProfileEnabled() {
         return true;
     }
 
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/SapProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/SapProfile.java
index 2c455d5f..f7cd393 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/SapProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/SapProfile.java
@@ -106,7 +106,7 @@
                 BluetoothProfile.SAP);
     }
 
-    public boolean isConnectable() {
+    public boolean accessProfileEnabled() {
         return true;
     }
 
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 271d205..fae4db9 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -17529,7 +17529,8 @@
         // Prepare the application profiles for the new code paths.
         // This needs to be done before invoking dexopt so that any install-time profile
         // can be used for optimizations.
-        mArtManagerService.prepareAppProfiles(pkg, resolveUserIds(args.user.getIdentifier()));
+        mArtManagerService.prepareAppProfiles(pkg, resolveUserIds(args.user.getIdentifier()),
+                /* updateReferenceProfileContent= */ true);
 
         // Check whether we need to dexopt the app.
         //
@@ -22606,8 +22607,18 @@
         //
         // We also have to cover non system users because we do not call the usual install package
         // methods for them.
+        //
+        // NOTE: in order to speed up first boot time we only create the current profile and do not
+        // update the content of the reference profile. A system image should already be configured
+        // with the right profile keys and the profiles for the speed-profile prebuilds should
+        // already be copied. That's done in #performDexOptUpgrade.
+        //
+        // TODO(calin, mathieuc): We should use .dm files for prebuilds profiles instead of
+        // manually copying them in #performDexOptUpgrade. When we do that we should have a more
+        // granular check here and only update the existing profiles.
         if (mIsUpgrade || mFirstBoot || (userId != UserHandle.USER_SYSTEM)) {
-            mArtManagerService.prepareAppProfiles(pkg, userId);
+            mArtManagerService.prepareAppProfiles(pkg, userId,
+                /* updateReferenceProfileContent= */ false);
         }
 
         if ((flags & StorageManager.FLAG_STORAGE_CE) != 0 && ceDataInode != -1) {
diff --git a/services/core/java/com/android/server/pm/dex/ArtManagerService.java b/services/core/java/com/android/server/pm/dex/ArtManagerService.java
index 0ba7822..833cc5b 100644
--- a/services/core/java/com/android/server/pm/dex/ArtManagerService.java
+++ b/services/core/java/com/android/server/pm/dex/ArtManagerService.java
@@ -389,7 +389,8 @@
      *   - create the current primary profile to save time at app startup time.
      *   - copy the profiles from the associated dex metadata file to the reference profile.
      */
-    public void prepareAppProfiles(PackageParser.Package pkg, @UserIdInt int user) {
+    public void prepareAppProfiles(PackageParser.Package pkg, @UserIdInt int user,
+            boolean updateReferenceProfileContent) {
         final int appId = UserHandle.getAppId(pkg.applicationInfo.uid);
         if (user < 0) {
             Slog.wtf(TAG, "Invalid user id: " + user);
@@ -404,8 +405,14 @@
             for (int i = codePathsProfileNames.size() - 1; i >= 0; i--) {
                 String codePath = codePathsProfileNames.keyAt(i);
                 String profileName = codePathsProfileNames.valueAt(i);
-                File dexMetadata = DexMetadataHelper.findDexMetadataForFile(new File(codePath));
-                String dexMetadataPath = dexMetadata == null ? null : dexMetadata.getAbsolutePath();
+                String dexMetadataPath = null;
+                // Passing the dex metadata file to the prepare method will update the reference
+                // profile content. As such, we look for the dex metadata file only if we need to
+                // perform an update.
+                if (updateReferenceProfileContent) {
+                    File dexMetadata = DexMetadataHelper.findDexMetadataForFile(new File(codePath));
+                    dexMetadataPath = dexMetadata == null ? null : dexMetadata.getAbsolutePath();
+                }
                 synchronized (mInstaller) {
                     boolean result = mInstaller.prepareAppProfile(pkg.packageName, user, appId,
                             profileName, codePath, dexMetadataPath);
@@ -423,9 +430,10 @@
     /**
      * Prepares the app profiles for a set of users. {@see ArtManagerService#prepareAppProfiles}.
      */
-    public void prepareAppProfiles(PackageParser.Package pkg, int[] user) {
+    public void prepareAppProfiles(PackageParser.Package pkg, int[] user,
+            boolean updateReferenceProfileContent) {
         for (int i = 0; i < user.length; i++) {
-            prepareAppProfiles(pkg, user[i]);
+            prepareAppProfiles(pkg, user[i], updateReferenceProfileContent);
         }
     }
 
diff --git a/services/core/java/com/android/server/pm/dex/PackageDexUsage.java b/services/core/java/com/android/server/pm/dex/PackageDexUsage.java
index e3e1590..602ce3b 100644
--- a/services/core/java/com/android/server/pm/dex/PackageDexUsage.java
+++ b/services/core/java/com/android/server/pm/dex/PackageDexUsage.java
@@ -93,7 +93,7 @@
     @GuardedBy("mPackageUseInfoMap")
     private final Map<String, PackageUseInfo> mPackageUseInfoMap;
 
-    public PackageDexUsage() {
+    /* package */ PackageDexUsage() {
         super("package-dex-usage.list", "PackageDexUsage_DiskWriter", /*lock*/ false);
         mPackageUseInfoMap = new HashMap<>();
     }
@@ -116,7 +116,7 @@
      * @return true if the dex load constitutes new information, or false if this information
      *         has been seen before.
      */
-    public boolean record(String owningPackageName, String dexPath, int ownerUserId,
+    /* package */ boolean record(String owningPackageName, String dexPath, int ownerUserId,
             String loaderIsa, boolean isUsedByOtherApps, boolean primaryOrSplit,
             String loadingPackageName, String classLoaderContext) {
         if (!PackageManagerServiceUtils.checkISA(loaderIsa)) {
@@ -193,7 +193,7 @@
      * Convenience method for sync reads which does not force the user to pass a useless
      * (Void) null.
      */
-    public void read() {
+    /* package */ void read() {
       read((Void) null);
     }
 
@@ -558,7 +558,7 @@
      * Remove the usage data associated with package {@code packageName}.
      * @return true if the package usage was found and removed successfully.
      */
-    public boolean removePackage(String packageName) {
+    /* package */ boolean removePackage(String packageName) {
         synchronized (mPackageUseInfoMap) {
             return mPackageUseInfoMap.remove(packageName) != null;
         }
@@ -653,11 +653,12 @@
         return packages;
     }
 
-    public void clear() {
+    /* package */ void clear() {
         synchronized (mPackageUseInfoMap) {
             mPackageUseInfoMap.clear();
         }
     }
+
     // Creates a deep copy of the class' mPackageUseInfoMap.
     private Map<String, PackageUseInfo> clonePackageUseInfoMap() {
         Map<String, PackageUseInfo> clone = new HashMap<>();
@@ -679,7 +680,7 @@
         throw new IllegalArgumentException("Unknown bool encoding: " + bool);
     }
 
-    public String dump() {
+    /* package */ String dump() {
         StringWriter sw = new StringWriter();
         write(sw);
         return sw.toString();
diff --git a/telecomm/java/android/telecom/Call.java b/telecomm/java/android/telecom/Call.java
index 096cf37..08bc9bc 100644
--- a/telecomm/java/android/telecom/Call.java
+++ b/telecomm/java/android/telecom/Call.java
@@ -141,6 +141,8 @@
      * The caller must specify the {@link #EXTRA_HANDOVER_PHONE_ACCOUNT_HANDLE} to indicate to
      * Telecom which {@link PhoneAccountHandle} the {@link Call} should be handed over to.
      * @hide
+     * @deprecated Use {@link Call#handoverTo(PhoneAccountHandle, int, Bundle)} and its associated
+     * APIs instead.
      */
     public static final String EVENT_REQUEST_HANDOVER =
             "android.telecom.event.REQUEST_HANDOVER";
@@ -149,6 +151,8 @@
      * Extra key used with the {@link #EVENT_REQUEST_HANDOVER} call event.  Specifies the
      * {@link PhoneAccountHandle} to which a call should be handed over to.
      * @hide
+     * @deprecated Use {@link Call#handoverTo(PhoneAccountHandle, int, Bundle)} and its associated
+     * APIs instead.
      */
     public static final String EXTRA_HANDOVER_PHONE_ACCOUNT_HANDLE =
             "android.telecom.extra.HANDOVER_PHONE_ACCOUNT_HANDLE";
@@ -161,6 +165,8 @@
      * {@link VideoProfile#STATE_BIDIRECTIONAL}, {@link VideoProfile#STATE_RX_ENABLED}, and
      * {@link VideoProfile#STATE_TX_ENABLED}.
      * @hide
+     * @deprecated Use {@link Call#handoverTo(PhoneAccountHandle, int, Bundle)} and its associated
+     * APIs instead.
      */
     public static final String EXTRA_HANDOVER_VIDEO_STATE =
             "android.telecom.extra.HANDOVER_VIDEO_STATE";
@@ -176,6 +182,8 @@
      * {@link ConnectionService#onCreateOutgoingConnection(PhoneAccountHandle, ConnectionRequest)}
      * is called to initate the handover.
      * @hide
+     * @deprecated Use {@link Call#handoverTo(PhoneAccountHandle, int, Bundle)} and its associated
+     * APIs instead.
      */
     public static final String EXTRA_HANDOVER_EXTRAS = "android.telecom.extra.HANDOVER_EXTRAS";
 
@@ -186,6 +194,8 @@
      * <p>
      * A handover is initiated with the {@link #EVENT_REQUEST_HANDOVER} call event.
      * @hide
+     * @deprecated Use {@link Call#handoverTo(PhoneAccountHandle, int, Bundle)} and its associated
+     * APIs instead.
      */
     public static final String EVENT_HANDOVER_COMPLETE =
             "android.telecom.event.HANDOVER_COMPLETE";
@@ -198,6 +208,8 @@
      * <p>
      * A handover is initiated with the {@link #EVENT_REQUEST_HANDOVER} call event.
      * @hide
+     * @deprecated Use {@link Call#handoverTo(PhoneAccountHandle, int, Bundle)} and its associated
+     * APIs instead.
      */
     public static final String EVENT_HANDOVER_SOURCE_DISCONNECTED =
             "android.telecom.event.HANDOVER_SOURCE_DISCONNECTED";
@@ -209,6 +221,8 @@
      * <p>
      * A handover is initiated with the {@link #EVENT_REQUEST_HANDOVER} call event.
      * @hide
+     * @deprecated Use {@link Call#handoverTo(PhoneAccountHandle, int, Bundle)} and its associated
+     * APIs instead.
      */
     public static final String EVENT_HANDOVER_FAILED =
             "android.telecom.event.HANDOVER_FAILED";
@@ -434,8 +448,15 @@
          */
         public static final int PROPERTY_RTT = 0x00000400;
 
+        /**
+         * Indicates that the call has been identified as the network as an emergency call. This
+         * property may be set for both incoming and outgoing calls which the network identifies as
+         * emergency calls.
+         */
+        public static final int PROPERTY_NETWORK_IDENTIFIED_EMERGENCY_CALL = 0x00000800;
+
         //******************************************************************************************
-        // Next PROPERTY value: 0x00000800
+        // Next PROPERTY value: 0x00001000
         //******************************************************************************************
 
         private final String mTelecomCallId;
@@ -601,6 +622,9 @@
             if(hasProperty(properties, PROPERTY_ASSISTED_DIALING_USED)) {
                 builder.append(" PROPERTY_ASSISTED_DIALING_USED");
             }
+            if (hasProperty(properties, PROPERTY_NETWORK_IDENTIFIED_EMERGENCY_CALL)) {
+                builder.append(" PROPERTY_NETWORK_IDENTIFIED_EMERGENCY_CALL");
+            }
             builder.append("]");
             return builder.toString();
         }
diff --git a/telecomm/java/android/telecom/Connection.java b/telecomm/java/android/telecom/Connection.java
index 330db28..ee1ca5f 100644
--- a/telecomm/java/android/telecom/Connection.java
+++ b/telecomm/java/android/telecom/Connection.java
@@ -413,6 +413,13 @@
      */
     public static final int PROPERTY_ASSISTED_DIALING_USED = 1 << 9;
 
+    /**
+     * Set by the framework to indicate that the network has identified a Connection as an emergency
+     * call.
+     * @hide
+     */
+    public static final int PROPERTY_NETWORK_IDENTIFIED_EMERGENCY_CALL = 1 << 10;
+
     //**********************************************************************************************
     // Next PROPERTY value: 1<<10
     //**********************************************************************************************
@@ -586,6 +593,8 @@
      * {@link Call#EVENT_REQUEST_HANDOVER} that the handover from this {@link Connection} has
      * successfully completed.
      * @hide
+     * @deprecated Use {@link Call#handoverTo(PhoneAccountHandle, int, Bundle)} and its associated
+     * APIs instead.
      */
     public static final String EVENT_HANDOVER_COMPLETE =
             "android.telecom.event.HANDOVER_COMPLETE";
@@ -595,6 +604,8 @@
      * {@link Call#EVENT_REQUEST_HANDOVER} that the handover from this {@link Connection} has failed
      * to complete.
      * @hide
+     * @deprecated Use {@link Call#handoverTo(PhoneAccountHandle, int, Bundle)} and its associated
+     * APIs instead.
      */
     public static final String EVENT_HANDOVER_FAILED =
             "android.telecom.event.HANDOVER_FAILED";
@@ -802,6 +813,10 @@
             builder.append(isLong ? " PROPERTY_IS_RTT" : " rtt");
         }
 
+        if (can(properties, PROPERTY_NETWORK_IDENTIFIED_EMERGENCY_CALL)) {
+            builder.append(isLong ? " PROPERTY_NETWORK_IDENTIFIED_EMERGENCY_CALL" : " ecall");
+        }
+
         builder.append("]");
         return builder.toString();
     }
diff --git a/telecomm/java/android/telecom/TelecomManager.java b/telecomm/java/android/telecom/TelecomManager.java
index b747dce3..8c37a21 100644
--- a/telecomm/java/android/telecom/TelecomManager.java
+++ b/telecomm/java/android/telecom/TelecomManager.java
@@ -1884,6 +1884,27 @@
         }
     }
 
+    /**
+     * Determines if there is an ongoing emergency call.  This can be either an outgoing emergency
+     * call, as identified by the dialed number, or because a call was identified by the network
+     * as an emergency call.
+     * @return {@code true} if there is an ongoing emergency call, {@code false} otherwise.
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
+    public boolean isInEmergencyCall() {
+        try {
+            if (isServiceConnected()) {
+                return getTelecomService().isInEmergencyCall();
+            }
+        } catch (RemoteException e) {
+            Log.e(TAG, "RemoteException isInEmergencyCall: " + e);
+            return false;
+        }
+        return false;
+    }
+
     private ITelecomService getTelecomService() {
         if (mTelecomServiceOverride != null) {
             return mTelecomServiceOverride;
diff --git a/telecomm/java/com/android/internal/telecom/ITelecomService.aidl b/telecomm/java/com/android/internal/telecom/ITelecomService.aidl
index b4e7d56..38247bc 100644
--- a/telecomm/java/com/android/internal/telecom/ITelecomService.aidl
+++ b/telecomm/java/com/android/internal/telecom/ITelecomService.aidl
@@ -279,4 +279,9 @@
      * @see TelecomServiceImpl#acceptHandover
      */
     void acceptHandover(in Uri srcAddr, int videoState, in PhoneAccountHandle destAcct);
+
+    /**
+     * @see TelecomServiceImpl#isInEmergencyCall
+     */
+    boolean isInEmergencyCall();
 }
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index 2d1b6ad..d8743bc 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -2116,6 +2116,16 @@
     public static final String KEY_CALL_REDIRECTION_SERVICE_COMPONENT_NAME_STRING =
             "call_redirection_service_component_name_string";
 
+    /**
+     * Flag specifying whether to show notification(call blocking disabled) when Enhanced Call
+     * Blocking(KEY_SUPPORT_ENHANCED_CALL_BLOCKING_BOOL) is enabled and making emergency call.
+     * When true, notification is shown always.
+     * When false, notification is shown only when any setting of "Enhanced Blocked number" is
+     * enabled.
+     */
+    public static final String KEY_SHOW_CALL_BLOCKING_DISABLED_NOTIFICATION_ALWAYS_BOOL =
+            "show_call_blocking_disabled_notification_always_bool";
+
     /** The default value for every variable. */
     private final static PersistableBundle sDefaults;
 
@@ -2454,6 +2464,7 @@
                 });
         sDefaults.putString(KEY_WCDMA_DEFAULT_SIGNAL_STRENGTH_MEASUREMENT_STRING, "");
         sDefaults.putBoolean(KEY_CONFIG_SHOW_ORIG_DIAL_STRING_FOR_CDMA_BOOL, false);
+        sDefaults.putBoolean(KEY_SHOW_CALL_BLOCKING_DISABLED_NOTIFICATION_ALWAYS_BOOL, false);
     }
 
     /**
diff --git a/telephony/java/android/telephony/MbmsGroupCallSession.java b/telephony/java/android/telephony/MbmsGroupCallSession.java
new file mode 100644
index 0000000..e373797
--- /dev/null
+++ b/telephony/java/android/telephony/MbmsGroupCallSession.java
@@ -0,0 +1,300 @@
+/*
+ * Copyright (C) 2018 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 android.telephony;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SdkConstant;
+import android.annotation.SystemApi;
+import android.annotation.TestApi;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.ServiceConnection;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.telephony.mbms.GroupCall;
+import android.telephony.mbms.GroupCallCallback;
+import android.telephony.mbms.InternalGroupCallCallback;
+import android.telephony.mbms.InternalGroupCallSessionCallback;
+import android.telephony.mbms.MbmsErrors;
+import android.telephony.mbms.MbmsGroupCallSessionCallback;
+import android.telephony.mbms.MbmsUtils;
+import android.telephony.mbms.vendor.IMbmsGroupCallService;
+import android.util.ArraySet;
+import android.util.Log;
+
+import java.util.Set;
+import java.util.concurrent.Executor;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicReference;
+
+/**
+ * This class provides functionality for accessing group call functionality over MBMS.
+ */
+public class MbmsGroupCallSession implements AutoCloseable {
+    private static final String LOG_TAG = "MbmsGroupCallSession";
+
+    /**
+     * Service action which must be handled by the middleware implementing the MBMS group call
+     * interface.
+     * @hide
+     */
+    @SystemApi
+    @SdkConstant(SdkConstant.SdkConstantType.SERVICE_ACTION)
+    public static final String MBMS_GROUP_CALL_SERVICE_ACTION =
+            "android.telephony.action.EmbmsGroupCall";
+
+    /**
+     * Metadata key that specifies the component name of the service to bind to for group calls.
+     * @hide
+     */
+    @TestApi
+    public static final String MBMS_GROUP_CALL_SERVICE_OVERRIDE_METADATA =
+            "mbms-group-call-service-override";
+
+    private static AtomicBoolean sIsInitialized = new AtomicBoolean(false);
+
+    private AtomicReference<IMbmsGroupCallService> mService = new AtomicReference<>(null);
+    private IBinder.DeathRecipient mDeathRecipient = new IBinder.DeathRecipient() {
+        @Override
+        public void binderDied() {
+            sIsInitialized.set(false);
+            mInternalCallback.onError(MbmsErrors.ERROR_MIDDLEWARE_LOST,
+                    "Received death notification");
+        }
+    };
+
+    private InternalGroupCallSessionCallback mInternalCallback;
+    private Set<GroupCall> mKnownActiveGroupCalls = new ArraySet<>();
+
+    private final Context mContext;
+    private int mSubscriptionId;
+
+    /** @hide */
+    private MbmsGroupCallSession(Context context, Executor executor, int subscriptionId,
+            MbmsGroupCallSessionCallback callback) {
+        mContext = context;
+        mSubscriptionId = subscriptionId;
+        mInternalCallback = new InternalGroupCallSessionCallback(callback, executor);
+    }
+
+    /**
+     * Create a new {@link MbmsGroupCallSession} using the given subscription ID.
+     *
+     * You may only have one instance of {@link MbmsGroupCallSession} per UID. If you call this
+     * method while there is an active instance of {@link MbmsGroupCallSession} in your process
+     * (in other words, one that has not had {@link #close()} called on it), this method will
+     * throw an {@link IllegalStateException}. If you call this method in a different process
+     * running under the same UID, an error will be indicated via
+     * {@link MbmsGroupCallSessionCallback#onError(int, String)}.
+     *
+     * Note that initialization may fail asynchronously. If you wish to try again after you
+     * receive such an asynchronous error, you must call {@link #close()} on the instance of
+     * {@link MbmsGroupCallSession} that you received before calling this method again.
+     *
+     * @param context The {@link Context} to use.
+     * @param executor The executor on which you wish to execute callbacks.
+     * @param subscriptionId The subscription ID to use.
+     * @param callback A callback object on which you wish to receive results of asynchronous
+     *                 operations.
+     * @return An instance of {@link MbmsGroupCallSession}, or null if an error occurred.
+     */
+    public static @Nullable MbmsGroupCallSession create(@NonNull Context context,
+            @NonNull Executor executor, int subscriptionId,
+            final @NonNull MbmsGroupCallSessionCallback callback) {
+        if (!sIsInitialized.compareAndSet(false, true)) {
+            throw new IllegalStateException("Cannot create two instances of MbmsGroupCallSession");
+        }
+        MbmsGroupCallSession session = new MbmsGroupCallSession(context, executor,
+                subscriptionId, callback);
+
+        final int result = session.bindAndInitialize();
+        if (result != MbmsErrors.SUCCESS) {
+            sIsInitialized.set(false);
+            executor.execute(new Runnable() {
+                @Override
+                public void run() {
+                    callback.onError(result, null);
+                }
+            });
+            return null;
+        }
+        return session;
+    }
+
+    /**
+     * Create a new {@link MbmsGroupCallSession} using the system default data subscription ID.
+     * See {@link #create(Context, Executor, int, MbmsGroupCallSessionCallback)}.
+     */
+    public static MbmsGroupCallSession create(@NonNull Context context,
+            @NonNull Executor executor, @NonNull MbmsGroupCallSessionCallback callback) {
+        return create(context, executor, SubscriptionManager.getDefaultSubscriptionId(), callback);
+    }
+
+    /**
+     * Terminates this instance. Also terminates
+     * any group calls spawned from this instance as if
+     * {@link GroupCall#close()} had been called on them. After this method returns,
+     * no further callbacks originating from the middleware will be enqueued on the provided
+     * instance of {@link MbmsGroupCallSessionCallback}, but callbacks that have already been
+     * enqueued will still be delivered.
+     *
+     * It is safe to call {@link #create(Context, Executor, int, MbmsGroupCallSessionCallback)} to
+     * obtain another instance of {@link MbmsGroupCallSession} immediately after this method
+     * returns.
+     *
+     * May throw an {@link IllegalStateException}
+     */
+    public void close() {
+        try {
+            IMbmsGroupCallService groupCallService = mService.get();
+            if (groupCallService == null) {
+                // Ignore and return, assume already disposed.
+                return;
+            }
+            groupCallService.dispose(mSubscriptionId);
+            for (GroupCall s : mKnownActiveGroupCalls) {
+                s.getCallback().stop();
+            }
+            mKnownActiveGroupCalls.clear();
+        } catch (RemoteException e) {
+            // Ignore for now
+        } finally {
+            mService.set(null);
+            sIsInitialized.set(false);
+            mInternalCallback.stop();
+        }
+    }
+
+    /**
+     * Starts the requested group call, reporting status to the indicated callback.
+     * Returns an object used to control that call.
+     *
+     * May throw an {@link IllegalArgumentException} or an {@link IllegalStateException}
+     *
+     * Asynchronous errors through the callback include any of the errors in
+     * {@link MbmsErrors.GeneralErrors}.
+     *
+     * @param executor The executor on which you wish to execute callbacks for this stream.
+     * @param tmgi The TMGI, an identifier for the group call you want to join.
+     * @param saiArray An array of SAIs for the group call that should be negotiated separately with
+     *                the carrier.
+     * @param frequencyArray An array of frequencies for the group call that should be negotiated
+     *                separately with the carrier.
+     * @param callback The callback that you want to receive information about the call on.
+     * @return An instance of {@link GroupCall} through which the call can be controlled.
+     *         May be {@code null} if an error occurred.
+     */
+    public @Nullable GroupCall startGroupCall(@NonNull Executor executor, long tmgi, int[] saiArray,
+            int[] frequencyArray, @NonNull GroupCallCallback callback) {
+        IMbmsGroupCallService groupCallService = mService.get();
+        if (groupCallService == null) {
+            throw new IllegalStateException("Middleware not yet bound");
+        }
+
+        InternalGroupCallCallback serviceCallback = new InternalGroupCallCallback(
+                callback, executor);
+
+        GroupCall serviceForApp = new GroupCall(mSubscriptionId,
+                groupCallService, this, tmgi, serviceCallback);
+        mKnownActiveGroupCalls.add(serviceForApp);
+
+        try {
+            int returnCode = groupCallService.startGroupCall(
+                    mSubscriptionId, tmgi, saiArray, frequencyArray, serviceCallback);
+            if (returnCode == MbmsErrors.UNKNOWN) {
+                // Unbind and throw an obvious error
+                close();
+                throw new IllegalStateException("Middleware must not return an unknown error code");
+            }
+            if (returnCode != MbmsErrors.SUCCESS) {
+                mInternalCallback.onError(returnCode, null);
+                return null;
+            }
+        } catch (RemoteException e) {
+            Log.w(LOG_TAG, "Remote process died");
+            mService.set(null);
+            sIsInitialized.set(false);
+            mInternalCallback.onError(MbmsErrors.ERROR_MIDDLEWARE_LOST, null);
+            return null;
+        }
+
+        return serviceForApp;
+    }
+
+    /** @hide */
+    public void onGroupCallStopped(GroupCall service) {
+        mKnownActiveGroupCalls.remove(service);
+    }
+
+    private int bindAndInitialize() {
+        return MbmsUtils.startBinding(mContext, MBMS_GROUP_CALL_SERVICE_ACTION,
+                new ServiceConnection() {
+                    @Override
+                    public void onServiceConnected(ComponentName name, IBinder service) {
+                        IMbmsGroupCallService groupCallService =
+                                IMbmsGroupCallService.Stub.asInterface(service);
+                        int result;
+                        try {
+                            result = groupCallService.initialize(mInternalCallback,
+                                    mSubscriptionId);
+                        } catch (RemoteException e) {
+                            Log.e(LOG_TAG, "Service died before initialization");
+                            mInternalCallback.onError(
+                                    MbmsErrors.InitializationErrors.ERROR_UNABLE_TO_INITIALIZE,
+                                    e.toString());
+                            sIsInitialized.set(false);
+                            return;
+                        } catch (RuntimeException e) {
+                            Log.e(LOG_TAG, "Runtime exception during initialization");
+                            mInternalCallback.onError(
+                                    MbmsErrors.InitializationErrors.ERROR_UNABLE_TO_INITIALIZE,
+                                    e.toString());
+                            sIsInitialized.set(false);
+                            return;
+                        }
+                        if (result == MbmsErrors.UNKNOWN) {
+                            // Unbind and throw an obvious error
+                            close();
+                            throw new IllegalStateException("Middleware must not return"
+                                    + " an unknown error code");
+                        }
+                        if (result != MbmsErrors.SUCCESS) {
+                            mInternalCallback.onError(result,
+                                    "Error returned during initialization");
+                            sIsInitialized.set(false);
+                            return;
+                        }
+                        try {
+                            groupCallService.asBinder().linkToDeath(mDeathRecipient, 0);
+                        } catch (RemoteException e) {
+                            mInternalCallback.onError(MbmsErrors.ERROR_MIDDLEWARE_LOST,
+                                    "Middleware lost during initialization");
+                            sIsInitialized.set(false);
+                            return;
+                        }
+                        mService.set(groupCallService);
+                    }
+
+                    @Override
+                    public void onServiceDisconnected(ComponentName name) {
+                        sIsInitialized.set(false);
+                        mService.set(null);
+                    }
+                });
+    }
+}
diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java
index 8f7993c..3ef80c2 100644
--- a/telephony/java/android/telephony/SubscriptionManager.java
+++ b/telephony/java/android/telephony/SubscriptionManager.java
@@ -1847,6 +1847,19 @@
     }
 
     /**
+     * Checks if the supplied subscription ID corresponds to an active subscription.
+     *
+     * @param subscriptionId the subscription ID.
+     * @return {@code true} if the supplied subscription ID corresponds to an active subscription;
+     * {@code false} if it does not correspond to an active subscription; or throw a
+     * SecurityException if the caller hasn't got the right permission.
+     */
+    @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
+    public boolean isActiveSubscriptionId(int subscriptionId) {
+        return isActiveSubId(subscriptionId);
+    }
+
+    /**
      * @return true if the sub ID is active. i.e. The sub ID corresponds to a known subscription
      * and the SIM providing the subscription is present in a slot and in "LOADED" state.
      * @hide
@@ -1856,7 +1869,7 @@
         try {
             ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
             if (iSub != null) {
-                return iSub.isActiveSubId(subId);
+                return iSub.isActiveSubId(subId, mContext.getOpPackageName());
             }
         } catch (RemoteException ex) {
         }
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index b73a42b..fe65514 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -2091,10 +2091,37 @@
 
     /** Max network type number. Update as new types are added. Don't add negative types. {@hide} */
     public static final int MAX_NETWORK_TYPE = NETWORK_TYPE_LTE_CA;
+
+    /** @hide */
+    @IntDef({
+            NETWORK_TYPE_UNKNOWN,
+            NETWORK_TYPE_GPRS,
+            NETWORK_TYPE_EDGE,
+            NETWORK_TYPE_UMTS,
+            NETWORK_TYPE_CDMA,
+            NETWORK_TYPE_EVDO_0,
+            NETWORK_TYPE_EVDO_A,
+            NETWORK_TYPE_1xRTT,
+            NETWORK_TYPE_HSDPA,
+            NETWORK_TYPE_HSUPA,
+            NETWORK_TYPE_HSPA,
+            NETWORK_TYPE_IDEN,
+            NETWORK_TYPE_EVDO_B,
+            NETWORK_TYPE_LTE,
+            NETWORK_TYPE_EHRPD,
+            NETWORK_TYPE_HSPAP,
+            NETWORK_TYPE_GSM,
+            NETWORK_TYPE_TD_SCDMA,
+            NETWORK_TYPE_IWLAN,
+            NETWORK_TYPE_LTE_CA,
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface NetworkType{}
+
     /**
      * @return the NETWORK_TYPE_xxxx for current data connection.
      */
-    public int getNetworkType() {
+    public @NetworkType int getNetworkType() {
        try {
            ITelephony telephony = getITelephony();
            if (telephony != null) {
@@ -2139,24 +2166,24 @@
      * @hide
      */
     @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
-   @UnsupportedAppUsage
-   public int getNetworkType(int subId) {
-       try {
-           ITelephony telephony = getITelephony();
-           if (telephony != null) {
-               return telephony.getNetworkTypeForSubscriber(subId, getOpPackageName());
-           } else {
-               // This can happen when the ITelephony interface is not up yet.
-               return NETWORK_TYPE_UNKNOWN;
-           }
-       } catch(RemoteException ex) {
-           // This shouldn't happen in the normal case
-           return NETWORK_TYPE_UNKNOWN;
-       } catch (NullPointerException ex) {
-           // This could happen before phone restarts due to crashing
-           return NETWORK_TYPE_UNKNOWN;
-       }
-   }
+    @UnsupportedAppUsage
+    public int getNetworkType(int subId) {
+        try {
+            ITelephony telephony = getITelephony();
+            if (telephony != null) {
+                return telephony.getNetworkTypeForSubscriber(subId, getOpPackageName());
+            } else {
+                // This can happen when the ITelephony interface is not up yet.
+                return NETWORK_TYPE_UNKNOWN;
+            }
+        } catch (RemoteException ex) {
+            // This shouldn't happen in the normal case
+            return NETWORK_TYPE_UNKNOWN;
+        } catch (NullPointerException ex) {
+            // This could happen before phone restarts due to crashing
+            return NETWORK_TYPE_UNKNOWN;
+        }
+    }
 
     /**
      * Returns a constant indicating the radio technology (network type)
@@ -2189,7 +2216,7 @@
      */
     @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges
     @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
-    public int getDataNetworkType() {
+    public @NetworkType int getDataNetworkType() {
         return getDataNetworkType(getSubId(SubscriptionManager.getDefaultDataSubscriptionId()));
     }
 
@@ -2229,7 +2256,7 @@
      */
     @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges
     @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
-    public int getVoiceNetworkType() {
+    public @NetworkType int getVoiceNetworkType() {
         return getVoiceNetworkType(getSubId());
     }
 
@@ -4141,11 +4168,16 @@
     }
 
     /**
-     * Returns the IMS home network domain name that was loaded from the ISIM.
-     * @return the IMS domain name, or null if not present or not loaded
+     * Returns the IMS home network domain name that was loaded from the ISIM {@see #APPTYPE_ISIM}.
+     * @return the IMS domain name. Returns {@code null} if ISIM hasn't been loaded or IMS domain
+     * hasn't been loaded or isn't present on the ISIM.
+     *
+     * <p>Requires Permission:
+     * {@link android.Manifest.permission#READ_PRIVILEGED_PHONE_STATE READ_PRIVILEGED_PHONE_STATE}
      * @hide
      */
-    @UnsupportedAppUsage
+    @SystemApi
+    @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
     public String getIsimDomain() {
         try {
             IPhoneSubInfo info = getSubscriberInfo();
@@ -5399,7 +5431,19 @@
         }
     }
 
-    // ICC SIM Application Types
+    /**
+     * UICC SIM Application Types
+     * @hide
+     */
+    @IntDef(prefix = { "APPTYPE_" }, value = {
+            APPTYPE_SIM,
+            APPTYPE_USIM,
+            APPTYPE_RUIM,
+            APPTYPE_CSIM,
+            APPTYPE_ISIM
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface UiccAppType{}
     /** UICC application type is SIM */
     public static final int APPTYPE_SIM = PhoneConstants.APPTYPE_SIM;
     /** UICC application type is USIM */
@@ -5410,6 +5454,7 @@
     public static final int APPTYPE_CSIM = PhoneConstants.APPTYPE_CSIM;
     /** UICC application type is ISIM */
     public static final int APPTYPE_ISIM = PhoneConstants.APPTYPE_ISIM;
+
     // authContext (parameter P2) when doing UICC challenge,
     // per 3GPP TS 31.102 (Section 7.1.2)
     /** Authentication type for UICC challenge is EAP SIM. See RFC 4186 for details. */
@@ -7845,26 +7890,23 @@
     }
 
     /**
-     * Return the application ID for the app type like {@link APPTYPE_CSIM}.
+     * Return the application ID for the uicc application type like {@link #APPTYPE_CSIM}.
+     * All uicc applications are uniquely identified by application ID. See ETSI 102.221 and 101.220
+     * <p>Requires Permission:
+     *   {@link android.Manifest.permission#READ_PRIVILEGED_PHONE_STATE}
      *
-     * Requires that the calling app has READ_PRIVILEGED_PHONE_STATE permission
-     *
-     * @param appType the uicc app type like {@link APPTYPE_CSIM}
-     * @return Application ID for specificied app type or null if no uicc or error.
+     * @param appType the uicc app type.
+     * @return Application ID for specified app type or {@code null} if no uicc or error.
      * @hide
      */
-    public String getAidForAppType(int appType) {
+    @SystemApi
+    @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+    public String getAidForAppType(@UiccAppType int appType) {
         return getAidForAppType(getSubId(), appType);
     }
 
     /**
-     * Return the application ID for the app type like {@link APPTYPE_CSIM}.
-     *
-     * Requires that the calling app has READ_PRIVILEGED_PHONE_STATE permission
-     *
-     * @param subId the subscription ID that this request applies to.
-     * @param appType the uicc app type, like {@link APPTYPE_CSIM}
-     * @return Application ID for specificied app type or null if no uicc or error.
+     * same as {@link #getAidForAppType(int)}
      * @hide
      */
     public String getAidForAppType(int subId, int appType) {
diff --git a/telephony/java/android/telephony/ims/ImsCallProfile.java b/telephony/java/android/telephony/ims/ImsCallProfile.java
index df7bd3e..5d6a8c1 100644
--- a/telephony/java/android/telephony/ims/ImsCallProfile.java
+++ b/telephony/java/android/telephony/ims/ImsCallProfile.java
@@ -118,7 +118,9 @@
      */
     public static final String EXTRA_CONFERENCE = "conference";
     /**
-     * @hide
+     * Boolean extra property set on an {@link ImsCallProfile} to indicate that this call is an
+     * emergency call.  The {@link ImsService} sets this on a call to indicate that the network has
+     * identified the call as an emergency call.
      */
     public static final String EXTRA_E_CALL = "e_call";
     /**
diff --git a/telephony/java/android/telephony/mbms/GroupCall.java b/telephony/java/android/telephony/mbms/GroupCall.java
new file mode 100644
index 0000000..9aca18e
--- /dev/null
+++ b/telephony/java/android/telephony/mbms/GroupCall.java
@@ -0,0 +1,176 @@
+/*
+ * Copyright (C) 2018 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 android.telephony.mbms;
+
+import android.annotation.IntDef;
+import android.os.RemoteException;
+import android.telephony.MbmsGroupCallSession;
+import android.telephony.mbms.vendor.IMbmsGroupCallService;
+import android.util.Log;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Class used to represent a single MBMS group call. After a call has been started with
+ * {@link MbmsGroupCallSession#startGroupCall},
+ * this class is used to hold information about the call and control it.
+ */
+public class GroupCall implements AutoCloseable {
+    private static final String LOG_TAG = "MbmsGroupCall";
+
+    /**
+     * The state of a group call, reported via
+     * {@link GroupCallCallback#onGroupCallStateChanged(int, int)}
+     * @hide
+     */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(prefix = { "STATE_" }, value = {STATE_STOPPED, STATE_STARTED, STATE_STALLED})
+    public @interface GroupCallState {}
+    public static final int STATE_STOPPED = 1;
+    public static final int STATE_STARTED = 2;
+    public static final int STATE_STALLED = 3;
+
+    /**
+     * The reason for a call state change, reported via
+     * {@link GroupCallCallback#onGroupCallStateChanged(int, int)}
+     * @hide
+     */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(prefix = { "REASON_" },
+            value = {REASON_BY_USER_REQUEST, REASON_FREQUENCY_CONFLICT,
+                    REASON_OUT_OF_MEMORY, REASON_NOT_CONNECTED_TO_HOMECARRIER_LTE,
+                    REASON_LEFT_MBMS_BROADCAST_AREA, REASON_NONE})
+    public @interface GroupCallStateChangeReason {}
+
+    /**
+     * Indicates that the middleware does not have a reason to provide for the state change.
+     */
+    public static final int REASON_NONE = 0;
+
+    /**
+     * State changed due to a call to {@link #close()} or
+     * {@link MbmsGroupCallSession#startGroupCall}
+     */
+    public static final int REASON_BY_USER_REQUEST = 1;
+
+    // 2 is unused to match up with streaming.
+
+    /**
+     * State changed due to a frequency conflict with another requested call.
+     */
+    public static final int REASON_FREQUENCY_CONFLICT = 3;
+
+    /**
+     * State changed due to the middleware running out of memory
+     */
+    public static final int REASON_OUT_OF_MEMORY = 4;
+
+    /**
+     * State changed due to the device leaving the home carrier's LTE network.
+     */
+    public static final int REASON_NOT_CONNECTED_TO_HOMECARRIER_LTE = 5;
+
+    /**
+     * State changed due to the device leaving the area where this call is being broadcast.
+     */
+    public static final int REASON_LEFT_MBMS_BROADCAST_AREA = 6;
+
+    private final int mSubscriptionId;
+    private final long mTmgi;
+    private final MbmsGroupCallSession mParentSession;
+    private final InternalGroupCallCallback mCallback;
+    private IMbmsGroupCallService mService;
+
+    /**
+     * @hide
+     */
+    public GroupCall(int subscriptionId,
+            IMbmsGroupCallService service,
+            MbmsGroupCallSession session,
+            long tmgi,
+            InternalGroupCallCallback callback) {
+        mSubscriptionId = subscriptionId;
+        mParentSession = session;
+        mService = service;
+        mTmgi = tmgi;
+        mCallback = callback;
+    }
+
+    /**
+     * Retrieve the TMGI (Temporary Mobile Group Identity) corresponding to this call.
+     */
+    public long getTmgi() {
+        return mTmgi;
+    }
+
+    /**
+     * Send an update to the middleware when the SAI (Service Area Identifier) list and frequency
+     * information of the group call has * changed. Callers must obtain this information from the
+     * wireless carrier independently.
+     * @param saiArray New array of SAIs that the call is available on.
+     * @param frequencyArray New array of frequencies that the call is available on.
+     */
+    public void updateGroupCall(int[] saiArray, int[] frequencyArray) {
+        if (mService == null) {
+            throw new IllegalStateException("No group call service attached");
+        }
+
+        try {
+            mService.updateGroupCall(mSubscriptionId, mTmgi, saiArray, frequencyArray);
+        } catch (RemoteException e) {
+            Log.w(LOG_TAG, "Remote process died");
+            mService = null;
+            sendErrorToApp(MbmsErrors.ERROR_MIDDLEWARE_LOST, null);
+        } finally {
+            mParentSession.onGroupCallStopped(this);
+        }
+    }
+
+    /**
+     * Stop this group call. Further operations on this object will fail with an
+     * {@link IllegalStateException}.
+     *
+     * May throw an {@link IllegalStateException}
+     */
+    @Override
+    public void close() {
+        if (mService == null) {
+            throw new IllegalStateException("No group call service attached");
+        }
+
+        try {
+            mService.stopGroupCall(mSubscriptionId, mTmgi);
+        } catch (RemoteException e) {
+            Log.w(LOG_TAG, "Remote process died");
+            mService = null;
+            sendErrorToApp(MbmsErrors.ERROR_MIDDLEWARE_LOST, null);
+        } finally {
+            mParentSession.onGroupCallStopped(this);
+        }
+    }
+
+    /** @hide */
+    public InternalGroupCallCallback getCallback() {
+        return mCallback;
+    }
+
+    private void sendErrorToApp(int errorCode, String message) {
+        mCallback.onError(errorCode, message);
+    }
+}
+
diff --git a/telephony/java/android/telephony/mbms/GroupCallCallback.java b/telephony/java/android/telephony/mbms/GroupCallCallback.java
new file mode 100644
index 0000000..001bb02
--- /dev/null
+++ b/telephony/java/android/telephony/mbms/GroupCallCallback.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2018 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 android.telephony.mbms;
+
+import android.annotation.IntDef;
+import android.annotation.Nullable;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * A callback class for use when the application is in a group call. The middleware
+ * will provide updates on the status of the call via this callback.
+ */
+public class GroupCallCallback {
+    /** @hide */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(value = {
+            MbmsErrors.ERROR_NO_UNIQUE_MIDDLEWARE,
+            MbmsErrors.ERROR_MIDDLEWARE_LOST,
+            MbmsErrors.ERROR_MIDDLEWARE_NOT_BOUND,
+            MbmsErrors.GeneralErrors.ERROR_MIDDLEWARE_NOT_YET_READY,
+            MbmsErrors.GeneralErrors.ERROR_OUT_OF_MEMORY,
+            MbmsErrors.GeneralErrors.ERROR_MIDDLEWARE_TEMPORARILY_UNAVAILABLE,
+            MbmsErrors.GeneralErrors.ERROR_IN_E911,
+            MbmsErrors.GeneralErrors.ERROR_NOT_CONNECTED_TO_HOME_CARRIER_LTE,
+            MbmsErrors.GeneralErrors.ERROR_UNABLE_TO_READ_SIM,
+            MbmsErrors.GeneralErrors.ERROR_CARRIER_CHANGE_NOT_ALLOWED}, prefix = { "ERROR_" })
+    private @interface GroupCallError{}
+
+    /**
+     * Indicates broadcast signal strength is not available for this call.
+     *
+     * This may be due to the call no longer being available due to geography
+     * or timing (end of service)
+     */
+    public static final int SIGNAL_STRENGTH_UNAVAILABLE = -1;
+
+    /**
+     * Called by the middleware when it has detected an error condition in this group call. The
+     * possible error codes are listed in {@link MbmsErrors}.
+     * @param errorCode The error code.
+     * @param message A human-readable message generated by the middleware for debugging purposes.
+     */
+    public void onError(@GroupCallError int errorCode, @Nullable String message) {
+        // default implementation empty
+    }
+
+    /**
+     * Called to indicate this call has changed state.
+     *
+     * See {@link GroupCall#STATE_STOPPED}, {@link GroupCall#STATE_STARTED}
+     * and {@link GroupCall#STATE_STALLED}.
+     */
+    public void onGroupCallStateChanged(@GroupCall.GroupCallState int state,
+            @GroupCall.GroupCallStateChangeReason int reason) {
+        // default implementation empty
+    }
+
+    /**
+     * Broadcast Signal Strength updated.
+     *
+     * This signal strength is the BROADCAST signal strength which,
+     * depending on technology in play and it's deployment, may be
+     * stronger or weaker than the traditional UNICAST signal
+     * strength.  It a simple int from 0-4 for valid levels or
+     * {@link #SIGNAL_STRENGTH_UNAVAILABLE} if broadcast is not available
+     * for this call due to timing, geography or popularity.
+     */
+    public void onBroadcastSignalStrengthUpdated(int signalStrength) {
+        // default implementation empty
+    }
+}
diff --git a/telephony/java/android/telephony/mbms/IGroupCallCallback.aidl b/telephony/java/android/telephony/mbms/IGroupCallCallback.aidl
new file mode 100755
index 0000000..844b634
--- /dev/null
+++ b/telephony/java/android/telephony/mbms/IGroupCallCallback.aidl
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2018 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 android.telephony.mbms;
+
+/**
+ * @hide
+ */
+oneway interface IGroupCallCallback {
+    void onError(int errorCode, String message);
+    void onGroupCallStateChanged(int state, int reason);
+    void onBroadcastSignalStrengthUpdated(int signalStrength);
+}
diff --git a/telephony/java/android/telephony/mbms/IMbmsGroupCallSessionCallback.aidl b/telephony/java/android/telephony/mbms/IMbmsGroupCallSessionCallback.aidl
new file mode 100755
index 0000000..1a1c7f8
--- /dev/null
+++ b/telephony/java/android/telephony/mbms/IMbmsGroupCallSessionCallback.aidl
@@ -0,0 +1,33 @@
+/*
+** Copyright 2018, 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 android.telephony.mbms;
+
+import java.util.List;
+
+/**
+ * @hide
+ */
+oneway interface IMbmsGroupCallSessionCallback
+{
+    void onError(int errorCode, String message);
+
+    void onAvailableSaisUpdated(in List currentSai, in List availableSais);
+
+    void onServiceInterfaceAvailable(String interfaceName, int index);
+
+    void onMiddlewareReady();
+}
diff --git a/telephony/java/android/telephony/mbms/InternalGroupCallCallback.java b/telephony/java/android/telephony/mbms/InternalGroupCallCallback.java
new file mode 100644
index 0000000..2910bb3
--- /dev/null
+++ b/telephony/java/android/telephony/mbms/InternalGroupCallCallback.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2018 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 android.telephony.mbms;
+
+import android.os.Binder;
+
+import java.util.concurrent.Executor;
+
+/** @hide */
+public class InternalGroupCallCallback extends IGroupCallCallback.Stub {
+    private final GroupCallCallback mAppCallback;
+    private final Executor mExecutor;
+    private volatile boolean mIsStopped = false;
+
+    public InternalGroupCallCallback(GroupCallCallback appCallback,
+            Executor executor) {
+        mAppCallback = appCallback;
+        mExecutor = executor;
+    }
+
+    @Override
+    public void onError(final int errorCode, final String message) {
+        if (mIsStopped) {
+            return;
+        }
+
+        mExecutor.execute(new Runnable() {
+            @Override
+            public void run() {
+                long token = Binder.clearCallingIdentity();
+                try {
+                    mAppCallback.onError(errorCode, message);
+                } finally {
+                    Binder.restoreCallingIdentity(token);
+                }
+            }
+        });
+    }
+
+    @Override
+    public void onGroupCallStateChanged(final int state, final int reason) {
+        if (mIsStopped) {
+            return;
+        }
+
+        mExecutor.execute(new Runnable() {
+            @Override
+            public void run() {
+                long token = Binder.clearCallingIdentity();
+                try {
+                    mAppCallback.onGroupCallStateChanged(state, reason);
+                } finally {
+                    Binder.restoreCallingIdentity(token);
+                }
+            }
+        });
+    }
+
+    @Override
+    public void onBroadcastSignalStrengthUpdated(final int signalStrength) {
+        if (mIsStopped) {
+            return;
+        }
+
+        mExecutor.execute(new Runnable() {
+            @Override
+            public void run() {
+                long token = Binder.clearCallingIdentity();
+                try {
+                    mAppCallback.onBroadcastSignalStrengthUpdated(signalStrength);
+                } finally {
+                    Binder.restoreCallingIdentity(token);
+                }
+            }
+        });
+    }
+
+    /** Prevents this callback from calling the app */
+    public void stop() {
+        mIsStopped = true;
+    }
+}
diff --git a/telephony/java/android/telephony/mbms/InternalGroupCallSessionCallback.java b/telephony/java/android/telephony/mbms/InternalGroupCallSessionCallback.java
new file mode 100644
index 0000000..4c9cf4d
--- /dev/null
+++ b/telephony/java/android/telephony/mbms/InternalGroupCallSessionCallback.java
@@ -0,0 +1,116 @@
+/*
+ * Copyright (C) 2018 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 android.telephony.mbms;
+
+import android.os.Binder;
+
+import java.util.List;
+import java.util.concurrent.Executor;
+
+/** @hide */
+public class InternalGroupCallSessionCallback extends IMbmsGroupCallSessionCallback.Stub {
+    private final Executor mExecutor;
+    private final MbmsGroupCallSessionCallback mAppCallback;
+    private volatile boolean mIsStopped = false;
+
+    public InternalGroupCallSessionCallback(MbmsGroupCallSessionCallback appCallback,
+            Executor executor) {
+        mAppCallback = appCallback;
+        mExecutor = executor;
+    }
+
+    @Override
+    public void onError(final int errorCode, final String message) {
+        if (mIsStopped) {
+            return;
+        }
+
+        mExecutor.execute(new Runnable() {
+            @Override
+            public void run() {
+                long token = Binder.clearCallingIdentity();
+                try {
+                    mAppCallback.onError(errorCode, message);
+                } finally {
+                    Binder.restoreCallingIdentity(token);
+                }
+            }
+        });
+    }
+
+    @Override
+    public void onAvailableSaisUpdated(final List currentSais, final List availableSais) {
+        if (mIsStopped) {
+            return;
+        }
+
+        mExecutor.execute(new Runnable() {
+            @Override
+            public void run() {
+                long token = Binder.clearCallingIdentity();
+                try {
+                    mAppCallback.onAvailableSaisUpdated(currentSais, availableSais);
+                } finally {
+                    Binder.restoreCallingIdentity(token);
+                }
+            }
+        });
+    }
+
+    @Override
+    public void onServiceInterfaceAvailable(final String interfaceName, final int index) {
+        if (mIsStopped) {
+            return;
+        }
+
+        mExecutor.execute(new Runnable() {
+            @Override
+            public void run() {
+                long token = Binder.clearCallingIdentity();
+                try {
+                    mAppCallback.onServiceInterfaceAvailable(interfaceName, index);
+                } finally {
+                    Binder.restoreCallingIdentity(token);
+                }
+            }
+        });
+    }
+
+    @Override
+    public void onMiddlewareReady() {
+        if (mIsStopped) {
+            return;
+        }
+
+        mExecutor.execute(new Runnable() {
+            @Override
+            public void run() {
+                long token = Binder.clearCallingIdentity();
+                try {
+                    mAppCallback.onMiddlewareReady();
+                } finally {
+                    Binder.restoreCallingIdentity(token);
+                }
+            }
+        });
+    }
+
+    /** Prevents this callback from calling the app */
+    public void stop() {
+        mIsStopped = true;
+    }
+}
diff --git a/telephony/java/android/telephony/mbms/MbmsGroupCallSessionCallback.java b/telephony/java/android/telephony/mbms/MbmsGroupCallSessionCallback.java
new file mode 100644
index 0000000..7da734e
--- /dev/null
+++ b/telephony/java/android/telephony/mbms/MbmsGroupCallSessionCallback.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2018 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 android.telephony.mbms;
+
+import android.annotation.IntDef;
+import android.annotation.Nullable;
+import android.content.Context;
+import android.telephony.MbmsGroupCallSession;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.List;
+import java.util.concurrent.Executor;
+
+/**
+ * A callback class that is used to receive information from the middleware on MBMS group-call
+ * services. An instance of this object should be passed into
+ * {@link MbmsGroupCallSession#create(Context, Executor, int, MbmsGroupCallSessionCallback)}.
+ */
+public class MbmsGroupCallSessionCallback {
+    /** @hide */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(value = {
+            MbmsErrors.ERROR_NO_UNIQUE_MIDDLEWARE,
+            MbmsErrors.ERROR_MIDDLEWARE_LOST,
+            MbmsErrors.ERROR_MIDDLEWARE_NOT_BOUND,
+            MbmsErrors.InitializationErrors.ERROR_APP_PERMISSIONS_NOT_GRANTED,
+            MbmsErrors.InitializationErrors.ERROR_DUPLICATE_INITIALIZE,
+            MbmsErrors.InitializationErrors.ERROR_UNABLE_TO_INITIALIZE,
+            MbmsErrors.GeneralErrors.ERROR_MIDDLEWARE_NOT_YET_READY,
+            MbmsErrors.GeneralErrors.ERROR_OUT_OF_MEMORY,
+            MbmsErrors.GeneralErrors.ERROR_MIDDLEWARE_TEMPORARILY_UNAVAILABLE,
+            MbmsErrors.GeneralErrors.ERROR_IN_E911,
+            MbmsErrors.GeneralErrors.ERROR_NOT_CONNECTED_TO_HOME_CARRIER_LTE,
+            MbmsErrors.GeneralErrors.ERROR_UNABLE_TO_READ_SIM,
+            MbmsErrors.GeneralErrors.ERROR_CARRIER_CHANGE_NOT_ALLOWED}, prefix = { "ERROR_" })
+    private @interface GroupCallError{}
+
+    /**
+     * Called by the middleware when it has detected an error condition. The possible error codes
+     * are listed in {@link MbmsErrors}.
+     * @param errorCode The error code.
+     * @param message A human-readable message generated by the middleware for debugging purposes.
+     */
+    public void onError(@GroupCallError int errorCode, @Nullable String message) {
+    }
+
+    /**
+     * Indicates that the list of currently available SAIs has been updated. The app may use this
+     * information to filter the list of group calls when displaying available group calls to
+     * the user by matching the SAIs with a list of group calls separately negotiated with the
+     * carrier. The app may also report the aggregate list of SAIs to the group call application
+     * server so that a network entity can determine when, and where to activate the broadcast of
+     * particular group calls.
+     * @param currentSais The available SAIs on the current cell.
+     * @param availableSais A list of lists of available SAIS in neighboring cells, where each list
+     *                      contains the available SAIs in an individual cell.
+     */
+    public void onAvailableSaisUpdated(List<Integer> currentSais,
+            List<List<Integer>> availableSais) {
+    }
+
+    /**
+     * Called soon after the app calls {@link MbmsGroupCallSession#create}. The information supplied
+     * via this callback may be used to establish a data-link interface with the modem before the
+     * middleware is ready.
+     * Note that this method may be called before {@link #onMiddlewareReady()}.
+     *
+     * @param interfaceName The interface name for the data link.
+     * @param index The index for the data link.
+     */
+    public void onServiceInterfaceAvailable(String interfaceName, int index) {
+    }
+
+    /**
+     * 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 MbmsGroupCallSession} will result in an {@link IllegalStateException} or an error
+     * delivered via {@link #onError(int, String)} with error code
+     * {@link MbmsErrors.GeneralErrors#ERROR_MIDDLEWARE_NOT_YET_READY}.
+     */
+    public void onMiddlewareReady() {
+    }
+}
diff --git a/telephony/java/android/telephony/mbms/MbmsUtils.java b/telephony/java/android/telephony/mbms/MbmsUtils.java
index 06b2120..95b4d37 100644
--- a/telephony/java/android/telephony/mbms/MbmsUtils.java
+++ b/telephony/java/android/telephony/mbms/MbmsUtils.java
@@ -23,6 +23,7 @@
 import android.content.pm.*;
 import android.content.pm.ServiceInfo;
 import android.telephony.MbmsDownloadSession;
+import android.telephony.MbmsGroupCallSession;
 import android.telephony.MbmsStreamingSession;
 import android.util.Log;
 
@@ -59,6 +60,9 @@
             case MbmsStreamingSession.MBMS_STREAMING_SERVICE_ACTION:
                 metaDataKey = MbmsStreamingSession.MBMS_STREAMING_SERVICE_OVERRIDE_METADATA;
                 break;
+            case MbmsGroupCallSession.MBMS_GROUP_CALL_SERVICE_ACTION:
+                metaDataKey = MbmsGroupCallSession.MBMS_GROUP_CALL_SERVICE_OVERRIDE_METADATA;
+                break;
         }
         if (metaDataKey == null) {
             return null;
diff --git a/telephony/java/android/telephony/mbms/vendor/IMbmsGroupCallService.aidl b/telephony/java/android/telephony/mbms/vendor/IMbmsGroupCallService.aidl
new file mode 100755
index 0000000..721256a
--- /dev/null
+++ b/telephony/java/android/telephony/mbms/vendor/IMbmsGroupCallService.aidl
@@ -0,0 +1,39 @@
+/*
+** Copyright 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 android.telephony.mbms.vendor;
+
+import android.net.Uri;
+import android.telephony.mbms.IMbmsGroupCallSessionCallback;
+import android.telephony.mbms.IGroupCallCallback;
+
+/**
+ * @hide
+ */
+interface IMbmsGroupCallService
+{
+    int initialize(IMbmsGroupCallSessionCallback callback, int subId);
+
+    void stopGroupCall(int subId, long tmgi);
+
+    void updateGroupCall(int subscriptionId, long tmgi, in int[] saiArray,
+        in int[] frequencyArray);
+
+    int startGroupCall(int subscriptionId, long tmgi, in int[] saiArray,
+        in int[] frequencyArray, IGroupCallCallback callback);
+
+    void dispose(int subId);
+}
diff --git a/telephony/java/android/telephony/mbms/vendor/MbmsGroupCallServiceBase.java b/telephony/java/android/telephony/mbms/vendor/MbmsGroupCallServiceBase.java
new file mode 100644
index 0000000..3734ca7
--- /dev/null
+++ b/telephony/java/android/telephony/mbms/vendor/MbmsGroupCallServiceBase.java
@@ -0,0 +1,275 @@
+/*
+ * Copyright (C) 2018 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 android.telephony.mbms.vendor;
+
+import android.annotation.SystemApi;
+import android.annotation.TestApi;
+import android.app.Service;
+import android.content.Intent;
+import android.os.Binder;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.telephony.mbms.GroupCallCallback;
+import android.telephony.mbms.IGroupCallCallback;
+import android.telephony.mbms.IMbmsGroupCallSessionCallback;
+import android.telephony.mbms.MbmsErrors;
+import android.telephony.mbms.MbmsGroupCallSessionCallback;
+import android.telephony.mbms.vendor.IMbmsGroupCallService.Stub;
+
+import java.util.List;
+
+/**
+ * Base class for MBMS group-call services. The middleware should override this class to implement
+ * its {@link Service} for group calls
+ * Subclasses should call this class's {@link #onBind} method to obtain an {@link IBinder} if they
+ * override {@link #onBind}.
+ * @hide
+ */
+@SystemApi
+@TestApi
+public class MbmsGroupCallServiceBase extends Service {
+    private final IBinder mInterface = new Stub() {
+        @Override
+        public int initialize(final IMbmsGroupCallSessionCallback callback,
+                final int subscriptionId) throws RemoteException {
+            if (callback == null) {
+                throw new NullPointerException("Callback must not be null");
+            }
+
+            final int uid = Binder.getCallingUid();
+
+            int result = MbmsGroupCallServiceBase.this.initialize(
+                    new MbmsGroupCallSessionCallback() {
+                        @Override
+                        public void onError(final int errorCode, final String message) {
+                            try {
+                                if (errorCode == MbmsErrors.UNKNOWN) {
+                                    throw new IllegalArgumentException(
+                                            "Middleware cannot send an unknown error.");
+                                }
+                                callback.onError(errorCode, message);
+                            } catch (RemoteException e) {
+                                onAppCallbackDied(uid, subscriptionId);
+                            }
+                        }
+
+                        @Override
+                        public void onAvailableSaisUpdated(final List currentSais,
+                                final List availableSais) {
+                            try {
+                                callback.onAvailableSaisUpdated(currentSais, availableSais);
+                            } catch (RemoteException e) {
+                                onAppCallbackDied(uid, subscriptionId);
+                            }
+                        }
+
+                        @Override
+                        public void onServiceInterfaceAvailable(final String interfaceName,
+                                final int index) {
+                            try {
+                                callback.onServiceInterfaceAvailable(interfaceName, index);
+                            } catch (RemoteException e) {
+                                onAppCallbackDied(uid, subscriptionId);
+                            }
+                        }
+
+                        @Override
+                        public void onMiddlewareReady() {
+                            try {
+                                callback.onMiddlewareReady();
+                            } catch (RemoteException e) {
+                                onAppCallbackDied(uid, subscriptionId);
+                            }
+                        }
+                    }, subscriptionId);
+
+            if (result == MbmsErrors.SUCCESS) {
+                callback.asBinder().linkToDeath(new DeathRecipient() {
+                    @Override
+                    public void binderDied() {
+                        onAppCallbackDied(uid, subscriptionId);
+                    }
+                }, 0);
+            }
+
+            return result;
+        }
+
+        @Override
+        public void stopGroupCall(int subId, long tmgi) {
+            MbmsGroupCallServiceBase.this.stopGroupCall(subId, tmgi);
+        }
+
+        @Override
+        public void updateGroupCall(int subscriptionId, long tmgi, int[] saiArray,
+                int[] frequencyArray) {
+            MbmsGroupCallServiceBase.this.updateGroupCall(
+                    subscriptionId, tmgi, saiArray, frequencyArray);
+        }
+
+        @Override
+        public int startGroupCall(final int subscriptionId, final long tmgi, final int[] saiArray,
+                final int[] frequencyArray, final IGroupCallCallback callback)
+                throws RemoteException {
+            if (callback == null) {
+                throw new NullPointerException("Callback must not be null");
+            }
+
+            final int uid = Binder.getCallingUid();
+
+            int result = MbmsGroupCallServiceBase.this.startGroupCall(
+                    subscriptionId, tmgi, saiArray, frequencyArray, new GroupCallCallback() {
+                        @Override
+                        public void onError(final int errorCode, final String message) {
+                            try {
+                                if (errorCode == MbmsErrors.UNKNOWN) {
+                                    throw new IllegalArgumentException(
+                                            "Middleware cannot send an unknown error.");
+                                }
+                                callback.onError(errorCode, message);
+                            } catch (RemoteException e) {
+                                onAppCallbackDied(uid, subscriptionId);
+                            }
+                        }
+
+                        public void onGroupCallStateChanged(int state, int reason) {
+                            try {
+                                callback.onGroupCallStateChanged(state, reason);
+                            } catch (RemoteException e) {
+                                onAppCallbackDied(uid, subscriptionId);
+                            }
+                        }
+
+                        public void onBroadcastSignalStrengthUpdated(int signalStrength) {
+                            try {
+                                callback.onBroadcastSignalStrengthUpdated(signalStrength);
+                            } catch (RemoteException e) {
+                                onAppCallbackDied(uid, subscriptionId);
+                            }
+                        }
+                    });
+
+            if (result == MbmsErrors.SUCCESS) {
+                callback.asBinder().linkToDeath(new DeathRecipient() {
+                    @Override
+                    public void binderDied() {
+                        onAppCallbackDied(uid, subscriptionId);
+                    }
+                }, 0);
+            }
+
+            return result;
+        }
+
+        @Override
+        public void dispose(int subId) throws RemoteException {
+            MbmsGroupCallServiceBase.this.dispose(subId);
+        }
+    };
+
+    /**
+     * Initialize the group call service for this app and subscription ID, registering the callback.
+     *
+     * May throw an {@link IllegalArgumentException} or a {@link SecurityException}, which
+     * will be intercepted and passed to the app as
+     * {@link MbmsErrors.InitializationErrors#ERROR_UNABLE_TO_INITIALIZE}
+     *
+     * May return any value from {@link MbmsErrors.InitializationErrors}
+     * or {@link MbmsErrors#SUCCESS}. Non-successful error codes will be passed to the app via
+     * {@link IMbmsGroupCallSessionCallback#onError(int, String)}.
+     *
+     * @param callback The callback to use to communicate with the app.
+     * @param subscriptionId The subscription ID to use.
+     */
+    public int initialize(MbmsGroupCallSessionCallback callback, int subscriptionId)
+            throws RemoteException {
+        throw new UnsupportedOperationException("Not implemented");
+    }
+
+    /**
+     * Starts a particular group call. This method may perform asynchronous work. When
+     * the call is ready for consumption, the middleware should inform the app via
+     * {@link IGroupCallCallback#onGroupCallStateChanged(int, int)}.
+     *
+     * May throw an {@link IllegalArgumentException} or an {@link IllegalStateException}
+     *
+     * @param subscriptionId The subscription id to use.
+     * @param tmgi The TMGI, an identifier for the group call.
+     * @param saiArray An array of SAIs for the group call.
+     * @param frequencyArray An array of frequencies for the group call.
+     * @param callback The callback object on which the app wishes to receive updates.
+     * @return Any error in {@link MbmsErrors.GeneralErrors}
+     */
+    public int startGroupCall(int subscriptionId, long tmgi, int[] saiArray, int[] frequencyArray,
+            GroupCallCallback callback) {
+        throw new UnsupportedOperationException("Not implemented");
+    }
+
+    /**
+     * Stop the group call identified by {@code tmgi}.
+     *
+     * The callback provided via {@link #startGroupCall} should no longer be
+     * used after this method has called by the app.
+     *
+     * May throw an {@link IllegalStateException}
+     *
+     * @param subscriptionId The subscription id to use.
+     * @param tmgi The TMGI for the call to stop.
+     */
+    public void stopGroupCall(int subscriptionId, long tmgi) {
+        throw new UnsupportedOperationException("Not implemented");
+    }
+
+    /**
+     * Called when the app receives new SAI and frequency information for the group call identified
+     * by {@code tmgi}.
+     * @param saiArray New array of SAIs that the call is available on.
+     * @param frequencyArray New array of frequencies that the call is available on.
+     */
+    public void updateGroupCall(int subscriptionId, long tmgi, int[] saiArray,
+            int[] frequencyArray) {
+        throw new UnsupportedOperationException("Not implemented");
+    }
+
+    /**
+     * Signals that the app wishes to dispose of the session identified by the
+     * {@code subscriptionId} argument and the caller's uid. No notification back to the
+     * app is required for this operation, and the corresponding callback provided via
+     * {@link #initialize} should no longer be used
+     * after this method has been called by the app.
+     *
+     * May throw an {@link IllegalStateException}
+     *
+     * @param subscriptionId The subscription id to use.
+     */
+    public void dispose(int subscriptionId) throws RemoteException {
+        throw new UnsupportedOperationException("Not implemented");
+    }
+
+    /**
+     * Indicates that the app identified by the given UID and subscription ID has died.
+     * @param uid the UID of the app, as returned by {@link Binder#getCallingUid()}.
+     * @param subscriptionId The subscription ID the app is using.
+     */
+    public void onAppCallbackDied(int uid, int subscriptionId) {
+    }
+
+    @Override
+    public IBinder onBind(Intent intent) {
+        return mInterface;
+    }
+}
diff --git a/telephony/java/com/android/internal/telephony/ISub.aidl b/telephony/java/com/android/internal/telephony/ISub.aidl
index 6521f0b..0ccd748 100755
--- a/telephony/java/com/android/internal/telephony/ISub.aidl
+++ b/telephony/java/com/android/internal/telephony/ISub.aidl
@@ -232,5 +232,5 @@
      */
     int getSimStateForSlotIndex(int slotIndex);
 
-    boolean isActiveSubId(int subId);
+    boolean isActiveSubId(int subId, String callingPackage);
 }
diff --git a/tests/DexLoggerIntegrationTests/AndroidManifest.xml b/tests/DexLoggerIntegrationTests/AndroidManifest.xml
index a847e8f..a9f01ed 100644
--- a/tests/DexLoggerIntegrationTests/AndroidManifest.xml
+++ b/tests/DexLoggerIntegrationTests/AndroidManifest.xml
@@ -17,10 +17,10 @@
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
         package="com.android.frameworks.dexloggertest">
 
-    <!-- Tests feature introduced in P (27) -->
+    <!-- Tests feature introduced in P (28) -->
     <uses-sdk
-        android:minSdkVersion="27"
-        android:targetSdkVersion="27" />
+        android:minSdkVersion="28"
+        android:targetSdkVersion="28" />
 
     <uses-permission android:name="android.permission.READ_LOGS" />
 
diff --git a/tools/incident_section_gen/main.cpp b/tools/incident_section_gen/main.cpp
index 3689a8f..4b5677a 100644
--- a/tools/incident_section_gen/main.cpp
+++ b/tools/incident_section_gen/main.cpp
@@ -140,7 +140,7 @@
     size_t base = 0;
     size_t found;
     while (true) {
-        found = args.find_first_of(" ", base);
+        found = args.find_first_of(' ', base);
         if (found != base) {
             string arg = args.substr(base, found - base);
             printf(" \"%s\",", arg.c_str());