Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit c72d63df authored by Hall Liu's avatar Hall Liu
Browse files

Hide actions and number in disconnect notification

When an emergency call is disconnected because another outgoing
emergency call was made, do not show the number called for privacy
reasons, and do not include the "call back" and "message" intents to
avoid pocket dials.

Fixes: 150278492
Test: atest TelecomUnitTests:DisconnectedCallNotifierTest
Test: manual
Change-Id: Id8585d05de1448f0aabc54aa0a848f5ff84ade7c
parent 0cd4c9b4
Loading
Loading
Loading
Loading
+7 −0
Original line number Diff line number Diff line
@@ -55,6 +55,13 @@
    <!-- Body of the notification presented when an ongoing call is disconnected in favor of placing
         an emergency call. This is required by some carriers. [CHAR LIMIT=NONE] -->
    <string name="notification_disconnectedCall_body">The call to <xliff:g id="caller">%s</xliff:g> has been disconnected due to an emergency call being placed.</string>
    <!-- Body of the notification presented when an ongoing call is disconnected in favor of placing
         an emergency call. This version is used when the call that was disconnected was also an
         emergency call. In this case, we want to hide the exact number dialed in order to protect
         user privacy. [CHAR LIMIT=NONE] -->
    <string name="notification_disconnectedCall_generic_body">
        Your call has been disconnected due to an emergency call being placed.
    </string>

    <!-- Title for the persistent notification presented when an app has requested that a call
         be put into the background so that the app can access the audio from the call
+19 −7
Original line number Diff line number Diff line
@@ -78,15 +78,17 @@ public class DisconnectedCallNotifier extends CallsManagerListenerBase {
        public final Bitmap callerInfoIcon;
        public final Drawable callerInfoPhoto;
        public final String callerInfoName;
        public final boolean isEmergency;

        public CallInfo(UserHandle userHandle, Uri handle, long endTimeMs, Bitmap callerInfoIcon,
                Drawable callerInfoPhoto, String callerInfoName) {
                Drawable callerInfoPhoto, String callerInfoName, boolean isEmergency) {
            this.userHandle = userHandle;
            this.handle = handle;
            this.endTimeMs = endTimeMs;
            this.callerInfoIcon = callerInfoIcon;
            this.callerInfoPhoto = callerInfoPhoto;
            this.callerInfoName = callerInfoName;
            this.isEmergency = isEmergency;
        }

        @Override
@@ -94,6 +96,7 @@ public class DisconnectedCallNotifier extends CallsManagerListenerBase {
            return "CallInfo{" +
                    "userHandle=" + userHandle +
                    ", handle=" + handle +
                    ", isEmergency=" + isEmergency +
                    ", endTimeMs=" + endTimeMs +
                    ", callerInfoIcon=" + callerInfoIcon +
                    ", callerInfoPhoto=" + callerInfoPhoto +
@@ -146,7 +149,7 @@ public class DisconnectedCallNotifier extends CallsManagerListenerBase {
            if (userHandle == null) userHandle = mCallsManager.getCurrentUserHandle();
            mPendingCallNotification = new CallInfo(userHandle, call.getHandle(),
                    call.getCreationTimeMillis() + call.getAgeMillis(), call.getPhotoIcon(),
                    call.getPhoto(), call.getName());
                    call.getPhoto(), call.getName(), call.isEmergencyCall());
        }
    }

