Merge "Cache call events to ensure that cap exchange events are not missed" into main
diff --git a/Android.bp b/Android.bp
index 94654a6..0d1c81d 100644
--- a/Android.bp
+++ b/Android.bp
@@ -84,9 +84,9 @@
"tests/res",
],
libs: [
- "android.test.mock",
- "android.test.base",
- "android.test.runner",
+ "android.test.mock.stubs.system",
+ "android.test.base.stubs.system",
+ "android.test.runner.stubs.system",
],
jni_libs: [
diff --git a/TEST_MAPPING b/TEST_MAPPING
index acab8ef..09ebfe2 100644
--- a/TEST_MAPPING
+++ b/TEST_MAPPING
@@ -58,5 +58,15 @@
}
]
}
+ ],
+ "postsubmit": [
+ {
+ "name": "CtsTelecomCujTestCases",
+ "options": [
+ {
+ "exclude-annotation": "androidx.test.filters.FlakyTest"
+ }
+ ]
+ }
]
}
diff --git a/flags/telecom_anomaly_report_flags.aconfig b/flags/telecom_anomaly_report_flags.aconfig
index 296b300..b060ed0 100644
--- a/flags/telecom_anomaly_report_flags.aconfig
+++ b/flags/telecom_anomaly_report_flags.aconfig
@@ -8,3 +8,11 @@
description: "When getCurrentFocusCall times out, generate an anom. report"
bug: "309541253"
}
+
+# OWNER=tjstuart TARGET=25Q2
+flag {
+ name: "disconnect_self_managed_stuck_startup_calls"
+ namespace: "telecom"
+ description: "If a self-managed call is stuck in certain states, disconnect it"
+ bug: "360298368"
+}
diff --git a/flags/telecom_call_flags.aconfig b/flags/telecom_call_flags.aconfig
index 331c328..2c53938 100644
--- a/flags/telecom_call_flags.aconfig
+++ b/flags/telecom_call_flags.aconfig
@@ -3,6 +3,13 @@
# OWNER=tjstuart TARGET=24Q3
flag {
+ name: "prevent_redundant_location_permission_grant_and_revoke"
+ namespace: "telecom"
+ description: "avoid redundant action of grant and revoke location permission for multiple emergency calls"
+ bug: "345386002"
+}
+
+flag {
name: "transactional_cs_verifier"
namespace: "telecom"
description: "verify connection service callbacks via a transaction"
@@ -37,3 +44,14 @@
purpose: PURPOSE_BUGFIX
}
}
+
+# OWNER=breadley TARGET=24Q4
+flag {
+ name: "use_stream_voice_call_tones"
+ namespace: "telecom"
+ description: "Use STREAM_VOICE_CALL only for ToneGenerator"
+ bug: "363262590"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
\ No newline at end of file
diff --git a/res/values-gu/strings.xml b/res/values-gu/strings.xml
index 3d69e13..dd04bcf 100644
--- a/res/values-gu/strings.xml
+++ b/res/values-gu/strings.xml
@@ -43,8 +43,8 @@
<string name="respond_via_sms_setting_title_2" msgid="4914853536609553457">"હાજરજવાબમાં ફેરફાર કરો"</string>
<string name="respond_via_sms_setting_summary" msgid="8054571501085436868"></string>
<string name="respond_via_sms_edittext_dialog_title" msgid="6579353156073272157">"ઝડપી પ્રતિસાદ"</string>
- <string name="respond_via_sms_confirmation_format" msgid="2932395476561267842">"<xliff:g id="PHONE_NUMBER">%s</xliff:g> પર સંદેશ મોકલ્યો."</string>
- <string name="respond_via_sms_failure_format" msgid="5198680980054596391">"<xliff:g id="PHONE_NUMBER">%s</xliff:g>ને સંદેશ મોકલવામાં નિષ્ફળ રહ્યાં."</string>
+ <string name="respond_via_sms_confirmation_format" msgid="2932395476561267842">"<xliff:g id="PHONE_NUMBER">%s</xliff:g> પર મેસેજ મોકલ્યો."</string>
+ <string name="respond_via_sms_failure_format" msgid="5198680980054596391">"<xliff:g id="PHONE_NUMBER">%s</xliff:g> પર મેસેજ મોકલવામાં નિષ્ફળ રહ્યાં."</string>
<string name="enable_account_preference_title" msgid="6949224486748457976">"કૉલ કરવા માટેના એકાઉન્ટ"</string>
<string name="outgoing_call_not_allowed_user_restriction" msgid="3424338207838851646">"ફક્ત કટોકટીના કૉલ્સને મંજૂરી છે."</string>
<string name="outgoing_call_not_allowed_no_permission" msgid="8590468836581488679">"ફોન પરવાનગી વિના આ ઍપ્લિકેશન આઉટગોઇંગ કૉલ્સ કરી શકતી નથી."</string>
diff --git a/res/values-mk/strings.xml b/res/values-mk/strings.xml
index c607df5..0f6e41f 100644
--- a/res/values-mk/strings.xml
+++ b/res/values-mk/strings.xml
@@ -90,7 +90,7 @@
<string name="answering_ends_other_managed_video_call" msgid="1988508241432031327">"Ако одговорите, ќе се прекине вашиот тековен видеоповик"</string>
<string name="answer_incoming_call" msgid="2045888814782215326">"Одговорете"</string>
<string name="decline_incoming_call" msgid="922147089348451310">"Одбијте"</string>
- <string name="cant_call_due_to_no_supported_service" msgid="6720817368116820027">"Не може да се оствари повик. Проверете ја мрежата на уредот."</string>
+ <string name="cant_call_due_to_no_supported_service" msgid="6720817368116820027">"Не може да се оствари повик. Проверете ја врската на уредот."</string>
<string name="cant_call_due_to_ongoing_call" msgid="8004235328451385493">"Не може да се воспостави повик поради вашиот повик на <xliff:g id="OTHER_CALL">%1$s</xliff:g>."</string>
<string name="cant_call_due_to_ongoing_calls" msgid="6379163795277824868">"Не може да се воспостави повик поради вашите повици на <xliff:g id="OTHER_CALL">%1$s</xliff:g>."</string>
<string name="cant_call_due_to_ongoing_unknown_call" msgid="8243532328969433172">"Не може да се воспостави повик поради вашиот повик на друга апликација."</string>
diff --git a/src/com/android/server/telecom/Call.java b/src/com/android/server/telecom/Call.java
index 9845f1c..ba371f1 100644
--- a/src/com/android/server/telecom/Call.java
+++ b/src/com/android/server/telecom/Call.java
@@ -39,7 +39,6 @@
import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
import android.os.SystemClock;
-import android.os.Trace;
import android.os.UserHandle;
import android.provider.CallLog;
import android.provider.ContactsContract.Contacts;
@@ -2192,10 +2191,15 @@
isWorkCall = UserUtil.isManagedProfile(mContext, userHandle, mFlags);
}
- isCallRecordingToneSupported = (phoneAccount.hasCapabilities(
- PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION) && phoneAccount.getExtras() != null
- && phoneAccount.getExtras().getBoolean(
- PhoneAccount.EXTRA_PLAY_CALL_RECORDING_TONE, false));
+ if (!mFlags.telecomResolveHiddenDependencies()) {
+ isCallRecordingToneSupported = (phoneAccount.hasCapabilities(
+ PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION)
+ && phoneAccount.getExtras() != null
+ && phoneAccount.getExtras().getBoolean(
+ PhoneAccount.EXTRA_PLAY_CALL_RECORDING_TONE, false));
+ } else {
+ isCallRecordingToneSupported = false;
+ }
isSimCall = phoneAccount.hasCapabilities(PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION);
}
mIsWorkCall = isWorkCall;
@@ -3891,7 +3895,6 @@
* @param callerInfo The new caller information to set.
*/
private void setCallerInfo(Uri handle, CallerInfo callerInfo) {
- Trace.beginSection("setCallerInfo");
if (callerInfo == null) {
Log.i(this, "CallerInfo lookup returned null, skipping update");
return;
@@ -3915,8 +3918,6 @@
l.onCallerInfoChanged(this);
}
}
-
- Trace.endSection();
}
public CallerInfo getCallerInfo() {
diff --git a/src/com/android/server/telecom/CallAnomalyWatchdog.java b/src/com/android/server/telecom/CallAnomalyWatchdog.java
index 045671e..497d7e6 100644
--- a/src/com/android/server/telecom/CallAnomalyWatchdog.java
+++ b/src/com/android/server/telecom/CallAnomalyWatchdog.java
@@ -18,15 +18,22 @@
import static com.android.server.telecom.LogUtils.Events.STATE_TIMEOUT;
+import android.content.Context;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.os.Build;
+import android.os.UserHandle;
import android.provider.DeviceConfig;
import android.telecom.ConnectionService;
import android.telecom.DisconnectCause;
import android.telecom.Log;
+import android.telecom.PhoneAccountHandle;
import android.util.LocalLog;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.IndentingPrintWriter;
import com.android.server.telecom.stats.CallStateChangedAtomWriter;
+import com.android.server.telecom.flags.FeatureFlags;
import java.util.Collections;
import java.util.Map;
@@ -113,6 +120,7 @@
private final TelecomSystem.SyncRoot mLock;
private final Timeouts.Adapter mTimeoutAdapter;
private final ClockProxy mClockProxy;
+ private final FeatureFlags mFeatureFlags;
private AnomalyReporterAdapter mAnomalyReporter = new AnomalyReporterAdapterImpl();
// Pre-allocate space for 2 calls; realistically thats all we should ever need (tm)
private final Map<Call, ScheduledFuture<?>> mScheduledFutureMap = new ConcurrentHashMap<>(2);
@@ -140,6 +148,11 @@
UUID.fromString("d57d8aab-d723-485e-a0dd-d1abb0f346c8");
public static final String WATCHDOG_DISCONNECTED_STUCK_EMERGENCY_CALL_MSG =
"Telecom CallAnomalyWatchdog caught and disconnected a stuck/zombie emergency call.";
+ public static final UUID WATCHDOG_DISCONNECTED_STUCK_VOIP_CALL_UUID =
+ UUID.fromString("3fbecd12-059d-4fd3-87b7-6c3079891c23");
+ public static final String WATCHDOG_DISCONNECTED_STUCK_VOIP_CALL_MSG =
+ "Telecom CallAnomalyWatchdog caught stuck VoIP call in a starting state";
+
@VisibleForTesting
public void setAnomalyReporterAdapter(AnomalyReporterAdapter mAnomalyReporterAdapter){
@@ -148,10 +161,12 @@
public CallAnomalyWatchdog(ScheduledExecutorService executorService,
TelecomSystem.SyncRoot lock,
+ FeatureFlags featureFlags,
Timeouts.Adapter timeoutAdapter, ClockProxy clockProxy,
EmergencyCallDiagnosticLogger emergencyCallDiagnosticLogger) {
mScheduledExecutorService = executorService;
mLock = lock;
+ mFeatureFlags = featureFlags;
mTimeoutAdapter = timeoutAdapter;
mClockProxy = clockProxy;
mEmergencyCallDiagnosticLogger = emergencyCallDiagnosticLogger;
@@ -272,8 +287,13 @@
*/
private void maybeTrackCall(Call call) {
final WatchdogCallState currentState = mWatchdogCallStateMap.get(call);
+ boolean isCreateConnectionComplete = call.isCreateConnectionComplete();
+ if (mFeatureFlags.disconnectSelfManagedStuckStartupCalls()) {
+ isCreateConnectionComplete =
+ isCreateConnectionComplete || call.isTransactionalCall();
+ }
final WatchdogCallState newState = new WatchdogCallState(call.getState(),
- call.isCreateConnectionComplete(), mClockProxy.elapsedRealtime());
+ isCreateConnectionComplete, mClockProxy.elapsedRealtime());
if (Objects.equals(currentState, newState)) {
// No state change; skip.
return;
@@ -348,8 +368,13 @@
}
// Ensure that at timeout we are still in the original state when we posted the
// timeout.
+ boolean isCreateConnectionComplete = call.isCreateConnectionComplete();
+ if (mFeatureFlags.disconnectSelfManagedStuckStartupCalls()) {
+ isCreateConnectionComplete =
+ isCreateConnectionComplete || call.isTransactionalCall();
+ }
final WatchdogCallState expiredState = new WatchdogCallState(call.getState(),
- call.isCreateConnectionComplete(), mClockProxy.elapsedRealtime());
+ isCreateConnectionComplete, mClockProxy.elapsedRealtime());
if (expiredState.equals(newState)
&& getDurationInCurrentStateMillis(newState) > timeoutMillis) {
// The call has been in this transitory or intermediate state too long,
@@ -368,7 +393,7 @@
WATCHDOG_DISCONNECTED_STUCK_CALL_MSG);
}
- if (isEnabledDisconnect) {
+ if (isEnabledDisconnect || isInSelfManagedStuckStartingState(call)) {
call.setOverrideDisconnectCauseCode(
new DisconnectCause(DisconnectCause.ERROR, "state_timeout"));
call.disconnect("State timeout");
@@ -387,6 +412,50 @@
return cleanupRunnable;
}
+ private boolean isInSelfManagedStuckStartingState(Call call) {
+ Context context = call.getContext();
+ if (!mFeatureFlags.disconnectSelfManagedStuckStartupCalls() || context == null) {
+ return false;
+ }
+ int currentStuckState = call.getState();
+ return call.isSelfManaged() &&
+ (currentStuckState == CallState.NEW ||
+ currentStuckState == CallState.RINGING ||
+ currentStuckState == CallState.DIALING ||
+ currentStuckState == CallState.CONNECTING) &&
+ isVanillaIceCreamBuildOrHigher(context, call);
+ }
+
+ private boolean isVanillaIceCreamBuildOrHigher(Context context, Call call) {
+ // report the anomaly for metrics purposes
+ mAnomalyReporter.reportAnomaly(
+ WATCHDOG_DISCONNECTED_STUCK_VOIP_CALL_UUID,
+ WATCHDOG_DISCONNECTED_STUCK_VOIP_CALL_MSG);
+ // only disconnect calls running on V and when the flag is enabled!
+ PhoneAccountHandle phoneAccountHandle = call.getTargetPhoneAccount();
+ PackageManager pm = context.getPackageManager();
+ if (pm == null ||
+ phoneAccountHandle == null ||
+ phoneAccountHandle.getComponentName() == null) {
+ return false;
+ }
+ String packageName = phoneAccountHandle.getComponentName().getPackageName();
+ Log.d(this, "pah=[%s], user=[%s]", phoneAccountHandle, call.getAssociatedUser());
+ ApplicationInfo applicationInfo;
+ try {
+ applicationInfo = pm.getApplicationInfoAsUser(
+ packageName,
+ 0,
+ call.getAssociatedUser());
+ } catch (Exception e) {
+ Log.e(this, e, "iVICBOH: pm.getApplicationInfoAsUser(...) exception");
+ return false;
+ }
+ int targetSdk = (applicationInfo == null) ? 0 : applicationInfo.targetSdkVersion;
+ Log.i(this, "iVICBOH: packageName=[%s], sdk=[%d]", packageName, targetSdk);
+ return targetSdk >= Build.VERSION_CODES.VANILLA_ICE_CREAM;
+ }
+
/**
* Returns whether the action to disconnect the call when the Transitory state and
* Intermediate state time expires is enabled or disabled.
diff --git a/src/com/android/server/telecom/CallAudioModeStateMachine.java b/src/com/android/server/telecom/CallAudioModeStateMachine.java
index cd1d6a3..fb196f2 100644
--- a/src/com/android/server/telecom/CallAudioModeStateMachine.java
+++ b/src/com/android/server/telecom/CallAudioModeStateMachine.java
@@ -21,7 +21,6 @@
import android.media.AudioManager;
import android.os.Looper;
import android.os.Message;
-import android.os.Trace;
import android.telecom.Log;
import android.telecom.Logging.Runnable;
import android.telecom.Logging.Session;
@@ -461,40 +460,35 @@
private boolean mHasFocus = false;
private void tryStartRinging() {
- Trace.traceBegin(Trace.TRACE_TAG_AUDIO, "CallAudioMode.tryStartRinging");
- try {
- if (mHasFocus && mCallAudioManager.isRingtonePlaying()) {
- Log.i(LOG_TAG,
- "RingingFocusState#tryStartRinging -- audio focus previously"
- + " acquired and ringtone already playing -- skipping.");
- return;
- }
+ if (mHasFocus && mCallAudioManager.isRingtonePlaying()) {
+ Log.i(LOG_TAG,
+ "RingingFocusState#tryStartRinging -- audio focus previously"
+ + " acquired and ringtone already playing -- skipping.");
+ return;
+ }
- if (mCallAudioManager.startRinging()) {
- if (mFeatureFlags.telecomResolveHiddenDependencies()) {
- mCurrentAudioFocusRequest = RING_AUDIO_FOCUS_REQUEST;
- Log.i(this, "tryStartRinging: AudioManager#requestAudioFocus(RING)");
- mAudioManager.requestAudioFocus(RING_AUDIO_FOCUS_REQUEST);
- } else {
- mAudioManager.requestAudioFocusForCall(
- AudioManager.STREAM_RING, AudioManager.AUDIOFOCUS_GAIN_TRANSIENT);
- }
- // Do not set MODE_RINGTONE if we were previously in the CALL_SCREENING mode --
- // this trips up the audio system.
- if (mAudioManager.getMode() != AudioManager.MODE_CALL_SCREENING) {
- Log.i(this, "enter: AudioManager#setMode(MODE_RINGTONE)");
- mAudioManager.setMode(AudioManager.MODE_RINGTONE);
- mLocalLog.log("Mode MODE_RINGTONE");
- }
- mCallAudioManager.setCallAudioRouteFocusState(
- CallAudioRouteStateMachine.RINGING_FOCUS);
- mHasFocus = true;
+ if (mCallAudioManager.startRinging()) {
+ if (mFeatureFlags.telecomResolveHiddenDependencies()) {
+ mCurrentAudioFocusRequest = RING_AUDIO_FOCUS_REQUEST;
+ Log.i(this, "tryStartRinging: AudioManager#requestAudioFocus(RING)");
+ mAudioManager.requestAudioFocus(RING_AUDIO_FOCUS_REQUEST);
} else {
- Log.i(
- LOG_TAG, "RINGING state, try start ringing but not acquiring audio focus");
+ mAudioManager.requestAudioFocusForCall(
+ AudioManager.STREAM_RING, AudioManager.AUDIOFOCUS_GAIN_TRANSIENT);
}
- } finally {
- Trace.traceEnd(Trace.TRACE_TAG_AUDIO);
+ // Do not set MODE_RINGTONE if we were previously in the CALL_SCREENING mode --
+ // this trips up the audio system.
+ if (mAudioManager.getMode() != AudioManager.MODE_CALL_SCREENING) {
+ Log.i(this, "enter: AudioManager#setMode(MODE_RINGTONE)");
+ mAudioManager.setMode(AudioManager.MODE_RINGTONE);
+ mLocalLog.log("Mode MODE_RINGTONE");
+ }
+ mCallAudioManager.setCallAudioRouteFocusState(
+ CallAudioRouteStateMachine.RINGING_FOCUS);
+ mHasFocus = true;
+ } else {
+ Log.i(
+ LOG_TAG, "RINGING state, try start ringing but not acquiring audio focus");
}
}
diff --git a/src/com/android/server/telecom/CallAudioRouteController.java b/src/com/android/server/telecom/CallAudioRouteController.java
index 9c593f4..abee2a8 100644
--- a/src/com/android/server/telecom/CallAudioRouteController.java
+++ b/src/com/android/server/telecom/CallAudioRouteController.java
@@ -533,14 +533,6 @@
mIsScoAudioConnected);
mIsActive = active;
mPendingAudioRoute.evaluatePendingState();
- postTimeoutMessage();
- }
-
- private void postTimeoutMessage() {
- // reset timeout handler
- mHandler.removeMessages(PENDING_ROUTE_TIMEOUT);
- mHandler.postDelayed(() -> mHandler.sendMessage(
- Message.obtain(mHandler, PENDING_ROUTE_TIMEOUT)), TIMEOUT_LIMIT);
}
private void handleWiredHeadsetConnected() {
@@ -657,9 +649,6 @@
mPendingAudioRoute.onMessageReceived(new Pair<>(BT_AUDIO_CONNECTED,
bluetoothDevice.getAddress()), null);
}
- } else {
- // ignore, not triggered by telecom
- Log.i(this, "handleBtAudioActive: ignoring handling bt audio active.");
}
}
@@ -679,9 +668,6 @@
mPendingAudioRoute.onMessageReceived(new Pair<>(BT_AUDIO_DISCONNECTED,
bluetoothDevice.getAddress()), null);
}
- } else {
- // ignore, not triggered by telecom
- Log.i(this, "handleBtAudioInactive: ignoring handling bt audio inactive.");
}
}
@@ -1156,7 +1142,8 @@
: mSpeakerDockRoute;
// Ensure that we default to speaker route if we're in a video call, but disregard it if
// a wired headset is plugged in.
- if (skipEarpiece && defaultRoute.getType() == AudioRoute.TYPE_EARPIECE) {
+ if (skipEarpiece && defaultRoute != null
+ && defaultRoute.getType() == AudioRoute.TYPE_EARPIECE) {
Log.i(this, "getPreferredAudioRouteFromDefault: Audio routing defaulting to "
+ "speaker route for video call.");
defaultRoute = mSpeakerDockRoute;
@@ -1227,7 +1214,8 @@
public AudioRoute getBaseRoute(boolean includeBluetooth, String btAddressToExclude) {
AudioRoute destRoute = getPreferredAudioRouteFromStrategy();
- if (destRoute == null || (destRoute.getBluetoothAddress() != null && !includeBluetooth)) {
+ if (destRoute == null || (destRoute.getBluetoothAddress() != null && (!includeBluetooth
+ || destRoute.getBluetoothAddress().equals(btAddressToExclude)))) {
destRoute = getPreferredAudioRouteFromDefault(includeBluetooth, btAddressToExclude);
}
if (destRoute != null && !getCallSupportedRoutes().contains(destRoute)) {
diff --git a/src/com/android/server/telecom/CallIntentProcessor.java b/src/com/android/server/telecom/CallIntentProcessor.java
index 8e1f754..c77b9ff 100644
--- a/src/com/android/server/telecom/CallIntentProcessor.java
+++ b/src/com/android/server/telecom/CallIntentProcessor.java
@@ -14,7 +14,6 @@
import android.net.Uri;
import android.os.Bundle;
import android.os.Looper;
-import android.os.Trace;
import android.os.UserHandle;
import android.os.UserManager;
import android.telecom.DefaultDialerManager;
@@ -95,14 +94,12 @@
final boolean isUnknownCall = intent.getBooleanExtra(KEY_IS_UNKNOWN_CALL, false);
Log.i(this, "onReceive - isUnknownCall: %s", isUnknownCall);
- Trace.beginSection("processNewCallCallIntent");
if (isUnknownCall) {
processUnknownCallIntent(mCallsManager, intent);
} else {
processOutgoingCallIntent(mContext, mCallsManager, intent, callingPackage,
mDefaultDialerCache, mFeatureFlags);
}
- Trace.endSection();
}
diff --git a/src/com/android/server/telecom/CallsManager.java b/src/com/android/server/telecom/CallsManager.java
index 600f847..a7ad3b8 100644
--- a/src/com/android/server/telecom/CallsManager.java
+++ b/src/com/android/server/telecom/CallsManager.java
@@ -75,7 +75,6 @@
import android.os.SystemClock;
import android.os.SystemProperties;
import android.os.SystemVibrator;
-import android.os.Trace;
import android.os.UserHandle;
import android.os.UserManager;
import android.provider.BlockedNumberContract;
@@ -444,6 +443,7 @@
private final InCallController mInCallController;
private final CallDiagnosticServiceController mCallDiagnosticServiceController;
private final CallAudioManager mCallAudioManager;
+ /** @deprecated not used any more */
private final CallRecordingTonePlayer mCallRecordingTonePlayer;
private RespondViaSmsManager mRespondViaSmsManager;
private final Ringer mRinger;
@@ -680,7 +680,7 @@
audioManager.generateAudioSessionId()));
InCallTonePlayer.Factory playerFactory = new InCallTonePlayer.Factory(
callAudioRoutePeripheralAdapter, lock, toneGeneratorFactory, mediaPlayerFactory,
- () -> audioManager.getStreamVolume(AudioManager.STREAM_RING) > 0);
+ () -> audioManager.getStreamVolume(AudioManager.STREAM_RING) > 0, featureFlags);
SystemSettingsUtil systemSettingsUtil = new SystemSettingsUtil();
RingtoneFactory ringtoneFactory = new RingtoneFactory(this, context, featureFlags);
@@ -696,8 +696,13 @@
new Ringer.VibrationEffectProxy(), mInCallController,
mContext.getSystemService(NotificationManager.class),
accessibilityManagerAdapter, featureFlags);
- mCallRecordingTonePlayer = new CallRecordingTonePlayer(mContext, audioManager,
- mTimeoutsAdapter, mLock);
+ if (featureFlags.telecomResolveHiddenDependencies()) {
+ // This is now deprecated
+ mCallRecordingTonePlayer = null;
+ } else {
+ mCallRecordingTonePlayer = new CallRecordingTonePlayer(mContext, audioManager,
+ mTimeoutsAdapter, mLock);
+ }
mCallAudioManager = new CallAudioManager(callAudioRouteAdapter,
this, callAudioModeStateMachineFactory.create(systemStateHelper,
(AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE),
@@ -742,7 +747,9 @@
mListeners.add(mCallEndpointController);
mListeners.add(mCallDiagnosticServiceController);
mListeners.add(mCallAudioManager);
- mListeners.add(mCallRecordingTonePlayer);
+ if (!featureFlags.telecomResolveHiddenDependencies()) {
+ mListeners.add(mCallRecordingTonePlayer);
+ }
mListeners.add(missedCallNotifier);
mListeners.add(mDisconnectedCallNotifier);
mListeners.add(mHeadsetMediaButton);
@@ -4621,7 +4628,6 @@
Log.i(this, "addCall(%s) is already added");
return;
}
- Trace.beginSection("addCall");
Log.i(this, "addCall(%s)", call);
call.addListener(this);
mCalls.add(call);
@@ -4638,20 +4644,12 @@
updateExternalCallCanPullSupport();
// onCallAdded for calls which immediately take the foreground (like the first call).
for (CallsManagerListener listener : mListeners) {
- if (LogUtils.SYSTRACE_DEBUG) {
- Trace.beginSection(listener.getClass().toString() + " addCall");
- }
listener.onCallAdded(call);
- if (LogUtils.SYSTRACE_DEBUG) {
- Trace.endSection();
- }
}
- Trace.endSection();
}
@VisibleForTesting
public void removeCall(Call call) {
- Trace.beginSection("removeCall");
Log.v(this, "removeCall(%s)", call);
if (call.isTransactionalCall() && call.getTransactionServiceWrapper() != null) {
@@ -4678,16 +4676,9 @@
updateCanAddCall();
updateHasActiveRttCall();
for (CallsManagerListener listener : mListeners) {
- if (LogUtils.SYSTRACE_DEBUG) {
- Trace.beginSection(listener.getClass().toString() + " onCallRemoved");
- }
listener.onCallRemoved(call);
- if (LogUtils.SYSTRACE_DEBUG) {
- Trace.endSection();
- }
}
}
- Trace.endSection();
}
private void updateHasActiveRttCall() {
@@ -4750,13 +4741,8 @@
call.getAnalytics().setMissedReason(call.getMissedReason());
maybeShowErrorDialogOnDisconnect(call);
-
- Trace.beginSection("onCallStateChanged");
-
maybeHandleHandover(call, newState);
notifyCallStateChanged(call, oldState, newState);
-
- Trace.endSection();
} else {
Log.i(this, "failed in setting the state to new state");
}
@@ -4769,14 +4755,7 @@
updateCanAddCall();
updateHasActiveRttCall();
for (CallsManagerListener listener : mListeners) {
- if (LogUtils.SYSTRACE_DEBUG) {
- Trace.beginSection(listener.getClass().toString() +
- " onCallStateChanged");
- }
listener.onCallStateChanged(call, oldState, newState);
- if (LogUtils.SYSTRACE_DEBUG) {
- Trace.endSection();
- }
}
}
}
@@ -4901,13 +4880,7 @@
if (newCanAddCall != mCanAddCall) {
mCanAddCall = newCanAddCall;
for (CallsManagerListener listener : mListeners) {
- if (LogUtils.SYSTRACE_DEBUG) {
- Trace.beginSection(listener.getClass().toString() + " updateCanAddCall");
- }
listener.onCanAddCallChanged(mCanAddCall);
- if (LogUtils.SYSTRACE_DEBUG) {
- Trace.endSection();
- }
}
}
}
diff --git a/src/com/android/server/telecom/EmergencyCallHelper.java b/src/com/android/server/telecom/EmergencyCallHelper.java
index 5ab0e99..c0e38ca 100644
--- a/src/com/android/server/telecom/EmergencyCallHelper.java
+++ b/src/com/android/server/telecom/EmergencyCallHelper.java
@@ -24,6 +24,7 @@
import android.telecom.PhoneAccountHandle;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.server.telecom.flags.FeatureFlags;
/**
* Helps with emergency calls by:
@@ -51,19 +52,25 @@
private long mLastEmergencyCallTimestampMillis;
private long mLastOutgoingEmergencyCallTimestampMillis;
+ private final FeatureFlags mFeatureFlags;
+
@VisibleForTesting
public EmergencyCallHelper(
Context context,
DefaultDialerCache defaultDialerCache,
- Timeouts.Adapter timeoutsAdapter) {
+ Timeouts.Adapter timeoutsAdapter,
+ FeatureFlags featureFlags) {
mContext = context;
mDefaultDialerCache = defaultDialerCache;
mTimeoutsAdapter = timeoutsAdapter;
+ mFeatureFlags = featureFlags;
}
@VisibleForTesting
public void maybeGrantTemporaryLocationPermission(Call call, UserHandle userHandle) {
- if (shouldGrantTemporaryLocationPermission(call)) {
+ if (shouldGrantTemporaryLocationPermission(call) && (
+ !mFeatureFlags.preventRedundantLocationPermissionGrantAndRevoke()
+ || !wasGrantedTemporaryLocationPermission())) {
grantLocationPermission(userHandle);
}
if (call != null && call.isEmergencyCall()) {
diff --git a/src/com/android/server/telecom/InCallController.java b/src/com/android/server/telecom/InCallController.java
index 6164638..5a6f0ea 100644
--- a/src/com/android/server/telecom/InCallController.java
+++ b/src/com/android/server/telecom/InCallController.java
@@ -45,7 +45,6 @@
import android.os.Looper;
import android.os.PackageTagsList;
import android.os.RemoteException;
-import android.os.Trace;
import android.os.UserHandle;
import android.os.UserManager;
import android.telecom.CallAudioState;
@@ -1302,6 +1301,8 @@
private ArraySet<String> mAllCarrierPrivilegedApps = new ArraySet<>();
private ArraySet<String> mActiveCarrierPrivilegedApps = new ArraySet<>();
+ private java.lang.Runnable mCallRemovedRunnable;
+
public InCallController(Context context, TelecomSystem.SyncRoot lock, CallsManager callsManager,
SystemStateHelper systemStateHelper, DefaultDialerCache defaultDialerCache,
Timeouts.Adapter timeoutsAdapter, EmergencyCallHelper emergencyCallHelper,
@@ -1517,7 +1518,11 @@
/** Let's add a 2 second delay before we send unbind to the services to hopefully
* give them enough time to process all the pending messages.
*/
- mHandler.postDelayed(new Runnable("ICC.oCR", mLock) {
+ if (mCallRemovedRunnable != null
+ && mFeatureFlags.preventRedundantLocationPermissionGrantAndRevoke()) {
+ mHandler.removeCallbacks(mCallRemovedRunnable);
+ }
+ mCallRemovedRunnable = new Runnable("ICC.oCR", mLock) {
@Override
public void loggedRun() {
// Check again to make sure there are no active calls for the associated user.
@@ -1531,8 +1536,10 @@
mEmergencyCallHelper.maybeRevokeTemporaryLocationPermission();
}
}
- }.prepare(), mTimeoutsAdapter.getCallRemoveUnbindInCallServicesDelay(
- mContext.getContentResolver()));
+ }.prepare();
+ mHandler.postDelayed(mCallRemovedRunnable,
+ mTimeoutsAdapter.getCallRemoveUnbindInCallServicesDelay(
+ mContext.getContentResolver()));
}
call.removeListener(mCallListener);
mCallIdMapper.removeCall(call);
@@ -2573,7 +2580,6 @@
Log.e(this, e, "Failed to set the in-call adapter.");
mAnomalyReporter.reportAnomaly(SET_IN_CALL_ADAPTER_ERROR_UUID,
SET_IN_CALL_ADAPTER_ERROR_MSG);
- Trace.endSection();
return false;
}
diff --git a/src/com/android/server/telecom/InCallTonePlayer.java b/src/com/android/server/telecom/InCallTonePlayer.java
index a5942f0..b7edeb5 100644
--- a/src/com/android/server/telecom/InCallTonePlayer.java
+++ b/src/com/android/server/telecom/InCallTonePlayer.java
@@ -30,6 +30,7 @@
import android.telecom.Logging.Session;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.server.telecom.flags.FeatureFlags;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
@@ -54,15 +55,18 @@
private final ToneGeneratorFactory mToneGeneratorFactory;
private final MediaPlayerFactory mMediaPlayerFactory;
private final AudioManagerAdapter mAudioManagerAdapter;
+ private final FeatureFlags mFeatureFlags;
public Factory(CallAudioRoutePeripheralAdapter callAudioRoutePeripheralAdapter,
TelecomSystem.SyncRoot lock, ToneGeneratorFactory toneGeneratorFactory,
- MediaPlayerFactory mediaPlayerFactory, AudioManagerAdapter audioManagerAdapter) {
+ MediaPlayerFactory mediaPlayerFactory, AudioManagerAdapter audioManagerAdapter,
+ FeatureFlags flags) {
mCallAudioRoutePeripheralAdapter = callAudioRoutePeripheralAdapter;
mLock = lock;
mToneGeneratorFactory = toneGeneratorFactory;
mMediaPlayerFactory = mediaPlayerFactory;
mAudioManagerAdapter = audioManagerAdapter;
+ mFeatureFlags = flags;
}
public void setCallAudioManager(CallAudioManager callAudioManager) {
@@ -72,7 +76,7 @@
public InCallTonePlayer createPlayer(Call call, int tone) {
return new InCallTonePlayer(call, tone, mCallAudioManager,
mCallAudioRoutePeripheralAdapter, mLock, mToneGeneratorFactory,
- mMediaPlayerFactory, mAudioManagerAdapter);
+ mMediaPlayerFactory, mAudioManagerAdapter, mFeatureFlags);
}
}
@@ -216,6 +220,7 @@
private final ToneGeneratorFactory mToneGenerator;
private final MediaPlayerFactory mMediaPlayerFactory;
private final AudioManagerAdapter mAudioManagerAdapter;
+ private final FeatureFlags mFeatureFlags;
/**
* Latch used for awaiting on playback, which may be interrupted if the tone is stopped from
@@ -236,7 +241,8 @@
TelecomSystem.SyncRoot lock,
ToneGeneratorFactory toneGeneratorFactory,
MediaPlayerFactory mediaPlayerFactor,
- AudioManagerAdapter audioManagerAdapter) {
+ AudioManagerAdapter audioManagerAdapter,
+ FeatureFlags flags) {
mCall = call;
mState = STATE_OFF;
mToneId = toneId;
@@ -246,6 +252,7 @@
mToneGenerator = toneGeneratorFactory;
mMediaPlayerFactory = mediaPlayerFactor;
mAudioManagerAdapter = audioManagerAdapter;
+ mFeatureFlags = flags;
}
/** {@inheritDoc} */
@@ -364,18 +371,8 @@
throw new IllegalStateException("Bad toneId: " + mToneId);
}
- int stream = AudioManager.STREAM_VOICE_CALL;
- if (mCallAudioRoutePeripheralAdapter.isBluetoothAudioOn()) {
- stream = AudioManager.STREAM_BLUETOOTH_SCO;
- }
+ int stream = getStreamType(toneType);
if (toneType != ToneGenerator.TONE_UNKNOWN) {
- if (stream == AudioManager.STREAM_BLUETOOTH_SCO) {
- // Override audio stream for BT le device and hearing aid device
- if (mCallAudioRoutePeripheralAdapter.isLeAudioDeviceOn()
- || mCallAudioRoutePeripheralAdapter.isHearingAidDeviceOn()) {
- stream = AudioManager.STREAM_VOICE_CALL;
- }
- }
playToneGeneratorTone(stream, toneVolume, toneType, toneLengthMillis);
} else if (mediaResourceId != TONE_RESOURCE_ID_UNDEFINED) {
playMediaTone(stream, mediaResourceId);
@@ -387,6 +384,31 @@
}
/**
+ * @param toneType The ToneGenerator tone type
+ * @return The ToneGenerator stream type
+ */
+ private int getStreamType(int toneType) {
+ if (mFeatureFlags.useStreamVoiceCallTones()) {
+ return AudioManager.STREAM_VOICE_CALL;
+ }
+
+ int stream = AudioManager.STREAM_VOICE_CALL;
+ if (mCallAudioRoutePeripheralAdapter.isBluetoothAudioOn()) {
+ stream = AudioManager.STREAM_BLUETOOTH_SCO;
+ }
+ if (toneType != ToneGenerator.TONE_UNKNOWN) {
+ if (stream == AudioManager.STREAM_BLUETOOTH_SCO) {
+ // Override audio stream for BT le device and hearing aid device
+ if (mCallAudioRoutePeripheralAdapter.isLeAudioDeviceOn()
+ || mCallAudioRoutePeripheralAdapter.isHearingAidDeviceOn()) {
+ stream = AudioManager.STREAM_VOICE_CALL;
+ }
+ }
+ }
+ return stream;
+ }
+
+ /**
* Play a tone generated by the {@link ToneGenerator}.
* @param stream The stream on which the tone will be played.
* @param toneVolume The volume of the tone.
diff --git a/src/com/android/server/telecom/NewOutgoingCallIntentBroadcaster.java b/src/com/android/server/telecom/NewOutgoingCallIntentBroadcaster.java
index c24ac97..fce3f1a 100644
--- a/src/com/android/server/telecom/NewOutgoingCallIntentBroadcaster.java
+++ b/src/com/android/server/telecom/NewOutgoingCallIntentBroadcaster.java
@@ -25,7 +25,6 @@
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
-import android.os.Trace;
import android.os.UserHandle;
import android.telecom.GatewayInfo;
import android.telecom.Log;
@@ -126,7 +125,6 @@
public void onReceive(Context context, Intent intent) {
try {
Log.startSession("NOCBIR.oR");
- Trace.beginSection("onReceiveNewOutgoingCallBroadcast");
synchronized (mLock) {
Log.v(this, "onReceive: %s", intent);
@@ -194,7 +192,6 @@
VideoProfile.STATE_AUDIO_ONLY));
}
} finally {
- Trace.endSection();
Log.endSession();
}
}
diff --git a/src/com/android/server/telecom/TelecomSystem.java b/src/com/android/server/telecom/TelecomSystem.java
index d7dcf38..1cbe846 100644
--- a/src/com/android/server/telecom/TelecomSystem.java
+++ b/src/com/android/server/telecom/TelecomSystem.java
@@ -285,7 +285,7 @@
mContactsAsyncHelper, mLock);
EmergencyCallHelper emergencyCallHelper = new EmergencyCallHelper(mContext,
- defaultDialerCache, timeoutsAdapter);
+ defaultDialerCache, timeoutsAdapter, mFeatureFlags);
InCallControllerFactory inCallControllerFactory = new InCallControllerFactory() {
@Override
@@ -375,7 +375,8 @@
CallAnomalyWatchdog callAnomalyWatchdog = new CallAnomalyWatchdog(
Executors.newSingleThreadScheduledExecutor(),
- mLock, timeoutsAdapter, clockProxy, emergencyCallDiagnosticLogger);
+ mLock, mFeatureFlags, timeoutsAdapter, clockProxy,
+ emergencyCallDiagnosticLogger);
TransactionManager transactionManager = TransactionManager.getInstance();
diff --git a/src/com/android/server/telecom/bluetooth/BluetoothStateReceiver.java b/src/com/android/server/telecom/bluetooth/BluetoothStateReceiver.java
index b4c3d8d..cd52889 100644
--- a/src/com/android/server/telecom/bluetooth/BluetoothStateReceiver.java
+++ b/src/com/android/server/telecom/bluetooth/BluetoothStateReceiver.java
@@ -23,6 +23,8 @@
import static com.android.server.telecom.CallAudioRouteAdapter.BT_DEVICE_ADDED;
import static com.android.server.telecom.CallAudioRouteAdapter.BT_DEVICE_REMOVED;
import static com.android.server.telecom.CallAudioRouteAdapter.PENDING_ROUTE_FAILED;
+import static com.android.server.telecom.CallAudioRouteAdapter.SWITCH_BASELINE_ROUTE;
+import static com.android.server.telecom.CallAudioRouteController.INCLUDE_BLUETOOTH_IN_BASELINE;
import static com.android.server.telecom.bluetooth.BluetoothRouteManager.BT_AUDIO_IS_ON;
import static com.android.server.telecom.bluetooth.BluetoothRouteManager.BT_AUDIO_LOST;
@@ -153,8 +155,19 @@
CallAudioRouteController audioRouteController =
(CallAudioRouteController) mCallAudioRouteAdapter;
audioRouteController.setIsScoAudioConnected(false);
- mCallAudioRouteAdapter.sendMessageWithSessionInfo(BT_AUDIO_DISCONNECTED, 0,
- device);
+ if (audioRouteController.isPending()) {
+ mCallAudioRouteAdapter.sendMessageWithSessionInfo(BT_AUDIO_DISCONNECTED, 0,
+ device);
+ } else {
+ // Handle case where BT stack signals SCO disconnected but Telecom isn't
+ // processing any pending routes. This explicitly addresses cf instances
+ // where a remote device disconnects SCO. Telecom should ensure that audio
+ // is properly routed in the UI.
+ audioRouteController.getPendingAudioRoute()
+ .setCommunicationDeviceType(AudioRoute.TYPE_INVALID);
+ mCallAudioRouteAdapter.sendMessageWithSessionInfo(SWITCH_BASELINE_ROUTE,
+ INCLUDE_BLUETOOTH_IN_BASELINE, device.getAddress());
+ }
} else {
mBluetoothRouteManager.sendMessage(BT_AUDIO_LOST, args);
}
diff --git a/src/com/android/server/telecom/settings/BlockedNumbersUtil.java b/src/com/android/server/telecom/settings/BlockedNumbersUtil.java
index 3e1da17..99c5746 100644
--- a/src/com/android/server/telecom/settings/BlockedNumbersUtil.java
+++ b/src/com/android/server/telecom/settings/BlockedNumbersUtil.java
@@ -133,9 +133,12 @@
public static boolean isEnhancedCallBlockingEnabledByPlatform(Context context) {
CarrierConfigManager configManager = (CarrierConfigManager) context.getSystemService(
Context.CARRIER_CONFIG_SERVICE);
- PersistableBundle carrierConfig = configManager.getConfig();
+ PersistableBundle carrierConfig = null;
+ if (configManager != null) {
+ carrierConfig = configManager.getConfig();
+ }
if (carrierConfig == null) {
- carrierConfig = configManager.getDefaultConfig();
+ carrierConfig = CarrierConfigManager.getDefaultConfig();
}
return carrierConfig.getBoolean(
CarrierConfigManager.KEY_SUPPORT_ENHANCED_CALL_BLOCKING_BOOL)
diff --git a/src/com/android/server/telecom/voip/OutgoingCallTransaction.java b/src/com/android/server/telecom/voip/OutgoingCallTransaction.java
index 8c970db..68ffecf 100644
--- a/src/com/android/server/telecom/voip/OutgoingCallTransaction.java
+++ b/src/com/android/server/telecom/voip/OutgoingCallTransaction.java
@@ -114,6 +114,12 @@
Log.d(TAG, "processTransaction: call done. id=" + call.getId());
}
+ if (mFeatureFlags.disconnectSelfManagedStuckStartupCalls()) {
+ // set to dialing so the CallAnomalyWatchdog gives the VoIP calls 1
+ // minute to timeout rather than 5 seconds.
+ mCallsManager.markCallAsDialing(call);
+ }
+
return CompletableFuture.completedFuture(
new VoipCallTransactionResult(
VoipCallTransactionResult.RESULT_SUCCEED,
diff --git a/tests/src/com/android/server/telecom/tests/CallAnomalyWatchdogTest.java b/tests/src/com/android/server/telecom/tests/CallAnomalyWatchdogTest.java
index 86d24f9..a6f63bc 100644
--- a/tests/src/com/android/server/telecom/tests/CallAnomalyWatchdogTest.java
+++ b/tests/src/com/android/server/telecom/tests/CallAnomalyWatchdogTest.java
@@ -122,7 +122,7 @@
doReturn(new ComponentName(mContext, CallTest.class))
.when(mMockConnectionService).getComponentName();
mCallAnomalyWatchdog = new CallAnomalyWatchdog(mTestScheduledExecutorService, mLock,
- mTimeouts, mMockClockProxy, mMockEmergencyCallDiagnosticLogger);
+ mFeatureFlags, mTimeouts, mMockClockProxy, mMockEmergencyCallDiagnosticLogger);
mCallAnomalyWatchdog.setAnomalyReporterAdapter(mAnomalyReporterAdapter);
when(mMockCallsManager.getCurrentUserHandle()).thenReturn(UserHandle.CURRENT);
}
diff --git a/tests/src/com/android/server/telecom/tests/CallRecordingTonePlayerTest.java b/tests/src/com/android/server/telecom/tests/CallRecordingTonePlayerTest.java
index 60952d3..5ccb2fe 100644
--- a/tests/src/com/android/server/telecom/tests/CallRecordingTonePlayerTest.java
+++ b/tests/src/com/android/server/telecom/tests/CallRecordingTonePlayerTest.java
@@ -42,6 +42,7 @@
import android.media.MediaRecorder;
import android.os.Handler;
import android.os.Looper;
+import android.platform.test.annotations.RequiresFlagsDisabled;
import android.telecom.PhoneAccountHandle;
import androidx.test.filters.MediumTest;
@@ -52,6 +53,7 @@
import com.android.server.telecom.CallState;
import com.android.server.telecom.TelecomSystem;
import com.android.server.telecom.Timeouts;
+import com.android.server.telecom.flags.Flags;
import org.junit.After;
import org.junit.Before;
@@ -71,6 +73,7 @@
* Unit tests for the {@link com.android.server.telecom.CallRecordingTonePlayer} class.
*/
@RunWith(JUnit4.class)
+@RequiresFlagsDisabled(Flags.FLAG_TELECOM_RESOLVE_HIDDEN_DEPENDENCIES)
public class CallRecordingTonePlayerTest extends TelecomTestCase {
private static final String PHONE_ACCOUNT_PACKAGE = "com.android.telecom.test";
diff --git a/tests/src/com/android/server/telecom/tests/EmergencyCallHelperTest.java b/tests/src/com/android/server/telecom/tests/EmergencyCallHelperTest.java
index f2ad2f7..cc1c38a 100644
--- a/tests/src/com/android/server/telecom/tests/EmergencyCallHelperTest.java
+++ b/tests/src/com/android/server/telecom/tests/EmergencyCallHelperTest.java
@@ -75,7 +75,7 @@
mContext = mComponentContextFixture.getTestDouble().getApplicationContext();
when(mContext.getPackageManager()).thenReturn(mPackageManager);
mEmergencyCallHelper = new EmergencyCallHelper(mContext, mDefaultDialerCache,
- mTimeoutsAdapter);
+ mTimeoutsAdapter, mFeatureFlags);
when(mDefaultDialerCache.getSystemDialerApplication()).thenReturn(SYSTEM_DIALER_PACKAGE);
//start with no perms
@@ -185,6 +185,61 @@
@SmallTest
@Test
+ public void testPermGrantAndRevokeForEmergencyCall() {
+
+ when(mFeatureFlags.preventRedundantLocationPermissionGrantAndRevoke()).thenReturn(true);
+
+ mEmergencyCallHelper.maybeGrantTemporaryLocationPermission(mCall, mUserHandle);
+ mEmergencyCallHelper.maybeRevokeTemporaryLocationPermission();
+
+ //permissions should be granted then revoked
+ verifyGrantInvokedFor(ACCESS_BACKGROUND_LOCATION);
+ verifyGrantInvokedFor(ACCESS_FINE_LOCATION);
+ verifyRevokeInvokedFor(ACCESS_BACKGROUND_LOCATION);
+ verifyRevokeInvokedFor(ACCESS_FINE_LOCATION);
+ }
+
+ @SmallTest
+ @Test
+ public void testPermGrantAndRevokeForMultiEmergencyCall() {
+
+ when(mFeatureFlags.preventRedundantLocationPermissionGrantAndRevoke()).thenReturn(true);
+
+ //first call is emergency call
+ mEmergencyCallHelper.maybeGrantTemporaryLocationPermission(mCall, mUserHandle);
+ //second call is emergency call
+ mEmergencyCallHelper.maybeGrantTemporaryLocationPermission(mCall, mUserHandle);
+ mEmergencyCallHelper.maybeRevokeTemporaryLocationPermission();
+
+ //permissions should be granted then revoked
+ verifyGrantInvokedFor(ACCESS_BACKGROUND_LOCATION);
+ verifyGrantInvokedFor(ACCESS_FINE_LOCATION);
+ verifyRevokeInvokedFor(ACCESS_BACKGROUND_LOCATION);
+ verifyRevokeInvokedFor(ACCESS_FINE_LOCATION);
+ }
+
+ @SmallTest
+ @Test
+ public void testPermGrantAndRevokeForEmergencyCallAndNormalCall() {
+
+ when(mFeatureFlags.preventRedundantLocationPermissionGrantAndRevoke()).thenReturn(true);
+
+ //first call is emergency call
+ mEmergencyCallHelper.maybeGrantTemporaryLocationPermission(mCall, mUserHandle);
+ //second call is normal call
+ when(mCall.isEmergencyCall()).thenReturn(false);
+ mEmergencyCallHelper.maybeGrantTemporaryLocationPermission(mCall, mUserHandle);
+ mEmergencyCallHelper.maybeRevokeTemporaryLocationPermission();
+
+ //permissions should be granted then revoked
+ verifyGrantInvokedFor(ACCESS_BACKGROUND_LOCATION);
+ verifyGrantInvokedFor(ACCESS_FINE_LOCATION);
+ verifyRevokeInvokedFor(ACCESS_BACKGROUND_LOCATION);
+ verifyRevokeInvokedFor(ACCESS_FINE_LOCATION);
+ }
+
+ @SmallTest
+ @Test
public void testNoPermGrantForNonEmergencyCall() {
when(mCall.isEmergencyCall()).thenReturn(false);
diff --git a/tests/src/com/android/server/telecom/tests/InCallControllerTests.java b/tests/src/com/android/server/telecom/tests/InCallControllerTests.java
index 449aa41..bea3fe3 100644
--- a/tests/src/com/android/server/telecom/tests/InCallControllerTests.java
+++ b/tests/src/com/android/server/telecom/tests/InCallControllerTests.java
@@ -230,7 +230,7 @@
new ComponentName(SYS_PKG, SYS_CLASS));
when(mDefaultDialerCache.getBTInCallServicePackages()).thenReturn(new String[] {BT_PKG});
mEmergencyCallHelper = new EmergencyCallHelper(mMockContext, mDefaultDialerCache,
- mTimeoutsAdapter);
+ mTimeoutsAdapter, mFeatureFlags);
when(mMockCallsManager.getRoleManagerAdapter()).thenReturn(mMockRoleManagerAdapter);
when(mMockContext.getSystemService(eq(Context.NOTIFICATION_SERVICE)))
.thenReturn(mNotificationManager);
diff --git a/tests/src/com/android/server/telecom/tests/InCallTonePlayerTest.java b/tests/src/com/android/server/telecom/tests/InCallTonePlayerTest.java
index c9faa52..df26684 100644
--- a/tests/src/com/android/server/telecom/tests/InCallTonePlayerTest.java
+++ b/tests/src/com/android/server/telecom/tests/InCallTonePlayerTest.java
@@ -27,7 +27,6 @@
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
-import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.media.AudioManager;
import android.media.MediaPlayer;
@@ -43,10 +42,10 @@
import com.android.server.telecom.DockManager;
import com.android.server.telecom.InCallTonePlayer;
import com.android.server.telecom.TelecomSystem;
-import com.android.server.telecom.Timeouts;
import com.android.server.telecom.WiredHeadsetManager;
import com.android.server.telecom.bluetooth.BluetoothDeviceManager;
import com.android.server.telecom.bluetooth.BluetoothRouteManager;
+import com.android.server.telecom.flags.FeatureFlags;
import org.junit.After;
import org.junit.Before;
@@ -64,7 +63,6 @@
@Mock private BluetoothRouteManager mBluetoothRouteManager;
@Mock private CallAudioRouteStateMachine mCallAudioRouteStateMachine;
- @Mock private Timeouts.Adapter mTimeoutsAdapter;
@Mock private BluetoothDeviceManager mBluetoothDeviceManager;
@Mock private TelecomSystem.SyncRoot mLock;
@Mock private ToneGenerator mToneGenerator;
@@ -73,7 +71,6 @@
@Mock private DockManager mDockManager;
@Mock private AsyncRingtonePlayer mRingtonePlayer;
@Mock private BluetoothDevice mDevice;
- @Mock private BluetoothAdapter mBluetoothAdapter;
private InCallTonePlayer.MediaPlayerAdapter mMediaPlayerAdapter =
new InCallTonePlayer.MediaPlayerAdapter() {
@@ -115,7 +112,6 @@
private CallAudioManager mCallAudioManager;
@Mock
private Call mCall;
-
private InCallTonePlayer mInCallTonePlayer;
@Override
@@ -131,7 +127,7 @@
mCallAudioRouteStateMachine, mBluetoothRouteManager, mWiredHeadsetManager,
mDockManager, mRingtonePlayer);
mFactory = new InCallTonePlayer.Factory(mCallAudioRoutePeripheralAdapter, mLock,
- mToneGeneratorFactory, mMediaPlayerFactory, mAudioManagerAdapter);
+ mToneGeneratorFactory, mMediaPlayerFactory, mAudioManagerAdapter, mFeatureFlags);
mFactory.setCallAudioManager(mCallAudioManager);
mInCallTonePlayer = mFactory.createPlayer(mCall, InCallTonePlayer.TONE_CALL_ENDED);
}
@@ -209,55 +205,92 @@
eq(true));
}
+ /**
+ * Only applicable when {@link FeatureFlags#useStreamVoiceCallTones()} is false and we use
+ * STREAM_BLUETOOTH_SCO for tones.
+ */
@SmallTest
@Test
public void testRingbackToneAudioStreamHeadset() {
+ when(mFeatureFlags.useStreamVoiceCallTones()).thenReturn(false);
when(mAudioManagerAdapter.isVolumeOverZero()).thenReturn(true);
- mBluetoothDeviceManager.setBluetoothRouteManager(mBluetoothRouteManager);
- when(mBluetoothRouteManager.getBluetoothAudioConnectedDevice()).thenReturn(mDevice);
- when(mBluetoothRouteManager.isBluetoothAudioConnectedOrPending()).thenReturn(true);
-
- when(mBluetoothRouteManager.isCachedLeAudioDevice(mDevice)).thenReturn(false);
- when(mBluetoothRouteManager.isCachedHearingAidDevice(mDevice)).thenReturn(false);
+ setConnectedBluetoothDevice(false /*isLe*/, false /*isHearingAid*/);
mInCallTonePlayer = mFactory.createPlayer(mCall, InCallTonePlayer.TONE_RING_BACK);
assertTrue(mInCallTonePlayer.startTone());
+
verify(mToneGeneratorFactory, timeout(TEST_TIMEOUT))
.get(eq(AudioManager.STREAM_BLUETOOTH_SCO), anyInt());
verify(mCallAudioManager).setIsTonePlaying(any(Call.class), eq(true));
}
+ /**
+ * Only applicable when {@link FeatureFlags#useStreamVoiceCallTones()} is false and we use
+ * STREAM_BLUETOOTH_SCO for tones.
+ */
@SmallTest
@Test
public void testCallWaitingToneAudioStreamHeadset() {
+ when(mFeatureFlags.useStreamVoiceCallTones()).thenReturn(false);
when(mAudioManagerAdapter.isVolumeOverZero()).thenReturn(true);
- mBluetoothDeviceManager.setBluetoothRouteManager(mBluetoothRouteManager);
- when(mBluetoothRouteManager.getBluetoothAudioConnectedDevice()).thenReturn(mDevice);
- when(mBluetoothRouteManager.isBluetoothAudioConnectedOrPending()).thenReturn(true);
-
- when(mBluetoothRouteManager.isCachedLeAudioDevice(mDevice)).thenReturn(false);
- when(mBluetoothRouteManager.isCachedHearingAidDevice(mDevice)).thenReturn(false);
+ setConnectedBluetoothDevice(false /*isLe*/, false /*isHearingAid*/);
mInCallTonePlayer = mFactory.createPlayer(mCall, InCallTonePlayer.TONE_CALL_WAITING);
assertTrue(mInCallTonePlayer.startTone());
+
verify(mToneGeneratorFactory, timeout(TEST_TIMEOUT))
.get(eq(AudioManager.STREAM_BLUETOOTH_SCO), anyInt());
verify(mCallAudioManager).setIsTonePlaying(any(Call.class), eq(true));
}
+
+ /**
+ * Only applicable when {@link FeatureFlags#useStreamVoiceCallTones()} is true and we use
+ * STREAM_VOICE_CALL for ALL tones.
+ */
+ @SmallTest
+ @Test
+ public void testRingbackToneAudioStreamSco() {
+ when(mFeatureFlags.useStreamVoiceCallTones()).thenReturn(true);
+ when(mAudioManagerAdapter.isVolumeOverZero()).thenReturn(true);
+ setConnectedBluetoothDevice(false /*isLe*/, false /*isHearingAid*/);
+
+ mInCallTonePlayer = mFactory.createPlayer(mCall, InCallTonePlayer.TONE_RING_BACK);
+ assertTrue(mInCallTonePlayer.startTone());
+
+ verify(mToneGeneratorFactory, timeout(TEST_TIMEOUT))
+ .get(eq(AudioManager.STREAM_VOICE_CALL), anyInt());
+ verify(mCallAudioManager).setIsTonePlaying(any(Call.class), eq(true));
+ }
+
+ /**
+ * Only applicable when {@link FeatureFlags#useStreamVoiceCallTones()} is true and we use
+ * STREAM_VOICE_CALL for ALL tones.
+ */
+ @SmallTest
+ @Test
+ public void testRingbackToneAudioStreamLe() {
+ when(mFeatureFlags.useStreamVoiceCallTones()).thenReturn(true);
+ when(mAudioManagerAdapter.isVolumeOverZero()).thenReturn(true);
+ setConnectedBluetoothDevice(true /*isLe*/, false /*isHearingAid*/);
+
+ mInCallTonePlayer = mFactory.createPlayer(mCall, InCallTonePlayer.TONE_RING_BACK);
+ assertTrue(mInCallTonePlayer.startTone());
+
+ verify(mToneGeneratorFactory, timeout(TEST_TIMEOUT))
+ .get(eq(AudioManager.STREAM_VOICE_CALL), anyInt());
+ verify(mCallAudioManager).setIsTonePlaying(any(Call.class), eq(true));
+ }
+
@SmallTest
@Test
public void testRingbackToneAudioStreamHearingAid() {
when(mAudioManagerAdapter.isVolumeOverZero()).thenReturn(true);
- mBluetoothDeviceManager.setBluetoothRouteManager(mBluetoothRouteManager);
- when(mBluetoothRouteManager.getBluetoothAudioConnectedDevice()).thenReturn(mDevice);
- when(mBluetoothRouteManager.isBluetoothAudioConnectedOrPending()).thenReturn(true);
-
- when(mBluetoothRouteManager.isCachedLeAudioDevice(mDevice)).thenReturn(false);
- when(mBluetoothRouteManager.isCachedHearingAidDevice(mDevice)).thenReturn(true);
+ setConnectedBluetoothDevice(false /*isLe*/, true /*isHearingAid*/);
mInCallTonePlayer = mFactory.createPlayer(mCall, InCallTonePlayer.TONE_RING_BACK);
assertTrue(mInCallTonePlayer.startTone());
+
verify(mToneGeneratorFactory, timeout(TEST_TIMEOUT))
.get(eq(AudioManager.STREAM_VOICE_CALL), anyInt());
verify(mCallAudioManager).setIsTonePlaying(any(Call.class), eq(true));
@@ -267,17 +300,27 @@
@Test
public void testCallWaitingToneAudioStreamHearingAid() {
when(mAudioManagerAdapter.isVolumeOverZero()).thenReturn(true);
+ setConnectedBluetoothDevice(false /*isLe*/, true /*isHearingAid*/);
+
+ mInCallTonePlayer = mFactory.createPlayer(mCall, InCallTonePlayer.TONE_CALL_WAITING);
+ assertTrue(mInCallTonePlayer.startTone());
+
+ verify(mToneGeneratorFactory, timeout(TEST_TIMEOUT))
+ .get(eq(AudioManager.STREAM_VOICE_CALL), anyInt());
+ verify(mCallAudioManager).setIsTonePlaying(any(Call.class), eq(true));
+ }
+
+ /**
+ * Set a connected BT device. If not LE or Hearing Aid, it will be configured as SCO
+ * @param isLe true if LE
+ * @param isHearingAid true if hearing aid
+ */
+ private void setConnectedBluetoothDevice(boolean isLe, boolean isHearingAid) {
mBluetoothDeviceManager.setBluetoothRouteManager(mBluetoothRouteManager);
when(mBluetoothRouteManager.getBluetoothAudioConnectedDevice()).thenReturn(mDevice);
when(mBluetoothRouteManager.isBluetoothAudioConnectedOrPending()).thenReturn(true);
- when(mBluetoothRouteManager.isCachedLeAudioDevice(mDevice)).thenReturn(false);
- when(mBluetoothRouteManager.isCachedHearingAidDevice(mDevice)).thenReturn(true);
-
- mInCallTonePlayer = mFactory.createPlayer(mCall, InCallTonePlayer.TONE_CALL_WAITING);
- assertTrue(mInCallTonePlayer.startTone());
- verify(mToneGeneratorFactory, timeout(TEST_TIMEOUT))
- .get(eq(AudioManager.STREAM_VOICE_CALL), anyInt());
- verify(mCallAudioManager).setIsTonePlaying(any(Call.class), eq(true));
+ when(mBluetoothRouteManager.isCachedLeAudioDevice(mDevice)).thenReturn(isLe);
+ when(mBluetoothRouteManager.isCachedHearingAidDevice(mDevice)).thenReturn(isHearingAid);
}
}