diff options
author | Jinsuk Kim <jinsukkim@google.com> | 2014-05-11 06:54:49 +0900 |
---|---|---|
committer | Jinsuk Kim <jinsukkim@google.com> | 2014-06-12 23:06:29 +0000 |
commit | a6ce7708d6124224399241503fadcafe0c4684d4 (patch) | |
tree | 2a9a02085a02b19a3656d79525e9d1f34ff63c12 | |
parent | 85c262772de33a12a20bbcc11eb8349738e550d7 (diff) | |
download | frameworks_base-a6ce7708d6124224399241503fadcafe0c4684d4.zip frameworks_base-a6ce7708d6124224399241503fadcafe0c4684d4.tar.gz frameworks_base-a6ce7708d6124224399241503fadcafe0c4684d4.tar.bz2 |
DeviceSelectAction for HdmiControlService
DeviceSelectAction is the main handler for the API deviceSelect() which is
used to choose a new active source among logical devices on the bus.
Change-Id: I77582a1f873423fc316d89f67a89a867461a76b2
10 files changed, 549 insertions, 39 deletions
diff --git a/core/java/android/hardware/hdmi/HdmiTvClient.java b/core/java/android/hardware/hdmi/HdmiTvClient.java index 6dc4a4f..85af3d1 100644 --- a/core/java/android/hardware/hdmi/HdmiTvClient.java +++ b/core/java/android/hardware/hdmi/HdmiTvClient.java @@ -16,6 +16,8 @@ package android.hardware.hdmi; import android.annotation.SystemApi; +import android.os.RemoteException; +import android.util.Log; /** * HdmiTvClient represents HDMI-CEC logical device of type TV in the Android system @@ -33,4 +35,46 @@ public final class HdmiTvClient { HdmiTvClient(IHdmiControlService service) { mService = service; } + + // Factory method for HdmiTvClient. + // Declared package-private. Accessed by HdmiControlManager only. + static HdmiTvClient create(IHdmiControlService service) { + return new HdmiTvClient(service); + } + + /** + * Callback interface used to get the result of {@link #deviceSelect}. + */ + public interface SelectCallback { + /** + * Called when the operation is finished. + * + * @param result the result value of {@link #deviceSelect} + */ + void onComplete(int result); + } + + /** + * Select a CEC logical device to be a new active source. + * + * @param logicalAddress + * @param callback + */ + public void deviceSelect(int logicalAddress, SelectCallback callback) { + // TODO: Replace SelectCallback with PartialResult. + try { + mService.deviceSelect(logicalAddress, getCallbackWrapper(callback)); + } catch (RemoteException e) { + Log.e(TAG, "failed to select device: ", e); + } + } + + private static IHdmiControlCallback getCallbackWrapper(final SelectCallback callback) { + return new IHdmiControlCallback.Stub() { + @Override + public void onComplete(int result) { + callback.onComplete(result); + } + }; + } } diff --git a/core/java/android/hardware/hdmi/IHdmiControlService.aidl b/core/java/android/hardware/hdmi/IHdmiControlService.aidl index 8da38e1..8d7c638 100644 --- a/core/java/android/hardware/hdmi/IHdmiControlService.aidl +++ b/core/java/android/hardware/hdmi/IHdmiControlService.aidl @@ -33,4 +33,5 @@ interface IHdmiControlService { void queryDisplayStatus(IHdmiControlCallback callback); void addHotplugEventListener(IHdmiHotplugEventListener listener); void removeHotplugEventListener(IHdmiHotplugEventListener listener); + void deviceSelect(int logicalAddress, IHdmiControlCallback callback); } diff --git a/services/core/java/com/android/server/hdmi/ActiveSourceHandler.java b/services/core/java/com/android/server/hdmi/ActiveSourceHandler.java new file mode 100644 index 0000000..32bcb69 --- /dev/null +++ b/services/core/java/com/android/server/hdmi/ActiveSourceHandler.java @@ -0,0 +1,112 @@ +/* + * Copyright (C) 2014 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 android.annotation.Nullable; +import android.hardware.hdmi.IHdmiControlCallback; +import android.hardware.hdmi.HdmiCec; +import android.hardware.hdmi.HdmiCecDeviceInfo; +import android.hardware.hdmi.HdmiCecMessage; +import android.os.RemoteException; +import android.util.Slog; + +/** + * Handles CEC command <Active Source>. + * + * <p>Used by feature actions that need to handle the command in their flow. + */ +final class ActiveSourceHandler { + private static final String TAG = "ActiveSourceHandler"; + + private final HdmiControlService mService; + private final int mSourceAddress; + private final int mSourcePath; + @Nullable private final IHdmiControlCallback mCallback; + + static ActiveSourceHandler create(HdmiControlService service, int sourceAddress, + int sourcePath, IHdmiControlCallback callback) { + if (service == null) { + Slog.e(TAG, "Wrong arguments"); + return null; + } + return new ActiveSourceHandler(service, sourceAddress, sourcePath, callback); + } + + private ActiveSourceHandler(HdmiControlService service, int sourceAddress, int sourcePath, + IHdmiControlCallback callback) { + mService = service; + mSourceAddress = sourceAddress; + mSourcePath = sourcePath; + mCallback = callback; + } + + /** + * Handles the incoming active source command. + * + * @param deviceLogicalAddress logical address of the device to be the active source + * @param routingPath routing path of the device to be the active source + */ + void process(int deviceLogicalAddress, int routingPath) { + if (mSourcePath == routingPath && mService.getActiveSource() == mSourceAddress) { + invokeCallback(HdmiCec.RESULT_SUCCESS); + return; + } + HdmiCecDeviceInfo device = mService.getDeviceInfo(deviceLogicalAddress); + if (device == null) { + // TODO: Start new device action (Device Discovery) sequence 5. + } + + if (!mService.isInPresetInstallationMode()) { + int prevActiveInput = mService.getActiveInput(); + mService.updateActiveDevice(deviceLogicalAddress, routingPath); + if (prevActiveInput != mService.getActiveInput()) { + // TODO: change port input here. + } + invokeCallback(HdmiCec.RESULT_SUCCESS); + } else { + // TV is in a mode that should keep its current source/input from + // being changed for its operation. Reclaim the active source + // or switch the port back to the one used for the current mode. + if (mService.getActiveSource() == mSourceAddress) { + HdmiCecMessage activeSource = + HdmiCecMessageBuilder.buildActiveSource(mSourceAddress, mSourcePath); + mService.sendCecCommand(activeSource); + mService.updateActiveDevice(deviceLogicalAddress, routingPath); + invokeCallback(HdmiCec.RESULT_SUCCESS); + } else { + int activePath = mService.getActivePath(); + mService.sendCecCommand(HdmiCecMessageBuilder.buildRoutingChange(mSourceAddress, + routingPath, activePath)); + // TODO: Start port select action here + // PortSelectAction action = new PortSelectAction(mService, mSourceAddress, + // activePath, mCallback); + // mService.addActionAndStart(action); + } + } + } + + private void invokeCallback(int result) { + if (mCallback == null) { + return; + } + try { + mCallback.onComplete(result); + } catch (RemoteException e) { + Slog.e(TAG, "Callback failed:" + e); + } + } +} diff --git a/services/core/java/com/android/server/hdmi/DeviceSelectAction.java b/services/core/java/com/android/server/hdmi/DeviceSelectAction.java new file mode 100644 index 0000000..f170de0 --- /dev/null +++ b/services/core/java/com/android/server/hdmi/DeviceSelectAction.java @@ -0,0 +1,223 @@ +/* + * Copyright (C) 2014 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 android.hardware.hdmi.IHdmiControlCallback; +import android.hardware.hdmi.HdmiCecDeviceInfo; +import android.hardware.hdmi.HdmiCec; +import android.hardware.hdmi.HdmiCecMessage; +import android.os.RemoteException; +import android.util.Slog; + +/** + * Handles an action that selects a logical device as a new active source. + * + * Triggered by {@link HdmiTvClient}, attempts to select the given target device + * for a new active source. It does its best to wake up the target in standby mode + * before issuing the command >Set Stream path<. + */ +final class DeviceSelectAction extends FeatureAction { + private static final String TAG = "DeviceSelect"; + + // Time in milliseconds we wait for the device power status to switch to 'Standby' + private static final int TIMEOUT_TRANSIT_TO_STANDBY_MS = 5 * 1000; + + // Time in milliseconds we wait for the device power status to turn to 'On'. + private static final int TIMEOUT_POWER_ON_MS = 5 * 1000; + + // Time in milliseconds we wait for <Active Source>. + private static final int TIMEOUT_ACTIVE_SOURCE_MS = 20 * 1000; + + // The number of times we try to wake up the target device before we give up + // and just send <Set Stream Path>. + private static final int LOOP_COUNTER_MAX = 20; + + // State in which we wait for <Report Power Status> to come in response to the command + // <Give Device Power Status> we have sent. + private static final int STATE_WAIT_FOR_REPORT_POWER_STATUS = 1; + + // State in which we wait for the device power status to switch to 'Standby'. + // We wait till the status becomes 'Standby' before we send <Set Stream Path> + // to wake up the device again. + private static final int STATE_WAIT_FOR_DEVICE_TO_TRANSIT_TO_STANDBY = 2; + + // State in which we wait for the device power status to switch to 'on'. We wait + // maximum 100 seconds (20 * 5) before we give up and just send <Set Stream Path>. + private static final int STATE_WAIT_FOR_DEVICE_POWER_ON = 3; + + // State in which we wait for the <Active Source> in response to the command + // <Set Stream Path> we have sent. We wait as much as TIMEOUT_ACTIVE_SOURCE_MS + // before we give up and mark the action as failure. + private static final int STATE_WAIT_FOR_ACTIVE_SOURCE = 4; + + private final HdmiCecDeviceInfo mTarget; + private final IHdmiControlCallback mCallback; + private final int mSourcePath; + + private int mPowerStatusCounter = 0; + + /** + * Constructor. + * + * @param service {@link HdmiControlService} instance + * @param sourceAddress logical address of TV initiating this action + * @param sourcePath physical address of TV + * @param target target logical device that will be a new active source + * @param callback callback object + */ + public DeviceSelectAction(HdmiControlService service, int sourceAddress, int sourcePath, + HdmiCecDeviceInfo target, IHdmiControlCallback callback) { + super(service, sourceAddress); + mCallback = callback; + mSourcePath = sourcePath; + mTarget = target; + } + + @Override + public boolean start() { + // TODO: Call the logic that display a banner saying the select action got started. + queryDevicePowerStatus(); + return true; + } + + private void queryDevicePowerStatus() { + sendCommand(HdmiCecMessageBuilder.buildGiveDevicePowerStatus( + mSourceAddress, mTarget.getLogicalAddress())); + mState = STATE_WAIT_FOR_REPORT_POWER_STATUS; + addTimer(mState, TIMEOUT_MS); + } + + @Override + public boolean processCommand(HdmiCecMessage cmd) { + if (cmd.getSource() != mTarget.getLogicalAddress()) { + return false; + } + int opcode = cmd.getOpcode(); + byte[] params = cmd.getParams(); + + switch (mState) { + case STATE_WAIT_FOR_REPORT_POWER_STATUS: + if (opcode == HdmiCec.MESSAGE_REPORT_POWER_STATUS && params.length == 1) { + return handleReportPowerStatus(params[0]); + } + return false; + case STATE_WAIT_FOR_ACTIVE_SOURCE: + if (opcode == HdmiCec.MESSAGE_ACTIVE_SOURCE && params.length == 2) { + int activePath = HdmiUtils.twoBytesToInt(params); + ActiveSourceHandler.create(mService, mSourceAddress, mSourcePath, mCallback) + .process(cmd.getSource(), activePath); + finish(); + return true; + } + return false; + default: + break; + } + return false; + } + + private boolean handleReportPowerStatus(int powerStatus) { + // TODO: Check TV's own status which might have been updated during the action. + // If in 'Standby' or 'Transit to standby', remove the banner + // and stop this action. Otherwise, send <Set Stream Path> + switch (powerStatus) { + case HdmiCec.POWER_STATUS_ON: + sendSetStreamPath(); + return true; + case HdmiCec.POWER_STATUS_TRANSIENT_TO_STANDBY: + if (mPowerStatusCounter < 4) { + mState = STATE_WAIT_FOR_DEVICE_TO_TRANSIT_TO_STANDBY; + addTimer(mState, TIMEOUT_TRANSIT_TO_STANDBY_MS); + } else { + sendSetStreamPath(); + } + return true; + case HdmiCec.POWER_STATUS_STANDBY: + if (mPowerStatusCounter == 0) { + turnOnDevice(); + } else { + sendSetStreamPath(); + } + return true; + case HdmiCec.POWER_STATUS_TRANSIENT_TO_ON: + if (mPowerStatusCounter < LOOP_COUNTER_MAX) { + mState = STATE_WAIT_FOR_DEVICE_POWER_ON; + addTimer(mState, TIMEOUT_POWER_ON_MS); + } else { + sendSetStreamPath(); + } + return true; + } + return false; + } + + private void turnOnDevice() { + sendRemoteKeyCommand(HdmiConstants.UI_COMMAND_POWER); + sendRemoteKeyCommand(HdmiConstants.UI_COMMAND_POWER_ON_FUNCTION); + mState = STATE_WAIT_FOR_DEVICE_POWER_ON; + addTimer(mState, TIMEOUT_POWER_ON_MS); + } + + private void sendSetStreamPath() { + sendCommand(HdmiCecMessageBuilder.buildSetStreamPath( + mSourceAddress, mTarget.getPhysicalAddress())); + mState = STATE_WAIT_FOR_ACTIVE_SOURCE; + addTimer(mState, TIMEOUT_ACTIVE_SOURCE_MS); + } + + private void sendRemoteKeyCommand(int keyCode) { + sendCommand(HdmiCecMessageBuilder.buildUserControlPressed(mSourceAddress, + mTarget.getLogicalAddress(), keyCode)); + sendCommand(HdmiCecMessageBuilder.buildUserControlReleased(mSourceAddress, + mTarget.getLogicalAddress())); + } + + @Override + public void handleTimerEvent(int timeoutState) { + if (mState != timeoutState) { + Slog.w(TAG, "Timer in a wrong state. Ignored."); + return; + } + switch (mState) { + case STATE_WAIT_FOR_REPORT_POWER_STATUS: + sendSetStreamPath(); + break; + case STATE_WAIT_FOR_DEVICE_TO_TRANSIT_TO_STANDBY: + case STATE_WAIT_FOR_DEVICE_POWER_ON: + mPowerStatusCounter++; + queryDevicePowerStatus(); + break; + case STATE_WAIT_FOR_ACTIVE_SOURCE: + // TODO: Remove the banner + // Display banner "Communication failed. Please check your cable or connection" + invokeCallback(HdmiCec.RESULT_TIMEOUT); + finish(); + break; + } + } + + private void invokeCallback(int result) { + if (mCallback == null) { + return; + } + try { + mCallback.onComplete(result); + } catch (RemoteException e) { + Slog.e(TAG, "Callback failed:" + e); + } + } +} diff --git a/services/core/java/com/android/server/hdmi/FeatureAction.java b/services/core/java/com/android/server/hdmi/FeatureAction.java index 0ba7773..ae272b4 100644 --- a/services/core/java/com/android/server/hdmi/FeatureAction.java +++ b/services/core/java/com/android/server/hdmi/FeatureAction.java @@ -46,8 +46,9 @@ abstract class FeatureAction { // Timer handler message used for timeout event protected static final int MSG_TIMEOUT = 100; - // Default timeout for the incoming command to arrive in response to a request - protected static final int TIMEOUT_MS = 1000; + // Default timeout for the incoming command to arrive in response to a request. + // TODO: Consider reading this value from configuration to allow customization. + protected static final int TIMEOUT_MS = 2000; // Default state used in common by all the feature actions. protected static final int STATE_NONE = 0; diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java index 8bd81ea..6394fe7 100644 --- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java +++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java @@ -16,8 +16,11 @@ package com.android.server.hdmi; +import android.hardware.hdmi.IHdmiControlCallback; import android.hardware.hdmi.HdmiCec; +import android.hardware.hdmi.HdmiCecDeviceInfo; import android.hardware.hdmi.HdmiCecMessage; +import android.os.RemoteException; import android.util.Slog; import java.util.Locale; @@ -55,6 +58,31 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice { } } + /** + * Performs the action 'device select', or 'one touch play' initiated by TV. + * + * @param targetAddress logical address of the device to select + * @param callback callback object to report the result with + */ + void deviceSelect(int targetAddress, IHdmiControlCallback callback) { + HdmiCecDeviceInfo targetDevice = mService.getDeviceInfo(targetAddress); + if (targetDevice == null) { + invokeCallback(callback, HdmiCec.RESULT_TARGET_NOT_AVAILABLE); + return; + } + mService.removeAction(DeviceSelectAction.class); + mService.addAndStartAction(new DeviceSelectAction(mService, mAddress, + mService.getPhysicalAddress(), targetDevice, callback)); + } + + private static void invokeCallback(IHdmiControlCallback callback, int result) { + try { + callback.onComplete(result); + } catch (RemoteException e) { + Slog.e(TAG, "Invoking callback failed:" + e); + } + } + @Override protected boolean handleGetMenuLanguage(HdmiCecMessage message) { HdmiCecMessage command = HdmiCecMessageBuilder.buildSetMenuLanguageCommand( diff --git a/services/core/java/com/android/server/hdmi/HdmiCecMessageBuilder.java b/services/core/java/com/android/server/hdmi/HdmiCecMessageBuilder.java index 1fcb32f..8dbfd85 100644 --- a/services/core/java/com/android/server/hdmi/HdmiCecMessageBuilder.java +++ b/services/core/java/com/android/server/hdmi/HdmiCecMessageBuilder.java @@ -270,6 +270,38 @@ public class HdmiCecMessageBuilder { } /** + * Build <Set Stream Path> command. + * + * <p>This is a broadcast message sent to all devices on the bus. + * + * @param src source address of command + * @param streamPath physical address of the device to start streaming + * @return newly created {@link HdmiCecMessage} + */ + static HdmiCecMessage buildSetStreamPath(int src, int streamPath) { + return buildCommand(src, HdmiCec.ADDR_BROADCAST, HdmiCec.MESSAGE_SET_STREAM_PATH, + physicalAddressToParam(streamPath)); + } + + /** + * Build <Routing Change> command. + * + * <p>This is a broadcast message sent to all devices on the bus. + * + * @param src source address of command + * @param oldPath physical address of the currently active routing path + * @param newPath physical address of the new active routing path + * @return newly created {@link HdmiCecMessage} + */ + static HdmiCecMessage buildRoutingChange(int src, int oldPath, int newPath) { + byte[] param = new byte[] { + (byte) ((oldPath >> 8) & 0xFF), (byte) (oldPath & 0xFF), + (byte) ((newPath >> 8) & 0xFF), (byte) (newPath & 0xFF) + }; + return buildCommand(src, HdmiCec.ADDR_BROADCAST, HdmiCec.MESSAGE_ROUTING_CHANGE, param); + } + + /** * Build <Give Device Power Status> command. * * @param src source address of command diff --git a/services/core/java/com/android/server/hdmi/HdmiConstants.java b/services/core/java/com/android/server/hdmi/HdmiConstants.java index 54b5dcb..8f319ea 100644 --- a/services/core/java/com/android/server/hdmi/HdmiConstants.java +++ b/services/core/java/com/android/server/hdmi/HdmiConstants.java @@ -39,9 +39,15 @@ final class HdmiConstants { // Constants related to UI Command Codes. // Refer to CEC Table 30 in HDMI Spec v1.4b. + static final int UI_COMMAND_POWER = 0x40; static final int UI_COMMAND_MUTE = 0x43; static final int UI_COMMAND_MUTE_FUNCTION = 0x65; static final int UI_COMMAND_RESTORE_VOLUME_FUNCTION = 0x66; + static final int UI_COMMAND_POWER_ON_FUNCTION = 0x6D; + + // Bit mask used to get the routing path of the top level device. + // When &'d with the path 1.2.2.0 (0x1220), for instance, gives 1.0.0.0. + static final int ROUTING_PATH_TOP_MASK = 0xF000; // Flags used for setOption to CEC HAL. /** diff --git a/services/core/java/com/android/server/hdmi/HdmiControlService.java b/services/core/java/com/android/server/hdmi/HdmiControlService.java index d41da30..5eb0db7 100644 --- a/services/core/java/com/android/server/hdmi/HdmiControlService.java +++ b/services/core/java/com/android/server/hdmi/HdmiControlService.java @@ -125,6 +125,21 @@ public final class HdmiControlService extends SystemService { @Nullable private HdmiMhlController mMhlController; + // Logical address of the active source. + @GuardedBy("mLock") + private int mActiveSource; + + // Active routing path. Physical address of the active source but not all the time, such as + // when the new active source does not claim itself to be one. + @GuardedBy("mLock") + private int mActiveRoutingPath; + + // Set to true while the service is in normal mode. While set to false, no input change is + // allowed. Used for situations where input change can confuse users such as channel auto-scan, + // system upgrade, etc., a.k.a. "prohibit mode". + @GuardedBy("mLock") + private boolean mInputChangeEnabled; + @GuardedBy("mLock") // Whether ARC is "enabled" or not. // TODO: it may need to hold lock if it's accessed from others. @@ -141,6 +156,8 @@ public final class HdmiControlService extends SystemService { super(context); mLocalDevices = getContext().getResources().getIntArray( com.android.internal.R.array.config_hdmiCecLogicalDeviceType); + // TODO: Get control flag from persistent storage + mInputChangeEnabled = true; } @Override @@ -224,6 +241,41 @@ public final class HdmiControlService extends SystemService { return mHandler.getLooper(); } + int getActiveSource() { + synchronized (mLock) { + return mActiveSource; + } + } + + int getActivePath() { + synchronized (mLock) { + return mActiveRoutingPath; + } + } + + /** + * Returns the path (physical address) of the device at the top of the currently active + * routing path. Used to get the corresponding port address of the HDMI input of the TV. + */ + int getActiveInput() { + synchronized (mLock) { + return mActiveRoutingPath & HdmiConstants.ROUTING_PATH_TOP_MASK; + } + } + + void updateActiveDevice(int logicalAddress, int physicalAddress) { + synchronized (mLock) { + mActiveSource = logicalAddress; + mActiveRoutingPath = physicalAddress; + } + } + + void setInputChangeEnabled(boolean enabled) { + synchronized (mLock) { + mInputChangeEnabled = enabled; + } + } + /** * Returns physical address of the device. */ @@ -238,6 +290,10 @@ public final class HdmiControlService extends SystemService { return mCecController.getVendorId(); } + HdmiCecDeviceInfo getDeviceInfo(int logicalAddress) { + return mCecController.getDeviceInfo(logicalAddress); + } + /** * Returns version of CEC. */ @@ -304,7 +360,7 @@ public final class HdmiControlService extends SystemService { } // Remove all actions matched with the given Class type. - private <T extends FeatureAction> void removeAction(final Class<T> clazz) { + <T extends FeatureAction> void removeAction(final Class<T> clazz) { removeActionExcept(clazz, null); } @@ -575,6 +631,25 @@ public final class HdmiControlService extends SystemService { } @Override + public void deviceSelect(final int logicalAddress, final IHdmiControlCallback callback) { + enforceAccessPermission(); + runOnServiceThread(new Runnable() { + @Override + public void run() { + HdmiCecLocalDeviceTv tv = + (HdmiCecLocalDeviceTv) mCecController.getLocalDevice(HdmiCec.DEVICE_TV); + if (tv == null) { + Slog.w(TAG, "Local playback device not available"); + invokeCallback(callback, HdmiCec.RESULT_SOURCE_NOT_AVAILABLE); + return; + } + tv.deviceSelect(logicalAddress, callback); + } + }); + } + + + @Override public void oneTouchPlay(final IHdmiControlCallback callback) { enforceAccessPermission(); runOnServiceThread(new Runnable() { @@ -710,8 +785,9 @@ public final class HdmiControlService extends SystemService { } boolean isInPresetInstallationMode() { - // TODO: Implement this. - return false; + synchronized (mLock) { + return !mInputChangeEnabled; + } } /** diff --git a/services/core/jni/com_android_server_hdmi_HdmiCecController.cpp b/services/core/jni/com_android_server_hdmi_HdmiCecController.cpp index cbc853d..5bfabd9 100644 --- a/services/core/jni/com_android_server_hdmi_HdmiCecController.cpp +++ b/services/core/jni/com_android_server_hdmi_HdmiCecController.cpp @@ -69,6 +69,7 @@ public: } private: + static const int INVALID_PHYSICAL_ADDRESS = 0xFFFF; static void onReceived(const hdmi_event_t* event, void* arg); hdmi_cec_device_t* mDevice; @@ -209,11 +210,11 @@ void HdmiCecController::clearLogicaladdress() { } int HdmiCecController::getPhysicalAddress() { - uint16_t physicalAddress = 0xFFFF; - if (mDevice->get_physical_address(mDevice, &physicalAddress) == 0) { - return physicalAddress; + uint16_t addr; + if (!mDevice->get_physical_address(mDevice, &addr)) { + return addr; } - return -1; + return INVALID_PHYSICAL_ADDRESS; } int HdmiCecController::getVersion() { @@ -311,58 +312,45 @@ static jint nativeSendCecCommand(JNIEnv* env, jclass clazz, jlong controllerPtr, return controller->sendMessage(message); } -static jint nativeAddLogicalAddress(JNIEnv* env, jclass clazz, - jlong controllerPtr, jint logicalAddress) { - HdmiCecController* controller = - reinterpret_cast<HdmiCecController*>(controllerPtr); - return controller->addLogicalAddress( - static_cast<cec_logical_address_t>(logicalAddress)); +static jint nativeAddLogicalAddress(JNIEnv* env, jclass clazz, jlong controllerPtr, + jint logicalAddress) { + HdmiCecController* controller = reinterpret_cast<HdmiCecController*>(controllerPtr); + return controller->addLogicalAddress(static_cast<cec_logical_address_t>(logicalAddress)); } -static void nativeClearLogicalAddress(JNIEnv* env, jclass clazz, - jlong controllerPtr) { - HdmiCecController* controller = - reinterpret_cast<HdmiCecController*>(controllerPtr); +static void nativeClearLogicalAddress(JNIEnv* env, jclass clazz, jlong controllerPtr) { + HdmiCecController* controller = reinterpret_cast<HdmiCecController*>(controllerPtr); controller->clearLogicaladdress(); } -static jint nativeGetPhysicalAddress(JNIEnv* env, jclass clazz, - jlong controllerPtr) { - HdmiCecController* controller = - reinterpret_cast<HdmiCecController*>(controllerPtr); +static jint nativeGetPhysicalAddress(JNIEnv* env, jclass clazz, jlong controllerPtr) { + HdmiCecController* controller = reinterpret_cast<HdmiCecController*>(controllerPtr); return controller->getPhysicalAddress(); } -static jint nativeGetVersion(JNIEnv* env, jclass clazz, - jlong controllerPtr) { - HdmiCecController* controller = - reinterpret_cast<HdmiCecController*>(controllerPtr); +static jint nativeGetVersion(JNIEnv* env, jclass clazz, jlong controllerPtr) { + HdmiCecController* controller = reinterpret_cast<HdmiCecController*>(controllerPtr); return controller->getVersion(); } static jint nativeGetVendorId(JNIEnv* env, jclass clazz, jlong controllerPtr) { - HdmiCecController* controller = - reinterpret_cast<HdmiCecController*>(controllerPtr); + HdmiCecController* controller = reinterpret_cast<HdmiCecController*>(controllerPtr); return controller->getVendorId(); } -static void nativeSetOption(JNIEnv* env, jclass clazz, jlong controllerPtr, jint flag, - jint value) { - HdmiCecController* controller = - reinterpret_cast<HdmiCecController*>(controllerPtr); +static void nativeSetOption(JNIEnv* env, jclass clazz, jlong controllerPtr, jint flag, jint value) { + HdmiCecController* controller = reinterpret_cast<HdmiCecController*>(controllerPtr); controller->setOption(flag, value); } static void nativeSetAudioReturnChannel(JNIEnv* env, jclass clazz, jlong controllerPtr, jboolean enabled) { - HdmiCecController* controller = - reinterpret_cast<HdmiCecController*>(controllerPtr); + HdmiCecController* controller = reinterpret_cast<HdmiCecController*>(controllerPtr); controller->setAudioReturnChannel(enabled == JNI_TRUE); } static jboolean nativeIsConnected(JNIEnv* env, jclass clazz, jlong controllerPtr, jint port) { - HdmiCecController* controller = - reinterpret_cast<HdmiCecController*>(controllerPtr); + HdmiCecController* controller = reinterpret_cast<HdmiCecController*>(controllerPtr); return controller->isConnected(port) ? JNI_TRUE : JNI_FALSE ; } @@ -385,8 +373,7 @@ static JNINativeMethod sMethods[] = { #define CLASS_PATH "com/android/server/hdmi/HdmiCecController" int register_android_server_hdmi_HdmiCecController(JNIEnv* env) { - int res = jniRegisterNativeMethods(env, CLASS_PATH, sMethods, - NELEM(sMethods)); + int res = jniRegisterNativeMethods(env, CLASS_PATH, sMethods, NELEM(sMethods)); LOG_FATAL_IF(res < 0, "Unable to register native methods."); return 0; } |