Merge "Fix for busted call duration in CDMA conference" into lmp-dev
diff --git a/res/values/config.xml b/res/values/config.xml
index 39923d4..6c6f215 100644
--- a/res/values/config.xml
+++ b/res/values/config.xml
@@ -43,8 +43,4 @@
          if this package has not registered any accounts, then it will be ignored.
          [DO NOT TRANSLATE] -->
     <string name="default_connection_manager_component" translatable="false"></string>
-
-    <!-- Flag indicating that wi-fi calling through a connection manager is supported.
-         [DO NOT TRANSLATE] -->
-    <bool name="connection_manager_enabled" translatable="false">true</bool>
 </resources>
diff --git a/src/com/android/server/telecom/CreateConnectionProcessor.java b/src/com/android/server/telecom/CreateConnectionProcessor.java
index e4c5463..11623b0 100644
--- a/src/com/android/server/telecom/CreateConnectionProcessor.java
+++ b/src/com/android/server/telecom/CreateConnectionProcessor.java
@@ -16,7 +16,6 @@
 
 package com.android.server.telecom;
 
-import android.content.Context;
 import android.telecom.ParcelableConnection;
 import android.telecom.PhoneAccount;
 import android.telecom.PhoneAccountHandle;
@@ -177,12 +176,6 @@
     }
 
     private boolean shouldSetConnectionManager() {
-        Context context = TelecomApp.getInstance();
-        if (!context.getResources().getBoolean(R.bool.connection_manager_enabled)) {
-            // Connection Manager support has been turned off, disregard.
-            return false;
-        }
-
         if (mAttemptRecords.size() == 0) {
             return false;
         }
diff --git a/src/com/android/server/telecom/PhoneAccountRegistrar.java b/src/com/android/server/telecom/PhoneAccountRegistrar.java
index 31dd727..ed2ca05 100644
--- a/src/com/android/server/telecom/PhoneAccountRegistrar.java
+++ b/src/com/android/server/telecom/PhoneAccountRegistrar.java
@@ -183,10 +183,6 @@
     }
 
     public void setSimCallManager(PhoneAccountHandle callManager) {
-        if (!isEnabledConnectionManager()) {
-            return;
-        }
-
         if (callManager != null) {
             PhoneAccount callManagerAccount = getPhoneAccount(callManager);
             if (callManagerAccount == null) {
@@ -207,10 +203,6 @@
     }
 
     public PhoneAccountHandle getSimCallManager() {
-        if (!isEnabledConnectionManager()) {
-            return null;
-        }
-
         if (mState.simCallManager != null) {
             if (NO_ACCOUNT_SELECTED.equals(mState.simCallManager)) {
                 return null;
@@ -308,11 +300,8 @@
      * @return The phone account handles.
      */
     public List<PhoneAccountHandle> getConnectionManagerPhoneAccounts() {
-        if (isEnabledConnectionManager()) {
-            return getPhoneAccountHandles(PhoneAccount.CAPABILITY_CONNECTION_MANAGER,
-                    null /* supportedUriScheme */, false /* includeDisabled */);
-        }
-        return Collections.emptyList();
+        return getPhoneAccountHandles(PhoneAccount.CAPABILITY_CONNECTION_MANAGER,
+                null /* supportedUriScheme */, false /* includeDisabled */);
     }
 
     public PhoneAccount getPhoneAccount(PhoneAccountHandle handle) {
@@ -470,10 +459,6 @@
         }
     }
 
-    private boolean isEnabledConnectionManager() {
-        return mContext.getResources().getBoolean(R.bool.connection_manager_enabled);
-    }
-
     /**
      * Determines if the connection service specified by a {@link PhoneAccountHandle} has the
      * {@link Manifest.permission#BIND_CONNECTION_SERVICE} permission.
diff --git a/src/com/android/server/telecom/TelecomServiceImpl.java b/src/com/android/server/telecom/TelecomServiceImpl.java
index 2a740a7..750c77a 100644
--- a/src/com/android/server/telecom/TelecomServiceImpl.java
+++ b/src/com/android/server/telecom/TelecomServiceImpl.java
@@ -16,11 +16,12 @@
 
 package com.android.server.telecom;
 
+import android.Manifest;
 import android.app.AppOpsManager;
 import android.content.ComponentName;
 import android.content.Context;
-
 import android.content.Intent;
+import android.content.pm.PackageManager;
 import android.content.res.Resources;
 import android.os.Binder;
 import android.os.Bundle;
@@ -286,7 +287,7 @@
     @Override
     public void registerPhoneAccount(PhoneAccount account) {
         try {
-            enforceModifyPermissionOrCallingPackage(
+            enforcePhoneAccountModificationForPackage(
                     account.getAccountHandle().getComponentName().getPackageName());
             if (account.hasCapabilities(PhoneAccount.CAPABILITY_CALL_PROVIDER) ||
                 account.hasCapabilities(PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION)) {
@@ -333,7 +334,7 @@
     @Override
     public void unregisterPhoneAccount(PhoneAccountHandle accountHandle) {
         try {
-            enforceModifyPermissionOrCallingPackage(
+            enforcePhoneAccountModificationForPackage(
                     accountHandle.getComponentName().getPackageName());
             mPhoneAccountRegistrar.unregisterPhoneAccount(accountHandle);
         } catch (Exception e) {
@@ -345,7 +346,7 @@
     @Override
     public void clearAccounts(String packageName) {
         try {
-            enforceModifyPermissionOrCallingPackage(packageName);
+            enforcePhoneAccountModificationForPackage(packageName);
             mPhoneAccountRegistrar.clearAccounts(packageName);
         } catch (Exception e) {
             Log.e(this, e, "clearAccounts %s", packageName);
@@ -531,51 +532,69 @@
         return false;
     }
 
-    /**
-     * Make sure the caller has the MODIFY_PHONE_STATE permission.
-     *
-     * @throws SecurityException if the caller does not have the required permission
-     */
-    private void enforceModifyPermission() {
-        TelecomApp.getInstance().enforceCallingOrSelfPermission(
-                android.Manifest.permission.MODIFY_PHONE_STATE, null);
-    }
+    private void enforcePhoneAccountModificationForPackage(String packageName) {
+        // TODO: Use a new telecomm permission for this instead of reusing modify.
 
-    private void enforceModifyPermissionOrDefaultDialer() {
-        if (!isDefaultDialerCalling()) {
-            enforceModifyPermission();
-        }
-    }
+        int result = TelecomApp.getInstance().checkCallingOrSelfPermission(
+                Manifest.permission.MODIFY_PHONE_STATE);
 
-    private void enforceRegisterProviderOrSubscriptionPermission() {
-        TelecomApp.getInstance().enforceCallingOrSelfPermission(
-                REGISTER_PROVIDER_OR_SUBSCRIPTION, null);
-    }
+        // Callers with MODIFY_PHONE_STATE can use the PhoneAccount mechanism to implement
+        // built-in behavior even when PhoneAccounts are not exposed as a third-part API. They
+        // may also modify PhoneAccounts on behalf of any 'packageName'.
 
-    private void enforceModifyPermissionOrCallingPackage(String packageName) {
-        // TODO: Use a new telecom permission for this instead of reusing modify.
-        try {
-            enforceModifyPermission();
-        } catch (SecurityException e) {
+        if (result != PackageManager.PERMISSION_GRANTED) {
+            // Other callers are only allowed to modify PhoneAccounts if the relevant system
+            // feature is enabled ...
+            enforceConnectionServiceFeature();
+            // ... and the PhoneAccounts they refer to are for their own package.
             enforceCallingPackage(packageName);
         }
     }
 
-    private void enforceReadPermission() {
-        TelecomApp.getInstance().enforceCallingOrSelfPermission(
-                android.Manifest.permission.READ_PHONE_STATE, null);
-    }
-
     private void enforceReadPermissionOrDefaultDialer() {
         if (!isDefaultDialerCalling()) {
             enforceReadPermission();
         }
     }
 
+    private void enforceModifyPermissionOrDefaultDialer() {
+        if (!isDefaultDialerCalling()) {
+            enforceModifyPermission();
+        }
+    }
+
     private void enforceCallingPackage(String packageName) {
         mAppOpsManager.checkPackage(Binder.getCallingUid(), packageName);
     }
 
+    private void enforceConnectionServiceFeature() {
+        enforceFeature(PackageManager.FEATURE_CONNECTION_SERVICE);
+    }
+
+    private void enforceRegisterProviderOrSubscriptionPermission() {
+        enforcePermission(REGISTER_PROVIDER_OR_SUBSCRIPTION);
+    }
+
+    private void enforceReadPermission() {
+        enforcePermission(Manifest.permission.READ_PHONE_STATE);
+    }
+
+    private void enforceModifyPermission() {
+        enforcePermission(Manifest.permission.MODIFY_PHONE_STATE);
+    }
+
+    private void enforcePermission(String permission) {
+        TelecomApp.getInstance().enforceCallingOrSelfPermission(permission, null);
+    }
+
+    private void enforceFeature(String feature) {
+        PackageManager pm = TelecomApp.getInstance().getPackageManager();
+        if (!pm.hasSystemFeature(feature)) {
+            throw new UnsupportedOperationException(
+                    "System does not support feature " + feature);
+        }
+    }
+
     private boolean isDefaultDialerCalling() {
         ComponentName defaultDialerComponent = getDefaultPhoneApp();
         if (defaultDialerComponent != null) {