DO NOT MERGE - Merge qt-qpr1-dev-plus-aosp-without-vendor (6129114) into stage-aosp-master

Bug: 146167222
Change-Id: Ife93594158dbd0b15cf06fabcfd5a8512093f4a2
diff --git a/src/com/android/server/telecom/Call.java b/src/com/android/server/telecom/Call.java
index 86a0c3a..8773ea2 100644
--- a/src/com/android/server/telecom/Call.java
+++ b/src/com/android/server/telecom/Call.java
@@ -136,6 +136,7 @@
         void onPhoneAccountChanged(Call call);
         void onConferenceableCallsChanged(Call call);
         void onConferenceStateChanged(Call call, boolean isConference);
+        void onCdmaConferenceSwap(Call call);
         boolean onCanceledViaNewOutgoingCallBroadcast(Call call, long disconnectionTimeout);
         void onHoldToneRequested(Call call);
         void onCallHoldFailed(Call call);
@@ -208,6 +209,8 @@
         @Override
         public void onConferenceStateChanged(Call call, boolean isConference) {}
         @Override
+        public void onCdmaConferenceSwap(Call call) {}
+        @Override
         public boolean onCanceledViaNewOutgoingCallBroadcast(Call call, long disconnectionTimeout) {
             return false;
         }
@@ -2413,6 +2416,9 @@
                     mConferenceLevelActiveCall = null;
                     break;
             }
+            for (Listener l : mListeners) {
+                l.onCdmaConferenceSwap(this);
+            }
         }
     }
 
diff --git a/src/com/android/server/telecom/CallsManager.java b/src/com/android/server/telecom/CallsManager.java
index afd1c6b..e8b7939 100644
--- a/src/com/android/server/telecom/CallsManager.java
+++ b/src/com/android/server/telecom/CallsManager.java
@@ -166,6 +166,7 @@
         void onDisconnectedTonePlaying(boolean isTonePlaying);
         void onConnectionTimeChanged(Call call);
         void onConferenceStateChanged(Call call, boolean isConference);
+        void onCdmaConferenceSwap(Call call);
     }
 
     /** Interface used to define the action which is executed delay under some condition. */
@@ -929,6 +930,14 @@
     }
 
     @Override
+    public void onCdmaConferenceSwap(Call call) {
+        // SWAP was executed on a CDMA conference
+        for (CallsManagerListener listener : mListeners) {
+            listener.onCdmaConferenceSwap(call);
+        }
+    }
+
+    @Override
     public void onIsVoipAudioModeChanged(Call call) {
         for (CallsManagerListener listener : mListeners) {
             listener.onIsVoipAudioModeChanged(call);
diff --git a/src/com/android/server/telecom/CallsManagerListenerBase.java b/src/com/android/server/telecom/CallsManagerListenerBase.java
index 4fa2ee5..e0d2831 100644
--- a/src/com/android/server/telecom/CallsManagerListenerBase.java
+++ b/src/com/android/server/telecom/CallsManagerListenerBase.java
@@ -100,4 +100,8 @@
     @Override
     public void onConferenceStateChanged(Call call, boolean isConference) {
     }
+
+    @Override
+    public void onCdmaConferenceSwap(Call call) {
+    }
 }
diff --git a/src/com/android/server/telecom/InCallController.java b/src/com/android/server/telecom/InCallController.java
index 9fc06e4..b18c6ff 100644
--- a/src/com/android/server/telecom/InCallController.java
+++ b/src/com/android/server/telecom/InCallController.java
@@ -865,7 +865,7 @@
                         info.isExternalCallsSupported(), includeRttCall,
                         info.getType() == IN_CALL_SERVICE_TYPE_SYSTEM_UI);
                 try {
-                    inCallService.addCall(parcelableCall);
+                    inCallService.addCall(sanitizeParcelableCallForService(info, parcelableCall));
                 } catch (RemoteException ignored) {
                 }
             }
@@ -929,7 +929,7 @@
                         info.isExternalCallsSupported(), includeRttCall,
                         info.getType() == IN_CALL_SERVICE_TYPE_SYSTEM_UI);
                 try {
-                    inCallService.addCall(parcelableCall);
+                    inCallService.addCall(sanitizeParcelableCallForService(info, parcelableCall));
                 } catch (RemoteException ignored) {
                 }
             }
