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

Commit 422b0d24 authored by Thomas Stuart's avatar Thomas Stuart
Browse files

add anom report and more logs to Ringer haptics

Some users reported their incoming calls did not vibrate even though
their settings indicate vibrate.  It's not clear what exactly is
happening so more logs should be added to the haptics path.

Flag: com.android.server.telecom.flags.get_ringer_mode_anom_report
Bug: 307389562
Test: manual
Change-Id: If2b88c7c6141007899d870e49e334d758bd02745
parent 16f94ccc
Loading
Loading
Loading
Loading
+12 −0
Original line number Original line Diff line number Diff line
@@ -16,3 +16,15 @@ flag {
  description: "Gates whether to ensure that when a user is in their car, they are able to hear ringing for an incoming call."
  description: "Gates whether to ensure that when a user is in their car, they are able to hear ringing for an incoming call."
  bug: "348708398"
  bug: "348708398"
}
}


# OWNER=tjstuart TARGET=25Q1
flag {
  name: "get_ringer_mode_anom_report"
  namespace: "telecom"
  description: "getRingerMode & getRingerModeInternal should return the same val when dnd is off"
  bug: "307389562"
    metadata {
      purpose: PURPOSE_BUGFIX
    }
}
 No newline at end of file
+1 −1
Original line number Original line Diff line number Diff line
@@ -703,7 +703,7 @@ public class CallsManager extends Call.ListenerBase
                ringtoneFactory, systemVibrator,
                ringtoneFactory, systemVibrator,
                new Ringer.VibrationEffectProxy(), mInCallController,
                new Ringer.VibrationEffectProxy(), mInCallController,
                mContext.getSystemService(NotificationManager.class),
                mContext.getSystemService(NotificationManager.class),
                accessibilityManagerAdapter, featureFlags);
                accessibilityManagerAdapter, featureFlags, mAnomalyReporter);
        if (featureFlags.telecomResolveHiddenDependencies()) {
        if (featureFlags.telecomResolveHiddenDependencies()) {
            // This is now deprecated
            // This is now deprecated
            mCallRecordingTonePlayer = null;
            mCallRecordingTonePlayer = null;
+45 −5
Original line number Original line Diff line number Diff line
@@ -59,6 +59,7 @@ import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.ArrayList;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutionException;
@@ -176,6 +177,11 @@ public class Ringer {


    private static VolumeShaper.Configuration mVolumeShaperConfig;
    private static VolumeShaper.Configuration mVolumeShaperConfig;


    public static final UUID GET_RINGER_MODE_ANOMALY_UUID =
            UUID.fromString("eb10505b-4d7b-4fab-b4a1-a18186799065");
    public static final String GET_RINGER_MODE_ANOMALY_MSG = "AM#GetRingerMode() and"
            + " AM#GetRingerModeInternal() are returning diff values when DoNotDisturb is OFF!";

    /**
    /**
     * Used to keep ordering of unanswered incoming calls. There can easily exist multiple incoming
     * Used to keep ordering of unanswered incoming calls. There can easily exist multiple incoming
     * calls and explicit ordering is useful for maintaining the proper state of the ringer.
     * calls and explicit ordering is useful for maintaining the proper state of the ringer.
@@ -191,6 +197,8 @@ public class Ringer {
    private final boolean mIsHapticPlaybackSupportedByDevice;
    private final boolean mIsHapticPlaybackSupportedByDevice;
    private final FeatureFlags mFlags;
    private final FeatureFlags mFlags;
    private final boolean mRingtoneVibrationSupported;
    private final boolean mRingtoneVibrationSupported;
    private final AnomalyReporterAdapter mAnomalyReporter;

    /**
    /**
     * For unit testing purposes only; when set, {@link #startRinging(Call, boolean)} will complete
     * For unit testing purposes only; when set, {@link #startRinging(Call, boolean)} will complete
     * the future provided by the test using {@link #setBlockOnRingingFuture(CompletableFuture)}.
     * the future provided by the test using {@link #setBlockOnRingingFuture(CompletableFuture)}.
@@ -237,7 +245,8 @@ public class Ringer {
            InCallController inCallController,
            InCallController inCallController,
            NotificationManager notificationManager,
            NotificationManager notificationManager,
            AccessibilityManagerAdapter accessibilityManagerAdapter,
            AccessibilityManagerAdapter accessibilityManagerAdapter,
            FeatureFlags featureFlags) {
            FeatureFlags featureFlags,
            AnomalyReporterAdapter anomalyReporter) {


        mLock = new Object();
        mLock = new Object();
        mSystemSettingsUtil = systemSettingsUtil;
        mSystemSettingsUtil = systemSettingsUtil;
@@ -252,6 +261,7 @@ public class Ringer {
        mVibrationEffectProxy = vibrationEffectProxy;
        mVibrationEffectProxy = vibrationEffectProxy;
        mNotificationManager = notificationManager;
        mNotificationManager = notificationManager;
        mAccessibilityManagerAdapter = accessibilityManagerAdapter;
        mAccessibilityManagerAdapter = accessibilityManagerAdapter;
        mAnomalyReporter = anomalyReporter;


        mDefaultVibrationEffect =
        mDefaultVibrationEffect =
                loadDefaultRingVibrationEffect(
                loadDefaultRingVibrationEffect(
@@ -405,10 +415,9 @@ public class Ringer {
                    // If ringer is not audible for this call, then the phone is in "Vibrate" mode.
                    // If ringer is not audible for this call, then the phone is in "Vibrate" mode.
                    // Use haptic-only ringtone or do not play anything.
                    // Use haptic-only ringtone or do not play anything.
                    isHapticOnly = true;
                    isHapticOnly = true;
                    if (DEBUG_RINGER) {
                    Log.i(this, "Set ringtone as haptic only: " + isHapticOnly);
                    Log.i(this, "Set ringtone as haptic only: " + isHapticOnly);
                    }
                } else {
                } else {
                    Log.i(this, "ringer & haptics are off, user missed alerts for call");
                    foregroundCall.setUserMissed(USER_MISSED_NO_VIBRATE);
                    foregroundCall.setUserMissed(USER_MISSED_NO_VIBRATE);
                    Log.addEvent(foregroundCall, LogUtils.Events.SKIP_VIBRATION,
                    Log.addEvent(foregroundCall, LogUtils.Events.SKIP_VIBRATION,
                            vibratorAttrs);
                            vibratorAttrs);
@@ -437,7 +446,7 @@ public class Ringer {
                ringtoneInfoSupplier = () -> mRingtoneFactory.getRingtone(
                ringtoneInfoSupplier = () -> mRingtoneFactory.getRingtone(
                        foregroundCall, null, false);
                        foregroundCall, null, false);
            }
            }

            Log.i(this, "isRingtoneInfoSupplierNull=[%b]", ringtoneInfoSupplier == null);
            // If vibration will be done, reserve the vibrator.
            // If vibration will be done, reserve the vibrator.
            boolean vibratorReserved = isVibratorEnabled && attributes.shouldRingForContact()
            boolean vibratorReserved = isVibratorEnabled && attributes.shouldRingForContact()
                && tryReserveVibration(foregroundCall);
                && tryReserveVibration(foregroundCall);
@@ -706,12 +715,43 @@ public class Ringer {
        // AudioManager#getRingerModeInternal which only useful for volume controllers
        // AudioManager#getRingerModeInternal which only useful for volume controllers
        boolean zenModeOn = mNotificationManager != null
        boolean zenModeOn = mNotificationManager != null
                && mNotificationManager.getZenMode() != ZEN_MODE_OFF;
                && mNotificationManager.getZenMode() != ZEN_MODE_OFF;
        maybeGenAnomReportForGetRingerMode(zenModeOn, audioManager);
        return mVibrator.hasVibrator()
        return mVibrator.hasVibrator()
                && mSystemSettingsUtil.isRingVibrationEnabled(context)
                && mSystemSettingsUtil.isRingVibrationEnabled(context)
                && (audioManager.getRingerMode() != AudioManager.RINGER_MODE_SILENT
                && (audioManager.getRingerMode() != AudioManager.RINGER_MODE_SILENT
                || (zenModeOn && shouldRingForContact));
                || (zenModeOn && shouldRingForContact));
    }
    }


    /**
     * There are 3 settings for haptics:
     * - AudioManager.RINGER_MODE_SILENT
     * - AudioManager.RINGER_MODE_VIBRATE
     * - AudioManager.RINGER_MODE_NORMAL
     * If the user does not have {@link AudioManager#RINGER_MODE_SILENT} set, the user should
     * have haptic feeback
     *
     * Note: If DND/ZEN_MODE is on, {@link AudioManager#getRingerMode()} will return
     * {@link AudioManager#RINGER_MODE_SILENT}, regardless of the user setting. Therefore,
     * getRingerModeInternal is the source of truth instead of {@link AudioManager#getRingerMode()}.
     * However, if DND/ZEN_MOD is off, the APIs should return the same value.  Generate an anomaly
     * report if they diverge.
     */
    private void maybeGenAnomReportForGetRingerMode(boolean isZenModeOn, AudioManager am) {
        if (!mFlags.getRingerModeAnomReport()) {
            return;
        }
        if (!isZenModeOn) {
            int ringerMode = am.getRingerMode();
            int ringerModeInternal = am.getRingerModeInternal();
            if (ringerMode != ringerModeInternal) {
                Log.i(this, "getRingerMode=[%d], getRingerModeInternal=[%d]",
                        ringerMode, ringerModeInternal);
                mAnomalyReporter.reportAnomaly(GET_RINGER_MODE_ANOMALY_UUID,
                        GET_RINGER_MODE_ANOMALY_MSG);
            }
        }
    }

    private RingerAttributes getRingerAttributes(Call call, boolean isHfpDeviceAttached) {
    private RingerAttributes getRingerAttributes(Call call, boolean isHfpDeviceAttached) {
        mAudioManager = mContext.getSystemService(AudioManager.class);
        mAudioManager = mContext.getSystemService(AudioManager.class);
        RingerAttributes.Builder builder = new RingerAttributes.Builder();
        RingerAttributes.Builder builder = new RingerAttributes.Builder();
+3 −1
Original line number Original line Diff line number Diff line
@@ -66,6 +66,7 @@ import android.util.Pair;


import androidx.test.filters.SmallTest;
import androidx.test.filters.SmallTest;


import com.android.server.telecom.AnomalyReporterAdapter;
import com.android.server.telecom.AsyncRingtonePlayer;
import com.android.server.telecom.AsyncRingtonePlayer;
import com.android.server.telecom.Call;
import com.android.server.telecom.Call;
import com.android.server.telecom.CallState;
import com.android.server.telecom.CallState;
@@ -123,6 +124,7 @@ public class RingerTest extends TelecomTestCase {
    @Mock NotificationManager mockNotificationManager;
    @Mock NotificationManager mockNotificationManager;
    @Mock Ringer.AccessibilityManagerAdapter mockAccessibilityManagerAdapter;
    @Mock Ringer.AccessibilityManagerAdapter mockAccessibilityManagerAdapter;
    @Mock private FeatureFlags mFeatureFlags;
    @Mock private FeatureFlags mFeatureFlags;
    @Mock private AnomalyReporterAdapter mAnomalyReporterAdapter;


    @Spy Ringer.VibrationEffectProxy spyVibrationEffectProxy;
    @Spy Ringer.VibrationEffectProxy spyVibrationEffectProxy;


@@ -178,7 +180,7 @@ public class RingerTest extends TelecomTestCase {
        mRingerUnderTest = new Ringer(mockPlayerFactory, mContext, mockSystemSettingsUtil,
        mRingerUnderTest = new Ringer(mockPlayerFactory, mContext, mockSystemSettingsUtil,
                asyncRingtonePlayer, mockRingtoneFactory, mockVibrator, spyVibrationEffectProxy,
                asyncRingtonePlayer, mockRingtoneFactory, mockVibrator, spyVibrationEffectProxy,
                mockInCallController, mockNotificationManager, mockAccessibilityManagerAdapter,
                mockInCallController, mockNotificationManager, mockAccessibilityManagerAdapter,
                mFeatureFlags);
                mFeatureFlags, mAnomalyReporterAdapter);
        // This future is used to wait for AsyncRingtonePlayer to finish its part.
        // This future is used to wait for AsyncRingtonePlayer to finish its part.
        mRingerUnderTest.setBlockOnRingingFuture(mRingCompletionFuture);
        mRingerUnderTest.setBlockOnRingingFuture(mRingCompletionFuture);
    }
    }