Merge "Rename the flag of keep_bt_devices_cache_updated" into main
diff --git a/flags/telecom_ringer_flag_declarations.aconfig b/flags/telecom_ringer_flag_declarations.aconfig
index 6517e0f..f954b09 100644
--- a/flags/telecom_ringer_flag_declarations.aconfig
+++ b/flags/telecom_ringer_flag_declarations.aconfig
@@ -15,4 +15,16 @@
   namespace: "telecom"
   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"
+}
+
+
+# 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
diff --git a/src/com/android/server/telecom/CallsManager.java b/src/com/android/server/telecom/CallsManager.java
index 9670d6a..22b28b5 100644
--- a/src/com/android/server/telecom/CallsManager.java
+++ b/src/com/android/server/telecom/CallsManager.java
@@ -703,7 +703,7 @@
                 ringtoneFactory, systemVibrator,
                 new Ringer.VibrationEffectProxy(), mInCallController,
                 mContext.getSystemService(NotificationManager.class),
-                accessibilityManagerAdapter, featureFlags);
+                accessibilityManagerAdapter, featureFlags, mAnomalyReporter);
         if (featureFlags.telecomResolveHiddenDependencies()) {
             // This is now deprecated
             mCallRecordingTonePlayer = null;
diff --git a/src/com/android/server/telecom/Ringer.java b/src/com/android/server/telecom/Ringer.java
index 12778b0..bfaadf0 100644
--- a/src/com/android/server/telecom/Ringer.java
+++ b/src/com/android/server/telecom/Ringer.java
@@ -59,6 +59,7 @@
 import java.io.InputStreamReader;
 import java.nio.charset.StandardCharsets;
 import java.util.ArrayList;
+import java.util.UUID;
 import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.ExecutionException;
@@ -176,6 +177,11 @@
 
     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
      * calls and explicit ordering is useful for maintaining the proper state of the ringer.
@@ -191,6 +197,8 @@
     private final boolean mIsHapticPlaybackSupportedByDevice;
     private final FeatureFlags mFlags;
     private final boolean mRingtoneVibrationSupported;
+    private final AnomalyReporterAdapter mAnomalyReporter;
+
     /**
      * For unit testing purposes only; when set, {@link #startRinging(Call, boolean)} will complete
      * the future provided by the test using {@link #setBlockOnRingingFuture(CompletableFuture)}.
@@ -237,7 +245,8 @@
             InCallController inCallController,
             NotificationManager notificationManager,
             AccessibilityManagerAdapter accessibilityManagerAdapter,
-            FeatureFlags featureFlags) {
+            FeatureFlags featureFlags,
+            AnomalyReporterAdapter anomalyReporter) {
 
         mLock = new Object();
         mSystemSettingsUtil = systemSettingsUtil;
@@ -252,6 +261,7 @@
         mVibrationEffectProxy = vibrationEffectProxy;
         mNotificationManager = notificationManager;
         mAccessibilityManagerAdapter = accessibilityManagerAdapter;
+        mAnomalyReporter = anomalyReporter;
 
         mDefaultVibrationEffect =
                 loadDefaultRingVibrationEffect(
@@ -405,10 +415,9 @@
                     // If ringer is not audible for this call, then the phone is in "Vibrate" mode.
                     // Use haptic-only ringtone or do not play anything.
                     isHapticOnly = true;
-                    if (DEBUG_RINGER) {
-                        Log.i(this, "Set ringtone as haptic only: " + isHapticOnly);
-                    }
+                    Log.i(this, "Set ringtone as haptic only: " + isHapticOnly);
                 } else {
+                    Log.i(this, "ringer & haptics are off, user missed alerts for call");
                     foregroundCall.setUserMissed(USER_MISSED_NO_VIBRATE);
                     Log.addEvent(foregroundCall, LogUtils.Events.SKIP_VIBRATION,
                             vibratorAttrs);
@@ -437,7 +446,7 @@
                 ringtoneInfoSupplier = () -> mRingtoneFactory.getRingtone(
                         foregroundCall, null, false);
             }
-
+            Log.i(this, "isRingtoneInfoSupplierNull=[%b]", ringtoneInfoSupplier == null);
             // If vibration will be done, reserve the vibrator.
             boolean vibratorReserved = isVibratorEnabled && attributes.shouldRingForContact()
                 && tryReserveVibration(foregroundCall);
@@ -706,12 +715,43 @@
         // AudioManager#getRingerModeInternal which only useful for volume controllers
         boolean zenModeOn = mNotificationManager != null
                 && mNotificationManager.getZenMode() != ZEN_MODE_OFF;
+        maybeGenAnomReportForGetRingerMode(zenModeOn, audioManager);
         return mVibrator.hasVibrator()
                 && mSystemSettingsUtil.isRingVibrationEnabled(context)
                 && (audioManager.getRingerMode() != AudioManager.RINGER_MODE_SILENT
                 || (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) {
         mAudioManager = mContext.getSystemService(AudioManager.class);
         RingerAttributes.Builder builder = new RingerAttributes.Builder();
diff --git a/tests/src/com/android/server/telecom/tests/RingerTest.java b/tests/src/com/android/server/telecom/tests/RingerTest.java
index c4d9678..46916fd 100644
--- a/tests/src/com/android/server/telecom/tests/RingerTest.java
+++ b/tests/src/com/android/server/telecom/tests/RingerTest.java
@@ -66,6 +66,7 @@
 
 import androidx.test.filters.SmallTest;
 
+import com.android.server.telecom.AnomalyReporterAdapter;
 import com.android.server.telecom.AsyncRingtonePlayer;
 import com.android.server.telecom.Call;
 import com.android.server.telecom.CallState;
@@ -123,6 +124,7 @@
     @Mock NotificationManager mockNotificationManager;
     @Mock Ringer.AccessibilityManagerAdapter mockAccessibilityManagerAdapter;
     @Mock private FeatureFlags mFeatureFlags;
+    @Mock private AnomalyReporterAdapter mAnomalyReporterAdapter;
 
     @Spy Ringer.VibrationEffectProxy spyVibrationEffectProxy;
 
@@ -178,7 +180,7 @@
         mRingerUnderTest = new Ringer(mockPlayerFactory, mContext, mockSystemSettingsUtil,
                 asyncRingtonePlayer, mockRingtoneFactory, mockVibrator, spyVibrationEffectProxy,
                 mockInCallController, mockNotificationManager, mockAccessibilityManagerAdapter,
-                mFeatureFlags);
+                mFeatureFlags, mAnomalyReporterAdapter);
         // This future is used to wait for AsyncRingtonePlayer to finish its part.
         mRingerUnderTest.setBlockOnRingingFuture(mRingCompletionFuture);
     }