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
diff --git a/src/com/android/server/telecom/InCallController.java b/src/com/android/server/telecom/InCallController.java
index 9765c0e..c207940 100644
--- a/src/com/android/server/telecom/InCallController.java
+++ b/src/com/android/server/telecom/InCallController.java
@@ -45,6 +45,7 @@
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 @@
*/
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 {
/**
@@ -1006,6 +1007,14 @@
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.
*/
private ArrayList<String> mCallsUsingCamera = new ArrayList<>();
@@ -2210,16 +2219,38 @@
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 @@
c.getState()));
}
- private boolean carrierPrivilegedUsingMicDuringVoipCall() {
+ private boolean isCarrierPrivilegedUsingMicDuringVoipCall() {
return !mActiveCarrierPrivilegedApps.isEmpty() &&
mCallIdMapper.getCalls().stream().anyMatch(Call::getIsVoipAudioMode);
}
diff --git a/src/com/android/server/telecom/Timeouts.java b/src/com/android/server/telecom/Timeouts.java
index 4f35003..36caa25 100644
--- a/src/com/android/server/telecom/Timeouts.java
+++ b/src/com/android/server/telecom/Timeouts.java
@@ -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 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 @@
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