Loading src/com/android/server/telecom/Ringer.java +115 −57 Original line number Diff line number Diff line Loading @@ -20,26 +20,27 @@ import android.app.Notification; import android.app.NotificationManager; import android.app.Person; import android.content.Context; import android.os.VibrationEffect; import android.telecom.Log; import android.telecom.TelecomManager; import android.media.AudioAttributes; import android.media.AudioManager; import android.media.Ringtone; import android.media.VolumeShaper; import android.net.Uri; import android.os.Bundle; import android.os.Handler; import android.os.HandlerThread; import android.os.VibrationEffect; import android.os.Vibrator; import android.telecom.Log; import android.telecom.TelecomManager; import com.android.internal.annotations.VisibleForTesting; import com.android.server.telecom.LogUtils.EventTimer; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; import java.util.stream.Collectors; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; /** * Controls the ringtone player. Loading Loading @@ -113,6 +114,8 @@ public class Ringer { private static final int DEFAULT_RAMPING_RINGER_DURATION = 10000; // 10 seconds private static final long RINGER_ATTRIBUTES_TIMEOUT = 5000; // 5 seconds private int mRampingRingerDuration = -1; // ramping ringer duration in millisecond // vibration duration before ramping ringer in second Loading Loading @@ -151,6 +154,7 @@ public class Ringer { private InCallTonePlayer mCallWaitingPlayer; private RingtoneFactory mRingtoneFactory; private AudioManager mAudioManager; /** * Call objects that are ringing, vibrating or call-waiting. These are used only for logging Loading @@ -165,6 +169,8 @@ public class Ringer { */ private boolean mIsVibrating = false; private Handler mHandler = null; /** Initializes the Ringer. */ @VisibleForTesting public Ringer( Loading @@ -187,6 +193,7 @@ public class Ringer { mRingtoneFactory = ringtoneFactory; mInCallController = inCallController; mVibrationEffectProxy = vibrationEffectProxy; mAudioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE); if (mContext.getResources().getBoolean(R.bool.use_simple_vibration_pattern)) { mDefaultVibrationEffect = mVibrationEffectProxy.createWaveform(SIMPLE_VIBRATION_PATTERN, Loading Loading @@ -220,58 +227,39 @@ public class Ringer { return false; } AudioManager audioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE); LogUtils.EventTimer timer = new EventTimer(); boolean isVolumeOverZero = audioManager.getStreamVolume(AudioManager.STREAM_RING) > 0; timer.record("isVolumeOverZero"); boolean shouldRingForContact = shouldRingForContact(foregroundCall.getContactUri()); timer.record("shouldRingForContact"); boolean isRingtonePresent = !(mRingtoneFactory.getRingtone(foregroundCall) == null); timer.record("getRingtone"); boolean isSelfManaged = foregroundCall.isSelfManaged(); timer.record("isSelfManaged"); boolean isSilentRingingRequested = foregroundCall.isSilentRingingRequested(); timer.record("isSilentRingRequested"); boolean isRingerAudible = isVolumeOverZero && shouldRingForContact && isRingtonePresent; timer.record("isRingerAudible"); boolean hasExternalRinger = hasExternalRinger(foregroundCall); timer.record("hasExternalRinger"); // Don't do call waiting operations or vibration unless these are false. boolean isTheaterModeOn = mSystemSettingsUtil.isTheaterModeOn(mContext); timer.record("isTheaterModeOn"); boolean letDialerHandleRinging = mInCallController.doesConnectedDialerSupportRinging(); timer.record("letDialerHandleRinging"); // Use completable future to establish a timeout, not intent to make these work outside the // main thread asynchronously // TODO: moving these RingerAttributes calculation out of Telecom lock to avoid blocking. CompletableFuture<RingerAttributes> ringerAttributesFuture = CompletableFuture .supplyAsync(() -> getRingerAttributes(foregroundCall, isHfpDeviceAttached), new LoggedHandlerExecutor(getHandler(), "R.sR", null)); Log.i(this, "startRinging timings: " + timer); boolean endEarly = isTheaterModeOn || letDialerHandleRinging || isSelfManaged || hasExternalRinger || isSilentRingingRequested; RingerAttributes attributes = null; try { attributes = ringerAttributesFuture.get( RINGER_ATTRIBUTES_TIMEOUT, TimeUnit.MILLISECONDS); } catch (ExecutionException | InterruptedException | TimeoutException e) { // Keep attributs as null Log.i(this, "getAttributes error: " + e); } // Acquire audio focus under any of the following conditions: // 1. Should ring for contact and there's an HFP device attached // 2. Volume is over zero, we should ring for the contact, and there's a audible ringtone // present. // 3. The call is self-managed. boolean shouldAcquireAudioFocus = isRingerAudible || (isHfpDeviceAttached && shouldRingForContact) || isSelfManaged; if (attributes == null) { Log.addEvent(foregroundCall, LogUtils.Events.SKIP_RINGING, "RingerAttributes error"); return false; } if (endEarly) { if (letDialerHandleRinging) { if (attributes.isEndEarly()) { if (attributes.letDialerHandleRinging()) { Log.addEvent(foregroundCall, LogUtils.Events.SKIP_RINGING, "Dialer handles"); } if (isSilentRingingRequested) { if (attributes.isSilentRingingRequested()) { Log.addEvent(foregroundCall, LogUtils.Events.SKIP_RINGING, "Silent ringing " + "requested"); } Log.i(this, "Ending early -- isTheaterModeOn=%s, letDialerHandleRinging=%s, " + "isSelfManaged=%s, hasExternalRinger=%s, silentRingingRequested=%s", isTheaterModeOn, letDialerHandleRinging, isSelfManaged, hasExternalRinger, isSilentRingingRequested); if (mBlockOnRingingFuture != null) { mBlockOnRingingFuture.complete(null); } return shouldAcquireAudioFocus; return attributes.shouldAcquireAudioFocus(); } stopCallWaiting(); Loading @@ -280,7 +268,7 @@ public class Ringer { CompletableFuture<Boolean> hapticsFuture = null; // Determine if the settings and DND mode indicate that the vibrator can be used right now. boolean isVibratorEnabled = isVibratorEnabled(mContext, foregroundCall); if (isRingerAudible) { if (attributes.isRingerAudible()) { mRingingCall = foregroundCall; Log.addEvent(foregroundCall, LogUtils.Events.START_RINGER); // Because we wait until a contact info query to complete before processing a Loading Loading @@ -331,15 +319,14 @@ public class Ringer { effect = getVibrationEffectForCall(mRingtoneFactory, foregroundCall); } } else { String reason = String.format( "isVolumeOverZero=%s, shouldRingForContact=%s, isRingtonePresent=%s", isVolumeOverZero, shouldRingForContact, isRingtonePresent); Log.i(this, "startRinging: skipping because ringer would not be audible. " + reason); Log.addEvent(foregroundCall, LogUtils.Events.SKIP_RINGING, "Inaudible: " + reason); Log.addEvent(foregroundCall, LogUtils.Events.SKIP_RINGING, "Inaudible: " + attributes.getInaudibleReason()); effect = mDefaultVibrationEffect; } if (hapticsFuture != null) { final boolean shouldRingForContact = attributes.shouldRingForContact(); final boolean isRingerAudible = attributes.isRingerAudible(); mVibrateFuture = hapticsFuture.thenAccept(isUsingAudioCoupledHaptics -> { if (!isUsingAudioCoupledHaptics || !mIsHapticPlaybackSupportedByDevice) { Log.i(this, "startRinging: fileHasHaptics=%b, hapticsSupported=%b", Loading @@ -365,11 +352,11 @@ public class Ringer { mBlockOnRingingFuture.complete(null); } Log.w(this, "startRinging: No haptics future; fallback to default behavior"); maybeStartVibration(foregroundCall, shouldRingForContact, effect, isVibratorEnabled, isRingerAudible); maybeStartVibration(foregroundCall, attributes.shouldRingForContact(), effect, isVibratorEnabled, attributes.isRingerAudible()); } return shouldAcquireAudioFocus; return attributes.shouldAcquireAudioFocus(); } private void maybeStartVibration(Call foregroundCall, boolean shouldRingForContact, Loading Loading @@ -538,4 +525,75 @@ public class Ringer { || (mSystemSettingsUtil.applyRampingRinger(context) && mSystemSettingsUtil.enableRampingRingerFromDeviceConfig()); } private RingerAttributes getRingerAttributes(Call call, boolean isHfpDeviceAttached) { RingerAttributes.Builder builder = new RingerAttributes.Builder(); LogUtils.EventTimer timer = new EventTimer(); boolean isVolumeOverZero = mAudioManager.getStreamVolume(AudioManager.STREAM_RING) > 0; timer.record("isVolumeOverZero"); boolean shouldRingForContact = shouldRingForContact(call.getContactUri()); timer.record("shouldRingForContact"); boolean isRingtonePresent = !(mRingtoneFactory.getRingtone(call) == null); timer.record("getRingtone"); boolean isSelfManaged = call.isSelfManaged(); timer.record("isSelfManaged"); boolean isSilentRingingRequested = call.isSilentRingingRequested(); timer.record("isSilentRingRequested"); boolean isRingerAudible = isVolumeOverZero && shouldRingForContact && isRingtonePresent; timer.record("isRingerAudible"); String inaudibleReason = ""; if (!isRingerAudible) { inaudibleReason = String.format( "isVolumeOverZero=%s, shouldRingForContact=%s, isRingtonePresent=%s", isVolumeOverZero, shouldRingForContact, isRingtonePresent); } boolean hasExternalRinger = hasExternalRinger(call); timer.record("hasExternalRinger"); // Don't do call waiting operations or vibration unless these are false. boolean isTheaterModeOn = mSystemSettingsUtil.isTheaterModeOn(mContext); timer.record("isTheaterModeOn"); boolean letDialerHandleRinging = mInCallController.doesConnectedDialerSupportRinging(); timer.record("letDialerHandleRinging"); Log.i(this, "startRinging timings: " + timer); boolean endEarly = isTheaterModeOn || letDialerHandleRinging || isSelfManaged || hasExternalRinger || isSilentRingingRequested; if (endEarly) { Log.i(this, "Ending early -- isTheaterModeOn=%s, letDialerHandleRinging=%s, " + "isSelfManaged=%s, hasExternalRinger=%s, silentRingingRequested=%s", isTheaterModeOn, letDialerHandleRinging, isSelfManaged, hasExternalRinger, isSilentRingingRequested); } // Acquire audio focus under any of the following conditions: // 1. Should ring for contact and there's an HFP device attached // 2. Volume is over zero, we should ring for the contact, and there's a audible ringtone // present. // 3. The call is self-managed. boolean shouldAcquireAudioFocus = isRingerAudible || (isHfpDeviceAttached && shouldRingForContact) || isSelfManaged; return builder.setEndEarly(endEarly) .setLetDialerHandleRinging(letDialerHandleRinging) .setAcquireAudioFocus(shouldAcquireAudioFocus) .setRingerAudible(isRingerAudible) .setInaudibleReason(inaudibleReason) .setShouldRingForContact(shouldRingForContact) .setSilentRingingRequested(isSilentRingingRequested) .build(); } private Handler getHandler() { if (mHandler == null) { HandlerThread handlerThread = new HandlerThread("Ringer"); handlerThread.start(); mHandler = handlerThread.getThreadHandler(); } return mHandler; } } src/com/android/server/telecom/RingerAttributes.java 0 → 100644 +118 −0 Original line number Diff line number Diff line /* * Copyright (C) 2020 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.server.telecom; public class RingerAttributes { public static class Builder { private boolean mEndEarly; private boolean mLetDialerHandleRinging; private boolean mAcquireAudioFocus; private boolean mRingerAudible; private String mInaudibleReason; private boolean mShouldRingForContact; private boolean mSilentRingingRequested; public RingerAttributes.Builder setEndEarly(boolean endEarly) { mEndEarly = endEarly; return this; } public RingerAttributes.Builder setLetDialerHandleRinging(boolean letDialerHandleRinging) { mLetDialerHandleRinging = letDialerHandleRinging; return this; } public RingerAttributes.Builder setAcquireAudioFocus(boolean acquireAudioFocus) { mAcquireAudioFocus = acquireAudioFocus; return this; } public RingerAttributes.Builder setRingerAudible(boolean ringerAudible) { mRingerAudible = ringerAudible; return this; } public RingerAttributes.Builder setInaudibleReason(String inaudibleReason) { mInaudibleReason = inaudibleReason; return this; } public RingerAttributes.Builder setShouldRingForContact(boolean shouldRingForContact) { mShouldRingForContact = shouldRingForContact; return this; } public RingerAttributes.Builder setSilentRingingRequested(boolean silentRingingRequested) { mSilentRingingRequested = silentRingingRequested; return this; } public RingerAttributes build() { return new RingerAttributes(mEndEarly, mLetDialerHandleRinging, mAcquireAudioFocus, mRingerAudible, mInaudibleReason, mShouldRingForContact, mSilentRingingRequested); } } private boolean mEndEarly; private boolean mLetDialerHandleRinging; private boolean mAcquireAudioFocus; private boolean mRingerAudible; private String mInaudibleReason; private boolean mShouldRingForContact; private boolean mSilentRingingRequested; private RingerAttributes(boolean endEarly, boolean letDialerHandleRinging, boolean acquireAudioFocus, boolean ringerAudible, String inaudibleReason, boolean shouldRingForContact, boolean silentRingingRequested) { mEndEarly = endEarly; mLetDialerHandleRinging = letDialerHandleRinging; mAcquireAudioFocus = acquireAudioFocus; mRingerAudible = ringerAudible; mInaudibleReason = inaudibleReason; mShouldRingForContact = shouldRingForContact; mSilentRingingRequested = silentRingingRequested; } public boolean isEndEarly() { return mEndEarly; } public boolean letDialerHandleRinging() { return mLetDialerHandleRinging; } public boolean shouldAcquireAudioFocus() { return mAcquireAudioFocus; } public boolean isRingerAudible() { return mRingerAudible; } public String getInaudibleReason() { return mInaudibleReason; } public boolean shouldRingForContact() { return mShouldRingForContact; } public boolean isSilentRingingRequested() { return mSilentRingingRequested; } } Loading
src/com/android/server/telecom/Ringer.java +115 −57 Original line number Diff line number Diff line Loading @@ -20,26 +20,27 @@ import android.app.Notification; import android.app.NotificationManager; import android.app.Person; import android.content.Context; import android.os.VibrationEffect; import android.telecom.Log; import android.telecom.TelecomManager; import android.media.AudioAttributes; import android.media.AudioManager; import android.media.Ringtone; import android.media.VolumeShaper; import android.net.Uri; import android.os.Bundle; import android.os.Handler; import android.os.HandlerThread; import android.os.VibrationEffect; import android.os.Vibrator; import android.telecom.Log; import android.telecom.TelecomManager; import com.android.internal.annotations.VisibleForTesting; import com.android.server.telecom.LogUtils.EventTimer; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; import java.util.stream.Collectors; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; /** * Controls the ringtone player. Loading Loading @@ -113,6 +114,8 @@ public class Ringer { private static final int DEFAULT_RAMPING_RINGER_DURATION = 10000; // 10 seconds private static final long RINGER_ATTRIBUTES_TIMEOUT = 5000; // 5 seconds private int mRampingRingerDuration = -1; // ramping ringer duration in millisecond // vibration duration before ramping ringer in second Loading Loading @@ -151,6 +154,7 @@ public class Ringer { private InCallTonePlayer mCallWaitingPlayer; private RingtoneFactory mRingtoneFactory; private AudioManager mAudioManager; /** * Call objects that are ringing, vibrating or call-waiting. These are used only for logging Loading @@ -165,6 +169,8 @@ public class Ringer { */ private boolean mIsVibrating = false; private Handler mHandler = null; /** Initializes the Ringer. */ @VisibleForTesting public Ringer( Loading @@ -187,6 +193,7 @@ public class Ringer { mRingtoneFactory = ringtoneFactory; mInCallController = inCallController; mVibrationEffectProxy = vibrationEffectProxy; mAudioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE); if (mContext.getResources().getBoolean(R.bool.use_simple_vibration_pattern)) { mDefaultVibrationEffect = mVibrationEffectProxy.createWaveform(SIMPLE_VIBRATION_PATTERN, Loading Loading @@ -220,58 +227,39 @@ public class Ringer { return false; } AudioManager audioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE); LogUtils.EventTimer timer = new EventTimer(); boolean isVolumeOverZero = audioManager.getStreamVolume(AudioManager.STREAM_RING) > 0; timer.record("isVolumeOverZero"); boolean shouldRingForContact = shouldRingForContact(foregroundCall.getContactUri()); timer.record("shouldRingForContact"); boolean isRingtonePresent = !(mRingtoneFactory.getRingtone(foregroundCall) == null); timer.record("getRingtone"); boolean isSelfManaged = foregroundCall.isSelfManaged(); timer.record("isSelfManaged"); boolean isSilentRingingRequested = foregroundCall.isSilentRingingRequested(); timer.record("isSilentRingRequested"); boolean isRingerAudible = isVolumeOverZero && shouldRingForContact && isRingtonePresent; timer.record("isRingerAudible"); boolean hasExternalRinger = hasExternalRinger(foregroundCall); timer.record("hasExternalRinger"); // Don't do call waiting operations or vibration unless these are false. boolean isTheaterModeOn = mSystemSettingsUtil.isTheaterModeOn(mContext); timer.record("isTheaterModeOn"); boolean letDialerHandleRinging = mInCallController.doesConnectedDialerSupportRinging(); timer.record("letDialerHandleRinging"); // Use completable future to establish a timeout, not intent to make these work outside the // main thread asynchronously // TODO: moving these RingerAttributes calculation out of Telecom lock to avoid blocking. CompletableFuture<RingerAttributes> ringerAttributesFuture = CompletableFuture .supplyAsync(() -> getRingerAttributes(foregroundCall, isHfpDeviceAttached), new LoggedHandlerExecutor(getHandler(), "R.sR", null)); Log.i(this, "startRinging timings: " + timer); boolean endEarly = isTheaterModeOn || letDialerHandleRinging || isSelfManaged || hasExternalRinger || isSilentRingingRequested; RingerAttributes attributes = null; try { attributes = ringerAttributesFuture.get( RINGER_ATTRIBUTES_TIMEOUT, TimeUnit.MILLISECONDS); } catch (ExecutionException | InterruptedException | TimeoutException e) { // Keep attributs as null Log.i(this, "getAttributes error: " + e); } // Acquire audio focus under any of the following conditions: // 1. Should ring for contact and there's an HFP device attached // 2. Volume is over zero, we should ring for the contact, and there's a audible ringtone // present. // 3. The call is self-managed. boolean shouldAcquireAudioFocus = isRingerAudible || (isHfpDeviceAttached && shouldRingForContact) || isSelfManaged; if (attributes == null) { Log.addEvent(foregroundCall, LogUtils.Events.SKIP_RINGING, "RingerAttributes error"); return false; } if (endEarly) { if (letDialerHandleRinging) { if (attributes.isEndEarly()) { if (attributes.letDialerHandleRinging()) { Log.addEvent(foregroundCall, LogUtils.Events.SKIP_RINGING, "Dialer handles"); } if (isSilentRingingRequested) { if (attributes.isSilentRingingRequested()) { Log.addEvent(foregroundCall, LogUtils.Events.SKIP_RINGING, "Silent ringing " + "requested"); } Log.i(this, "Ending early -- isTheaterModeOn=%s, letDialerHandleRinging=%s, " + "isSelfManaged=%s, hasExternalRinger=%s, silentRingingRequested=%s", isTheaterModeOn, letDialerHandleRinging, isSelfManaged, hasExternalRinger, isSilentRingingRequested); if (mBlockOnRingingFuture != null) { mBlockOnRingingFuture.complete(null); } return shouldAcquireAudioFocus; return attributes.shouldAcquireAudioFocus(); } stopCallWaiting(); Loading @@ -280,7 +268,7 @@ public class Ringer { CompletableFuture<Boolean> hapticsFuture = null; // Determine if the settings and DND mode indicate that the vibrator can be used right now. boolean isVibratorEnabled = isVibratorEnabled(mContext, foregroundCall); if (isRingerAudible) { if (attributes.isRingerAudible()) { mRingingCall = foregroundCall; Log.addEvent(foregroundCall, LogUtils.Events.START_RINGER); // Because we wait until a contact info query to complete before processing a Loading Loading @@ -331,15 +319,14 @@ public class Ringer { effect = getVibrationEffectForCall(mRingtoneFactory, foregroundCall); } } else { String reason = String.format( "isVolumeOverZero=%s, shouldRingForContact=%s, isRingtonePresent=%s", isVolumeOverZero, shouldRingForContact, isRingtonePresent); Log.i(this, "startRinging: skipping because ringer would not be audible. " + reason); Log.addEvent(foregroundCall, LogUtils.Events.SKIP_RINGING, "Inaudible: " + reason); Log.addEvent(foregroundCall, LogUtils.Events.SKIP_RINGING, "Inaudible: " + attributes.getInaudibleReason()); effect = mDefaultVibrationEffect; } if (hapticsFuture != null) { final boolean shouldRingForContact = attributes.shouldRingForContact(); final boolean isRingerAudible = attributes.isRingerAudible(); mVibrateFuture = hapticsFuture.thenAccept(isUsingAudioCoupledHaptics -> { if (!isUsingAudioCoupledHaptics || !mIsHapticPlaybackSupportedByDevice) { Log.i(this, "startRinging: fileHasHaptics=%b, hapticsSupported=%b", Loading @@ -365,11 +352,11 @@ public class Ringer { mBlockOnRingingFuture.complete(null); } Log.w(this, "startRinging: No haptics future; fallback to default behavior"); maybeStartVibration(foregroundCall, shouldRingForContact, effect, isVibratorEnabled, isRingerAudible); maybeStartVibration(foregroundCall, attributes.shouldRingForContact(), effect, isVibratorEnabled, attributes.isRingerAudible()); } return shouldAcquireAudioFocus; return attributes.shouldAcquireAudioFocus(); } private void maybeStartVibration(Call foregroundCall, boolean shouldRingForContact, Loading Loading @@ -538,4 +525,75 @@ public class Ringer { || (mSystemSettingsUtil.applyRampingRinger(context) && mSystemSettingsUtil.enableRampingRingerFromDeviceConfig()); } private RingerAttributes getRingerAttributes(Call call, boolean isHfpDeviceAttached) { RingerAttributes.Builder builder = new RingerAttributes.Builder(); LogUtils.EventTimer timer = new EventTimer(); boolean isVolumeOverZero = mAudioManager.getStreamVolume(AudioManager.STREAM_RING) > 0; timer.record("isVolumeOverZero"); boolean shouldRingForContact = shouldRingForContact(call.getContactUri()); timer.record("shouldRingForContact"); boolean isRingtonePresent = !(mRingtoneFactory.getRingtone(call) == null); timer.record("getRingtone"); boolean isSelfManaged = call.isSelfManaged(); timer.record("isSelfManaged"); boolean isSilentRingingRequested = call.isSilentRingingRequested(); timer.record("isSilentRingRequested"); boolean isRingerAudible = isVolumeOverZero && shouldRingForContact && isRingtonePresent; timer.record("isRingerAudible"); String inaudibleReason = ""; if (!isRingerAudible) { inaudibleReason = String.format( "isVolumeOverZero=%s, shouldRingForContact=%s, isRingtonePresent=%s", isVolumeOverZero, shouldRingForContact, isRingtonePresent); } boolean hasExternalRinger = hasExternalRinger(call); timer.record("hasExternalRinger"); // Don't do call waiting operations or vibration unless these are false. boolean isTheaterModeOn = mSystemSettingsUtil.isTheaterModeOn(mContext); timer.record("isTheaterModeOn"); boolean letDialerHandleRinging = mInCallController.doesConnectedDialerSupportRinging(); timer.record("letDialerHandleRinging"); Log.i(this, "startRinging timings: " + timer); boolean endEarly = isTheaterModeOn || letDialerHandleRinging || isSelfManaged || hasExternalRinger || isSilentRingingRequested; if (endEarly) { Log.i(this, "Ending early -- isTheaterModeOn=%s, letDialerHandleRinging=%s, " + "isSelfManaged=%s, hasExternalRinger=%s, silentRingingRequested=%s", isTheaterModeOn, letDialerHandleRinging, isSelfManaged, hasExternalRinger, isSilentRingingRequested); } // Acquire audio focus under any of the following conditions: // 1. Should ring for contact and there's an HFP device attached // 2. Volume is over zero, we should ring for the contact, and there's a audible ringtone // present. // 3. The call is self-managed. boolean shouldAcquireAudioFocus = isRingerAudible || (isHfpDeviceAttached && shouldRingForContact) || isSelfManaged; return builder.setEndEarly(endEarly) .setLetDialerHandleRinging(letDialerHandleRinging) .setAcquireAudioFocus(shouldAcquireAudioFocus) .setRingerAudible(isRingerAudible) .setInaudibleReason(inaudibleReason) .setShouldRingForContact(shouldRingForContact) .setSilentRingingRequested(isSilentRingingRequested) .build(); } private Handler getHandler() { if (mHandler == null) { HandlerThread handlerThread = new HandlerThread("Ringer"); handlerThread.start(); mHandler = handlerThread.getThreadHandler(); } return mHandler; } }
src/com/android/server/telecom/RingerAttributes.java 0 → 100644 +118 −0 Original line number Diff line number Diff line /* * Copyright (C) 2020 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.server.telecom; public class RingerAttributes { public static class Builder { private boolean mEndEarly; private boolean mLetDialerHandleRinging; private boolean mAcquireAudioFocus; private boolean mRingerAudible; private String mInaudibleReason; private boolean mShouldRingForContact; private boolean mSilentRingingRequested; public RingerAttributes.Builder setEndEarly(boolean endEarly) { mEndEarly = endEarly; return this; } public RingerAttributes.Builder setLetDialerHandleRinging(boolean letDialerHandleRinging) { mLetDialerHandleRinging = letDialerHandleRinging; return this; } public RingerAttributes.Builder setAcquireAudioFocus(boolean acquireAudioFocus) { mAcquireAudioFocus = acquireAudioFocus; return this; } public RingerAttributes.Builder setRingerAudible(boolean ringerAudible) { mRingerAudible = ringerAudible; return this; } public RingerAttributes.Builder setInaudibleReason(String inaudibleReason) { mInaudibleReason = inaudibleReason; return this; } public RingerAttributes.Builder setShouldRingForContact(boolean shouldRingForContact) { mShouldRingForContact = shouldRingForContact; return this; } public RingerAttributes.Builder setSilentRingingRequested(boolean silentRingingRequested) { mSilentRingingRequested = silentRingingRequested; return this; } public RingerAttributes build() { return new RingerAttributes(mEndEarly, mLetDialerHandleRinging, mAcquireAudioFocus, mRingerAudible, mInaudibleReason, mShouldRingForContact, mSilentRingingRequested); } } private boolean mEndEarly; private boolean mLetDialerHandleRinging; private boolean mAcquireAudioFocus; private boolean mRingerAudible; private String mInaudibleReason; private boolean mShouldRingForContact; private boolean mSilentRingingRequested; private RingerAttributes(boolean endEarly, boolean letDialerHandleRinging, boolean acquireAudioFocus, boolean ringerAudible, String inaudibleReason, boolean shouldRingForContact, boolean silentRingingRequested) { mEndEarly = endEarly; mLetDialerHandleRinging = letDialerHandleRinging; mAcquireAudioFocus = acquireAudioFocus; mRingerAudible = ringerAudible; mInaudibleReason = inaudibleReason; mShouldRingForContact = shouldRingForContact; mSilentRingingRequested = silentRingingRequested; } public boolean isEndEarly() { return mEndEarly; } public boolean letDialerHandleRinging() { return mLetDialerHandleRinging; } public boolean shouldAcquireAudioFocus() { return mAcquireAudioFocus; } public boolean isRingerAudible() { return mRingerAudible; } public String getInaudibleReason() { return mInaudibleReason; } public boolean shouldRingForContact() { return mShouldRingForContact; } public boolean isSilentRingingRequested() { return mSilentRingingRequested; } }