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

Commit 1d0b1377 authored by Amy's avatar Amy
Browse files

HdmiCecLocalDeviceTest

Test: atest com.android.server.hdmi
Change-Id: Ic051138202531871b6227d57ef35038d0971e9e5
parent 3281e43a
Loading
Loading
Loading
Loading
+8 −6
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@

package com.android.server.hdmi;

import android.annotation.Nullable;
import android.hardware.hdmi.HdmiDeviceInfo;
import android.hardware.input.InputManager;
import android.os.Handler;
@@ -31,6 +32,7 @@ import com.android.internal.annotations.GuardedBy;
import com.android.internal.util.IndentingPrintWriter;
import com.android.server.hdmi.HdmiAnnotations.ServiceThreadOnly;

import com.android.server.hdmi.HdmiControlService.SendMessageCallback;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
@@ -249,11 +251,11 @@ abstract class HdmiCecLocalDevice {
            case Constants.MESSAGE_SET_MENU_LANGUAGE:
                return handleSetMenuLanguage(message);
            case Constants.MESSAGE_GIVE_PHYSICAL_ADDRESS:
                return handleGivePhysicalAddress();
                return handleGivePhysicalAddress(null);
            case Constants.MESSAGE_GIVE_OSD_NAME:
                return handleGiveOsdName(message);
            case Constants.MESSAGE_GIVE_DEVICE_VENDOR_ID:
                return handleGiveDeviceVendorId();
                return handleGiveDeviceVendorId(null);
            case Constants.MESSAGE_GET_CEC_VERSION:
                return handleGetCecVersion(message);
            case Constants.MESSAGE_REPORT_PHYSICAL_ADDRESS:
@@ -325,23 +327,23 @@ abstract class HdmiCecLocalDevice {
    }

    @ServiceThreadOnly
    protected boolean handleGivePhysicalAddress() {
    protected boolean handleGivePhysicalAddress(@Nullable SendMessageCallback callback) {
        assertRunOnServiceThread();

        int physicalAddress = mService.getPhysicalAddress();
        HdmiCecMessage cecMessage = HdmiCecMessageBuilder.buildReportPhysicalAddressCommand(
                mAddress, physicalAddress, mDeviceType);
        mService.sendCecCommand(cecMessage);
        mService.sendCecCommand(cecMessage, callback);
        return true;
    }

    @ServiceThreadOnly
    protected boolean handleGiveDeviceVendorId() {
    protected boolean handleGiveDeviceVendorId(@Nullable SendMessageCallback callback) {
        assertRunOnServiceThread();
        int vendorId = mService.getVendorId();
        HdmiCecMessage cecMessage = HdmiCecMessageBuilder.buildDeviceVendorIdCommand(
                mAddress, vendorId);
        mService.sendCecCommand(cecMessage);
        mService.sendCecCommand(cecMessage, callback);
        return true;
    }

+1 −1
Original line number Diff line number Diff line
@@ -22,7 +22,7 @@ import android.util.SparseArray;
/**
 * A helper class to validates {@link HdmiCecMessage}.
 */
public final class HdmiCecMessageValidator {
public class HdmiCecMessageValidator {
    private static final String TAG = "HdmiCecMessageValidator";

    static final int OK = 0;
+31 −4
Original line number Diff line number Diff line
@@ -68,6 +68,7 @@ import android.util.Slog;
import android.util.SparseArray;
import android.util.SparseIntArray;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.DumpUtils;
import com.android.internal.util.IndentingPrintWriter;
import com.android.server.SystemService;
@@ -290,6 +291,9 @@ public class HdmiControlService extends SystemService {
    @Nullable
    private PowerManager mPowerManager;

    @Nullable
    private Looper mIoLooper;

    // Last input port before switching to the MHL port. Should switch back to this port
    // when the mobile device sends the request one touch play with off.
    // Gets invalidated if we go to other port/input.
@@ -383,13 +387,18 @@ public class HdmiControlService extends SystemService {

    @Override
    public void onStart() {
        if (mIoLooper == null) {
            mIoThread.start();
            mIoLooper = mIoThread.getLooper();
        }
        mPowerStatus = HdmiControlManager.POWER_STATUS_TRANSIENT_TO_ON;
        mProhibitMode = false;
        mHdmiControlEnabled = readBooleanSetting(Global.HDMI_CONTROL_ENABLED, true);
        mMhlInputChangeEnabled = readBooleanSetting(Global.MHL_INPUT_SWITCHING_ENABLED, true);

        if (mCecController == null) {
            mCecController = HdmiCecController.create(this);
        }
        if (mCecController != null) {
            if (mHdmiControlEnabled) {
                initializeCec(INITIATED_BY_BOOT_UP);
@@ -406,7 +415,9 @@ public class HdmiControlService extends SystemService {
        mMhlDevices = Collections.emptyList();

        initPortInfo();
        if (mMessageValidator == null) {
            mMessageValidator = new HdmiCecMessageValidator(this);
        }
        publishBinderService(Context.HDMI_CONTROL_SERVICE, new BinderService());

        if (mCecController != null) {
@@ -424,6 +435,11 @@ public class HdmiControlService extends SystemService {
        mMhlController.setOption(OPTION_MHL_SERVICE_CONTROL, ENABLED);
    }

    @VisibleForTesting
    void setCecController(HdmiCecController cecController) {
        mCecController = cecController;
    }

    @Override
    public void onBootPhase(int phase) {
        if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY) {
@@ -747,8 +763,19 @@ public class HdmiControlService extends SystemService {
     *
     * <p>Declared as package-private.
     */
    @Nullable
    Looper getIoLooper() {
        return mIoThread.getLooper();
        return mIoLooper;
    }

    @VisibleForTesting
    void setIoLooper(Looper ioLooper) {
        mIoLooper = ioLooper;
    }

    @VisibleForTesting
    void setMessageValidator(HdmiCecMessageValidator messageValidator) {
        mMessageValidator = messageValidator;
    }

    /**
+221 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2018 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.server.hdmi;

import static android.hardware.hdmi.HdmiDeviceInfo.DEVICE_TV;
import static com.android.server.hdmi.Constants.ADDR_BROADCAST;
import static com.android.server.hdmi.Constants.ADDR_TV;
import static com.android.server.hdmi.Constants.ADDR_UNREGISTERED;
import static com.android.server.hdmi.Constants.MESSAGE_DEVICE_VENDOR_ID;
import static com.android.server.hdmi.Constants.MESSAGE_REPORT_PHYSICAL_ADDRESS;
import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertFalse;
import static junit.framework.Assert.assertTrue;

import android.hardware.hdmi.HdmiPortInfo;
import android.os.test.TestLooper;
import android.support.test.filters.SmallTest;
import android.os.MessageQueue;
import com.android.server.hdmi.HdmiCecController.NativeWrapper;
import junit.framework.Assert;
import java.util.Arrays;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;

@SmallTest
@RunWith(JUnit4.class)
/**
 * Tests for {@link HdmiCecLocalDevice} class.
 */
public class HdmiCecLocalDeviceTest {

    private static final class NativeWrapperImpl implements NativeWrapper {

        @Override
        public long nativeInit(HdmiCecController handler, MessageQueue messageQueue) {
            return 1L;
        }

        @Override
        public int nativeSendCecCommand(long controllerPtr, int srcAddress, int dstAddress,
            byte[] body) {
            return SendCecCommandFactory(srcAddress, dstAddress, body);
        }

        @Override
        public int nativeAddLogicalAddress(long controllerPtr, int logicalAddress) {
            return 0;
        }

        @Override
        public void nativeClearLogicalAddress(long controllerPtr) {

        }

        @Override
        public int nativeGetPhysicalAddress(long controllerPtr) {
            return mPhysicalAddr;
        }

        @Override
        public int nativeGetVersion(long controllerPtr) {
            return 0;
        }

        @Override
        public int nativeGetVendorId(long controllerPtr) {
            return 0;
        }

        @Override
        public HdmiPortInfo[] nativeGetPortInfos(long controllerPtr) {
            return new HdmiPortInfo[0];
        }

        @Override
        public void nativeSetOption(long controllerPtr, int flag, boolean enabled) {

        }

        @Override
        public void nativeSetLanguage(long controllerPtr, String language) {

        }

        @Override
        public void nativeEnableAudioReturnChannel(long controllerPtr, int port, boolean flag) {

        }

        @Override
        public boolean nativeIsConnected(long controllerPtr, int port) {
            return false;
        }
    }

    private static int SendCecCommandFactory(int srcAddress, int dstAddress, byte[] body) {
        switch(body[0] & 0xFF) {
            /** {@link Constants#MESSAGE_GIVE_PHYSICAL_ADDRESS} */
            case MESSAGE_REPORT_PHYSICAL_ADDRESS:
            case MESSAGE_DEVICE_VENDOR_ID:
                return srcAddress == mSrcAddr &&
                    dstAddress == mDesAddr &&
                    Arrays.equals(Arrays.copyOfRange(body, 1, body.length), param)? 0 : 1;
            default:
                return 1;
        }
    }

    private class MyHdmiCecLocalDevice extends HdmiCecLocalDevice {


        protected MyHdmiCecLocalDevice(HdmiControlService service, int deviceType) {
            super(service, deviceType);
        }

        @Override
        protected void onAddressAllocated(int logicalAddress, int reason) {

        }

        @Override
        protected int getPreferredAddress() {
            return 0;
        }

        @Override
        protected void setPreferredAddress(int addr) {

        }
    }

    private MyHdmiCecLocalDevice mHdmiLocalDevice;
    private HdmiControlService mHdmiControlService;
    private HdmiCecController mHdmiCecController;
    private TestLooper mTestLooper = new TestLooper();
    private static int mDesAddr = -1;
    private static int mSrcAddr = -1;
    private static int mPhysicalAddr = 2;
    private int callbackResult;
    private HdmiCecMessageValidator mMessageValidator;
    private static byte[] param;

    @Before
    public void SetUp() {
        mHdmiControlService = new HdmiControlService(null);
        mHdmiControlService.setIoLooper(mTestLooper.getLooper());
        mHdmiCecController = HdmiCecController.createWithNativeWrapper(
            mHdmiControlService, new NativeWrapperImpl());
        mHdmiControlService.setCecController(mHdmiCecController);
        mHdmiLocalDevice = new MyHdmiCecLocalDevice(
            mHdmiControlService, DEVICE_TV);
        mMessageValidator = new HdmiCecMessageValidator(mHdmiControlService){
            @Override
            int isValid(HdmiCecMessage message) {
                return HdmiCecMessageValidator.OK;
            }
        };
        mHdmiControlService.setMessageValidator(mMessageValidator);
    }

    @Test
    public void dispatchMessage_desNotValid() {
        HdmiCecMessage msg = new HdmiCecMessage(
            ADDR_TV, ADDR_TV, Constants.MESSAGE_CEC_VERSION, HdmiCecMessage.EMPTY_PARAM);
        boolean handleResult = mHdmiLocalDevice.dispatchMessage(msg);
        assertFalse(handleResult);
    }

    @Test
    public void handleGivePhysicalAddress_success() {
        mSrcAddr = ADDR_UNREGISTERED;
        mDesAddr = ADDR_BROADCAST;
        param = new byte[] {
            (byte) ((mPhysicalAddr >> 8) & 0xFF),
            (byte) (mPhysicalAddr & 0xFF),
            (byte) (DEVICE_TV & 0xFF)
        };
        callbackResult = -1;
        boolean handleResult = mHdmiLocalDevice.handleGivePhysicalAddress(
            (int finalResult) -> callbackResult = finalResult);
        mTestLooper.dispatchAll();
        /**
         * Test if CecMessage is sent successfully
         * SendMessageResult#SUCCESS is defined in HAL as 0
         */
        assertEquals(0, callbackResult);
        assertTrue(handleResult);
    }

    @Test
    public void handleGiveDeviceVendorId_success() {
        mSrcAddr = ADDR_UNREGISTERED;
        mDesAddr = ADDR_BROADCAST;
        /** nativeGetVendorId returns 0 */
        param = new byte[] {
            (byte) ((0 >> 8) & 0xFF),
            (byte) (0 & 0xFF),
            (byte) (0 & 0xFF)
        };
        callbackResult = -1;
        mHdmiLocalDevice.handleGiveDeviceVendorId(
            (int finalResult) -> callbackResult = finalResult);
        mTestLooper.dispatchAll();
        assertEquals(0, callbackResult);
    }
}