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

Commit ff0df830 authored by Nate Myren's avatar Nate Myren
Browse files

Add debounce to start of phone call ops

Wait 250ms before starting PHONE_CALL ops. This gives time for apps like
dialer or Fi to mute the microphone or take over the call.
Test: manual
Fixes: 192076383

Change-Id: I729c318aada005f41d6fd43d52e1d18748c33e25
parent 8e75b865
Loading
Loading
Loading
Loading
+38 −7
Original line number Diff line number Diff line
@@ -45,6 +45,7 @@ import android.os.RemoteException;
import android.os.Trace;
import android.os.UserHandle;
import android.os.UserManager;
import android.provider.DeviceConfig;
import android.telecom.CallAudioState;
import android.telecom.ConnectionService;
import android.telecom.InCallService;
@@ -83,8 +84,8 @@ import java.util.stream.Collectors;
 */
public class InCallController extends CallsManagerListenerBase implements
        AppOpsManager.OnOpActiveChangedListener {
    public static final int IN_CALL_SERVICE_NOTIFICATION_ID = 3;
    public static final String NOTIFICATION_TAG = InCallController.class.getSimpleName();
    public static final int IN_CALL_SERVICE_NOTIFICATION_ID = 3;

    public class InCallServiceConnection {
        /**
@@ -1005,6 +1006,14 @@ public class InCallController extends CallsManagerListenerBase implements
     */
    private boolean mIsCallUsingMicrophone = false;

    /**
     * {@code true} if InCallController is tracking a managed, not external call which is using the
     * microphone, {@code false} otherwise.
     */
    private boolean mIsTrackingManagedAliveCall = false;

    private boolean mIsStartCallDelayScheduled = false;

    /**
     * A list of call IDs which are currently using the camera.
     */
@@ -2210,16 +2219,38 @@ public class InCallController extends CallsManagerListenerBase implements
        Log.i(this, "trackCallingUserInterfaceStopped: %s is no longer calling UX", packageName);
    }

    private void maybeTrackMicrophoneUse(boolean isMuted) {
        maybeTrackMicrophoneUse(isMuted, false);
    }

    /**
     * As calls are added, removed and change between external and non-external status, track
     * whether the current active calling UX is using the microphone.  We assume if there is a
     * managed call present and the mic is not muted that the microphone is in use.
     */
    private void maybeTrackMicrophoneUse(boolean isMuted) {
        boolean wasTrackingManagedCall = mIsCallUsingMicrophone;
        mIsCallUsingMicrophone = isTrackingManagedAliveCall() && !isMuted
                && !carrierPrivilegedUsingMicDuringVoipCall();
        if (wasTrackingManagedCall != mIsCallUsingMicrophone) {
    private void maybeTrackMicrophoneUse(boolean isMuted, boolean isScheduledDelay) {
        if (mIsStartCallDelayScheduled && !isScheduledDelay) {
            return;
        }

        mIsStartCallDelayScheduled = false;
        boolean wasUsingMicrophone = mIsCallUsingMicrophone;
        boolean wasTrackingCall = mIsTrackingManagedAliveCall;
        mIsTrackingManagedAliveCall = isTrackingManagedAliveCall();
        if (!wasTrackingCall && mIsTrackingManagedAliveCall) {
            mIsStartCallDelayScheduled = true;
            mHandler.postDelayed(new Runnable("ICC.mTMU", mLock) {
                @Override
                public void loggedRun() {
                    maybeTrackMicrophoneUse(isMuted(), true);
                }
            }.prepare(), mTimeoutsAdapter.getCallStartAppOpDebounceIntervalMillis());
            return;
        }

        mIsCallUsingMicrophone = mIsTrackingManagedAliveCall && !isMuted
                && !isCarrierPrivilegedUsingMicDuringVoipCall();
        if (wasUsingMicrophone != mIsCallUsingMicrophone) {
            if (mIsCallUsingMicrophone) {
                mAppOpsManager.startOp(AppOpsManager.OP_PHONE_CALL_MICROPHONE, myUid(),
                        mContext.getOpPackageName(), false, null, null);
@@ -2240,7 +2271,7 @@ public class InCallController extends CallsManagerListenerBase implements
                c.getState()));
    }

    private boolean carrierPrivilegedUsingMicDuringVoipCall() {
    private boolean isCarrierPrivilegedUsingMicDuringVoipCall() {
        return !mActiveCarrierPrivilegedApps.isEmpty() &&
                mCallIdMapper.getCalls().stream().anyMatch(Call::getIsVoipAudioMode);
    }
+9 −0
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@
package com.android.server.telecom;

import android.content.ContentResolver;
import android.provider.DeviceConfig;
import android.provider.Settings;
import android.telecom.CallDiagnosticService;
import android.telecom.CallRedirectionService;
@@ -75,6 +76,10 @@ public final class Timeouts {
        public long getCallDiagnosticServiceTimeoutMillis(ContentResolver cr) {
            return Timeouts.getCallDiagnosticServiceTimeoutMillis(cr);
        }

        public long getCallStartAppOpDebounceIntervalMillis() {
            return  Timeouts.getCallStartAppOpDebounceIntervalMillis();
        }
    }

    /** A prefix to use for all keys so to not clobber the global namespace. */
@@ -232,6 +237,10 @@ public final class Timeouts {
        return get(contentResolver, "call_diagnostic_service_timeout", 2000L /* 2 sec */);
    }

    public static long getCallStartAppOpDebounceIntervalMillis() {
        return DeviceConfig.getLong(DeviceConfig.NAMESPACE_PRIVACY, "app_op_debounce_time", 250L);
    }

    /**
     * Returns the number of milliseconds for which the system should exempt the default dialer from
     * power save restrictions due to the dialer needing to handle a missed call notification