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

Commit b79ddaf1 authored by Jungshik Jang's avatar Jungshik Jang Committed by Android (Google) Code Review
Browse files

Merge "DO NOT MERGE: Add SendMessageCallback to Hdmi control service." into lmp-preview-dev

parents 07cd153e 404d7041
Loading
Loading
Loading
Loading
+7 −2
Original line number Diff line number Diff line
@@ -164,8 +164,13 @@ abstract class FeatureAction {
        mActionTimer.sendTimerMessage(state, delayMillis);
    }

    protected final boolean sendCommand(HdmiCecMessage cmd) {
        return mService.sendCecCommand(cmd);
    protected final void sendCommand(HdmiCecMessage cmd) {
        mService.sendCecCommand(cmd);
    }

    protected final void sendCommand(HdmiCecMessage cmd,
            HdmiControlService.SendMessageCallback callback) {
        mService.sendCecCommand(cmd, callback);
    }

    /**
+83 −110
Original line number Diff line number Diff line
@@ -20,9 +20,6 @@ import android.hardware.hdmi.HdmiCec;
import android.hardware.hdmi.HdmiCecDeviceInfo;
import android.hardware.hdmi.HdmiCecMessage;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.util.Slog;
import android.util.SparseArray;
import android.util.SparseIntArray;

@@ -176,53 +173,20 @@ final class HdmiCecController {
     *                         Otherwise, scan address will start from {@code preferredAddress}
     * @param callback callback interface to report allocated logical address to caller
     */
    void allocateLogicalAddress(int deviceType, int preferredAddress,
            AllocateLogicalAddressCallback callback) {
        Message msg = mIoHandler.obtainMessage(MSG_ALLOCATE_LOGICAL_ADDRESS);
        msg.arg1 = deviceType;
        msg.arg2 = preferredAddress;
        msg.obj = callback;
        mIoHandler.sendMessage(msg);
    }

    private static byte[] buildBody(int opcode, byte[] params) {
        byte[] body = new byte[params.length + 1];
        body[0] = (byte) opcode;
        System.arraycopy(params, 0, body, 1, params.length);
        return body;
    }

    private final class IoHandler extends Handler {
        private IoHandler(Looper looper) {
            super(looper);
        }

    void allocateLogicalAddress(final int deviceType, final int preferredAddress,
            final AllocateLogicalAddressCallback callback) {
        runOnIoThread(new Runnable() {
            @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case MSG_SEND_CEC_COMMAND:
                    HdmiCecMessage cecMessage = (HdmiCecMessage) msg.obj;
                    byte[] body = buildBody(cecMessage.getOpcode(), cecMessage.getParams());
                    nativeSendCecCommand(mNativePtr, cecMessage.getSource(),
                            cecMessage.getDestination(), body);
                    break;
                case MSG_ALLOCATE_LOGICAL_ADDRESS:
                    int deviceType = msg.arg1;
                    int preferredAddress = msg.arg2;
                    AllocateLogicalAddressCallback callback =
                            (AllocateLogicalAddressCallback) msg.obj;
            public void run() {
                handleAllocateLogicalAddress(deviceType, preferredAddress, callback);
                    break;
                default:
                    Slog.w(TAG, "Unsupported CEC Io request:" + msg.what);
                    break;
            }
        });
    }

        private void handleAllocateLogicalAddress(int deviceType, int preferredAddress,
                AllocateLogicalAddressCallback callback) {
    private void handleAllocateLogicalAddress(final int deviceType, int preferredAddress,
            final AllocateLogicalAddressCallback callback) {
        int startAddress = preferredAddress;
            // If preferred address is "unregistered", start_index will be the smallest
        // If preferred address is "unregistered", start address will be the smallest
        // address matched with the given device type.
        if (preferredAddress == HdmiCec.ADDR_UNREGISTERED) {
            for (int i = 0; i < NUM_LOGICAL_ADDRESS; ++i) {
@@ -233,7 +197,7 @@ final class HdmiCecController {
            }
        }

            int logcialAddress = HdmiCec.ADDR_UNREGISTERED;
        int logicalAddress = HdmiCec.ADDR_UNREGISTERED;
        // Iterates all possible addresses which has the same device type.
        for (int i = 0; i < NUM_LOGICAL_ADDRESS; ++i) {
            int curAddress = (startAddress + i) % NUM_LOGICAL_ADDRESS;
@@ -247,44 +211,28 @@ final class HdmiCecController {
                int error = nativeSendCecCommand(mNativePtr, curAddress, curAddress,
                        EMPTY_BODY);
                if (error != ERROR_SUCCESS) {
                        logcialAddress = curAddress;
                    logicalAddress = curAddress;
                    break;
                }
            }
        }

            Message msg = mControlHandler.obtainMessage(MSG_REPORT_LOGICAL_ADDRESS);
            msg.arg1 = deviceType;
            msg.arg2 = logcialAddress;
            msg.obj = callback;
            mControlHandler.sendMessage(msg);
        final int assignedAddress = logicalAddress;
        if (callback != null) {
            runOnServiceThread(new Runnable() {
                    @Override
                public void run() {
                    callback.onAllocated(deviceType, assignedAddress);
                }
            });
        }

    private final class ControlHandler extends Handler {
        private ControlHandler(Looper looper) {
            super(looper);
    }

        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case MSG_RECEIVE_CEC_COMMAND:
                    // TODO: delegate it to HdmiControl service.
                    onReceiveCommand((HdmiCecMessage) msg.obj);
                    break;
                case MSG_REPORT_LOGICAL_ADDRESS:
                    int deviceType = msg.arg1;
                    int logicalAddress = msg.arg2;
                    AllocateLogicalAddressCallback callback =
                            (AllocateLogicalAddressCallback) msg.obj;
                    callback.onAllocated(deviceType, logicalAddress);
                    break;
                default:
                    Slog.i(TAG, "Unsupported message type:" + msg.what);
                    break;
            }
        }
    private static byte[] buildBody(int opcode, byte[] params) {
        byte[] body = new byte[params.length + 1];
        body[0] = (byte) opcode;
        System.arraycopy(params, 0, body, 1, params.length);
        return body;
    }

    /**
@@ -411,10 +359,18 @@ final class HdmiCecController {
        return nativeGetVendorId(mNativePtr);
    }

    private void runOnIoThread(Runnable runnable) {
        mIoHandler.post(runnable);
    }

    private void runOnServiceThread(Runnable runnable) {
        mControlHandler.post(runnable);
    }

    private void init(HdmiControlService service, long nativePtr) {
        mService = service;
        mIoHandler = new IoHandler(service.getServiceLooper());
        mControlHandler = new ControlHandler(service.getServiceLooper());
        mIoHandler = new Handler(service.getServiceLooper());
        mControlHandler = new Handler(service.getServiceLooper());
        mNativePtr = nativePtr;
    }

@@ -438,13 +394,27 @@ final class HdmiCecController {
        HdmiCecMessage cecMessage = HdmiCecMessageBuilder.buildFeatureAbortCommand
                (sourceAddress, message.getSource(), message.getOpcode(),
                        HdmiCecMessageBuilder.ABORT_REFUSED);
        sendCommand(cecMessage);

        sendCommand(cecMessage, null);
    }

    boolean sendCommand(HdmiCecMessage cecMessage) {
        Message message = mIoHandler.obtainMessage(MSG_SEND_CEC_COMMAND, cecMessage);
        return mIoHandler.sendMessage(message);
    void sendCommand(final HdmiCecMessage cecMessage,
            final HdmiControlService.SendMessageCallback callback) {
        runOnIoThread(new Runnable() {
            @Override
            public void run() {
                byte[] body = buildBody(cecMessage.getOpcode(), cecMessage.getParams());
                final int error = nativeSendCecCommand(mNativePtr, cecMessage.getSource(),
                        cecMessage.getDestination(), body);
                if (callback != null) {
                    runOnServiceThread(new Runnable() {
                        @Override
                        public void run() {
                            callback.onSendCompleted(error);
                        }
                    });
                }
            }
        });
    }

    /**
@@ -453,12 +423,15 @@ final class HdmiCecController {
    private void handleIncomingCecCommand(int srcAddress, int dstAddress, byte[] body) {
        byte opcode = body[0];
        byte params[] = Arrays.copyOfRange(body, 1, body.length);
        HdmiCecMessage cecMessage = new HdmiCecMessage(srcAddress, dstAddress, opcode, params);
        final HdmiCecMessage cecMessage = new HdmiCecMessage(srcAddress, dstAddress, opcode, params);

        // Delegate message to main handler so that it handles in main thread.
        Message message = mControlHandler.obtainMessage(
                MSG_RECEIVE_CEC_COMMAND, cecMessage);
        mControlHandler.sendMessage(message);
        runOnServiceThread(new Runnable() {
            @Override
            public void run() {
                onReceiveCommand(cecMessage);
            }
        });
    }

    /**
+24 −11
Original line number Diff line number Diff line
@@ -18,30 +18,25 @@ package com.android.server.hdmi;

import android.annotation.Nullable;
import android.content.Context;
import android.hardware.hdmi.IHdmiControlCallback;
import android.hardware.hdmi.IHdmiControlService;
import android.hardware.hdmi.IHdmiHotplugEventListener;
import android.hardware.hdmi.HdmiCec;
import android.hardware.hdmi.HdmiCecDeviceInfo;
import android.hardware.hdmi.HdmiCecMessage;
import android.hardware.hdmi.IHdmiControlCallback;
import android.hardware.hdmi.IHdmiControlService;
import android.hardware.hdmi.IHdmiHotplugEventListener;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.IBinder;
import android.os.Looper;
import android.os.RemoteException;
import android.util.Slog;
import android.util.SparseArray;


import com.android.internal.annotations.GuardedBy;
import com.android.server.SystemService;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Locale;

/**
@@ -54,6 +49,20 @@ public final class HdmiControlService extends SystemService {
    // TODO: Rename the permission to HDMI_CONTROL.
    private static final String PERMISSION = "android.permission.HDMI_CEC";

    /**
     * Interface to report send result.
     */
    interface SendMessageCallback {
        /**
         * Called when {@link HdmiControlService#sendCecCommand} is completed.
         *
         * @param error result of send request. 0 if succeed. Otherwise it will be
         *        negative value
         */
        // TODO: define error code as constants and update javadoc.
        void onSendCompleted(int error);
    }

    // A thread to handle synchronous IO of CEC and MHL control service.
    // Since all of CEC and MHL HAL interfaces processed in short time (< 200ms)
    // and sparse call it shares a thread to handle IO operations.
@@ -205,10 +214,14 @@ public final class HdmiControlService extends SystemService {
     * Transmit a CEC command to CEC bus.
     *
     * @param command CEC command to send out
     * @return {@code true} if succeeds to send command
     * @param callback interface used to the result of send command
     */
    boolean sendCecCommand(HdmiCecMessage command) {
        return mCecController.sendCommand(command);
    void sendCecCommand(HdmiCecMessage command, @Nullable SendMessageCallback callback) {
        mCecController.sendCommand(command, callback);
    }

    void sendCecCommand(HdmiCecMessage command) {
        mCecController.sendCommand(command, null);
    }

    /**
+19 −11
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@

package com.android.server.hdmi;

import android.hardware.hdmi.HdmiCecMessage;
import android.util.Slog;

/**
@@ -37,17 +38,24 @@ final class RequestArcInitiationAction extends RequestArcAction {

    @Override
    boolean start() {
        if (sendCommand(
                HdmiCecMessageBuilder.buildRequestArcInitiation(mSourceAddress, mAvrAddress))) {
        HdmiCecMessage command = HdmiCecMessageBuilder.buildRequestArcInitiation(mSourceAddress,
                mAvrAddress);
        sendCommand(command, new HdmiControlService.SendMessageCallback() {
            @Override
            public void onSendCompleted(int error) {
                // success.
                if (error == 0) {
                    mState = STATE_WATING_FOR_REQUEST_ARC_REQUEST_RESPONSE;
                    addTimer(mState, TIMEOUT_MS);
                } else {
                    Slog.w(TAG, "Failed to send <Request ARC Initiation>");
            // If failed to send <Request ARC Initiation>, start "Disabled" ARC transmission
            // action.
                    // If failed to send <Request ARC Initiation>, start "Disabled"
                    // ARC transmission action.
                    disableArcTransmission();
                    finish();
                }
            }
        });
        return true;
    }
}
+18 −11
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@

package com.android.server.hdmi;

import android.hardware.hdmi.HdmiCecMessage;
import android.util.Slog;

/**
@@ -37,17 +38,23 @@ final class RequestArcTerminationAction extends RequestArcAction {

    @Override
    boolean start() {
        if (sendCommand(
                HdmiCecMessageBuilder.buildRequestArcTermination(mSourceAddress, mAvrAddress))) {
        HdmiCecMessage command =
                HdmiCecMessageBuilder.buildRequestArcTermination(mSourceAddress, mAvrAddress);
        sendCommand(command, new HdmiControlService.SendMessageCallback() {
            @Override
            public void onSendCompleted(int error) {
                if (error == 0) {
                    mState = STATE_WATING_FOR_REQUEST_ARC_REQUEST_RESPONSE;
                    addTimer(mState, TIMEOUT_MS);
                } else {
                    Slog.w(TAG, "Failed to send <Request ARC Initiation>");
            // If failed to send <Request ARC Termination>, start "Disabled" ARC transmission
            // action.
                    // If failed to send <Request ARC Termination>, start "Disabled" ARC
                    // transmission action.
                    disableArcTransmission();
                    finish();
                }
            }
        });
        return true;
    }
}
Loading