Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 9ba52e22 authored by Charles Chen's avatar Charles Chen
Browse files

Add foldable support for RouteInfo#getPresentationDisplay

In this CL, RouteInfo#getPresentationDisplay by following order:
1. Connected Wifi displays (Ex: chromecast)
2. Attached external displays (Ex: an external display plugged by HDMI)
3. Non-default built-in displays

Test: MediaRouteInfoTest
Bug: 130035480
Change-Id: Ib2dd63217ebe415c2bda57f60e42713ca325f56e
parent bc888638
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
@@ -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
+72 −25
Original line number Diff line number Diff line
@@ -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,8 +2095,13 @@ public class MediaRouter {
        }

        private Display choosePresentationDisplay() {
            if ((mSupportedTypes & ROUTE_TYPE_LIVE_VIDEO) != 0) {
                Display[] displays = sStatic.getAllPresentationDisplays();
            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
@@ -2104,24 +2116,59 @@ public class MediaRouter {
            }

            // Find the indicated Wifi display by its address.
                if (mDeviceAddress != null) {
            if (getDeviceAddress() != null) {
                for (Display display : displays) {
                    if (display.getType() == Display.TYPE_WIFI
                                && mDeviceAddress.equals(display.getAddress())) {
                            && displayAddressEquals(display)) {
                        return display;
                    }
                }
                    return null;
            }

            // Returns the first hard-wired display.
            for (Display display : displays) {
                if (display.getType() == Display.TYPE_EXTERNAL) {
                    return display;
                }
            }

            // 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 == sStatic.mDefaultAudioVideo && displays.length > 0) {
            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() {
+2 −1
Original line number Diff line number Diff line
@@ -11,7 +11,8 @@ android_test {
    static_libs: [
        "android-support-test",
        "mockito-target-minus-junit4",
        "testng"
        "testng",
        "truth-prebuilt",
    ],

    platform_apis: true,
+195 −0
Original line number Diff line number Diff line
/*
 * 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;
        }
    }
}