@@ -961,7 +961,8 @@
                         );
 
                 try {
-                    inCallService.updateCall(parcelableCall);
+                    inCallService.updateCall(
+                            sanitizeParcelableCallForService(info, parcelableCall));
                 } catch (RemoteException ignored) {
                 }
             }
@@ -1046,6 +1047,12 @@
         updateCall(call);
     }
 
+    @Override
+    public void onCdmaConferenceSwap(Call call) {
+        Log.d(this, "onCdmaConferenceSwap %s", call);
+        updateCall(call);
+    }
+
     void bringToForeground(boolean showDialpad) {
         if (!mInCallServices.isEmpty()) {
             for (IInCallService inCallService : mInCallServices.values()) {
@@ -1446,13 +1453,14 @@
                 // Track the call if we don't already know about it.
                 addCall(call);
                 numCallsSent += 1;
-                inCallService.addCall(ParcelableCallUtils.toParcelableCall(
+                ParcelableCall parcelableCall = ParcelableCallUtils.toParcelableCall(
                         call,
                         true /* includeVideoProvider */,
                         mCallsManager.getPhoneAccountRegistrar(),
                         info.isExternalCallsSupported(),
                         includeRttCall,
-                        info.getType() == IN_CALL_SERVICE_TYPE_SYSTEM_UI));
+                        info.getType() == IN_CALL_SERVICE_TYPE_SYSTEM_UI);
+                inCallService.addCall(sanitizeParcelableCallForService(info, parcelableCall));
             } catch (RemoteException ignored) {
             }
         }
@@ -1522,7 +1530,8 @@
                 componentsUpdated.add(componentName);
 
                 try {
-                    inCallService.updateCall(parcelableCall);
+                    inCallService.updateCall(
+                            sanitizeParcelableCallForService(info, parcelableCall));
                 } catch (RemoteException ignored) {
                 }
             }
@@ -1654,6 +1663,21 @@
         return childCalls;
     }
 
