am 1dc7352e: am d0f94173: Merge "TIF: Extend multiple TV input per service for HDMI logical devices" into lmp-dev

* commit '1dc7352eacde37dac5459f0bc82c868e9548b521':
  TIF: Extend multiple TV input per service for HDMI logical devices
This commit is contained in:
Ji-Hwan Lee
2014-07-21 12:40:10 +00:00
committed by Android Git Automerger
7 changed files with 275 additions and 121 deletions

View File

@@ -64,11 +64,6 @@ interface ITvInputManager {
// For TV input hardware binding
List<TvInputHardwareInfo> getHardwareList();
/*
* All TvInputServices which want to use hardware must call this method on
* BOOT_COMPLETE.
*/
void registerTvInputInfo(in TvInputInfo info, int deviceId);
ITvInputHardware acquireTvInputHardware(int deviceId, in ITvInputHardwareCallback callback,
in TvInputInfo info, int userId);
void releaseTvInputHardware(int deviceId, in ITvInputHardware hardware, int userId);

View File

@@ -16,6 +16,7 @@
package android.media.tv;
import android.hardware.hdmi.HdmiCecDeviceInfo;
import android.media.tv.ITvInputServiceCallback;
import android.media.tv.ITvInputSessionCallback;
import android.media.tv.TvInputHardwareInfo;
@@ -32,6 +33,8 @@ oneway interface ITvInputService {
in String inputId);
// For hardware TvInputService
void notifyHardwareAdded(in TvInputHardwareInfo info);
void notifyHardwareRemoved(int deviceId);
void notifyHardwareAdded(in TvInputHardwareInfo hardwareInfo);
void notifyHardwareRemoved(in TvInputHardwareInfo hardwareInfo);
void notifyHdmiCecDeviceAdded(in HdmiCecDeviceInfo cecDeviceInfo);
void notifyHdmiCecDeviceRemoved(in HdmiCecDeviceInfo cecDeviceInfo);
}

View File

@@ -24,6 +24,7 @@ import android.media.tv.TvInputInfo;
* @hide
*/
oneway interface ITvInputServiceCallback {
void addTvInput(in TvInputInfo inputInfo);
void addHardwareTvInput(in int deviceID, in TvInputInfo inputInfo);
void addHdmiCecTvInput(in int logicalAddress, in TvInputInfo inputInfo);
void removeTvInput(in String inputId);
}

View File

