Implement handlers for system information query command.

System information query commands are stateless command and
it should be replied immediately when it receives query command.
Here is a list of command handler (and it's reply) implemented
in this change.
1. <Get Menu Language> -> <Set Menu Language>
2. <Give(Get) OSD Name> -> <Set OSD Name>
3. <Give Physical Address> -> <Report Physical Address>
4. <Give Device Vendor ID> -> <Device Vendor Id>
5. <Give CEC Version> -> <CEC Version>

In order to centralize all cec message building, added new
builder class, HdmiCecMessageBuilder for HdmiCecMessage.
Accordingly, all helper methods for building of HdmiCecMessage
are moved to HdmiCecMessageBuilder class.

Change-Id: Ib7c5d2b0cb3d69d51159af8bc277ffb49a60909b
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecController.java b/services/core/java/com/android/server/hdmi/HdmiCecController.java
index b103a4d..5327ef4 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecController.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecController.java
@@ -55,15 +55,6 @@
     // A message to report allocated logical address to main control looper.
     private final static int MSG_REPORT_LOGICAL_ADDRESS = 2;
 
-    // TODO: move these values to HdmiCec.java once make it internal constant class.
-    // CEC's ABORT reason values.
-    private static final int ABORT_UNRECOGNIZED_MODE = 0;
-    private static final int ABORT_NOT_IN_CORRECT_MODE = 1;
-    private static final int ABORT_CANNOT_PROVIDE_SOURCE = 2;
-    private static final int ABORT_INVALID_OPERAND = 3;
-    private static final int ABORT_REFUSED = 4;
-    private static final int ABORT_UNABLE_TO_DETERMINE = 5;
-
     private static final int NUM_LOGICAL_ADDRESS = 16;
 
     // TODO: define other constants for errors.
@@ -80,10 +71,16 @@
     // interacts with HAL.
     private long mNativePtr;
 
+    private HdmiControlService mService;
+
     // Map-like container of all cec devices. A logical address of device is
     // used as key of container.
     private final SparseArray<HdmiCecDeviceInfo> mDeviceInfos =
             new SparseArray<HdmiCecDeviceInfo>();
+    // Set-like container for all local devices' logical address.
+    // Key and value are same.
+    private final SparseArray<Integer> mLocalLogicalAddresses =
+            new SparseArray<Integer>();
 
     // Private constructor.  Use HdmiCecController.create().
     private HdmiCecController() {
@@ -325,6 +322,7 @@
      */
     int addLogicalAddress(int newLogicalAddress) {
         if (HdmiCec.isValidAddress(newLogicalAddress)) {
+            mLocalLogicalAddresses.append(newLogicalAddress, newLogicalAddress);
             return nativeAddLogicalAddress(mNativePtr, newLogicalAddress);
         } else {
             return -1;
@@ -337,6 +335,9 @@
      * <p>Declared as package-private. accessed by {@link HdmiControlService} only.
      */
     void clearLogicalAddress() {
+        // TODO: consider to backup logical address so that new logical address
+        // allocation can use it as preferred address.
+        mLocalLogicalAddresses.clear();
         nativeClearLogicalAddress(mNativePtr);
     }
 
@@ -371,30 +372,37 @@
     }
 
     private void init(HdmiControlService service, long nativePtr) {
+        mService = service;
         mIoHandler = new IoHandler(service.getServiceLooper());
         mControlHandler = new ControlHandler(service.getServiceLooper());
         mNativePtr = nativePtr;
     }
 
+    private boolean isAcceptableAddress(int address) {
+        // Can access command targeting devices available in local device or
+        // broadcast command.
+        return address == HdmiCec.ADDR_BROADCAST
+                || mLocalLogicalAddresses.get(address) != null;
+    }
+
     private void onReceiveCommand(HdmiCecMessage message) {
-        // TODO: Handle message according to opcode type.
+        if (isAcceptableAddress(message.getDestination()) &&
+                mService.handleCecCommand(message)) {
+            return;
+        }
 
         // TODO: Use device's source address for broadcast message.
         int sourceAddress = message.getDestination() != HdmiCec.ADDR_BROADCAST ?
                 message.getDestination() : 0;
         // Reply <Feature Abort> to initiator (source) for all requests.
-        sendFeatureAbort(sourceAddress, message.getSource(), message.getOpcode(),
-                ABORT_REFUSED);
+        HdmiCecMessage cecMessage = HdmiCecMessageBuilder.buildFeatureAbortCommand
+                (sourceAddress, message.getSource(), message.getOpcode(),
+                        HdmiCecMessageBuilder.ABORT_REFUSED);
+        sendCommand(cecMessage);
+
     }
 
-    private void sendFeatureAbort(int srcAddress, int destAddress, int originalOpcode,
-            int reason) {
-        byte[] params = new byte[2];
-        params[0] = (byte) originalOpcode;
-        params[1] = (byte) reason;
-
-        HdmiCecMessage cecMessage = new HdmiCecMessage(srcAddress, destAddress,
-                HdmiCec.MESSAGE_FEATURE_ABORT, params);
+    void sendCommand(HdmiCecMessage cecMessage) {
         Message message = mIoHandler.obtainMessage(MSG_SEND_CEC_COMMAND, cecMessage);
         mIoHandler.sendMessage(message);
     }