Remove HdmiCecService
The service is replaced with HdmiControlService. Removing all the related classes and the initialization of the service. Change-Id: Ic7baaddffb9873613ddd1096e874f226da983939
This commit is contained in:
@ -146,8 +146,6 @@ LOCAL_SRC_FILES += \
|
||||
core/java/android/hardware/ISerialManager.aidl \
|
||||
core/java/android/hardware/display/IDisplayManager.aidl \
|
||||
core/java/android/hardware/display/IDisplayManagerCallback.aidl \
|
||||
core/java/android/hardware/hdmi/IHdmiCecListener.aidl \
|
||||
core/java/android/hardware/hdmi/IHdmiCecService.aidl \
|
||||
core/java/android/hardware/hdmi/IHdmiControlCallback.aidl \
|
||||
core/java/android/hardware/hdmi/IHdmiControlService.aidl \
|
||||
core/java/android/hardware/hdmi/IHdmiHotplugEventListener.aidl \
|
||||
|
@ -6992,7 +6992,6 @@ package android.content {
|
||||
field public static final java.lang.String DISPLAY_SERVICE = "display";
|
||||
field public static final java.lang.String DOWNLOAD_SERVICE = "download";
|
||||
field public static final java.lang.String DROPBOX_SERVICE = "dropbox";
|
||||
field public static final java.lang.String HDMI_CEC_SERVICE = "hdmi_cec";
|
||||
field public static final java.lang.String HDMI_CONTROL_SERVICE = "hdmi_control";
|
||||
field public static final java.lang.String INPUT_METHOD_SERVICE = "input_method";
|
||||
field public static final java.lang.String INPUT_SERVICE = "input";
|
||||
@ -12826,21 +12825,6 @@ package android.hardware.hdmi {
|
||||
field public static final int UNKNOWN_VENDOR_ID = 16777215; // 0xffffff
|
||||
}
|
||||
|
||||
public final class HdmiCecClient {
|
||||
method public boolean isTvOn();
|
||||
method public void sendActiveSource();
|
||||
method public void sendGiveDevicePowerStatus(int);
|
||||
method public void sendImageViewOn();
|
||||
method public void sendInactiveSource();
|
||||
method public void sendTextViewOn();
|
||||
}
|
||||
|
||||
public static abstract class HdmiCecClient.Listener {
|
||||
ctor public HdmiCecClient.Listener();
|
||||
method public void onCableStatusChanged(boolean);
|
||||
method public void onMessageReceived(android.hardware.hdmi.HdmiCecMessage);
|
||||
}
|
||||
|
||||
public final class HdmiCecDeviceInfo implements android.os.Parcelable {
|
||||
method public int describeContents();
|
||||
method public int getDeviceType();
|
||||
@ -12852,10 +12836,6 @@ package android.hardware.hdmi {
|
||||
field public static final android.os.Parcelable.Creator CREATOR;
|
||||
}
|
||||
|
||||
public final class HdmiCecManager {
|
||||
method public android.hardware.hdmi.HdmiCecClient getClient(int, android.hardware.hdmi.HdmiCecClient.Listener);
|
||||
}
|
||||
|
||||
public final class HdmiCecMessage implements android.os.Parcelable {
|
||||
ctor public HdmiCecMessage(int, int, int, byte[]);
|
||||
method public int describeContents();
|
||||
|
@ -57,9 +57,7 @@ import android.hardware.ConsumerIrManager;
|
||||
import android.hardware.ISerialManager;
|
||||
import android.hardware.SerialManager;
|
||||
import android.hardware.SystemSensorManager;
|
||||
import android.hardware.hdmi.HdmiCecManager;
|
||||
import android.hardware.hdmi.HdmiControlManager;
|
||||
import android.hardware.hdmi.IHdmiCecService;
|
||||
import android.hardware.hdmi.IHdmiControlService;
|
||||
import android.hardware.camera2.CameraManager;
|
||||
import android.hardware.display.DisplayManager;
|
||||
@ -384,12 +382,6 @@ class ContextImpl extends Context {
|
||||
return new BluetoothManager(ctx);
|
||||
}});
|
||||
|
||||
registerService(HDMI_CEC_SERVICE, new StaticServiceFetcher() {
|
||||
public Object createStaticService() {
|
||||
IBinder b = ServiceManager.getService(HDMI_CEC_SERVICE);
|
||||
return new HdmiCecManager(IHdmiCecService.Stub.asInterface(b));
|
||||
}});
|
||||
|
||||
registerService(HDMI_CONTROL_SERVICE, new StaticServiceFetcher() {
|
||||
public Object createStaticService() {
|
||||
IBinder b = ServiceManager.getService(HDMI_CONTROL_SERVICE);
|
||||
|
@ -2148,8 +2148,6 @@ public abstract class Context {
|
||||
* @see android.app.SearchManager
|
||||
* @see #SENSOR_SERVICE
|
||||
* @see android.hardware.SensorManager
|
||||
* @see #HDMI_CEC_SERVICE
|
||||
* @see android.hardware.hdmi.HdmiCecManager
|
||||
* @see #STORAGE_SERVICE
|
||||
* @see android.os.storage.StorageManager
|
||||
* @see #VIBRATOR_SERVICE
|
||||
@ -2636,17 +2634,6 @@ public abstract class Context {
|
||||
*/
|
||||
public static final String SERIAL_SERVICE = "serial";
|
||||
|
||||
/**
|
||||
* Use with {@link #getSystemService} to retrieve a
|
||||
* {@link android.hardware.hdmi.HdmiCecManager} for controlling and managing
|
||||
* HDMI-CEC protocol.
|
||||
*
|
||||
* @see #getSystemService
|
||||
* @see android.hardware.hdmi.HdmiCecManager
|
||||
*/
|
||||
// TODO: Remove this once HdmiControlService is ready.
|
||||
public static final String HDMI_CEC_SERVICE = "hdmi_cec";
|
||||
|
||||
/**
|
||||
* Use with {@link #getSystemService} to retrieve a
|
||||
* {@link android.hardware.hdmi.HdmiControlManager} for controlling and managing
|
||||
|
@ -1,119 +0,0 @@
|
||||
/*
|
||||
* 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 android.hardware.hdmi;
|
||||
|
||||
import android.os.IBinder;
|
||||
import android.os.RemoteException;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
/**
|
||||
* HdmiCecClient is used to control HDMI-CEC logical device instance in the system.
|
||||
* It is connected to actual hardware part via HdmiCecService. It provides with methods
|
||||
* to send CEC messages to other device on the bus, and listener that allows to receive
|
||||
* incoming messages to the device.
|
||||
*/
|
||||
public final class HdmiCecClient {
|
||||
private static final String TAG = "HdmiCecClient";
|
||||
|
||||
private final IHdmiCecService mService;
|
||||
private final IBinder mBinder;
|
||||
|
||||
/**
|
||||
* Listener used by the client to get the incoming messages.
|
||||
*/
|
||||
public static abstract class Listener {
|
||||
/**
|
||||
* Called when CEC message arrives. Override this method to receive the incoming
|
||||
* CEC messages from other device on the bus.
|
||||
*
|
||||
* @param message {@link HdmiCecMessage} object
|
||||
*/
|
||||
public void onMessageReceived(HdmiCecMessage message) { }
|
||||
|
||||
/**
|
||||
* Called when hotplug event occurs. Override this method to receive the events.
|
||||
*
|
||||
* @param connected true if the cable is connected; otherwise false.
|
||||
*/
|
||||
public void onCableStatusChanged(boolean connected) { }
|
||||
}
|
||||
|
||||
// Private constructor.
|
||||
private HdmiCecClient(IHdmiCecService service, IBinder b) {
|
||||
mService = service;
|
||||
mBinder = b;
|
||||
}
|
||||
|
||||
// Factory method for HdmiCecClient.
|
||||
// Declared package-private. Accessed by HdmiCecManager only.
|
||||
static HdmiCecClient create(IHdmiCecService service, IBinder b) {
|
||||
return new HdmiCecClient(service, b);
|
||||
}
|
||||
|
||||
/**
|
||||
* Send <Active Source> message.
|
||||
*/
|
||||
public void sendActiveSource() {
|
||||
Log.w(TAG, "In transition to HdmiControlManager. Will not work.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Send <Inactive Source> message.
|
||||
*/
|
||||
public void sendInactiveSource() {
|
||||
Log.w(TAG, "In transition to HdmiControlManager. Will not work.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Send <Text View On> message.
|
||||
*/
|
||||
public void sendTextViewOn() {
|
||||
Log.w(TAG, "In transition to HdmiControlManager. Will not work.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Send <Image View On> message.
|
||||
*/
|
||||
public void sendImageViewOn() {
|
||||
Log.w(TAG, "In transition to HdmiControlManager. Will not work.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Send <Give Device Power Status> message.
|
||||
*
|
||||
* @param address logical address of the device to send the message to, such as
|
||||
* {@link HdmiCec#ADDR_TV}.
|
||||
*/
|
||||
public void sendGiveDevicePowerStatus(int address) {
|
||||
Log.w(TAG, "In transition to HdmiControlManager. Will not work.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the TV or attached display is powered on.
|
||||
* <p>
|
||||
* The result of this method is only meaningful on playback devices (where the device
|
||||
* type is {@link HdmiCec#DEVICE_PLAYBACK}).
|
||||
* </p>
|
||||
*
|
||||
* @return true if TV is on; otherwise false.
|
||||
*/
|
||||
public boolean isTvOn() {
|
||||
Log.w(TAG, "In transition to HdmiControlManager. Will not work.");
|
||||
return true;
|
||||
}
|
||||
}
|
@ -1,68 +0,0 @@
|
||||
/*
|
||||
* 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 android.hardware.hdmi;
|
||||
|
||||
import android.os.IBinder;
|
||||
import android.os.RemoteException;
|
||||
|
||||
/**
|
||||
* The HdmiCecManager class is used to provide an HdmiCecClient instance,
|
||||
* get various information on HDMI ports configuration. It is connected to actual hardware
|
||||
* via HdmiCecService.
|
||||
*/
|
||||
public final class HdmiCecManager {
|
||||
private final IHdmiCecService mService;
|
||||
|
||||
/**
|
||||
* @hide - hide this constructor because it has a parameter of type IHdmiCecService,
|
||||
* which is a system private class. The right way to create an instance of this class
|
||||
* is using the factory Context.getSystemService.
|
||||
*/
|
||||
public HdmiCecManager(IHdmiCecService service) {
|
||||
mService = service;
|
||||
}
|
||||
|
||||
/**
|
||||
* Provide the HdmiCecClient instance of the given type. It also registers the listener
|
||||
* for client to get the events coming to the device.
|
||||
*
|
||||
* @param type type of the HDMI-CEC logical device
|
||||
* @param listener listener to be called
|
||||
* @return {@link HdmiCecClient} instance. {@code null} on failure.
|
||||
*/
|
||||
public HdmiCecClient getClient(int type, HdmiCecClient.Listener listener) {
|
||||
return HdmiCecClient.create(mService, null);
|
||||
}
|
||||
|
||||
private IHdmiCecListener getListenerWrapper(final HdmiCecClient.Listener listener) {
|
||||
// TODO: The message/events are not yet forwarded to client since it is not clearly
|
||||
// defined as to how/who to handle them. Revisit it once the decision is
|
||||
// made on what messages will have to reach the clients, what will be
|
||||
// handled by service/manager.
|
||||
return new IHdmiCecListener.Stub() {
|
||||
@Override
|
||||
public void onMessageReceived(HdmiCecMessage message) {
|
||||
// Do nothing.
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCableStatusChanged(boolean connected) {
|
||||
// Do nothing.
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
@ -1,29 +0,0 @@
|
||||
/*
|
||||
* 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 android.hardware.hdmi;
|
||||
|
||||
import android.hardware.hdmi.HdmiCecMessage;
|
||||
|
||||
/**
|
||||
* Interface definition for HdmiCecService to do interprocess communcation.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
oneway interface IHdmiCecListener {
|
||||
void onMessageReceived(in HdmiCecMessage message);
|
||||
void onCableStatusChanged(in boolean connected);
|
||||
}
|
@ -1,40 +0,0 @@
|
||||
/*
|
||||
* 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 android.hardware.hdmi;
|
||||
|
||||
import android.hardware.hdmi.HdmiCecMessage;
|
||||
import android.hardware.hdmi.IHdmiCecListener;
|
||||
import android.os.IBinder;
|
||||
|
||||
/**
|
||||
* Binder interface that components running in the appplication process
|
||||
* will use to enable HDMI-CEC protocol exchange with other devices.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
interface IHdmiCecService {
|
||||
IBinder allocateLogicalDevice(int type, IHdmiCecListener listener);
|
||||
void removeServiceListener(IBinder b, IHdmiCecListener listener);
|
||||
void sendActiveSource(IBinder b);
|
||||
void sendInactiveSource(IBinder b);
|
||||
void sendImageViewOn(IBinder b);
|
||||
void sendTextViewOn(IBinder b);
|
||||
void sendGiveDevicePowerStatus(IBinder b, int address);
|
||||
boolean isTvOn(IBinder b);
|
||||
void sendMessage(IBinder b, in HdmiCecMessage message);
|
||||
}
|
||||
|
@ -1,230 +0,0 @@
|
||||
/*
|
||||
* 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.HdmiCec;
|
||||
import android.hardware.hdmi.HdmiCecMessage;
|
||||
import android.hardware.hdmi.IHdmiCecListener;
|
||||
import android.os.Binder;
|
||||
import android.os.RemoteException;
|
||||
import android.util.Log;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* HdmiCecDevice class represents a CEC logical device characterized
|
||||
* by its device type. It is a superclass of those serving concrete device type.
|
||||
* Currently we're interested in playback(one of sources), display(sink) device type
|
||||
* only. The support for the other types like recorder, audio system will come later.
|
||||
*
|
||||
* <p>A physical device can contain the functions of
|
||||
* more than one logical device, in which case it should create
|
||||
* as many logical devices as necessary.
|
||||
*
|
||||
* <p>Note that if a physical device has multiple instances of a particular
|
||||
* functionality, it should advertize only one instance. For instance, if
|
||||
* a device has multiple tuners, it should only expose one for control
|
||||
* via CEC. In this case, it is up to the device itself to manage multiple tuners.
|
||||
*
|
||||
* <p>The version of HDMI-CEC protocol supported in this class is 1.3a.
|
||||
*
|
||||
* <p>Declared as package-private, accessed by HdmiCecService only.
|
||||
*/
|
||||
abstract class HdmiCecDevice {
|
||||
private static final String TAG = "HdmiCecDevice";
|
||||
|
||||
private final int mType;
|
||||
|
||||
// List of listeners to the message/event coming to the device.
|
||||
private final List<IHdmiCecListener> mListeners = new ArrayList<IHdmiCecListener>();
|
||||
private final Binder mBinder = new Binder();
|
||||
private final HdmiCecService mService;
|
||||
|
||||
private boolean mIsActiveSource;
|
||||
|
||||
/**
|
||||
* Factory method that creates HdmiCecDevice instance to the device type.
|
||||
*/
|
||||
public static HdmiCecDevice create(HdmiCecService service, int type) {
|
||||
if (type == HdmiCec.DEVICE_PLAYBACK) {
|
||||
return new HdmiCecDevicePlayback(service, type);
|
||||
} else if (type == HdmiCec.DEVICE_TV) {
|
||||
return new HdmiCecDeviceTv(service, type);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
public HdmiCecDevice(HdmiCecService service, int type) {
|
||||
mService = service;
|
||||
mType = type;
|
||||
mIsActiveSource = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called right after the class is instantiated. This method can be used to
|
||||
* implement any initialization tasks for the instance.
|
||||
*/
|
||||
abstract public void initialize();
|
||||
|
||||
/**
|
||||
* Return the binder token that identifies this instance.
|
||||
*/
|
||||
public Binder getToken() {
|
||||
return mBinder;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the service instance.
|
||||
*/
|
||||
public HdmiCecService getService() {
|
||||
return mService;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the type of this device.
|
||||
*/
|
||||
public int getType() {
|
||||
return mType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a listener to be invoked when events occur.
|
||||
*
|
||||
* @param listener the listern that will run
|
||||
*/
|
||||
public void addListener(IHdmiCecListener listener) {
|
||||
mListeners.add(listener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the listener that was previously registered.
|
||||
*
|
||||
* @param listener IHdmiCecListener instance to be removed
|
||||
*/
|
||||
public void removeListener(IHdmiCecListener listener) {
|
||||
mListeners.remove(listener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicate if the device has listeners.
|
||||
*
|
||||
* @return true if there are listener instances for this device
|
||||
*/
|
||||
public boolean hasListener() {
|
||||
return !mListeners.isEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle HDMI-CEC message coming to the device by invoking the registered
|
||||
* listeners.
|
||||
*/
|
||||
public void handleMessage(int srcAddress, int dstAddress, int opcode, byte[] params) {
|
||||
if (opcode == HdmiCec.MESSAGE_ACTIVE_SOURCE) {
|
||||
mIsActiveSource = false;
|
||||
}
|
||||
|
||||
if (mListeners.size() == 0) {
|
||||
return;
|
||||
}
|
||||
HdmiCecMessage message = new HdmiCecMessage(srcAddress, dstAddress, opcode, params);
|
||||
for (IHdmiCecListener listener : mListeners) {
|
||||
try {
|
||||
listener.onMessageReceived(message);
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "listener.onMessageReceived failed.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void handleHotplug(boolean connected) {
|
||||
for (IHdmiCecListener listener : mListeners) {
|
||||
try {
|
||||
listener.onCableStatusChanged(connected);
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "listener.onCableStatusChanged failed.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the active status of the device.
|
||||
*
|
||||
* @return true if the device is the active source among the connected
|
||||
* HDMI-CEC-enabled devices; otherwise false.
|
||||
*/
|
||||
public boolean isActiveSource() {
|
||||
return mIsActiveSource;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the active source state of the device.
|
||||
*/
|
||||
public void setIsActiveSource(boolean state) {
|
||||
mIsActiveSource = state;
|
||||
}
|
||||
|
||||
/**
|
||||
* Send <Active Source> command. The default implementation does nothing. Should be
|
||||
* overriden by subclass.
|
||||
*/
|
||||
public void sendActiveSource(int physicalAddress) {
|
||||
logWarning("<Active Source> not valid for the device type: " + mType
|
||||
+ " address:" + physicalAddress);
|
||||
}
|
||||
|
||||
/**
|
||||
* Send <Inactive Source> command. The default implementation does nothing. Should be
|
||||
* overriden by subclass.
|
||||
*/
|
||||
public void sendInactiveSource(int physicalAddress) {
|
||||
logWarning("<Inactive Source> not valid for the device type: " + mType
|
||||
+ " address:" + physicalAddress);
|
||||
}
|
||||
|
||||
/**
|
||||
* Send <Image View On> command. The default implementation does nothing. Should be
|
||||
* overriden by subclass.
|
||||
*/
|
||||
public void sendImageViewOn() {
|
||||
logWarning("<Image View On> not valid for the device type: " + mType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Send <Text View On> command. The default implementation does nothing. Should be
|
||||
* overriden by subclass.
|
||||
*/
|
||||
public void sendTextViewOn() {
|
||||
logWarning("<Text View On> not valid for the device type: " + mType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the connected sink device is in powered-on state. The default implementation
|
||||
* simply returns false. Should be overriden by subclass to report the correct state.
|
||||
*/
|
||||
public boolean isSinkDeviceOn() {
|
||||
logWarning("isSinkDeviceOn() not valid for the device type: " + mType);
|
||||
return false;
|
||||
}
|
||||
|
||||
private void logWarning(String msg) {
|
||||
Log.w(TAG, msg);
|
||||
}
|
||||
}
|
@ -1,129 +0,0 @@
|
||||
/*
|
||||
* 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.HdmiCec;
|
||||
|
||||
/**
|
||||
* Class for the logical device of playback type. Devices such as DVD/Blueray player
|
||||
* that support 'playback' feature are classified as playback device. It is common
|
||||
* that they don't have built-in display, therefore need to talk, stream their contents
|
||||
* to TV/display device which is connected through HDMI cable.
|
||||
*
|
||||
* <p>It closely monitors the status of display device (other devices can be of interest
|
||||
* too, but with much less priority), declares itself as 'active source' to have
|
||||
* display show its output, switch the source state as ordered by display that may be
|
||||
* talking to many other devices connected to it. It also receives commands from display
|
||||
* such as remote control signal, standby, status report, playback mode.
|
||||
*
|
||||
* <p>Declared as package-private, accessed by HdmiCecService only.
|
||||
*/
|
||||
final class HdmiCecDevicePlayback extends HdmiCecDevice {
|
||||
private static final String TAG = "HdmiCecDevicePlayback";
|
||||
|
||||
private int mSinkDevicePowerStatus;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
public HdmiCecDevicePlayback(HdmiCecService service, int type) {
|
||||
super(service, type);
|
||||
mSinkDevicePowerStatus = HdmiCec.POWER_STATUS_UNKNOWN;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initialize() {
|
||||
// Playback device tries to obtain the power status of TV/display when created,
|
||||
// and maintains it all through its lifecycle. CEC spec says there is
|
||||
// a maximum 1 second response time. Therefore it should be kept in mind
|
||||
// that there can be as much amount of period of time the power status
|
||||
// of the display remains unknown after the query is sent out.
|
||||
queryTvPowerStatus();
|
||||
}
|
||||
|
||||
private void queryTvPowerStatus() {
|
||||
getService().sendMessage(getType(), HdmiCec.ADDR_TV,
|
||||
HdmiCec.MESSAGE_GIVE_DEVICE_POWER_STATUS, HdmiCecService.EMPTY_PARAM);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleMessage(int srcAddress, int dstAddress, int opcode, byte[] params) {
|
||||
// Updates power status of display. The cases are:
|
||||
// 1) Response for the queried power status request arrives. Update the status.
|
||||
// 2) Broadcast or direct <Standby> command from TV, which is sent as TV itself is going
|
||||
// into standby mode too.
|
||||
if (opcode == HdmiCec.MESSAGE_REPORT_POWER_STATUS) {
|
||||
mSinkDevicePowerStatus = params[0];
|
||||
} else if (srcAddress == HdmiCec.ADDR_TV) {
|
||||
if (opcode == HdmiCec.MESSAGE_STANDBY) {
|
||||
mSinkDevicePowerStatus = HdmiCec.POWER_STATUS_STANDBY;
|
||||
}
|
||||
}
|
||||
super.handleMessage(srcAddress, dstAddress, opcode, params);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleHotplug(boolean connected) {
|
||||
// If cable get disconnected sink device becomes unreachable. Switch the status
|
||||
// to unknown, and query the status once the cable gets connected back.
|
||||
if (!connected) {
|
||||
mSinkDevicePowerStatus = HdmiCec.POWER_STATUS_UNKNOWN;
|
||||
} else {
|
||||
queryTvPowerStatus();
|
||||
}
|
||||
super.handleHotplug(connected);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSinkDeviceOn() {
|
||||
return mSinkDevicePowerStatus == HdmiCec.POWER_STATUS_ON;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendActiveSource(int physicalAddress) {
|
||||
setIsActiveSource(true);
|
||||
byte[] param = new byte[] {
|
||||
(byte) ((physicalAddress >> 8) & 0xff),
|
||||
(byte) (physicalAddress & 0xff)
|
||||
};
|
||||
getService().sendMessage(getType(), HdmiCec.ADDR_BROADCAST, HdmiCec.MESSAGE_ACTIVE_SOURCE,
|
||||
param);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendInactiveSource(int physicalAddress) {
|
||||
setIsActiveSource(false);
|
||||
byte[] param = new byte[] {
|
||||
(byte) ((physicalAddress >> 8) & 0xff),
|
||||
(byte) (physicalAddress & 0xff)
|
||||
};
|
||||
getService().sendMessage(getType(), HdmiCec.ADDR_TV, HdmiCec.MESSAGE_INACTIVE_SOURCE,
|
||||
param);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendImageViewOn() {
|
||||
getService().sendMessage(getType(), HdmiCec.ADDR_TV, HdmiCec.MESSAGE_IMAGE_VIEW_ON,
|
||||
HdmiCecService.EMPTY_PARAM);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendTextViewOn() {
|
||||
getService().sendMessage(getType(), HdmiCec.ADDR_TV, HdmiCec.MESSAGE_TEXT_VIEW_ON,
|
||||
HdmiCecService.EMPTY_PARAM);
|
||||
}
|
||||
}
|
@ -1,35 +0,0 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* Class for logical device of TV type.
|
||||
*/
|
||||
final class HdmiCecDeviceTv extends HdmiCecDevice {
|
||||
private static final String TAG = "HdmiCecDeviceTv";
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
public HdmiCecDeviceTv(HdmiCecService service, int type) {
|
||||
super(service, type);
|
||||
}
|
||||
|
||||
public void initialize() {
|
||||
// TODO: Do the initialization task for TV device here.
|
||||
}
|
||||
}
|
@ -1,383 +0,0 @@
|
||||
/*
|
||||
* 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.content.Context;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.hardware.hdmi.HdmiCec;
|
||||
import android.hardware.hdmi.HdmiCecMessage;
|
||||
import android.hardware.hdmi.IHdmiCecListener;
|
||||
import android.hardware.hdmi.IHdmiCecService;
|
||||
import android.os.Binder;
|
||||
import android.os.Build;
|
||||
import android.os.IBinder;
|
||||
import android.os.RemoteException;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
import android.util.SparseArray;
|
||||
|
||||
import com.android.server.SystemService;
|
||||
import libcore.util.EmptyArray;
|
||||
|
||||
import java.io.FileDescriptor;
|
||||
import java.io.PrintWriter;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Locale;
|
||||
|
||||
/**
|
||||
* Provides a service for sending and processing HDMI-CEC messages, and providing
|
||||
* the information on HDMI settings in general.
|
||||
*/
|
||||
public final class HdmiCecService extends SystemService {
|
||||
private static final String TAG = "HdmiCecService";
|
||||
|
||||
// Maintains the allocated logical devices. Device type, not logical address,
|
||||
// is used for key as logical address is likely to change over time while
|
||||
// device type is permanent. Type-address mapping is maintained only at
|
||||
// native level.
|
||||
private final SparseArray<HdmiCecDevice> mLogicalDevices = new SparseArray<HdmiCecDevice>();
|
||||
|
||||
// List of IBinder.DeathRecipient instances to handle dead IHdmiCecListener
|
||||
// objects.
|
||||
private final ArrayList<ListenerRecord> mListenerRecords = new ArrayList<ListenerRecord>();
|
||||
|
||||
// Used to synchronize the access to the service.
|
||||
private final Object mLock = new Object();
|
||||
|
||||
// Stores the pointer to the native implementation of the service that
|
||||
// interacts with HAL.
|
||||
private long mNativePtr;
|
||||
|
||||
private static final String PERMISSION = "android.permission.HDMI_CEC";
|
||||
|
||||
static final byte[] EMPTY_PARAM = EmptyArray.BYTE;
|
||||
|
||||
public HdmiCecService(Context context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
private static native long nativeInit(HdmiCecService service);
|
||||
|
||||
@Override
|
||||
public void onStart() {
|
||||
// Stop publishing the service. Soon to be deprecated.
|
||||
Log.w(TAG, "In transition to HdmiControlService. May not work.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Called by native when an HDMI-CEC message arrived. Invokes the registered
|
||||
* listeners to handle the message.
|
||||
*/
|
||||
private void handleMessage(int srcAddress, int dstAddress, int opcode, byte[] params) {
|
||||
// TODO: Messages like <Standby> may not need be passed to listener
|
||||
// but better be handled in service by turning off the screen
|
||||
// or putting the device into suspend mode. List up such messages
|
||||
// and handle them here.
|
||||
synchronized (mLock) {
|
||||
if (dstAddress == HdmiCec.ADDR_BROADCAST) {
|
||||
for (int i = 0; i < mLogicalDevices.size(); ++i) {
|
||||
mLogicalDevices.valueAt(i).handleMessage(srcAddress, dstAddress, opcode,
|
||||
params);
|
||||
}
|
||||
} else {
|
||||
int type = HdmiCec.getTypeFromAddress(dstAddress);
|
||||
HdmiCecDevice device = mLogicalDevices.get(type);
|
||||
if (device == null) {
|
||||
Log.w(TAG, "logical device not found. type: " + type);
|
||||
return;
|
||||
}
|
||||
device.handleMessage(srcAddress, dstAddress, opcode, params);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called by native when internal HDMI hotplug event occurs. Invokes the registered
|
||||
* listeners to handle the event.
|
||||
*/
|
||||
private void handleHotplug(boolean connected) {
|
||||
synchronized(mLock) {
|
||||
for (int i = 0; i < mLogicalDevices.size(); ++i) {
|
||||
mLogicalDevices.valueAt(i).handleHotplug(connected);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called by native when it needs to know whether we have an active source.
|
||||
* The native part uses the return value to respond to <Request Active
|
||||
* Source >.
|
||||
*
|
||||
* @return type of the device which is active; DEVICE_INACTIVE if there is
|
||||
* no active logical device in the system.
|
||||
*/
|
||||
private int getActiveSource() {
|
||||
synchronized(mLock) {
|
||||
for (int i = 0; i < mLogicalDevices.size(); ++i) {
|
||||
if (mLogicalDevices.valueAt(i).isActiveSource()) {
|
||||
return mLogicalDevices.keyAt(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
return HdmiCec.DEVICE_INACTIVE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called by native when a request for the menu language of the device was
|
||||
* received. The native part uses the return value to generate the message
|
||||
* <Set Menu Language> in response. The language should be of
|
||||
* the 3-letter format as defined in ISO/FDIS 639-2. We use system default
|
||||
* locale.
|
||||
*/
|
||||
private String getLanguage(int type) {
|
||||
return Locale.getDefault().getISO3Language();
|
||||
}
|
||||
|
||||
private void enforceAccessPermission() {
|
||||
getContext().enforceCallingOrSelfPermission(PERMISSION, "HdmiCecService");
|
||||
}
|
||||
|
||||
private void dumpInternal(PrintWriter pw) {
|
||||
pw.println("HdmiCecService (dumpsys hdmi_cec)");
|
||||
pw.println("");
|
||||
synchronized (mLock) {
|
||||
for (int i = 0; i < mLogicalDevices.size(); ++i) {
|
||||
HdmiCecDevice device = mLogicalDevices.valueAt(i);
|
||||
pw.println("Device: type=" + device.getType() +
|
||||
", active=" + device.isActiveSource());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Remove logical device of a given type.
|
||||
private void removeLogicalDeviceLocked(int type) {
|
||||
ensureValidType(type);
|
||||
mLogicalDevices.remove(type);
|
||||
nativeRemoveLogicalAddress(mNativePtr, type);
|
||||
}
|
||||
|
||||
private static void ensureValidType(int type) {
|
||||
if (!HdmiCec.isValidType(type)) {
|
||||
throw new IllegalArgumentException("invalid type: " + type);
|
||||
}
|
||||
}
|
||||
|
||||
// Return the logical device identified by the given binder token.
|
||||
private HdmiCecDevice getLogicalDeviceLocked(IBinder b) {
|
||||
for (int i = 0; i < mLogicalDevices.size(); ++i) {
|
||||
HdmiCecDevice device = mLogicalDevices.valueAt(i);
|
||||
if (device.getToken() == b) {
|
||||
return device;
|
||||
}
|
||||
}
|
||||
throw new IllegalArgumentException("Device not found");
|
||||
}
|
||||
|
||||
// package-private. Used by HdmiCecDevice and its subclasses only.
|
||||
void sendMessage(int type, int address, int opcode, byte[] params) {
|
||||
nativeSendMessage(mNativePtr, type, address, opcode, params);
|
||||
}
|
||||
|
||||
private void setOsdNameLocked(String name) {
|
||||
nativeSetOsdName(mNativePtr, name.getBytes(Charset.forName("US-ASCII")));
|
||||
}
|
||||
|
||||
private final class ListenerRecord implements IBinder.DeathRecipient {
|
||||
private final IHdmiCecListener mListener;
|
||||
private final int mType;
|
||||
|
||||
public ListenerRecord(IHdmiCecListener listener, int type) {
|
||||
mListener = listener;
|
||||
mType = type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void binderDied() {
|
||||
synchronized (mLock) {
|
||||
mListenerRecords.remove(this);
|
||||
HdmiCecDevice device = mLogicalDevices.get(mType);
|
||||
if (device != null) {
|
||||
device.removeListener(mListener);
|
||||
if (!device.hasListener()) {
|
||||
removeLogicalDeviceLocked(mType);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private final class BinderService extends IHdmiCecService.Stub {
|
||||
|
||||
@Override
|
||||
public IBinder allocateLogicalDevice(int type, IHdmiCecListener listener) {
|
||||
enforceAccessPermission();
|
||||
ensureValidType(type);
|
||||
if (listener == null) {
|
||||
throw new IllegalArgumentException("listener must not be null");
|
||||
}
|
||||
synchronized (mLock) {
|
||||
HdmiCecDevice device = mLogicalDevices.get(type);
|
||||
if (device != null) {
|
||||
Log.v(TAG, "Logical address already allocated. Adding listener only.");
|
||||
} else {
|
||||
int address = nativeAllocateLogicalAddress(mNativePtr, type);
|
||||
if (!HdmiCec.isValidAddress(address)) {
|
||||
Log.e(TAG, "Logical address was not allocated");
|
||||
return null;
|
||||
} else {
|
||||
device = HdmiCecDevice.create(HdmiCecService.this, type);
|
||||
if (device == null) {
|
||||
Log.e(TAG, "Device type not supported yet.");
|
||||
return null;
|
||||
}
|
||||
device.initialize();
|
||||
mLogicalDevices.put(type, device);
|
||||
}
|
||||
}
|
||||
|
||||
// Adds the listener and its monitor
|
||||
ListenerRecord record = new ListenerRecord(listener, type);
|
||||
try {
|
||||
listener.asBinder().linkToDeath(record, 0);
|
||||
} catch (RemoteException e) {
|
||||
Log.w(TAG, "Listener already died");
|
||||
if (!device.hasListener()) {
|
||||
removeLogicalDeviceLocked(type);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
mListenerRecords.add(record);
|
||||
device.addListener(listener);
|
||||
return device.getToken();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendActiveSource(IBinder b) {
|
||||
enforceAccessPermission();
|
||||
synchronized (mLock) {
|
||||
HdmiCecDevice device = getLogicalDeviceLocked(b);
|
||||
device.sendActiveSource(nativeGetPhysicalAddress(mNativePtr));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendInactiveSource(IBinder b) {
|
||||
enforceAccessPermission();
|
||||
synchronized (mLock) {
|
||||
HdmiCecDevice device = getLogicalDeviceLocked(b);
|
||||
device.sendInactiveSource(nativeGetPhysicalAddress(mNativePtr));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendImageViewOn(IBinder b) {
|
||||
enforceAccessPermission();
|
||||
synchronized (mLock) {
|
||||
HdmiCecDevice device = getLogicalDeviceLocked(b);
|
||||
device.sendImageViewOn();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendTextViewOn(IBinder b) {
|
||||
enforceAccessPermission();
|
||||
synchronized (mLock) {
|
||||
HdmiCecDevice device = getLogicalDeviceLocked(b);
|
||||
device.sendTextViewOn();
|
||||
}
|
||||
}
|
||||
|
||||
public void sendGiveDevicePowerStatus(IBinder b, int address) {
|
||||
enforceAccessPermission();
|
||||
synchronized (mLock) {
|
||||
HdmiCecDevice device = getLogicalDeviceLocked(b);
|
||||
nativeSendMessage(mNativePtr, device.getType(), address,
|
||||
HdmiCec.MESSAGE_GIVE_DEVICE_POWER_STATUS, EMPTY_PARAM);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isTvOn(IBinder b) {
|
||||
enforceAccessPermission();
|
||||
synchronized (mLock) {
|
||||
HdmiCecDevice device = getLogicalDeviceLocked(b);
|
||||
return device.isSinkDeviceOn();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeServiceListener(IBinder b, IHdmiCecListener listener) {
|
||||
enforceAccessPermission();
|
||||
if (listener == null) {
|
||||
throw new IllegalArgumentException("listener must not be null");
|
||||
}
|
||||
synchronized (mLock) {
|
||||
HdmiCecDevice device = getLogicalDeviceLocked(b);
|
||||
for (ListenerRecord record : mListenerRecords) {
|
||||
if (record.mType == device.getType()
|
||||
&& record.mListener.asBinder() == listener.asBinder()) {
|
||||
mListenerRecords.remove(record);
|
||||
device.removeListener(record.mListener);
|
||||
if (!device.hasListener()) {
|
||||
removeLogicalDeviceLocked(record.mType);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendMessage(IBinder b, HdmiCecMessage message) {
|
||||
enforceAccessPermission();
|
||||
if (message == null) {
|
||||
throw new IllegalArgumentException("message must not be null");
|
||||
}
|
||||
synchronized (mLock) {
|
||||
HdmiCecDevice device = getLogicalDeviceLocked(b);
|
||||
nativeSendMessage(mNativePtr, device.getType(), message.getDestination(),
|
||||
message.getOpcode(), message.getParams());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
|
||||
if (getContext().checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
|
||||
!= PackageManager.PERMISSION_GRANTED) {
|
||||
pw.println("Permission denial: can't dump HdmiCecService from pid="
|
||||
+ Binder.getCallingPid() + ", uid=" + Binder.getCallingUid()
|
||||
+ " without permission " + android.Manifest.permission.DUMP);
|
||||
return;
|
||||
}
|
||||
final long ident = Binder.clearCallingIdentity();
|
||||
try {
|
||||
dumpInternal(pw);
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(ident);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static native int nativeAllocateLogicalAddress(long handler, int deviceType);
|
||||
private static native void nativeRemoveLogicalAddress(long handler, int deviceType);
|
||||
private static native void nativeSendMessage(long handler, int deviceType, int destination,
|
||||
int opcode, byte[] params);
|
||||
private static native int nativeGetPhysicalAddress(long handler);
|
||||
private static native void nativeSetOsdName(long handler, byte[] name);
|
||||
}
|
@ -12,7 +12,6 @@ LOCAL_SRC_FILES += \
|
||||
$(LOCAL_REL_DIR)/com_android_server_ConsumerIrService.cpp \
|
||||
$(LOCAL_REL_DIR)/com_android_server_dreams_McuHal.cpp \
|
||||
$(LOCAL_REL_DIR)/com_android_server_hdmi_HdmiCecController.cpp \
|
||||
$(LOCAL_REL_DIR)/com_android_server_hdmi_HdmiCecService.cpp \
|
||||
$(LOCAL_REL_DIR)/com_android_server_hdmi_HdmiMhlController.cpp \
|
||||
$(LOCAL_REL_DIR)/com_android_server_input_InputApplicationHandle.cpp \
|
||||
$(LOCAL_REL_DIR)/com_android_server_input_InputManagerService.cpp \
|
||||
|
@ -1,756 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#define LOG_TAG "HdmiCecJni"
|
||||
|
||||
#define LOG_NDEBUG 1
|
||||
|
||||
#include "ScopedPrimitiveArray.h"
|
||||
|
||||
#include <string>
|
||||
#include <deque>
|
||||
#include <map>
|
||||
|
||||
#include <android_runtime/AndroidRuntime.h>
|
||||
#include <android_runtime/Log.h>
|
||||
#include <hardware/hdmi_cec.h>
|
||||
|
||||
namespace android {
|
||||
|
||||
static struct {
|
||||
jmethodID handleMessage;
|
||||
jmethodID handleHotplug;
|
||||
jmethodID getActiveSource;
|
||||
jmethodID getLanguage;
|
||||
} gHdmiCecServiceClassInfo;
|
||||
|
||||
#ifndef min
|
||||
#define min(a, b) ((a) > (b) ? (b) : (a))
|
||||
#endif
|
||||
|
||||
class HdmiCecHandler {
|
||||
public:
|
||||
enum HdmiCecError {
|
||||
SUCCESS = 0,
|
||||
FAILED = -1
|
||||
};
|
||||
|
||||
// Data type to hold a CEC message or internal event data.
|
||||
typedef union {
|
||||
cec_message_t cec;
|
||||
hotplug_event_t hotplug;
|
||||
} queue_item_t;
|
||||
|
||||
// Entry used for message queue.
|
||||
typedef std::pair<int, const queue_item_t> MessageEntry;
|
||||
|
||||
HdmiCecHandler(hdmi_cec_device_t* device, jobject callbacksObj);
|
||||
|
||||
void initialize();
|
||||
|
||||
// initialize individual logical device.
|
||||
cec_logical_address_t initLogicalDevice(cec_device_type_t type);
|
||||
void releaseLogicalDevice(cec_device_type_t type);
|
||||
|
||||
cec_logical_address_t getLogicalAddress(cec_device_type_t deviceType);
|
||||
uint16_t getPhysicalAddress();
|
||||
cec_device_type_t getDeviceType(cec_logical_address_t addr);
|
||||
void queueMessage(const MessageEntry& message);
|
||||
void queueOutgoingMessage(const cec_message_t& message);
|
||||
void sendReportPhysicalAddress(cec_logical_address_t srcAddr);
|
||||
void sendActiveSource(cec_logical_address_t srcAddr);
|
||||
void sendFeatureAbort(cec_logical_address_t srcAddr, cec_logical_address_t dstAddr,
|
||||
int opcode, int reason);
|
||||
void sendCecVersion(cec_logical_address_t srcAddr, cec_logical_address_t dstAddr,
|
||||
int version);
|
||||
void sendDeviceVendorId(cec_logical_address_t srcAddr, cec_logical_address_t dstAddr);
|
||||
void sendGiveDeviceVendorID(cec_logical_address_t srcAddr, cec_logical_address_t dstAddr);
|
||||
void sendSetOsdName(cec_logical_address_t srcAddr, cec_logical_address_t dstAddr,
|
||||
const char* name, size_t len);
|
||||
void sendSetMenuLanguage(cec_logical_address_t srcAddr, cec_logical_address_t dstAddr);
|
||||
|
||||
void sendCecMessage(const cec_message_t& message);
|
||||
void setOsdName(const char* name, size_t len);
|
||||
|
||||
private:
|
||||
enum {
|
||||
EVENT_TYPE_RX,
|
||||
EVENT_TYPE_TX,
|
||||
EVENT_TYPE_HOTPLUG,
|
||||
EVENT_TYPE_STANDBY
|
||||
};
|
||||
|
||||
/*
|
||||
* logical address pool for each device type.
|
||||
*/
|
||||
static const cec_logical_address_t TV_ADDR_POOL[];
|
||||
static const cec_logical_address_t PLAYBACK_ADDR_POOL[];
|
||||
static const cec_logical_address_t RECORDER_ADDR_POOL[];
|
||||
static const cec_logical_address_t TUNER_ADDR_POOL[];
|
||||
|
||||
static const unsigned int MAX_BUFFER_SIZE = 256;
|
||||
static const uint16_t INVALID_PHYSICAL_ADDRESS = 0xFFFF;
|
||||
|
||||
static void onReceived(const hdmi_event_t* event, void* arg);
|
||||
static void checkAndClearExceptionFromCallback(JNIEnv* env, const char* methodName);
|
||||
|
||||
void updatePhysicalAddress();
|
||||
void updateLogicalAddress();
|
||||
|
||||
// Allocate logical address. The CEC standard recommends that we try to use the address
|
||||
// we have ever used before, in case this is to allocate an address afte the cable is
|
||||
// connected again. If preferredAddr is given a valid one (not CEC_ADDR_UNREGISTERED), then
|
||||
// this method checks if the address is available first. If not, it tries other addresses
|
||||
// int the address pool available for the given type.
|
||||
cec_logical_address_t allocateLogicalAddress(cec_device_type_t type,
|
||||
cec_logical_address_t preferredAddr);
|
||||
|
||||
// Send a CEC ping message. Returns true if successful.
|
||||
bool sendPing(cec_logical_address_t addr);
|
||||
|
||||
// Return the pool of logical addresses that are used for a given device type.
|
||||
// One of the addresses in the pool will be chosen in the allocation logic.
|
||||
bool getLogicalAddressPool(cec_device_type_t type, const cec_logical_address_t** addrPool,
|
||||
size_t* poolSize);
|
||||
|
||||
// Handles the message retrieved from internal message queue. The message can be
|
||||
// for either rx or tx.
|
||||
void dispatchMessage(const MessageEntry& message);
|
||||
void processIncomingMessage(const cec_message_t& msg);
|
||||
|
||||
// Check the message before we pass it up to framework. If true, we proceed.
|
||||
// otherwise do not propagate it.
|
||||
bool precheckMessage(const cec_message_t& msg);
|
||||
|
||||
// Propagate the message up to Java layer.
|
||||
void propagateMessage(const cec_message_t& msg);
|
||||
void propagateHotplug(bool connected);
|
||||
|
||||
// Handles incoming <Request Active Source> message. If one of logical
|
||||
// devices is active, it should reply with <Active Source> message.
|
||||
void handleRequestActiveSource();
|
||||
void handleGiveOsdName(const cec_message_t& msg);
|
||||
void handleGiveDeviceVendorID(const cec_message_t& msg);
|
||||
void handleGetCECVersion(const cec_message_t& msg);
|
||||
void handleGetMenuLanguage(const cec_message_t& msg);
|
||||
|
||||
// Internal thread for message queue handler
|
||||
class HdmiThread : public Thread {
|
||||
public:
|
||||
HdmiThread(HdmiCecHandler* hdmiCecHandler, bool canCallJava) :
|
||||
Thread(canCallJava),
|
||||
mHdmiCecHandler(hdmiCecHandler) {
|
||||
}
|
||||
private:
|
||||
virtual bool threadLoop() {
|
||||
ALOGV("HdmiThread started");
|
||||
AutoMutex _l(mHdmiCecHandler->mMessageQueueLock);
|
||||
mHdmiCecHandler->mMessageQueueCondition.wait(mHdmiCecHandler->mMessageQueueLock);
|
||||
/* Process all messages in the queue */
|
||||
while (mHdmiCecHandler->mMessageQueue.size() > 0) {
|
||||
MessageEntry entry = mHdmiCecHandler->mMessageQueue.front();
|
||||
mHdmiCecHandler->dispatchMessage(entry);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
HdmiCecHandler* mHdmiCecHandler;
|
||||
};
|
||||
|
||||
// device type -> logical address mapping
|
||||
std::map<cec_device_type_t, cec_logical_address_t> mLogicalDevices;
|
||||
|
||||
hdmi_cec_device_t* mDevice;
|
||||
jobject mCallbacksObj;
|
||||
Mutex mLock;
|
||||
Mutex mMessageQueueLock;
|
||||
Condition mMessageQueueCondition;
|
||||
sp<HdmiThread> mMessageQueueHandler;
|
||||
|
||||
std::deque<MessageEntry> mMessageQueue;
|
||||
uint16_t mPhysicalAddress;
|
||||
std::string mOsdName;
|
||||
};
|
||||
|
||||
const cec_logical_address_t HdmiCecHandler::TV_ADDR_POOL[] = {
|
||||
CEC_ADDR_TV,
|
||||
CEC_ADDR_FREE_USE,
|
||||
};
|
||||
|
||||
const cec_logical_address_t HdmiCecHandler::PLAYBACK_ADDR_POOL[] = {
|
||||
CEC_ADDR_PLAYBACK_1,
|
||||
CEC_ADDR_PLAYBACK_2,
|
||||
CEC_ADDR_PLAYBACK_3
|
||||
};
|
||||
|
||||
const cec_logical_address_t HdmiCecHandler::RECORDER_ADDR_POOL[] = {
|
||||
CEC_ADDR_RECORDER_1,
|
||||
CEC_ADDR_RECORDER_2,
|
||||
CEC_ADDR_RECORDER_3
|
||||
};
|
||||
|
||||
const cec_logical_address_t HdmiCecHandler::TUNER_ADDR_POOL[] = {
|
||||
CEC_ADDR_TUNER_1,
|
||||
CEC_ADDR_TUNER_2,
|
||||
CEC_ADDR_TUNER_3,
|
||||
CEC_ADDR_TUNER_4
|
||||
};
|
||||
|
||||
HdmiCecHandler::HdmiCecHandler(hdmi_cec_device_t* device, jobject callbacksObj) :
|
||||
mDevice(device),
|
||||
mCallbacksObj(callbacksObj) {
|
||||
}
|
||||
|
||||
void HdmiCecHandler::initialize() {
|
||||
mDevice->register_event_callback(mDevice, HdmiCecHandler::onReceived, this);
|
||||
mMessageQueueHandler = new HdmiThread(this, true /* canCallJava */);
|
||||
mMessageQueueHandler->run("MessageHandler");
|
||||
updatePhysicalAddress();
|
||||
}
|
||||
|
||||
uint16_t HdmiCecHandler::getPhysicalAddress() {
|
||||
return mPhysicalAddress;
|
||||
}
|
||||
|
||||
cec_logical_address_t HdmiCecHandler::initLogicalDevice(cec_device_type_t type) {
|
||||
cec_logical_address addr = allocateLogicalAddress(type, CEC_ADDR_UNREGISTERED);
|
||||
if (addr != CEC_ADDR_UNREGISTERED && !mDevice->add_logical_address(mDevice, addr)) {
|
||||
mLogicalDevices.insert(std::pair<cec_device_type_t, cec_logical_address_t>(type, addr));
|
||||
|
||||
// Broadcast <Report Physical Address> when a new logical address was allocated to let
|
||||
// other devices discover the new logical device and its logical - physical address
|
||||
// association.
|
||||
sendReportPhysicalAddress(addr);
|
||||
}
|
||||
return addr;
|
||||
}
|
||||
|
||||
void HdmiCecHandler::releaseLogicalDevice(cec_device_type_t type) {
|
||||
std::map<cec_device_type_t, cec_logical_address_t>::iterator it = mLogicalDevices.find(type);
|
||||
if (it != mLogicalDevices.end()) {
|
||||
mLogicalDevices.erase(it);
|
||||
}
|
||||
// TODO: remove the address monitored in HAL as well.
|
||||
}
|
||||
|
||||
cec_logical_address_t HdmiCecHandler::getLogicalAddress(cec_device_type_t type) {
|
||||
std::map<cec_device_type_t, cec_logical_address_t>::iterator it = mLogicalDevices.find(type);
|
||||
if (it != mLogicalDevices.end()) {
|
||||
return it->second;
|
||||
}
|
||||
return CEC_ADDR_UNREGISTERED;
|
||||
}
|
||||
|
||||
cec_device_type_t HdmiCecHandler::getDeviceType(cec_logical_address_t addr) {
|
||||
std::map<cec_device_type_t, cec_logical_address_t>::iterator it = mLogicalDevices.begin();
|
||||
for (; it != mLogicalDevices.end(); ++it) {
|
||||
if (it->second == addr) {
|
||||
return it->first;
|
||||
}
|
||||
}
|
||||
return CEC_DEVICE_INACTIVE;
|
||||
}
|
||||
|
||||
void HdmiCecHandler::queueMessage(const MessageEntry& entry) {
|
||||
AutoMutex _l(mMessageQueueLock);
|
||||
if (mMessageQueue.size() <= MAX_BUFFER_SIZE) {
|
||||
mMessageQueue.push_back(entry);
|
||||
mMessageQueueCondition.signal();
|
||||
} else {
|
||||
ALOGW("Queue is full! Message dropped.");
|
||||
}
|
||||
}
|
||||
|
||||
void HdmiCecHandler::queueOutgoingMessage(const cec_message_t& message) {
|
||||
queue_item_t item;
|
||||
item.cec = message;
|
||||
MessageEntry entry = std::make_pair(EVENT_TYPE_TX, item);
|
||||
queueMessage(entry);
|
||||
}
|
||||
|
||||
void HdmiCecHandler::sendReportPhysicalAddress(cec_logical_address_t addr) {
|
||||
if (mPhysicalAddress == INVALID_PHYSICAL_ADDRESS) {
|
||||
ALOGE("Invalid physical address.");
|
||||
return;
|
||||
}
|
||||
cec_device_type_t deviceType = getDeviceType(addr);
|
||||
if (deviceType == CEC_DEVICE_INACTIVE) {
|
||||
ALOGE("Invalid logical address: %d", addr);
|
||||
return;
|
||||
}
|
||||
|
||||
cec_message_t msg;
|
||||
msg.initiator = addr;
|
||||
msg.destination = CEC_ADDR_BROADCAST;
|
||||
msg.length = 4;
|
||||
msg.body[0] = CEC_MESSAGE_REPORT_PHYSICAL_ADDRESS;
|
||||
msg.body[1] = (mPhysicalAddress >> 8) & 0xff;
|
||||
msg.body[2] = mPhysicalAddress & 0xff;
|
||||
msg.body[3] = deviceType;
|
||||
queueOutgoingMessage(msg);
|
||||
}
|
||||
|
||||
void HdmiCecHandler::sendActiveSource(cec_logical_address_t srcAddr) {
|
||||
if (mPhysicalAddress == INVALID_PHYSICAL_ADDRESS) {
|
||||
ALOGE("Error getting physical address.");
|
||||
return;
|
||||
}
|
||||
cec_message_t msg;
|
||||
msg.initiator = srcAddr;
|
||||
msg.destination = CEC_ADDR_BROADCAST;
|
||||
msg.length = 3;
|
||||
msg.body[0] = CEC_MESSAGE_ACTIVE_SOURCE;
|
||||
msg.body[1] = (mPhysicalAddress >> 8) & 0xff;
|
||||
msg.body[2] = mPhysicalAddress & 0xff;
|
||||
queueOutgoingMessage(msg);
|
||||
}
|
||||
|
||||
void HdmiCecHandler::sendFeatureAbort(cec_logical_address_t srcAddr,
|
||||
cec_logical_address_t dstAddr, int opcode, int reason) {
|
||||
cec_message_t msg;
|
||||
msg.initiator = srcAddr;
|
||||
msg.destination = dstAddr;
|
||||
msg.length = 3;
|
||||
msg.body[0] = CEC_MESSAGE_FEATURE_ABORT;
|
||||
msg.body[1] = opcode;
|
||||
msg.body[2] = reason;
|
||||
queueOutgoingMessage(msg);
|
||||
}
|
||||
|
||||
void HdmiCecHandler::sendCecVersion(cec_logical_address_t srcAddr,
|
||||
cec_logical_address_t dstAddr, int version) {
|
||||
cec_message_t msg;
|
||||
msg.initiator = srcAddr;
|
||||
msg.destination = dstAddr;
|
||||
msg.length = 2;
|
||||
msg.body[0] = CEC_MESSAGE_CEC_VERSION;
|
||||
msg.body[1] = version;
|
||||
queueOutgoingMessage(msg);
|
||||
}
|
||||
|
||||
void HdmiCecHandler::sendGiveDeviceVendorID(cec_logical_address_t srcAddr,
|
||||
cec_logical_address_t dstAddr) {
|
||||
cec_message_t msg;
|
||||
msg.initiator = srcAddr;
|
||||
msg.destination = dstAddr;
|
||||
msg.length = 1;
|
||||
msg.body[0] = CEC_MESSAGE_GIVE_DEVICE_VENDOR_ID;
|
||||
queueOutgoingMessage(msg);
|
||||
}
|
||||
|
||||
void HdmiCecHandler::sendDeviceVendorId(cec_logical_address_t srcAddr,
|
||||
cec_logical_address_t dstAddr) {
|
||||
cec_message_t msg;
|
||||
msg.initiator = srcAddr;
|
||||
msg.destination = dstAddr;
|
||||
msg.length = 4;
|
||||
msg.body[0] = CEC_MESSAGE_DEVICE_VENDOR_ID;
|
||||
uint32_t vendor_id;
|
||||
mDevice->get_vendor_id(mDevice, &vendor_id);
|
||||
msg.body[1] = (vendor_id >> 16) & 0xff;
|
||||
msg.body[2] = (vendor_id >> 8) & 0xff;
|
||||
msg.body[3] = vendor_id & 0xff;
|
||||
queueOutgoingMessage(msg);
|
||||
}
|
||||
|
||||
void HdmiCecHandler::sendSetOsdName(cec_logical_address_t srcAddr, cec_logical_address_t dstAddr,
|
||||
const char* name, size_t len) {
|
||||
cec_message_t msg;
|
||||
msg.initiator = srcAddr;
|
||||
msg.destination = dstAddr;
|
||||
msg.body[0] = CEC_MESSAGE_SET_OSD_NAME;
|
||||
msg.length = min(len + 1, CEC_MESSAGE_BODY_MAX_LENGTH);
|
||||
std::memcpy(msg.body + 1, name, msg.length - 1);
|
||||
queueOutgoingMessage(msg);
|
||||
}
|
||||
|
||||
void HdmiCecHandler::sendSetMenuLanguage(cec_logical_address_t srcAddr,
|
||||
cec_logical_address_t dstAddr) {
|
||||
char lang[4]; // buffer for 3-letter language code
|
||||
JNIEnv* env = AndroidRuntime::getJNIEnv();
|
||||
jstring res = (jstring) env->CallObjectMethod(mCallbacksObj,
|
||||
gHdmiCecServiceClassInfo.getLanguage,
|
||||
getDeviceType(srcAddr));
|
||||
const char *clang = env->GetStringUTFChars(res, NULL);
|
||||
strlcpy(lang, clang, sizeof(lang));
|
||||
env->ReleaseStringUTFChars(res, clang);
|
||||
|
||||
cec_message_t msg;
|
||||
msg.initiator = srcAddr;
|
||||
msg.destination = dstAddr;
|
||||
msg.length = 4; // opcode (1) + language code (3)
|
||||
msg.body[0] = CEC_MESSAGE_SET_MENU_LANGUAGE;
|
||||
std::memcpy(msg.body + 1, lang, 3);
|
||||
queueOutgoingMessage(msg);
|
||||
checkAndClearExceptionFromCallback(env, __FUNCTION__);
|
||||
}
|
||||
|
||||
void HdmiCecHandler::sendCecMessage(const cec_message_t& message) {
|
||||
AutoMutex _l(mLock);
|
||||
ALOGV("sendCecMessage");
|
||||
mDevice->send_message(mDevice, &message);
|
||||
}
|
||||
|
||||
void HdmiCecHandler::setOsdName(const char* name, size_t len) {
|
||||
mOsdName.assign(name, min(len, CEC_MESSAGE_BODY_MAX_LENGTH - 1));
|
||||
}
|
||||
|
||||
// static
|
||||
void HdmiCecHandler::onReceived(const hdmi_event_t* event, void* arg) {
|
||||
HdmiCecHandler* handler = static_cast<HdmiCecHandler*>(arg);
|
||||
if (handler == NULL) {
|
||||
return;
|
||||
}
|
||||
queue_item_t item;
|
||||
if (event->type == HDMI_EVENT_CEC_MESSAGE) {
|
||||
item.cec = event->cec;
|
||||
MessageEntry entry = std::make_pair<int, const queue_item_t>(EVENT_TYPE_RX, item);
|
||||
handler->queueMessage(entry);
|
||||
} else if (event->type == HDMI_EVENT_HOT_PLUG) {
|
||||
item.hotplug = event->hotplug;
|
||||
MessageEntry entry = std::make_pair<int, const queue_item_t>(EVENT_TYPE_HOTPLUG, item);
|
||||
handler->queueMessage(entry);
|
||||
}
|
||||
}
|
||||
|
||||
// static
|
||||
void HdmiCecHandler::checkAndClearExceptionFromCallback(JNIEnv* env, const char* methodName) {
|
||||
if (env->ExceptionCheck()) {
|
||||
ALOGE("An exception was thrown by callback '%s'.", methodName);
|
||||
LOGE_EX(env);
|
||||
env->ExceptionClear();
|
||||
}
|
||||
}
|
||||
|
||||
void HdmiCecHandler::updatePhysicalAddress() {
|
||||
uint16_t addr;
|
||||
if (!mDevice->get_physical_address(mDevice, &addr)) {
|
||||
mPhysicalAddress = addr;
|
||||
} else {
|
||||
mPhysicalAddress = INVALID_PHYSICAL_ADDRESS;
|
||||
}
|
||||
}
|
||||
|
||||
void HdmiCecHandler::updateLogicalAddress() {
|
||||
mDevice->clear_logical_address(mDevice);
|
||||
std::map<cec_device_type_t, cec_logical_address_t>::iterator it = mLogicalDevices.begin();
|
||||
for (; it != mLogicalDevices.end(); ++it) {
|
||||
cec_logical_address_t addr;
|
||||
cec_logical_address_t preferredAddr = it->second;
|
||||
cec_device_type_t deviceType = it->first;
|
||||
addr = allocateLogicalAddress(deviceType, preferredAddr);
|
||||
if (!mDevice->add_logical_address(mDevice, addr)) {
|
||||
it->second = addr;
|
||||
} else {
|
||||
it->second = CEC_ADDR_UNREGISTERED;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
cec_logical_address_t HdmiCecHandler::allocateLogicalAddress(cec_device_type_t type,
|
||||
cec_logical_address_t preferredAddr) {
|
||||
const cec_logical_address_t* addrPool;
|
||||
size_t poolSize;
|
||||
if (getLogicalAddressPool(type, &addrPool, &poolSize) < 0) {
|
||||
return CEC_ADDR_UNREGISTERED;
|
||||
}
|
||||
unsigned start = 0;
|
||||
|
||||
// Find the index of preferred address in the pool. If not found, the start
|
||||
// position will be 0. This happens when the passed preferredAddr is set to
|
||||
// CEC_ADDR_UNREGISTERED, meaning that no preferred address is given.
|
||||
for (unsigned i = 0; i < poolSize; i++) {
|
||||
if (addrPool[i] == preferredAddr) {
|
||||
start = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
for (unsigned i = 0; i < poolSize; i++) {
|
||||
cec_logical_address_t addr = addrPool[(start + i) % poolSize];
|
||||
if (!sendPing(addr)) {
|
||||
// Failure in pinging means the address is available, not taken by any device.
|
||||
ALOGV("Logical Address Allocation success: %d", addr);
|
||||
return addr;
|
||||
}
|
||||
}
|
||||
ALOGE("Logical Address Allocation failed");
|
||||
return CEC_ADDR_UNREGISTERED;
|
||||
}
|
||||
|
||||
bool HdmiCecHandler::sendPing(cec_logical_address addr) {
|
||||
cec_message_t msg;
|
||||
msg.initiator = msg.destination = addr;
|
||||
msg.length = 0;
|
||||
return !mDevice->send_message(mDevice, &msg);
|
||||
|
||||
}
|
||||
|
||||
#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
|
||||
|
||||
bool HdmiCecHandler::getLogicalAddressPool(cec_device_type_t deviceType,
|
||||
const cec_logical_address_t** addrPool, size_t* poolSize) {
|
||||
switch (deviceType) {
|
||||
case CEC_DEVICE_TV:
|
||||
*addrPool = TV_ADDR_POOL;
|
||||
*poolSize = ARRAY_SIZE(TV_ADDR_POOL);
|
||||
break;
|
||||
case CEC_DEVICE_RECORDER:
|
||||
*addrPool = RECORDER_ADDR_POOL;
|
||||
*poolSize = ARRAY_SIZE(RECORDER_ADDR_POOL);
|
||||
break;
|
||||
case CEC_DEVICE_TUNER:
|
||||
*addrPool = TUNER_ADDR_POOL;
|
||||
*poolSize = ARRAY_SIZE(TUNER_ADDR_POOL);
|
||||
break;
|
||||
case CEC_DEVICE_PLAYBACK:
|
||||
*addrPool = PLAYBACK_ADDR_POOL;
|
||||
*poolSize = ARRAY_SIZE(PLAYBACK_ADDR_POOL);
|
||||
break;
|
||||
default:
|
||||
ALOGE("Unsupported device type: %d", deviceType);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
#undef ARRAY_SIZE
|
||||
|
||||
void HdmiCecHandler::dispatchMessage(const MessageEntry& entry) {
|
||||
int type = entry.first;
|
||||
mMessageQueueLock.unlock();
|
||||
if (type == EVENT_TYPE_RX) {
|
||||
mMessageQueue.pop_front();
|
||||
processIncomingMessage(entry.second.cec);
|
||||
} else if (type == EVENT_TYPE_TX) {
|
||||
sendCecMessage(entry.second.cec);
|
||||
mMessageQueue.pop_front();
|
||||
} else if (type == EVENT_TYPE_HOTPLUG) {
|
||||
mMessageQueue.pop_front();
|
||||
bool connected = entry.second.hotplug.connected;
|
||||
if (connected) {
|
||||
updatePhysicalAddress();
|
||||
updateLogicalAddress();
|
||||
}
|
||||
propagateHotplug(connected);
|
||||
}
|
||||
mMessageQueueLock.lock();
|
||||
}
|
||||
|
||||
void HdmiCecHandler::processIncomingMessage(const cec_message_t& msg) {
|
||||
int opcode = msg.body[0];
|
||||
if (opcode == CEC_MESSAGE_GIVE_PHYSICAL_ADDRESS) {
|
||||
sendReportPhysicalAddress(msg.destination);
|
||||
} else if (opcode == CEC_MESSAGE_REQUEST_ACTIVE_SOURCE) {
|
||||
handleRequestActiveSource();
|
||||
} else if (opcode == CEC_MESSAGE_GIVE_OSD_NAME) {
|
||||
handleGiveOsdName(msg);
|
||||
} else if (opcode == CEC_MESSAGE_GIVE_DEVICE_VENDOR_ID) {
|
||||
handleGiveDeviceVendorID(msg);
|
||||
} else if (opcode == CEC_MESSAGE_GET_CEC_VERSION) {
|
||||
handleGetCECVersion(msg);
|
||||
} else if (opcode == CEC_MESSAGE_GET_MENU_LANGUAGE) {
|
||||
handleGetMenuLanguage(msg);
|
||||
} else if (opcode == CEC_MESSAGE_ABORT) {
|
||||
// Compliance testing requires that abort message be responded with feature abort.
|
||||
sendFeatureAbort(msg.destination, msg.initiator, msg.body[0], ABORT_REFUSED);
|
||||
} else {
|
||||
if (precheckMessage(msg)) {
|
||||
propagateMessage(msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool HdmiCecHandler::precheckMessage(const cec_message_t& msg) {
|
||||
// Check if this is the broadcast message coming to itself, which need not be passed
|
||||
// back to framework. This happens because CEC spec specifies that a physical device
|
||||
// may host multiple logical devices. A broadcast message sent by one of them therefore
|
||||
// should be able to reach the others by the loopback mechanism.
|
||||
//
|
||||
// Currently we don't deal with multiple logical devices, so this is not necessary.
|
||||
// It should be revisited once we support hosting multiple logical devices.
|
||||
int opcode = msg.body[0];
|
||||
if (msg.destination == CEC_ADDR_BROADCAST &&
|
||||
(opcode == CEC_MESSAGE_ACTIVE_SOURCE ||
|
||||
opcode == CEC_MESSAGE_SET_STREAM_PATH ||
|
||||
opcode == CEC_MESSAGE_INACTIVE_SOURCE)) {
|
||||
uint16_t senderAddr = (msg.body[1] << 8) + msg.body[2];
|
||||
if (senderAddr == mPhysicalAddress) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void HdmiCecHandler::propagateMessage(const cec_message_t& msg) {
|
||||
int paramLen = msg.length - 1;
|
||||
jint srcAddr = msg.initiator;
|
||||
jint dstAddr = msg.destination;
|
||||
jint opcode = msg.body[0];
|
||||
JNIEnv* env = AndroidRuntime::getJNIEnv();
|
||||
jbyteArray params = env->NewByteArray(paramLen);
|
||||
const jbyte* body = reinterpret_cast<const jbyte *>(msg.body + 1);
|
||||
if (paramLen > 0) {
|
||||
env->SetByteArrayRegion(params, 0, paramLen, body);
|
||||
}
|
||||
env->CallVoidMethod(mCallbacksObj,
|
||||
gHdmiCecServiceClassInfo.handleMessage,
|
||||
srcAddr, dstAddr, opcode, params);
|
||||
env->DeleteLocalRef(params);
|
||||
checkAndClearExceptionFromCallback(env, __FUNCTION__);
|
||||
}
|
||||
|
||||
void HdmiCecHandler::propagateHotplug(bool connected) {
|
||||
JNIEnv* env = AndroidRuntime::getJNIEnv();
|
||||
env->CallVoidMethod(mCallbacksObj,
|
||||
gHdmiCecServiceClassInfo.handleHotplug,
|
||||
connected);
|
||||
checkAndClearExceptionFromCallback(env, __FUNCTION__);
|
||||
}
|
||||
|
||||
|
||||
void HdmiCecHandler::handleRequestActiveSource() {
|
||||
JNIEnv* env = AndroidRuntime::getJNIEnv();
|
||||
jint activeDeviceType = env->CallIntMethod(mCallbacksObj,
|
||||
gHdmiCecServiceClassInfo.getActiveSource);
|
||||
if (activeDeviceType != CEC_DEVICE_INACTIVE) {
|
||||
sendActiveSource(getLogicalAddress(static_cast<cec_device_type_t>(activeDeviceType)));
|
||||
}
|
||||
checkAndClearExceptionFromCallback(env, __FUNCTION__);
|
||||
}
|
||||
|
||||
void HdmiCecHandler::handleGiveOsdName(const cec_message_t& msg) {
|
||||
if (!mOsdName.empty()) {
|
||||
sendSetOsdName(msg.destination, msg.initiator, mOsdName.c_str(), mOsdName.length());
|
||||
}
|
||||
}
|
||||
|
||||
void HdmiCecHandler::handleGiveDeviceVendorID(const cec_message_t& msg) {
|
||||
sendDeviceVendorId(msg.destination, msg.initiator);
|
||||
}
|
||||
|
||||
void HdmiCecHandler::handleGetCECVersion(const cec_message_t& msg) {
|
||||
int version;
|
||||
mDevice->get_version(mDevice, &version);
|
||||
sendCecVersion(msg.destination, msg.initiator, version);
|
||||
}
|
||||
|
||||
void HdmiCecHandler::handleGetMenuLanguage(const cec_message_t& msg) {
|
||||
sendSetMenuLanguage(msg.destination, msg.initiator);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
#define GET_METHOD_ID(var, clazz, methodName, methodDescriptor) \
|
||||
var = env->GetMethodID(clazz, methodName, methodDescriptor); \
|
||||
LOG_FATAL_IF(! var, "Unable to find method " methodName);
|
||||
|
||||
static jlong nativeInit(JNIEnv* env, jclass clazz, jobject callbacksObj) {
|
||||
int err;
|
||||
hw_module_t* module;
|
||||
err = hw_get_module(HDMI_CEC_HARDWARE_MODULE_ID, const_cast<const hw_module_t **>(&module));
|
||||
if (err != 0) {
|
||||
ALOGE("Error acquiring hardware module: %d", err);
|
||||
return 0;
|
||||
}
|
||||
hw_device_t* device;
|
||||
err = module->methods->open(module, HDMI_CEC_HARDWARE_INTERFACE, &device);
|
||||
if (err != 0) {
|
||||
ALOGE("Error opening hardware module: %d", err);
|
||||
return 0;
|
||||
}
|
||||
HdmiCecHandler *handler = new HdmiCecHandler(reinterpret_cast<hdmi_cec_device *>(device),
|
||||
env->NewGlobalRef(callbacksObj));
|
||||
handler->initialize();
|
||||
|
||||
GET_METHOD_ID(gHdmiCecServiceClassInfo.handleMessage, clazz,
|
||||
"handleMessage", "(III[B)V");
|
||||
GET_METHOD_ID(gHdmiCecServiceClassInfo.handleHotplug, clazz,
|
||||
"handleHotplug", "(Z)V");
|
||||
GET_METHOD_ID(gHdmiCecServiceClassInfo.getActiveSource, clazz,
|
||||
"getActiveSource", "()I");
|
||||
GET_METHOD_ID(gHdmiCecServiceClassInfo.getLanguage, clazz,
|
||||
"getLanguage", "(I)Ljava/lang/String;");
|
||||
|
||||
return reinterpret_cast<jlong>(handler);
|
||||
}
|
||||
|
||||
static void nativeSendMessage(JNIEnv* env, jclass clazz, jlong handlerPtr, jint deviceType,
|
||||
jint dstAddr, jint opcode, jbyteArray params) {
|
||||
HdmiCecHandler *handler = reinterpret_cast<HdmiCecHandler *>(handlerPtr);
|
||||
cec_logical_address_t srcAddr = handler->getLogicalAddress(
|
||||
static_cast<cec_device_type_t>(deviceType));
|
||||
jsize len = env->GetArrayLength(params);
|
||||
ScopedByteArrayRO paramsPtr(env, params);
|
||||
cec_message_t message;
|
||||
message.initiator = srcAddr;
|
||||
message.destination = static_cast<cec_logical_address_t>(dstAddr);
|
||||
message.length = min(len + 1, CEC_MESSAGE_BODY_MAX_LENGTH);
|
||||
message.body[0] = opcode;
|
||||
std::memcpy(message.body + 1, paramsPtr.get(), message.length - 1);
|
||||
handler->sendCecMessage(message);
|
||||
}
|
||||
|
||||
static jint nativeAllocateLogicalAddress(JNIEnv* env, jclass clazz, jlong handlerPtr,
|
||||
jint deviceType) {
|
||||
HdmiCecHandler *handler = reinterpret_cast<HdmiCecHandler *>(handlerPtr);
|
||||
return handler->initLogicalDevice(static_cast<cec_device_type_t>(deviceType));
|
||||
}
|
||||
|
||||
static void nativeRemoveLogicalAddress(JNIEnv* env, jclass clazz, jlong handlerPtr,
|
||||
jint deviceType) {
|
||||
HdmiCecHandler *handler = reinterpret_cast<HdmiCecHandler *>(handlerPtr);
|
||||
return handler->releaseLogicalDevice(static_cast<cec_device_type_t>(deviceType));
|
||||
}
|
||||
|
||||
static jint nativeGetPhysicalAddress(JNIEnv* env, jclass clazz, jlong handlerPtr) {
|
||||
HdmiCecHandler *handler = reinterpret_cast<HdmiCecHandler *>(handlerPtr);
|
||||
return handler->getPhysicalAddress();
|
||||
}
|
||||
|
||||
static void nativeSetOsdName(JNIEnv* env, jclass clazz, jlong handlerPtr, jbyteArray name) {
|
||||
HdmiCecHandler *handler = reinterpret_cast<HdmiCecHandler *>(handlerPtr);
|
||||
jsize len = env->GetArrayLength(name);
|
||||
if (len > 0) {
|
||||
ScopedByteArrayRO namePtr(env, name);
|
||||
handler->setOsdName(reinterpret_cast<const char *>(namePtr.get()), len);
|
||||
}
|
||||
}
|
||||
|
||||
static JNINativeMethod sMethods[] = {
|
||||
/* name, signature, funcPtr */
|
||||
{ "nativeInit", "(Lcom/android/server/hdmi/HdmiCecService;)J",
|
||||
(void *)nativeInit },
|
||||
{ "nativeSendMessage", "(JIII[B)V",
|
||||
(void *)nativeSendMessage },
|
||||
{ "nativeAllocateLogicalAddress", "(JI)I",
|
||||
(void *)nativeAllocateLogicalAddress },
|
||||
{ "nativeRemoveLogicalAddress", "(JI)V",
|
||||
(void *)nativeRemoveLogicalAddress },
|
||||
{ "nativeGetPhysicalAddress", "(J)I",
|
||||
(void *)nativeGetPhysicalAddress },
|
||||
{ "nativeSetOsdName", "(J[B)V",
|
||||
(void *)nativeSetOsdName },
|
||||
};
|
||||
|
||||
#define CLASS_PATH "com/android/server/hdmi/HdmiCecService"
|
||||
|
||||
int register_android_server_hdmi_HdmiCecService(JNIEnv* env) {
|
||||
int res = jniRegisterNativeMethods(env, CLASS_PATH, sMethods, NELEM(sMethods));
|
||||
LOG_FATAL_IF(res < 0, "Unable to register native methods.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
} /* namespace android */
|
@ -39,7 +39,6 @@ int register_android_server_location_FlpHardwareProvider(JNIEnv* env);
|
||||
int register_android_server_connectivity_Vpn(JNIEnv* env);
|
||||
int register_android_server_dreams_McuHal(JNIEnv* env);
|
||||
int register_android_server_hdmi_HdmiCecController(JNIEnv* env);
|
||||
int register_android_server_hdmi_HdmiCecService(JNIEnv* env);
|
||||
int register_android_server_hdmi_HdmiMhlController(JNIEnv* env);
|
||||
int register_android_server_tv_TvInputHal(JNIEnv* env);
|
||||
};
|
||||
@ -76,8 +75,6 @@ extern "C" jint JNI_OnLoad(JavaVM* vm, void* reserved)
|
||||
register_android_server_dreams_McuHal(env);
|
||||
register_android_server_BatteryStatsService(env);
|
||||
register_android_server_hdmi_HdmiCecController(env);
|
||||
// TODO: remove this once replaces HdmiCecService with HdmiControlService.
|
||||
register_android_server_hdmi_HdmiCecService(env);
|
||||
register_android_server_hdmi_HdmiMhlController(env);
|
||||
register_android_server_tv_TvInputHal(env);
|
||||
|
||||
|
@ -129,8 +129,6 @@ public final class SystemServer {
|
||||
"com.android.server.wifi.passpoint.PasspointService";
|
||||
private static final String WIFI_P2P_SERVICE_CLASS =
|
||||
"com.android.server.wifi.p2p.WifiP2pService";
|
||||
private static final String HDMI_CEC_SERVICE_CLASS =
|
||||
"com.android.server.hdmi.HdmiCecService";
|
||||
private static final String ETHERNET_SERVICE_CLASS =
|
||||
"com.android.server.ethernet.EthernetService";
|
||||
private static final String TASK_SERVICE_CLASS =
|
||||
@ -953,12 +951,6 @@ public final class SystemServer {
|
||||
reportWtf("starting MediaSessionService", e);
|
||||
}
|
||||
|
||||
try {
|
||||
mSystemServiceManager.startService(HDMI_CEC_SERVICE_CLASS);
|
||||
} catch (Throwable e) {
|
||||
reportWtf("starting HdmiCec Service", e);
|
||||
}
|
||||
|
||||
try {
|
||||
mSystemServiceManager.startService(HdmiControlService.class);
|
||||
} catch (Throwable e) {
|
||||
|
Reference in New Issue
Block a user