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

Commit fa0c303d authored by Amy Zhang's avatar Amy Zhang Committed by Android (Google) Code Review
Browse files

Merge "HdmiCecLocalDeviceTest"

parents bf58e764 1d0b1377
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);
    }
}