@@ -122,7 +122,8 @@ public final class TvInputInfo implements Parcelable {
public static TvInputInfo createTvInputInfo(Context context, ResolveInfo service)
throws XmlPullParserException, IOException {
return createTvInputInfo(context, service, generateInputIdForComponentName(
new ComponentName(service.serviceInfo.packageName, service.serviceInfo.name)));
new ComponentName(service.serviceInfo.packageName, service.serviceInfo.name)),
null);
}
/**
@@ -134,10 +135,10 @@ public final class TvInputInfo implements Parcelable {
* @hide
*/
public static TvInputInfo createTvInputInfo(Context context, ResolveInfo service,
HdmiCecDeviceInfo cecInfo) throws XmlPullParserException, IOException {
HdmiCecDeviceInfo cecInfo, String parentId) throws XmlPullParserException, IOException {
return createTvInputInfo(context, service, generateInputIdForHdmiCec(
new ComponentName(service.serviceInfo.packageName, service.serviceInfo.name),
cecInfo));
cecInfo), parentId);
}
/**
@@ -152,11 +153,11 @@ public final class TvInputInfo implements Parcelable {
TvInputHardwareInfo hardwareInfo) throws XmlPullParserException, IOException {
return createTvInputInfo(context, service, generateInputIdForHardware(
new ComponentName(service.serviceInfo.packageName, service.serviceInfo.name),
hardwareInfo));
hardwareInfo), null);
}
private static TvInputInfo createTvInputInfo(Context context, ResolveInfo service,
String id) throws XmlPullParserException, IOException {
String id, String parentId) throws XmlPullParserException, IOException {
ServiceInfo si = service.serviceInfo;
PackageManager pm = context.getPackageManager();
XmlResourceParser parser = null;
@@ -181,7 +182,7 @@ public final class TvInputInfo implements Parcelable {
"Meta-data does not start with tv-input-service tag in " + si.name);
}
TvInputInfo input = new TvInputInfo(context, service, id, null);
TvInputInfo input = new TvInputInfo(service, id, parentId);
TypedArray sa = res.obtainAttributes(attrs,
com.android.internal.R.styleable.TvInputService);
input.mSetupActivity = sa.getString(
@@ -222,9 +223,8 @@ public final class TvInputInfo implements Parcelable {
* @param id ID of this TV input. Should be generated via generateInputId*().
* @param parentId ID of this TV input's parent input. {@code null} if none exists.
*/
private TvInputInfo(Context context, ResolveInfo service, String id, String parentId) {
private TvInputInfo(ResolveInfo service, String id, String parentId) {
mService = service;
ServiceInfo si = service.serviceInfo;
mId = id;
mParentId = parentId;
}
@@ -429,7 +429,6 @@ public final class TvInputInfo implements Parcelable {
/**
* Used to make this class parcelable.
*
* @hide
*/
public static final Parcelable.Creator<TvInputInfo> CREATOR =

View File

@@ -23,6 +23,7 @@ import android.content.Context;
import android.content.Intent;
import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.hardware.hdmi.HdmiCecDeviceInfo;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
@@ -121,21 +122,32 @@ public abstract class TvInputService extends Service {
@Override
public void notifyHardwareAdded(TvInputHardwareInfo hardwareInfo) {
mHandler.obtainMessage(ServiceHandler.DO_ADD_TV_INPUT_FROM_HARDWARE,
mHandler.obtainMessage(ServiceHandler.DO_ADD_HARDWARE_TV_INPUT,
hardwareInfo).sendToTarget();
}
@Override
public void notifyHardwareRemoved(int deviceId) {
mHandler.obtainMessage(ServiceHandler.DO_REMOVE_TV_INPUT_FROM_HARDWARE,
deviceId, 0).sendToTarget();
public void notifyHardwareRemoved(TvInputHardwareInfo hardwareInfo) {
mHandler.obtainMessage(ServiceHandler.DO_REMOVE_HARDWARE_TV_INPUT,
hardwareInfo).sendToTarget();
}
@Override
public void notifyHdmiCecDeviceAdded(HdmiCecDeviceInfo cecDeviceInfo) {
mHandler.obtainMessage(ServiceHandler.DO_ADD_HDMI_CEC_TV_INPUT,
cecDeviceInfo).sendToTarget();
}
@Override
public void notifyHdmiCecDeviceRemoved(HdmiCecDeviceInfo cecDeviceInfo) {
mHandler.obtainMessage(ServiceHandler.DO_REMOVE_HDMI_CEC_TV_INPUT,
cecDeviceInfo).sendToTarget();
}
};
}
/**
* Get the number of callbacks that are registered.
*
* @hide
*/
@VisibleForTesting
@@ -153,11 +165,11 @@ public abstract class TvInputService extends Service {
public abstract Session onCreateSession(String inputId);
/**
* Returns a new TvInputInfo object if this service is responsible for {@code hardwareInfo};
* otherwise, return {@code null}. Override to modify default behavior of ignoring all input.
*
* @param hardwareInfo TvInputHardwareInfo object just added.
* Returns a new {@link TvInputInfo} object if this service is responsible for
* {@code hardwareInfo}; otherwise, return {@code null}. Override to modify default behavior of
* ignoring all hardware input.
*
* @param hardwareInfo {@link TvInputHardwareInfo} object just added.
* @hide
*/
@SystemApi
@@ -167,12 +179,40 @@ public abstract class TvInputService extends Service {
/**
* Returns the input ID for {@code deviceId} if it is handled by this service;
* otherwise, return {@code null}. Override to modify default behavior of ignoring all input.
* otherwise, return {@code null}. Override to modify default behavior of ignoring all hardware
* input.
*
* @param hardwareInfo {@link TvInputHardwareInfo} object just removed.
* @hide
*/
@SystemApi
public String onHardwareRemoved(int deviceId) {
public String onHardwareRemoved(TvInputHardwareInfo hardwareInfo) {
return null;
}
/**
* Returns a new {@link TvInputInfo} object if this service is responsible for
* {@code cecDeviceInfo}; otherwise, return {@code null}. Override to modify default behavior
* of ignoring all HDMI CEC logical input device.
*
* @param cecDeviceInfo {@link HdmiCecDeviceInfo} object just added.
* @hide
*/
@SystemApi
public TvInputInfo onHdmiCecDeviceAdded(HdmiCecDeviceInfo cecDeviceInfo) {
return null;
}
/**
* Returns the input ID for {@code logicalAddress} if it is handled by this service;
* otherwise, return {@code null}. Override to modify default behavior of ignoring all HDMI CEC
* logical input device.
*
* @param cecDeviceInfo {@link HdmiCecDeviceInfo} object just removed.
* @hide
*/
@SystemApi
public String onHdmiCecDeviceRemoved(HdmiCecDeviceInfo cecDeviceInfo) {
return null;
}
@@ -899,14 +939,29 @@ public abstract class TvInputService extends Service {
@SuppressLint("HandlerLeak")
private final class ServiceHandler extends Handler {
private static final int DO_CREATE_SESSION = 1;
private static final int DO_ADD_TV_INPUT_FROM_HARDWARE = 2;
private static final int DO_REMOVE_TV_INPUT_FROM_HARDWARE = 3;
private static final int DO_ADD_HARDWARE_TV_INPUT = 2;
private static final int DO_REMOVE_HARDWARE_TV_INPUT = 3;
private static final int DO_ADD_HDMI_CEC_TV_INPUT = 4;
private static final int DO_REMOVE_HDMI_CEC_TV_INPUT = 5;
private void broadcastAddTvInput(TvInputInfo inputInfo) {
private void broadcastAddHardwareTvInput(int deviceId, TvInputInfo inputInfo) {
int n = mCallbacks.beginBroadcast();
for (int i = 0; i < n; ++i) {
try {
mCallbacks.getBroadcastItem(i).addTvInput(inputInfo);
mCallbacks.getBroadcastItem(i).addHardwareTvInput(deviceId, inputInfo);
} catch (RemoteException e) {
Log.e(TAG, "Error while broadcasting: " + e);
}
}
mCallbacks.finishBroadcast();
}
private void broadcastAddHdmiCecTvInput(
int logicalAddress, TvInputInfo inputInfo) {
int n = mCallbacks.beginBroadcast();
for (int i = 0; i < n; ++i) {
try {
mCallbacks.getBroadcastItem(i).addHdmiCecTvInput(logicalAddress, inputInfo);
} catch (RemoteException e) {
Log.e(TAG, "Error while broadcasting: " + e);
}
@@ -951,17 +1006,33 @@ public abstract class TvInputService extends Service {
args.recycle();
return;
}
case DO_ADD_TV_INPUT_FROM_HARDWARE: {
case DO_ADD_HARDWARE_TV_INPUT: {
TvInputHardwareInfo hardwareInfo = (TvInputHardwareInfo) msg.obj;
TvInputInfo inputInfo = onHardwareAdded(hardwareInfo);
if (inputInfo != null) {
broadcastAddTvInput(inputInfo);
broadcastAddHardwareTvInput(hardwareInfo.getDeviceId(), inputInfo);
}
return;
}
case DO_REMOVE_TV_INPUT_FROM_HARDWARE: {
int deviceId = msg.arg1;
String inputId = onHardwareRemoved(deviceId);
case DO_REMOVE_HARDWARE_TV_INPUT: {
TvInputHardwareInfo hardwareInfo = (TvInputHardwareInfo) msg.obj;
String inputId = onHardwareRemoved(hardwareInfo);
if (inputId != null) {
broadcastRemoveTvInput(inputId);
}
return;
}
case DO_ADD_HDMI_CEC_TV_INPUT: {
HdmiCecDeviceInfo cecDeviceInfo = (HdmiCecDeviceInfo) msg.obj;
TvInputInfo inputInfo = onHdmiCecDeviceAdded(cecDeviceInfo);
if (inputInfo != null) {
broadcastAddHdmiCecTvInput(cecDeviceInfo.getLogicalAddress(), inputInfo);
}
return;
}
case DO_REMOVE_HDMI_CEC_TV_INPUT: {
HdmiCecDeviceInfo cecDeviceInfo = (HdmiCecDeviceInfo) msg.obj;
String inputId = onHdmiCecDeviceRemoved(cecDeviceInfo);
if (inputId != null) {
broadcastRemoveTvInput(inputId);
}

View File

@@ -42,6 +42,7 @@ import android.os.Looper;
import android.os.Message;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.util.ArrayMap;
import android.util.Slog;
import android.util.SparseArray;
import android.util.SparseBooleanArray;
@@ -51,8 +52,10 @@ import android.view.Surface;
import com.android.server.SystemService;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
@@ -65,20 +68,27 @@ import java.util.Set;
*/
class TvInputHardwareManager implements TvInputHal.Callback {
private static final String TAG = TvInputHardwareManager.class.getSimpleName();
private final Context mContext;
private final Listener mListener;
private final TvInputHal mHal = new TvInputHal(this);
private final SparseArray<Connection> mConnections = new SparseArray<Connection>();
private final List<TvInputHardwareInfo> mInfoList = new ArrayList<TvInputHardwareInfo>();
private final Context mContext;
private final Listener mListener;
private final Set<Integer> mActiveHdmiSources = new HashSet<Integer>();
/* A map from a device ID to the matching TV input ID. */
private final SparseArray<String> mHardwareInputIdMap = new SparseArray<String>();
/* A map from a HDMI logical address to the matching TV input ID. */
private final SparseArray<String> mHdmiCecInputIdMap = new SparseArray<String>();
private final Map<String, TvInputInfo> mInputMap = new ArrayMap<String, TvInputInfo>();
private final AudioManager mAudioManager;
private final SparseBooleanArray mHdmiStateMap = new SparseBooleanArray();
// TODO: Should handle INACTIVE case.
private final SparseArray<TvInputInfo> mTvInputInfoMap = new SparseArray<TvInputInfo>();
private final IHdmiDeviceEventListener mHdmiDeviceEventListener = new HdmiDeviceEventListener();
private IHdmiControlService mHdmiControlService;
private final IHdmiHotplugEventListener mHdmiHotplugEventListener =
new HdmiHotplugEventListener();
private final IHdmiDeviceEventListener mHdmiDeviceEventListener = new HdmiDeviceEventListener();
private final IHdmiInputChangeListener mHdmiInputChangeListener = new HdmiInputChangeListener();
private final Set<Integer> mActiveHdmiSources = new HashSet<Integer>();
// TODO: Should handle INACTIVE case.
private final SparseBooleanArray mHdmiStateMap = new SparseBooleanArray();
// Calls to mListener should happen here.
private final Handler mHandler = new ListenerHandler();
@@ -94,23 +104,22 @@ class TvInputHardwareManager implements TvInputHal.Callback {
public void onBootPhase(int phase) {
if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY) {
IHdmiControlService hdmiControlService = IHdmiControlService.Stub.asInterface(
ServiceManager.getService(Context.HDMI_CONTROL_SERVICE));
if (hdmiControlService != null) {
mHdmiControlService = IHdmiControlService.Stub.asInterface(ServiceManager.getService(
Context.HDMI_CONTROL_SERVICE));
if (mHdmiControlService != null) {
try {
hdmiControlService.addHotplugEventListener(mHdmiHotplugEventListener);
hdmiControlService.addDeviceEventListener(mHdmiDeviceEventListener);
hdmiControlService.setInputChangeListener(mHdmiInputChangeListener);
mHdmiControlService.addHotplugEventListener(mHdmiHotplugEventListener);
mHdmiControlService.addDeviceEventListener(mHdmiDeviceEventListener);
mHdmiControlService.setInputChangeListener(mHdmiInputChangeListener);
} catch (RemoteException e) {
Slog.w(TAG, "Error registering listeners to HdmiControlService:" + e);
Slog.w(TAG, "Error registering listeners to HdmiControlService:", e);
}
}
}
}
@Override
public void onDeviceAvailable(
TvInputHardwareInfo info, TvStreamConfig[] configs) {
public void onDeviceAvailable(TvInputHardwareInfo info, TvStreamConfig[] configs) {
synchronized (mLock) {
Connection connection = new Connection(info);
connection.updateConfigsLocked(configs);
@@ -139,8 +148,9 @@ class TvInputHardwareManager implements TvInputHal.Callback {
connection.resetLocked(null, null, null, null, null);
mConnections.remove(deviceId);
buildInfoListLocked();
TvInputHardwareInfo info = connection.getHardwareInfoLocked();
mHandler.obtainMessage(
ListenerHandler.HARDWARE_DEVICE_REMOVED, deviceId, 0).sendToTarget();
ListenerHandler.HARDWARE_DEVICE_REMOVED, 0, 0, info).sendToTarget();
}
}
@@ -157,7 +167,7 @@ class TvInputHardwareManager implements TvInputHal.Callback {
try {
connection.getCallbackLocked().onStreamConfigChanged(configs);
} catch (RemoteException e) {
Slog.e(TAG, "onStreamConfigurationChanged: " + e);
Slog.e(TAG, "error in onStreamConfigurationChanged", e);
}
}
}
@@ -168,6 +178,17 @@ class TvInputHardwareManager implements TvInputHal.Callback {
}
}
public List<HdmiCecDeviceInfo> getHdmiCecInputDeviceList() {
if (mHdmiControlService != null) {
try {
return mHdmiControlService.getInputDevices();
} catch (RemoteException e) {
Slog.e(TAG, "error in getHdmiCecInputDeviceList", e);
}
}
return Collections.emptyList();
}
private boolean checkUidChangedLocked(
Connection connection, int callingUid, int resolvedUserId) {
Integer connectionCallingUid = connection.getCallingUidLocked();
@@ -189,17 +210,19 @@ class TvInputHardwareManager implements TvInputHal.Callback {
}
}
public void registerTvInputInfo(TvInputInfo info, int deviceId) {
public void addHardwareTvInput(int deviceId, TvInputInfo info) {
if (info.getType() == TvInputInfo.TYPE_VIRTUAL) {
throw new IllegalArgumentException("info (" + info + ") has virtual type.");
}
synchronized (mLock) {
if (mTvInputInfoMap.indexOfKey(deviceId) >= 0) {
String oldInputId = mHardwareInputIdMap.get(deviceId);
if (oldInputId != null) {
Slog.w(TAG, "Trying to override previous registration: old = "
+ mTvInputInfoMap.get(deviceId) + ":" + deviceId + ", new = "
+ mInputMap.get(oldInputId) + ":" + deviceId + ", new = "
+ info + ":" + deviceId);
}
mTvInputInfoMap.put(deviceId, info);
mHardwareInputIdMap.put(deviceId, info.getId());
mInputMap.put(info.getId(), info);
for (int i = 0; i < mHdmiStateMap.size(); ++i) {
String inputId = findInputIdForHdmiPortLocked(mHdmiStateMap.keyAt(i));
@@ -212,6 +235,41 @@ class TvInputHardwareManager implements TvInputHal.Callback {
}
}
public void addHdmiCecTvInput(int logicalAddress, TvInputInfo info) {
if (info.getType() != TvInputInfo.TYPE_HDMI) {
throw new IllegalArgumentException("info (" + info + ") has non-HDMI type.");
}
synchronized (mLock) {
String parentId = info.getParentId();
int parentIndex = mHardwareInputIdMap.indexOfValue(parentId);
if (parentIndex < 0 || !parentId.equals(mHardwareInputIdMap.valueAt(parentIndex))) {
throw new IllegalArgumentException("info (" + info + ") has invalid parentId.");
}
String oldInputId = mHdmiCecInputIdMap.get(logicalAddress);
if (oldInputId != null) {
Slog.w(TAG, "Trying to override previous registration: old = "
+ mInputMap.get(oldInputId) + ":" + logicalAddress + ", new = "
+ info + ":" + logicalAddress);
}
mHdmiCecInputIdMap.put(logicalAddress, info.getId());
mInputMap.put(info.getId(), info);
}
}
public void removeTvInput(String inputId) {
synchronized (mLock) {
mInputMap.remove(inputId);
int hardwareIndex = mHardwareInputIdMap.indexOfValue(inputId);
if (hardwareIndex >= 0) {
mHardwareInputIdMap.removeAt(hardwareIndex);
}
int cecIndex = mHdmiCecInputIdMap.indexOfValue(inputId);
if (cecIndex >= 0) {
mHdmiCecInputIdMap.removeAt(cecIndex);
}
}
}
/**
* Create a TvInputHardware object with a specific deviceId. One service at a time can access
* the object, and if more than one process attempts to create hardware with the same deviceId,
@@ -267,8 +325,7 @@ class TvInputHardwareManager implements TvInputHal.Callback {
for (TvInputHardwareInfo hardwareInfo : mInfoList) {
if (hardwareInfo.getType() == TvInputHardwareInfo.TV_INPUT_TYPE_HDMI
&& hardwareInfo.getHdmiPortId() == port) {
TvInputInfo info = mTvInputInfoMap.get(hardwareInfo.getDeviceId());
return (info == null) ? null : info.getId();
return mHardwareInputIdMap.get(hardwareInfo.getDeviceId());
}
}
return null;
@@ -295,7 +352,7 @@ class TvInputHardwareManager implements TvInputHal.Callback {
try {
mCallback.onReleased();
} catch (RemoteException e) {
Slog.e(TAG, "Connection::resetHardware: " + e);
Slog.e(TAG, "error in Connection::resetLocked", e);
}
mHardware.release();
}
@@ -309,7 +366,7 @@ class TvInputHardwareManager implements TvInputHal.Callback {
try {
mCallback.onStreamConfigChanged(getConfigsLocked());
} catch (RemoteException e) {
Slog.e(TAG, "Connection::resetHardware: " + e);
Slog.e(TAG, "error in Connection::resetLocked", e);
}
}
}
@@ -501,7 +558,7 @@ class TvInputHardwareManager implements TvInputHal.Callback {
interface Listener {
public void onStateChanged(String inputId, int state);
public void onHardwareDeviceAdded(TvInputHardwareInfo info);
public void onHardwareDeviceRemoved(int deviceId);
public void onHardwareDeviceRemoved(TvInputHardwareInfo info);
public void onHdmiCecDeviceAdded(HdmiCecDeviceInfo cecDevice);
public void onHdmiCecDeviceRemoved(HdmiCecDeviceInfo cecDevice);
}
@@ -510,8 +567,8 @@ class TvInputHardwareManager implements TvInputHal.Callback {
private static final int STATE_CHANGED = 1;
private static final int HARDWARE_DEVICE_ADDED = 2;
private static final int HARDWARE_DEVICE_REMOVED = 3;
private static final int CEC_DEVICE_ADDED = 4;
private static final int CEC_DEVICE_REMOVED = 5;
private static final int HDMI_CEC_DEVICE_ADDED = 4;
private static final int HDMI_CEC_DEVICE_REMOVED = 5;
@Override
public final void handleMessage(Message msg) {
@@ -528,16 +585,16 @@ class TvInputHardwareManager implements TvInputHal.Callback {
break;
}
case HARDWARE_DEVICE_REMOVED: {
int deviceId = msg.arg1;
mListener.onHardwareDeviceRemoved(deviceId);
TvInputHardwareInfo info = (TvInputHardwareInfo) msg.obj;
mListener.onHardwareDeviceRemoved(info);
break;
}
case CEC_DEVICE_ADDED: {
case HDMI_CEC_DEVICE_ADDED: {
HdmiCecDeviceInfo info = (HdmiCecDeviceInfo) msg.obj;
mListener.onHdmiCecDeviceAdded(info);
break;
}
case CEC_DEVICE_REMOVED: {
case HDMI_CEC_DEVICE_REMOVED: {
HdmiCecDeviceInfo info = (HdmiCecDeviceInfo) msg.obj;
mListener.onHdmiCecDeviceRemoved(info);
break;
@@ -571,8 +628,8 @@ class TvInputHardwareManager implements TvInputHal.Callback {
@Override
public void onStatusChanged(HdmiCecDeviceInfo deviceInfo, boolean activated) {
mHandler.obtainMessage(
activated ? ListenerHandler.CEC_DEVICE_ADDED
: ListenerHandler.CEC_DEVICE_REMOVED,
activated ? ListenerHandler.HDMI_CEC_DEVICE_ADDED
: ListenerHandler.HDMI_CEC_DEVICE_REMOVED,
0, 0, deviceInfo).sendToTarget();
}
}

View File

@@ -220,7 +220,7 @@ public final class TvInputManagerService extends SystemService {
List<ResolveInfo> services = pm.queryIntentServices(
new Intent(TvInputService.SERVICE_INTERFACE),
PackageManager.GET_SERVICES | PackageManager.GET_META_DATA);
List<TvInputInfo> infoList = new ArrayList<TvInputInfo>();
List<TvInputInfo> inputList = new ArrayList<TvInputInfo>();
for (ResolveInfo ri : services) {
ServiceInfo si = ri.serviceInfo;
if (!android.Manifest.permission.BIND_TV_INPUT.equals(si.permission)) {
@@ -229,7 +229,7 @@ public final class TvInputManagerService extends SystemService {
continue;
}
try {
infoList.clear();
inputList.clear();
ComponentName service = new ComponentName(si.packageName, si.name);
if (hasHardwarePermission(pm, service)) {
ServiceState serviceState = userState.serviceStateMap.get(service);
@@ -240,13 +240,13 @@ public final class TvInputManagerService extends SystemService {
serviceState = new ServiceState(service, userId);
userState.serviceStateMap.put(service, serviceState);
} else {
infoList.addAll(serviceState.mInputList);
inputList.addAll(serviceState.mInputList);
}
} else {
infoList.add(TvInputInfo.createTvInputInfo(mContext, ri));
inputList.add(TvInputInfo.createTvInputInfo(mContext, ri));
}
for (TvInputInfo info : infoList) {
for (TvInputInfo info : inputList) {
if (DEBUG) Slog.d(TAG, "add " + info.getId());
TvInputState state = userState.inputMap.get(info.getId());
if (state == null) {
@@ -1212,22 +1212,6 @@ public final class TvInputManagerService extends SystemService {
}
}
@Override
public void registerTvInputInfo(TvInputInfo info, int deviceId) {
// TODO: Revisit to sort out deviceId ownership.
if (mContext.checkCallingPermission(android.Manifest.permission.TV_INPUT_HARDWARE)
!= PackageManager.PERMISSION_GRANTED) {
return;
}
final long identity = Binder.clearCallingIdentity();
try {
mTvInputHardwareManager.registerTvInputInfo(info, deviceId);
} finally {
Binder.restoreCallingIdentity(identity);
}
}
@Override
public ITvInputHardware acquireTvInputHardware(int deviceId,
ITvInputHardwareCallback callback, TvInputInfo info, int userId)
@@ -1550,8 +1534,6 @@ public final class TvInputManagerService extends SystemService {
Slog.d(TAG, "onServiceConnected(name=" + name + ")");
}
synchronized (mLock) {
List<TvInputHardwareInfo> hardwareInfoList =
mTvInputHardwareManager.getHardwareList();
UserState userState = getUserStateLocked(mUserId);
ServiceState serviceState = userState.serviceStateMap.get(mName);
serviceState.mService = ITvInputService.Stub.asInterface(service);
@@ -1580,6 +1562,8 @@ public final class TvInputManagerService extends SystemService {
}
if (serviceState.mIsHardware) {
List<TvInputHardwareInfo> hardwareInfoList =
mTvInputHardwareManager.getHardwareList();
for (TvInputHardwareInfo hardwareInfo : hardwareInfoList) {
try {
serviceState.mService.notifyHardwareAdded(hardwareInfo);
@@ -1588,7 +1572,15 @@ public final class TvInputManagerService extends SystemService {
}
}
// TODO: Grab CEC devices and notify them to the service.
List<HdmiCecDeviceInfo> cecDeviceInfoList =
mTvInputHardwareManager.getHdmiCecInputDeviceList();
for (HdmiCecDeviceInfo cecDeviceInfo : cecDeviceInfoList) {
try {
serviceState.mService.notifyHdmiCecDeviceAdded(cecDeviceInfo);
} catch (RemoteException e) {
Slog.e(TAG, "error in notifyHdmiCecDeviceAdded", e);
}
}
}
}
}
@@ -1642,32 +1634,49 @@ public final class TvInputManagerService extends SystemService {
mUserId = userId;
}
@Override
public void addTvInput(TvInputInfo inputInfo) {
synchronized (mLock) {
if (mContext.checkCallingPermission(android.Manifest.permission.TV_INPUT_HARDWARE)
!= PackageManager.PERMISSION_GRANTED) {
Slog.w(TAG, "The caller does not have permission to add a TV input ("
+ inputInfo + ").");
return;
}
private void ensureHardwarePermission() {
if (mContext.checkCallingPermission(android.Manifest.permission.TV_INPUT_HARDWARE)
!= PackageManager.PERMISSION_GRANTED) {
throw new SecurityException("The caller does not have hardware permission");
}
}
ServiceState serviceState = getServiceStateLocked(mName, mUserId);
serviceState.mInputList.add(inputInfo);
buildTvInputListLocked(mUserId);
private void ensureValidInput(TvInputInfo inputInfo) {
if (inputInfo.getId() == null || !mName.equals(inputInfo.getComponent())) {
throw new IllegalArgumentException("Invalid TvInputInfo");
}
}
private void addTvInputLocked(TvInputInfo inputInfo) {
ServiceState serviceState = getServiceStateLocked(mName, mUserId);
serviceState.mInputList.add(inputInfo);
buildTvInputListLocked(mUserId);
}
@Override
public void addHardwareTvInput(int deviceId, TvInputInfo inputInfo) {
ensureHardwarePermission();
ensureValidInput(inputInfo);
synchronized (mLock) {
mTvInputHardwareManager.addHardwareTvInput(deviceId, inputInfo);
addTvInputLocked(inputInfo);
}
}
@Override
public void addHdmiCecTvInput(int logicalAddress, TvInputInfo inputInfo) {
ensureHardwarePermission();
ensureValidInput(inputInfo);
synchronized (mLock) {
mTvInputHardwareManager.addHdmiCecTvInput(logicalAddress, inputInfo);
addTvInputLocked(inputInfo);
}
}
@Override
public void removeTvInput(String inputId) {
ensureHardwarePermission();
synchronized (mLock) {
if (mContext.checkCallingPermission(android.Manifest.permission.TV_INPUT_HARDWARE)
!= PackageManager.PERMISSION_GRANTED) {
Slog.w(TAG, "The caller does not have permission to remove a TV input ("
+ inputId + ").");
return;
}
ServiceState serviceState = getServiceStateLocked(mName, mUserId);
boolean removed = false;
for (Iterator<TvInputInfo> it = serviceState.mInputList.iterator();
@@ -1680,6 +1689,7 @@ public final class TvInputManagerService extends SystemService {
}
if (removed) {
buildTvInputListLocked(mUserId);
mTvInputHardwareManager.removeTvInput(inputId);
} else {
Slog.e(TAG, "TvInputInfo with inputId=" + inputId + " not found.");
}
@@ -1856,14 +1866,14 @@ public final class TvInputManagerService extends SystemService {
}
@Override
public void onHardwareDeviceRemoved(int deviceId) {
public void onHardwareDeviceRemoved(TvInputHardwareInfo info) {
synchronized (mLock) {
UserState userState = getUserStateLocked(mCurrentUserId);
// Broadcast the event to all hardware inputs.
for (ServiceState serviceState : userState.serviceStateMap.values()) {
if (!serviceState.mIsHardware || serviceState.mService == null) continue;
try {
serviceState.mService.notifyHardwareRemoved(deviceId);
serviceState.mService.notifyHardwareRemoved(info);
} catch (RemoteException e) {
Slog.e(TAG, "error in notifyHardwareRemoved", e);
}
@@ -1872,16 +1882,34 @@ public final class TvInputManagerService extends SystemService {
}
@Override
public void onHdmiCecDeviceAdded(HdmiCecDeviceInfo cecDevice) {
public void onHdmiCecDeviceAdded(HdmiCecDeviceInfo cecDeviceInfo) {
synchronized (mLock) {
// TODO
UserState userState = getUserStateLocked(mCurrentUserId);
// Broadcast the event to all hardware inputs.
for (ServiceState serviceState : userState.serviceStateMap.values()) {
if (!serviceState.mIsHardware || serviceState.mService == null) continue;
try {
serviceState.mService.notifyHdmiCecDeviceAdded(cecDeviceInfo);
} catch (RemoteException e) {
Slog.e(TAG, "error in notifyHdmiCecDeviceAdded", e);
}
}
}
}
@Override
public void onHdmiCecDeviceRemoved(HdmiCecDeviceInfo cecDevice) {
public void onHdmiCecDeviceRemoved(HdmiCecDeviceInfo cecDeviceInfo) {
synchronized (mLock) {
// TODO
UserState userState = getUserStateLocked(mCurrentUserId);
// Broadcast the event to all hardware inputs.
for (ServiceState serviceState : userState.serviceStateMap.values()) {
if (!serviceState.mIsHardware || serviceState.mService == null) continue;
try {
serviceState.mService.notifyHdmiCecDeviceRemoved(cecDeviceInfo);
} catch (RemoteException e) {
Slog.e(TAG, "error in notifyHdmiCecDeviceRemoved", e);
}
}
}
}
}