diff options
7 files changed, 273 insertions, 119 deletions
diff --git a/media/java/android/media/tv/ITvInputManager.aidl b/media/java/android/media/tv/ITvInputManager.aidl index ccfc484..8e64693 100644 --- a/media/java/android/media/tv/ITvInputManager.aidl +++ b/media/java/android/media/tv/ITvInputManager.aidl @@ -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); diff --git a/media/java/android/media/tv/ITvInputService.aidl b/media/java/android/media/tv/ITvInputService.aidl index 158223a..651669b 100644 --- a/media/java/android/media/tv/ITvInputService.aidl +++ b/media/java/android/media/tv/ITvInputService.aidl @@ -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); } diff --git a/media/java/android/media/tv/ITvInputServiceCallback.aidl b/media/java/android/media/tv/ITvInputServiceCallback.aidl index 287da71..df648e7 100644 --- a/media/java/android/media/tv/ITvInputServiceCallback.aidl +++ b/media/java/android/media/tv/ITvInputServiceCallback.aidl @@ -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); } diff --git a/media/java/android/media/tv/TvInputInfo.java b/media/java/android/media/tv/TvInputInfo.java index 77cfc32..86fd4ff 100644 --- a/media/java/android/media/tv/TvInputInfo.java +++ b/media/java/android/media/tv/TvInputInfo.java @@ -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 = diff --git a/media/java/android/media/tv/TvInputService.java b/media/java/android/media/tv/TvInputService.java index 39e7f9d..db07b65 100644 --- a/media/java/android/media/tv/TvInputService.java +++ b/media/java/android/media/tv/TvInputService.java @@ -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 broadcastAddHardwareTvInput(int deviceId, TvInputInfo inputInfo) { + int n = mCallbacks.beginBroadcast(); + for (int i = 0; i < n; ++i) { + try { + mCallbacks.getBroadcastItem(i).addHardwareTvInput(deviceId, inputInfo); + } catch (RemoteException e) { + Log.e(TAG, "Error while broadcasting: " + e); + } + } + mCallbacks.finishBroadcast(); + } - private void broadcastAddTvInput(TvInputInfo inputInfo) { + private void broadcastAddHdmiCecTvInput( + int logicalAddress, TvInputInfo inputInfo) { int n = mCallbacks.beginBroadcast(); for (int i = 0; i < n; ++i) { try { - mCallbacks.getBroadcastItem(i).addTvInput(inputInfo); + 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_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_TV_INPUT_FROM_HARDWARE: { - int deviceId = msg.arg1; - String inputId = onHardwareRemoved(deviceId); + case DO_REMOVE_HDMI_CEC_TV_INPUT: { + HdmiCecDeviceInfo cecDeviceInfo = (HdmiCecDeviceInfo) msg.obj; + String inputId = onHdmiCecDeviceRemoved(cecDeviceInfo); if (inputId != null) { broadcastRemoveTvInput(inputId); } diff --git a/services/core/java/com/android/server/tv/TvInputHardwareManager.java b/services/core/java/com/android/server/tv/TvInputHardwareManager.java index 332e426..0a9c646 100644 --- a/services/core/java/com/android/server/tv/TvInputHardwareManager.java +++ b/services/core/java/com/android/server/tv/TvInputHardwareManager.java @@ -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(); } } diff --git a/services/core/java/com/android/server/tv/TvInputManagerService.java b/services/core/java/com/android/server/tv/TvInputManagerService.java index c112b13..01aaca0 100644 --- a/services/core/java/com/android/server/tv/TvInputManagerService.java +++ b/services/core/java/com/android/server/tv/TvInputManagerService.java @@ -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) { @@ -1213,22 +1213,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) throws RemoteException { @@ -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; } + 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"); + } + } + + 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 addTvInput(TvInputInfo inputInfo) { + public void addHardwareTvInput(int deviceId, TvInputInfo inputInfo) { + ensureHardwarePermission(); + ensureValidInput(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; - } + mTvInputHardwareManager.addHardwareTvInput(deviceId, inputInfo); + addTvInputLocked(inputInfo); + } + } - ServiceState serviceState = getServiceStateLocked(mName, mUserId); - serviceState.mInputList.add(inputInfo); - buildTvInputListLocked(mUserId); + @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); + } + } } } } |