TvInputManagerService.java revision abca0ee7949f59e72b8d2764dafa23af18eb51db
13957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo/*
23957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo * Copyright (C) 2014 The Android Open Source Project
33957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo *
43957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo * Licensed under the Apache License, Version 2.0 (the "License");
53957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo * you may not use this file except in compliance with the License.
63957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo * You may obtain a copy of the License at
73957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo *
83957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo *      http://www.apache.org/licenses/LICENSE-2.0
93957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo *
103957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo * Unless required by applicable law or agreed to in writing, software
113957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo * distributed under the License is distributed on an "AS IS" BASIS,
123957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
133957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo * See the License for the specific language governing permissions and
143957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo * limitations under the License.
153957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo */
163957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
173957091ba8f08c02b5e781098cb955a5f697a1ffJae Seopackage com.android.server.tv;
183957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
19969167dc05a6485a32d160895871cff46fd81884Wonsik Kimimport static android.media.tv.TvInputManager.INPUT_STATE_CONNECTED;
20969167dc05a6485a32d160895871cff46fd81884Wonsik Kimimport static android.media.tv.TvInputManager.INPUT_STATE_DISCONNECTED;
21969167dc05a6485a32d160895871cff46fd81884Wonsik Kim
223957091ba8f08c02b5e781098cb955a5f697a1ffJae Seoimport android.app.ActivityManager;
233957091ba8f08c02b5e781098cb955a5f697a1ffJae Seoimport android.content.BroadcastReceiver;
243957091ba8f08c02b5e781098cb955a5f697a1ffJae Seoimport android.content.ComponentName;
255c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seoimport android.content.ContentProviderOperation;
265c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seoimport android.content.ContentProviderResult;
2731dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seoimport android.content.ContentResolver;
2831dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seoimport android.content.ContentUris;
2931dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seoimport android.content.ContentValues;
303957091ba8f08c02b5e781098cb955a5f697a1ffJae Seoimport android.content.Context;
313957091ba8f08c02b5e781098cb955a5f697a1ffJae Seoimport android.content.Intent;
323957091ba8f08c02b5e781098cb955a5f697a1ffJae Seoimport android.content.IntentFilter;
335c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seoimport android.content.OperationApplicationException;
343957091ba8f08c02b5e781098cb955a5f697a1ffJae Seoimport android.content.ServiceConnection;
353957091ba8f08c02b5e781098cb955a5f697a1ffJae Seoimport android.content.pm.PackageManager;
363957091ba8f08c02b5e781098cb955a5f697a1ffJae Seoimport android.content.pm.ResolveInfo;
373957091ba8f08c02b5e781098cb955a5f697a1ffJae Seoimport android.content.pm.ServiceInfo;
3831dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seoimport android.database.Cursor;
399a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Choimport android.graphics.Rect;
40187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kimimport android.hardware.hdmi.HdmiCecDeviceInfo;
41d5cc4a281e7ce29d1e8687ff3394b57a3a549260Jae Seoimport android.media.tv.ITvInputClient;
42d5cc4a281e7ce29d1e8687ff3394b57a3a549260Jae Seoimport android.media.tv.ITvInputHardware;
43d5cc4a281e7ce29d1e8687ff3394b57a3a549260Jae Seoimport android.media.tv.ITvInputHardwareCallback;
44d5cc4a281e7ce29d1e8687ff3394b57a3a549260Jae Seoimport android.media.tv.ITvInputManager;
45969167dc05a6485a32d160895871cff46fd81884Wonsik Kimimport android.media.tv.ITvInputManagerCallback;
46d5cc4a281e7ce29d1e8687ff3394b57a3a549260Jae Seoimport android.media.tv.ITvInputService;
47d5cc4a281e7ce29d1e8687ff3394b57a3a549260Jae Seoimport android.media.tv.ITvInputServiceCallback;
48d5cc4a281e7ce29d1e8687ff3394b57a3a549260Jae Seoimport android.media.tv.ITvInputSession;
49d5cc4a281e7ce29d1e8687ff3394b57a3a549260Jae Seoimport android.media.tv.ITvInputSessionCallback;
50d5cc4a281e7ce29d1e8687ff3394b57a3a549260Jae Seoimport android.media.tv.TvContract;
51d5cc4a281e7ce29d1e8687ff3394b57a3a549260Jae Seoimport android.media.tv.TvInputHardwareInfo;
52d5cc4a281e7ce29d1e8687ff3394b57a3a549260Jae Seoimport android.media.tv.TvInputInfo;
53d5cc4a281e7ce29d1e8687ff3394b57a3a549260Jae Seoimport android.media.tv.TvInputService;
54c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heoimport android.media.tv.TvStreamConfig;
551f213914c45c23c653f721690da2ce0718e63139Dongwon Kangimport android.media.tv.TvTrackInfo;
563957091ba8f08c02b5e781098cb955a5f697a1ffJae Seoimport android.net.Uri;
573957091ba8f08c02b5e781098cb955a5f697a1ffJae Seoimport android.os.Binder;
58832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Choimport android.os.Bundle;
5931dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seoimport android.os.Handler;
603957091ba8f08c02b5e781098cb955a5f697a1ffJae Seoimport android.os.IBinder;
6131dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seoimport android.os.Looper;
6231dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seoimport android.os.Message;
633957091ba8f08c02b5e781098cb955a5f697a1ffJae Seoimport android.os.Process;
643957091ba8f08c02b5e781098cb955a5f697a1ffJae Seoimport android.os.RemoteException;
653957091ba8f08c02b5e781098cb955a5f697a1ffJae Seoimport android.os.UserHandle;
669a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Choimport android.util.Slog;
673957091ba8f08c02b5e781098cb955a5f697a1ffJae Seoimport android.util.SparseArray;
686a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seoimport android.view.InputChannel;
693957091ba8f08c02b5e781098cb955a5f697a1ffJae Seoimport android.view.Surface;
703957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
713957091ba8f08c02b5e781098cb955a5f697a1ffJae Seoimport com.android.internal.content.PackageMonitor;
7231dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seoimport com.android.internal.os.SomeArgs;
73e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kimimport com.android.internal.util.IndentingPrintWriter;
7431dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seoimport com.android.server.IoThread;
753957091ba8f08c02b5e781098cb955a5f697a1ffJae Seoimport com.android.server.SystemService;
763957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
77e7bb7d6bb2257c24076f5a4b9f536f90a6637f58Chulwoo Leeimport org.xmlpull.v1.XmlPullParserException;
78e7bb7d6bb2257c24076f5a4b9f536f90a6637f58Chulwoo Lee
79e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kimimport java.io.FileDescriptor;
80e7bb7d6bb2257c24076f5a4b9f536f90a6637f58Chulwoo Leeimport java.io.IOException;
81e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kimimport java.io.PrintWriter;
823957091ba8f08c02b5e781098cb955a5f697a1ffJae Seoimport java.util.ArrayList;
833957091ba8f08c02b5e781098cb955a5f697a1ffJae Seoimport java.util.HashMap;
845c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seoimport java.util.HashSet;
85187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kimimport java.util.Iterator;
863957091ba8f08c02b5e781098cb955a5f697a1ffJae Seoimport java.util.List;
873957091ba8f08c02b5e781098cb955a5f697a1ffJae Seoimport java.util.Map;
885c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seoimport java.util.Set;
893957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
903957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo/** This class provides a system service that manages television inputs. */
913957091ba8f08c02b5e781098cb955a5f697a1ffJae Seopublic final class TvInputManagerService extends SystemService {
923957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    // STOPSHIP: Turn debugging off.
933957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    private static final boolean DEBUG = true;
943957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    private static final String TAG = "TvInputManagerService";
953957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
963957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    private final Context mContext;
97c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim    private final TvInputHardwareManager mTvInputHardwareManager;
983957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
9931dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo    private final ContentResolver mContentResolver;
10031dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo
1013957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    // A global lock.
1023957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    private final Object mLock = new Object();
1033957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
1043957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    // ID of the current user.
1053957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    private int mCurrentUserId = UserHandle.USER_OWNER;
1063957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
1073957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    // A map from user id to UserState.
1083957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    private final SparseArray<UserState> mUserStates = new SparseArray<UserState>();
1093957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
11031dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo    private final Handler mLogHandler;
11131dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo
1123957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    public TvInputManagerService(Context context) {
1133957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        super(context);
11431dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo
1153957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        mContext = context;
11631dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo        mContentResolver = context.getContentResolver();
11731dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo        mLogHandler = new LogHandler(IoThread.get().getLooper());
11831dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo
119187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim        mTvInputHardwareManager = new TvInputHardwareManager(context, new HardwareListener());
12031dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo
1213957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        synchronized (mLock) {
1223957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            mUserStates.put(mCurrentUserId, new UserState());
1233957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
1243957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    }
1253957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
1263957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    @Override
1273957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    public void onStart() {
1283957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        publishBinderService(Context.TV_INPUT_SERVICE, new BinderService());
1293957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    }
1303957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
1310ceb7e4755015eafda29c251eac285620788a51bJi-Hwan Lee    @Override
1320ceb7e4755015eafda29c251eac285620788a51bJi-Hwan Lee    public void onBootPhase(int phase) {
1330ceb7e4755015eafda29c251eac285620788a51bJi-Hwan Lee        if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY) {
1340ceb7e4755015eafda29c251eac285620788a51bJi-Hwan Lee            registerBroadcastReceivers();
135187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim        } else if (phase == SystemService.PHASE_THIRD_PARTY_APPS_CAN_START) {
1360ceb7e4755015eafda29c251eac285620788a51bJi-Hwan Lee            synchronized (mLock) {
1370ceb7e4755015eafda29c251eac285620788a51bJi-Hwan Lee                buildTvInputListLocked(mCurrentUserId);
1380ceb7e4755015eafda29c251eac285620788a51bJi-Hwan Lee            }
1390ceb7e4755015eafda29c251eac285620788a51bJi-Hwan Lee        }
140969167dc05a6485a32d160895871cff46fd81884Wonsik Kim        mTvInputHardwareManager.onBootPhase(phase);
1410ceb7e4755015eafda29c251eac285620788a51bJi-Hwan Lee    }
1420ceb7e4755015eafda29c251eac285620788a51bJi-Hwan Lee
1433957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    private void registerBroadcastReceivers() {
1443957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        PackageMonitor monitor = new PackageMonitor() {
1453957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            @Override
1463957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            public void onSomePackagesChanged() {
1473957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                synchronized (mLock) {
1483957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    buildTvInputListLocked(mCurrentUserId);
1493957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                }
1503957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            }
1515c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo
1525c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo            @Override
1535c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo            public void onPackageRemoved(String packageName, int uid) {
1545c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo                synchronized (mLock) {
1555c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo                    UserState userState = getUserStateLocked(mCurrentUserId);
156969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                    if (!userState.packageSet.contains(packageName)) {
1575c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo                        // Not a TV input package.
1585c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo                        return;
1595c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo                    }
1605c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo                }
1615c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo
1625c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo                ArrayList<ContentProviderOperation> operations =
1635c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo                        new ArrayList<ContentProviderOperation>();
1645c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo
1655c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo                String selection = TvContract.BaseTvColumns.COLUMN_PACKAGE_NAME + "=?";
1665c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo                String[] selectionArgs = { packageName };
1675c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo
1685c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo                operations.add(ContentProviderOperation.newDelete(TvContract.Channels.CONTENT_URI)
1695c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo                        .withSelection(selection, selectionArgs).build());
1705c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo                operations.add(ContentProviderOperation.newDelete(TvContract.Programs.CONTENT_URI)
1715c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo                        .withSelection(selection, selectionArgs).build());
1725c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo                operations.add(ContentProviderOperation
1735c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo                        .newDelete(TvContract.WatchedPrograms.CONTENT_URI)
1745c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo                        .withSelection(selection, selectionArgs).build());
1755c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo
1765c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo                ContentProviderResult[] results = null;
1775c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo                try {
1785c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo                    results = mContentResolver.applyBatch(TvContract.AUTHORITY, operations);
1795c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo                } catch (RemoteException | OperationApplicationException e) {
1805c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo                    Slog.e(TAG, "error in applyBatch" + e);
1815c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo                }
1825c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo
1835c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo                if (DEBUG) {
1845c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo                    Slog.d(TAG, "onPackageRemoved(packageName=" + packageName + ", uid=" + uid
1855c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo                            + ")");
1865c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo                    Slog.d(TAG, "results=" + results);
1875c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo                }
1885c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo            }
1893957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        };
1903957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        monitor.register(mContext, null, UserHandle.ALL, true);
1913957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
1923957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        IntentFilter intentFilter = new IntentFilter();
1933957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        intentFilter.addAction(Intent.ACTION_USER_SWITCHED);
1943957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        intentFilter.addAction(Intent.ACTION_USER_REMOVED);
1953957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        mContext.registerReceiverAsUser(new BroadcastReceiver() {
1963957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            @Override
1973957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            public void onReceive(Context context, Intent intent) {
1983957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                String action = intent.getAction();
1993957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                if (Intent.ACTION_USER_SWITCHED.equals(action)) {
2003957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    switchUser(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0));
2013957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                } else if (Intent.ACTION_USER_REMOVED.equals(action)) {
2023957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    removeUser(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0));
2033957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                }
2043957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            }
2053957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }, UserHandle.ALL, intentFilter, null, null);
2063957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    }
2073957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
208187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim    private static boolean hasHardwarePermission(PackageManager pm, ComponentName name) {
209187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim        return pm.checkPermission(android.Manifest.permission.TV_INPUT_HARDWARE,
210187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                name.getPackageName()) == PackageManager.PERMISSION_GRANTED;
211187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim    }
212187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim
2133957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    private void buildTvInputListLocked(int userId) {
2143957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        UserState userState = getUserStateLocked(userId);
215969167dc05a6485a32d160895871cff46fd81884Wonsik Kim
2168e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim        Map<String, TvInputState> inputMap = new HashMap<String, TvInputState>();
217969167dc05a6485a32d160895871cff46fd81884Wonsik Kim        userState.packageSet.clear();
2183957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
2199a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho        if (DEBUG) Slog.d(TAG, "buildTvInputList");
2203957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        PackageManager pm = mContext.getPackageManager();
2213957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        List<ResolveInfo> services = pm.queryIntentServices(
222e7bb7d6bb2257c24076f5a4b9f536f90a6637f58Chulwoo Lee                new Intent(TvInputService.SERVICE_INTERFACE),
223e7bb7d6bb2257c24076f5a4b9f536f90a6637f58Chulwoo Lee                PackageManager.GET_SERVICES | PackageManager.GET_META_DATA);
2244f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee        List<TvInputInfo> inputList = new ArrayList<TvInputInfo>();
2253957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        for (ResolveInfo ri : services) {
2263957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            ServiceInfo si = ri.serviceInfo;
2273957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            if (!android.Manifest.permission.BIND_TV_INPUT.equals(si.permission)) {
2289a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                Slog.w(TAG, "Skipping TV input " + si.name + ": it does not require the permission "
2293957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                        + android.Manifest.permission.BIND_TV_INPUT);
2303957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                continue;
2313957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            }
232e7bb7d6bb2257c24076f5a4b9f536f90a6637f58Chulwoo Lee            try {
2334f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                inputList.clear();
234187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                ComponentName service = new ComponentName(si.packageName, si.name);
235187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                if (hasHardwarePermission(pm, service)) {
236187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                    ServiceState serviceState = userState.serviceStateMap.get(service);
237187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                    if (serviceState == null) {
238187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                        // We see this hardware TV input service for the first time; we need to
239187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                        // prepare the ServiceState object so that we can connect to the service and
240187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                        // let it add TvInputInfo objects to mInputList if there's any.
241187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                        serviceState = new ServiceState(service, userId);
242187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                        userState.serviceStateMap.put(service, serviceState);
243187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                    } else {
2444f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                        inputList.addAll(serviceState.mInputList);
245187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                    }
246187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                } else {
2474f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                    inputList.add(TvInputInfo.createTvInputInfo(mContext, ri));
248187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                }
249187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim
2504f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                for (TvInputInfo info : inputList) {
251187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                    if (DEBUG) Slog.d(TAG, "add " + info.getId());
2528e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim                    TvInputState state = userState.inputMap.get(info.getId());
253187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                    if (state == null) {
254187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                        state = new TvInputState();
255187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                    }
256187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                    state.mInfo = info;
2578e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim                    inputMap.put(info.getId(), state);
258969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                }
259226a51958d645a8e2be3e40a6b6daaca558b4913Jaewan Kim
260226a51958d645a8e2be3e40a6b6daaca558b4913Jaewan Kim                // Reconnect the service if existing input is updated.
261187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                updateServiceConnectionLocked(service, userId);
262187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim
263187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                userState.packageSet.add(si.packageName);
264e7bb7d6bb2257c24076f5a4b9f536f90a6637f58Chulwoo Lee            } catch (IOException | XmlPullParserException e) {
265e7bb7d6bb2257c24076f5a4b9f536f90a6637f58Chulwoo Lee                Slog.e(TAG, "Can't load TV input " + si.name, e);
266e7bb7d6bb2257c24076f5a4b9f536f90a6637f58Chulwoo Lee            }
2673957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
2688e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim
2698e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim        for (String inputId : inputMap.keySet()) {
2708e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim            if (!userState.inputMap.containsKey(inputId)) {
2718e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim                notifyInputAddedLocked(userState, inputId);
2728e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim            }
2738e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim        }
2748e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim
2758e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim        for (String inputId : userState.inputMap.keySet()) {
2768e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim            if (!inputMap.containsKey(inputId)) {
2778e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim                notifyInputRemovedLocked(userState, inputId);
2788e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim            }
2798e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim        }
2808e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim
2818e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim        userState.inputMap.clear();
2828e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim        userState.inputMap = inputMap;
2833957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    }
2843957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
2853957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    private void switchUser(int userId) {
2863957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        synchronized (mLock) {
2873957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            if (mCurrentUserId == userId) {
2883957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                return;
2893957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            }
2903957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            // final int oldUserId = mCurrentUserId;
2913957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            // TODO: Release services and sessions in the old user state, if needed.
2923957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            mCurrentUserId = userId;
2933957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
2943957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            UserState userState = mUserStates.get(userId);
2953957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            if (userState == null) {
2963957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                userState = new UserState();
2973957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            }
2983957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            mUserStates.put(userId, userState);
2993957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            buildTvInputListLocked(userId);
3003957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
3013957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    }
3023957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
3033957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    private void removeUser(int userId) {
3043957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        synchronized (mLock) {
305b06cb8870f0407f18bb1225065a93aba2a5de2bfJae Seo            UserState userState = mUserStates.get(userId);
306b06cb8870f0407f18bb1225065a93aba2a5de2bfJae Seo            if (userState == null) {
307b06cb8870f0407f18bb1225065a93aba2a5de2bfJae Seo                return;
308b06cb8870f0407f18bb1225065a93aba2a5de2bfJae Seo            }
3093957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            // Release created sessions.
3103957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            for (SessionState state : userState.sessionStateMap.values()) {
311d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim                if (state.mSession != null) {
3123957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    try {
313d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim                        state.mSession.release();
3143957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    } catch (RemoteException e) {
3159a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                        Slog.e(TAG, "error in release", e);
3163957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    }
3173957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                }
3183957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            }
3193957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            userState.sessionStateMap.clear();
3203957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
3213957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            // Unregister all callbacks and unbind all services.
3223957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            for (ServiceState serviceState : userState.serviceStateMap.values()) {
323d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim                if (serviceState.mCallback != null) {
3243957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    try {
325d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim                        serviceState.mService.unregisterCallback(serviceState.mCallback);
3263957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    } catch (RemoteException e) {
3279a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                        Slog.e(TAG, "error in unregisterCallback", e);
3283957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    }
3293957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                }
33072ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim                serviceState.mClientTokens.clear();
331d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim                mContext.unbindService(serviceState.mConnection);
3323957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            }
3333957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            userState.serviceStateMap.clear();
3343957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
33572ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim            userState.clientStateMap.clear();
33672ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim
3373957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            mUserStates.remove(userId);
3383957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
3393957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    }
3403957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
3413957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    private UserState getUserStateLocked(int userId) {
3423957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        UserState userState = mUserStates.get(userId);
3433957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        if (userState == null) {
3443957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            throw new IllegalStateException("User state not found for user ID " + userId);
3453957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
3463957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        return userState;
3473957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    }
3483957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
349187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim    private ServiceState getServiceStateLocked(ComponentName name, int userId) {
3503957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        UserState userState = getUserStateLocked(userId);
351187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim        ServiceState serviceState = userState.serviceStateMap.get(name);
3523957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        if (serviceState == null) {
353187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim            throw new IllegalStateException("Service state not found for " + name + " (userId="
3547de5e234715a3baa8905afa3dd0c5009af64541fSungsoo Lim                    + userId + ")");
3553957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
3563957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        return serviceState;
3573957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    }
3583957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
3592b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim    private SessionState getSessionStateLocked(IBinder sessionToken, int callingUid, int userId) {
3603957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        UserState userState = getUserStateLocked(userId);
3613957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        SessionState sessionState = userState.sessionStateMap.get(sessionToken);
3623957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        if (sessionState == null) {
3633957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            throw new IllegalArgumentException("Session state not found for token " + sessionToken);
3643957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
3653957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        // Only the application that requested this session or the system can access it.
366d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim        if (callingUid != Process.SYSTEM_UID && callingUid != sessionState.mCallingUid) {
3673957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            throw new SecurityException("Illegal access to the session with token " + sessionToken
3683957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    + " from uid " + callingUid);
3693957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
3702b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim        return sessionState;
3712b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim    }
3722b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim
3732b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim    private ITvInputSession getSessionLocked(IBinder sessionToken, int callingUid, int userId) {
3744c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee        return getSessionLocked(getSessionStateLocked(sessionToken, callingUid, userId));
3754c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee    }
3764c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee
3774c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee    private ITvInputSession getSessionLocked(SessionState sessionState) {
378d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim        ITvInputSession session = sessionState.mSession;
3793957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        if (session == null) {
3804c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee            throw new IllegalStateException("Session not yet created for token "
3814c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee                    + sessionState.mSessionToken);
3823957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
3833957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        return session;
3843957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    }
3853957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
3863957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    private int resolveCallingUserId(int callingPid, int callingUid, int requestedUserId,
3873957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            String methodName) {
3883957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        return ActivityManager.handleIncomingUser(callingPid, callingUid, requestedUserId, false,
3893957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                false, methodName, null);
3903957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    }
3913957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
392187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim    private static boolean shouldMaintainConnection(ServiceState serviceState) {
393187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim        return !serviceState.mClientTokens.isEmpty()
394187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                || !serviceState.mSessionTokens.isEmpty()
395187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                || serviceState.mIsHardware;
396187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim        // TODO: Find a way to maintain connection only when necessary.
397187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim    }
398187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim
399187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim    private void updateServiceConnectionLocked(ComponentName service, int userId) {
4003957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        UserState userState = getUserStateLocked(userId);
401187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim        ServiceState serviceState = userState.serviceStateMap.get(service);
4023957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        if (serviceState == null) {
4033957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            return;
4043957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
4052b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim        if (serviceState.mReconnecting) {
4062b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim            if (!serviceState.mSessionTokens.isEmpty()) {
4072b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                // wait until all the sessions are removed.
4082b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                return;
4092b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim            }
4102b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim            serviceState.mReconnecting = false;
4112b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim        }
412187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim        boolean maintainConnection = shouldMaintainConnection(serviceState);
413187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim        if (serviceState.mService == null && maintainConnection && userId == mCurrentUserId) {
4143957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            // This means that the service is not yet connected but its state indicates that we
4153957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            // have pending requests. Then, connect the service.
416d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim            if (serviceState.mBound) {
4173957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                // We have already bound to the service so we don't try to bind again until after we
4183957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                // unbind later on.
4193957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                return;
4203957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            }
4213957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            if (DEBUG) {
422187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                Slog.d(TAG, "bindServiceAsUser(service=" + service + ", userId=" + userId + ")");
4233957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            }
424d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim
425187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim            Intent i = new Intent(TvInputService.SERVICE_INTERFACE).setComponent(service);
426226a51958d645a8e2be3e40a6b6daaca558b4913Jaewan Kim            // Binding service may fail if the service is updating.
427226a51958d645a8e2be3e40a6b6daaca558b4913Jaewan Kim            // In that case, the connection will be revived in buildTvInputListLocked called by
428226a51958d645a8e2be3e40a6b6daaca558b4913Jaewan Kim            // onSomePackagesChanged.
429e17b2dd7bcc137bf4d842a779e8d62c63957a978Ji-Hwan Lee            serviceState.mBound = mContext.bindServiceAsUser(
430e17b2dd7bcc137bf4d842a779e8d62c63957a978Ji-Hwan Lee                    i, serviceState.mConnection, Context.BIND_AUTO_CREATE, new UserHandle(userId));
431187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim        } else if (serviceState.mService != null && !maintainConnection) {
4323957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            // This means that the service is already connected but its state indicates that we have
4333957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            // nothing to do with it. Then, disconnect the service.
4343957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            if (DEBUG) {
435187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                Slog.d(TAG, "unbindService(service=" + service + ")");
4363957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            }
437d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim            mContext.unbindService(serviceState.mConnection);
438187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim            userState.serviceStateMap.remove(service);
4393957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
4403957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    }
4413957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
44272ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim    private ClientState createClientStateLocked(IBinder clientToken, int userId) {
44372ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim        UserState userState = getUserStateLocked(userId);
44472ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim        ClientState clientState = new ClientState(clientToken, userId);
44572ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim        try {
44672ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim            clientToken.linkToDeath(clientState, 0);
44772ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim        } catch (RemoteException e) {
44872ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim            Slog.e(TAG, "Client is already died.");
44972ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim        }
45072ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim        userState.clientStateMap.put(clientToken, clientState);
45172ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim        return clientState;
45272ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim    }
45372ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim
4543957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    private void createSessionInternalLocked(ITvInputService service, final IBinder sessionToken,
4557de5e234715a3baa8905afa3dd0c5009af64541fSungsoo Lim            final int userId) {
45672ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim        final UserState userState = getUserStateLocked(userId);
45772ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim        final SessionState sessionState = userState.sessionStateMap.get(sessionToken);
4583957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        if (DEBUG) {
459187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim            Slog.d(TAG, "createSessionInternalLocked(inputId=" + sessionState.mInfo.getId() + ")");
4603957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
4616a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo
4626a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo        final InputChannel[] channels = InputChannel.openInputChannelPair(sessionToken.toString());
4636a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo
4643957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        // Set up a callback to send the session token.
4653957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        ITvInputSessionCallback callback = new ITvInputSessionCallback.Stub() {
4663957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            @Override
4673957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            public void onSessionCreated(ITvInputSession session) {
4683957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                if (DEBUG) {
469187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                    Slog.d(TAG, "onSessionCreated(inputId=" + sessionState.mInfo.getId() + ")");
4703957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                }
4713957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                synchronized (mLock) {
472d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim                    sessionState.mSession = session;
473fd5b72f1ed2ee74a4204eef65f560fc82f0b62feDongwon Kang                    if (session == null) {
474fd5b72f1ed2ee74a4204eef65f560fc82f0b62feDongwon Kang                        removeSessionStateLocked(sessionToken, userId);
475187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                        sendSessionTokenToClientLocked(sessionState.mClient,
476187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                                sessionState.mInfo.getId(), null, null, sessionState.mSeq);
477fd5b72f1ed2ee74a4204eef65f560fc82f0b62feDongwon Kang                    } else {
4782b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                        try {
4792b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                            session.asBinder().linkToDeath(sessionState, 0);
4802b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                        } catch (RemoteException e) {
4812b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                            Slog.e(TAG, "Session is already died.");
4822b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                        }
48372ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim
48472ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim                        IBinder clientToken = sessionState.mClient.asBinder();
48572ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim                        ClientState clientState = userState.clientStateMap.get(clientToken);
48672ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim                        if (clientState == null) {
48772ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim                            clientState = createClientStateLocked(clientToken, userId);
48872ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim                        }
48972ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim                        clientState.mSessionTokens.add(sessionState.mSessionToken);
49072ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim
491187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                        sendSessionTokenToClientLocked(sessionState.mClient,
492187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                                sessionState.mInfo.getId(), sessionToken, channels[0],
493187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                                sessionState.mSeq);
494fd5b72f1ed2ee74a4204eef65f560fc82f0b62feDongwon Kang                    }
4956a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                    channels[0].dispose();
4963957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                }
4973957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            }
498832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho
499832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho            @Override
5001f213914c45c23c653f721690da2ce0718e63139Dongwon Kang            public void onChannelRetuned(Uri channelUri) {
501a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang                synchronized (mLock) {
502a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang                    if (DEBUG) {
5031f213914c45c23c653f721690da2ce0718e63139Dongwon Kang                        Slog.d(TAG, "onChannelRetuned(" + channelUri + ")");
504a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang                    }
505a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang                    if (sessionState.mSession == null || sessionState.mClient == null) {
506a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang                        return;
507a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang                    }
508a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang                    try {
5091f213914c45c23c653f721690da2ce0718e63139Dongwon Kang                        // TODO: Consider adding this channel change in the watch log. When we do
5101f213914c45c23c653f721690da2ce0718e63139Dongwon Kang                        // that, how we can protect the watch log from malicious tv inputs should
5111f213914c45c23c653f721690da2ce0718e63139Dongwon Kang                        // be addressed. e.g. add a field which represents where the channel change
5121f213914c45c23c653f721690da2ce0718e63139Dongwon Kang                        // originated from.
5131f213914c45c23c653f721690da2ce0718e63139Dongwon Kang                        sessionState.mClient.onChannelRetuned(channelUri, sessionState.mSeq);
514a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang                    } catch (RemoteException e) {
5151f213914c45c23c653f721690da2ce0718e63139Dongwon Kang                        Slog.e(TAG, "error in onChannelRetuned");
516a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang                    }
517a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang                }
518a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang            }
519a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang
520a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang            @Override
5211f213914c45c23c653f721690da2ce0718e63139Dongwon Kang            public void onTrackInfoChanged(List<TvTrackInfo> tracks) {
522a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang                synchronized (mLock) {
523a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang                    if (DEBUG) {
5241f213914c45c23c653f721690da2ce0718e63139Dongwon Kang                        Slog.d(TAG, "onTrackInfoChanged(" + tracks + ")");
525a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang                    }
526a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang                    if (sessionState.mSession == null || sessionState.mClient == null) {
527a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang                        return;
528a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang                    }
529a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang                    try {
5301f213914c45c23c653f721690da2ce0718e63139Dongwon Kang                        sessionState.mClient.onTrackInfoChanged(tracks,
531a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang                                sessionState.mSeq);
532a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang                    } catch (RemoteException e) {
5331f213914c45c23c653f721690da2ce0718e63139Dongwon Kang                        Slog.e(TAG, "error in onTrackInfoChanged");
534b93ccca6139a7ee2dba5c110e5f8213a2bd231e5Dongwon Kang                    }
535b93ccca6139a7ee2dba5c110e5f8213a2bd231e5Dongwon Kang                }
536b93ccca6139a7ee2dba5c110e5f8213a2bd231e5Dongwon Kang            }
537b93ccca6139a7ee2dba5c110e5f8213a2bd231e5Dongwon Kang
538b93ccca6139a7ee2dba5c110e5f8213a2bd231e5Dongwon Kang            @Override
5399b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang            public void onVideoAvailable() {
5409b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                synchronized (mLock) {
5419b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                    if (DEBUG) {
5429b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                        Slog.d(TAG, "onVideoAvailable()");
5439b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                    }
5449b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                    if (sessionState.mSession == null || sessionState.mClient == null) {
5459b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                        return;
5469b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                    }
5479b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                    try {
5489b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                        sessionState.mClient.onVideoAvailable(sessionState.mSeq);
5499b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                    } catch (RemoteException e) {
5509b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                        Slog.e(TAG, "error in onVideoAvailable");
5519b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                    }
5529b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                }
5539b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang            }
5549b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang
5559b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang            @Override
5569b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang            public void onVideoUnavailable(int reason) {
5579b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                synchronized (mLock) {
5589b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                    if (DEBUG) {
5599b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                        Slog.d(TAG, "onVideoUnavailable(" + reason + ")");
5609b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                    }
5619b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                    if (sessionState.mSession == null || sessionState.mClient == null) {
5629b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                        return;
5639b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                    }
5649b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                    try {
5659b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                        sessionState.mClient.onVideoUnavailable(reason, sessionState.mSeq);
5669b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                    } catch (RemoteException e) {
5679b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                        Slog.e(TAG, "error in onVideoUnavailable");
5689b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                    }
5699b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                }
5709b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang            }
5719b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang
5729b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang            @Override
573bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo            public void onContentAllowed() {
574bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo                synchronized (mLock) {
575bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo                    if (DEBUG) {
576bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo                        Slog.d(TAG, "onContentAllowed()");
577bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo                    }
578bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo                    if (sessionState.mSession == null || sessionState.mClient == null) {
579bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo                        return;
580bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo                    }
581bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo                    try {
582bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo                        sessionState.mClient.onContentAllowed(sessionState.mSeq);
583bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo                    } catch (RemoteException e) {
584bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo                        Slog.e(TAG, "error in onContentAllowed");
585bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo                    }
586bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo                }
587bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo            }
588bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo
589bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo            @Override
5906057102dbb746593a7d59cf377c969b62e38c664Jae Seo            public void onContentBlocked(String rating) {
5916057102dbb746593a7d59cf377c969b62e38c664Jae Seo                synchronized (mLock) {
5926057102dbb746593a7d59cf377c969b62e38c664Jae Seo                    if (DEBUG) {
5936057102dbb746593a7d59cf377c969b62e38c664Jae Seo                        Slog.d(TAG, "onContentBlocked()");
5946057102dbb746593a7d59cf377c969b62e38c664Jae Seo                    }
5956057102dbb746593a7d59cf377c969b62e38c664Jae Seo                    if (sessionState.mSession == null || sessionState.mClient == null) {
5966057102dbb746593a7d59cf377c969b62e38c664Jae Seo                        return;
5976057102dbb746593a7d59cf377c969b62e38c664Jae Seo                    }
5986057102dbb746593a7d59cf377c969b62e38c664Jae Seo                    try {
5996057102dbb746593a7d59cf377c969b62e38c664Jae Seo                        sessionState.mClient.onContentBlocked(rating, sessionState.mSeq);
6006057102dbb746593a7d59cf377c969b62e38c664Jae Seo                    } catch (RemoteException e) {
6016057102dbb746593a7d59cf377c969b62e38c664Jae Seo                        Slog.e(TAG, "error in onContentBlocked");
6026057102dbb746593a7d59cf377c969b62e38c664Jae Seo                    }
6036057102dbb746593a7d59cf377c969b62e38c664Jae Seo                }
6046057102dbb746593a7d59cf377c969b62e38c664Jae Seo            }
6056057102dbb746593a7d59cf377c969b62e38c664Jae Seo
6066057102dbb746593a7d59cf377c969b62e38c664Jae Seo            @Override
607832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho            public void onSessionEvent(String eventType, Bundle eventArgs) {
608832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho                synchronized (mLock) {
609832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho                    if (DEBUG) {
610832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho                        Slog.d(TAG, "onEvent(what=" + eventType + ", data=" + eventArgs + ")");
611832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho                    }
612832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho                    if (sessionState.mSession == null || sessionState.mClient == null) {
613832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho                        return;
614832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho                    }
615832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho                    try {
616832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho                        sessionState.mClient.onSessionEvent(eventType, eventArgs,
617832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho                                sessionState.mSeq);
618832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho                    } catch (RemoteException e) {
619832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho                        Slog.e(TAG, "error in onSessionEvent");
620832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho                    }
621832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho                }
622832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho            }
6233957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        };
6243957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
6253957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        // Create a session. When failed, send a null token immediately.
6263957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        try {
627187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim            service.createSession(channels[1], callback, sessionState.mInfo.getId());
6283957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        } catch (RemoteException e) {
6299a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            Slog.e(TAG, "error in createSession", e);
630fd5b72f1ed2ee74a4204eef65f560fc82f0b62feDongwon Kang            removeSessionStateLocked(sessionToken, userId);
631187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim            sendSessionTokenToClientLocked(sessionState.mClient, sessionState.mInfo.getId(), null,
632187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                    null, sessionState.mSeq);
6333957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
6346a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo        channels[1].dispose();
6353957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    }
6363957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
637d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim    private void sendSessionTokenToClientLocked(ITvInputClient client, String inputId,
6385c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo            IBinder sessionToken, InputChannel channel, int seq) {
6393957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        try {
640d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim            client.onSessionCreated(inputId, sessionToken, channel, seq);
6413957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        } catch (RemoteException exception) {
6429a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            Slog.e(TAG, "error in onSessionCreated", exception);
6433957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
6442b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim    }
6453957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
6462b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim    private void releaseSessionLocked(IBinder sessionToken, int callingUid, int userId) {
6472b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim        SessionState sessionState = getSessionStateLocked(sessionToken, callingUid, userId);
6482b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim        if (sessionState.mSession != null) {
6492b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim            try {
6502b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                sessionState.mSession.release();
6512b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim            } catch (RemoteException e) {
6522b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                Slog.w(TAG, "session is already disapeared", e);
6532b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim            }
6542b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim            sessionState.mSession = null;
6553957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
6562b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim        removeSessionStateLocked(sessionToken, userId);
6573957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    }
6583957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
659fd5b72f1ed2ee74a4204eef65f560fc82f0b62feDongwon Kang    private void removeSessionStateLocked(IBinder sessionToken, int userId) {
660fd5b72f1ed2ee74a4204eef65f560fc82f0b62feDongwon Kang        UserState userState = getUserStateLocked(userId);
661abca0ee7949f59e72b8d2764dafa23af18eb51dbJi-Hwan Lee        if (sessionToken == userState.mainSessionToken) {
662abca0ee7949f59e72b8d2764dafa23af18eb51dbJi-Hwan Lee            userState.mainSessionToken = null;
663abca0ee7949f59e72b8d2764dafa23af18eb51dbJi-Hwan Lee        }
664abca0ee7949f59e72b8d2764dafa23af18eb51dbJi-Hwan Lee
665abca0ee7949f59e72b8d2764dafa23af18eb51dbJi-Hwan Lee        // Remove the session state from the global session state map of the current user.
666fd5b72f1ed2ee74a4204eef65f560fc82f0b62feDongwon Kang        SessionState sessionState = userState.sessionStateMap.remove(sessionToken);
667fd5b72f1ed2ee74a4204eef65f560fc82f0b62feDongwon Kang
66831dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo        // Close the open log entry, if any.
669d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim        if (sessionState.mLogUri != null) {
67031dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo            SomeArgs args = SomeArgs.obtain();
671d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim            args.arg1 = sessionState.mLogUri;
67231dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo            args.arg2 = System.currentTimeMillis();
67331dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo            mLogHandler.obtainMessage(LogHandler.MSG_CLOSE_ENTRY, args).sendToTarget();
67431dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo        }
67531dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo
67672ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim        // Also remove the session token from the session token list of the current client and
67772ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim        // service.
67872ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim        ClientState clientState = userState.clientStateMap.get(sessionState.mClient.asBinder());
67972ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim        if (clientState != null) {
68072ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim            clientState.mSessionTokens.remove(sessionToken);
68172ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim            if (clientState.isEmpty()) {
68272ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim                userState.clientStateMap.remove(sessionState.mClient.asBinder());
68372ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim            }
68472ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim        }
68572ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim
686187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim        TvInputInfo info = sessionState.mInfo;
687187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim        if (info != null) {
688187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim            ServiceState serviceState = userState.serviceStateMap.get(info.getComponent());
689187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim            if (serviceState != null) {
690187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                serviceState.mSessionTokens.remove(sessionToken);
691187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim            }
692fd5b72f1ed2ee74a4204eef65f560fc82f0b62feDongwon Kang        }
693187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim        updateServiceConnectionLocked(sessionState.mInfo.getComponent(), userId);
694fd5b72f1ed2ee74a4204eef65f560fc82f0b62feDongwon Kang    }
695fd5b72f1ed2ee74a4204eef65f560fc82f0b62feDongwon Kang
696969167dc05a6485a32d160895871cff46fd81884Wonsik Kim    private void unregisterClientInternalLocked(IBinder clientToken, String inputId,
69772ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim            int userId) {
69872ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim        UserState userState = getUserStateLocked(userId);
69972ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim        ClientState clientState = userState.clientStateMap.get(clientToken);
70072ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim        if (clientState != null) {
70172ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim            clientState.mInputIds.remove(inputId);
70272ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim            if (clientState.isEmpty()) {
70372ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim                userState.clientStateMap.remove(clientToken);
70472ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim            }
70572ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim        }
70672ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim
707187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim        TvInputInfo info = userState.inputMap.get(inputId).mInfo;
708187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim        if (info == null) {
709187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim            return;
710187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim        }
711187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim        ServiceState serviceState = userState.serviceStateMap.get(info.getComponent());
71272ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim        if (serviceState == null) {
71372ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim            return;
71472ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim        }
71572ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim
71672ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim        // Remove this client from the client list and unregister the callback.
71772ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim        serviceState.mClientTokens.remove(clientToken);
71872ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim        if (!serviceState.mClientTokens.isEmpty()) {
71972ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim            // We have other clients who want to keep the callback. Do this later.
72072ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim            return;
72172ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim        }
72272ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim        if (serviceState.mService == null || serviceState.mCallback == null) {
72372ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim            return;
72472ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim        }
72572ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim        try {
72672ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim            serviceState.mService.unregisterCallback(serviceState.mCallback);
72772ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim        } catch (RemoteException e) {
72872ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim            Slog.e(TAG, "error in unregisterCallback", e);
72972ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim        } finally {
73072ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim            serviceState.mCallback = null;
731187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim            updateServiceConnectionLocked(info.getComponent(), userId);
73272ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim        }
73372ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim    }
73472ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim
7358e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim    private void notifyInputAddedLocked(UserState userState, String inputId) {
7368e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim        if (DEBUG) {
7378e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim            Slog.d(TAG, "notifyInputAdded: inputId = " + inputId);
7388e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim        }
7398e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim        for (ITvInputManagerCallback callback : userState.callbackSet) {
7408e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim            try {
7418e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim                callback.onInputAdded(inputId);
7428e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim            } catch (RemoteException e) {
7438e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim                Slog.e(TAG, "Failed to report added input to callback.");
7448e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim            }
7458e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim        }
7468e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim    }
7478e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim
7488e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim    private void notifyInputRemovedLocked(UserState userState, String inputId) {
7498e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim        if (DEBUG) {
7508e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim            Slog.d(TAG, "notifyInputRemovedLocked: inputId = " + inputId);
7518e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim        }
7528e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim        for (ITvInputManagerCallback callback : userState.callbackSet) {
7538e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim            try {
7548e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim                callback.onInputRemoved(inputId);
7558e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim            } catch (RemoteException e) {
7568e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim                Slog.e(TAG, "Failed to report removed input to callback.");
7578e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim            }
7588e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim        }
7598e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim    }
7608e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim
7618e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim    private void notifyInputStateChangedLocked(UserState userState, String inputId,
762969167dc05a6485a32d160895871cff46fd81884Wonsik Kim            int state, ITvInputManagerCallback targetCallback) {
763969167dc05a6485a32d160895871cff46fd81884Wonsik Kim        if (DEBUG) {
7648e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim            Slog.d(TAG, "notifyInputStateChangedLocked: inputId = " + inputId
765969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                    + "; state = " + state);
766969167dc05a6485a32d160895871cff46fd81884Wonsik Kim        }
767969167dc05a6485a32d160895871cff46fd81884Wonsik Kim        if (targetCallback == null) {
768969167dc05a6485a32d160895871cff46fd81884Wonsik Kim            for (ITvInputManagerCallback callback : userState.callbackSet) {
769969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                try {
770969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                    callback.onInputStateChanged(inputId, state);
771969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                } catch (RemoteException e) {
772969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                    Slog.e(TAG, "Failed to report state change to callback.");
773969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                }
774969167dc05a6485a32d160895871cff46fd81884Wonsik Kim            }
775969167dc05a6485a32d160895871cff46fd81884Wonsik Kim        } else {
7762b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim            try {
777969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                targetCallback.onInputStateChanged(inputId, state);
7782b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim            } catch (RemoteException e) {
779969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                Slog.e(TAG, "Failed to report state change to callback.");
7802b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim            }
7812b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim        }
7822b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim    }
7832b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim
784969167dc05a6485a32d160895871cff46fd81884Wonsik Kim    private void setStateLocked(String inputId, int state, int userId) {
785969167dc05a6485a32d160895871cff46fd81884Wonsik Kim        UserState userState = getUserStateLocked(userId);
786969167dc05a6485a32d160895871cff46fd81884Wonsik Kim        TvInputState inputState = userState.inputMap.get(inputId);
787969167dc05a6485a32d160895871cff46fd81884Wonsik Kim        ServiceState serviceState = userState.serviceStateMap.get(inputId);
788969167dc05a6485a32d160895871cff46fd81884Wonsik Kim        int oldState = inputState.mState;
789969167dc05a6485a32d160895871cff46fd81884Wonsik Kim        inputState.mState = state;
790187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim        if (serviceState != null && serviceState.mService == null
791187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                && shouldMaintainConnection(serviceState)) {
792969167dc05a6485a32d160895871cff46fd81884Wonsik Kim            // We don't notify state change while reconnecting. It should remain disconnected.
793969167dc05a6485a32d160895871cff46fd81884Wonsik Kim            return;
794969167dc05a6485a32d160895871cff46fd81884Wonsik Kim        }
795969167dc05a6485a32d160895871cff46fd81884Wonsik Kim        if (oldState != state) {
7968e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim            notifyInputStateChangedLocked(userState, inputId, state, null);
797969167dc05a6485a32d160895871cff46fd81884Wonsik Kim        }
798969167dc05a6485a32d160895871cff46fd81884Wonsik Kim    }
799969167dc05a6485a32d160895871cff46fd81884Wonsik Kim
8003957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    private final class BinderService extends ITvInputManager.Stub {
8013957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        @Override
8023957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        public List<TvInputInfo> getTvInputList(int userId) {
8033957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(),
8043957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    Binder.getCallingUid(), userId, "getTvInputList");
8053957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            final long identity = Binder.clearCallingIdentity();
8063957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            try {
8073957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                synchronized (mLock) {
8083957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    UserState userState = getUserStateLocked(resolvedUserId);
809969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                    List<TvInputInfo> inputList = new ArrayList<TvInputInfo>();
810969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                    for (TvInputState state : userState.inputMap.values()) {
811969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                        inputList.add(state.mInfo);
8123957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    }
813969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                    return inputList;
8143957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                }
8153957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            } finally {
8163957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                Binder.restoreCallingIdentity(identity);
8173957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            }
818b375805f3b1672e68d1511565af4700e5fa8491dJae Seo        }
819b375805f3b1672e68d1511565af4700e5fa8491dJae Seo
820b375805f3b1672e68d1511565af4700e5fa8491dJae Seo        @Override
821b375805f3b1672e68d1511565af4700e5fa8491dJae Seo        public TvInputInfo getTvInputInfo(String inputId, int userId) {
822b375805f3b1672e68d1511565af4700e5fa8491dJae Seo            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(),
823b375805f3b1672e68d1511565af4700e5fa8491dJae Seo                    Binder.getCallingUid(), userId, "getTvInputInfo");
824b375805f3b1672e68d1511565af4700e5fa8491dJae Seo            final long identity = Binder.clearCallingIdentity();
825b375805f3b1672e68d1511565af4700e5fa8491dJae Seo            try {
826b375805f3b1672e68d1511565af4700e5fa8491dJae Seo                synchronized (mLock) {
827b375805f3b1672e68d1511565af4700e5fa8491dJae Seo                    UserState userState = getUserStateLocked(resolvedUserId);
828b375805f3b1672e68d1511565af4700e5fa8491dJae Seo                    TvInputState state = userState.inputMap.get(inputId);
829b375805f3b1672e68d1511565af4700e5fa8491dJae Seo                    return state == null ? null : state.mInfo;
830b375805f3b1672e68d1511565af4700e5fa8491dJae Seo                }
831b375805f3b1672e68d1511565af4700e5fa8491dJae Seo            } finally {
832b375805f3b1672e68d1511565af4700e5fa8491dJae Seo                Binder.restoreCallingIdentity(identity);
833b375805f3b1672e68d1511565af4700e5fa8491dJae Seo            }
8343957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
8353957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
8363957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        @Override
837969167dc05a6485a32d160895871cff46fd81884Wonsik Kim        public void registerCallback(final ITvInputManagerCallback callback, int userId) {
8383957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(),
8393957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    Binder.getCallingUid(), userId, "registerCallback");
8403957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            final long identity = Binder.clearCallingIdentity();
8413957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            try {
8423957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                synchronized (mLock) {
8433957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    UserState userState = getUserStateLocked(resolvedUserId);
844969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                    userState.callbackSet.add(callback);
845969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                    for (TvInputState state : userState.inputMap.values()) {
8468e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim                        notifyInputStateChangedLocked(userState, state.mInfo.getId(),
847969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                                state.mState, callback);
8483957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    }
8493957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                }
8503957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            } finally {
8513957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                Binder.restoreCallingIdentity(identity);
8523957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            }
8533957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
8543957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
8553957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        @Override
856969167dc05a6485a32d160895871cff46fd81884Wonsik Kim        public void unregisterCallback(ITvInputManagerCallback callback, int userId) {
8573957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(),
8583957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    Binder.getCallingUid(), userId, "unregisterCallback");
8593957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            final long identity = Binder.clearCallingIdentity();
8603957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            try {
8613957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                synchronized (mLock) {
862969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                    UserState userState = getUserStateLocked(resolvedUserId);
863969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                    userState.callbackSet.remove(callback);
8643957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                }
8653957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            } finally {
8663957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                Binder.restoreCallingIdentity(identity);
8673957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            }
8683957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
8693957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
8703957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        @Override
871d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim        public void createSession(final ITvInputClient client, final String inputId,
8723957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                int seq, int userId) {
8733957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            final int callingUid = Binder.getCallingUid();
8743957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
8753957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    userId, "createSession");
8763957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            final long identity = Binder.clearCallingIdentity();
8773957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            try {
8783957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                synchronized (mLock) {
8793957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    UserState userState = getUserStateLocked(resolvedUserId);
880187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                    TvInputInfo info = userState.inputMap.get(inputId).mInfo;
881187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                    ServiceState serviceState = userState.serviceStateMap.get(info.getComponent());
8823957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    if (serviceState == null) {
883187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                        serviceState = new ServiceState(info.getComponent(), resolvedUserId);
884187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                        userState.serviceStateMap.put(info.getComponent(), serviceState);
8853957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    }
8862b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                    // Send a null token immediately while reconnecting.
8872b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                    if (serviceState.mReconnecting == true) {
8885c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo                        sendSessionTokenToClientLocked(client, inputId, null, null, seq);
8892b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                        return;
8902b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                    }
8912b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim
8922b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                    // Create a new session token and a session state.
8932b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                    IBinder sessionToken = new Binder();
894187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                    SessionState sessionState = new SessionState(sessionToken, info, client,
89572ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim                            seq, callingUid, resolvedUserId);
8962b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim
8972b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                    // Add them to the global session state map of the current user.
8982b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                    userState.sessionStateMap.put(sessionToken, sessionState);
8992b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim
9002b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                    // Also, add them to the session state map of the current service.
901d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim                    serviceState.mSessionTokens.add(sessionToken);
9023957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
903d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim                    if (serviceState.mService != null) {
904d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim                        createSessionInternalLocked(serviceState.mService, sessionToken,
9057de5e234715a3baa8905afa3dd0c5009af64541fSungsoo Lim                                resolvedUserId);
9063957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    } else {
907187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                        updateServiceConnectionLocked(info.getComponent(), resolvedUserId);
9083957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    }
9093957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                }
9103957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            } finally {
9113957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                Binder.restoreCallingIdentity(identity);
9123957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            }
9133957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
9143957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
9153957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        @Override
9163957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        public void releaseSession(IBinder sessionToken, int userId) {
9173957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            final int callingUid = Binder.getCallingUid();
9183957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
9193957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    userId, "releaseSession");
9203957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            final long identity = Binder.clearCallingIdentity();
9213957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            try {
9223957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                synchronized (mLock) {
9232b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                    releaseSessionLocked(sessionToken, callingUid, resolvedUserId);
9243957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                }
9253957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            } finally {
9263957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                Binder.restoreCallingIdentity(identity);
9273957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            }
9283957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
9293957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
9303957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        @Override
9314c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee        public void setMainSession(IBinder sessionToken, int userId) {
9324c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee            final int callingUid = Binder.getCallingUid();
9334c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
9344c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee                    userId, "setMainSession");
9354c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee            final long identity = Binder.clearCallingIdentity();
9364c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee            try {
9374c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee                synchronized (mLock) {
938982abe693f66037ca265b88057eceb5a3e815182Ji-Hwan Lee                    UserState userState = getUserStateLocked(resolvedUserId);
9394c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee                    if (sessionToken == userState.mainSessionToken) {
9404c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee                        return;
9414c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee                    }
9424c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee
9434c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee                    SessionState sessionState = getSessionStateLocked(sessionToken, callingUid,
9444c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee                            resolvedUserId);
9454c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee                    ServiceState serviceState = getServiceStateLocked(
9464c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee                            sessionState.mInfo.getComponent(), resolvedUserId);
9474c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee                    ITvInputSession session = getSessionLocked(sessionState);
9484c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee
949abca0ee7949f59e72b8d2764dafa23af18eb51dbJi-Hwan Lee                    ServiceState prevMainServiceState = null;
950abca0ee7949f59e72b8d2764dafa23af18eb51dbJi-Hwan Lee                    ITvInputSession prevMainSession = null;
951abca0ee7949f59e72b8d2764dafa23af18eb51dbJi-Hwan Lee                    if (userState.mainSessionToken != null) {
952abca0ee7949f59e72b8d2764dafa23af18eb51dbJi-Hwan Lee                        SessionState prevMainSessionState = getSessionStateLocked(
953abca0ee7949f59e72b8d2764dafa23af18eb51dbJi-Hwan Lee                                userState.mainSessionToken, Process.SYSTEM_UID, resolvedUserId);
954abca0ee7949f59e72b8d2764dafa23af18eb51dbJi-Hwan Lee                        prevMainServiceState = getServiceStateLocked(
955abca0ee7949f59e72b8d2764dafa23af18eb51dbJi-Hwan Lee                                prevMainSessionState.mInfo.getComponent(), resolvedUserId);
956abca0ee7949f59e72b8d2764dafa23af18eb51dbJi-Hwan Lee                        prevMainSession = getSessionLocked(prevMainSessionState);
957abca0ee7949f59e72b8d2764dafa23af18eb51dbJi-Hwan Lee                    }
958abca0ee7949f59e72b8d2764dafa23af18eb51dbJi-Hwan Lee
9594c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee                    userState.mainSessionToken = sessionToken;
9604c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee
9614c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee                    // Inform the new main session first. See {@link TvInputService#onSetMain}.
9624c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee                    if (serviceState.mIsHardware) {
9634c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee                        try {
9644c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee                            session.setMainSession(true);
9654c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee                        } catch (RemoteException e) {
9664c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee                            Slog.e(TAG, "error in setMainSession", e);
9674c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee                        }
9684c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee                    }
969abca0ee7949f59e72b8d2764dafa23af18eb51dbJi-Hwan Lee                    if (prevMainSession != null && prevMainServiceState.mIsHardware) {
9704c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee                        try {
9714c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee                            prevMainSession.setMainSession(false);
9724c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee                        } catch (RemoteException e) {
9734c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee                            Slog.e(TAG, "error in setMainSession", e);
9744c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee                        }
9754c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee                    }
9764c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee                }
9774c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee            } finally {
9784c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee                Binder.restoreCallingIdentity(identity);
9794c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee            }
9804c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee        }
9814c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee
9824c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee        @Override
9833957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        public void setSurface(IBinder sessionToken, Surface surface, int userId) {
9843957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            final int callingUid = Binder.getCallingUid();
9853957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
9863957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    userId, "setSurface");
9873957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            final long identity = Binder.clearCallingIdentity();
9883957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            try {
9893957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                synchronized (mLock) {
9903957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    try {
9913957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                        getSessionLocked(sessionToken, callingUid, resolvedUserId).setSurface(
9923957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                                surface);
9933957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    } catch (RemoteException e) {
9949a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                        Slog.e(TAG, "error in setSurface", e);
9953957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    }
9963957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                }
9973957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            } finally {
998f836206818ce338db83a3c23c486fb8cab29cb6dYoungsang Cho                if (surface != null) {
999f836206818ce338db83a3c23c486fb8cab29cb6dYoungsang Cho                    // surface is not used in TvInputManagerService.
1000f836206818ce338db83a3c23c486fb8cab29cb6dYoungsang Cho                    surface.release();
1001f836206818ce338db83a3c23c486fb8cab29cb6dYoungsang Cho                }
10023957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                Binder.restoreCallingIdentity(identity);
10033957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            }
10043957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
10053957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
10063957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        @Override
1007e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho        public void dispatchSurfaceChanged(IBinder sessionToken, int format, int width,
1008e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho                int height, int userId) {
1009e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho            final int callingUid = Binder.getCallingUid();
1010e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
1011e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho                    userId, "dispatchSurfaceChanged");
1012e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho            final long identity = Binder.clearCallingIdentity();
1013e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho            try {
1014e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho                synchronized (mLock) {
1015e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho                    try {
1016e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho                        getSessionLocked(sessionToken, callingUid, resolvedUserId)
1017e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho                                .dispatchSurfaceChanged(format, width, height);
1018e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho                    } catch (RemoteException e) {
1019e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho                        Slog.e(TAG, "error in dispatchSurfaceChanged", e);
1020e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho                    }
1021e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho                }
1022e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho            } finally {
1023e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho                Binder.restoreCallingIdentity(identity);
1024e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho            }
1025e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho        }
1026e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho
1027e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho        @Override
10283957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        public void setVolume(IBinder sessionToken, float volume, int userId) {
10293957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            final int callingUid = Binder.getCallingUid();
10303957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
10313957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    userId, "setVolume");
10323957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            final long identity = Binder.clearCallingIdentity();
10333957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            try {
10343957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                synchronized (mLock) {
10353957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    try {
10363957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                        getSessionLocked(sessionToken, callingUid, resolvedUserId).setVolume(
10373957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                                volume);
10383957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    } catch (RemoteException e) {
10399a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                        Slog.e(TAG, "error in setVolume", e);
10403957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    }
10413957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                }
10423957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            } finally {
10433957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                Binder.restoreCallingIdentity(identity);
10443957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            }
10453957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
10463957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
10473957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        @Override
10483957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        public void tune(IBinder sessionToken, final Uri channelUri, int userId) {
10493957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            final int callingUid = Binder.getCallingUid();
10503957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
10513957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    userId, "tune");
10523957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            final long identity = Binder.clearCallingIdentity();
10533957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            try {
10543957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                synchronized (mLock) {
10553957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    try {
10563957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                        getSessionLocked(sessionToken, callingUid, resolvedUserId).tune(channelUri);
1057008f6d4e326f6372e165bdf342178ecd1e834e2fYoungsang Cho                        if (TvContract.isChannelUriForPassthroughTvInput(channelUri)) {
1058008f6d4e326f6372e165bdf342178ecd1e834e2fYoungsang Cho                            // Do not log the watch history for passthrough inputs.
1059008f6d4e326f6372e165bdf342178ecd1e834e2fYoungsang Cho                            return;
1060008f6d4e326f6372e165bdf342178ecd1e834e2fYoungsang Cho                        }
106131dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                        long currentTime = System.currentTimeMillis();
106231dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                        long channelId = ContentUris.parseId(channelUri);
106331dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo
106431dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                        // Close the open log entry first, if any.
106531dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                        UserState userState = getUserStateLocked(resolvedUserId);
106631dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                        SessionState sessionState = userState.sessionStateMap.get(sessionToken);
1067d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim                        if (sessionState.mLogUri != null) {
106831dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                            SomeArgs args = SomeArgs.obtain();
1069d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim                            args.arg1 = sessionState.mLogUri;
107031dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                            args.arg2 = currentTime;
107131dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                            mLogHandler.obtainMessage(LogHandler.MSG_CLOSE_ENTRY, args)
107231dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                                    .sendToTarget();
107331dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                        }
107431dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo
107531dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                        // Create a log entry and fill it later.
1076187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                        String packageName = sessionState.mInfo.getServiceInfo().packageName;
107731dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                        ContentValues values = new ContentValues();
10785c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo                        values.put(TvContract.WatchedPrograms.COLUMN_PACKAGE_NAME, packageName);
1079f5cd0b388ac31104e014f9193d06080851a09e18Jae Seo                        values.put(TvContract.WatchedPrograms.COLUMN_WATCH_START_TIME_UTC_MILLIS,
108031dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                                currentTime);
1081f5cd0b388ac31104e014f9193d06080851a09e18Jae Seo                        values.put(TvContract.WatchedPrograms.COLUMN_WATCH_END_TIME_UTC_MILLIS, 0);
1082f5cd0b388ac31104e014f9193d06080851a09e18Jae Seo                        values.put(TvContract.WatchedPrograms.COLUMN_CHANNEL_ID, channelId);
108331dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo
1084d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim                        sessionState.mLogUri = mContentResolver.insert(
108531dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                                TvContract.WatchedPrograms.CONTENT_URI, values);
108631dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                        SomeArgs args = SomeArgs.obtain();
1087d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim                        args.arg1 = sessionState.mLogUri;
108831dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                        args.arg2 = ContentUris.parseId(channelUri);
108931dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                        args.arg3 = currentTime;
109031dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                        mLogHandler.obtainMessage(LogHandler.MSG_OPEN_ENTRY, args).sendToTarget();
10913957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    } catch (RemoteException e) {
10929a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                        Slog.e(TAG, "error in tune", e);
10933957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                        return;
10943957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    }
10953957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                }
10963957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            } finally {
10973957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                Binder.restoreCallingIdentity(identity);
10983957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            }
10993957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
11009a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho
11019a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho        @Override
11029bf671f8ee72b156f16fcf05a3d1c6e093ecba67Sungsoo Lim        public void requestUnblockContent(
11039bf671f8ee72b156f16fcf05a3d1c6e093ecba67Sungsoo Lim                IBinder sessionToken, String unblockedRating, int userId) {
1104903d6b72cd572665309633e925485464d08bb25aJaewan Kim            final int callingUid = Binder.getCallingUid();
1105903d6b72cd572665309633e925485464d08bb25aJaewan Kim            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
1106903d6b72cd572665309633e925485464d08bb25aJaewan Kim                    userId, "unblockContent");
1107903d6b72cd572665309633e925485464d08bb25aJaewan Kim            final long identity = Binder.clearCallingIdentity();
1108903d6b72cd572665309633e925485464d08bb25aJaewan Kim            try {
1109903d6b72cd572665309633e925485464d08bb25aJaewan Kim                synchronized (mLock) {
1110903d6b72cd572665309633e925485464d08bb25aJaewan Kim                    try {
1111903d6b72cd572665309633e925485464d08bb25aJaewan Kim                        getSessionLocked(sessionToken, callingUid, resolvedUserId)
11129bf671f8ee72b156f16fcf05a3d1c6e093ecba67Sungsoo Lim                                .requestUnblockContent(unblockedRating);
1113903d6b72cd572665309633e925485464d08bb25aJaewan Kim                    } catch (RemoteException e) {
1114903d6b72cd572665309633e925485464d08bb25aJaewan Kim                        Slog.e(TAG, "error in unblockContent", e);
1115903d6b72cd572665309633e925485464d08bb25aJaewan Kim                    }
1116903d6b72cd572665309633e925485464d08bb25aJaewan Kim                }
1117903d6b72cd572665309633e925485464d08bb25aJaewan Kim            } finally {
1118903d6b72cd572665309633e925485464d08bb25aJaewan Kim                Binder.restoreCallingIdentity(identity);
1119903d6b72cd572665309633e925485464d08bb25aJaewan Kim            }
1120903d6b72cd572665309633e925485464d08bb25aJaewan Kim        }
1121903d6b72cd572665309633e925485464d08bb25aJaewan Kim
1122903d6b72cd572665309633e925485464d08bb25aJaewan Kim        @Override
11232c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo        public void setCaptionEnabled(IBinder sessionToken, boolean enabled, int userId) {
11242c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo            final int callingUid = Binder.getCallingUid();
11252c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
11262c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo                    userId, "setCaptionEnabled");
11272c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo            final long identity = Binder.clearCallingIdentity();
11282c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo            try {
11292c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo                synchronized (mLock) {
11302c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo                    try {
11312c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo                        getSessionLocked(sessionToken, callingUid, resolvedUserId)
11322c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo                                .setCaptionEnabled(enabled);
11332c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo                    } catch (RemoteException e) {
11342c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo                        Slog.e(TAG, "error in setCaptionEnabled", e);
11352c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo                    }
11362c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo                }
11372c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo            } finally {
11382c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo                Binder.restoreCallingIdentity(identity);
11392c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo            }
11402c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo        }
11412c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo
11422c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo        @Override
11431f213914c45c23c653f721690da2ce0718e63139Dongwon Kang        public void selectTrack(IBinder sessionToken, TvTrackInfo track, int userId) {
11441f213914c45c23c653f721690da2ce0718e63139Dongwon Kang            final int callingUid = Binder.getCallingUid();
11451f213914c45c23c653f721690da2ce0718e63139Dongwon Kang            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
11461f213914c45c23c653f721690da2ce0718e63139Dongwon Kang                    userId, "selectTrack");
11471f213914c45c23c653f721690da2ce0718e63139Dongwon Kang            final long identity = Binder.clearCallingIdentity();
11481f213914c45c23c653f721690da2ce0718e63139Dongwon Kang            try {
11491f213914c45c23c653f721690da2ce0718e63139Dongwon Kang                synchronized (mLock) {
11501f213914c45c23c653f721690da2ce0718e63139Dongwon Kang                    try {
11511f213914c45c23c653f721690da2ce0718e63139Dongwon Kang                        getSessionLocked(sessionToken, callingUid, resolvedUserId).selectTrack(
11521f213914c45c23c653f721690da2ce0718e63139Dongwon Kang                                track);
11531f213914c45c23c653f721690da2ce0718e63139Dongwon Kang                    } catch (RemoteException e) {
11541f213914c45c23c653f721690da2ce0718e63139Dongwon Kang                        Slog.e(TAG, "error in selectTrack", e);
11551f213914c45c23c653f721690da2ce0718e63139Dongwon Kang                    }
11561f213914c45c23c653f721690da2ce0718e63139Dongwon Kang                }
11571f213914c45c23c653f721690da2ce0718e63139Dongwon Kang            } finally {
11581f213914c45c23c653f721690da2ce0718e63139Dongwon Kang                Binder.restoreCallingIdentity(identity);
11591f213914c45c23c653f721690da2ce0718e63139Dongwon Kang            }
11601f213914c45c23c653f721690da2ce0718e63139Dongwon Kang        }
11611f213914c45c23c653f721690da2ce0718e63139Dongwon Kang
11621f213914c45c23c653f721690da2ce0718e63139Dongwon Kang        @Override
11631f213914c45c23c653f721690da2ce0718e63139Dongwon Kang        public void unselectTrack(IBinder sessionToken, TvTrackInfo track, int userId) {
11641f213914c45c23c653f721690da2ce0718e63139Dongwon Kang            final int callingUid = Binder.getCallingUid();
11651f213914c45c23c653f721690da2ce0718e63139Dongwon Kang            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
11661f213914c45c23c653f721690da2ce0718e63139Dongwon Kang                    userId, "unselectTrack");
11671f213914c45c23c653f721690da2ce0718e63139Dongwon Kang            final long identity = Binder.clearCallingIdentity();
11681f213914c45c23c653f721690da2ce0718e63139Dongwon Kang            try {
11691f213914c45c23c653f721690da2ce0718e63139Dongwon Kang                synchronized (mLock) {
11701f213914c45c23c653f721690da2ce0718e63139Dongwon Kang                    try {
11711f213914c45c23c653f721690da2ce0718e63139Dongwon Kang                        getSessionLocked(sessionToken, callingUid, resolvedUserId).unselectTrack(
11721f213914c45c23c653f721690da2ce0718e63139Dongwon Kang                                track);
11731f213914c45c23c653f721690da2ce0718e63139Dongwon Kang                    } catch (RemoteException e) {
11741f213914c45c23c653f721690da2ce0718e63139Dongwon Kang                        Slog.e(TAG, "error in unselectTrack", e);
11751f213914c45c23c653f721690da2ce0718e63139Dongwon Kang                    }
11761f213914c45c23c653f721690da2ce0718e63139Dongwon Kang                }
11771f213914c45c23c653f721690da2ce0718e63139Dongwon Kang            } finally {
11781f213914c45c23c653f721690da2ce0718e63139Dongwon Kang                Binder.restoreCallingIdentity(identity);
11791f213914c45c23c653f721690da2ce0718e63139Dongwon Kang            }
11801f213914c45c23c653f721690da2ce0718e63139Dongwon Kang        }
11811f213914c45c23c653f721690da2ce0718e63139Dongwon Kang
11821f213914c45c23c653f721690da2ce0718e63139Dongwon Kang        @Override
1183a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo        public void sendAppPrivateCommand(IBinder sessionToken, String command, Bundle data,
1184a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo                int userId) {
1185a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo            final int callingUid = Binder.getCallingUid();
1186a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
1187a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo                    userId, "sendAppPrivateCommand");
1188a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo            final long identity = Binder.clearCallingIdentity();
1189a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo            try {
1190a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo                synchronized (mLock) {
1191a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo                    try {
1192a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo                        getSessionLocked(sessionToken, callingUid, resolvedUserId)
1193a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo                                .appPrivateCommand(command, data);
1194a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo                    } catch (RemoteException e) {
1195a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo                        Slog.e(TAG, "error in sendAppPrivateCommand", e);
1196a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo                    }
1197a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo                }
1198a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo            } finally {
1199a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo                Binder.restoreCallingIdentity(identity);
1200a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo            }
1201a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo        }
1202a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo
1203a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo        @Override
12049a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho        public void createOverlayView(IBinder sessionToken, IBinder windowToken, Rect frame,
12059a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                int userId) {
12069a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            final int callingUid = Binder.getCallingUid();
12079a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
12089a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                    userId, "createOverlayView");
12099a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            final long identity = Binder.clearCallingIdentity();
12109a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            try {
12119a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                synchronized (mLock) {
12129a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                    try {
12139a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                        getSessionLocked(sessionToken, callingUid, resolvedUserId)
12149a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                                .createOverlayView(windowToken, frame);
12159a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                    } catch (RemoteException e) {
12169a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                        Slog.e(TAG, "error in createOverlayView", e);
12179a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                    }
12189a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                }
12199a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            } finally {
12209a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                Binder.restoreCallingIdentity(identity);
12219a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            }
12229a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho        }
12239a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho
12249a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho        @Override
12259a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho        public void relayoutOverlayView(IBinder sessionToken, Rect frame, int userId) {
12269a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            final int callingUid = Binder.getCallingUid();
12279a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
12289a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                    userId, "relayoutOverlayView");
12299a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            final long identity = Binder.clearCallingIdentity();
12309a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            try {
12319a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                synchronized (mLock) {
12329a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                    try {
12339a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                        getSessionLocked(sessionToken, callingUid, resolvedUserId)
12349a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                                .relayoutOverlayView(frame);
12359a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                    } catch (RemoteException e) {
12369a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                        Slog.e(TAG, "error in relayoutOverlayView", e);
12379a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                    }
12389a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                }
12399a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            } finally {
12409a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                Binder.restoreCallingIdentity(identity);
12419a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            }
12429a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho        }
12439a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho
12449a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho        @Override
12459a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho        public void removeOverlayView(IBinder sessionToken, int userId) {
12469a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            final int callingUid = Binder.getCallingUid();
12479a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
12489a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                    userId, "removeOverlayView");
12499a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            final long identity = Binder.clearCallingIdentity();
12509a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            try {
12519a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                synchronized (mLock) {
12529a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                    try {
12539a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                        getSessionLocked(sessionToken, callingUid, resolvedUserId)
12549a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                                .removeOverlayView();
12559a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                    } catch (RemoteException e) {
12569a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                        Slog.e(TAG, "error in removeOverlayView", e);
12579a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                    }
12589a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                }
12599a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            } finally {
12609a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                Binder.restoreCallingIdentity(identity);
12619a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            }
12629a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho        }
1263c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim
1264c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim        @Override
1265c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim        public List<TvInputHardwareInfo> getHardwareList() throws RemoteException {
1266969167dc05a6485a32d160895871cff46fd81884Wonsik Kim            if (mContext.checkCallingPermission(android.Manifest.permission.TV_INPUT_HARDWARE)
1267c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim                    != PackageManager.PERMISSION_GRANTED) {
1268c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim                return null;
1269c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim            }
1270c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim
1271c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim            final long identity = Binder.clearCallingIdentity();
1272c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim            try {
1273c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim                return mTvInputHardwareManager.getHardwareList();
1274c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim            } finally {
1275c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim                Binder.restoreCallingIdentity(identity);
1276c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim            }
1277c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim        }
1278c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim
1279c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim        @Override
1280c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim        public ITvInputHardware acquireTvInputHardware(int deviceId,
1281969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                ITvInputHardwareCallback callback, TvInputInfo info, int userId)
1282969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                throws RemoteException {
1283969167dc05a6485a32d160895871cff46fd81884Wonsik Kim            if (mContext.checkCallingPermission(android.Manifest.permission.TV_INPUT_HARDWARE)
1284c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim                    != PackageManager.PERMISSION_GRANTED) {
1285c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim                return null;
1286c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim            }
1287c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim
1288c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim            final long identity = Binder.clearCallingIdentity();
1289c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim            final int callingUid = Binder.getCallingUid();
1290c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
1291c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim                    userId, "acquireTvInputHardware");
1292c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim            try {
1293c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim                return mTvInputHardwareManager.acquireHardware(
1294969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                        deviceId, callback, info, callingUid, resolvedUserId);
1295c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim            } finally {
1296c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim                Binder.restoreCallingIdentity(identity);
1297c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim            }
1298c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim        }
1299c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim
1300c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim        @Override
1301c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim        public void releaseTvInputHardware(int deviceId, ITvInputHardware hardware, int userId)
1302c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim                throws RemoteException {
1303969167dc05a6485a32d160895871cff46fd81884Wonsik Kim            if (mContext.checkCallingPermission(android.Manifest.permission.TV_INPUT_HARDWARE)
1304c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim                    != PackageManager.PERMISSION_GRANTED) {
1305c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim                return;
1306c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim            }
1307c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim
1308c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim            final long identity = Binder.clearCallingIdentity();
1309c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim            final int callingUid = Binder.getCallingUid();
1310c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
1311c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim                    userId, "releaseTvInputHardware");
1312c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim            try {
1313c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim                mTvInputHardwareManager.releaseHardware(
1314c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim                        deviceId, hardware, callingUid, resolvedUserId);
1315c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim            } finally {
1316c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim                Binder.restoreCallingIdentity(identity);
1317c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim            }
1318c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim        }
1319e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim
1320e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim        @Override
1321c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo        public List<TvStreamConfig> getAvailableTvStreamConfigList(String inputId, int userId)
1322c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo                throws RemoteException {
1323c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo            if (mContext.checkCallingPermission(
1324c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo                    android.Manifest.permission.CAPTURE_TV_INPUT)
1325c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo                    != PackageManager.PERMISSION_GRANTED) {
1326c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo                throw new SecurityException("Requires CAPTURE_TV_INPUT permission");
1327c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo            }
1328c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo
1329c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo            final long identity = Binder.clearCallingIdentity();
1330c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo            final int callingUid = Binder.getCallingUid();
1331c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
1332c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo                    userId, "getAvailableTvStreamConfigList");
1333c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo            try {
1334c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo                return mTvInputHardwareManager.getAvailableTvStreamConfigList(
1335c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo                        inputId, callingUid, resolvedUserId);
1336c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo            } finally {
1337c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo                Binder.restoreCallingIdentity(identity);
1338c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo            }
1339c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo        }
1340c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo
1341c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo        @Override
1342c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo        public boolean captureFrame(String inputId, Surface surface, TvStreamConfig config,
1343c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo                int userId)
1344c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo                throws RemoteException {
1345c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo            if (mContext.checkCallingPermission(
1346c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo                    android.Manifest.permission.CAPTURE_TV_INPUT)
1347c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo                    != PackageManager.PERMISSION_GRANTED) {
1348c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo                throw new SecurityException("Requires CAPTURE_TV_INPUT permission");
1349c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo            }
1350c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo
1351c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo            final long identity = Binder.clearCallingIdentity();
1352c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo            final int callingUid = Binder.getCallingUid();
1353c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
1354c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo                    userId, "captureFrame");
1355c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo            try {
135679124a717c09f12c74d587d3977bf33ca37e6420Terry Heo                final String wrappedInputId;
135779124a717c09f12c74d587d3977bf33ca37e6420Terry Heo                synchronized (mLock) {
135879124a717c09f12c74d587d3977bf33ca37e6420Terry Heo                    UserState userState = getUserStateLocked(resolvedUserId);
135979124a717c09f12c74d587d3977bf33ca37e6420Terry Heo                    wrappedInputId = userState.wrappedInputMap.get(inputId);
136079124a717c09f12c74d587d3977bf33ca37e6420Terry Heo                }
1361c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo                return mTvInputHardwareManager.captureFrame(
136279124a717c09f12c74d587d3977bf33ca37e6420Terry Heo                        (wrappedInputId != null) ? wrappedInputId : inputId,
136379124a717c09f12c74d587d3977bf33ca37e6420Terry Heo                        surface, config, callingUid, resolvedUserId);
1364c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo            } finally {
1365c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo                Binder.restoreCallingIdentity(identity);
1366c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo            }
1367c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo        }
1368c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo
1369c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo        @Override
13700f8fc345ea61928265fdd6d461bf1babe353fbe4Jae Seo        @SuppressWarnings("resource")
1371e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim        protected void dump(FileDescriptor fd, final PrintWriter writer, String[] args) {
1372e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim            final IndentingPrintWriter pw = new IndentingPrintWriter(writer, "  ");
13730f8fc345ea61928265fdd6d461bf1babe353fbe4Jae Seo            if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
1374e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                    != PackageManager.PERMISSION_GRANTED) {
13750f8fc345ea61928265fdd6d461bf1babe353fbe4Jae Seo                pw.println("Permission Denial: can't dump TvInputManager from pid="
13760f8fc345ea61928265fdd6d461bf1babe353fbe4Jae Seo                        + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid());
1377e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                return;
1378e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim            }
1379e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim
1380e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim            synchronized (mLock) {
1381e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                pw.println("User Ids (Current user: " + mCurrentUserId + "):");
1382e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                pw.increaseIndent();
1383e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                for (int i = 0; i < mUserStates.size(); i++) {
1384e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                    int userId = mUserStates.keyAt(i);
1385e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                    pw.println(Integer.valueOf(userId));
1386e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                }
1387e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                pw.decreaseIndent();
1388e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim
1389e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                for (int i = 0; i < mUserStates.size(); i++) {
1390e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                    int userId = mUserStates.keyAt(i);
1391e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                    UserState userState = getUserStateLocked(userId);
1392e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                    pw.println("UserState (" + userId + "):");
1393e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                    pw.increaseIndent();
1394e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim
1395969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                    pw.println("inputMap: inputId -> TvInputState");
1396e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                    pw.increaseIndent();
13978e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim                    for (Map.Entry<String, TvInputState> entry: userState.inputMap.entrySet()) {
13988e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim                        pw.println(entry.getKey() + ": " + entry.getValue());
1399e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                    }
1400e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                    pw.decreaseIndent();
1401e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim
1402969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                    pw.println("packageSet:");
1403e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                    pw.increaseIndent();
1404969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                    for (String packageName : userState.packageSet) {
1405e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        pw.println(packageName);
1406e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                    }
1407e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                    pw.decreaseIndent();
1408e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim
1409e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                    pw.println("clientStateMap: ITvInputClient -> ClientState");
1410e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                    pw.increaseIndent();
1411e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                    for (Map.Entry<IBinder, ClientState> entry :
1412e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                            userState.clientStateMap.entrySet()) {
1413e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        ClientState client = entry.getValue();
1414e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        pw.println(entry.getKey() + ": " + client);
1415e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim
1416e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        pw.increaseIndent();
1417e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim
1418e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        pw.println("mInputIds:");
1419e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        pw.increaseIndent();
1420e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        for (String inputId : client.mInputIds) {
1421e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                            pw.println(inputId);
1422e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        }
1423e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        pw.decreaseIndent();
1424e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim
1425e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        pw.println("mSessionTokens:");
1426e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        pw.increaseIndent();
1427e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        for (IBinder token : client.mSessionTokens) {
1428e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                            pw.println("" + token);
1429e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        }
1430e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        pw.decreaseIndent();
1431e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim
1432e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        pw.println("mClientTokens: " + client.mClientToken);
1433e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        pw.println("mUserId: " + client.mUserId);
1434e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim
1435e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        pw.decreaseIndent();
1436e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                    }
1437e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                    pw.decreaseIndent();
1438e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim
1439187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                    pw.println("serviceStateMap: ComponentName -> ServiceState");
1440e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                    pw.increaseIndent();
1441187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                    for (Map.Entry<ComponentName, ServiceState> entry :
1442e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                            userState.serviceStateMap.entrySet()) {
1443e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        ServiceState service = entry.getValue();
1444e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        pw.println(entry.getKey() + ": " + service);
1445e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim
1446e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        pw.increaseIndent();
1447e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim
1448e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        pw.println("mClientTokens:");
1449e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        pw.increaseIndent();
1450e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        for (IBinder token : service.mClientTokens) {
1451e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                            pw.println("" + token);
1452e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        }
1453e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        pw.decreaseIndent();
1454e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim
1455e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        pw.println("mSessionTokens:");
1456e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        pw.increaseIndent();
1457e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        for (IBinder token : service.mSessionTokens) {
1458e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                            pw.println("" + token);
1459e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        }
1460e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        pw.decreaseIndent();
1461e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim
1462e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        pw.println("mService: " + service.mService);
1463e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        pw.println("mCallback: " + service.mCallback);
1464e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        pw.println("mBound: " + service.mBound);
1465e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        pw.println("mReconnecting: " + service.mReconnecting);
1466e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim
1467e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        pw.decreaseIndent();
1468e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                    }
1469e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                    pw.decreaseIndent();
1470e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim
1471e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                    pw.println("sessionStateMap: ITvInputSession -> SessionState");
1472e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                    pw.increaseIndent();
1473e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                    for (Map.Entry<IBinder, SessionState> entry :
1474e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                            userState.sessionStateMap.entrySet()) {
1475e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        SessionState session = entry.getValue();
1476e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        pw.println(entry.getKey() + ": " + session);
1477e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim
1478e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        pw.increaseIndent();
1479187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                        pw.println("mInfo: " + session.mInfo);
1480e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        pw.println("mClient: " + session.mClient);
1481e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        pw.println("mSeq: " + session.mSeq);
1482e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        pw.println("mCallingUid: " + session.mCallingUid);
1483e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        pw.println("mUserId: " + session.mUserId);
1484e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        pw.println("mSessionToken: " + session.mSessionToken);
1485e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        pw.println("mSession: " + session.mSession);
1486e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        pw.println("mLogUri: " + session.mLogUri);
1487e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        pw.decreaseIndent();
1488e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                    }
1489e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                    pw.decreaseIndent();
1490e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim
1491969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                    pw.println("callbackSet:");
1492969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                    pw.increaseIndent();
1493969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                    for (ITvInputManagerCallback callback : userState.callbackSet) {
1494969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                        pw.println(callback.toString());
1495969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                    }
1496969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                    pw.decreaseIndent();
1497969167dc05a6485a32d160895871cff46fd81884Wonsik Kim
1498e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                    pw.decreaseIndent();
1499e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                }
1500e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim            }
1501e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim        }
15023957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    }
15033957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
1504969167dc05a6485a32d160895871cff46fd81884Wonsik Kim    private static final class TvInputState {
1505969167dc05a6485a32d160895871cff46fd81884Wonsik Kim        // A TvInputInfo object which represents the TV input.
1506969167dc05a6485a32d160895871cff46fd81884Wonsik Kim        private TvInputInfo mInfo;
1507969167dc05a6485a32d160895871cff46fd81884Wonsik Kim
1508969167dc05a6485a32d160895871cff46fd81884Wonsik Kim        // The state of TV input. Connected by default.
1509969167dc05a6485a32d160895871cff46fd81884Wonsik Kim        private int mState = INPUT_STATE_CONNECTED;
1510969167dc05a6485a32d160895871cff46fd81884Wonsik Kim
1511969167dc05a6485a32d160895871cff46fd81884Wonsik Kim        @Override
1512969167dc05a6485a32d160895871cff46fd81884Wonsik Kim        public String toString() {
1513969167dc05a6485a32d160895871cff46fd81884Wonsik Kim            return "mInfo: " + mInfo + "; mState: " + mState;
1514969167dc05a6485a32d160895871cff46fd81884Wonsik Kim        }
1515969167dc05a6485a32d160895871cff46fd81884Wonsik Kim    }
1516969167dc05a6485a32d160895871cff46fd81884Wonsik Kim
15173957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    private static final class UserState {
1518969167dc05a6485a32d160895871cff46fd81884Wonsik Kim        // A mapping from the TV input id to its TvInputState.
1519969167dc05a6485a32d160895871cff46fd81884Wonsik Kim        private Map<String, TvInputState> inputMap = new HashMap<String, TvInputState>();
15203957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
1521969167dc05a6485a32d160895871cff46fd81884Wonsik Kim        // A set of all TV input packages.
1522969167dc05a6485a32d160895871cff46fd81884Wonsik Kim        private final Set<String> packageSet = new HashSet<String>();
15235c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo
152472ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim        // A mapping from the token of a client to its state.
152572ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim        private final Map<IBinder, ClientState> clientStateMap =
152672ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim                new HashMap<IBinder, ClientState>();
152772ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim
15283957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        // A mapping from the name of a TV input service to its state.
1529187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim        private final Map<ComponentName, ServiceState> serviceStateMap =
1530187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                new HashMap<ComponentName, ServiceState>();
15313957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
15323957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        // A mapping from the token of a TV input session to its state.
15333957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        private final Map<IBinder, SessionState> sessionStateMap =
15343957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                new HashMap<IBinder, SessionState>();
1535969167dc05a6485a32d160895871cff46fd81884Wonsik Kim
1536969167dc05a6485a32d160895871cff46fd81884Wonsik Kim        // A set of callbacks.
1537969167dc05a6485a32d160895871cff46fd81884Wonsik Kim        private final Set<ITvInputManagerCallback> callbackSet =
1538969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                new HashSet<ITvInputManagerCallback>();
153979124a717c09f12c74d587d3977bf33ca37e6420Terry Heo
154079124a717c09f12c74d587d3977bf33ca37e6420Terry Heo        // A mapping from the TV input id to wrapped input id.
154179124a717c09f12c74d587d3977bf33ca37e6420Terry Heo        private final Map<String, String> wrappedInputMap = new HashMap<String, String>();
15424c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee
15434c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee        // The token of a "main" TV input session.
15444c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee        private IBinder mainSessionToken = null;
15453957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    }
15463957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
154772ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim    private final class ClientState implements IBinder.DeathRecipient {
154872ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim        private final List<String> mInputIds = new ArrayList<String>();
154972ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim        private final List<IBinder> mSessionTokens = new ArrayList<IBinder>();
155072ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim
155172ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim        private IBinder mClientToken;
155272ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim        private final int mUserId;
155372ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim
155472ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim        ClientState(IBinder clientToken, int userId) {
155572ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim            mClientToken = clientToken;
155672ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim            mUserId = userId;
155772ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim        }
155872ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim
155972ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim        public boolean isEmpty() {
156072ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim            return mInputIds.isEmpty() && mSessionTokens.isEmpty();
156172ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim        }
156272ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim
156372ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim        @Override
156472ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim        public void binderDied() {
156572ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim            synchronized (mLock) {
156672ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim                UserState userState = getUserStateLocked(mUserId);
156772ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim                // DO NOT remove the client state of clientStateMap in this method. It will be
1568969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                // removed in releaseSessionLocked() or unregisterClientInternalLocked().
156972ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim                ClientState clientState = userState.clientStateMap.get(mClientToken);
157072ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim                if (clientState != null) {
157172ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim                    while (clientState.mSessionTokens.size() > 0) {
157272ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim                        releaseSessionLocked(
157372ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim                                clientState.mSessionTokens.get(0), Process.SYSTEM_UID, mUserId);
157472ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim                    }
157572ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim                    while (clientState.mInputIds.size() > 0) {
1576969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                        unregisterClientInternalLocked(
157772ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim                                mClientToken, clientState.mInputIds.get(0), mUserId);
157872ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim                    }
157972ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim                }
158072ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim                mClientToken = null;
158172ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim            }
158272ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim        }
158372ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim    }
158472ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim
15853957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    private final class ServiceState {
158672ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim        private final List<IBinder> mClientTokens = new ArrayList<IBinder>();
1587d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim        private final List<IBinder> mSessionTokens = new ArrayList<IBinder>();
1588d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim        private final ServiceConnection mConnection;
1589187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim        private final ComponentName mName;
1590187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim        private final boolean mIsHardware;
1591187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim        private final List<TvInputInfo> mInputList = new ArrayList<TvInputInfo>();
15923957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
1593d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim        private ITvInputService mService;
1594d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim        private ServiceCallback mCallback;
1595d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim        private boolean mBound;
15962b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim        private boolean mReconnecting;
15973957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
1598187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim        private ServiceState(ComponentName name, int userId) {
1599187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim            mName = name;
1600187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim            mConnection = new InputServiceConnection(name, userId);
1601187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim            mIsHardware = hasHardwarePermission(mContext.getPackageManager(), mName);
16023957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
16033957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    }
16043957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
16052b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim    private final class SessionState implements IBinder.DeathRecipient {
1606187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim        private final TvInputInfo mInfo;
1607d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim        private final ITvInputClient mClient;
1608d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim        private final int mSeq;
1609d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim        private final int mCallingUid;
16102b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim        private final int mUserId;
161172ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim        private final IBinder mSessionToken;
1612d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim        private ITvInputSession mSession;
1613d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim        private Uri mLogUri;
16143957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
1615187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim        private SessionState(IBinder sessionToken, TvInputInfo info, ITvInputClient client, int seq,
16162b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                int callingUid, int userId) {
161772ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim            mSessionToken = sessionToken;
1618187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim            mInfo = info;
16192b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim            mClient = client;
16202b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim            mSeq = seq;
16212b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim            mCallingUid = callingUid;
16222b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim            mUserId = userId;
16232b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim        }
16242b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim
16252b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim        @Override
16262b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim        public void binderDied() {
16272b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim            synchronized (mLock) {
16282b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                mSession = null;
16292b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                if (mClient != null) {
16302b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                    try {
16312b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                        mClient.onSessionReleased(mSeq);
16322b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                    } catch(RemoteException e) {
16332b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                        Slog.e(TAG, "error in onSessionReleased", e);
16342b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                    }
16352b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                }
163672ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim                removeSessionStateLocked(mSessionToken, mUserId);
16372b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim            }
16383957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
16393957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    }
16403957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
16413957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    private final class InputServiceConnection implements ServiceConnection {
1642187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim        private final ComponentName mName;
16433957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        private final int mUserId;
16443957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
1645187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim        private InputServiceConnection(ComponentName name, int userId) {
1646187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim            mName = name;
16473957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            mUserId = userId;
16483957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
16493957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
16503957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        @Override
16513957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        public void onServiceConnected(ComponentName name, IBinder service) {
16523957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            if (DEBUG) {
1653187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                Slog.d(TAG, "onServiceConnected(name=" + name + ")");
16543957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            }
16553957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            synchronized (mLock) {
1656969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                UserState userState = getUserStateLocked(mUserId);
1657187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                ServiceState serviceState = userState.serviceStateMap.get(mName);
1658d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim                serviceState.mService = ITvInputService.Stub.asInterface(service);
16593957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
16603957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                // Register a callback, if we need to.
1661187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                if (serviceState.mIsHardware && serviceState.mCallback == null) {
1662187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                    serviceState.mCallback = new ServiceCallback(mName, mUserId);
16633957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    try {
1664d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim                        serviceState.mService.registerCallback(serviceState.mCallback);
16653957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    } catch (RemoteException e) {
16669a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                        Slog.e(TAG, "error in registerCallback", e);
16673957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    }
16683957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                }
16693957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
16703957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                // And create sessions, if any.
1671d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim                for (IBinder sessionToken : serviceState.mSessionTokens) {
1672d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim                    createSessionInternalLocked(serviceState.mService, sessionToken, mUserId);
16733957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                }
1674969167dc05a6485a32d160895871cff46fd81884Wonsik Kim
1675187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                for (TvInputState inputState : userState.inputMap.values()) {
1676187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                    if (inputState.mInfo.getComponent().equals(name)
1677187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                            && inputState.mState != INPUT_STATE_DISCONNECTED) {
16788e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim                        notifyInputStateChangedLocked(userState, inputState.mInfo.getId(),
1679187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                                inputState.mState, null);
1680187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                    }
1681187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                }
1682187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim
1683187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                if (serviceState.mIsHardware) {
16844f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                    List<TvInputHardwareInfo> hardwareInfoList =
16854f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                            mTvInputHardwareManager.getHardwareList();
1686187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                    for (TvInputHardwareInfo hardwareInfo : hardwareInfoList) {
1687187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                        try {
1688187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                            serviceState.mService.notifyHardwareAdded(hardwareInfo);
1689187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                        } catch (RemoteException e) {
1690187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                            Slog.e(TAG, "error in notifyHardwareAdded", e);
1691187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                        }
1692187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                    }
1693187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim
16944f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                    List<HdmiCecDeviceInfo> cecDeviceInfoList =
16954f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                            mTvInputHardwareManager.getHdmiCecInputDeviceList();
16964f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                    for (HdmiCecDeviceInfo cecDeviceInfo : cecDeviceInfoList) {
16974f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                        try {
16984f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                            serviceState.mService.notifyHdmiCecDeviceAdded(cecDeviceInfo);
16994f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                        } catch (RemoteException e) {
17004f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                            Slog.e(TAG, "error in notifyHdmiCecDeviceAdded", e);
17014f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                        }
17024f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                    }
1703969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                }
17043957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            }
17053957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
17063957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
17073957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        @Override
17083957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        public void onServiceDisconnected(ComponentName name) {
17093957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            if (DEBUG) {
1710187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                Slog.d(TAG, "onServiceDisconnected(name=" + name + ")");
17113957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            }
1712187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim            if (!mName.equals(name)) {
17132b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                throw new IllegalArgumentException("Mismatched ComponentName: "
1714187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                        + mName + " (expected), " + name + " (actual).");
17152b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim            }
17162b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim            synchronized (mLock) {
17172b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                UserState userState = getUserStateLocked(mUserId);
1718187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                ServiceState serviceState = userState.serviceStateMap.get(mName);
17192b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                if (serviceState != null) {
17202b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                    serviceState.mReconnecting = true;
17212b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                    serviceState.mBound = false;
17222b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                    serviceState.mService = null;
17232b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                    serviceState.mCallback = null;
17242b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim
17252b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                    // Send null tokens for not finishing create session events.
17262b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                    for (IBinder sessionToken : serviceState.mSessionTokens) {
17272b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                        SessionState sessionState = userState.sessionStateMap.get(sessionToken);
17282b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                        if (sessionState.mSession == null) {
17292b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                            removeSessionStateLocked(sessionToken, sessionState.mUserId);
17302b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                            sendSessionTokenToClientLocked(sessionState.mClient,
1731187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                                    sessionState.mInfo.getId(), null, null, sessionState.mSeq);
17322b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                        }
17332b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                    }
17342b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim
1735187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                    for (TvInputState inputState : userState.inputMap.values()) {
1736187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                        if (inputState.mInfo.getComponent().equals(name)) {
173779124a717c09f12c74d587d3977bf33ca37e6420Terry Heo                            String inputId = inputState.mInfo.getId();
173879124a717c09f12c74d587d3977bf33ca37e6420Terry Heo                            notifyInputStateChangedLocked(userState, inputId,
1739187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                                    INPUT_STATE_DISCONNECTED, null);
174079124a717c09f12c74d587d3977bf33ca37e6420Terry Heo                            userState.wrappedInputMap.remove(inputId);
1741187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                        }
1742187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                    }
1743187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                    updateServiceConnectionLocked(mName, mUserId);
17442b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                }
17452b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim            }
17463957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
17473957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    }
17483957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
17493957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    private final class ServiceCallback extends ITvInputServiceCallback.Stub {
1750187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim        private final ComponentName mName;
17513957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        private final int mUserId;
17523957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
1753187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim        ServiceCallback(ComponentName name, int userId) {
1754187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim            mName = name;
17553957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            mUserId = userId;
17563957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
17573957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
17584f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee        private void ensureHardwarePermission() {
17594f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee            if (mContext.checkCallingPermission(android.Manifest.permission.TV_INPUT_HARDWARE)
17604f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                    != PackageManager.PERMISSION_GRANTED) {
17614f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                throw new SecurityException("The caller does not have hardware permission");
17624f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee            }
17634f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee        }
17644f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee
17654f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee        private void ensureValidInput(TvInputInfo inputInfo) {
17664f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee            if (inputInfo.getId() == null || !mName.equals(inputInfo.getComponent())) {
17674f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                throw new IllegalArgumentException("Invalid TvInputInfo");
17684f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee            }
17694f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee        }
17704f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee
17714f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee        private void addTvInputLocked(TvInputInfo inputInfo) {
17724f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee            ServiceState serviceState = getServiceStateLocked(mName, mUserId);
17734f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee            serviceState.mInputList.add(inputInfo);
17744f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee            buildTvInputListLocked(mUserId);
17754f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee        }
17764f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee
17773957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        @Override
17784f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee        public void addHardwareTvInput(int deviceId, TvInputInfo inputInfo) {
17794f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee            ensureHardwarePermission();
17804f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee            ensureValidInput(inputInfo);
1781187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim            synchronized (mLock) {
17824f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                mTvInputHardwareManager.addHardwareTvInput(deviceId, inputInfo);
17834f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                addTvInputLocked(inputInfo);
17844f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee            }
17854f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee        }
1786187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim
17874f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee        @Override
17884f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee        public void addHdmiCecTvInput(int logicalAddress, TvInputInfo inputInfo) {
17894f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee            ensureHardwarePermission();
17904f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee            ensureValidInput(inputInfo);
17914f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee            synchronized (mLock) {
17924f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                mTvInputHardwareManager.addHdmiCecTvInput(logicalAddress, inputInfo);
17934f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                addTvInputLocked(inputInfo);
17943957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            }
1795187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim        }
1796187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim
1797187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim        @Override
1798187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim        public void removeTvInput(String inputId) {
17994f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee            ensureHardwarePermission();
18003957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            synchronized (mLock) {
1801187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                ServiceState serviceState = getServiceStateLocked(mName, mUserId);
1802187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                boolean removed = false;
1803187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                for (Iterator<TvInputInfo> it = serviceState.mInputList.iterator();
1804187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                        it.hasNext(); ) {
1805187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                    if (it.next().getId().equals(inputId)) {
1806187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                        it.remove();
1807187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                        removed = true;
1808187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                        break;
1809187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                    }
1810187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                }
1811187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                if (removed) {
1812187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                    buildTvInputListLocked(mUserId);
18134f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                    mTvInputHardwareManager.removeTvInput(inputId);
1814187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                } else {
1815187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                    Slog.e(TAG, "TvInputInfo with inputId=" + inputId + " not found.");
1816187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                }
18173957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            }
18183957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
181979124a717c09f12c74d587d3977bf33ca37e6420Terry Heo
182079124a717c09f12c74d587d3977bf33ca37e6420Terry Heo        @Override
182179124a717c09f12c74d587d3977bf33ca37e6420Terry Heo        public void setWrappedInputId(String inputId, String wrappedInputId) {
182279124a717c09f12c74d587d3977bf33ca37e6420Terry Heo            synchronized (mLock) {
182379124a717c09f12c74d587d3977bf33ca37e6420Terry Heo                if (!hasInputIdLocked(inputId)) {
182479124a717c09f12c74d587d3977bf33ca37e6420Terry Heo                    return;
182579124a717c09f12c74d587d3977bf33ca37e6420Terry Heo                }
182679124a717c09f12c74d587d3977bf33ca37e6420Terry Heo                UserState userState = getUserStateLocked(mUserId);
182779124a717c09f12c74d587d3977bf33ca37e6420Terry Heo                userState.wrappedInputMap.put(inputId, wrappedInputId);
182879124a717c09f12c74d587d3977bf33ca37e6420Terry Heo            }
182979124a717c09f12c74d587d3977bf33ca37e6420Terry Heo        }
183079124a717c09f12c74d587d3977bf33ca37e6420Terry Heo
183179124a717c09f12c74d587d3977bf33ca37e6420Terry Heo        private boolean hasInputIdLocked(String inputId) {
183279124a717c09f12c74d587d3977bf33ca37e6420Terry Heo            ServiceState serviceState = getServiceStateLocked(mName, mUserId);
183379124a717c09f12c74d587d3977bf33ca37e6420Terry Heo            for (TvInputInfo inputInfo : serviceState.mInputList) {
183479124a717c09f12c74d587d3977bf33ca37e6420Terry Heo                if (inputInfo.getId().equals(inputId)) {
183579124a717c09f12c74d587d3977bf33ca37e6420Terry Heo                    return true;
183679124a717c09f12c74d587d3977bf33ca37e6420Terry Heo                }
183779124a717c09f12c74d587d3977bf33ca37e6420Terry Heo            }
183879124a717c09f12c74d587d3977bf33ca37e6420Terry Heo            return false;
183979124a717c09f12c74d587d3977bf33ca37e6420Terry Heo        }
18403957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    }
184131dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo
184231dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo    private final class LogHandler extends Handler {
184331dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo        private static final int MSG_OPEN_ENTRY = 1;
184431dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo        private static final int MSG_UPDATE_ENTRY = 2;
184531dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo        private static final int MSG_CLOSE_ENTRY = 3;
184631dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo
184731dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo        public LogHandler(Looper looper) {
184831dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo            super(looper);
184931dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo        }
185031dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo
185131dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo        @Override
185231dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo        public void handleMessage(Message msg) {
185331dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo            switch (msg.what) {
185431dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                case MSG_OPEN_ENTRY: {
185531dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                    SomeArgs args = (SomeArgs) msg.obj;
185631dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                    Uri uri = (Uri) args.arg1;
185731dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                    long channelId = (long) args.arg2;
185831dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                    long time = (long) args.arg3;
185931dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                    onOpenEntry(uri, channelId, time);
186031dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                    args.recycle();
186131dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                    return;
186231dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                }
186331dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                case MSG_UPDATE_ENTRY: {
186431dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                    SomeArgs args = (SomeArgs) msg.obj;
186531dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                    Uri uri = (Uri) args.arg1;
186631dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                    long channelId = (long) args.arg2;
186731dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                    long time = (long) args.arg3;
186831dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                    onUpdateEntry(uri, channelId, time);
186931dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                    args.recycle();
187031dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                    return;
187131dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                }
187231dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                case MSG_CLOSE_ENTRY: {
187331dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                    SomeArgs args = (SomeArgs) msg.obj;
187431dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                    Uri uri = (Uri) args.arg1;
187531dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                    long time = (long) args.arg2;
187631dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                    onCloseEntry(uri, time);
187731dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                    args.recycle();
187831dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                    return;
187931dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                }
188031dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                default: {
18816a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                    Slog.w(TAG, "Unhandled message code: " + msg.what);
188231dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                    return;
188331dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                }
188431dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo            }
188531dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo        }
188631dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo
188731dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo        private void onOpenEntry(Uri uri, long channelId, long watchStarttime) {
188831dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo            String[] projection = {
1889f5cd0b388ac31104e014f9193d06080851a09e18Jae Seo                    TvContract.Programs.COLUMN_TITLE,
1890f5cd0b388ac31104e014f9193d06080851a09e18Jae Seo                    TvContract.Programs.COLUMN_START_TIME_UTC_MILLIS,
1891f5cd0b388ac31104e014f9193d06080851a09e18Jae Seo                    TvContract.Programs.COLUMN_END_TIME_UTC_MILLIS,
1892bd23fa0ba1460a8d5194fd7c700030bf9c3f6fcbJae Seo                    TvContract.Programs.COLUMN_SHORT_DESCRIPTION
189331dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo            };
1894f5cd0b388ac31104e014f9193d06080851a09e18Jae Seo            String selection = TvContract.Programs.COLUMN_CHANNEL_ID + "=? AND "
1895f5cd0b388ac31104e014f9193d06080851a09e18Jae Seo                    + TvContract.Programs.COLUMN_START_TIME_UTC_MILLIS + "<=? AND "
1896f5cd0b388ac31104e014f9193d06080851a09e18Jae Seo                    + TvContract.Programs.COLUMN_END_TIME_UTC_MILLIS + ">?";
189731dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo            String[] selectionArgs = {
189831dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                    String.valueOf(channelId),
189931dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                    String.valueOf(watchStarttime),
190031dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                    String.valueOf(watchStarttime)
190131dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo            };
1902f5cd0b388ac31104e014f9193d06080851a09e18Jae Seo            String sortOrder = TvContract.Programs.COLUMN_START_TIME_UTC_MILLIS + " ASC";
190331dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo            Cursor cursor = null;
190431dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo            try {
190531dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                cursor = mContentResolver.query(TvContract.Programs.CONTENT_URI, projection,
190631dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                        selection, selectionArgs, sortOrder);
190731dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                if (cursor != null && cursor.moveToNext()) {
190831dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                    ContentValues values = new ContentValues();
1909f5cd0b388ac31104e014f9193d06080851a09e18Jae Seo                    values.put(TvContract.WatchedPrograms.COLUMN_TITLE, cursor.getString(0));
1910f5cd0b388ac31104e014f9193d06080851a09e18Jae Seo                    values.put(TvContract.WatchedPrograms.COLUMN_START_TIME_UTC_MILLIS,
1911f5cd0b388ac31104e014f9193d06080851a09e18Jae Seo                            cursor.getLong(1));
191231dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                    long endTime = cursor.getLong(2);
1913f5cd0b388ac31104e014f9193d06080851a09e18Jae Seo                    values.put(TvContract.WatchedPrograms.COLUMN_END_TIME_UTC_MILLIS, endTime);
1914f5cd0b388ac31104e014f9193d06080851a09e18Jae Seo                    values.put(TvContract.WatchedPrograms.COLUMN_DESCRIPTION, cursor.getString(3));
191531dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                    mContentResolver.update(uri, values, null, null);
191631dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo
191731dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                    // Schedule an update when the current program ends.
191831dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                    SomeArgs args = SomeArgs.obtain();
191931dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                    args.arg1 = uri;
192031dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                    args.arg2 = channelId;
192131dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                    args.arg3 = endTime;
192231dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                    Message msg = obtainMessage(LogHandler.MSG_UPDATE_ENTRY, args);
192331dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                    sendMessageDelayed(msg, endTime - System.currentTimeMillis());
192431dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                }
192531dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo            } finally {
192631dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                if (cursor != null) {
192731dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                    cursor.close();
192831dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                }
192931dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo            }
193031dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo        }
193131dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo
193231dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo        private void onUpdateEntry(Uri uri, long channelId, long time) {
193331dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo            String[] projection = {
1934f5cd0b388ac31104e014f9193d06080851a09e18Jae Seo                    TvContract.WatchedPrograms.COLUMN_WATCH_START_TIME_UTC_MILLIS,
1935f5cd0b388ac31104e014f9193d06080851a09e18Jae Seo                    TvContract.WatchedPrograms.COLUMN_WATCH_END_TIME_UTC_MILLIS,
1936f5cd0b388ac31104e014f9193d06080851a09e18Jae Seo                    TvContract.WatchedPrograms.COLUMN_TITLE,
1937f5cd0b388ac31104e014f9193d06080851a09e18Jae Seo                    TvContract.WatchedPrograms.COLUMN_START_TIME_UTC_MILLIS,
1938f5cd0b388ac31104e014f9193d06080851a09e18Jae Seo                    TvContract.WatchedPrograms.COLUMN_END_TIME_UTC_MILLIS,
1939f5cd0b388ac31104e014f9193d06080851a09e18Jae Seo                    TvContract.WatchedPrograms.COLUMN_DESCRIPTION
194031dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo            };
194131dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo            Cursor cursor = null;
194231dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo            try {
194331dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                cursor = mContentResolver.query(uri, projection, null, null, null);
194431dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                if (cursor != null && cursor.moveToNext()) {
194531dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                    long watchStartTime = cursor.getLong(0);
194631dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                    long watchEndTime = cursor.getLong(1);
194731dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                    String title = cursor.getString(2);
194831dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                    long startTime = cursor.getLong(3);
194931dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                    long endTime = cursor.getLong(4);
195031dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                    String description = cursor.getString(5);
195131dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo
195231dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                    // Do nothing if the current log entry is already closed.
195331dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                    if (watchEndTime > 0) {
195431dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                        return;
195531dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                    }
195631dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo
195731dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                    // The current program has just ended. Create a (complete) log entry off the
195831dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                    // current entry.
195931dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                    ContentValues values = new ContentValues();
1960f5cd0b388ac31104e014f9193d06080851a09e18Jae Seo                    values.put(TvContract.WatchedPrograms.COLUMN_WATCH_START_TIME_UTC_MILLIS,
196131dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                            watchStartTime);
1962f5cd0b388ac31104e014f9193d06080851a09e18Jae Seo                    values.put(TvContract.WatchedPrograms.COLUMN_WATCH_END_TIME_UTC_MILLIS, time);
1963f5cd0b388ac31104e014f9193d06080851a09e18Jae Seo                    values.put(TvContract.WatchedPrograms.COLUMN_CHANNEL_ID, channelId);
1964f5cd0b388ac31104e014f9193d06080851a09e18Jae Seo                    values.put(TvContract.WatchedPrograms.COLUMN_TITLE, title);
1965f5cd0b388ac31104e014f9193d06080851a09e18Jae Seo                    values.put(TvContract.WatchedPrograms.COLUMN_START_TIME_UTC_MILLIS, startTime);
1966f5cd0b388ac31104e014f9193d06080851a09e18Jae Seo                    values.put(TvContract.WatchedPrograms.COLUMN_END_TIME_UTC_MILLIS, endTime);
1967f5cd0b388ac31104e014f9193d06080851a09e18Jae Seo                    values.put(TvContract.WatchedPrograms.COLUMN_DESCRIPTION, description);
196831dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                    mContentResolver.insert(TvContract.WatchedPrograms.CONTENT_URI, values);
196931dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                }
197031dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo            } finally {
197131dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                if (cursor != null) {
197231dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                    cursor.close();
197331dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                }
197431dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo            }
197531dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo            // Re-open the current log entry with the next program information.
197631dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo            onOpenEntry(uri, channelId, time);
197731dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo        }
197831dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo
197931dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo        private void onCloseEntry(Uri uri, long watchEndTime) {
198031dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo            ContentValues values = new ContentValues();
1981f5cd0b388ac31104e014f9193d06080851a09e18Jae Seo            values.put(TvContract.WatchedPrograms.COLUMN_WATCH_END_TIME_UTC_MILLIS, watchEndTime);
198231dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo            mContentResolver.update(uri, values, null, null);
198331dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo        }
198431dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo    }
1985969167dc05a6485a32d160895871cff46fd81884Wonsik Kim
1986187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim    final class HardwareListener implements TvInputHardwareManager.Listener {
1987187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim        @Override
1988187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim        public void onStateChanged(String inputId, int state) {
1989969167dc05a6485a32d160895871cff46fd81884Wonsik Kim            synchronized (mLock) {
1990969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                setStateLocked(inputId, state, mCurrentUserId);
1991969167dc05a6485a32d160895871cff46fd81884Wonsik Kim            }
1992969167dc05a6485a32d160895871cff46fd81884Wonsik Kim        }
1993187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim
1994187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim        @Override
1995187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim        public void onHardwareDeviceAdded(TvInputHardwareInfo info) {
1996187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim            synchronized (mLock) {
1997187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                UserState userState = getUserStateLocked(mCurrentUserId);
1998187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                // Broadcast the event to all hardware inputs.
1999187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                for (ServiceState serviceState : userState.serviceStateMap.values()) {
2000187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                    if (!serviceState.mIsHardware || serviceState.mService == null) continue;
2001187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                    try {
2002187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                        serviceState.mService.notifyHardwareAdded(info);
2003187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                    } catch (RemoteException e) {
2004187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                        Slog.e(TAG, "error in notifyHardwareAdded", e);
2005187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                    }
2006187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                }
2007187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim            }
2008187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim        }
2009187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim
2010187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim        @Override
20114f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee        public void onHardwareDeviceRemoved(TvInputHardwareInfo info) {
2012187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim            synchronized (mLock) {
2013187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                UserState userState = getUserStateLocked(mCurrentUserId);
2014187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                // Broadcast the event to all hardware inputs.
2015187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                for (ServiceState serviceState : userState.serviceStateMap.values()) {
2016187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                    if (!serviceState.mIsHardware || serviceState.mService == null) continue;
2017187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                    try {
20184f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                        serviceState.mService.notifyHardwareRemoved(info);
2019187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                    } catch (RemoteException e) {
2020187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                        Slog.e(TAG, "error in notifyHardwareRemoved", e);
2021187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                    }
2022187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                }
2023187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim            }
2024187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim        }
2025187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim
2026187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim        @Override
20274f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee        public void onHdmiCecDeviceAdded(HdmiCecDeviceInfo cecDeviceInfo) {
2028187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim            synchronized (mLock) {
20294f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                UserState userState = getUserStateLocked(mCurrentUserId);
20304f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                // Broadcast the event to all hardware inputs.
20314f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                for (ServiceState serviceState : userState.serviceStateMap.values()) {
20324f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                    if (!serviceState.mIsHardware || serviceState.mService == null) continue;
20334f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                    try {
20344f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                        serviceState.mService.notifyHdmiCecDeviceAdded(cecDeviceInfo);
20354f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                    } catch (RemoteException e) {
20364f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                        Slog.e(TAG, "error in notifyHdmiCecDeviceAdded", e);
20374f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                    }
20384f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                }
2039187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim            }
2040187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim        }
2041187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim
2042187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim        @Override
20434f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee        public void onHdmiCecDeviceRemoved(HdmiCecDeviceInfo cecDeviceInfo) {
2044187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim            synchronized (mLock) {
20454f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                UserState userState = getUserStateLocked(mCurrentUserId);
20464f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                // Broadcast the event to all hardware inputs.
20474f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                for (ServiceState serviceState : userState.serviceStateMap.values()) {
20484f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                    if (!serviceState.mIsHardware || serviceState.mService == null) continue;
20494f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                    try {
20504f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                        serviceState.mService.notifyHdmiCecDeviceRemoved(cecDeviceInfo);
20514f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                    } catch (RemoteException e) {
20524f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                        Slog.e(TAG, "error in notifyHdmiCecDeviceRemoved", e);
20534f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                    }
20544f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                }
2055187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim            }
2056187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim        }
2057969167dc05a6485a32d160895871cff46fd81884Wonsik Kim    }
20583957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo}
2059