+    private ParcelableCall sanitizeParcelableCallForService(
+            InCallServiceInfo info, ParcelableCall parcelableCall) {
+        ParcelableCall.ParcelableCallBuilder builder =
+                ParcelableCall.ParcelableCallBuilder.fromParcelableCall(parcelableCall);
+        // Check for contacts permission. If it's not there, remove the contactsDisplayName.
+        PackageManager pm = mContext.getPackageManager();
+        if (pm.checkPermission(Manifest.permission.READ_CONTACTS,
+                info.getComponentName().getPackageName()) != PackageManager.PERMISSION_GRANTED) {
+            builder.setContactDisplayName(null);
+        }
+
+        // TODO: move all the other service-specific sanitizations in here
+        return builder.createParcelableCall();
+    }
+
     @VisibleForTesting
     public Handler getHandler() {
         return mHandler;
diff --git a/src/com/android/server/telecom/ParcelableCallUtils.java b/src/com/android/server/telecom/ParcelableCallUtils.java
index d490cd2..69d9c5e 100644
--- a/src/com/android/server/telecom/ParcelableCallUtils.java
+++ b/src/com/android/server/telecom/ParcelableCallUtils.java
@@ -29,14 +29,10 @@
 import android.telecom.TelecomManager;
 import android.text.TextUtils;
 
-import com.android.internal.annotations.VisibleForTesting;
-
 import java.util.ArrayList;
 import java.util.Collections;
-import java.util.HashMap;
 import java.util.Iterator;
 import java.util.List;
-import java.util.Map;
 
 /**
  * Utilities dealing with {@link ParcelableCall}.
@@ -224,6 +220,11 @@
             callDirection = DIRECTION_OUTGOING;
         }
 
+        String activeChildCallId = null;
+        if (call.getConferenceLevelActiveCall() != null) {
+            activeChildCallId = call.getConferenceLevelActiveCall().getId();
+        }
+
         Bundle extras;
         if (isForSystemDialer) {
             extras = call.getExtras();
@@ -231,35 +232,38 @@
             extras = sanitizeExtras(call.getExtras());
         }
 
-        return new ParcelableCall(
-                call.getId(),
-                state,
-                call.getDisconnectCause(),
-                call.getCannedSmsResponses(),
-                capabilities,
-                properties,
-                supportedAudioRoutes,
-                connectTimeMillis,
-                handle,
-                call.getHandlePresentation(),
-                callerDisplayName,
-                call.getCallerDisplayNamePresentation(),
-                call.getGatewayInfo(),
-                call.getTargetPhoneAccount(),
-                includeVideoProvider,
-                includeVideoProvider ? call.getVideoProvider() : null,
-                includeRttCall,
-                rttCall,
-                parentCallId,
-                childCallIds,
-                call.getStatusHints(),
-                call.getVideoState(),
-                conferenceableCallIds,
-                call.getIntentExtras(),
-                extras,
-                call.getCreationTimeMillis(),
-                callDirection,
-                call.getCallerNumberVerificationStatus());
+        return new ParcelableCall.ParcelableCallBuilder()
+                .setId(call.getId())
+                .setState(state)
+                .setDisconnectCause(call.getDisconnectCause())
+                .setCannedSmsResponses(call.getCannedSmsResponses())
+                .setCapabilities(capabilities)
+                .setProperties(properties)
+                .setSupportedAudioRoutes(supportedAudioRoutes)
+                .setConnectTimeMillis(connectTimeMillis)
+                .setHandle(handle)
+                .setHandlePresentation(call.getHandlePresentation())
+                .setCallerDisplayName(callerDisplayName)
+                .setCallerDisplayNamePresentation(call.getCallerDisplayNamePresentation())
+                .setGatewayInfo(call.getGatewayInfo())
+                .setAccountHandle(call.getTargetPhoneAccount())
+                .setIsVideoCallProviderChanged(includeVideoProvider)
+                .setVideoCallProvider(includeVideoProvider ? call.getVideoProvider() : null)
+                .setIsRttCallChanged(includeRttCall)
+                .setRttCall(rttCall)
+                .setParentCallId(parentCallId)
+                .setChildCallIds(childCallIds)
+                .setStatusHints(call.getStatusHints())
+                .setVideoState(call.getVideoState())
+                .setConferenceableCallIds(conferenceableCallIds)
+                .setIntentExtras(call.getIntentExtras())
+                .setExtras(extras)
+                .setCreationTimeMillis(call.getCreationTimeMillis())
+                .setCallDirection(callDirection)
+                .setCallerNumberVerificationStatus(call.getCallerNumberVerificationStatus())
+                .setContactDisplayName(call.getName())
+                .setActiveChildCallId(activeChildCallId)
+                .createParcelableCall();
     }
 
     /**
@@ -303,35 +307,38 @@
             callExtras = new Bundle();
         }
 
-        return new ParcelableCall(
-                call.getId(),
-                getParcelableState(call, false /* supportsExternalCalls */),
-                new DisconnectCause(DisconnectCause.UNKNOWN),
-                null, /* cannedSmsResponses */
-                0, /* capabilities */
-                0, /* properties */
-                0, /* supportedAudioRoutes */
-                call.getConnectTimeMillis(),
-                handle,
-                call.getHandlePresentation(),
-                null, /* callerDisplayName */
-                0 /* callerDisplayNamePresentation */,
-                null, /* gatewayInfo */
-                null, /* targetPhoneAccount */
-                false, /* includeVideoProvider */
-                null, /* videoProvider */
-                false, /* includeRttCall */
-                null, /* rttCall */
-                null, /* parentCallId */
-                null, /* childCallIds */
-                null, /* statusHints */
-                0, /* videoState */
-                Collections.emptyList(), /* conferenceableCallIds */
-                null, /* intentExtras */
-                callExtras, /* callExtras */
-                call.getCreationTimeMillis(),
-                callDirection,
-                call.getCallerNumberVerificationStatus());
+        return new ParcelableCall.ParcelableCallBuilder()
+                .setId(call.getId())
+                .setState(getParcelableState(call, false /* supportsExternalCalls */))
+                .setDisconnectCause(new DisconnectCause(DisconnectCause.UNKNOWN))
+                .setCannedSmsResponses(null)
+                .setCapabilities(0)
+                .setProperties(0)
+                .setSupportedAudioRoutes(0)
+                .setConnectTimeMillis(call.getConnectTimeMillis())
+                .setHandle(handle)
+                .setHandlePresentation(call.getHandlePresentation())
+                .setCallerDisplayName(null)
+                .setCallerDisplayNamePresentation(0)
+                .setGatewayInfo(null)
+                .setAccountHandle(null)
+                .setIsVideoCallProviderChanged(false)
+                .setVideoCallProvider(null)
+                .setIsRttCallChanged(false)
+                .setRttCall(null)
+                .setParentCallId(null)
+                .setChildCallIds(null)
+                .setStatusHints(null)
+                .setVideoState(0)
+                .setConferenceableCallIds(Collections.emptyList())
+                .setIntentExtras(null)
+                .setExtras(callExtras)
+                .setCreationTimeMillis(call.getCreationTimeMillis())
+                .setCallDirection(callDirection)
+                .setCallerNumberVerificationStatus(call.getCallerNumberVerificationStatus())
+                .setContactDisplayName(null)
+                .setActiveChildCallId(null)
+                .createParcelableCall();
     }
 
     /**
diff --git a/tests/src/com/android/server/telecom/tests/InCallControllerTests.java b/tests/src/com/android/server/telecom/tests/InCallControllerTests.java
index ed36d29..23d22e9 100644
--- a/tests/src/com/android/server/telecom/tests/InCallControllerTests.java
+++ b/tests/src/com/android/server/telecom/tests/InCallControllerTests.java
@@ -625,6 +625,44 @@
         verifyBinding(bindIntentCaptor, 0, DEF_PKG, DEF_CLASS);
     }
 
+    @MediumTest
+    @Test
+    public void testSanitizeContactName() throws Exception {
+        setupMocks(false /* isExternalCall */);
+        setupMockPackageManager(true /* default */, true /* system */, true /* external calls */);
+        when(mMockPackageManager.checkPermission(
+                matches(Manifest.permission.READ_CONTACTS),
+                matches(DEF_PKG))).thenReturn(PackageManager.PERMISSION_DENIED);
+        when(mMockCall.getName()).thenReturn("evil");
+
+        mInCallController.bindToServices(mMockCall);
+
+        // Bind InCallServices
+        ArgumentCaptor<Intent> bindIntentCaptor = ArgumentCaptor.forClass(Intent.class);
+        ArgumentCaptor<ServiceConnection> serviceConnectionCaptor =
+                ArgumentCaptor.forClass(ServiceConnection.class);
+        verify(mMockContext, times(1)).bindServiceAsUser(
+                bindIntentCaptor.capture(),
+                serviceConnectionCaptor.capture(),
+                eq(Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE
+                        | Context.BIND_ALLOW_BACKGROUND_ACTIVITY_STARTS),
+                eq(UserHandle.CURRENT));
+        assertEquals(1, bindIntentCaptor.getAllValues().size());
+        verifyBinding(bindIntentCaptor, 0, DEF_PKG, DEF_CLASS);
+
+        IInCallService.Stub mockInCallServiceStub = mock(IInCallService.Stub.class);
+        IInCallService mockInCallService = mock(IInCallService.class);
+        when(mockInCallServiceStub.queryLocalInterface(anyString())).thenReturn(mockInCallService);
+        serviceConnectionCaptor.getValue().onServiceConnected(new ComponentName(DEF_PKG, DEF_CLASS),
+                mockInCallServiceStub);
+
+        mInCallController.onCallAdded(mMockCall);
+        ArgumentCaptor<ParcelableCall> parcelableCallCaptor =
+                ArgumentCaptor.forClass(ParcelableCall.class);
+        verify(mockInCallService).addCall(parcelableCallCaptor.capture());
+        assertTrue(TextUtils.isEmpty(parcelableCallCaptor.getValue().getContactDisplayName()));
+    }
+
     /**
      * Ensures that the {@link InCallController} will bind to a higher priority car mode service
      * when one becomes available.