Replace ComponentName to InputId.

Change-Id: Ia4b5b7fa3f2dfa68629f78981b4ea7f7017d6504
diff --git a/api/current.txt b/api/current.txt
index 380d641..92e3fb1 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -29130,11 +29130,11 @@
   }
 
   public final class TvInputManager {
-    method public void createSession(android.content.ComponentName, android.tv.TvInputManager.SessionCreateCallback, android.os.Handler);
-    method public boolean getAvailability(android.content.ComponentName);
+    method public void createSession(java.lang.String, android.tv.TvInputManager.SessionCreateCallback, android.os.Handler);
+    method public boolean getAvailability(java.lang.String);
     method public java.util.List<android.tv.TvInputInfo> getTvInputList();
-    method public void registerListener(android.content.ComponentName, android.tv.TvInputManager.TvInputListener, android.os.Handler);
-    method public void unregisterListener(android.content.ComponentName, android.tv.TvInputManager.TvInputListener);
+    method public void registerListener(java.lang.String, android.tv.TvInputManager.TvInputListener, android.os.Handler);
+    method public void unregisterListener(java.lang.String, android.tv.TvInputManager.TvInputListener);
   }
 
   public static final class TvInputManager.Session {
@@ -29149,7 +29149,7 @@
 
   public static abstract class TvInputManager.TvInputListener {
     ctor public TvInputManager.TvInputListener();
-    method public void onAvailabilityChanged(android.content.ComponentName, boolean);
+    method public void onAvailabilityChanged(java.lang.String, boolean);
   }
 
   public abstract class TvInputService extends android.app.Service {
@@ -29181,7 +29181,7 @@
     ctor public TvView(android.content.Context);
     ctor public TvView(android.content.Context, android.util.AttributeSet);
     ctor public TvView(android.content.Context, android.util.AttributeSet, int);
-    method public void bindTvInput(android.content.ComponentName, android.tv.TvInputManager.SessionCreateCallback);
+    method public void bindTvInput(java.lang.String, android.tv.TvInputManager.SessionCreateCallback);
     method public boolean dispatchUnhandledInputEvent(android.view.InputEvent);
     method public boolean onUnhandledInputEvent(android.view.InputEvent);
     method public void setOnUnhandledInputEventListener(android.tv.TvView.OnUnhandledInputEventListener);
diff --git a/core/java/android/tv/ITvInputClient.aidl b/core/java/android/tv/ITvInputClient.aidl
index 538f8a1..2adcaf1 100644
--- a/core/java/android/tv/ITvInputClient.aidl
+++ b/core/java/android/tv/ITvInputClient.aidl
@@ -26,6 +26,6 @@
  * @hide
  */
 oneway interface ITvInputClient {
-    void onSessionCreated(in ComponentName name, IBinder token, in InputChannel channel, int seq);
-    void onAvailabilityChanged(in ComponentName name, boolean isAvailable);
+    void onSessionCreated(in String inputId, IBinder token, in InputChannel channel, int seq);
+    void onAvailabilityChanged(in String inputId, boolean isAvailable);
 }
diff --git a/core/java/android/tv/ITvInputManager.aidl b/core/java/android/tv/ITvInputManager.aidl
index a4c99e4..b756aba 100644
--- a/core/java/android/tv/ITvInputManager.aidl
+++ b/core/java/android/tv/ITvInputManager.aidl
@@ -30,12 +30,12 @@
 interface ITvInputManager {
     List<TvInputInfo> getTvInputList(int userId);
 
-    boolean getAvailability(in ITvInputClient client, in ComponentName name, int userId);
+    boolean getAvailability(in ITvInputClient client, in String inputId, int userId);
 
-    void registerCallback(in ITvInputClient client, in ComponentName name, int userId);
-    void unregisterCallback(in ITvInputClient client, in ComponentName name, int userId);
+    void registerCallback(in ITvInputClient client, in String inputId, int userId);
+    void unregisterCallback(in ITvInputClient client, in String inputId, int userId);
 
-    void createSession(in ITvInputClient client, in ComponentName name, int seq, int userId);
+    void createSession(in ITvInputClient client, in String inputId, int seq, int userId);
     void releaseSession(in IBinder sessionToken, int userId);
 
     void setSurface(in IBinder sessionToken, in Surface surface, int userId);
diff --git a/core/java/android/tv/ITvInputServiceCallback.aidl b/core/java/android/tv/ITvInputServiceCallback.aidl
index e535c81..71fc780 100644
--- a/core/java/android/tv/ITvInputServiceCallback.aidl
+++ b/core/java/android/tv/ITvInputServiceCallback.aidl
@@ -24,5 +24,5 @@
  * @hide
  */
 oneway interface ITvInputServiceCallback {
-    void onAvailabilityChanged(in ComponentName name, boolean isAvailable);
+    void onAvailabilityChanged(in String inputId, boolean isAvailable);
 }
diff --git a/core/java/android/tv/TvInputInfo.java b/core/java/android/tv/TvInputInfo.java
index 90e4177..50462cc 100644
--- a/core/java/android/tv/TvInputInfo.java
+++ b/core/java/android/tv/TvInputInfo.java
@@ -39,7 +39,7 @@
     public TvInputInfo(ResolveInfo service) {
         mService = service;
         ServiceInfo si = service.serviceInfo;
-        mId = new ComponentName(si.packageName, si.name).flattenToShortString();
+        mId = generateInputIdForComponenetName(new ComponentName(si.packageName, si.name));
     }
 
     /**
@@ -75,7 +75,7 @@
      * Loads the user-displayed label for this TV input service.
      *
      * @param pm Supplies a PackageManager used to load the TV input's resources.
-     * @return Returns a CharSequence containing the TV input's label. If the TV input does not have
+     * @return a CharSequence containing the TV input's label. If the TV input does not have
      *         a label, its name is returned.
      */
     public CharSequence loadLabel(PackageManager pm) {
@@ -128,6 +128,17 @@
     }
 
     /**
+     * Used to generate an input id from a ComponentName.
+     *
+     * @param name the component name for generating an input id.
+     * @return the generated input id for the given {@code name}.
+     * @hide
+     */
+    public static final String generateInputIdForComponenetName(ComponentName name) {
+        return name.flattenToShortString();
+    }
+
+    /**
      * Used to make this class parcelable.
      *
      * @hide
diff --git a/core/java/android/tv/TvInputManager.java b/core/java/android/tv/TvInputManager.java
index 7b9b1fb..e246fcf 100644
--- a/core/java/android/tv/TvInputManager.java
+++ b/core/java/android/tv/TvInputManager.java
@@ -16,7 +16,6 @@
 
 package android.tv;
 
-import android.content.ComponentName;
 import android.graphics.Rect;
 import android.net.Uri;
 import android.os.Handler;
@@ -50,8 +49,8 @@
     private final ITvInputManager mService;
 
     // A mapping from an input to the list of its TvInputListenerRecords.
-    private final Map<ComponentName, List<TvInputListenerRecord>> mTvInputListenerRecordsMap =
-            new HashMap<ComponentName, List<TvInputListenerRecord>>();
+    private final Map<String, List<TvInputListenerRecord>> mTvInputListenerRecordsMap =
+            new HashMap<String, List<TvInputListenerRecord>>();
 
     // A mapping from the sequence number of a session to its SessionCreateCallbackRecord.
     private final SparseArray<SessionCreateCallbackRecord> mSessionCreateCallbackRecordMap =
@@ -105,12 +104,11 @@
         /**
          * This is called when the availability status of a given TV input is changed.
          *
-         * @param name {@link ComponentName} of {@link android.app.Service} that implements the
-         *            given TV input.
+         * @param inputId the id of the TV input.
          * @param isAvailable {@code true} if the given TV input is available to show TV programs.
          *            {@code false} otherwise.
          */
-        public void onAvailabilityChanged(ComponentName name, boolean isAvailable) {
+        public void onAvailabilityChanged(String inputId, boolean isAvailable) {
         }
     }
 
@@ -127,11 +125,11 @@
             return mListener;
         }
 
-        public void postAvailabilityChanged(final ComponentName name, final boolean isAvailable) {
+        public void postAvailabilityChanged(final String inputId, final boolean isAvailable) {
             mHandler.post(new Runnable() {
                 @Override
                 public void run() {
-                    mListener.onAvailabilityChanged(name, isAvailable);
+                    mListener.onAvailabilityChanged(inputId, isAvailable);
                 }
             });
         }
@@ -145,7 +143,7 @@
         mUserId = userId;
         mClient = new ITvInputClient.Stub() {
             @Override
-            public void onSessionCreated(ComponentName name, IBinder token, InputChannel channel,
+            public void onSessionCreated(String inputId, IBinder token, InputChannel channel,
                     int seq) {
                 synchronized (mSessionCreateCallbackRecordMap) {
                     SessionCreateCallbackRecord record = mSessionCreateCallbackRecordMap.get(seq);
@@ -163,16 +161,16 @@
             }
 
             @Override
-            public void onAvailabilityChanged(ComponentName name, boolean isAvailable) {
+            public void onAvailabilityChanged(String inputId, boolean isAvailable) {
                 synchronized (mTvInputListenerRecordsMap) {
-                    List<TvInputListenerRecord> records = mTvInputListenerRecordsMap.get(name);
+                    List<TvInputListenerRecord> records = mTvInputListenerRecordsMap.get(inputId);
                     if (records == null) {
                         // Silently ignore - no listener is registered yet.
                         return;
                     }
                     int recordsCount = records.size();
                     for (int i = 0; i < recordsCount; i++) {
-                        records.get(i).postAvailabilityChanged(name, isAvailable);
+                        records.get(i).postAvailabilityChanged(inputId, isAvailable);
                     }
                 }
             }
@@ -195,24 +193,23 @@
     /**
      * Returns the availability of a given TV input.
      *
-     * @param name {@link ComponentName} of {@link android.app.Service} that implements the given TV
-     *            input.
+     * @param inputId the id of the TV input.
      * @throws IllegalArgumentException if the argument is {@code null}.
      * @throws IllegalStateException If there is no {@link TvInputListener} registered on the given
      *             TV input.
      */
-    public boolean getAvailability(ComponentName name) {
-        if (name == null) {
-            throw new IllegalArgumentException("name cannot be null");
+    public boolean getAvailability(String inputId) {
+        if (inputId == null) {
+            throw new IllegalArgumentException("id cannot be null");
         }
         synchronized (mTvInputListenerRecordsMap) {
-            List<TvInputListenerRecord> records = mTvInputListenerRecordsMap.get(name);
+            List<TvInputListenerRecord> records = mTvInputListenerRecordsMap.get(inputId);
             if (records == null || records.size() == 0) {
                 throw new IllegalStateException("At least one listener should be registered.");
             }
         }
         try {
-            return mService.getAvailability(mClient, name, mUserId);
+            return mService.getAvailability(mClient, inputId, mUserId);
         } catch (RemoteException e) {
             throw new RuntimeException(e);
         }
@@ -221,15 +218,14 @@
     /**
      * Registers a {@link TvInputListener} for a given TV input.
      *
-     * @param name {@link ComponentName} of {@link android.app.Service} that implements the given TV
-     *            input.
+     * @param inputId the id of the TV input.
      * @param listener a listener used to monitor status of the given TV input.
      * @param handler a {@link Handler} that the status change will be delivered to.
      * @throws IllegalArgumentException if any of the arguments is {@code null}.
      */
-    public void registerListener(ComponentName name, TvInputListener listener, Handler handler) {
-        if (name == null) {
-            throw new IllegalArgumentException("name cannot be null");
+    public void registerListener(String inputId, TvInputListener listener, Handler handler) {
+        if (inputId == null) {
+            throw new IllegalArgumentException("id cannot be null");
         }
         if (listener == null) {
             throw new IllegalArgumentException("listener cannot be null");
@@ -238,12 +234,12 @@
             throw new IllegalArgumentException("handler cannot be null");
         }
         synchronized (mTvInputListenerRecordsMap) {
-            List<TvInputListenerRecord> records = mTvInputListenerRecordsMap.get(name);
+            List<TvInputListenerRecord> records = mTvInputListenerRecordsMap.get(inputId);
             if (records == null) {
                 records = new ArrayList<TvInputListenerRecord>();
-                mTvInputListenerRecordsMap.put(name, records);
+                mTvInputListenerRecordsMap.put(inputId, records);
                 try {
-                    mService.registerCallback(mClient, name, mUserId);
+                    mService.registerCallback(mClient, inputId, mUserId);
                 } catch (RemoteException e) {
                     throw new RuntimeException(e);
                 }
@@ -255,22 +251,21 @@
     /**
      * Unregisters the existing {@link TvInputListener} for a given TV input.
      *
-     * @param name {@link ComponentName} of {@link android.app.Service} that implements the given TV
-     *            input.
+     * @param inputId the id of the TV input.
      * @param listener the existing listener to remove for the given TV input.
      * @throws IllegalArgumentException if any of the arguments is {@code null}.
      */
-    public void unregisterListener(ComponentName name, final TvInputListener listener) {
-        if (name == null) {
-            throw new IllegalArgumentException("name cannot be null");
+    public void unregisterListener(String inputId, final TvInputListener listener) {
+        if (inputId == null) {
+            throw new IllegalArgumentException("id cannot be null");
         }
         if (listener == null) {
             throw new IllegalArgumentException("listener cannot be null");
         }
         synchronized (mTvInputListenerRecordsMap) {
-            List<TvInputListenerRecord> records = mTvInputListenerRecordsMap.get(name);
+            List<TvInputListenerRecord> records = mTvInputListenerRecordsMap.get(inputId);
             if (records == null) {
-                Log.e(TAG, "No listener found for " + name.getClassName());
+                Log.e(TAG, "No listener found for " + inputId);
                 return;
             }
             for (Iterator<TvInputListenerRecord> it = records.iterator(); it.hasNext();) {
@@ -281,11 +276,11 @@
             }
             if (records.isEmpty()) {
                 try {
-                    mService.unregisterCallback(mClient, name, mUserId);
+                    mService.unregisterCallback(mClient, inputId, mUserId);
                 } catch (RemoteException e) {
                     throw new RuntimeException(e);
                 } finally {
-                    mTvInputListenerRecordsMap.remove(name);
+                    mTvInputListenerRecordsMap.remove(inputId);
                 }
             }
         }
@@ -298,16 +293,15 @@
      * the given TV input.
      * </p>
      *
-     * @param name {@link ComponentName} of {@link android.app.Service} that implements the given TV
-     *            input.
+     * @param inputId the id of the TV input.
      * @param callback a callback used to receive the created session.
      * @param handler a {@link Handler} that the session creation will be delivered to.
      * @throws IllegalArgumentException if any of the arguments is {@code null}.
      */
-    public void createSession(ComponentName name, final SessionCreateCallback callback,
+    public void createSession(String inputId, final SessionCreateCallback callback,
             Handler handler) {
-        if (name == null) {
-            throw new IllegalArgumentException("name cannot be null");
+        if (inputId == null) {
+            throw new IllegalArgumentException("id cannot be null");
         }
         if (callback == null) {
             throw new IllegalArgumentException("callback cannot be null");
@@ -320,7 +314,7 @@
             int seq = mNextSeq++;
             mSessionCreateCallbackRecordMap.put(seq, record);
             try {
-                mService.createSession(mClient, name, seq, mUserId);
+                mService.createSession(mClient, inputId, seq, mUserId);
             } catch (RemoteException e) {
                 throw new RuntimeException(e);
             }
diff --git a/core/java/android/tv/TvInputService.java b/core/java/android/tv/TvInputService.java
index 70e7f95..1d6298d 100644
--- a/core/java/android/tv/TvInputService.java
+++ b/core/java/android/tv/TvInputService.java
@@ -60,7 +60,7 @@
      */
     public static final String SERVICE_INTERFACE = "android.tv.TvInputService";
 
-    private ComponentName mComponentName;
+    private String mId;
     private final Handler mHandler = new ServiceHandler();
     private final RemoteCallbackList<ITvInputServiceCallback> mCallbacks =
             new RemoteCallbackList<ITvInputServiceCallback>();
@@ -69,7 +69,8 @@
     @Override
     public void onCreate() {
         super.onCreate();
-        mComponentName = new ComponentName(getPackageName(), getClass().getName());
+        mId = TvInputInfo.generateInputIdForComponenetName(
+                new ComponentName(getPackageName(), getClass().getName()));
     }
 
     @Override
@@ -82,7 +83,7 @@
                     // The first time a callback is registered, the service needs to report its
                     // availability status so that the system can know its initial value.
                     try {
-                        cb.onAvailabilityChanged(mComponentName, mAvailable);
+                        cb.onAvailabilityChanged(mId, mAvailable);
                     } catch (RemoteException e) {
                         Log.e(TAG, "error in onAvailabilityChanged", e);
                     }
@@ -531,8 +532,7 @@
                     int n = mCallbacks.beginBroadcast();
                     try {
                         for (int i = 0; i < n; i++) {
-                            mCallbacks.getBroadcastItem(i).onAvailabilityChanged(mComponentName,
-                                    isAvailable);
+                            mCallbacks.getBroadcastItem(i).onAvailabilityChanged(mId, isAvailable);
                         }
                     } catch (RemoteException e) {
                         Log.e(TAG, "Unexpected exception", e);
diff --git a/core/java/android/tv/TvView.java b/core/java/android/tv/TvView.java
index 289823b..0186220 100644
--- a/core/java/android/tv/TvView.java
+++ b/core/java/android/tv/TvView.java
@@ -16,10 +16,10 @@
 
 package android.tv;
 
-import android.content.ComponentName;
 import android.content.Context;
 import android.graphics.Rect;
 import android.os.Handler;
+import android.text.TextUtils;
 import android.tv.TvInputManager.Session;
 import android.tv.TvInputManager.Session.FinishedInputEventCallback;
 import android.tv.TvInputManager.SessionCreateCallback;
@@ -113,14 +113,14 @@
      * If a TV input is already bound, the input will be unbound from this view and its session
      * will be released.
      *
-     * @param name TV input name will be bound to this view.
+     * @param inputId the id of TV input which will be bound to this view.
      * @param callback called when TV input is bound. The callback sends
      *        {@link TvInputManager.Session}
      * @throws IllegalArgumentException if any of the arguments is {@code null}.
      */
-    public void bindTvInput(ComponentName name, SessionCreateCallback callback) {
-        if (name == null) {
-            throw new IllegalArgumentException("name cannot be null");
+    public void bindTvInput(String inputId, SessionCreateCallback callback) {
+        if (TextUtils.isEmpty(inputId)) {
+            throw new IllegalArgumentException("inputId cannot be null or an empty string");
         }
         if (callback == null) {
             throw new IllegalArgumentException("callback cannot be null");
@@ -134,7 +134,7 @@
         // is newly assigned for every bindTvInput call and compared with
         // MySessionCreateCallback.this.
         mSessionCreateCallback = new MySessionCreateCallback(callback);
-        mTvInputManager.createSession(name, mSessionCreateCallback, mHandler);
+        mTvInputManager.createSession(inputId, mSessionCreateCallback, mHandler);
     }
 
     /**
diff --git a/services/core/java/com/android/server/tv/TvInputManagerService.java b/services/core/java/com/android/server/tv/TvInputManagerService.java
index 50dd27d..5524bca 100644
--- a/services/core/java/com/android/server/tv/TvInputManagerService.java
+++ b/services/core/java/com/android/server/tv/TvInputManagerService.java
@@ -134,7 +134,7 @@
 
     private void buildTvInputListLocked(int userId) {
         UserState userState = getUserStateLocked(userId);
-        userState.inputList.clear();
+        userState.inputMap.clear();
 
         if (DEBUG) Slog.d(TAG, "buildTvInputList");
         PackageManager pm = mContext.getPackageManager();
@@ -149,7 +149,7 @@
             }
             TvInputInfo info = new TvInputInfo(ri);
             if (DEBUG) Slog.d(TAG, "add " + info.getId());
-            userState.inputList.add(info);
+            userState.inputMap.put(info.getId(), info);
         }
     }
 
@@ -179,9 +179,9 @@
             }
             // Release created sessions.
             for (SessionState state : userState.sessionStateMap.values()) {
-                if (state.session != null) {
+                if (state.mSession != null) {
                     try {
-                        state.session.release();
+                        state.mSession.release();
                     } catch (RemoteException e) {
                         Slog.e(TAG, "error in release", e);
                     }
@@ -191,15 +191,15 @@
 
             // Unregister all callbacks and unbind all services.
             for (ServiceState serviceState : userState.serviceStateMap.values()) {
-                if (serviceState.callback != null) {
+                if (serviceState.mCallback != null) {
                     try {
-                        serviceState.service.unregisterCallback(serviceState.callback);
+                        serviceState.mService.unregisterCallback(serviceState.mCallback);
                     } catch (RemoteException e) {
                         Slog.e(TAG, "error in unregisterCallback", e);
                     }
                 }
-                serviceState.clients.clear();
-                mContext.unbindService(serviceState.connection);
+                serviceState.mClients.clear();
+                mContext.unbindService(serviceState.mConnection);
             }
             userState.serviceStateMap.clear();
 
@@ -215,11 +215,11 @@
         return userState;
     }
 
-    private ServiceState getServiceStateLocked(ComponentName name, int userId) {
+    private ServiceState getServiceStateLocked(String inputId, int userId) {
         UserState userState = getUserStateLocked(userId);
-        ServiceState serviceState = userState.serviceStateMap.get(name);
+        ServiceState serviceState = userState.serviceStateMap.get(inputId);
         if (serviceState == null) {
-            throw new IllegalStateException("Service state not found for " + name + " (userId="
+            throw new IllegalStateException("Service state not found for " + inputId + " (userId="
                     + userId + ")");
         }
         return serviceState;
@@ -232,11 +232,11 @@
             throw new IllegalArgumentException("Session state not found for token " + sessionToken);
         }
         // Only the application that requested this session or the system can access it.
-        if (callingUid != Process.SYSTEM_UID && callingUid != sessionState.callingUid) {
+        if (callingUid != Process.SYSTEM_UID && callingUid != sessionState.mCallingUid) {
             throw new SecurityException("Illegal access to the session with token " + sessionToken
                     + " from uid " + callingUid);
         }
-        ITvInputSession session = sessionState.session;
+        ITvInputSession session = sessionState.mSession;
         if (session == null) {
             throw new IllegalStateException("Session not yet created for token " + sessionToken);
         }
@@ -249,38 +249,40 @@
                 false, methodName, null);
     }
 
-    private void updateServiceConnectionLocked(ComponentName name, int userId) {
+    private void updateServiceConnectionLocked(String inputId, int userId) {
         UserState userState = getUserStateLocked(userId);
-        ServiceState serviceState = userState.serviceStateMap.get(name);
+        ServiceState serviceState = userState.serviceStateMap.get(inputId);
         if (serviceState == null) {
             return;
         }
-        boolean isStateEmpty = serviceState.clients.isEmpty()
-                && serviceState.sessionTokens.isEmpty();
-        if (serviceState.service == null && !isStateEmpty && userId == mCurrentUserId) {
+        boolean isStateEmpty = serviceState.mClients.isEmpty()
+                && serviceState.mSessionTokens.isEmpty();
+        if (serviceState.mService == null && !isStateEmpty && userId == mCurrentUserId) {
             // This means that the service is not yet connected but its state indicates that we
             // have pending requests. Then, connect the service.
-            if (serviceState.bound) {
+            if (serviceState.mBound) {
                 // We have already bound to the service so we don't try to bind again until after we
                 // unbind later on.
                 return;
             }
             if (DEBUG) {
-                Slog.d(TAG, "bindServiceAsUser(name=" + name.getClassName() + ", userId=" + userId
+                Slog.d(TAG, "bindServiceAsUser(inputId=" + inputId + ", userId=" + userId
                         + ")");
             }
-            Intent i = new Intent(TvInputService.SERVICE_INTERFACE).setComponent(name);
-            mContext.bindServiceAsUser(i, serviceState.connection, Context.BIND_AUTO_CREATE,
+
+            Intent i = new Intent(TvInputService.SERVICE_INTERFACE).setComponent(
+                    userState.inputMap.get(inputId).getComponent());
+            mContext.bindServiceAsUser(i, serviceState.mConnection, Context.BIND_AUTO_CREATE,
                     new UserHandle(userId));
-            serviceState.bound = true;
-        } else if (serviceState.service != null && isStateEmpty) {
+            serviceState.mBound = true;
+        } else if (serviceState.mService != null && isStateEmpty) {
             // This means that the service is already connected but its state indicates that we have
             // nothing to do with it. Then, disconnect the service.
             if (DEBUG) {
-                Slog.d(TAG, "unbindService(name=" + name.getClassName() + ")");
+                Slog.d(TAG, "unbindService(inputId=" + inputId + ")");
             }
-            mContext.unbindService(serviceState.connection);
-            userState.serviceStateMap.remove(name);
+            mContext.unbindService(serviceState.mConnection);
+            userState.serviceStateMap.remove(inputId);
         }
     }
 
@@ -289,8 +291,7 @@
         final SessionState sessionState =
                 getUserStateLocked(userId).sessionStateMap.get(sessionToken);
         if (DEBUG) {
-            Slog.d(TAG, "createSessionInternalLocked(name=" + sessionState.name.getClassName()
-                    + ")");
+            Slog.d(TAG, "createSessionInternalLocked(inputId=" + sessionState.mInputId + ")");
         }
 
         final InputChannel[] channels = InputChannel.openInputChannelPair(sessionToken.toString());
@@ -300,17 +301,17 @@
             @Override
             public void onSessionCreated(ITvInputSession session) {
                 if (DEBUG) {
-                    Slog.d(TAG, "onSessionCreated(name=" + sessionState.name.getClassName() + ")");
+                    Slog.d(TAG, "onSessionCreated(inputId=" + sessionState.mInputId + ")");
                 }
                 synchronized (mLock) {
-                    sessionState.session = session;
+                    sessionState.mSession = session;
                     if (session == null) {
                         removeSessionStateLocked(sessionToken, userId);
-                        sendSessionTokenToClientLocked(sessionState.client, sessionState.name, null,
-                                null, sessionState.seq, userId);
+                        sendSessionTokenToClientLocked(sessionState.mClient, sessionState.mInputId, null,
+                                null, sessionState.mSeq, userId);
                     } else {
-                        sendSessionTokenToClientLocked(sessionState.client, sessionState.name,
-                                sessionToken, channels[0], sessionState.seq, userId);
+                        sendSessionTokenToClientLocked(sessionState.mClient, sessionState.mInputId,
+                                sessionToken, channels[0], sessionState.mSeq, userId);
                     }
                     channels[0].dispose();
                 }
@@ -323,23 +324,23 @@
         } catch (RemoteException e) {
             Slog.e(TAG, "error in createSession", e);
             removeSessionStateLocked(sessionToken, userId);
-            sendSessionTokenToClientLocked(sessionState.client, sessionState.name, null, null,
-                    sessionState.seq, userId);
+            sendSessionTokenToClientLocked(sessionState.mClient, sessionState.mInputId, null, null,
+                    sessionState.mSeq, userId);
         }
         channels[1].dispose();
     }
 
-    private void sendSessionTokenToClientLocked(ITvInputClient client, ComponentName name,
+    private void sendSessionTokenToClientLocked(ITvInputClient client, String inputId,
             IBinder sessionToken, InputChannel channel, int seq, int userId) {
         try {
-            client.onSessionCreated(name, sessionToken, channel, seq);
+            client.onSessionCreated(inputId, sessionToken, channel, seq);
         } catch (RemoteException exception) {
             Slog.e(TAG, "error in onSessionCreated", exception);
         }
 
         if (sessionToken == null) {
             // This means that the session creation failed. We might want to disconnect the service.
-            updateServiceConnectionLocked(name, userId);
+            updateServiceConnectionLocked(inputId, userId);
         }
     }
 
@@ -349,19 +350,19 @@
         SessionState sessionState = userState.sessionStateMap.remove(sessionToken);
 
         // Close the open log entry, if any.
-        if (sessionState.logUri != null) {
+        if (sessionState.mLogUri != null) {
             SomeArgs args = SomeArgs.obtain();
-            args.arg1 = sessionState.logUri;
+            args.arg1 = sessionState.mLogUri;
             args.arg2 = System.currentTimeMillis();
             mLogHandler.obtainMessage(LogHandler.MSG_CLOSE_ENTRY, args).sendToTarget();
         }
 
         // Also remove the session token from the session token list of the current service.
-        ServiceState serviceState = userState.serviceStateMap.get(sessionState.name);
+        ServiceState serviceState = userState.serviceStateMap.get(sessionState.mInputId);
         if (serviceState != null) {
-            serviceState.sessionTokens.remove(sessionToken);
+            serviceState.mSessionTokens.remove(sessionToken);
         }
-        updateServiceConnectionLocked(sessionState.name, userId);
+        updateServiceConnectionLocked(sessionState.mInputId, userId);
     }
 
     private final class BinderService extends ITvInputManager.Stub {
@@ -373,7 +374,7 @@
             try {
                 synchronized (mLock) {
                     UserState userState = getUserStateLocked(resolvedUserId);
-                    return new ArrayList<TvInputInfo>(userState.inputList);
+                    return new ArrayList<TvInputInfo>(userState.inputMap.values());
                 }
             } finally {
                 Binder.restoreCallingIdentity(identity);
@@ -381,7 +382,7 @@
         }
 
         @Override
-        public boolean getAvailability(final ITvInputClient client, final ComponentName name,
+        public boolean getAvailability(final ITvInputClient client, final String inputId,
                 int userId) {
             final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(),
                     Binder.getCallingUid(), userId, "getAvailability");
@@ -389,11 +390,11 @@
             try {
                 synchronized (mLock) {
                     UserState userState = getUserStateLocked(resolvedUserId);
-                    ServiceState serviceState = userState.serviceStateMap.get(name);
+                    ServiceState serviceState = userState.serviceStateMap.get(inputId);
                     if (serviceState != null) {
                         // We already know the status of this input service. Return the cached
                         // status.
-                        return serviceState.available;
+                        return serviceState.mAvailable;
                     }
                 }
             } finally {
@@ -403,7 +404,7 @@
         }
 
         @Override
-        public void registerCallback(final ITvInputClient client, final ComponentName name,
+        public void registerCallback(final ITvInputClient client, final String inputId,
                 int userId) {
             final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(),
                     Binder.getCallingUid(), userId, "registerCallback");
@@ -413,28 +414,29 @@
                     // Create a new service callback and add it to the callback map of the current
                     // service.
                     UserState userState = getUserStateLocked(resolvedUserId);
-                    ServiceState serviceState = userState.serviceStateMap.get(name);
+                    ServiceState serviceState = userState.serviceStateMap.get(inputId);
                     if (serviceState == null) {
-                        serviceState = new ServiceState(resolvedUserId);
-                        userState.serviceStateMap.put(name, serviceState);
+                        serviceState = new ServiceState(
+                                userState.inputMap.get(inputId), resolvedUserId);
+                        userState.serviceStateMap.put(inputId, serviceState);
                     }
                     IBinder iBinder = client.asBinder();
-                    if (!serviceState.clients.contains(iBinder)) {
-                        serviceState.clients.add(iBinder);
+                    if (!serviceState.mClients.contains(iBinder)) {
+                        serviceState.mClients.add(iBinder);
                     }
-                    if (serviceState.service != null) {
-                        if (serviceState.callback != null) {
+                    if (serviceState.mService != null) {
+                        if (serviceState.mCallback != null) {
                             // We already handled.
                             return;
                         }
-                        serviceState.callback = new ServiceCallback(resolvedUserId);
+                        serviceState.mCallback = new ServiceCallback(resolvedUserId);
                         try {
-                            serviceState.service.registerCallback(serviceState.callback);
+                            serviceState.mService.registerCallback(serviceState.mCallback);
                         } catch (RemoteException e) {
                             Slog.e(TAG, "error in registerCallback", e);
                         }
                     } else {
-                        updateServiceConnectionLocked(name, resolvedUserId);
+                        updateServiceConnectionLocked(inputId, resolvedUserId);
                     }
                 }
             } finally {
@@ -443,34 +445,34 @@
         }
 
         @Override
-        public void unregisterCallback(ITvInputClient client, ComponentName name, int userId) {
+        public void unregisterCallback(ITvInputClient client, String inputId, int userId) {
             final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(),
                     Binder.getCallingUid(), userId, "unregisterCallback");
             final long identity = Binder.clearCallingIdentity();
             try {
                 synchronized (mLock) {
                     UserState userState = getUserStateLocked(resolvedUserId);
-                    ServiceState serviceState = userState.serviceStateMap.get(name);
+                    ServiceState serviceState = userState.serviceStateMap.get(inputId);
                     if (serviceState == null) {
                         return;
                     }
 
                     // Remove this client from the client list and unregister the callback.
-                    serviceState.clients.remove(client.asBinder());
-                    if (!serviceState.clients.isEmpty()) {
+                    serviceState.mClients.remove(client.asBinder());
+                    if (!serviceState.mClients.isEmpty()) {
                         // We have other clients who want to keep the callback. Do this later.
                         return;
                     }
-                    if (serviceState.service == null || serviceState.callback == null) {
+                    if (serviceState.mService == null || serviceState.mCallback == null) {
                         return;
                     }
                     try {
-                        serviceState.service.unregisterCallback(serviceState.callback);
+                        serviceState.mService.unregisterCallback(serviceState.mCallback);
                     } catch (RemoteException e) {
                         Slog.e(TAG, "error in unregisterCallback", e);
                     } finally {
-                        serviceState.callback = null;
-                        updateServiceConnectionLocked(name, resolvedUserId);
+                        serviceState.mCallback = null;
+                        updateServiceConnectionLocked(inputId, resolvedUserId);
                     }
                 }
             } finally {
@@ -479,7 +481,7 @@
         }
 
         @Override
-        public void createSession(final ITvInputClient client, final ComponentName name,
+        public void createSession(final ITvInputClient client, final String inputId,
                 int seq, int userId) {
             final int callingUid = Binder.getCallingUid();
             final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
@@ -489,26 +491,27 @@
                 synchronized (mLock) {
                     // Create a new session token and a session state.
                     IBinder sessionToken = new Binder();
-                    SessionState sessionState = new SessionState(name, client, seq, callingUid);
-                    sessionState.session = null;
+                    SessionState sessionState = new SessionState(inputId, client, seq, callingUid);
+                    sessionState.mSession = null;
 
                     // Add them to the global session state map of the current user.
                     UserState userState = getUserStateLocked(resolvedUserId);
                     userState.sessionStateMap.put(sessionToken, sessionState);
 
                     // Also, add them to the session state map of the current service.
-                    ServiceState serviceState = userState.serviceStateMap.get(name);
+                    ServiceState serviceState = userState.serviceStateMap.get(inputId);
                     if (serviceState == null) {
-                        serviceState = new ServiceState(resolvedUserId);
-                        userState.serviceStateMap.put(name, serviceState);
+                        serviceState = new ServiceState(
+                                userState.inputMap.get(inputId), resolvedUserId);
+                        userState.serviceStateMap.put(inputId, serviceState);
                     }
-                    serviceState.sessionTokens.add(sessionToken);
+                    serviceState.mSessionTokens.add(sessionToken);
 
-                    if (serviceState.service != null) {
-                        createSessionInternalLocked(serviceState.service, sessionToken,
+                    if (serviceState.mService != null) {
+                        createSessionInternalLocked(serviceState.mService, sessionToken,
                                 resolvedUserId);
                     } else {
-                        updateServiceConnectionLocked(name, resolvedUserId);
+                        updateServiceConnectionLocked(inputId, resolvedUserId);
                     }
                 }
             } finally {
@@ -599,9 +602,9 @@
                         // Close the open log entry first, if any.
                         UserState userState = getUserStateLocked(resolvedUserId);
                         SessionState sessionState = userState.sessionStateMap.get(sessionToken);
-                        if (sessionState.logUri != null) {
+                        if (sessionState.mLogUri != null) {
                             SomeArgs args = SomeArgs.obtain();
-                            args.arg1 = sessionState.logUri;
+                            args.arg1 = sessionState.mLogUri;
                             args.arg2 = currentTime;
                             mLogHandler.obtainMessage(LogHandler.MSG_CLOSE_ENTRY, args)
                                     .sendToTarget();
@@ -614,10 +617,10 @@
                         values.put(TvContract.WatchedPrograms.WATCH_END_TIME_UTC_MILLIS, 0);
                         values.put(TvContract.WatchedPrograms.CHANNEL_ID, channelId);
 
-                        sessionState.logUri = mContentResolver.insert(
+                        sessionState.mLogUri = mContentResolver.insert(
                                 TvContract.WatchedPrograms.CONTENT_URI, values);
                         SomeArgs args = SomeArgs.obtain();
-                        args.arg1 = sessionState.logUri;
+                        args.arg1 = sessionState.mLogUri;
                         args.arg2 = ContentUris.parseId(channelUri);
                         args.arg3 = currentTime;
                         mLogHandler.obtainMessage(LogHandler.MSG_OPEN_ENTRY, args).sendToTarget();
@@ -694,12 +697,12 @@
     }
 
     private static final class UserState {
-        // A list of all known TV inputs on the system.
-        private final List<TvInputInfo> inputList = new ArrayList<TvInputInfo>();
+        // A mapping from the TV input id to its TvInputInfo.
+        private final Map<String, TvInputInfo> inputMap = new HashMap<String,TvInputInfo>();
 
         // A mapping from the name of a TV input service to its state.
-        private final Map<ComponentName, ServiceState> serviceStateMap =
-                new HashMap<ComponentName, ServiceState>();
+        private final Map<String, ServiceState> serviceStateMap =
+                new HashMap<String, ServiceState>();
 
         // A mapping from the token of a TV input session to its state.
         private final Map<IBinder, SessionState> sessionStateMap =
@@ -707,66 +710,68 @@
     }
 
     private final class ServiceState {
-        private final List<IBinder> clients = new ArrayList<IBinder>();
-        private final List<IBinder> sessionTokens = new ArrayList<IBinder>();
-        private final ServiceConnection connection;
+        private final List<IBinder> mClients = new ArrayList<IBinder>();
+        private final List<IBinder> mSessionTokens = new ArrayList<IBinder>();
+        private final ServiceConnection mConnection;
 
-        private ITvInputService service;
-        private ServiceCallback callback;
-        private boolean bound;
-        private boolean available;
+        private ITvInputService mService;
+        private ServiceCallback mCallback;
+        private boolean mBound;
+        private boolean mAvailable;
 
-        private ServiceState(int userId) {
-            this.connection = new InputServiceConnection(userId);
+        private ServiceState(TvInputInfo inputInfo, int userId) {
+            this.mConnection = new InputServiceConnection(inputInfo, userId);
         }
     }
 
     private static final class SessionState {
-        private final ComponentName name;
-        private final ITvInputClient client;
-        private final int seq;
-        private final int callingUid;
+        private final String mInputId;
+        private final ITvInputClient mClient;
+        private final int mSeq;
+        private final int mCallingUid;
 
-        private ITvInputSession session;
-        private Uri logUri;
+        private ITvInputSession mSession;
+        private Uri mLogUri;
 
-        private SessionState(ComponentName name, ITvInputClient client, int seq, int callingUid) {
-            this.name = name;
-            this.client = client;
-            this.seq = seq;
-            this.callingUid = callingUid;
+        private SessionState(String inputId, ITvInputClient client, int seq, int callingUid) {
+            this.mInputId = inputId;
+            this.mClient = client;
+            this.mSeq = seq;
+            this.mCallingUid = callingUid;
         }
     }
 
     private final class InputServiceConnection implements ServiceConnection {
+        private final TvInputInfo mTvInputInfo;
         private final int mUserId;
 
-        private InputServiceConnection(int userId) {
+        private InputServiceConnection(TvInputInfo inputInfo, int userId) {
             mUserId = userId;
+            mTvInputInfo = inputInfo;
         }
 
         @Override
         public void onServiceConnected(ComponentName name, IBinder service) {
             if (DEBUG) {
-                Slog.d(TAG, "onServiceConnected(name=" + name.getClassName() + ")");
+                Slog.d(TAG, "onServiceConnected(inputId=" + mTvInputInfo.getId() + ")");
             }
             synchronized (mLock) {
-                ServiceState serviceState = getServiceStateLocked(name, mUserId);
-                serviceState.service = ITvInputService.Stub.asInterface(service);
+                ServiceState serviceState = getServiceStateLocked(mTvInputInfo.getId(), mUserId);
+                serviceState.mService = ITvInputService.Stub.asInterface(service);
 
                 // Register a callback, if we need to.
-                if (!serviceState.clients.isEmpty() && serviceState.callback == null) {
-                    serviceState.callback = new ServiceCallback(mUserId);
+                if (!serviceState.mClients.isEmpty() && serviceState.mCallback == null) {
+                    serviceState.mCallback = new ServiceCallback(mUserId);
                     try {
-                        serviceState.service.registerCallback(serviceState.callback);
+                        serviceState.mService.registerCallback(serviceState.mCallback);
                     } catch (RemoteException e) {
                         Slog.e(TAG, "error in registerCallback", e);
                     }
                 }
 
                 // And create sessions, if any.
-                for (IBinder sessionToken : serviceState.sessionTokens) {
-                    createSessionInternalLocked(serviceState.service, sessionToken, mUserId);
+                for (IBinder sessionToken : serviceState.mSessionTokens) {
+                    createSessionInternalLocked(serviceState.mService, sessionToken, mUserId);
                 }
             }
         }
@@ -774,7 +779,7 @@
         @Override
         public void onServiceDisconnected(ComponentName name) {
             if (DEBUG) {
-                Slog.d(TAG, "onServiceDisconnected(name=" + name.getClassName() + ")");
+                Slog.d(TAG, "onServiceDisconnected(inputId=" + mTvInputInfo.getId() + ")");
             }
         }
     }
@@ -787,18 +792,18 @@
         }
 
         @Override
-        public void onAvailabilityChanged(ComponentName name, boolean isAvailable)
+        public void onAvailabilityChanged(String inputId, boolean isAvailable)
                 throws RemoteException {
             if (DEBUG) {
-                Slog.d(TAG, "onAvailabilityChanged(name=" + name.getClassName() + ", isAvailable="
+                Slog.d(TAG, "onAvailabilityChanged(inputId=" + inputId + ", isAvailable="
                         + isAvailable + ")");
             }
             synchronized (mLock) {
-                ServiceState serviceState = getServiceStateLocked(name, mUserId);
-                serviceState.available = isAvailable;
-                for (IBinder iBinder : serviceState.clients) {
+                ServiceState serviceState = getServiceStateLocked(inputId, mUserId);
+                serviceState.mAvailable = isAvailable;
+                for (IBinder iBinder : serviceState.mClients) {
                     ITvInputClient client = ITvInputClient.Stub.asInterface(iBinder);
-                    client.onAvailabilityChanged(name, isAvailable);
+                    client.onAvailabilityChanged(inputId, isAvailable);
                 }
             }
         }