Merge changes from topic "opt_mode_ds" into main

* changes:
  Add AppOptimizationModeEventsUtils to save & update app optimization mode expiration events.
  Dump app optimization mode expiration event data in bug report.
diff --git a/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamButtonControllerTest.java b/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamButtonControllerTest.java
index adcc617..cbf1432 100644
--- a/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamButtonControllerTest.java
+++ b/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamButtonControllerTest.java
@@ -34,12 +34,12 @@
 import com.android.settings.testutils.shadow.ShadowThreadUtils;
 import com.android.settingslib.widget.ActionButtonsPreference;
 
+import org.junit.After;
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.Mock;
-import org.mockito.Spy;
 import org.mockito.junit.MockitoJUnit;
 import org.mockito.junit.MockitoRule;
 import org.robolectric.RobolectricTestRunner;
@@ -59,7 +59,7 @@
     @Rule public final MockitoRule mMockitoRule = MockitoJUnit.rule();
     private static final String KEY = "audio_stream_button";
     private static final int BROADCAST_ID = 1;
-    @Spy Context mContext = ApplicationProvider.getApplicationContext();
+    private final Context mContext = ApplicationProvider.getApplicationContext();
     @Mock private AudioStreamsHelper mAudioStreamsHelper;
     @Mock private PreferenceScreen mScreen;
     @Mock private BluetoothLeBroadcastReceiveState mBroadcastReceiveState;
@@ -80,6 +80,11 @@
                 .thenReturn(mPreference);
     }
 
+    @After
+    public void tearDown() {
+        ShadowAudioStreamsHelper.reset();
+    }
+
     @Test
     public void testDisplayPreference_sourceConnected_setDisconnectButton() {
         when(mAudioStreamsHelper.getAllConnectedSources())
diff --git a/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamHeaderControllerTest.java b/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamHeaderControllerTest.java
index 0af9c17..0cd5d61 100644
--- a/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamHeaderControllerTest.java
+++ b/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamHeaderControllerTest.java
@@ -34,12 +34,12 @@
 import com.android.settings.widget.EntityHeaderController;
 import com.android.settingslib.widget.LayoutPreference;
 
+import org.junit.After;
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.Mock;
-import org.mockito.Spy;
 import org.mockito.junit.MockitoJUnit;
 import org.mockito.junit.MockitoRule;
 import org.robolectric.RobolectricTestRunner;
@@ -61,7 +61,7 @@
     private static final String KEY = "audio_stream_header";
     private static final int BROADCAST_ID = 1;
     private static final String BROADCAST_NAME = "broadcast name";
-    @Spy Context mContext = ApplicationProvider.getApplicationContext();
+    private final Context mContext = ApplicationProvider.getApplicationContext();
     @Mock private AudioStreamsHelper mAudioStreamsHelper;
     @Mock private PreferenceScreen mScreen;
     @Mock private BluetoothLeBroadcastReceiveState mBroadcastReceiveState;
@@ -81,6 +81,12 @@
         when(mPreference.getContext()).thenReturn(mContext);
     }
 
