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

Commit 35ab806b authored by Pranav Madapurmath's avatar Pranav Madapurmath
Browse files

Allow return to call from keyguard UI.

When placing emergency calls from the keyguard UI and the device has a
lock, the user should be able to return to the call from the keyguard
UI at any time. Note that the keyguard UI belongs to the system user.

With the changes to handle multi-user calling scenarios,
a system user would not be able to access the available ICS for other
users (secondary/guest/work profiles), preventing the user from being
able to return to the call from the keyguard UI.

This CL ensures that the system user can access these calls with the
precondition that the device is currently locked and the ongoing call is
an emergency call. This also handles the work profile case when the
admin has also set a lock on the device and the user needs to be able to
return to the work profile emergency call.

Bug: 306582821
Test: atest TelecomUnitTests
Test: Manual to confirm that we are able to return to the ECC from the
keyguard UI for secondary/guest users as well as for work profiles.
Confirmed that the issue exists on the aforementioned profiles without
the change. For the work profile case, the user would need to place the
ECC when the device is unlocked and once it is locked, the user wouldn't
be able to return to the call.

Change-Id: I5d4b42fd162fa981c6f9cfe713815016ee0c5d92
parent da111027
Loading
Loading
Loading
Loading
+7 −0
Original line number Diff line number Diff line
@@ -6,3 +6,10 @@ flag {
  description: "Binds to InCallServices when call requires no call filtering on watch"
  bug: "282113261"
}

flag {
  name: "ecc_keyguard"
  namespace: "telecom"
  description: "Ensure that users are able to return to call from keyguard UI for ECC"
  bug: "306582821"
}
 No newline at end of file
+29 −2
Original line number Diff line number Diff line
@@ -22,7 +22,9 @@ import static android.os.Process.myUid;
import android.Manifest;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.ActivityManager;
import android.app.AppOpsManager;
import android.app.KeyguardManager;
import android.app.Notification;
import android.app.NotificationManager;
import android.content.AttributionSource;
@@ -47,7 +49,6 @@ import android.os.RemoteException;
import android.os.Trace;
import android.os.UserHandle;
import android.os.UserManager;
import android.permission.PermissionManager;
import android.telecom.CallAudioState;
import android.telecom.CallEndpoint;
import android.telecom.ConnectionService;
@@ -66,6 +67,7 @@ import com.android.internal.telecom.IInCallService;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.IndentingPrintWriter;
import com.android.server.telecom.SystemStateHelper.SystemStateListener;
import com.android.server.telecom.flags.FeatureFlags;
import com.android.server.telecom.ui.NotificationChannelManager;

import java.util.ArrayList;
@@ -1237,11 +1239,12 @@ public class InCallController extends CallsManagerListenerBase implements

    private ArraySet<String> mAllCarrierPrivilegedApps = new ArraySet<>();
    private ArraySet<String> mActiveCarrierPrivilegedApps = new ArraySet<>();
    private FeatureFlags mFeatureFlags;

    public InCallController(Context context, TelecomSystem.SyncRoot lock, CallsManager callsManager,
            SystemStateHelper systemStateHelper, DefaultDialerCache defaultDialerCache,
            Timeouts.Adapter timeoutsAdapter, EmergencyCallHelper emergencyCallHelper,
            CarModeTracker carModeTracker, ClockProxy clockProxy) {
            CarModeTracker carModeTracker, ClockProxy clockProxy, FeatureFlags featureFlags) {
        mContext = context;
        mAppOpsManager = context.getSystemService(AppOpsManager.class);
        mSensorPrivacyManager = context.getSystemService(SensorPrivacyManager.class);
@@ -1258,6 +1261,7 @@ public class InCallController extends CallsManagerListenerBase implements
        IntentFilter userAddedFilter = new IntentFilter(Intent.ACTION_USER_ADDED);
        userAddedFilter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
        mContext.registerReceiver(mUserAddedReceiver, userAddedFilter);
        mFeatureFlags = featureFlags;
    }

    private void restrictPhoneCallOps() {
@@ -1690,6 +1694,29 @@ public class InCallController extends CallsManagerListenerBase implements

    @VisibleForTesting
    public void bringToForeground(boolean showDialpad, UserHandle callingUser) {
        KeyguardManager keyguardManager = mContext.getSystemService(KeyguardManager.class);
        boolean isLockscreenRestricted = keyguardManager != null
                && keyguardManager.isKeyguardLocked();
        UserHandle currentUser = mCallsManager.getCurrentUserHandle();
        // Handle cases when calls are placed from the keyguard UI screen, which operates under
        // the admin user. This needs to account for emergency calls placed from secondary/guest
        // users as well as the work profile. Once the screen is locked, the user should be able to
        // return to the call (from the keyguard UI).
        if (mFeatureFlags.eccKeyguard() && mCallsManager.isInEmergencyCall()
                && isLockscreenRestricted && !mInCallServices.containsKey(callingUser)) {
            // If screen is locked and the current user is the system, query calls for the work
            // profile user, if available. Otherwise, the user is in the secondary/guest profile,
            // so we can default to the system user.
            if (currentUser.isSystem()) {
                UserManager um = mContext.getSystemService(UserManager.class);
                UserHandle workProfileUser = findChildManagedProfileUser(currentUser, um);
                boolean hasWorkCalls = mCallsManager.getCalls().stream()
                        .filter((c) -> getUserFromCall(c).equals(workProfileUser)).count() > 0;
                callingUser = hasWorkCalls ? workProfileUser : currentUser;
            } else {
                callingUser = currentUser;
            }
        }
        if (mInCallServices.containsKey(callingUser)) {
            for (IInCallService inCallService : mInCallServices.get(callingUser).values()) {
                try {
+1 −1
Original line number Diff line number Diff line
@@ -294,7 +294,7 @@ public class TelecomSystem {
                        EmergencyCallHelper emergencyCallHelper) {
                    return new InCallController(context, lock, callsManager, systemStateProvider,
                            defaultDialerCache, timeoutsAdapter, emergencyCallHelper,
                            new CarModeTracker(), clockProxy);
                            new CarModeTracker(), clockProxy, featureFlags);
                }
            };

+1 −3
Original line number Diff line number Diff line
@@ -28,7 +28,6 @@ import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.anyObject;
import static org.mockito.ArgumentMatchers.argThat;
import static org.mockito.ArgumentMatchers.matches;
import static org.mockito.ArgumentMatchers.nullable;
@@ -36,7 +35,6 @@ import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyInt;
import static org.mockito.Matchers.anyString;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
@@ -236,7 +234,7 @@ public class InCallControllerTests extends TelecomTestCase {
                "com.android.server.telecom.tests", null));
        mInCallController = new InCallController(mMockContext, mLock, mMockCallsManager,
                mMockSystemStateHelper, mDefaultDialerCache, mTimeoutsAdapter,
                mEmergencyCallHelper, mCarModeTracker, mClockProxy);
                mEmergencyCallHelper, mCarModeTracker, mClockProxy, mFeatureFlags);
        // Capture the broadcast receiver registered.
        doAnswer(invocation -> {
            mRegisteredReceiver = invocation.getArgument(0);