Snap for 7550844 from b29f3c0303d491e2bebb50ecd48527d87f836aa9 to mainline-tethering-release

Change-Id: Ide18f0041a4a4a1284adbea4b42c14bde3188ed6
diff --git a/METADATA b/METADATA
new file mode 100644
index 0000000..d97975c
--- /dev/null
+++ b/METADATA
@@ -0,0 +1,3 @@
+third_party {
+  license_type: NOTICE
+}
diff --git a/rcs/presencepolling/Android.bp b/rcs/presencepolling/Android.bp
index dfe9f68..ed4a656 100644
--- a/rcs/presencepolling/Android.bp
+++ b/rcs/presencepolling/Android.bp
@@ -24,12 +24,43 @@
 // OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
 // DAMAGE.
 
+package {
+    default_applicable_licenses: ["external_ims_rcs_presencepolling_license"],
+}
+
+// Added automatically by a large-scale-change that took the approach of
+// 'apply every license found to every target'. While this makes sure we respect
+// every license restriction, it may not be entirely correct.
+//
+// e.g. GPL in an MIT project might only apply to the contrib/ directory.
+//
+// Please consider splitting the single license below into multiple licenses,
+// taking care not to lose any license_kind information, and overriding the
+// default license using the 'licenses: [...]' property on targets as needed.
+//
+// For unused files, consider creating a 'fileGroup' with "//visibility:private"
+// to attach the license to, and including a comment whether the files may be
+// used in the current project.
+// See: http://go/android-license-faq
+license {
+    name: "external_ims_rcs_presencepolling_license",
+    visibility: [":__subpackages__"],
+    license_kinds: [
+        "SPDX-license-identifier-Apache-2.0",
+        "SPDX-license-identifier-BSD",
+    ],
+    license_text: [
+        "LICENSE",
+    ],
+}
+
 java_defaults {
     name: "presence_polling_defaults",
     srcs: ["src/**/*.java"],
     static_libs: ["com.android.ims.rcsmanager"],
-    platform_apis: true,
     certificate: "platform",
+    system_ext_specific: true,
+    platform_apis: true,
     optimize: {
         proguard_flags_files: ["proguard.flags"],
     },
diff --git a/rcs/presencepolling/AndroidManifest.xml b/rcs/presencepolling/AndroidManifest.xml
index 9ee86ef..2ffcc5c 100644
--- a/rcs/presencepolling/AndroidManifest.xml
+++ b/rcs/presencepolling/AndroidManifest.xml
@@ -1,4 +1,4 @@
-<?xml version="1.0" encoding="utf-8" standalone="no"?>
+<?xml version="1.0" encoding="utf-8"?>
 <!--
  * Copyright (c) 2015, Motorola Mobility LLC
  * All rights reserved.
@@ -28,20 +28,20 @@
 -->
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
-    package="com.android.service.ims.presence"
-    android:sharedUserId="android.uid.phone"
-    coreApp="true">
+     xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
+     package="com.android.service.ims.presence"
+     android:sharedUserId="android.uid.phone"
+     coreApp="true">
 
     <uses-sdk android:minSdkVersion="19"/>
 
     <permission android:name="com.android.rcs.eab.permission.READ_WRITE_EAB"
-            android:protectionLevel="signatureOrSystem" />
+         android:protectionLevel="signatureOrSystem"/>
 
-    <protected-broadcast android:name="android.provider.rcs.eab.EAB_NEW_CONTACT_INSERTED" />
-    <protected-broadcast android:name="android.provider.rcs.eab.EAB_DATABASE_RESET" />
-    <protected-broadcast android:name="com.android.service.ims.presence.capability_polling_retry" />
-    <protected-broadcast android:name="com.android.service.ims.presence.periodical_capability_discovery" />
+    <protected-broadcast android:name="android.provider.rcs.eab.EAB_NEW_CONTACT_INSERTED"/>
+    <protected-broadcast android:name="android.provider.rcs.eab.EAB_DATABASE_RESET"/>
+    <protected-broadcast android:name="com.android.service.ims.presence.capability_polling_retry"/>
+    <protected-broadcast android:name="com.android.service.ims.presence.periodical_capability_discovery"/>
 
     <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
     <uses-permission android:name="android.permission.BROADCAST_STICKY"/>
@@ -51,64 +51,65 @@
     <uses-permission android:name="android.permission.READ_PHONE_STATE"/>
     <uses-permission android:name="android.permission.READ_PRIVILEGED_PHONE_STATE"/>
     <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
-    <uses-permission android:name="android.permission.GET_ACCOUNTS" />
+    <uses-permission android:name="android.permission.GET_ACCOUNTS"/>
     <uses-permission android:name="com.android.rcs.eab.permission.READ_WRITE_EAB"/>
     <uses-permission android:name="android.permission.READ_PROFILE"/>
     <uses-permission android:name="com.android.ims.rcs.permission.STATUS_CHANGED"/>
     <uses-permission android:name="com.android.ims.permission.PRESENCE_ACCESS"/>
 
-    <application
-        android:label="@string/app_label"
-        android:singleUser="true"
-        android:process="com.android.ims.rcsservice">
+    <application android:label="@string/app_label"
+         android:singleUser="true"
+         android:process="com.android.ims.rcsservice">
 
-        <service
-            android:name=".PollingService"
-            android:excludeFromRecents="true"
-            android:singleUser="true"
-            android:permission="com.android.ims.permission.PRESENCE_ACCESS">
+        <service android:name=".PollingService"
+             android:excludeFromRecents="true"
+             android:singleUser="true"
+             android:permission="com.android.ims.permission.PRESENCE_ACCESS">
         </service>
 
-        <receiver android:name=".DeviceBoot" androidprv:systemUserOnly="true">
+        <receiver android:name=".DeviceBoot"
+             androidprv:systemUserOnly="true"
+             android:exported="true">
             <intent-filter android:priority="103">
                  <action android:name="android.intent.action.BOOT_COMPLETED"/>
             </intent-filter>
         </receiver>
 
-        <receiver android:name=".DeviceShutdown" androidprv:systemUserOnly="true">
+        <receiver android:name=".DeviceShutdown"
+             androidprv:systemUserOnly="true"
+             android:exported="true">
             <intent-filter>
                  <action android:name="android.intent.action.ACTION_SHUTDOWN"/>
             </intent-filter>
         </receiver>
 
         <receiver android:name=".AlarmBroadcastReceiver"
-            androidprv:systemUserOnly="true"
-            android:permission="com.android.ims.permission.PRESENCE_ACCESS">
+             androidprv:systemUserOnly="true"
+             android:permission="com.android.ims.permission.PRESENCE_ACCESS"
+             android:exported="true">
             <intent-filter>
                 <action android:name="com.android.service.ims.presence.periodical_capability_discovery"/>
                 <action android:name="com.android.service.ims.presence.capability_polling_retry"/>
-                <action android:name="android.provider.rcs.eab.EAB_NEW_CONTACT_INSERTED" />
+                <action android:name="android.provider.rcs.eab.EAB_NEW_CONTACT_INSERTED"/>
             </intent-filter>
         </receiver>
 
         <service android:name=".PersistService"
-          android:exported="false"
-          android:permission="com.android.ims.permission.PRESENCE_ACCESS">
+             android:exported="false"
+             android:permission="com.android.ims.permission.PRESENCE_ACCESS">
             <intent-filter>
                 <action android:name="com.android.ims.ACTION_PRESENCE_CHANGED"/>
             </intent-filter>
         </service>
 
-        <service
-            android:name="com.android.service.ims.presence.EABService"
-            android:enabled="true">
+        <service android:name="com.android.service.ims.presence.EABService"
+             android:enabled="true">
         </service>
 
-        <provider
-            android:name=".EABProvider"
-            android:permission="com.android.rcs.eab.permission.READ_WRITE_EAB"
-            android:exported="true"
-            android:enabled="true"
-            android:authorities="com.android.rcs.eab" />
+        <provider android:name=".EABProvider"
+             android:permission="com.android.rcs.eab.permission.READ_WRITE_EAB"
+             android:exported="true"
+             android:enabled="true"
+             android:authorities="com.android.rcs.eab"/>
     </application>
 </manifest>
diff --git a/rcs/presencepolling/CleanSpec.mk b/rcs/presencepolling/CleanSpec.mk
new file mode 100644
index 0000000..f9d044f
--- /dev/null
+++ b/rcs/presencepolling/CleanSpec.mk
@@ -0,0 +1,44 @@
+# Copyright (C) 2021 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.
+#
+
+# If you don't need to do a full clean build but would like to touch
+# a file or delete some intermediate files, add a clean step to the end
+# of the list.  These steps will only be run once, if they haven't been
+# run before.
+#
+# E.g.:
+#     $(call add-clean-step, touch -c external/sqlite/sqlite3.h)
+#     $(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/STATIC_LIBRARIES/libz_intermediates)
+#
+# Always use "touch -c" and "rm -f" or "rm -rf" to gracefully deal with
+# files that are missing or have been moved.
+#
+# Use $(PRODUCT_OUT) to get to the "out/target/product/blah/" directory.
+# Use $(OUT_DIR) to refer to the "out" directory.
+#
+# If you need to re-do something that's already mentioned, just copy
+# the command and add it to the bottom of the list.  E.g., if a change
+# that you made last week required touching a file and a change you
+# made today requires touching the same file, just copy the old
+# touch step and add it to the end of the list.
+#
+# *****************************************************************
+# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST ABOVE THE BANNER
+# *****************************************************************
+# Remove old version of PresencePolling in system, since this moved to system-ext
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/app/PresencePolling)
+# ******************************************************************
+# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST ABOVE THIS BANNER
+# ******************************************************************
diff --git a/rcs/presencepolling/src/com/android/service/ims/presence/CapabilityPolling.java b/rcs/presencepolling/src/com/android/service/ims/presence/CapabilityPolling.java
index d2e2178..5002b60 100644
--- a/rcs/presencepolling/src/com/android/service/ims/presence/CapabilityPolling.java
+++ b/rcs/presencepolling/src/com/android/service/ims/presence/CapabilityPolling.java
@@ -31,6 +31,7 @@
 import android.app.AlarmManager;
 import android.app.PendingIntent;
 import android.content.BroadcastReceiver;
