media2-session: Fix flaky MediaSession_KeyEventTest

Test had been randomly failed because setUp() fails to start playback
and being notified via OnCompletionListener. It was because MediaPlayer
object was GCed while playback is running, so the listener wasn't
called as expected.

This CL keeps the MediaPlayer instance as a member variable so it
wouldn't be unexpectedly GCed.

Bug: 139173649
Test: Run following tests 10 times on API 25 and 29
      $ media2/session/version-compat-tests/runtest.sh 4
Change-Id: Ie18bc0c3704ed962f959e925c1aeb72292a1dc08
diff --git a/media2/session/version-compat-tests/current/service/src/androidTest/java/androidx/media2/test/service/tests/MediaSession_KeyEventTest.java b/media2/session/version-compat-tests/current/service/src/androidTest/java/androidx/media2/test/service/tests/MediaSession_KeyEventTest.java
index 9976d50..8228a4a 100644
--- a/media2/session/version-compat-tests/current/service/src/androidTest/java/androidx/media2/test/service/tests/MediaSession_KeyEventTest.java
+++ b/media2/session/version-compat-tests/current/service/src/androidTest/java/androidx/media2/test/service/tests/MediaSession_KeyEventTest.java
@@ -60,6 +60,10 @@
 public class MediaSession_KeyEventTest extends MediaSessionTestBase {
     private static String sExpectedControllerPackageName;
 
+    // Intentionally member variable to prevent GC while playback is running.
+    // Should be only used on the sHandler.
+    private MediaPlayer mMediaPlayer;
+
     private AudioManager mAudioManager;
     private MediaSession mSession;
     private MockPlayer mPlayer;
@@ -90,35 +94,50 @@
                 .setSessionCallback(sHandlerExecutor, mSessionCallback)
                 .build();
 
-        // Make this test to get priority for handling media key event
-        // SDK < 26: Playback state should become *playing*
-        mPlayer.notifyPlayerStateChanged(SessionPlayer.PLAYER_STATE_PLAYING);
-
-        // SDK >= 26: Play a media item in the same process of the session.
-        // Target raw resource should be short enough to finish within the time limit of @SmallTest.
-        final CountDownLatch latch = new CountDownLatch(1);
-        sHandler.postAndSync(new Runnable() {
-            @Override
-            public void run() {
-                // Pick the shortest media.
-                final MediaPlayer player = MediaPlayer.create(mContext, R.raw.camera_click);
-                player.setOnCompletionListener(new OnCompletionListener() {
-                    @Override
-                    public void onCompletion(MediaPlayer mp) {
-                        latch.countDown();
-                        player.release();
-                    }
-                });
-                player.start();
-            }
-        });
-        assertTrue(latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
+        // Make this test to get priority for handling media key event.
+        // Here's the requirement for an app to receive media key events via MediaSession.
+        // SDK < 26: Playback state should become *playing* for receiving key events.
+        // SDK >= 26: Play a media item in the same process of the session for receiving key
+        //            events.
+        if (Build.VERSION.SDK_INT < 26) {
+            mPlayer.notifyPlayerStateChanged(SessionPlayer.PLAYER_STATE_PLAYING);
+        } else {
+            final CountDownLatch latch = new CountDownLatch(1);
+            sHandler.postAndSync(new Runnable() {
+                @Override
+                public void run() {
+                    // Pick the shortest media to finish within the TIMEOUT_MS.
+                    mMediaPlayer = MediaPlayer.create(mContext, R.raw.camera_click);
+                    mMediaPlayer.setOnCompletionListener(new OnCompletionListener() {
+                        @Override
+                        public void onCompletion(MediaPlayer mp) {
+                            if (mMediaPlayer != null) {
+                                mMediaPlayer.release();
+                                mMediaPlayer = null;
+                                latch.countDown();
+                            }
+                        }
+                    });
+                    mMediaPlayer.start();
+                }
+            });
+            assertTrue(latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
+        }
     }
 
     @After
     @Override
     public void cleanUp() throws Exception {
         super.cleanUp();
+        sHandler.postAndSync(new Runnable() {
+            @Override
+            public void run() {
+                if (mMediaPlayer != null) {
+                    mMediaPlayer.release();
+                    mMediaPlayer = null;
+                }
+            }
+        });
         mSession.close();
     }
 
diff --git a/media2/session/version-compat-tests/previous/service/src/androidTest/java/androidx/media2/test/service/tests/MediaSession_KeyEventTest.java b/media2/session/version-compat-tests/previous/service/src/androidTest/java/androidx/media2/test/service/tests/MediaSession_KeyEventTest.java
index b605f9b..bef96da 100644
--- a/media2/session/version-compat-tests/previous/service/src/androidTest/java/androidx/media2/test/service/tests/MediaSession_KeyEventTest.java
+++ b/media2/session/version-compat-tests/previous/service/src/androidTest/java/androidx/media2/test/service/tests/MediaSession_KeyEventTest.java
@@ -59,6 +59,10 @@
 public class MediaSession_KeyEventTest extends MediaSessionTestBase {
     private static String sExpectedControllerPackageName;
 
+    // Intentionally member variable to prevent GC while playback is running.
+    // Should be only used on the sHandler.
+    private MediaPlayer mMediaPlayer;
+
     private AudioManager mAudioManager;
     private MediaSession mSession;
     private MockPlayer mPlayer;
@@ -93,31 +97,50 @@
         // SDK < 26: Playback state should become *playing*
         mPlayer.notifyPlayerStateChanged(SessionPlayer.PLAYER_STATE_PLAYING);
 
-        // SDK >= 26: Play a media item in the same process of the session.
-        // Target raw resource should be short enough to finish within the time limit of @SmallTest.
-        final CountDownLatch latch = new CountDownLatch(1);
-        sHandler.postAndSync(new Runnable() {
-            @Override
-            public void run() {
-                // Pick the shortest media.
-                final MediaPlayer player = MediaPlayer.create(mContext, R.raw.camera_click);
-                player.setOnCompletionListener(new OnCompletionListener() {
-                    @Override
-                    public void onCompletion(MediaPlayer mp) {
-                        latch.countDown();
-                        player.release();
-                    }
-                });
-                player.start();
-            }
-        });
-        assertTrue(latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
+        // Make this test to get priority for handling media key event.
+        // Here's the requirement for an app to receive media key events via MediaSession.
+        // SDK < 26: Playback state should become *playing* for receiving key events.
+        // SDK >= 26: Play a media item in the same process of the session for receiving key
+        //            events.
+        if (Build.VERSION.SDK_INT < 26) {
+            mPlayer.notifyPlayerStateChanged(SessionPlayer.PLAYER_STATE_PLAYING);
+        } else {
+            final CountDownLatch latch = new CountDownLatch(1);
+            sHandler.postAndSync(new Runnable() {
+                @Override
+                public void run() {
+                    // Pick the shortest media to finish within the TIMEOUT_MS.
+                    mMediaPlayer = MediaPlayer.create(mContext, R.raw.camera_click);
+                    mMediaPlayer.setOnCompletionListener(new OnCompletionListener() {
+                        @Override
+                        public void onCompletion(MediaPlayer mp) {
+                            if (mMediaPlayer != null) {
+                                mMediaPlayer.release();
+                                mMediaPlayer = null;
+                                latch.countDown();
+                            }
+                        }
+                    });
+                    mMediaPlayer.start();
+                }
+            });
+            assertTrue(latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
+        }
     }
 
     @After
     @Override
     public void cleanUp() throws Exception {
         super.cleanUp();
+        sHandler.postAndSync(new Runnable() {
+            @Override
+            public void run() {
+                if (mMediaPlayer != null) {
+                    mMediaPlayer.release();
+                    mMediaPlayer = null;
+                }
+            }
+        });
         mSession.close();
     }