Fix failing MediaRouter2ManagerTest

The test failed for several reasons:
 - When other real cast device is present, tests are run before actual
   routes arrive.
 - Screen is not turned on during test.
 - Test lacks MEDIA_CONTENT_CONTROL permission.

This CL fixes the test.

Bug: 186190171
Test: atest com.android.mediaroutertest.MediaRouter2ManagerTest \
        --rerun-until-failure
Change-Id: I6f86ae7cba25871ffb7c8ee96f4c8db6bd86b816
diff --git a/media/java/android/media/MediaRouter2.java b/media/java/android/media/MediaRouter2.java
index 232de0b..fbf7def 100644
--- a/media/java/android/media/MediaRouter2.java
+++ b/media/java/android/media/MediaRouter2.java
@@ -180,7 +180,7 @@
             // SecurityException will be thrown if there's no permission.
             serviceBinder.enforceMediaContentControlPermission();
         } catch (RemoteException e) {
-            Log.e(TAG, "Unable to check MEDIA_CONTENT_CONTROL permission.");
+            e.rethrowFromSystemServer();
         }
 
         PackageManager pm = context.getPackageManager();
diff --git a/media/tests/MediaRouter/Android.bp b/media/tests/MediaRouter/Android.bp
index d41bc02..2da6c98 100644
--- a/media/tests/MediaRouter/Android.bp
+++ b/media/tests/MediaRouter/Android.bp
@@ -18,7 +18,9 @@
     ],
 
     static_libs: [
+        "androidx.test.core",
         "androidx.test.rules",
+        "compatibility-device-util-axt",
         "mockito-target-minus-junit4",
         "testng",
         "truth-prebuilt",
diff --git a/media/tests/MediaRouter/AndroidManifest.xml b/media/tests/MediaRouter/AndroidManifest.xml
index 02688d5..018f148 100644
--- a/media/tests/MediaRouter/AndroidManifest.xml
+++ b/media/tests/MediaRouter/AndroidManifest.xml
@@ -19,6 +19,7 @@
 
     <application android:label="@string/app_name">
         <uses-library android:name="android.test.runner" />
+        <activity android:name="com.android.mediaroutertest.MediaRouter2ManagerTestActivity" />
         <service android:name=".StubMediaRoute2ProviderService"
                  android:exported="true">
             <intent-filter>
diff --git a/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouter2ManagerTest.java b/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouter2ManagerTest.java
index eaa4f03..3a34e75 100644
--- a/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouter2ManagerTest.java
+++ b/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouter2ManagerTest.java
@@ -16,7 +16,6 @@
 
 package com.android.mediaroutertest;
 
-import static android.media.MediaRoute2Info.FEATURE_LIVE_AUDIO;
 import static android.media.MediaRoute2Info.FEATURE_REMOTE_PLAYBACK;
 import static android.media.MediaRoute2Info.PLAYBACK_VOLUME_FIXED;
 import static android.media.MediaRoute2Info.PLAYBACK_VOLUME_VARIABLE;
@@ -61,6 +60,8 @@
 import androidx.test.filters.SmallTest;
 import androidx.test.runner.AndroidJUnit4;
 
+import com.android.compatibility.common.util.PollingCheck;
+
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
@@ -94,6 +95,7 @@
     private MediaRouter2 mRouter2;
     private Executor mExecutor;
     private String mPackageName;
+    private StubMediaRoute2ProviderService mService;
 
     private final List<MediaRouter2Manager.Callback> mManagerCallbacks = new ArrayList<>();
     private final List<RouteCallback> mRouteCallbacks = new ArrayList<>();
@@ -105,7 +107,6 @@
     static {
         FEATURES_ALL.add(FEATURE_SAMPLE);
         FEATURES_ALL.add(FEATURE_SPECIAL);
-        FEATURES_ALL.add(FEATURE_LIVE_AUDIO);
 
         FEATURES_SPECIAL.add(FEATURE_SPECIAL);
     }
@@ -115,26 +116,53 @@
         mContext = InstrumentationRegistry.getTargetContext();
         mUiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
         mUiAutomation.adoptShellPermissionIdentity(Manifest.permission.MEDIA_CONTENT_CONTROL);
+        MediaRouter2ManagerTestActivity.startActivity(mContext);
+
         mManager = MediaRouter2Manager.getInstance(mContext);
+        mManager.startScan();
         mRouter2 = MediaRouter2.getInstance(mContext);
+
         // If we need to support thread pool executors, change this to thread pool executor.
         mExecutor = Executors.newSingleThreadExecutor();
         mPackageName = mContext.getPackageName();
+
+        // In order to make the system bind to the test service,
+        // set a non-empty discovery preference while app is in foreground.
+        List<String> features = new ArrayList<>();
+        features.add("A test feature");
+        RouteDiscoveryPreference preference =
+                new RouteDiscoveryPreference.Builder(features, false).build();
+        mRouter2.registerRouteCallback(mExecutor, new RouteCallback() {}, preference);
+
+        new PollingCheck(TIMEOUT_MS) {
+            @Override
+            protected boolean check() {
+                StubMediaRoute2ProviderService service =
+                        StubMediaRoute2ProviderService.getInstance();
+                if (service != null) {
+                    mService = service;
+                    return true;
+                }
+                return false;
+            }
+        }.run();
     }
 
     @After
     public void tearDown() {
+        mManager.stopScan();
+
         // order matters (callbacks should be cleared at the last)
         releaseAllSessions();
         // unregister callbacks
         clearCallbacks();
 
-        StubMediaRoute2ProviderService instance = StubMediaRoute2ProviderService.getInstance();
-        if (instance != null) {
-            instance.setProxy(null);
-            instance.setSpy(null);
+        if (mService != null) {
+            mService.setProxy(null);
+            mService.setSpy(null);
         }
 
+        MediaRouter2ManagerTestActivity.finishActivity();
         mUiAutomation.dropShellPermissionIdentity();
     }
 
@@ -179,13 +207,10 @@
         MediaRoute2Info routeToRemove = routes.get(ROUTE_ID2);
         assertNotNull(routeToRemove);
 
-        StubMediaRoute2ProviderService sInstance =
-                StubMediaRoute2ProviderService.getInstance();
-        assertNotNull(sInstance);
-        sInstance.removeRoute(ROUTE_ID2);
+        mService.removeRoute(ROUTE_ID2);
         assertTrue(removedLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
 
-        sInstance.addRoute(routeToRemove);
+        mService.addRoute(routeToRemove);
         assertTrue(addedLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
     }
 
@@ -218,10 +243,7 @@
         MediaRoute2Info routeToRemove = routes.get(ROUTE_ID2);
         assertNotNull(routeToRemove);
 
-        StubMediaRoute2ProviderService sInstance =
-                StubMediaRoute2ProviderService.getInstance();
-        assertNotNull(sInstance);
-        sInstance.removeRoute(ROUTE_ID2);
+        mService.removeRoute(ROUTE_ID2);
 
         // Wait until the route is removed.
         assertTrue(removedLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
@@ -230,7 +252,7 @@
         assertNull(newRoutes.get(ROUTE_ID2));
 
         // Revert the removal.
-        sInstance.addRoute(routeToRemove);
+        mService.addRoute(routeToRemove);
         assertTrue(addedLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
         mRouter2.unregisterRouteCallback(routeCallback);
     }
@@ -445,9 +467,7 @@
         CountDownLatch serviceOnReleaseSessionLatch = new CountDownLatch(1);
         List<RoutingSessionInfo> sessions = new ArrayList<>();
 
-        StubMediaRoute2ProviderService instance = StubMediaRoute2ProviderService.getInstance();
-        assertNotNull(instance);
-        instance.setSpy(new StubMediaRoute2ProviderService.Spy() {
+        mService.setSpy(new StubMediaRoute2ProviderService.Spy() {
             @Override
             public void onReleaseSession(long requestId, String sessionId) {
                 serviceOnReleaseSessionLatch.countDown();
@@ -652,12 +672,9 @@
         Map<String, MediaRoute2Info> routes = waitAndGetRoutesWithManager(FEATURES_ALL);
         MediaRoute2Info volRoute = routes.get(ROUTE_ID_VARIABLE_VOLUME);
 
-        StubMediaRoute2ProviderService instance = StubMediaRoute2ProviderService.getInstance();
-        assertNotNull(instance);
-
         final List<Long> requestIds = new ArrayList<>();
         final CountDownLatch onSetRouteVolumeLatch = new CountDownLatch(1);
-        instance.setProxy(new StubMediaRoute2ProviderService.Proxy() {
+        mService.setProxy(new StubMediaRoute2ProviderService.Proxy() {
             @Override
             public void onSetRouteVolume(String routeId, int volume, long requestId) {
                 requestIds.add(requestId);
@@ -687,16 +704,16 @@
         });
 
         final long invalidRequestId = REQUEST_ID_NONE;
-        instance.notifyRequestFailed(invalidRequestId, failureReason);
+        mService.notifyRequestFailed(invalidRequestId, failureReason);
         assertFalse(onRequestFailedLatch.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS));
 
         final long validRequestId = requestIds.get(0);
-        instance.notifyRequestFailed(validRequestId, failureReason);
+        mService.notifyRequestFailed(validRequestId, failureReason);
         assertTrue(onRequestFailedLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
 
         // Test calling notifyRequestFailed() multiple times with the same valid requestId.
         // onRequestFailed() shouldn't be called since the requestId has been already handled.
-        instance.notifyRequestFailed(validRequestId, failureReason);
+        mService.notifyRequestFailed(validRequestId, failureReason);
         assertFalse(onRequestFailedSecondCallLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
     }
 
@@ -813,7 +830,8 @@
             @Override
             public void onRoutesAdded(List<MediaRoute2Info> routes) {
                 for (MediaRoute2Info route : routes) {
-                    if (!route.isSystemRoute()) {
+                    if (!route.isSystemRoute()
+                            && hasMatchingFeature(route.getFeatures(), routeFeatures)) {
                         addedLatch.countDown();
                         break;
                     }
@@ -834,10 +852,10 @@
         mRouter2.registerRouteCallback(mExecutor, routeCallback,
                 new RouteDiscoveryPreference.Builder(routeFeatures, true).build());
         try {
-            if (mManager.getAllRoutes().isEmpty()) {
+            featuresLatch.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS);
+            if (mManager.getAvailableRoutes(mPackageName).isEmpty()) {
                 addedLatch.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS);
             }
-            featuresLatch.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS);
             return createRouteMap(mManager.getAvailableRoutes(mPackageName));
         } finally {
             mRouter2.unregisterRouteCallback(routeCallback);
@@ -845,6 +863,15 @@
         }
     }
 
+    boolean hasMatchingFeature(List<String> features1, List<String> features2) {
+        for (String feature : features1) {
+            if (features2.contains(feature)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
     void awaitOnRouteChangedManager(Runnable task, String routeId,
             Predicate<MediaRoute2Info> predicate) throws Exception {
         CountDownLatch latch = new CountDownLatch(1);
diff --git a/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouter2ManagerTestActivity.java b/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouter2ManagerTestActivity.java
new file mode 100644
index 0000000..ac2a8bb
--- /dev/null
+++ b/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouter2ManagerTestActivity.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2021 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.mediaroutertest;
+
+import android.app.Activity;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Bundle;
+import android.view.WindowManager;
+
+import androidx.test.core.app.ActivityScenario;
+
+public class MediaRouter2ManagerTestActivity extends Activity {
+
+    private static ActivityScenario<MediaRouter2ManagerTestActivity> sActivityScenario;
+
+    public static ActivityScenario<MediaRouter2ManagerTestActivity> startActivity(Context context) {
+        Intent intent = new Intent(Intent.ACTION_MAIN);
+        intent.setClass(context, MediaRouter2ManagerTestActivity.class);
+        sActivityScenario = ActivityScenario.launch(intent);
+        return sActivityScenario;
+    }
+
+    public static void finishActivity() {
+        if (sActivityScenario != null) {
+            // TODO: Sometimes calling this takes about 5 seconds. Need to figure out why.
+            sActivityScenario.close();
+            sActivityScenario = null;
+        }
+    }
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setTurnScreenOn(true);
+        setShowWhenLocked(true);
+        getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
+    }
+}