+import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
@@ -44,7 +45,9 @@
 import android.telephony.SubscriptionManager;
 import android.telephony.TelephonyManager;
 import android.telephony.ims.ImsException;
+import android.telephony.ims.ImsManager;
 import android.telephony.ims.ProvisioningManager;
+import android.telephony.ims.RcsUceAdapter;
 import android.text.format.TimeMigrationUtils;
 import android.text.TextUtils;
 
@@ -62,6 +65,10 @@
     private Logger logger = Logger.getLogger(this.getClass().getName());
     private final Context mContext;
 
+    private static final String PERSIST_SERVICE_NAME =
+        "com.android.service.ims.presence.PersistService";
+    private static final String PERSIST_SERVICE_PACKAGE = "com.android.service.ims.presence";
+
     public static final String ACTION_PERIODICAL_DISCOVERY_ALARM =
             "com.android.service.ims.presence.periodical_capability_discovery";
     private PendingIntent mDiscoveryAlarmIntent = null;
@@ -83,6 +90,7 @@
     private int mPublished = -1;
     private int mProvisioned = -1;
     private int mDefaultSubId;
+    private boolean isInitializing = false;
 
     private HandlerThread mDiscoveryThread;
     private Handler mDiscoveryHandler;
@@ -126,6 +134,25 @@
         }
     };
 
+    private RcsUceAdapter.OnPublishStateChangedListener mPublishStateCallback =
+            new RcsUceAdapter.OnPublishStateChangedListener() {
+        @Override
+        public void onPublishStateChange(int publishState) {
+            logger.info("publish state changed: " + publishState);
+            Intent intent = new Intent(RcsPresence.ACTION_PUBLISH_STATE_CHANGED);
+            intent.putExtra(RcsPresence.EXTRA_PUBLISH_STATE, publishState);
+            mContext.sendStickyBroadcast(intent);
+            launchPersistService(intent);
+        }
+    };
+
+    private void launchPersistService(Intent intent) {
+        ComponentName component = new ComponentName(PERSIST_SERVICE_PACKAGE,
+            PERSIST_SERVICE_NAME);
+        intent.setComponent(component);
+        mContext.startService(intent);
+    }
+
     private Runnable mRegisterCallbackRunnable = this::tryProvisioningManagerRegistration;
 
     private static CapabilityPolling sInstance = null;
@@ -234,6 +261,7 @@
         cancelDiscoveryAlarm();
         clearPollingTasks();
         mContext.unregisterReceiver(mReceiver);
+        unregisterPublishStateChangedCallback();
         mDiscoveryThread.quit();
 
         if (SubscriptionManager.isValidSubscriptionId(mDefaultSubId)) {
@@ -253,6 +281,29 @@
         mContext.registerReceiver(mReceiver, intentFilter);
     }
 