@@ -154,7 +157,9 @@ public class DisconnectedCallNotifier extends CallsManagerListenerBase {
        Log.i(this, "showDisconnectedNotification: userHandle=%d", call.userHandle.getIdentifier());

        final int titleResId = R.string.notification_disconnectedCall_title;
        final String expandedText = mContext.getString(R.string.notification_disconnectedCall_body,
        final CharSequence expandedText = call.isEmergency
                ? mContext.getText(R.string.notification_disconnectedCall_generic_body)
                : mContext.getString(R.string.notification_disconnectedCall_body,
                        getNameForCallNotification(call));

        // Create a public viewable version of the notification, suitable for display when sensitive
@@ -173,9 +178,12 @@ public class DisconnectedCallNotifier extends CallsManagerListenerBase {
                // Notification details shows that there are disconnected call(s), but does not
                // reveal the caller information.
                .setContentText(mContext.getText(titleResId))
                .setContentIntent(createCallLogPendingIntent(call.userHandle))
                .setAutoCancel(true);

        if (!call.isEmergency) {
            publicBuilder.setContentIntent(createCallLogPendingIntent(call.userHandle));
        }

        // Create the notification suitable for display when sensitive information is showing.
        Notification.Builder builder = new Notification.Builder(contextForUser,
                NotificationChannelManager.CHANNEL_ID_DISCONNECTED_CALLS);
@@ -186,7 +194,6 @@ public class DisconnectedCallNotifier extends CallsManagerListenerBase {
                .setContentTitle(mContext.getText(titleResId))
                //Only show expanded text for sensitive information
                .setStyle(new Notification.BigTextStyle().bigText(expandedText))
                .setContentIntent(createCallLogPendingIntent(call.userHandle))
                .setAutoCancel(true)
                // Include a public version of the notification to be shown when the call
                // notification is shown on the user's lock screen and they have chosen to hide
@@ -194,10 +201,15 @@ public class DisconnectedCallNotifier extends CallsManagerListenerBase {
                .setPublicVersion(publicBuilder.build())
                .setChannelId(NotificationChannelManager.CHANNEL_ID_DISCONNECTED_CALLS);

        if (!call.isEmergency) {
            builder.setContentIntent(createCallLogPendingIntent(call.userHandle));
        }

        String handle = call.handle != null ? call.handle.getSchemeSpecificPart() : null;

        if (!TextUtils.isEmpty(handle)
                && !TextUtils.equals(handle, mContext.getString(R.string.handle_restricted))) {
                && !TextUtils.equals(handle, mContext.getString(R.string.handle_restricted))
                && !call.isEmergency) {
            builder.addAction(new Notification.Action.Builder(
                    Icon.createWithResource(contextForUser, R.drawable.ic_phone_24dp),
                    // Reuse missed call "Call back"
+33 −0
Original line number Diff line number Diff line
package com.android.server.telecom.tests;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyString;
@@ -31,6 +34,7 @@ import com.android.server.telecom.ui.DisconnectedCallNotifier;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;

import java.util.Collections;
@@ -82,8 +86,37 @@ public class DisconnectedCallNotifierTest extends TelecomTestCase {

        doReturn(Collections.EMPTY_LIST).when(mCallsManager).getCalls();
        notifier.onCallRemoved(call);
        ArgumentCaptor<Notification> captor = ArgumentCaptor.forClass(Notification.class);
        verify(mNotificationManager).notifyAsUser(anyString(), anyInt(),
                captor.capture(), any(UserHandle.class));
        Notification notification = captor.getValue();
        assertNotNull(notification.contentIntent);
        assertEquals(2, notification.actions.length);
    }

    @Test
    @SmallTest
    public void testNotificationShownForDisconnectedEmergencyCall() {
        Call call = createCall(new DisconnectCause(DisconnectCause.LOCAL,
                DisconnectCause.REASON_EMERGENCY_CALL_PLACED));
        when(call.isEmergencyCall()).thenReturn(true);

        DisconnectedCallNotifier notifier = new DisconnectedCallNotifier(mContext, mCallsManager);
        notifier.onCallStateChanged(call, CallState.NEW, CallState.DIALING);
        notifier.onCallStateChanged(call, CallState.DIALING, CallState.DISCONNECTED);
        verify(mNotificationManager, never()).notifyAsUser(anyString(), anyInt(),
                any(Notification.class), any(UserHandle.class));

        doReturn(Collections.EMPTY_LIST).when(mCallsManager).getCalls();
        notifier.onCallRemoved(call);
        ArgumentCaptor<Notification> captor = ArgumentCaptor.forClass(Notification.class);
        verify(mNotificationManager).notifyAsUser(anyString(), anyInt(),
                captor.capture(), any(UserHandle.class));
        Notification notification = captor.getValue();
        assertNull(notification.contentIntent);
        if (notification.actions != null) {
            assertEquals(0, notification.actions.length);
        }
    }

    @Test