+    @After
+    public void tearDown() {
+        ShadowEntityHeaderController.reset();
+        ShadowAudioStreamsHelper.reset();
+    }
+
     @Test
     public void testDisplayPreference_sourceConnected_setSummary() {
         when(mAudioStreamsHelper.getAllConnectedSources())
diff --git a/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamPreferenceTest.java b/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamPreferenceTest.java
index 0c93e3e..456e45d3 100644
--- a/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamPreferenceTest.java
+++ b/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamPreferenceTest.java
@@ -30,6 +30,7 @@
 
 import androidx.preference.Preference.OnPreferenceClickListener;
 import androidx.preference.PreferenceViewHolder;
+import androidx.test.core.app.ApplicationProvider;
 
 import com.android.settings.R;
 import com.android.settings.connecteddevice.audiosharing.audiostreams.AudioStreamsProgressCategoryController.AudioStreamState;
@@ -42,7 +43,6 @@
 import org.mockito.junit.MockitoJUnit;
 import org.mockito.junit.MockitoRule;
 import org.robolectric.RobolectricTestRunner;
-import org.robolectric.RuntimeEnvironment;
 
 import java.util.Collections;
 
@@ -53,7 +53,7 @@
     private static final String PROGRAM_NAME = "program_name";
     private static final int BROADCAST_RSSI = 1;
     @Rule public final MockitoRule mMockitoRule = MockitoJUnit.rule();
-    private Context mContext;
+    private final Context mContext = ApplicationProvider.getApplicationContext();
     private AudioStreamPreference mPreference;
     @Mock private BluetoothLeBroadcastMetadata mBluetoothLeBroadcastMetadata;
     @Mock private BluetoothLeBroadcastReceiveState mBluetoothLeBroadcastReceiveState;
@@ -61,7 +61,6 @@
 
     @Before
     public void setUp() {
-        mContext = RuntimeEnvironment.application;
         mPreference = new AudioStreamPreference(mContext, null);
         when(mBluetoothLeBroadcastMetadata.getBroadcastId()).thenReturn(BROADCAST_ID);
         when(mBluetoothLeBroadcastMetadata.getBroadcastName()).thenReturn(BROADCAST_NAME);
diff --git a/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamsActiveDeviceControllerTest.java b/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamsActiveDeviceControllerTest.java
index c029635..3fd257f 100644
--- a/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamsActiveDeviceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamsActiveDeviceControllerTest.java
@@ -28,6 +28,7 @@
 
 import androidx.preference.Preference;
 import androidx.preference.PreferenceScreen;
+import androidx.test.core.app.ApplicationProvider;
 
 import org.junit.Before;
 import org.junit.Rule;
@@ -37,7 +38,6 @@
 import org.mockito.junit.MockitoJUnit;
 import org.mockito.junit.MockitoRule;
 import org.robolectric.RobolectricTestRunner;
-import org.robolectric.RuntimeEnvironment;
 
 @RunWith(RobolectricTestRunner.class)
 public class AudioStreamsActiveDeviceControllerTest {
@@ -48,7 +48,7 @@
 
     @Before
     public void setUp() {
-        Context context = RuntimeEnvironment.application;
+        Context context = ApplicationProvider.getApplicationContext();
         mController =
                 new AudioStreamsActiveDeviceController(
                         context, AudioStreamsActiveDeviceController.KEY);
diff --git a/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamsActiveDeviceSummaryUpdaterTest.java b/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamsActiveDeviceSummaryUpdaterTest.java
index 3bcc9a3..4403528 100644
--- a/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamsActiveDeviceSummaryUpdaterTest.java
+++ b/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamsActiveDeviceSummaryUpdaterTest.java
@@ -30,12 +30,12 @@
 import com.android.settings.connecteddevice.audiosharing.audiostreams.testshadows.ShadowAudioStreamsHelper;
 import com.android.settingslib.bluetooth.CachedBluetoothDevice;
 
+import org.junit.After;
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.Mock;
-import org.mockito.Spy;
 import org.mockito.junit.MockitoJUnit;
 import org.mockito.junit.MockitoRule;
 import org.robolectric.RobolectricTestRunner;
@@ -49,7 +49,7 @@
 public class AudioStreamsActiveDeviceSummaryUpdaterTest {
     @Rule public final MockitoRule mMockitoRule = MockitoJUnit.rule();
     private static final String DEVICE_NAME = "device_name";
-    @Spy private final Context mContext = ApplicationProvider.getApplicationContext();
+    private final Context mContext = ApplicationProvider.getApplicationContext();
     private final AudioStreamsActiveDeviceSummaryUpdater.OnSummaryChangeListener mFakeListener =
             summary -> mUpdatedSummary = summary;
     @Mock private CachedBluetoothDevice mCachedBluetoothDevice;
@@ -60,10 +60,14 @@
     @Before
     public void setUp() {
         ShadowAudioStreamsHelper.setUseMock(mAudioStreamsHelper);
-        ShadowAudioStreamsHelper.resetCachedBluetoothDevice();
         mUpdater = new AudioStreamsActiveDeviceSummaryUpdater(mContext, mFakeListener);
     }
 
+    @After
+    public void tearDown() {
+        ShadowAudioStreamsHelper.reset();
+    }
+
     @Test
     public void register_summaryUpdated() {
         mUpdater.register(true);
diff --git a/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/audiostreams/MediaControlHelperTest.java b/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/audiostreams/MediaControlHelperTest.java
index 113fc72..2506d86 100644
--- a/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/audiostreams/MediaControlHelperTest.java
+++ b/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/audiostreams/MediaControlHelperTest.java
@@ -23,6 +23,8 @@
 import android.media.session.MediaSessionManager;
 import android.media.session.PlaybackState;
 
+import androidx.test.core.app.ApplicationProvider;
+
 import com.android.settings.connecteddevice.audiosharing.audiostreams.testshadows.ShadowAudioStreamsHelper;
 import com.android.settings.connecteddevice.audiosharing.audiostreams.testshadows.ShadowLocalMediaManager;
 import com.android.settingslib.bluetooth.CachedBluetoothDevice;
@@ -30,6 +32,7 @@
 import com.android.settingslib.media.BluetoothMediaDevice;
 import com.android.settingslib.media.LocalMediaManager;
 
+import org.junit.After;
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
@@ -38,7 +41,6 @@
 import org.mockito.junit.MockitoJUnit;
 import org.mockito.junit.MockitoRule;
 import org.robolectric.RobolectricTestRunner;
-import org.robolectric.RuntimeEnvironment;
 import org.robolectric.annotation.Config;
 
 import java.util.List;
@@ -64,15 +66,20 @@
 
     @Before
     public void setUp() {
-        mContext = spy(RuntimeEnvironment.application);
+        mContext = spy(ApplicationProvider.getApplicationContext());
         when(mContext.getSystemService(MediaSessionManager.class)).thenReturn(mMediaSessionManager);
         when(mMediaSessionManager.getActiveSessions(any())).thenReturn(List.of(mMediaController));
         when(mMediaController.getPackageName()).thenReturn(FAKE_PACKAGE);
         when(mMediaController.getPlaybackState()).thenReturn(mPlaybackState);
-        ShadowAudioStreamsHelper.resetCachedBluetoothDevice();
         ShadowLocalMediaManager.setUseMock(mLocalMediaManager);
     }
 
+    @After
+    public void tearDown() {
+        ShadowAudioStreamsHelper.reset();
+        ShadowLocalMediaManager.reset();
+    }
+
     @Test
     public void testStart_noBluetoothManager_doNothing() {
         MediaControlHelper helper = new MediaControlHelper(mContext, null);
diff --git a/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/audiostreams/SyncedStateTest.java b/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/audiostreams/SyncedStateTest.java
index 64e1bc4..e9eab50 100644
--- a/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/audiostreams/SyncedStateTest.java
+++ b/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/audiostreams/SyncedStateTest.java
@@ -21,7 +21,6 @@
 import static com.google.common.truth.Truth.assertThat;
 
 import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 import static org.robolectric.shadows.ShadowLooper.shadowMainLooper;
@@ -33,6 +32,7 @@
 import androidx.preference.Preference;
 import androidx.test.core.app.ApplicationProvider;
 
+import org.junit.After;
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
@@ -60,10 +60,15 @@
     @Before
     public void setUp() {
         ShadowAlertDialog.reset();
-        mMockContext = spy(ApplicationProvider.getApplicationContext());
+        mMockContext = ApplicationProvider.getApplicationContext();
         mInstance = SyncedState.getInstance();
     }
 
+    @After
+    public void tearDown() {
+        ShadowAlertDialog.reset();
+    }
+
     @Test
     public void testGetInstance() {
         assertThat(mInstance).isNotNull();
diff --git a/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/audiostreams/testshadows/ShadowAudioStreamsHelper.java b/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/audiostreams/testshadows/ShadowAudioStreamsHelper.java
index 0dff64d..331a30b 100644
--- a/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/audiostreams/testshadows/ShadowAudioStreamsHelper.java
+++ b/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/audiostreams/testshadows/ShadowAudioStreamsHelper.java
@@ -18,12 +18,15 @@
 
 import android.bluetooth.BluetoothLeBroadcastReceiveState;
 
+import androidx.annotation.Nullable;
+
 import com.android.settings.connecteddevice.audiosharing.audiostreams.AudioStreamsHelper;
 import com.android.settingslib.bluetooth.CachedBluetoothDevice;
 import com.android.settingslib.bluetooth.LocalBluetoothManager;
 
 import org.robolectric.annotation.Implementation;
 import org.robolectric.annotation.Implements;
+import org.robolectric.annotation.Resetter;
 
 import java.util.List;
 import java.util.Optional;
@@ -31,20 +34,22 @@
 @Implements(value = AudioStreamsHelper.class, callThroughByDefault = false)
 public class ShadowAudioStreamsHelper {
     private static AudioStreamsHelper sMockHelper;
-    private static Optional<CachedBluetoothDevice> sCachedBluetoothDevice;
+    @Nullable private static CachedBluetoothDevice sCachedBluetoothDevice;
 
     public static void setUseMock(AudioStreamsHelper mockAudioStreamsHelper) {
         sMockHelper = mockAudioStreamsHelper;
     }
 
-    /** Resets {@link CachedBluetoothDevice} */
-    public static void resetCachedBluetoothDevice() {
-        sCachedBluetoothDevice = Optional.empty();
+    /** Reset static fields */
+    @Resetter
+    public static void reset() {
+        sMockHelper = null;
+        sCachedBluetoothDevice = null;
     }
 
     public static void setCachedBluetoothDeviceInSharingOrLeConnected(
             CachedBluetoothDevice cachedBluetoothDevice) {
-        sCachedBluetoothDevice = Optional.of(cachedBluetoothDevice);
+        sCachedBluetoothDevice = cachedBluetoothDevice;
     }
 
     @Implementation
@@ -56,6 +61,6 @@
     @Implementation
     public static Optional<CachedBluetoothDevice> getCachedBluetoothDeviceInSharingOrLeConnected(
             LocalBluetoothManager manager) {
-        return sCachedBluetoothDevice;
+        return Optional.ofNullable(sCachedBluetoothDevice);
     }
 }
diff --git a/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/audiostreams/testshadows/ShadowEntityHeaderController.java b/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/audiostreams/testshadows/ShadowEntityHeaderController.java
index 951fb26..82519c5 100644
--- a/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/audiostreams/testshadows/ShadowEntityHeaderController.java
+++ b/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/audiostreams/testshadows/ShadowEntityHeaderController.java
@@ -25,6 +25,7 @@
 
 import org.robolectric.annotation.Implementation;
 import org.robolectric.annotation.Implements;
+import org.robolectric.annotation.Resetter;
 
 @Implements(value = EntityHeaderController.class, callThroughByDefault = false)
 public class ShadowEntityHeaderController {
@@ -34,6 +35,12 @@
         sMockController = mockController;
     }
 
+    /** Reset static fields */
+    @Resetter
+    public static void reset() {
+        sMockController = null;
+    }
+
     /** Returns new instance of {@link EntityHeaderController} */
     @Implementation
     public static EntityHeaderController newInstance(
diff --git a/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/audiostreams/testshadows/ShadowLocalMediaManager.java b/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/audiostreams/testshadows/ShadowLocalMediaManager.java
index 02f12c2..4c679fb 100644
--- a/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/audiostreams/testshadows/ShadowLocalMediaManager.java
+++ b/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/audiostreams/testshadows/ShadowLocalMediaManager.java
@@ -21,6 +21,7 @@
 
 import org.robolectric.annotation.Implementation;
 import org.robolectric.annotation.Implements;
+import org.robolectric.annotation.Resetter;
 
 import java.util.Collections;
 
@@ -34,6 +35,13 @@
         sMockManager = mockLocalMediaManager;
     }
 
+    /** Reset static fields */
+    @Resetter
+    public static void reset() {
+        sMockManager = null;
+        sDeviceCallback = null;
+    }
+
     /** Triggers onDeviceListUpdate of {@link LocalMediaManager.DeviceCallback} */
     public static void onDeviceListUpdate() {
         sDeviceCallback.onDeviceListUpdate(Collections.emptyList());
@@ -45,7 +53,7 @@
         sMockManager.startScan();
     }
 
-    /** Registers {@link  LocalMediaManager.DeviceCallback} */
+    /** Registers {@link LocalMediaManager.DeviceCallback} */
     @Implementation
     public void registerCallback(LocalMediaManager.DeviceCallback deviceCallback) {
         sMockManager.registerCallback(deviceCallback);