+    private void registerPublishStateChangedCallback() {
+        try {
+            ImsManager imsManager =
+                    (ImsManager) mContext.getSystemService(Context.TELEPHONY_IMS_SERVICE);
+            RcsUceAdapter uceAdapter = imsManager.getImsRcsManager(mDefaultSubId).getUceAdapter();
+            uceAdapter.addOnPublishStateChangedListener(mContext.getMainExecutor(),
+                    mPublishStateCallback);
+        } catch (Exception ex) {
+            logger.warn("register publish state callback failed, exception: " + ex);
+        }
+    }
+
+    private void unregisterPublishStateChangedCallback() {
+        try {
+            ImsManager imsManager =
+                    (ImsManager) mContext.getSystemService(Context.TELEPHONY_IMS_SERVICE);
+            RcsUceAdapter uceAdapter = imsManager.getImsRcsManager(mDefaultSubId).getUceAdapter();
+            uceAdapter.removeOnPublishStateChangedListener(mPublishStateCallback);
+        } catch (Exception ex) {
+            logger.warn("unregister publish state callback failed, exception: " + ex);
+        }
+    }
+
     private boolean isPollingReady() {
         RcsManager rcsManager = RcsManager.getInstance(mContext, 0);
         if (rcsManager != null) {
@@ -423,7 +474,7 @@
         intent.putExtra("pollingType", type);
 
         mDiscoveryAlarmIntent = PendingIntent.getBroadcast(mContext, 0, intent,
-                PendingIntent.FLAG_UPDATE_CURRENT);
+                PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_UPDATE_CURRENT);
         mAlarmManager.setExact(AlarmManager.ELAPSED_REALTIME_WAKEUP,
                 SystemClock.elapsedRealtime() + msec, mDiscoveryAlarmIntent);
 
@@ -755,18 +806,23 @@
     // Track the default subscription (the closest we can get to MSIM).
     // call from main thread only.
     public void handleDefaultSubscriptionChanged(int newDefaultSubId) {
-        logger.print("registerImsCallbacksAndSetAssociatedSubscription: new default= "
+        logger.print("handleDefaultSubscriptionChanged: new default= "
                 + newDefaultSubId);
+
         if (!SubscriptionManager.isValidSubscriptionId(newDefaultSubId)) {
             return;
         }
-        if (mDefaultSubId == newDefaultSubId) {
+        if (isInitializing && (mDefaultSubId == newDefaultSubId)) {
             return;
+        } else {
+            isInitializing = true;
         }
         // unregister old default first
         if (SubscriptionManager.isValidSubscriptionId(mDefaultSubId)) {
             ProvisioningManager pm = ProvisioningManager.createForSubscriptionId(mDefaultSubId);
             pm.unregisterProvisioningChangedCallback(mProvisioningManagerCallback);
+
+            unregisterPublishStateChangedCallback();
         }
         // register new default and clear old cached values in EAB only if we are changing the
         // default sub ID.
@@ -783,6 +839,7 @@
         enqueueSettingsChanged();
         // load settings for new default.
         enqueueProvisionStateChanged();
+        registerPublishStateChangedCallback();
     }
 
     public void tryProvisioningManagerRegistration() {
diff --git a/rcs/presencepolling/src/com/android/service/ims/presence/PollingService.java b/rcs/presencepolling/src/com/android/service/ims/presence/PollingService.java
index ed511e7..8bfd8d1 100644
--- a/rcs/presencepolling/src/com/android/service/ims/presence/PollingService.java
+++ b/rcs/presencepolling/src/com/android/service/ims/presence/PollingService.java
@@ -209,6 +209,7 @@
             logger.info("Starting CapabilityPolling...");
             mCapabilityPolling = CapabilityPolling.getInstance(this);
             mCapabilityPolling.start();
+            mCapabilityPolling.handleDefaultSubscriptionChanged(mDefaultSubId);
         }
     }
 
diff --git a/rcs/presencepolling/src/com/android/service/ims/presence/PollingTask.java b/rcs/presencepolling/src/com/android/service/ims/presence/PollingTask.java
index f3b17dd..b9835bb 100644
--- a/rcs/presencepolling/src/com/android/service/ims/presence/PollingTask.java
+++ b/rcs/presencepolling/src/com/android/service/ims/presence/PollingTask.java
@@ -201,7 +201,7 @@
             intent.putExtra("pollingTaskId", mId);
 
             mRetryAlarmIntent = PendingIntent.getBroadcast(mContext, 0, intent,
-                    PendingIntent.FLAG_UPDATE_CURRENT);
+                    PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_UPDATE_CURRENT);
 
             AlarmManager alarmManager = (AlarmManager)
                     mContext.getSystemService(Context.ALARM_SERVICE);
@@ -254,4 +254,3 @@
         return sb.toString();
     }
 }
