diff options
4 files changed, 275 insertions, 26 deletions
diff --git a/core/java/android/hardware/display/DisplayManager.java b/core/java/android/hardware/display/DisplayManager.java index dda1890b0757..fc14b89d83f7 100644 --- a/core/java/android/hardware/display/DisplayManager.java +++ b/core/java/android/hardware/display/DisplayManager.java @@ -16,6 +16,8 @@ package android.hardware.display; +import static android.view.Display.DEFAULT_DISPLAY; + import android.Manifest; import android.annotation.NonNull; import android.annotation.Nullable; @@ -381,6 +383,7 @@ public final class DisplayManager { addPresentationDisplaysLocked(mTempDisplays, displayIds, Display.TYPE_EXTERNAL); addPresentationDisplaysLocked(mTempDisplays, displayIds, Display.TYPE_OVERLAY); addPresentationDisplaysLocked(mTempDisplays, displayIds, Display.TYPE_VIRTUAL); + addPresentationDisplaysLocked(mTempDisplays, displayIds, Display.TYPE_INTERNAL); } return mTempDisplays.toArray(new Display[mTempDisplays.size()]); } finally { @@ -401,6 +404,9 @@ public final class DisplayManager { private void addPresentationDisplaysLocked( ArrayList<Display> displays, int[] displayIds, int matchType) { for (int i = 0; i < displayIds.length; i++) { + if (displayIds[i] == DEFAULT_DISPLAY) { + continue; + } Display display = getOrCreateDisplayLocked(displayIds[i], true /*assumeValid*/); if (display != null && (display.getFlags() & Display.FLAG_PRESENTATION) != 0 diff --git a/media/java/android/media/MediaRouter.java b/media/java/android/media/MediaRouter.java index 2b3f420cd834..4d87fb3fa81f 100644 --- a/media/java/android/media/MediaRouter.java +++ b/media/java/android/media/MediaRouter.java @@ -45,6 +45,9 @@ import android.os.UserHandle; import android.text.TextUtils; import android.util.Log; import android.view.Display; +import android.view.DisplayAddress; + +import com.android.internal.annotations.VisibleForTesting; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -1737,7 +1740,9 @@ public class MediaRouter { */ private static final int DEFAULT_PLAYBACK_VOLUME = DEFAULT_PLAYBACK_MAX_VOLUME; - RouteInfo(RouteCategory category) { + /** @hide */ + @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) + public RouteInfo(RouteCategory category) { mCategory = category; mDeviceType = DEVICE_TYPE_UNKNOWN; } @@ -2078,7 +2083,9 @@ public class MediaRouter { return mPresentationDisplay; } - boolean updatePresentationDisplay() { + /** @hide */ + @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) + public boolean updatePresentationDisplay() { Display display = choosePresentationDisplay(); if (mPresentationDisplay != display) { mPresentationDisplay = display; @@ -2088,41 +2095,81 @@ public class MediaRouter { } private Display choosePresentationDisplay() { - if ((mSupportedTypes & ROUTE_TYPE_LIVE_VIDEO) != 0) { - Display[] displays = sStatic.getAllPresentationDisplays(); - - // Ensure that the specified display is valid for presentations. - // This check will normally disallow the default display unless it was - // configured as a presentation display for some reason. - if (mPresentationDisplayId >= 0) { - for (Display display : displays) { - if (display.getDisplayId() == mPresentationDisplayId) { - return display; - } + if ((getSupportedTypes() & ROUTE_TYPE_LIVE_VIDEO) == 0) { + return null; + } + final Display[] displays = getAllPresentationDisplays(); + if (displays == null || displays.length == 0) { + return null; + } + + // Ensure that the specified display is valid for presentations. + // This check will normally disallow the default display unless it was + // configured as a presentation display for some reason. + if (mPresentationDisplayId >= 0) { + for (Display display : displays) { + if (display.getDisplayId() == mPresentationDisplayId) { + return display; } - return null; } + return null; + } - // Find the indicated Wifi display by its address. - if (mDeviceAddress != null) { - for (Display display : displays) { - if (display.getType() == Display.TYPE_WIFI - && mDeviceAddress.equals(display.getAddress())) { - return display; - } + // Find the indicated Wifi display by its address. + if (getDeviceAddress() != null) { + for (Display display : displays) { + if (display.getType() == Display.TYPE_WIFI + && displayAddressEquals(display)) { + return display; } - return null; } + } + + // Returns the first hard-wired display. + for (Display display : displays) { + if (display.getType() == Display.TYPE_EXTERNAL) { + return display; + } + } - // For the default route, choose the first presentation display from the list. - if (this == sStatic.mDefaultAudioVideo && displays.length > 0) { - return displays[0]; + // Returns the first non-default built-in display. + for (Display display : displays) { + if (display.getType() == Display.TYPE_INTERNAL) { + return display; } } + + // For the default route, choose the first presentation display from the list. + if (this == getDefaultAudioVideo()) { + return displays[0]; + } return null; } /** @hide */ + @VisibleForTesting + public Display[] getAllPresentationDisplays() { + return sStatic.getAllPresentationDisplays(); + } + + /** @hide */ + @VisibleForTesting + public RouteInfo getDefaultAudioVideo() { + return sStatic.mDefaultAudioVideo; + } + + private boolean displayAddressEquals(Display display) { + final DisplayAddress displayAddress = display.getAddress(); + // mDeviceAddress recorded mac address. If displayAddress is not a kind of Network, + // return false early. + if (!(displayAddress instanceof DisplayAddress.Network)) { + return false; + } + final DisplayAddress.Network networkAddress = (DisplayAddress.Network) displayAddress; + return getDeviceAddress().equals(networkAddress.toString()); + } + + /** @hide */ @UnsupportedAppUsage public String getDeviceAddress() { return mDeviceAddress; diff --git a/media/tests/MediaRouter/Android.bp b/media/tests/MediaRouter/Android.bp index 5a0a50c2ae38..4d0c258843f9 100644 --- a/media/tests/MediaRouter/Android.bp +++ b/media/tests/MediaRouter/Android.bp @@ -11,7 +11,8 @@ android_test { static_libs: [ "android-support-test", "mockito-target-minus-junit4", - "testng" + "testng", + "truth-prebuilt", ], platform_apis: true, diff --git a/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouteInfoTest.java b/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouteInfoTest.java new file mode 100644 index 000000000000..92e4c9554cb4 --- /dev/null +++ b/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouteInfoTest.java @@ -0,0 +1,195 @@ +/* + * Copyright (C) 2020 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 static com.google.common.truth.Truth.assertThat; + +import android.hardware.display.DisplayManagerGlobal; +import android.media.MediaRouter; +import android.support.test.filters.SmallTest; +import android.support.test.runner.AndroidJUnit4; +import android.view.Display; +import android.view.DisplayAddress; +import android.view.DisplayAdjustments; +import android.view.DisplayInfo; + +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; + +@RunWith(AndroidJUnit4.class) +@SmallTest +public class MediaRouteInfoTest { + private TestableRouteInfo mRouteInfo; + private static Display sWifiDisplay; + private static Display sExternalDisplay; + private static Display sInternalDisplay; + private static final String FAKE_MAC_ADDRESS = "fake MAC address"; + + @BeforeClass + public static void setUpOnce() { + final DisplayManagerGlobal global = DisplayManagerGlobal.getInstance(); + final DisplayInfo wifiInfo = new DisplayInfo(); + wifiInfo.flags = Display.FLAG_PRESENTATION; + wifiInfo.type = Display.TYPE_WIFI; + wifiInfo.address = DisplayAddress.fromMacAddress(FAKE_MAC_ADDRESS); + sWifiDisplay = new Display(global, 2, wifiInfo, new DisplayAdjustments()); + + final DisplayInfo externalInfo = new DisplayInfo(); + externalInfo.flags = Display.FLAG_PRESENTATION; + externalInfo.type = Display.TYPE_EXTERNAL; + sExternalDisplay = new Display(global, 3, externalInfo, new DisplayAdjustments()); + + final DisplayInfo internalInfo = new DisplayInfo(); + internalInfo.flags = Display.FLAG_PRESENTATION; + internalInfo.type = Display.TYPE_INTERNAL; + sInternalDisplay = new Display(global, 4, internalInfo, new DisplayAdjustments()); + } + + @Before + public void setUp() { + mRouteInfo = new TestableRouteInfo(); + } + + @Test + public void testGetPresentationDisplay_notLiveVideo() { + mRouteInfo.setPresentationDisplays(sWifiDisplay); + mRouteInfo.mSupportedType = MediaRouter.ROUTE_TYPE_REMOTE_DISPLAY; + + mRouteInfo.updatePresentationDisplay(); + + assertThat(mRouteInfo.getPresentationDisplay()).isNull(); + } + + @Test + public void testGetPresentationDisplay_includesLiveVideo() { + mRouteInfo.setPresentationDisplays(sWifiDisplay); + mRouteInfo.mSupportedType |= MediaRouter.ROUTE_TYPE_LIVE_AUDIO; + + mRouteInfo.updatePresentationDisplay(); + + assertThat(mRouteInfo.getPresentationDisplay()).isEqualTo(sWifiDisplay); + } + + @Test + public void testGetPresentationDisplay_noPresentationDisplay() { + mRouteInfo.updatePresentationDisplay(); + + assertThat(mRouteInfo.getPresentationDisplay()).isNull(); + } + + @Test + public void testGetPresentationDisplay_wifiDisplayOnly() { + mRouteInfo.setPresentationDisplays(sWifiDisplay); + + mRouteInfo.updatePresentationDisplay(); + + assertThat(mRouteInfo.getPresentationDisplay()).isEqualTo(sWifiDisplay); + } + + @Test + public void testGetPresentationDisplay_externalDisplayOnly() { + mRouteInfo.setPresentationDisplays(sExternalDisplay); + + mRouteInfo.updatePresentationDisplay(); + + assertThat(mRouteInfo.getPresentationDisplay()).isEqualTo(sExternalDisplay); + } + + @Test + public void testGetPresentationDisplay_internalDisplayOnly() { + mRouteInfo.setPresentationDisplays(sInternalDisplay); + + mRouteInfo.updatePresentationDisplay(); + + assertThat(mRouteInfo.getPresentationDisplay()).isEqualTo(sInternalDisplay); + } + + @Test + public void testGetPresentationDisplay_addressNotMatch() { + mRouteInfo.setPresentationDisplays(sWifiDisplay); + mRouteInfo.mDeviceAddress = "Not match"; + + mRouteInfo.updatePresentationDisplay(); + + assertThat(mRouteInfo.getPresentationDisplay()).isNull(); + } + + @Test + public void testGetPresentationDisplay_containsWifiAndExternalDisplays_returnWifiDisplay() { + mRouteInfo.setPresentationDisplays(sExternalDisplay, sWifiDisplay); + + mRouteInfo.updatePresentationDisplay(); + + assertThat(mRouteInfo.getPresentationDisplay()).isEqualTo(sWifiDisplay); + } + + @Test + public void testGetPresentationDisplay_containsExternalAndInternalDisplays_returnExternal() { + mRouteInfo.setPresentationDisplays(sExternalDisplay, sInternalDisplay); + + mRouteInfo.updatePresentationDisplay(); + + assertThat(mRouteInfo.getPresentationDisplay()).isEqualTo(sExternalDisplay); + } + + @Test + public void testGetPresentationDisplay_containsAllDisplays_returnWifiDisplay() { + mRouteInfo.setPresentationDisplays(sExternalDisplay, sInternalDisplay, sWifiDisplay); + + mRouteInfo.updatePresentationDisplay(); + + assertThat(mRouteInfo.getPresentationDisplay()).isEqualTo(sWifiDisplay); + } + + private static class TestableRouteInfo extends MediaRouter.RouteInfo { + private Display[] mDisplays = new Display[0]; + private int mSupportedType = MediaRouter.ROUTE_TYPE_LIVE_VIDEO; + private String mDeviceAddress = FAKE_MAC_ADDRESS; + private MediaRouter.RouteInfo mDefaultRouteInfo = null; + + private TestableRouteInfo() { + super(null); + } + + private void setPresentationDisplays(Display ...displays) { + mDisplays = new Display[displays.length]; + System.arraycopy(displays, 0, mDisplays, 0, displays.length); + } + + @Override + public Display[] getAllPresentationDisplays() { + return mDisplays; + } + + @Override + public int getSupportedTypes() { + return mSupportedType; + } + + @Override + public String getDeviceAddress() { + return mDeviceAddress; + } + + @Override + public MediaRouter.RouteInfo getDefaultAudioVideo() { + return mDefaultRouteInfo; + } + } +} |