-
diff --git a/rcs/presencepolling/tests/Android.bp b/rcs/presencepolling/tests/Android.bp
index 3dfc931..9f0bdd1 100644
--- a/rcs/presencepolling/tests/Android.bp
+++ b/rcs/presencepolling/tests/Android.bp
@@ -14,6 +14,15 @@
 // limitations under the License.
 //
 
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "external_ims_rcs_presencepolling_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["external_ims_rcs_presencepolling_license"],
+}
+
 android_test {
     name: "PresencePollingTests",
     srcs: ["src/**/*.java"],
diff --git a/rcs/rcsmanager/Android.bp b/rcs/rcsmanager/Android.bp
index 8a12412..0058f80 100644
--- a/rcs/rcsmanager/Android.bp
+++ b/rcs/rcsmanager/Android.bp
@@ -24,6 +24,23 @@
 // OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
 // DAMAGE.
 
+package {
+    default_applicable_licenses: ["external_ims_rcs_rcsmanager_license"],
+}
+
+// Added automatically by a large-scale-change
+// See: http://go/android-license-faq
+license {
+    name: "external_ims_rcs_rcsmanager_license",
+    visibility: [":__subpackages__"],
+    license_kinds: [
+        "SPDX-license-identifier-BSD",
+    ],
+    license_text: [
+        "LICENSE",
+    ],
+}
+
 java_library {
     name: "com.android.ims.rcsmanager",
     aidl: {
diff --git a/rcs/rcsmanager/src/java/com/android/ims/ResultCode.java b/rcs/rcsmanager/src/java/com/android/ims/ResultCode.java
index 2119d5c..8934115 100644
--- a/rcs/rcsmanager/src/java/com/android/ims/ResultCode.java
+++ b/rcs/rcsmanager/src/java/com/android/ims/ResultCode.java
@@ -178,4 +178,18 @@
      * The Client should not send any EAB traffic after get this error.
      */
     public static final int PUBLISH_NOT_PROVISIONED = ResultCode.SUBSCRIBER_ERROR_CODE_END - 3;
+
+    public static final int PUBLISH_NOT_REGISTERED = ResultCode.SUBSCRIBER_ERROR_CODE_END - 4;
+
+    public static final int PUBLISH_FORBIDDEN = ResultCode.SUBSCRIBER_ERROR_CODE_END - 5;
+
+    public static final int PUBLISH_NOT_FOUND = ResultCode.SUBSCRIBER_ERROR_CODE_END - 6;
+
+    public static final int PUBLISH_REQUEST_TIMEOUT = ResultCode.SUBSCRIBER_ERROR_CODE_END - 7;
+
+    public static final int PUBLISH_TOO_LARGE = ResultCode.SUBSCRIBER_ERROR_CODE_END - 8;
+
+    public static final int PUBLISH_TOO_SHORT = ResultCode.SUBSCRIBER_ERROR_CODE_END - 9;
+
+    public static final int PUBLISH_TEMPORARY_ERROR = ResultCode.SUBSCRIBER_ERROR_CODE_END - 10;
 }
diff --git a/rcs/rcsmanager/src/java/com/android/ims/internal/ContactNumberUtils.java b/rcs/rcsmanager/src/java/com/android/ims/internal/ContactNumberUtils.java
index 1ed03f9..094afb4 100644
--- a/rcs/rcsmanager/src/java/com/android/ims/internal/ContactNumberUtils.java
+++ b/rcs/rcsmanager/src/java/com/android/ims/internal/ContactNumberUtils.java
@@ -134,7 +134,9 @@
     public static int NUMBER_INVALID = 5;
 
     /**
-     * Check if it is a valid contact number for presence
+     * Check if it is a valid contact number for presence.
+     *
+     * Note: mContext must be set via setContext() before calling this method.
      *
      * @param phoneNumber read from contact db.
      * @return contact number error code.
@@ -161,7 +163,16 @@
             return NUMBER_INVALID;
         }
 
-        if (PhoneNumberUtils.isEmergencyNumber(number)) {
+        boolean isEmergencyNumber;
+        if (mContext == null) {
+            Log.e(TAG, "context is unexpectedly null to provide emergency identification service");
+            isEmergencyNumber = false;
+        } else {
+            TelephonyManager tm = mContext.getSystemService(TelephonyManager.class);
+            isEmergencyNumber = tm.isEmergencyNumber(number);
+        }
+
+        if (isEmergencyNumber) {
             return NUMBER_EMERGENCY;
         // TODO: To handle short code
         //} else if ((mContext != null) && PhoneNumberUtils.isN11Number(mContext, number)) {
diff --git a/rcs/rcsservice/Android.bp b/rcs/rcsservice/Android.bp
index 775275b..ad24544 100644
--- a/rcs/rcsservice/Android.bp
+++ b/rcs/rcsservice/Android.bp
@@ -28,6 +28,23 @@
 // Build the application : Presence.apk
 //#########################################################################
 
+package {
+    default_applicable_licenses: ["external_ims_rcs_rcsservice_license"],
+}
+
+// Added automatically by a large-scale-change
+// See: http://go/android-license-faq
+license {
+    name: "external_ims_rcs_rcsservice_license",
+    visibility: [":__subpackages__"],
+    license_kinds: [
+        "SPDX-license-identifier-BSD",
+    ],
+    license_text: [
+        "LICENSE",
+    ],
+}
+
 java_library {
     name: "ucepresencelib",
     // We only want this to be used as a static import.
@@ -44,7 +61,6 @@
 android_app {
     // This is the target being built. (Name of APK)
     name: "RcsService",
-    platform_apis: true,
     // Only compile source java files in this apk.
     srcs: [
         "src/com/android/service/ims/AlarmBroadcastReceiver.java",
@@ -62,4 +78,6 @@
         "com.android.ims.rcsmanager"
     ],
     certificate: "platform",
+    system_ext_specific: true,
+    platform_apis: true,
 }
diff --git a/rcs/rcsservice/AndroidManifest.xml b/rcs/rcsservice/AndroidManifest.xml
index 77921c3..6d108a1 100644
--- a/rcs/rcsservice/AndroidManifest.xml
+++ b/rcs/rcsservice/AndroidManifest.xml
@@ -1,4 +1,4 @@
-<?xml version="1.0" encoding="utf-8" standalone="no"?>
+<?xml version="1.0" encoding="utf-8"?>
 <!--
  * Copyright (c) 2015, Motorola Mobility LLC
  * All rights reserved.
@@ -28,23 +28,22 @@
 -->
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
- android:versionCode="1"
- android:versionName="2.4.6"
- coreApp="true"
- android:sharedUserId="android.uid.phone"
- package="com.android.service.ims">
+     xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
+     android:versionCode="1"
+     android:versionName="2.4.6"
+     coreApp="true"
+     android:sharedUserId="android.uid.phone"
+     package="com.android.service.ims">
 
     <uses-sdk android:minSdkVersion="19"/>
 
-    <permission
-        android:name="com.android.ims.rcs.permission.STATUS_CHANGED"
-        android:protectionLevel="signatureOrSystem" />
+    <permission android:name="com.android.ims.rcs.permission.STATUS_CHANGED"
+         android:protectionLevel="signatureOrSystem"/>
 
     <permission android:name="com.android.ims.permission.PRESENCE_ACCESS"
-        android:label="@string/ims_presence_permission"
-        android:description="@string/ims_ims_permission_desc"
-        android:protectionLevel="signatureOrSystem" />
+         android:label="@string/ims_presence_permission"
+         android:description="@string/ims_ims_permission_desc"
+         android:protectionLevel="signatureOrSystem"/>
 
     <uses-permission android:name="android.permission.READ_PHONE_STATE"/>
     <uses-permission android:name="android.permission.BROADCAST_STICKY"/>
@@ -55,24 +54,27 @@
     <uses-permission android:name="com.android.ims.permission.PRESENCE_ACCESS"/>
     <uses-permission android:name="com.android.rcs.eab.permission.READ_WRITE_EAB"/>
 
-    <application android:name="RcsServiceApp" android:persistent="true"
-        android:process="com.android.ims.rcsservice">
+    <application android:name="RcsServiceApp"
+         android:persistent="true"
+         android:process="com.android.ims.rcsservice">
         <service android:name="com.android.service.ims.RcsService"
-            android:exported="true"
-            android:enabled="true"
-            android:permission="com.android.ims.permission.PRESENCE_ACCESS">
+             android:exported="true"
+             android:enabled="true"
+             android:permission="com.android.ims.permission.PRESENCE_ACCESS">
         </service>
 
         <receiver android:name="com.android.service.ims.DeviceShutdown"
-            androidprv:systemUserOnly="true">
+             androidprv:systemUserOnly="true"
+             android:exported="true">
             <intent-filter>
                  <action android:name="android.intent.action.ACTION_SHUTDOWN"/>
             </intent-filter>
         </receiver>
 
         <receiver android:name=".AlarmBroadcastReceiver"
-            android:permission="com.android.ims.permission.PRESENCE_ACCESS"
-            androidprv:systemUserOnly="true">
+             android:permission="com.android.ims.permission.PRESENCE_ACCESS"
+             androidprv:systemUserOnly="true"
+             android:exported="true">
             <intent-filter>
                 <action android:name="com.android.service.ims.presence.retry"/>
                 <action android:name="com.android.service.ims.presence.task.timeout"/>
diff --git a/rcs/rcsservice/CleanSpec.mk b/rcs/rcsservice/CleanSpec.mk
new file mode 100644
index 0000000..5fb4204
--- /dev/null
+++ b/rcs/rcsservice/CleanSpec.mk
@@ -0,0 +1,45 @@
+# Copyright (C) 2021 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.
+#
+
+# If you don't need to do a full clean build but would like to touch
+# a file or delete some intermediate files, add a clean step to the end
+# of the list.  These steps will only be run once, if they haven't been
+# run before.
+#
+# E.g.:
+#     $(call add-clean-step, touch -c external/sqlite/sqlite3.h)
+#     $(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/STATIC_LIBRARIES/libz_intermediates)
+#
+# Always use "touch -c" and "rm -f" or "rm -rf" to gracefully deal with
+# files that are missing or have been moved.
+#
+# Use $(PRODUCT_OUT) to get to the "out/target/product/blah/" directory.
+# Use $(OUT_DIR) to refer to the "out" directory.
+#
+# If you need to re-do something that's already mentioned, just copy
+# the command and add it to the bottom of the list.  E.g., if a change
+# that you made last week required touching a file and a change you
+# made today requires touching the same file, just copy the old
+# touch step and add it to the end of the list.
+#
+# *****************************************************************
+# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST ABOVE THE BANNER
+# *****************************************************************
+# Remove old version of RcsService in system, since this moved to system-ext
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/app/RcsService)
+
+# ******************************************************************
+# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST ABOVE THIS BANNER
+# ******************************************************************
diff --git a/rcs/rcsservice/src/com/android/service/ims/PresenceInfoParser.java b/rcs/rcsservice/src/com/android/service/ims/PresenceInfoParser.java
index 5edb9a1..dac1401 100644
--- a/rcs/rcsservice/src/com/android/service/ims/PresenceInfoParser.java
+++ b/rcs/rcsservice/src/com/android/service/ims/PresenceInfoParser.java
@@ -29,7 +29,10 @@
 package com.android.service.ims;
 
 import android.net.Uri;
+import android.telephony.ims.RcsContactPresenceTuple;
+import android.telephony.ims.RcsContactPresenceTuple.ServiceCapabilities;
 import android.telephony.ims.RcsContactUceCapability;
+import android.telephony.ims.RcsContactUceCapability.PresenceBuilder;
 
 import java.lang.String;
 import java.util.ArrayList;
@@ -274,36 +277,57 @@
     }
 
     public static RcsContactUceCapability getUceCapability(RcsPresenceInfo info) {
-        RcsContactUceCapability.Builder result = new RcsContactUceCapability.Builder(
-                PresenceUtils.convertContactNumber(info.getContactNumber()));
+        boolean volteCapable = false;
         if (ServiceState.ONLINE == info.getServiceState(ServiceType.VOLTE_CALL)) {
-            result.add(RcsContactUceCapability.CAPABILITY_IP_VOICE_CALL,
-                    PresenceUtils.convertContactNumber(
-                            info.getServiceContact(ServiceType.VOLTE_CALL)));
+            volteCapable = true;
         }
+
+        boolean vtCapable = false;
         if (ServiceState.ONLINE == info.getServiceState(ServiceType.VT_CALL)) {
-            result.add(RcsContactUceCapability.CAPABILITY_IP_VIDEO_CALL,
-                    PresenceUtils.convertContactNumber(
-                            info.getServiceContact(ServiceType.VT_CALL)));
+            vtCapable = true;
         }
-        return result.build();
+
+        ServiceCapabilities.Builder servCapsBuilder = new ServiceCapabilities.Builder(
+            volteCapable, vtCapable);
+        servCapsBuilder.addSupportedDuplexMode(ServiceCapabilities.DUPLEX_MODE_FULL);
+
+        Uri contactUri = PresenceUtils.convertContactNumber(info.getContactNumber());
+
+        RcsContactPresenceTuple.Builder tupleBuilder = new RcsContactPresenceTuple.Builder(
+                RcsContactPresenceTuple.TUPLE_BASIC_STATUS_OPEN,
+                RcsContactPresenceTuple.SERVICE_ID_MMTEL, "1.0");
+        tupleBuilder.setContactUri(contactUri).setServiceCapabilities(servCapsBuilder.build());
+
+        PresenceBuilder presenceBuilder = new PresenceBuilder(contactUri,
+                RcsContactUceCapability.SOURCE_TYPE_CACHED,
+                RcsContactUceCapability.REQUEST_RESULT_FOUND);
+        presenceBuilder.addCapabilityTuple(tupleBuilder.build());
+
+        return presenceBuilder.build();
     }
 
     public static RcsPresenceInfo getRcsPresenceInfo(RcsContactUceCapability capability) {
-        int volteCapable = capability.isCapable(RcsContactUceCapability.CAPABILITY_IP_VOICE_CALL) ?
-                ServiceState.ONLINE : ServiceState.OFFLINE;
-        int vtCapable = capability.isCapable(RcsContactUceCapability.CAPABILITY_IP_VIDEO_CALL) ?
-                ServiceState.ONLINE : ServiceState.OFFLINE;
+        int volteCapable = ServiceState.OFFLINE;
+        int vtCapable = ServiceState.OFFLINE;
+        RcsContactPresenceTuple presenceTuple = capability.getCapabilityTuple(
+                RcsContactPresenceTuple.SERVICE_ID_MMTEL);
+        if (presenceTuple != null) {
+            ServiceCapabilities serviceCaps = presenceTuple.getServiceCapabilities();
+            if (serviceCaps != null && serviceCaps.isAudioCapable()) {
+                volteCapable = ServiceState.ONLINE;
+            }
+            if (serviceCaps != null && serviceCaps.isVideoCapable()) {
+                vtCapable = ServiceState.ONLINE;
+            }
+        }
         return new RcsPresenceInfo(capability.getContactUri().getSchemeSpecificPart(),
                 // Not sure what the difference is, just track voice capable.
                 (volteCapable == ServiceState.ONLINE) ? RcsPresenceInfo.VolteStatus.VOLTE_ENABLED :
                         RcsPresenceInfo.VolteStatus.VOLTE_DISABLED, volteCapable,
-                PresenceUtils.getNumber(capability.getServiceUri(
-                        RcsContactUceCapability.CAPABILITY_IP_VOICE_CALL)),
+                PresenceUtils.getNumber(capability.getContactUri()),
                 // We always use system current time instead of time from server
                 System.currentTimeMillis(), vtCapable,
-                PresenceUtils.getNumber(capability.getServiceUri(
-                        RcsContactUceCapability.CAPABILITY_IP_VIDEO_CALL)),
+                PresenceUtils.getNumber(capability.getContactUri()),
                 // We always use system current time instead of time from server
                 System.currentTimeMillis());
     }
diff --git a/rcs/rcsservice/src/com/android/service/ims/RcsService.java b/rcs/rcsservice/src/com/android/service/ims/RcsService.java
index cbd4a8b..7d7b744 100644
--- a/rcs/rcsservice/src/com/android/service/ims/RcsService.java
+++ b/rcs/rcsservice/src/com/android/service/ims/RcsService.java
@@ -218,7 +218,7 @@
         mRcsStackAdaptor.getListener().setPresenceSubscriber(mSubscriber);
         mPublication.setSubscriber(mSubscriber);
 
-        ConnectivityManager cm = ConnectivityManager.from(this);
+        final ConnectivityManager cm = getSystemService(ConnectivityManager.class);
         if (cm != null) {
             boolean enabled = Settings.Global.getInt(getContentResolver(),
                     Settings.Global.MOBILE_DATA, 1) == 1;
@@ -275,15 +275,12 @@
             return;
         }
         int defaultSub = RcsSettingUtils.getDefaultSubscriptionId(this);
-        if (!SubscriptionManager.isValidSubscriptionId(defaultSub)) {
-            mAssociatedSubscription = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
-            handleAssociatedSubscriptionChanged(mAssociatedSubscription);
-            return;
+        // If the presence SIP PUBLISH procedure is not supported, treat it as if there is no valid
+        // associated sub
+        if (!RcsSettingUtils.isPublishEnabled(this, defaultSub)) {
+            defaultSub = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
         }
 
-        ImsMmTelManager imsManager = ImsMmTelManager.createForSubscriptionId(defaultSub);
-        ProvisioningManager provisioningManager =
-                ProvisioningManager.createForSubscriptionId(defaultSub);
         try {
             if (defaultSub == mAssociatedSubscription) {
                 // Don't register duplicate callbacks for the same subscription.
@@ -301,15 +298,23 @@
                         mProvisioningChangedCallback);
                 logger.print("callbacks unregistered for sub " + mAssociatedSubscription);
             }
-            // move over registrations.
-            imsManager.registerImsRegistrationCallback(getMainExecutor(), mImsRegistrationCallback);
-            imsManager.registerMmTelCapabilityCallback(getMainExecutor(), mCapabilityCallback);
-            provisioningManager.registerProvisioningChangedCallback(getMainExecutor(),
-                    mProvisioningChangedCallback);
-            mAssociatedSubscription = defaultSub;
+            if (SubscriptionManager.isValidSubscriptionId(defaultSub)) {
+                ImsMmTelManager imsManager = ImsMmTelManager.createForSubscriptionId(defaultSub);
+                ProvisioningManager provisioningManager =
+                        ProvisioningManager.createForSubscriptionId(defaultSub);
+                // move over registrations if the new sub id is valid.
+                imsManager.registerImsRegistrationCallback(getMainExecutor(),
+                        mImsRegistrationCallback);
+                imsManager.registerMmTelCapabilityCallback(getMainExecutor(), mCapabilityCallback);
+                provisioningManager.registerProvisioningChangedCallback(getMainExecutor(),
+                        mProvisioningChangedCallback);
+                mAssociatedSubscription = defaultSub;
+                logger.print("callbacks registered for sub " + mAssociatedSubscription);
+            } else {
+                mAssociatedSubscription = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
+            }
             logger.print("registerImsCallbacksAndSetAssociatedSubscription: new default="
-                    + defaultSub);
-            logger.print("callbacks registered for sub " + mAssociatedSubscription);
+                    + mAssociatedSubscription);
             handleAssociatedSubscriptionChanged(mAssociatedSubscription);
         } catch (ImsException e) {
             logger.info("Couldn't register callbacks for " + defaultSub + ": "
diff --git a/rcs/rcsservice/src/com/android/service/ims/RcsSettingUtils.java b/rcs/rcsservice/src/com/android/service/ims/RcsSettingUtils.java
index 056e4d0..d39952f 100644
--- a/rcs/rcsservice/src/com/android/service/ims/RcsSettingUtils.java
+++ b/rcs/rcsservice/src/com/android/service/ims/RcsSettingUtils.java
@@ -134,6 +134,21 @@
         return isProvisioned;
     }
 
+    public static boolean isPublishEnabled(Context context, int subId) {
+        if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
+            logger.debug("isPublishEnabled: no valid subscriptions!");
+            return false;
+        }
+        CarrierConfigManager configManager = (CarrierConfigManager)
+                context.getSystemService(Context.CARRIER_CONFIG_SERVICE);
+        if (configManager != null) {
+            PersistableBundle config = configManager.getConfigForSubId(subId);
+            return (config != null) && config.getBoolean(
+                    CarrierConfigManager.Ims.KEY_ENABLE_PRESENCE_PUBLISH_BOOL, false);
+        }
+        return false;
+    }
+
     public static boolean hasUserEnabledContactDiscovery(Context context, int subId) {
         if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
             logger.debug("hasUserEnabledContactDiscovery: no valid subscriptions!");
diff --git a/rcs/rcsservice/src/com/android/service/ims/RcsStackAdaptor.java b/rcs/rcsservice/src/com/android/service/ims/RcsStackAdaptor.java
index d864701..e279c83 100644
--- a/rcs/rcsservice/src/com/android/service/ims/RcsStackAdaptor.java
+++ b/rcs/rcsservice/src/com/android/service/ims/RcsStackAdaptor.java
@@ -44,6 +44,8 @@
 import android.telephony.SubscriptionInfo;
 import android.telephony.SubscriptionManager;
 import android.telephony.TelephonyManager;
+import android.telephony.ims.RcsContactPresenceTuple;
+import android.telephony.ims.RcsContactPresenceTuple.ServiceCapabilities;
 import android.telephony.ims.RcsContactUceCapability;
 
 import com.android.ims.ResultCode;
@@ -253,14 +255,16 @@
     public void updatePublisherState(@PresenceBase.PresencePublishState int publishState) {
         synchronized (mSyncObj) {
             logger.print("mPublishingState=" + mPublishingState + " publishState=" + publishState);
+            if (mPublishingState != publishState ) {
+                Intent publishIntent = new Intent(RcsPresence.ACTION_PUBLISH_STATE_CHANGED);
+                publishIntent.putExtra(RcsPresence.EXTRA_PUBLISH_STATE, publishState);
+                // Start PersistService and broadcast to other receivers that are listening
+                // dynamically.
+                mContext.sendStickyBroadcast(publishIntent);
+                launchPersistService(publishIntent);
+            }
             mPublishingState = publishState;
         }
-        Intent publishIntent = new Intent(RcsPresence.ACTION_PUBLISH_STATE_CHANGED);
-        publishIntent.putExtra(RcsPresence.EXTRA_PUBLISH_STATE, publishState);
-        // Start PersistService and broadcast to other receivers that are listening
-        // dynamically.
-        mContext.sendStickyBroadcast(publishIntent);
-        launchPersistService(publishIntent);
     }
 
     @Override
@@ -376,10 +380,8 @@
             pMyCapInfo.setContactUri(myUri);
 
             CapInfo capInfo = new CapInfo();
-            capInfo.setIpVoiceSupported(capabilities.isCapable(
-                    RcsContactUceCapability.CAPABILITY_IP_VOICE_CALL));
-            capInfo.setIpVideoSupported(capabilities.isCapable(
-                    RcsContactUceCapability.CAPABILITY_IP_VIDEO_CALL));
+            capInfo.setIpVoiceSupported(isVolteSupported(capabilities));
+            capInfo.setIpVideoSupported(isVtSupported(capabilities));
             capInfo.setCdViaPresenceSupported(true);
 
             capInfo.setFtSupported(false); // TODO: support FT
@@ -417,6 +419,30 @@
         return  ResultCode.SUCCESS;
     }
 
+    private boolean isVolteSupported(RcsContactUceCapability capabilities) {
+        RcsContactPresenceTuple presenceTuple = capabilities.getCapabilityTuple(
+                RcsContactPresenceTuple.SERVICE_ID_MMTEL);
+        if (presenceTuple != null) {
+            ServiceCapabilities serviceCaps = presenceTuple.getServiceCapabilities();
+            if (serviceCaps != null && serviceCaps.isAudioCapable()) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    private boolean isVtSupported(RcsContactUceCapability capabilities) {
+        RcsContactPresenceTuple presenceTuple = capabilities.getCapabilityTuple(
+                RcsContactPresenceTuple.SERVICE_ID_MMTEL);
+        if (presenceTuple != null) {
+            ServiceCapabilities serviceCaps = presenceTuple.getServiceCapabilities();
+            if (serviceCaps != null && serviceCaps.isVideoCapable()) {
+                return true;
+            }
+        }
+        return false;
+    }
+
     private void launchPersistService(Intent intent) {
         ComponentName component = new ComponentName(PERSIST_SERVICE_PACKAGE,
                 PERSIST_SERVICE_NAME);
@@ -671,7 +697,7 @@
             intent.putExtra("times", times);
             intent.setPackage(mContext.getPackageName());
             mRetryAlarmIntent = PendingIntent.getBroadcast(mContext, 0, intent,
-                    PendingIntent.FLAG_UPDATE_CURRENT);
+                    PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE);
 
             // Wait for 1s to ignore duplicate init request as possible as we can.
             long timeSkip = 1000;
diff --git a/rcs/rcsservice/src/com/android/service/ims/presence/PresenceCapabilityTask.java b/rcs/rcsservice/src/com/android/service/ims/presence/PresenceCapabilityTask.java
index e94e51a..fb22b5e 100644
--- a/rcs/rcsservice/src/com/android/service/ims/presence/PresenceCapabilityTask.java
+++ b/rcs/rcsservice/src/com/android/service/ims/presence/PresenceCapabilityTask.java
@@ -109,7 +109,7 @@
         intent.setPackage(mContext.getPackageName());
         intent.putExtra("taskId", mTaskId);
         PendingIntent mAlarmIntent = PendingIntent.getBroadcast(mContext, 0, intent,
-                PendingIntent.FLAG_ONE_SHOT);
+                PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_ONE_SHOT);
 
         if(sAlarmManager == null){
             sAlarmManager = (AlarmManager)mContext.getSystemService(Context.ALARM_SERVICE);
@@ -162,4 +162,3 @@
         TaskManager.getDefault().removeTask(mTaskId);
     }
 };
-
diff --git a/rcs/rcsservice/src/com/android/service/ims/presence/PresencePublication.java b/rcs/rcsservice/src/com/android/service/ims/presence/PresencePublication.java
index 0b6b2ea..29391f7 100644
--- a/rcs/rcsservice/src/com/android/service/ims/presence/PresencePublication.java
+++ b/rcs/rcsservice/src/com/android/service/ims/presence/PresencePublication.java
@@ -44,7 +44,10 @@
 import android.telephony.AccessNetworkConstants;
 import android.telephony.SubscriptionManager;
 import android.telephony.TelephonyManager;
+import android.telephony.ims.RcsContactPresenceTuple;
+import android.telephony.ims.RcsContactPresenceTuple.ServiceCapabilities;
 import android.telephony.ims.RcsContactUceCapability;
+import android.telephony.ims.RcsContactUceCapability.PresenceBuilder;
 import android.telephony.ims.feature.MmTelFeature;
 import android.text.TextUtils;
 
@@ -906,14 +909,10 @@
             return;
         }
 
-        RcsContactUceCapability.Builder presenceInfoBuilder =
-                new RcsContactUceCapability.Builder(myUri);
-        if (publishRequest.getVolteCapable()) {
-            presenceInfoBuilder.add(RcsContactUceCapability.CAPABILITY_IP_VOICE_CALL);
-        }
-        if (publishRequest.getVtCapable()) {
-            presenceInfoBuilder.add(RcsContactUceCapability.CAPABILITY_IP_VIDEO_CALL);
-        }
+        boolean isVolteCapble = publishRequest.getVolteCapable();
+        boolean isVtCapable = publishRequest.getVtCapable();
+        RcsContactUceCapability presenceInfo =
+                getRcsContactUceCapability(myUri, isVolteCapble, isVtCapable);
 
         synchronized(mSyncObj) {
             mPublishingRequest = publishRequest;
@@ -923,8 +922,7 @@
         String myNumber = getNumberFromUri(myUri);
         int taskId = TaskManager.getDefault().addPublishTask(myNumber);
         logger.print("doPublish, uri=" + myUri + ", myNumber=" + myNumber + ", taskId=" + taskId);
-        int ret = presencePublisher.requestPublication(presenceInfoBuilder.build(),
-                myUri.toString(), taskId);
+        int ret = presencePublisher.requestPublication(presenceInfo, myUri.toString(), taskId);
         if (ret != ResultCode.SUCCESS) {
             logger.print("doPublish, task=" + taskId + " failed with code=" + ret);
             TaskManager.getDefault().removeTask(taskId);
@@ -933,6 +931,27 @@
         mHasCachedTrigger = (ret == ResultCode.ERROR_SERVICE_NOT_AVAILABLE);
     }
 
+    private RcsContactUceCapability getRcsContactUceCapability(Uri contact, boolean isVolteCapable,
+            boolean isVtCapable) {
+
+        ServiceCapabilities.Builder servCapsBuilder = new ServiceCapabilities.Builder(
+            isVolteCapable, isVtCapable);
+        servCapsBuilder.addSupportedDuplexMode(ServiceCapabilities.DUPLEX_MODE_FULL);
+
+        RcsContactPresenceTuple.Builder tupleBuilder = new RcsContactPresenceTuple.Builder(
+                RcsContactPresenceTuple.TUPLE_BASIC_STATUS_OPEN,
+                RcsContactPresenceTuple.SERVICE_ID_MMTEL, "1.0");
+        tupleBuilder.setContactUri(contact)
+                .setServiceCapabilities(servCapsBuilder.build());
+
+        PresenceBuilder presenceBuilder = new PresenceBuilder(contact,
+                RcsContactUceCapability.SOURCE_TYPE_CACHED,
+                RcsContactUceCapability.REQUEST_RESULT_FOUND);
+        presenceBuilder.addCapabilityTuple(tupleBuilder.build());
+
+        return presenceBuilder.build();
+    }
+
     private String getNumberFromUri(Uri uri) {
         if (uri == null) return null;
         String number = uri.getSchemeSpecificPart();
@@ -1014,7 +1033,7 @@
         Intent intent = new Intent(ACTION_RETRY_PUBLISH_ALARM);
         intent.setPackage(mContext.getPackageName());
         mRetryAlarmIntent = PendingIntent.getBroadcast(mContext, 0, intent,
-                PendingIntent.FLAG_UPDATE_CURRENT);
+                PendingIntent.FLAG_UPDATE_CURRENT|PendingIntent.FLAG_IMMUTABLE);
 
         if(mAlarmManager == null) {
             mAlarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
diff --git a/rcs/rcsservice/src/com/android/service/ims/presence/PresenceSubscriber.java b/rcs/rcsservice/src/com/android/service/ims/presence/PresenceSubscriber.java
index c804675..fb2b57e 100644
--- a/rcs/rcsservice/src/com/android/service/ims/presence/PresenceSubscriber.java
+++ b/rcs/rcsservice/src/com/android/service/ims/presence/PresenceSubscriber.java
@@ -29,9 +29,11 @@
 package com.android.service.ims.presence;
 
 import android.content.Context;
+import android.net.Uri;
 import android.telephony.SubscriptionManager;
 import android.telephony.TelephonyManager;
 import android.telephony.ims.RcsContactUceCapability;
+import android.telephony.ims.RcsContactUceCapability.PresenceBuilder;
 import android.text.TextUtils;
 
 import com.android.ims.ResultCode;
@@ -449,8 +451,8 @@
                 }
                 logger.debug("onSipResponse: contact= " + contacts[i] + ", not found.");
                 // Build contacts with no capabilities.
-                contactCapabilities.add(new RcsContactUceCapability.Builder(
-                        PresenceUtils.convertContactNumber(contacts[i])).build());
+                contactCapabilities.add(buildContactWithNoCapabilities(
+                        PresenceUtils.convertContactNumber(contacts[i])));
             }
             handleCapabilityUpdate(task, contactCapabilities, true);
 
@@ -461,6 +463,13 @@
         handleCallback(task, errorCode, false);
     }
 
+    private RcsContactUceCapability buildContactWithNoCapabilities(Uri contactUri) {
+        PresenceBuilder presenceBuilder = new PresenceBuilder(contactUri,
+                RcsContactUceCapability.SOURCE_TYPE_CACHED,
+                RcsContactUceCapability.REQUEST_RESULT_FOUND);
+        return presenceBuilder.build();
+    }
+
     private void handleCapabilityUpdate(Task task, List<RcsContactUceCapability> capabilities,
             boolean updateLastTimestamp) {
         if (task == null || task.mListener == null ) {
@@ -568,8 +577,11 @@
                 continue;
             }
             // Add each contacts with no capabilities.
-            presenceInfoList.add(new RcsContactUceCapability.Builder(
-                    PresenceUtils.convertContactNumber(task.mContacts[i])).build());
+            Uri uri = PresenceUtils.convertContactNumber(task.mContacts[i]);
+            PresenceBuilder presenceBuilder = new PresenceBuilder(uri,
+                    RcsContactUceCapability.SOURCE_TYPE_CACHED,
+                    RcsContactUceCapability.REQUEST_RESULT_FOUND);
+            presenceInfoList.add(presenceBuilder.build());
         }
 
         if(presenceInfoList.size() > 0) {