TvInputManagerService.java revision 008f6d4e326f6372e165bdf342178ecd1e834e2f
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;
541f213914c45c23c653f721690da2ce0718e63139Dongwon Kangimport android.media.tv.TvTrackInfo;
553957091ba8f08c02b5e781098cb955a5f697a1ffJae Seoimport android.net.Uri;
563957091ba8f08c02b5e781098cb955a5f697a1ffJae Seoimport android.os.Binder;
57832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Choimport android.os.Bundle;
5831dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seoimport android.os.Handler;
593957091ba8f08c02b5e781098cb955a5f697a1ffJae Seoimport android.os.IBinder;
6031dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seoimport android.os.Looper;
6131dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seoimport android.os.Message;
623957091ba8f08c02b5e781098cb955a5f697a1ffJae Seoimport android.os.Process;
633957091ba8f08c02b5e781098cb955a5f697a1ffJae Seoimport android.os.RemoteException;
643957091ba8f08c02b5e781098cb955a5f697a1ffJae Seoimport android.os.UserHandle;
659a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Choimport android.util.Slog;
663957091ba8f08c02b5e781098cb955a5f697a1ffJae Seoimport android.util.SparseArray;
676a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seoimport android.view.InputChannel;
683957091ba8f08c02b5e781098cb955a5f697a1ffJae Seoimport android.view.Surface;
693957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
703957091ba8f08c02b5e781098cb955a5f697a1ffJae Seoimport com.android.internal.content.PackageMonitor;
7131dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seoimport com.android.internal.os.SomeArgs;
72e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kimimport com.android.internal.util.IndentingPrintWriter;
7331dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seoimport com.android.server.IoThread;
743957091ba8f08c02b5e781098cb955a5f697a1ffJae Seoimport com.android.server.SystemService;
753957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
76e7bb7d6bb2257c24076f5a4b9f536f90a6637f58Chulwoo Leeimport org.xmlpull.v1.XmlPullParserException;
77e7bb7d6bb2257c24076f5a4b9f536f90a6637f58Chulwoo Lee
78e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kimimport java.io.FileDescriptor;
79e7bb7d6bb2257c24076f5a4b9f536f90a6637f58Chulwoo Leeimport java.io.IOException;
80e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kimimport java.io.PrintWriter;
813957091ba8f08c02b5e781098cb955a5f697a1ffJae Seoimport java.util.ArrayList;
823957091ba8f08c02b5e781098cb955a5f697a1ffJae Seoimport java.util.HashMap;
835c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seoimport java.util.HashSet;
84187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kimimport java.util.Iterator;
853957091ba8f08c02b5e781098cb955a5f697a1ffJae Seoimport java.util.List;
863957091ba8f08c02b5e781098cb955a5f697a1ffJae Seoimport java.util.Map;
875c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seoimport java.util.Set;
883957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
893957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo/** This class provides a system service that manages television inputs. */
903957091ba8f08c02b5e781098cb955a5f697a1ffJae Seopublic final class TvInputManagerService extends SystemService {
913957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    // STOPSHIP: Turn debugging off.
923957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    private static final boolean DEBUG = true;
933957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    private static final String TAG = "TvInputManagerService";
943957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
953957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    private final Context mContext;
96c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim    private final TvInputHardwareManager mTvInputHardwareManager;
973957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
9831dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo    private final ContentResolver mContentResolver;
9931dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo
1003957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    // A global lock.
1013957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    private final Object mLock = new Object();
1023957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
1033957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    // ID of the current user.
1043957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    private int mCurrentUserId = UserHandle.USER_OWNER;
1053957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
1063957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    // A map from user id to UserState.
1073957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    private final SparseArray<UserState> mUserStates = new SparseArray<UserState>();
1083957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
10931dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo    private final Handler mLogHandler;
11031dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo
1113957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    public TvInputManagerService(Context context) {
1123957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        super(context);
11331dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo
1143957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        mContext = context;
11531dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo        mContentResolver = context.getContentResolver();
11631dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo        mLogHandler = new LogHandler(IoThread.get().getLooper());
11731dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo
118187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim        mTvInputHardwareManager = new TvInputHardwareManager(context, new HardwareListener());
11931dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo
1203957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        synchronized (mLock) {
1213957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            mUserStates.put(mCurrentUserId, new UserState());
1223957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
1233957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    }
1243957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
1253957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    @Override
1263957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    public void onStart() {
1273957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        publishBinderService(Context.TV_INPUT_SERVICE, new BinderService());
1283957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    }
1293957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
1300ceb7e4755015eafda29c251eac285620788a51bJi-Hwan Lee    @Override
1310ceb7e4755015eafda29c251eac285620788a51bJi-Hwan Lee    public void onBootPhase(int phase) {
1320ceb7e4755015eafda29c251eac285620788a51bJi-Hwan Lee        if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY) {
1330ceb7e4755015eafda29c251eac285620788a51bJi-Hwan Lee            registerBroadcastReceivers();
134187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim        } else if (phase == SystemService.PHASE_THIRD_PARTY_APPS_CAN_START) {
1350ceb7e4755015eafda29c251eac285620788a51bJi-Hwan Lee            synchronized (mLock) {
1360ceb7e4755015eafda29c251eac285620788a51bJi-Hwan Lee                buildTvInputListLocked(mCurrentUserId);
1370ceb7e4755015eafda29c251eac285620788a51bJi-Hwan Lee            }
1380ceb7e4755015eafda29c251eac285620788a51bJi-Hwan Lee        }
139969167dc05a6485a32d160895871cff46fd81884Wonsik Kim        mTvInputHardwareManager.onBootPhase(phase);
1400ceb7e4755015eafda29c251eac285620788a51bJi-Hwan Lee    }
1410ceb7e4755015eafda29c251eac285620788a51bJi-Hwan Lee
1423957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    private void registerBroadcastReceivers() {
1433957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        PackageMonitor monitor = new PackageMonitor() {
1443957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            @Override
1453957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            public void onSomePackagesChanged() {
1463957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                synchronized (mLock) {
1473957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    buildTvInputListLocked(mCurrentUserId);
1483957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                }
1493957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            }
1505c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo
1515c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo            @Override
1525c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo            public void onPackageRemoved(String packageName, int uid) {
1535c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo                synchronized (mLock) {
1545c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo                    UserState userState = getUserStateLocked(mCurrentUserId);
155969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                    if (!userState.packageSet.contains(packageName)) {
1565c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo                        // Not a TV input package.
1575c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo                        return;
1585c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo                    }
1595c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo                }
1605c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo
1615c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo                ArrayList<ContentProviderOperation> operations =
1625c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo                        new ArrayList<ContentProviderOperation>();
1635c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo
1645c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo                String selection = TvContract.BaseTvColumns.COLUMN_PACKAGE_NAME + "=?";
1655c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo                String[] selectionArgs = { packageName };
1665c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo
1675c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo                operations.add(ContentProviderOperation.newDelete(TvContract.Channels.CONTENT_URI)
1685c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo                        .withSelection(selection, selectionArgs).build());
1695c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo                operations.add(ContentProviderOperation.newDelete(TvContract.Programs.CONTENT_URI)
1705c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo                        .withSelection(selection, selectionArgs).build());
1715c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo                operations.add(ContentProviderOperation
1725c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo                        .newDelete(TvContract.WatchedPrograms.CONTENT_URI)
1735c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo                        .withSelection(selection, selectionArgs).build());
1745c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo
1755c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo                ContentProviderResult[] results = null;
1765c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo                try {
1775c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo                    results = mContentResolver.applyBatch(TvContract.AUTHORITY, operations);
1785c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo                } catch (RemoteException | OperationApplicationException e) {
1795c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo                    Slog.e(TAG, "error in applyBatch" + e);
1805c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo                }
1815c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo
1825c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo                if (DEBUG) {
1835c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo                    Slog.d(TAG, "onPackageRemoved(packageName=" + packageName + ", uid=" + uid
1845c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo                            + ")");
1855c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo                    Slog.d(TAG, "results=" + results);
1865c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo                }
1875c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo            }
1883957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        };
1893957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        monitor.register(mContext, null, UserHandle.ALL, true);
1903957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
1913957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        IntentFilter intentFilter = new IntentFilter();
1923957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        intentFilter.addAction(Intent.ACTION_USER_SWITCHED);
1933957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        intentFilter.addAction(Intent.ACTION_USER_REMOVED);
1943957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        mContext.registerReceiverAsUser(new BroadcastReceiver() {
1953957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            @Override
1963957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            public void onReceive(Context context, Intent intent) {
1973957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                String action = intent.getAction();
1983957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                if (Intent.ACTION_USER_SWITCHED.equals(action)) {
1993957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    switchUser(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0));
2003957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                } else if (Intent.ACTION_USER_REMOVED.equals(action)) {
2013957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    removeUser(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0));
2023957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                }
2033957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            }
2043957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }, UserHandle.ALL, intentFilter, null, null);
2053957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    }
2063957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
207187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim    private static boolean hasHardwarePermission(PackageManager pm, ComponentName name) {
208187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim        return pm.checkPermission(android.Manifest.permission.TV_INPUT_HARDWARE,
209187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                name.getPackageName()) == PackageManager.PERMISSION_GRANTED;
210187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim    }
211187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim
2123957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    private void buildTvInputListLocked(int userId) {
2133957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        UserState userState = getUserStateLocked(userId);
214969167dc05a6485a32d160895871cff46fd81884Wonsik Kim
2158e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim        Map<String, TvInputState> inputMap = new HashMap<String, TvInputState>();
216969167dc05a6485a32d160895871cff46fd81884Wonsik Kim        userState.packageSet.clear();
2173957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
2189a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho        if (DEBUG) Slog.d(TAG, "buildTvInputList");
2193957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        PackageManager pm = mContext.getPackageManager();
2203957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        List<ResolveInfo> services = pm.queryIntentServices(
221e7bb7d6bb2257c24076f5a4b9f536f90a6637f58Chulwoo Lee                new Intent(TvInputService.SERVICE_INTERFACE),
222e7bb7d6bb2257c24076f5a4b9f536f90a6637f58Chulwoo Lee                PackageManager.GET_SERVICES | PackageManager.GET_META_DATA);
2234f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee        List<TvInputInfo> inputList = new ArrayList<TvInputInfo>();
2243957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        for (ResolveInfo ri : services) {
2253957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            ServiceInfo si = ri.serviceInfo;
2263957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            if (!android.Manifest.permission.BIND_TV_INPUT.equals(si.permission)) {
2279a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                Slog.w(TAG, "Skipping TV input " + si.name + ": it does not require the permission "
2283957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                        + android.Manifest.permission.BIND_TV_INPUT);
2293957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                continue;
2303957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            }
231e7bb7d6bb2257c24076f5a4b9f536f90a6637f58Chulwoo Lee            try {
2324f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                inputList.clear();
233187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                ComponentName service = new ComponentName(si.packageName, si.name);
234187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                if (hasHardwarePermission(pm, service)) {
235187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                    ServiceState serviceState = userState.serviceStateMap.get(service);
236187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                    if (serviceState == null) {
237187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                        // We see this hardware TV input service for the first time; we need to
238187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                        // prepare the ServiceState object so that we can connect to the service and
239187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                        // let it add TvInputInfo objects to mInputList if there's any.
240187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                        serviceState = new ServiceState(service, userId);
241187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                        userState.serviceStateMap.put(service, serviceState);
242187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                    } else {
2434f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                        inputList.addAll(serviceState.mInputList);
244187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                    }
245187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                } else {
2464f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                    inputList.add(TvInputInfo.createTvInputInfo(mContext, ri));
247187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                }
248187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim
2494f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                for (TvInputInfo info : inputList) {
250187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                    if (DEBUG) Slog.d(TAG, "add " + info.getId());
2518e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim                    TvInputState state = userState.inputMap.get(info.getId());
252187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                    if (state == null) {
253187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                        state = new TvInputState();
254187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                    }
255187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                    state.mInfo = info;
2568e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim                    inputMap.put(info.getId(), state);
257969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                }
258226a51958d645a8e2be3e40a6b6daaca558b4913Jaewan Kim
259226a51958d645a8e2be3e40a6b6daaca558b4913Jaewan Kim                // Reconnect the service if existing input is updated.
260187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                updateServiceConnectionLocked(service, userId);
261187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim
262187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                userState.packageSet.add(si.packageName);
263e7bb7d6bb2257c24076f5a4b9f536f90a6637f58Chulwoo Lee            } catch (IOException | XmlPullParserException e) {
264e7bb7d6bb2257c24076f5a4b9f536f90a6637f58Chulwoo Lee                Slog.e(TAG, "Can't load TV input " + si.name, e);
265e7bb7d6bb2257c24076f5a4b9f536f90a6637f58Chulwoo Lee            }
2663957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
2678e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim
2688e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim        for (String inputId : inputMap.keySet()) {
2698e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim            if (!userState.inputMap.containsKey(inputId)) {
2708e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim                notifyInputAddedLocked(userState, inputId);
2718e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim            }
2728e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim        }
2738e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim
2748e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim        for (String inputId : userState.inputMap.keySet()) {
2758e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim            if (!inputMap.containsKey(inputId)) {
2768e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim                notifyInputRemovedLocked(userState, inputId);
2778e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim            }
2788e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim        }
2798e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim
2808e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim        userState.inputMap.clear();
2818e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim        userState.inputMap = inputMap;
2823957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    }
2833957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
2843957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    private void switchUser(int userId) {
2853957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        synchronized (mLock) {
2863957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            if (mCurrentUserId == userId) {
2873957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                return;
2883957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            }
2893957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            // final int oldUserId = mCurrentUserId;
2903957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            // TODO: Release services and sessions in the old user state, if needed.
2913957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            mCurrentUserId = userId;
2923957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
2933957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            UserState userState = mUserStates.get(userId);
2943957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            if (userState == null) {
2953957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                userState = new UserState();
2963957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            }
2973957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            mUserStates.put(userId, userState);
2983957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            buildTvInputListLocked(userId);
2993957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
3003957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    }
3013957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
3023957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    private void removeUser(int userId) {
3033957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        synchronized (mLock) {
304b06cb8870f0407f18bb1225065a93aba2a5de2bfJae Seo            UserState userState = mUserStates.get(userId);
305b06cb8870f0407f18bb1225065a93aba2a5de2bfJae Seo            if (userState == null) {
306b06cb8870f0407f18bb1225065a93aba2a5de2bfJae Seo                return;
307b06cb8870f0407f18bb1225065a93aba2a5de2bfJae Seo            }
3083957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            // Release created sessions.
3093957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            for (SessionState state : userState.sessionStateMap.values()) {
310d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim                if (state.mSession != null) {
3113957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    try {
312d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim                        state.mSession.release();
3133957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    } catch (RemoteException e) {
3149a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                        Slog.e(TAG, "error in release", e);
3153957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    }
3163957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                }
3173957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            }
3183957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            userState.sessionStateMap.clear();
3193957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
3203957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            // Unregister all callbacks and unbind all services.
3213957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            for (ServiceState serviceState : userState.serviceStateMap.values()) {
322d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim                if (serviceState.mCallback != null) {
3233957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    try {
324d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim                        serviceState.mService.unregisterCallback(serviceState.mCallback);
3253957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    } catch (RemoteException e) {
3269a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                        Slog.e(TAG, "error in unregisterCallback", e);
3273957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    }
3283957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                }
32972ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim                serviceState.mClientTokens.clear();
330d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim                mContext.unbindService(serviceState.mConnection);
3313957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            }
3323957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            userState.serviceStateMap.clear();
3333957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
33472ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim            userState.clientStateMap.clear();
33572ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim
3363957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            mUserStates.remove(userId);
3373957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
3383957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    }
3393957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
3403957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    private UserState getUserStateLocked(int userId) {
3413957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        UserState userState = mUserStates.get(userId);
3423957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        if (userState == null) {
3433957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            throw new IllegalStateException("User state not found for user ID " + userId);
3443957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
3453957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        return userState;
3463957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    }
3473957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
348187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim    private ServiceState getServiceStateLocked(ComponentName name, int userId) {
3493957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        UserState userState = getUserStateLocked(userId);
350187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim        ServiceState serviceState = userState.serviceStateMap.get(name);
3513957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        if (serviceState == null) {
352187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim            throw new IllegalStateException("Service state not found for " + name + " (userId="
3537de5e234715a3baa8905afa3dd0c5009af64541fSungsoo Lim                    + userId + ")");
3543957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
3553957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        return serviceState;
3563957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    }
3573957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
3582b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim    private SessionState getSessionStateLocked(IBinder sessionToken, int callingUid, int userId) {
3593957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        UserState userState = getUserStateLocked(userId);
3603957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        SessionState sessionState = userState.sessionStateMap.get(sessionToken);
3613957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        if (sessionState == null) {
3623957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            throw new IllegalArgumentException("Session state not found for token " + sessionToken);
3633957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
3643957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        // Only the application that requested this session or the system can access it.
365d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim        if (callingUid != Process.SYSTEM_UID && callingUid != sessionState.mCallingUid) {
3663957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            throw new SecurityException("Illegal access to the session with token " + sessionToken
3673957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    + " from uid " + callingUid);
3683957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
3692b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim        return sessionState;
3702b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim    }
3712b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim
3722b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim    private ITvInputSession getSessionLocked(IBinder sessionToken, int callingUid, int userId) {
3732b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim        SessionState sessionState = getSessionStateLocked(sessionToken, callingUid, userId);
374d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim        ITvInputSession session = sessionState.mSession;
3753957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        if (session == null) {
3763957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            throw new IllegalStateException("Session not yet created for token " + sessionToken);
3773957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
3783957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        return session;
3793957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    }
3803957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
3813957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    private int resolveCallingUserId(int callingPid, int callingUid, int requestedUserId,
3823957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            String methodName) {
3833957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        return ActivityManager.handleIncomingUser(callingPid, callingUid, requestedUserId, false,
3843957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                false, methodName, null);
3853957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    }
3863957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
387187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim    private static boolean shouldMaintainConnection(ServiceState serviceState) {
388187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim        return !serviceState.mClientTokens.isEmpty()
389187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                || !serviceState.mSessionTokens.isEmpty()
390187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                || serviceState.mIsHardware;
391187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim        // TODO: Find a way to maintain connection only when necessary.
392187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim    }
393187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim
394187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim    private void updateServiceConnectionLocked(ComponentName service, int userId) {
3953957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        UserState userState = getUserStateLocked(userId);
396187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim        ServiceState serviceState = userState.serviceStateMap.get(service);
3973957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        if (serviceState == null) {
3983957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            return;
3993957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
4002b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim        if (serviceState.mReconnecting) {
4012b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim            if (!serviceState.mSessionTokens.isEmpty()) {
4022b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                // wait until all the sessions are removed.
4032b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                return;
4042b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim            }
4052b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim            serviceState.mReconnecting = false;
4062b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim        }
407187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim        boolean maintainConnection = shouldMaintainConnection(serviceState);
408187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim        if (serviceState.mService == null && maintainConnection && userId == mCurrentUserId) {
4093957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            // This means that the service is not yet connected but its state indicates that we
4103957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            // have pending requests. Then, connect the service.
411d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim            if (serviceState.mBound) {
4123957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                // We have already bound to the service so we don't try to bind again until after we
4133957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                // unbind later on.
4143957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                return;
4153957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            }
4163957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            if (DEBUG) {
417187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                Slog.d(TAG, "bindServiceAsUser(service=" + service + ", userId=" + userId + ")");
4183957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            }
419d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim
420187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim            Intent i = new Intent(TvInputService.SERVICE_INTERFACE).setComponent(service);
421226a51958d645a8e2be3e40a6b6daaca558b4913Jaewan Kim            // Binding service may fail if the service is updating.
422226a51958d645a8e2be3e40a6b6daaca558b4913Jaewan Kim            // In that case, the connection will be revived in buildTvInputListLocked called by
423226a51958d645a8e2be3e40a6b6daaca558b4913Jaewan Kim            // onSomePackagesChanged.
424e17b2dd7bcc137bf4d842a779e8d62c63957a978Ji-Hwan Lee            serviceState.mBound = mContext.bindServiceAsUser(
425e17b2dd7bcc137bf4d842a779e8d62c63957a978Ji-Hwan Lee                    i, serviceState.mConnection, Context.BIND_AUTO_CREATE, new UserHandle(userId));
426187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim        } else if (serviceState.mService != null && !maintainConnection) {
4273957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            // This means that the service is already connected but its state indicates that we have
4283957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            // nothing to do with it. Then, disconnect the service.
4293957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            if (DEBUG) {
430187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                Slog.d(TAG, "unbindService(service=" + service + ")");
4313957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            }
432d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim            mContext.unbindService(serviceState.mConnection);
433187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim            userState.serviceStateMap.remove(service);
4343957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
4353957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    }
4363957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
43772ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim    private ClientState createClientStateLocked(IBinder clientToken, int userId) {
43872ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim        UserState userState = getUserStateLocked(userId);
43972ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim        ClientState clientState = new ClientState(clientToken, userId);
44072ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim        try {
44172ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim            clientToken.linkToDeath(clientState, 0);
44272ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim        } catch (RemoteException e) {
44372ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim            Slog.e(TAG, "Client is already died.");
44472ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim        }
44572ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim        userState.clientStateMap.put(clientToken, clientState);
44672ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim        return clientState;
44772ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim    }
44872ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim
4493957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    private void createSessionInternalLocked(ITvInputService service, final IBinder sessionToken,
4507de5e234715a3baa8905afa3dd0c5009af64541fSungsoo Lim            final int userId) {
45172ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim        final UserState userState = getUserStateLocked(userId);
45272ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim        final SessionState sessionState = userState.sessionStateMap.get(sessionToken);
4533957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        if (DEBUG) {
454187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim            Slog.d(TAG, "createSessionInternalLocked(inputId=" + sessionState.mInfo.getId() + ")");
4553957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
4566a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo
4576a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo        final InputChannel[] channels = InputChannel.openInputChannelPair(sessionToken.toString());
4586a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo
4593957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        // Set up a callback to send the session token.
4603957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        ITvInputSessionCallback callback = new ITvInputSessionCallback.Stub() {
4613957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            @Override
4623957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            public void onSessionCreated(ITvInputSession session) {
4633957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                if (DEBUG) {
464187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                    Slog.d(TAG, "onSessionCreated(inputId=" + sessionState.mInfo.getId() + ")");
4653957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                }
4663957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                synchronized (mLock) {
467d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim                    sessionState.mSession = session;
468fd5b72f1ed2ee74a4204eef65f560fc82f0b62feDongwon Kang                    if (session == null) {
469fd5b72f1ed2ee74a4204eef65f560fc82f0b62feDongwon Kang                        removeSessionStateLocked(sessionToken, userId);
470187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                        sendSessionTokenToClientLocked(sessionState.mClient,
471187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                                sessionState.mInfo.getId(), null, null, sessionState.mSeq);
472fd5b72f1ed2ee74a4204eef65f560fc82f0b62feDongwon Kang                    } else {
4732b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                        try {
4742b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                            session.asBinder().linkToDeath(sessionState, 0);
4752b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                        } catch (RemoteException e) {
4762b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                            Slog.e(TAG, "Session is already died.");
4772b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                        }
47872ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim
47972ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim                        IBinder clientToken = sessionState.mClient.asBinder();
48072ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim                        ClientState clientState = userState.clientStateMap.get(clientToken);
48172ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim                        if (clientState == null) {
48272ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim                            clientState = createClientStateLocked(clientToken, userId);
48372ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim                        }
48472ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim                        clientState.mSessionTokens.add(sessionState.mSessionToken);
48572ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim
486187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                        sendSessionTokenToClientLocked(sessionState.mClient,
487187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                                sessionState.mInfo.getId(), sessionToken, channels[0],
488187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                                sessionState.mSeq);
489fd5b72f1ed2ee74a4204eef65f560fc82f0b62feDongwon Kang                    }
4906a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                    channels[0].dispose();
4913957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                }
4923957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            }
493832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho
494832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho            @Override
4951f213914c45c23c653f721690da2ce0718e63139Dongwon Kang            public void onChannelRetuned(Uri channelUri) {
496a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang                synchronized (mLock) {
497a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang                    if (DEBUG) {
4981f213914c45c23c653f721690da2ce0718e63139Dongwon Kang                        Slog.d(TAG, "onChannelRetuned(" + channelUri + ")");
499a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang                    }
500a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang                    if (sessionState.mSession == null || sessionState.mClient == null) {
501a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang                        return;
502a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang                    }
503a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang                    try {
5041f213914c45c23c653f721690da2ce0718e63139Dongwon Kang                        // TODO: Consider adding this channel change in the watch log. When we do
5051f213914c45c23c653f721690da2ce0718e63139Dongwon Kang                        // that, how we can protect the watch log from malicious tv inputs should
5061f213914c45c23c653f721690da2ce0718e63139Dongwon Kang                        // be addressed. e.g. add a field which represents where the channel change
5071f213914c45c23c653f721690da2ce0718e63139Dongwon Kang                        // originated from.
5081f213914c45c23c653f721690da2ce0718e63139Dongwon Kang                        sessionState.mClient.onChannelRetuned(channelUri, sessionState.mSeq);
509a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang                    } catch (RemoteException e) {
5101f213914c45c23c653f721690da2ce0718e63139Dongwon Kang                        Slog.e(TAG, "error in onChannelRetuned");
511a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang                    }
512a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang                }
513a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang            }
514a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang
515a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang            @Override
5161f213914c45c23c653f721690da2ce0718e63139Dongwon Kang            public void onTrackInfoChanged(List<TvTrackInfo> tracks) {
517a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang                synchronized (mLock) {
518a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang                    if (DEBUG) {
5191f213914c45c23c653f721690da2ce0718e63139Dongwon Kang                        Slog.d(TAG, "onTrackInfoChanged(" + tracks + ")");
520a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang                    }
521a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang                    if (sessionState.mSession == null || sessionState.mClient == null) {
522a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang                        return;
523a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang                    }
524a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang                    try {
5251f213914c45c23c653f721690da2ce0718e63139Dongwon Kang                        sessionState.mClient.onTrackInfoChanged(tracks,
526a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang                                sessionState.mSeq);
527a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang                    } catch (RemoteException e) {
5281f213914c45c23c653f721690da2ce0718e63139Dongwon Kang                        Slog.e(TAG, "error in onTrackInfoChanged");
529b93ccca6139a7ee2dba5c110e5f8213a2bd231e5Dongwon Kang                    }
530b93ccca6139a7ee2dba5c110e5f8213a2bd231e5Dongwon Kang                }
531b93ccca6139a7ee2dba5c110e5f8213a2bd231e5Dongwon Kang            }
532b93ccca6139a7ee2dba5c110e5f8213a2bd231e5Dongwon Kang
533b93ccca6139a7ee2dba5c110e5f8213a2bd231e5Dongwon Kang            @Override
5349b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang            public void onVideoAvailable() {
5359b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                synchronized (mLock) {
5369b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                    if (DEBUG) {
5379b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                        Slog.d(TAG, "onVideoAvailable()");
5389b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                    }
5399b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                    if (sessionState.mSession == null || sessionState.mClient == null) {
5409b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                        return;
5419b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                    }
5429b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                    try {
5439b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                        sessionState.mClient.onVideoAvailable(sessionState.mSeq);
5449b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                    } catch (RemoteException e) {
5459b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                        Slog.e(TAG, "error in onVideoAvailable");
5469b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                    }
5479b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                }
5489b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang            }
5499b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang
5509b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang            @Override
5519b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang            public void onVideoUnavailable(int reason) {
5529b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                synchronized (mLock) {
5539b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                    if (DEBUG) {
5549b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                        Slog.d(TAG, "onVideoUnavailable(" + reason + ")");
5559b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                    }
5569b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                    if (sessionState.mSession == null || sessionState.mClient == null) {
5579b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                        return;
5589b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                    }
5599b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                    try {
5609b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                        sessionState.mClient.onVideoUnavailable(reason, sessionState.mSeq);
5619b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                    } catch (RemoteException e) {
5629b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                        Slog.e(TAG, "error in onVideoUnavailable");
5639b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                    }
5649b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                }
5659b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang            }
5669b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang
5679b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang            @Override
568bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo            public void onContentAllowed() {
569bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo                synchronized (mLock) {
570bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo                    if (DEBUG) {
571bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo                        Slog.d(TAG, "onContentAllowed()");
572bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo                    }
573bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo                    if (sessionState.mSession == null || sessionState.mClient == null) {
574bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo                        return;
575bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo                    }
576bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo                    try {
577bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo                        sessionState.mClient.onContentAllowed(sessionState.mSeq);
578bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo                    } catch (RemoteException e) {
579bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo                        Slog.e(TAG, "error in onContentAllowed");
580bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo                    }
581bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo                }
582bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo            }
583bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo
584bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo            @Override
5856057102dbb746593a7d59cf377c969b62e38c664Jae Seo            public void onContentBlocked(String rating) {
5866057102dbb746593a7d59cf377c969b62e38c664Jae Seo                synchronized (mLock) {
5876057102dbb746593a7d59cf377c969b62e38c664Jae Seo                    if (DEBUG) {
5886057102dbb746593a7d59cf377c969b62e38c664Jae Seo                        Slog.d(TAG, "onContentBlocked()");
5896057102dbb746593a7d59cf377c969b62e38c664Jae Seo                    }
5906057102dbb746593a7d59cf377c969b62e38c664Jae Seo                    if (sessionState.mSession == null || sessionState.mClient == null) {
5916057102dbb746593a7d59cf377c969b62e38c664Jae Seo                        return;
5926057102dbb746593a7d59cf377c969b62e38c664Jae Seo                    }
5936057102dbb746593a7d59cf377c969b62e38c664Jae Seo                    try {
5946057102dbb746593a7d59cf377c969b62e38c664Jae Seo                        sessionState.mClient.onContentBlocked(rating, sessionState.mSeq);
5956057102dbb746593a7d59cf377c969b62e38c664Jae Seo                    } catch (RemoteException e) {
5966057102dbb746593a7d59cf377c969b62e38c664Jae Seo                        Slog.e(TAG, "error in onContentBlocked");
5976057102dbb746593a7d59cf377c969b62e38c664Jae Seo                    }
5986057102dbb746593a7d59cf377c969b62e38c664Jae Seo                }
5996057102dbb746593a7d59cf377c969b62e38c664Jae Seo            }
6006057102dbb746593a7d59cf377c969b62e38c664Jae Seo
6016057102dbb746593a7d59cf377c969b62e38c664Jae Seo            @Override
602832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho            public void onSessionEvent(String eventType, Bundle eventArgs) {
603832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho                synchronized (mLock) {
604832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho                    if (DEBUG) {
605832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho                        Slog.d(TAG, "onEvent(what=" + eventType + ", data=" + eventArgs + ")");
606832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho                    }
607832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho                    if (sessionState.mSession == null || sessionState.mClient == null) {
608832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho                        return;
609832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho                    }
610832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho                    try {
611832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho                        sessionState.mClient.onSessionEvent(eventType, eventArgs,
612832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho                                sessionState.mSeq);
613832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho                    } catch (RemoteException e) {
614832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho                        Slog.e(TAG, "error in onSessionEvent");
615832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho                    }
616832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho                }
617832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho            }
6183957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        };
6193957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
6203957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        // Create a session. When failed, send a null token immediately.
6213957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        try {
622187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim            service.createSession(channels[1], callback, sessionState.mInfo.getId());
6233957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        } catch (RemoteException e) {
6249a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            Slog.e(TAG, "error in createSession", e);
625fd5b72f1ed2ee74a4204eef65f560fc82f0b62feDongwon Kang            removeSessionStateLocked(sessionToken, userId);
626187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim            sendSessionTokenToClientLocked(sessionState.mClient, sessionState.mInfo.getId(), null,
627187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                    null, sessionState.mSeq);
6283957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
6296a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo        channels[1].dispose();
6303957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    }
6313957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
632d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim    private void sendSessionTokenToClientLocked(ITvInputClient client, String inputId,
6335c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo            IBinder sessionToken, InputChannel channel, int seq) {
6343957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        try {
635d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim            client.onSessionCreated(inputId, sessionToken, channel, seq);
6363957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        } catch (RemoteException exception) {
6379a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            Slog.e(TAG, "error in onSessionCreated", exception);
6383957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
6392b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim    }
6403957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
6412b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim    private void releaseSessionLocked(IBinder sessionToken, int callingUid, int userId) {
6422b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim        SessionState sessionState = getSessionStateLocked(sessionToken, callingUid, userId);
6432b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim        if (sessionState.mSession != null) {
6442b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim            try {
6452b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                sessionState.mSession.release();
6462b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim            } catch (RemoteException e) {
6472b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                Slog.w(TAG, "session is already disapeared", e);
6482b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim            }
6492b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim            sessionState.mSession = null;
6503957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
6512b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim        removeSessionStateLocked(sessionToken, userId);
6523957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    }
6533957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
654fd5b72f1ed2ee74a4204eef65f560fc82f0b62feDongwon Kang    private void removeSessionStateLocked(IBinder sessionToken, int userId) {
655fd5b72f1ed2ee74a4204eef65f560fc82f0b62feDongwon Kang        // Remove the session state from the global session state map of the current user.
656fd5b72f1ed2ee74a4204eef65f560fc82f0b62feDongwon Kang        UserState userState = getUserStateLocked(userId);
657fd5b72f1ed2ee74a4204eef65f560fc82f0b62feDongwon Kang        SessionState sessionState = userState.sessionStateMap.remove(sessionToken);
658fd5b72f1ed2ee74a4204eef65f560fc82f0b62feDongwon Kang
65931dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo        // Close the open log entry, if any.
660d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim        if (sessionState.mLogUri != null) {
66131dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo            SomeArgs args = SomeArgs.obtain();
662d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim            args.arg1 = sessionState.mLogUri;
66331dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo            args.arg2 = System.currentTimeMillis();
66431dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo            mLogHandler.obtainMessage(LogHandler.MSG_CLOSE_ENTRY, args).sendToTarget();
66531dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo        }
66631dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo
66772ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim        // Also remove the session token from the session token list of the current client and
66872ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim        // service.
66972ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim        ClientState clientState = userState.clientStateMap.get(sessionState.mClient.asBinder());
67072ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim        if (clientState != null) {
67172ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim            clientState.mSessionTokens.remove(sessionToken);
67272ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim            if (clientState.isEmpty()) {
67372ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim                userState.clientStateMap.remove(sessionState.mClient.asBinder());
67472ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim            }
67572ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim        }
67672ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim
677187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim        TvInputInfo info = sessionState.mInfo;
678187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim        if (info != null) {
679187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim            ServiceState serviceState = userState.serviceStateMap.get(info.getComponent());
680187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim            if (serviceState != null) {
681187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                serviceState.mSessionTokens.remove(sessionToken);
682187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim            }
683fd5b72f1ed2ee74a4204eef65f560fc82f0b62feDongwon Kang        }
684187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim        updateServiceConnectionLocked(sessionState.mInfo.getComponent(), userId);
685fd5b72f1ed2ee74a4204eef65f560fc82f0b62feDongwon Kang    }
686fd5b72f1ed2ee74a4204eef65f560fc82f0b62feDongwon Kang
687969167dc05a6485a32d160895871cff46fd81884Wonsik Kim    private void unregisterClientInternalLocked(IBinder clientToken, String inputId,
68872ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim            int userId) {
68972ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim        UserState userState = getUserStateLocked(userId);
69072ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim        ClientState clientState = userState.clientStateMap.get(clientToken);
69172ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim        if (clientState != null) {
69272ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim            clientState.mInputIds.remove(inputId);
69372ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim            if (clientState.isEmpty()) {
69472ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim                userState.clientStateMap.remove(clientToken);
69572ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim            }
69672ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim        }
69772ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim
698187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim        TvInputInfo info = userState.inputMap.get(inputId).mInfo;
699187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim        if (info == null) {
700187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim            return;
701187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim        }
702187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim        ServiceState serviceState = userState.serviceStateMap.get(info.getComponent());
70372ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim        if (serviceState == null) {
70472ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim            return;
70572ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim        }
70672ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim
70772ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim        // Remove this client from the client list and unregister the callback.
70872ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim        serviceState.mClientTokens.remove(clientToken);
70972ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim        if (!serviceState.mClientTokens.isEmpty()) {
71072ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim            // We have other clients who want to keep the callback. Do this later.
71172ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim            return;
71272ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim        }
71372ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim        if (serviceState.mService == null || serviceState.mCallback == null) {
71472ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim            return;
71572ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim        }
71672ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim        try {
71772ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim            serviceState.mService.unregisterCallback(serviceState.mCallback);
71872ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim        } catch (RemoteException e) {
71972ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim            Slog.e(TAG, "error in unregisterCallback", e);
72072ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim        } finally {
72172ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim            serviceState.mCallback = null;
722187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim            updateServiceConnectionLocked(info.getComponent(), userId);
72372ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim        }
72472ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim    }
72572ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim
7268e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim    private void notifyInputAddedLocked(UserState userState, String inputId) {
7278e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim        if (DEBUG) {
7288e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim            Slog.d(TAG, "notifyInputAdded: inputId = " + inputId);
7298e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim        }
7308e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim        for (ITvInputManagerCallback callback : userState.callbackSet) {
7318e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim            try {
7328e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim                callback.onInputAdded(inputId);
7338e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim            } catch (RemoteException e) {
7348e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim                Slog.e(TAG, "Failed to report added input to callback.");
7358e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim            }
7368e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim        }
7378e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim    }
7388e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim
7398e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim    private void notifyInputRemovedLocked(UserState userState, String inputId) {
7408e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim        if (DEBUG) {
7418e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim            Slog.d(TAG, "notifyInputRemovedLocked: inputId = " + inputId);
7428e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim        }
7438e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim        for (ITvInputManagerCallback callback : userState.callbackSet) {
7448e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim            try {
7458e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim                callback.onInputRemoved(inputId);
7468e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim            } catch (RemoteException e) {
7478e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim                Slog.e(TAG, "Failed to report removed input to callback.");
7488e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim            }
7498e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim        }
7508e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim    }
7518e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim
7528e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim    private void notifyInputStateChangedLocked(UserState userState, String inputId,
753969167dc05a6485a32d160895871cff46fd81884Wonsik Kim            int state, ITvInputManagerCallback targetCallback) {
754969167dc05a6485a32d160895871cff46fd81884Wonsik Kim        if (DEBUG) {
7558e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim            Slog.d(TAG, "notifyInputStateChangedLocked: inputId = " + inputId
756969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                    + "; state = " + state);
757969167dc05a6485a32d160895871cff46fd81884Wonsik Kim        }
758969167dc05a6485a32d160895871cff46fd81884Wonsik Kim        if (targetCallback == null) {
759969167dc05a6485a32d160895871cff46fd81884Wonsik Kim            for (ITvInputManagerCallback callback : userState.callbackSet) {
760969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                try {
761969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                    callback.onInputStateChanged(inputId, state);
762969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                } catch (RemoteException e) {
763969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                    Slog.e(TAG, "Failed to report state change to callback.");
764969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                }
765969167dc05a6485a32d160895871cff46fd81884Wonsik Kim            }
766969167dc05a6485a32d160895871cff46fd81884Wonsik Kim        } else {
7672b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim            try {
768969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                targetCallback.onInputStateChanged(inputId, state);
7692b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim            } catch (RemoteException e) {
770969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                Slog.e(TAG, "Failed to report state change to callback.");
7712b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim            }
7722b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim        }
7732b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim    }
7742b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim
775969167dc05a6485a32d160895871cff46fd81884Wonsik Kim    private void setStateLocked(String inputId, int state, int userId) {
776969167dc05a6485a32d160895871cff46fd81884Wonsik Kim        UserState userState = getUserStateLocked(userId);
777969167dc05a6485a32d160895871cff46fd81884Wonsik Kim        TvInputState inputState = userState.inputMap.get(inputId);
778969167dc05a6485a32d160895871cff46fd81884Wonsik Kim        ServiceState serviceState = userState.serviceStateMap.get(inputId);
779969167dc05a6485a32d160895871cff46fd81884Wonsik Kim        int oldState = inputState.mState;
780969167dc05a6485a32d160895871cff46fd81884Wonsik Kim        inputState.mState = state;
781187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim        if (serviceState != null && serviceState.mService == null
782187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                && shouldMaintainConnection(serviceState)) {
783969167dc05a6485a32d160895871cff46fd81884Wonsik Kim            // We don't notify state change while reconnecting. It should remain disconnected.
784969167dc05a6485a32d160895871cff46fd81884Wonsik Kim            return;
785969167dc05a6485a32d160895871cff46fd81884Wonsik Kim        }
786969167dc05a6485a32d160895871cff46fd81884Wonsik Kim        if (oldState != state) {
7878e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim            notifyInputStateChangedLocked(userState, inputId, state, null);
788969167dc05a6485a32d160895871cff46fd81884Wonsik Kim        }
789969167dc05a6485a32d160895871cff46fd81884Wonsik Kim    }
790969167dc05a6485a32d160895871cff46fd81884Wonsik Kim
7913957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    private final class BinderService extends ITvInputManager.Stub {
7923957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        @Override
7933957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        public List<TvInputInfo> getTvInputList(int userId) {
7943957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(),
7953957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    Binder.getCallingUid(), userId, "getTvInputList");
7963957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            final long identity = Binder.clearCallingIdentity();
7973957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            try {
7983957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                synchronized (mLock) {
7993957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    UserState userState = getUserStateLocked(resolvedUserId);
800969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                    List<TvInputInfo> inputList = new ArrayList<TvInputInfo>();
801969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                    for (TvInputState state : userState.inputMap.values()) {
802969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                        inputList.add(state.mInfo);
8033957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    }
804969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                    return inputList;
8053957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                }
8063957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            } finally {
8073957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                Binder.restoreCallingIdentity(identity);
8083957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            }
809b375805f3b1672e68d1511565af4700e5fa8491dJae Seo        }
810b375805f3b1672e68d1511565af4700e5fa8491dJae Seo
811b375805f3b1672e68d1511565af4700e5fa8491dJae Seo        @Override
812b375805f3b1672e68d1511565af4700e5fa8491dJae Seo        public TvInputInfo getTvInputInfo(String inputId, int userId) {
813b375805f3b1672e68d1511565af4700e5fa8491dJae Seo            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(),
814b375805f3b1672e68d1511565af4700e5fa8491dJae Seo                    Binder.getCallingUid(), userId, "getTvInputInfo");
815b375805f3b1672e68d1511565af4700e5fa8491dJae Seo            final long identity = Binder.clearCallingIdentity();
816b375805f3b1672e68d1511565af4700e5fa8491dJae Seo            try {
817b375805f3b1672e68d1511565af4700e5fa8491dJae Seo                synchronized (mLock) {
818b375805f3b1672e68d1511565af4700e5fa8491dJae Seo                    UserState userState = getUserStateLocked(resolvedUserId);
819b375805f3b1672e68d1511565af4700e5fa8491dJae Seo                    TvInputState state = userState.inputMap.get(inputId);
820b375805f3b1672e68d1511565af4700e5fa8491dJae Seo                    return state == null ? null : state.mInfo;
821b375805f3b1672e68d1511565af4700e5fa8491dJae Seo                }
822b375805f3b1672e68d1511565af4700e5fa8491dJae Seo            } finally {
823b375805f3b1672e68d1511565af4700e5fa8491dJae Seo                Binder.restoreCallingIdentity(identity);
824b375805f3b1672e68d1511565af4700e5fa8491dJae Seo            }
8253957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
8263957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
8273957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        @Override
828969167dc05a6485a32d160895871cff46fd81884Wonsik Kim        public void registerCallback(final ITvInputManagerCallback callback, int userId) {
8293957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(),
8303957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    Binder.getCallingUid(), userId, "registerCallback");
8313957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            final long identity = Binder.clearCallingIdentity();
8323957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            try {
8333957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                synchronized (mLock) {
8343957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    UserState userState = getUserStateLocked(resolvedUserId);
835969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                    userState.callbackSet.add(callback);
836969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                    for (TvInputState state : userState.inputMap.values()) {
8378e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim                        notifyInputStateChangedLocked(userState, state.mInfo.getId(),
838969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                                state.mState, callback);
8393957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    }
8403957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                }
8413957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            } finally {
8423957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                Binder.restoreCallingIdentity(identity);
8433957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            }
8443957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
8453957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
8463957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        @Override
847969167dc05a6485a32d160895871cff46fd81884Wonsik Kim        public void unregisterCallback(ITvInputManagerCallback callback, int userId) {
8483957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(),
8493957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    Binder.getCallingUid(), userId, "unregisterCallback");
8503957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            final long identity = Binder.clearCallingIdentity();
8513957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            try {
8523957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                synchronized (mLock) {
853969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                    UserState userState = getUserStateLocked(resolvedUserId);
854969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                    userState.callbackSet.remove(callback);
8553957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                }
8563957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            } finally {
8573957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                Binder.restoreCallingIdentity(identity);
8583957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            }
8593957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
8603957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
8613957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        @Override
862d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim        public void createSession(final ITvInputClient client, final String inputId,
8633957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                int seq, int userId) {
8643957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            final int callingUid = Binder.getCallingUid();
8653957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
8663957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    userId, "createSession");
8673957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            final long identity = Binder.clearCallingIdentity();
8683957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            try {
8693957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                synchronized (mLock) {
8703957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    UserState userState = getUserStateLocked(resolvedUserId);
871187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                    TvInputInfo info = userState.inputMap.get(inputId).mInfo;
872187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                    ServiceState serviceState = userState.serviceStateMap.get(info.getComponent());
8733957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    if (serviceState == null) {
874187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                        serviceState = new ServiceState(info.getComponent(), resolvedUserId);
875187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                        userState.serviceStateMap.put(info.getComponent(), serviceState);
8763957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    }
8772b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                    // Send a null token immediately while reconnecting.
8782b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                    if (serviceState.mReconnecting == true) {
8795c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo                        sendSessionTokenToClientLocked(client, inputId, null, null, seq);
8802b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                        return;
8812b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                    }
8822b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim
8832b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                    // Create a new session token and a session state.
8842b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                    IBinder sessionToken = new Binder();
885187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                    SessionState sessionState = new SessionState(sessionToken, info, client,
88672ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim                            seq, callingUid, resolvedUserId);
8872b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim
8882b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                    // Add them to the global session state map of the current user.
8892b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                    userState.sessionStateMap.put(sessionToken, sessionState);
8902b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim
8912b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                    // Also, add them to the session state map of the current service.
892d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim                    serviceState.mSessionTokens.add(sessionToken);
8933957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
894d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim                    if (serviceState.mService != null) {
895d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim                        createSessionInternalLocked(serviceState.mService, sessionToken,
8967de5e234715a3baa8905afa3dd0c5009af64541fSungsoo Lim                                resolvedUserId);
8973957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    } else {
898187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                        updateServiceConnectionLocked(info.getComponent(), resolvedUserId);
8993957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    }
9003957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                }
9013957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            } finally {
9023957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                Binder.restoreCallingIdentity(identity);
9033957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            }
9043957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
9053957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
9063957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        @Override
9073957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        public void releaseSession(IBinder sessionToken, int userId) {
9083957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            final int callingUid = Binder.getCallingUid();
9093957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
9103957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    userId, "releaseSession");
9113957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            final long identity = Binder.clearCallingIdentity();
9123957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            try {
9133957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                synchronized (mLock) {
9142b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                    releaseSessionLocked(sessionToken, callingUid, resolvedUserId);
9153957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                }
9163957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            } finally {
9173957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                Binder.restoreCallingIdentity(identity);
9183957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            }
9193957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
9203957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
9213957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        @Override
9223957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        public void setSurface(IBinder sessionToken, Surface surface, int userId) {
9233957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            final int callingUid = Binder.getCallingUid();
9243957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
9253957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    userId, "setSurface");
9263957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            final long identity = Binder.clearCallingIdentity();
9273957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            try {
9283957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                synchronized (mLock) {
9293957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    try {
9303957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                        getSessionLocked(sessionToken, callingUid, resolvedUserId).setSurface(
9313957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                                surface);
9323957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    } catch (RemoteException e) {
9339a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                        Slog.e(TAG, "error in setSurface", e);
9343957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    }
9353957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                }
9363957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            } finally {
937f836206818ce338db83a3c23c486fb8cab29cb6dYoungsang Cho                if (surface != null) {
938f836206818ce338db83a3c23c486fb8cab29cb6dYoungsang Cho                    // surface is not used in TvInputManagerService.
939f836206818ce338db83a3c23c486fb8cab29cb6dYoungsang Cho                    surface.release();
940f836206818ce338db83a3c23c486fb8cab29cb6dYoungsang Cho                }
9413957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                Binder.restoreCallingIdentity(identity);
9423957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            }
9433957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
9443957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
9453957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        @Override
946e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho        public void dispatchSurfaceChanged(IBinder sessionToken, int format, int width,
947e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho                int height, int userId) {
948e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho            final int callingUid = Binder.getCallingUid();
949e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
950e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho                    userId, "dispatchSurfaceChanged");
951e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho            final long identity = Binder.clearCallingIdentity();
952e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho            try {
953e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho                synchronized (mLock) {
954e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho                    try {
955e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho                        getSessionLocked(sessionToken, callingUid, resolvedUserId)
956e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho                                .dispatchSurfaceChanged(format, width, height);
957e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho                    } catch (RemoteException e) {
958e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho                        Slog.e(TAG, "error in dispatchSurfaceChanged", e);
959e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho                    }
960e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho                }
961e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho            } finally {
962e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho                Binder.restoreCallingIdentity(identity);
963e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho            }
964e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho        }
965e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho
966e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho        @Override
9673957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        public void setVolume(IBinder sessionToken, float volume, int userId) {
9683957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            final int callingUid = Binder.getCallingUid();
9693957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
9703957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    userId, "setVolume");
9713957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            final long identity = Binder.clearCallingIdentity();
9723957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            try {
9733957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                synchronized (mLock) {
9743957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    try {
9753957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                        getSessionLocked(sessionToken, callingUid, resolvedUserId).setVolume(
9763957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                                volume);
9773957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    } catch (RemoteException e) {
9789a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                        Slog.e(TAG, "error in setVolume", e);
9793957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    }
9803957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                }
9813957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            } finally {
9823957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                Binder.restoreCallingIdentity(identity);
9833957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            }
9843957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
9853957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
9863957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        @Override
9873957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        public void tune(IBinder sessionToken, final Uri channelUri, int userId) {
9883957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            final int callingUid = Binder.getCallingUid();
9893957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
9903957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    userId, "tune");
9913957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            final long identity = Binder.clearCallingIdentity();
9923957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            try {
9933957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                synchronized (mLock) {
9943957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    try {
9953957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                        getSessionLocked(sessionToken, callingUid, resolvedUserId).tune(channelUri);
996008f6d4e326f6372e165bdf342178ecd1e834e2fYoungsang Cho                        if (TvContract.isChannelUriForPassthroughTvInput(channelUri)) {
997008f6d4e326f6372e165bdf342178ecd1e834e2fYoungsang Cho                            // Do not log the watch history for passthrough inputs.
998008f6d4e326f6372e165bdf342178ecd1e834e2fYoungsang Cho                            return;
999008f6d4e326f6372e165bdf342178ecd1e834e2fYoungsang Cho                        }
100031dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                        long currentTime = System.currentTimeMillis();
100131dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                        long channelId = ContentUris.parseId(channelUri);
100231dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo
100331dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                        // Close the open log entry first, if any.
100431dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                        UserState userState = getUserStateLocked(resolvedUserId);
100531dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                        SessionState sessionState = userState.sessionStateMap.get(sessionToken);
1006d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim                        if (sessionState.mLogUri != null) {
100731dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                            SomeArgs args = SomeArgs.obtain();
1008d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim                            args.arg1 = sessionState.mLogUri;
100931dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                            args.arg2 = currentTime;
101031dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                            mLogHandler.obtainMessage(LogHandler.MSG_CLOSE_ENTRY, args)
101131dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                                    .sendToTarget();
101231dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                        }
101331dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo
101431dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                        // Create a log entry and fill it later.
1015187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                        String packageName = sessionState.mInfo.getServiceInfo().packageName;
101631dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                        ContentValues values = new ContentValues();
10175c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo                        values.put(TvContract.WatchedPrograms.COLUMN_PACKAGE_NAME, packageName);
1018f5cd0b388ac31104e014f9193d06080851a09e18Jae Seo                        values.put(TvContract.WatchedPrograms.COLUMN_WATCH_START_TIME_UTC_MILLIS,
101931dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                                currentTime);
1020f5cd0b388ac31104e014f9193d06080851a09e18Jae Seo                        values.put(TvContract.WatchedPrograms.COLUMN_WATCH_END_TIME_UTC_MILLIS, 0);
1021f5cd0b388ac31104e014f9193d06080851a09e18Jae Seo                        values.put(TvContract.WatchedPrograms.COLUMN_CHANNEL_ID, channelId);
102231dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo
1023d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim                        sessionState.mLogUri = mContentResolver.insert(
102431dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                                TvContract.WatchedPrograms.CONTENT_URI, values);
102531dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                        SomeArgs args = SomeArgs.obtain();
1026d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim                        args.arg1 = sessionState.mLogUri;
102731dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                        args.arg2 = ContentUris.parseId(channelUri);
102831dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                        args.arg3 = currentTime;
102931dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                        mLogHandler.obtainMessage(LogHandler.MSG_OPEN_ENTRY, args).sendToTarget();
10303957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    } catch (RemoteException e) {
10319a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                        Slog.e(TAG, "error in tune", e);
10323957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                        return;
10333957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    }
10343957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                }
10353957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            } finally {
10363957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                Binder.restoreCallingIdentity(identity);
10373957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            }
10383957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
10399a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho
10409a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho        @Override
10419bf671f8ee72b156f16fcf05a3d1c6e093ecba67Sungsoo Lim        public void requestUnblockContent(
10429bf671f8ee72b156f16fcf05a3d1c6e093ecba67Sungsoo Lim                IBinder sessionToken, String unblockedRating, int userId) {
1043903d6b72cd572665309633e925485464d08bb25aJaewan Kim            final int callingUid = Binder.getCallingUid();
1044903d6b72cd572665309633e925485464d08bb25aJaewan Kim            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
1045903d6b72cd572665309633e925485464d08bb25aJaewan Kim                    userId, "unblockContent");
1046903d6b72cd572665309633e925485464d08bb25aJaewan Kim            final long identity = Binder.clearCallingIdentity();
1047903d6b72cd572665309633e925485464d08bb25aJaewan Kim            try {
1048903d6b72cd572665309633e925485464d08bb25aJaewan Kim                synchronized (mLock) {
1049903d6b72cd572665309633e925485464d08bb25aJaewan Kim                    try {
1050903d6b72cd572665309633e925485464d08bb25aJaewan Kim                        getSessionLocked(sessionToken, callingUid, resolvedUserId)
10519bf671f8ee72b156f16fcf05a3d1c6e093ecba67Sungsoo Lim                                .requestUnblockContent(unblockedRating);
1052903d6b72cd572665309633e925485464d08bb25aJaewan Kim                    } catch (RemoteException e) {
1053903d6b72cd572665309633e925485464d08bb25aJaewan Kim                        Slog.e(TAG, "error in unblockContent", e);
1054903d6b72cd572665309633e925485464d08bb25aJaewan Kim                    }
1055903d6b72cd572665309633e925485464d08bb25aJaewan Kim                }
1056903d6b72cd572665309633e925485464d08bb25aJaewan Kim            } finally {
1057903d6b72cd572665309633e925485464d08bb25aJaewan Kim                Binder.restoreCallingIdentity(identity);
1058903d6b72cd572665309633e925485464d08bb25aJaewan Kim            }
1059903d6b72cd572665309633e925485464d08bb25aJaewan Kim        }
1060903d6b72cd572665309633e925485464d08bb25aJaewan Kim
1061903d6b72cd572665309633e925485464d08bb25aJaewan Kim        @Override
10622c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo        public void setCaptionEnabled(IBinder sessionToken, boolean enabled, int userId) {
10632c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo            final int callingUid = Binder.getCallingUid();
10642c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
10652c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo                    userId, "setCaptionEnabled");
10662c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo            final long identity = Binder.clearCallingIdentity();
10672c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo            try {
10682c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo                synchronized (mLock) {
10692c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo                    try {
10702c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo                        getSessionLocked(sessionToken, callingUid, resolvedUserId)
10712c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo                                .setCaptionEnabled(enabled);
10722c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo                    } catch (RemoteException e) {
10732c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo                        Slog.e(TAG, "error in setCaptionEnabled", e);
10742c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo                    }
10752c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo                }
10762c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo            } finally {
10772c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo                Binder.restoreCallingIdentity(identity);
10782c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo            }
10792c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo        }
10802c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo
10812c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo        @Override
10821f213914c45c23c653f721690da2ce0718e63139Dongwon Kang        public void selectTrack(IBinder sessionToken, TvTrackInfo track, int userId) {
10831f213914c45c23c653f721690da2ce0718e63139Dongwon Kang            final int callingUid = Binder.getCallingUid();
10841f213914c45c23c653f721690da2ce0718e63139Dongwon Kang            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
10851f213914c45c23c653f721690da2ce0718e63139Dongwon Kang                    userId, "selectTrack");
10861f213914c45c23c653f721690da2ce0718e63139Dongwon Kang            final long identity = Binder.clearCallingIdentity();
10871f213914c45c23c653f721690da2ce0718e63139Dongwon Kang            try {
10881f213914c45c23c653f721690da2ce0718e63139Dongwon Kang                synchronized (mLock) {
10891f213914c45c23c653f721690da2ce0718e63139Dongwon Kang                    try {
10901f213914c45c23c653f721690da2ce0718e63139Dongwon Kang                        getSessionLocked(sessionToken, callingUid, resolvedUserId).selectTrack(
10911f213914c45c23c653f721690da2ce0718e63139Dongwon Kang                                track);
10921f213914c45c23c653f721690da2ce0718e63139Dongwon Kang                    } catch (RemoteException e) {
10931f213914c45c23c653f721690da2ce0718e63139Dongwon Kang                        Slog.e(TAG, "error in selectTrack", e);
10941f213914c45c23c653f721690da2ce0718e63139Dongwon Kang                    }
10951f213914c45c23c653f721690da2ce0718e63139Dongwon Kang                }
10961f213914c45c23c653f721690da2ce0718e63139Dongwon Kang            } finally {
10971f213914c45c23c653f721690da2ce0718e63139Dongwon Kang                Binder.restoreCallingIdentity(identity);
10981f213914c45c23c653f721690da2ce0718e63139Dongwon Kang            }
10991f213914c45c23c653f721690da2ce0718e63139Dongwon Kang        }
11001f213914c45c23c653f721690da2ce0718e63139Dongwon Kang
11011f213914c45c23c653f721690da2ce0718e63139Dongwon Kang        @Override
11021f213914c45c23c653f721690da2ce0718e63139Dongwon Kang        public void unselectTrack(IBinder sessionToken, TvTrackInfo track, int userId) {
11031f213914c45c23c653f721690da2ce0718e63139Dongwon Kang            final int callingUid = Binder.getCallingUid();
11041f213914c45c23c653f721690da2ce0718e63139Dongwon Kang            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
11051f213914c45c23c653f721690da2ce0718e63139Dongwon Kang                    userId, "unselectTrack");
11061f213914c45c23c653f721690da2ce0718e63139Dongwon Kang            final long identity = Binder.clearCallingIdentity();
11071f213914c45c23c653f721690da2ce0718e63139Dongwon Kang            try {
11081f213914c45c23c653f721690da2ce0718e63139Dongwon Kang                synchronized (mLock) {
11091f213914c45c23c653f721690da2ce0718e63139Dongwon Kang                    try {
11101f213914c45c23c653f721690da2ce0718e63139Dongwon Kang                        getSessionLocked(sessionToken, callingUid, resolvedUserId).unselectTrack(
11111f213914c45c23c653f721690da2ce0718e63139Dongwon Kang                                track);
11121f213914c45c23c653f721690da2ce0718e63139Dongwon Kang                    } catch (RemoteException e) {
11131f213914c45c23c653f721690da2ce0718e63139Dongwon Kang                        Slog.e(TAG, "error in unselectTrack", e);
11141f213914c45c23c653f721690da2ce0718e63139Dongwon Kang                    }
11151f213914c45c23c653f721690da2ce0718e63139Dongwon Kang                }
11161f213914c45c23c653f721690da2ce0718e63139Dongwon Kang            } finally {
11171f213914c45c23c653f721690da2ce0718e63139Dongwon Kang                Binder.restoreCallingIdentity(identity);
11181f213914c45c23c653f721690da2ce0718e63139Dongwon Kang            }
11191f213914c45c23c653f721690da2ce0718e63139Dongwon Kang        }
11201f213914c45c23c653f721690da2ce0718e63139Dongwon Kang
11211f213914c45c23c653f721690da2ce0718e63139Dongwon Kang        @Override
1122a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo        public void sendAppPrivateCommand(IBinder sessionToken, String command, Bundle data,
1123a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo                int userId) {
1124a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo            final int callingUid = Binder.getCallingUid();
1125a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
1126a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo                    userId, "sendAppPrivateCommand");
1127a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo            final long identity = Binder.clearCallingIdentity();
1128a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo            try {
1129a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo                synchronized (mLock) {
1130a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo                    try {
1131a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo                        getSessionLocked(sessionToken, callingUid, resolvedUserId)
1132a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo                                .appPrivateCommand(command, data);
1133a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo                    } catch (RemoteException e) {
1134a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo                        Slog.e(TAG, "error in sendAppPrivateCommand", e);
1135a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo                    }
1136a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo                }
1137a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo            } finally {
1138a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo                Binder.restoreCallingIdentity(identity);
1139a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo            }
1140a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo        }
1141a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo
1142a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo        @Override
11439a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho        public void createOverlayView(IBinder sessionToken, IBinder windowToken, Rect frame,
11449a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                int userId) {
11459a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            final int callingUid = Binder.getCallingUid();
11469a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
11479a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                    userId, "createOverlayView");
11489a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            final long identity = Binder.clearCallingIdentity();
11499a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            try {
11509a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                synchronized (mLock) {
11519a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                    try {
11529a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                        getSessionLocked(sessionToken, callingUid, resolvedUserId)
11539a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                                .createOverlayView(windowToken, frame);
11549a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                    } catch (RemoteException e) {
11559a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                        Slog.e(TAG, "error in createOverlayView", e);
11569a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                    }
11579a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                }
11589a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            } finally {
11599a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                Binder.restoreCallingIdentity(identity);
11609a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            }
11619a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho        }
11629a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho
11639a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho        @Override
11649a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho        public void relayoutOverlayView(IBinder sessionToken, Rect frame, int userId) {
11659a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            final int callingUid = Binder.getCallingUid();
11669a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
11679a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                    userId, "relayoutOverlayView");
11689a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            final long identity = Binder.clearCallingIdentity();
11699a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            try {
11709a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                synchronized (mLock) {
11719a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                    try {
11729a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                        getSessionLocked(sessionToken, callingUid, resolvedUserId)
11739a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                                .relayoutOverlayView(frame);
11749a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                    } catch (RemoteException e) {
11759a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                        Slog.e(TAG, "error in relayoutOverlayView", e);
11769a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                    }
11779a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                }
11789a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            } finally {
11799a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                Binder.restoreCallingIdentity(identity);
11809a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            }
11819a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho        }
11829a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho
11839a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho        @Override
11849a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho        public void removeOverlayView(IBinder sessionToken, int userId) {
11859a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            final int callingUid = Binder.getCallingUid();
11869a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
11879a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                    userId, "removeOverlayView");
11889a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            final long identity = Binder.clearCallingIdentity();
11899a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            try {
11909a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                synchronized (mLock) {
11919a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                    try {
11929a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                        getSessionLocked(sessionToken, callingUid, resolvedUserId)
11939a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                                .removeOverlayView();
11949a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                    } catch (RemoteException e) {
11959a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                        Slog.e(TAG, "error in removeOverlayView", e);
11969a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                    }
11979a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                }
11989a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            } finally {
11999a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                Binder.restoreCallingIdentity(identity);
12009a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            }
12019a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho        }
1202c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim
1203c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim        @Override
1204c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim        public List<TvInputHardwareInfo> getHardwareList() throws RemoteException {
1205969167dc05a6485a32d160895871cff46fd81884Wonsik Kim            if (mContext.checkCallingPermission(android.Manifest.permission.TV_INPUT_HARDWARE)
1206c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim                    != PackageManager.PERMISSION_GRANTED) {
1207c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim                return null;
1208c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim            }
1209c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim
1210c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim            final long identity = Binder.clearCallingIdentity();
1211c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim            try {
1212c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim                return mTvInputHardwareManager.getHardwareList();
1213c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim            } finally {
1214c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim                Binder.restoreCallingIdentity(identity);
1215c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim            }
1216c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim        }
1217c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim
1218c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim        @Override
1219c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim        public ITvInputHardware acquireTvInputHardware(int deviceId,
1220969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                ITvInputHardwareCallback callback, TvInputInfo info, int userId)
1221969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                throws RemoteException {
1222969167dc05a6485a32d160895871cff46fd81884Wonsik Kim            if (mContext.checkCallingPermission(android.Manifest.permission.TV_INPUT_HARDWARE)
1223c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim                    != PackageManager.PERMISSION_GRANTED) {
1224c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim                return null;
1225c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim            }
1226c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim
1227c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim            final long identity = Binder.clearCallingIdentity();
1228c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim            final int callingUid = Binder.getCallingUid();
1229c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
1230c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim                    userId, "acquireTvInputHardware");
1231c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim            try {
1232c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim                return mTvInputHardwareManager.acquireHardware(
1233969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                        deviceId, callback, info, callingUid, resolvedUserId);
1234c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim            } finally {
1235c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim                Binder.restoreCallingIdentity(identity);
1236c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim            }
1237c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim        }
1238c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim
1239c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim        @Override
1240c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim        public void releaseTvInputHardware(int deviceId, ITvInputHardware hardware, int userId)
1241c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim                throws RemoteException {
1242969167dc05a6485a32d160895871cff46fd81884Wonsik Kim            if (mContext.checkCallingPermission(android.Manifest.permission.TV_INPUT_HARDWARE)
1243c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim                    != PackageManager.PERMISSION_GRANTED) {
1244c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim                return;
1245c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim            }
1246c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim
1247c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim            final long identity = Binder.clearCallingIdentity();
1248c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim            final int callingUid = Binder.getCallingUid();
1249c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
1250c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim                    userId, "releaseTvInputHardware");
1251c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim            try {
1252c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim                mTvInputHardwareManager.releaseHardware(
1253c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim                        deviceId, hardware, callingUid, resolvedUserId);
1254c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim            } finally {
1255c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim                Binder.restoreCallingIdentity(identity);
1256c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim            }
1257c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim        }
1258e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim
1259e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim        @Override
12600f8fc345ea61928265fdd6d461bf1babe353fbe4Jae Seo        @SuppressWarnings("resource")
1261e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim        protected void dump(FileDescriptor fd, final PrintWriter writer, String[] args) {
1262e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim            final IndentingPrintWriter pw = new IndentingPrintWriter(writer, "  ");
12630f8fc345ea61928265fdd6d461bf1babe353fbe4Jae Seo            if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
1264e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                    != PackageManager.PERMISSION_GRANTED) {
12650f8fc345ea61928265fdd6d461bf1babe353fbe4Jae Seo                pw.println("Permission Denial: can't dump TvInputManager from pid="
12660f8fc345ea61928265fdd6d461bf1babe353fbe4Jae Seo                        + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid());
1267e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                return;
1268e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim            }
1269e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim
1270e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim            synchronized (mLock) {
1271e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                pw.println("User Ids (Current user: " + mCurrentUserId + "):");
1272e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                pw.increaseIndent();
1273e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                for (int i = 0; i < mUserStates.size(); i++) {
1274e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                    int userId = mUserStates.keyAt(i);
1275e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                    pw.println(Integer.valueOf(userId));
1276e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                }
1277e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                pw.decreaseIndent();
1278e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim
1279e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                for (int i = 0; i < mUserStates.size(); i++) {
1280e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                    int userId = mUserStates.keyAt(i);
1281e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                    UserState userState = getUserStateLocked(userId);
1282e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                    pw.println("UserState (" + userId + "):");
1283e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                    pw.increaseIndent();
1284e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim
1285969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                    pw.println("inputMap: inputId -> TvInputState");
1286e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                    pw.increaseIndent();
12878e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim                    for (Map.Entry<String, TvInputState> entry: userState.inputMap.entrySet()) {
12888e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim                        pw.println(entry.getKey() + ": " + entry.getValue());
1289e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                    }
1290e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                    pw.decreaseIndent();
1291e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim
1292969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                    pw.println("packageSet:");
1293e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                    pw.increaseIndent();
1294969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                    for (String packageName : userState.packageSet) {
1295e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        pw.println(packageName);
1296e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                    }
1297e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                    pw.decreaseIndent();
1298e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim
1299e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                    pw.println("clientStateMap: ITvInputClient -> ClientState");
1300e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                    pw.increaseIndent();
1301e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                    for (Map.Entry<IBinder, ClientState> entry :
1302e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                            userState.clientStateMap.entrySet()) {
1303e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        ClientState client = entry.getValue();
1304e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        pw.println(entry.getKey() + ": " + client);
1305e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim
1306e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        pw.increaseIndent();
1307e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim
1308e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        pw.println("mInputIds:");
1309e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        pw.increaseIndent();
1310e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        for (String inputId : client.mInputIds) {
1311e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                            pw.println(inputId);
1312e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        }
1313e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        pw.decreaseIndent();
1314e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim
1315e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        pw.println("mSessionTokens:");
1316e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        pw.increaseIndent();
1317e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        for (IBinder token : client.mSessionTokens) {
1318e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                            pw.println("" + token);
1319e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        }
1320e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        pw.decreaseIndent();
1321e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim
1322e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        pw.println("mClientTokens: " + client.mClientToken);
1323e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        pw.println("mUserId: " + client.mUserId);
1324e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim
1325e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        pw.decreaseIndent();
1326e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                    }
1327e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                    pw.decreaseIndent();
1328e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim
1329187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                    pw.println("serviceStateMap: ComponentName -> ServiceState");
1330e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                    pw.increaseIndent();
1331187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                    for (Map.Entry<ComponentName, ServiceState> entry :
1332e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                            userState.serviceStateMap.entrySet()) {
1333e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        ServiceState service = entry.getValue();
1334e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        pw.println(entry.getKey() + ": " + service);
1335e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim
1336e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        pw.increaseIndent();
1337e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim
1338e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        pw.println("mClientTokens:");
1339e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        pw.increaseIndent();
1340e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        for (IBinder token : service.mClientTokens) {
1341e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                            pw.println("" + token);
1342e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        }
1343e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        pw.decreaseIndent();
1344e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim
1345e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        pw.println("mSessionTokens:");
1346e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        pw.increaseIndent();
1347e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        for (IBinder token : service.mSessionTokens) {
1348e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                            pw.println("" + token);
1349e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        }
1350e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        pw.decreaseIndent();
1351e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim
1352e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        pw.println("mService: " + service.mService);
1353e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        pw.println("mCallback: " + service.mCallback);
1354e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        pw.println("mBound: " + service.mBound);
1355e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        pw.println("mReconnecting: " + service.mReconnecting);
1356e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim
1357e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        pw.decreaseIndent();
1358e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                    }
1359e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                    pw.decreaseIndent();
1360e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim
1361e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                    pw.println("sessionStateMap: ITvInputSession -> SessionState");
1362e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                    pw.increaseIndent();
1363e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                    for (Map.Entry<IBinder, SessionState> entry :
1364e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                            userState.sessionStateMap.entrySet()) {
1365e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        SessionState session = entry.getValue();
1366e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        pw.println(entry.getKey() + ": " + session);
1367e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim
1368e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        pw.increaseIndent();
1369187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                        pw.println("mInfo: " + session.mInfo);
1370e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        pw.println("mClient: " + session.mClient);
1371e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        pw.println("mSeq: " + session.mSeq);
1372e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        pw.println("mCallingUid: " + session.mCallingUid);
1373e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        pw.println("mUserId: " + session.mUserId);
1374e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        pw.println("mSessionToken: " + session.mSessionToken);
1375e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        pw.println("mSession: " + session.mSession);
1376e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        pw.println("mLogUri: " + session.mLogUri);
1377e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        pw.decreaseIndent();
1378e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                    }
1379e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                    pw.decreaseIndent();
1380e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim
1381969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                    pw.println("callbackSet:");
1382969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                    pw.increaseIndent();
1383969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                    for (ITvInputManagerCallback callback : userState.callbackSet) {
1384969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                        pw.println(callback.toString());
1385969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                    }
1386969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                    pw.decreaseIndent();
1387969167dc05a6485a32d160895871cff46fd81884Wonsik Kim
1388e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                    pw.decreaseIndent();
1389e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                }
1390e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim            }
1391e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim        }
13923957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    }
13933957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
1394969167dc05a6485a32d160895871cff46fd81884Wonsik Kim    private static final class TvInputState {
1395969167dc05a6485a32d160895871cff46fd81884Wonsik Kim        // A TvInputInfo object which represents the TV input.
1396969167dc05a6485a32d160895871cff46fd81884Wonsik Kim        private TvInputInfo mInfo;
1397969167dc05a6485a32d160895871cff46fd81884Wonsik Kim
1398969167dc05a6485a32d160895871cff46fd81884Wonsik Kim        // The state of TV input. Connected by default.
1399969167dc05a6485a32d160895871cff46fd81884Wonsik Kim        private int mState = INPUT_STATE_CONNECTED;
1400969167dc05a6485a32d160895871cff46fd81884Wonsik Kim
1401969167dc05a6485a32d160895871cff46fd81884Wonsik Kim        @Override
1402969167dc05a6485a32d160895871cff46fd81884Wonsik Kim        public String toString() {
1403969167dc05a6485a32d160895871cff46fd81884Wonsik Kim            return "mInfo: " + mInfo + "; mState: " + mState;
1404969167dc05a6485a32d160895871cff46fd81884Wonsik Kim        }
1405969167dc05a6485a32d160895871cff46fd81884Wonsik Kim    }
1406969167dc05a6485a32d160895871cff46fd81884Wonsik Kim
14073957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    private static final class UserState {
1408969167dc05a6485a32d160895871cff46fd81884Wonsik Kim        // A mapping from the TV input id to its TvInputState.
1409969167dc05a6485a32d160895871cff46fd81884Wonsik Kim        private Map<String, TvInputState> inputMap = new HashMap<String, TvInputState>();
14103957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
1411969167dc05a6485a32d160895871cff46fd81884Wonsik Kim        // A set of all TV input packages.
1412969167dc05a6485a32d160895871cff46fd81884Wonsik Kim        private final Set<String> packageSet = new HashSet<String>();
14135c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo
141472ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim        // A mapping from the token of a client to its state.
141572ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim        private final Map<IBinder, ClientState> clientStateMap =
141672ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim                new HashMap<IBinder, ClientState>();
141772ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim
14183957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        // A mapping from the name of a TV input service to its state.
1419187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim        private final Map<ComponentName, ServiceState> serviceStateMap =
1420187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                new HashMap<ComponentName, ServiceState>();
14213957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
14223957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        // A mapping from the token of a TV input session to its state.
14233957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        private final Map<IBinder, SessionState> sessionStateMap =
14243957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                new HashMap<IBinder, SessionState>();
1425969167dc05a6485a32d160895871cff46fd81884Wonsik Kim
1426969167dc05a6485a32d160895871cff46fd81884Wonsik Kim        // A set of callbacks.
1427969167dc05a6485a32d160895871cff46fd81884Wonsik Kim        private final Set<ITvInputManagerCallback> callbackSet =
1428969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                new HashSet<ITvInputManagerCallback>();
14293957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    }
14303957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
143172ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim    private final class ClientState implements IBinder.DeathRecipient {
143272ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim        private final List<String> mInputIds = new ArrayList<String>();
143372ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim        private final List<IBinder> mSessionTokens = new ArrayList<IBinder>();
143472ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim
143572ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim        private IBinder mClientToken;
143672ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim        private final int mUserId;
143772ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim
143872ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim        ClientState(IBinder clientToken, int userId) {
143972ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim            mClientToken = clientToken;
144072ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim            mUserId = userId;
144172ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim        }
144272ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim
144372ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim        public boolean isEmpty() {
144472ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim            return mInputIds.isEmpty() && mSessionTokens.isEmpty();
144572ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim        }
144672ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim
144772ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim        @Override
144872ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim        public void binderDied() {
144972ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim            synchronized (mLock) {
145072ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim                UserState userState = getUserStateLocked(mUserId);
145172ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim                // DO NOT remove the client state of clientStateMap in this method. It will be
1452969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                // removed in releaseSessionLocked() or unregisterClientInternalLocked().
145372ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim                ClientState clientState = userState.clientStateMap.get(mClientToken);
145472ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim                if (clientState != null) {
145572ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim                    while (clientState.mSessionTokens.size() > 0) {
145672ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim                        releaseSessionLocked(
145772ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim                                clientState.mSessionTokens.get(0), Process.SYSTEM_UID, mUserId);
145872ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim                    }
145972ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim                    while (clientState.mInputIds.size() > 0) {
1460969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                        unregisterClientInternalLocked(
146172ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim                                mClientToken, clientState.mInputIds.get(0), mUserId);
146272ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim                    }
146372ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim                }
146472ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim                mClientToken = null;
146572ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim            }
146672ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim        }
146772ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim    }
146872ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim
14693957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    private final class ServiceState {
147072ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim        private final List<IBinder> mClientTokens = new ArrayList<IBinder>();
1471d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim        private final List<IBinder> mSessionTokens = new ArrayList<IBinder>();
1472d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim        private final ServiceConnection mConnection;
1473187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim        private final ComponentName mName;
1474187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim        private final boolean mIsHardware;
1475187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim        private final List<TvInputInfo> mInputList = new ArrayList<TvInputInfo>();
14763957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
1477d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim        private ITvInputService mService;
1478d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim        private ServiceCallback mCallback;
1479d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim        private boolean mBound;
14802b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim        private boolean mReconnecting;
14813957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
1482187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim        private ServiceState(ComponentName name, int userId) {
1483187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim            mName = name;
1484187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim            mConnection = new InputServiceConnection(name, userId);
1485187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim            mIsHardware = hasHardwarePermission(mContext.getPackageManager(), mName);
14863957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
14873957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    }
14883957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
14892b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim    private final class SessionState implements IBinder.DeathRecipient {
1490187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim        private final TvInputInfo mInfo;
1491d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim        private final ITvInputClient mClient;
1492d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim        private final int mSeq;
1493d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim        private final int mCallingUid;
14942b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim        private final int mUserId;
149572ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim        private final IBinder mSessionToken;
1496d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim        private ITvInputSession mSession;
1497d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim        private Uri mLogUri;
14983957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
1499187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim        private SessionState(IBinder sessionToken, TvInputInfo info, ITvInputClient client, int seq,
15002b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                int callingUid, int userId) {
150172ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim            mSessionToken = sessionToken;
1502187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim            mInfo = info;
15032b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim            mClient = client;
15042b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim            mSeq = seq;
15052b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim            mCallingUid = callingUid;
15062b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim            mUserId = userId;
15072b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim        }
15082b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim
15092b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim        @Override
15102b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim        public void binderDied() {
15112b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim            synchronized (mLock) {
15122b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                mSession = null;
15132b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                if (mClient != null) {
15142b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                    try {
15152b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                        mClient.onSessionReleased(mSeq);
15162b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                    } catch(RemoteException e) {
15172b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                        Slog.e(TAG, "error in onSessionReleased", e);
15182b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                    }
15192b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                }
152072ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim                removeSessionStateLocked(mSessionToken, mUserId);
15212b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim            }
15223957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
15233957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    }
15243957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
15253957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    private final class InputServiceConnection implements ServiceConnection {
1526187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim        private final ComponentName mName;
15273957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        private final int mUserId;
15283957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
1529187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim        private InputServiceConnection(ComponentName name, int userId) {
1530187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim            mName = name;
15313957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            mUserId = userId;
15323957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
15333957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
15343957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        @Override
15353957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        public void onServiceConnected(ComponentName name, IBinder service) {
15363957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            if (DEBUG) {
1537187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                Slog.d(TAG, "onServiceConnected(name=" + name + ")");
15383957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            }
15393957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            synchronized (mLock) {
1540969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                UserState userState = getUserStateLocked(mUserId);
1541187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                ServiceState serviceState = userState.serviceStateMap.get(mName);
1542d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim                serviceState.mService = ITvInputService.Stub.asInterface(service);
15433957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
15443957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                // Register a callback, if we need to.
1545187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                if (serviceState.mIsHardware && serviceState.mCallback == null) {
1546187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                    serviceState.mCallback = new ServiceCallback(mName, mUserId);
15473957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    try {
1548d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim                        serviceState.mService.registerCallback(serviceState.mCallback);
15493957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    } catch (RemoteException e) {
15509a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                        Slog.e(TAG, "error in registerCallback", e);
15513957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    }
15523957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                }
15533957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
15543957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                // And create sessions, if any.
1555d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim                for (IBinder sessionToken : serviceState.mSessionTokens) {
1556d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim                    createSessionInternalLocked(serviceState.mService, sessionToken, mUserId);
15573957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                }
1558969167dc05a6485a32d160895871cff46fd81884Wonsik Kim
1559187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                for (TvInputState inputState : userState.inputMap.values()) {
1560187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                    if (inputState.mInfo.getComponent().equals(name)
1561187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                            && inputState.mState != INPUT_STATE_DISCONNECTED) {
15628e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim                        notifyInputStateChangedLocked(userState, inputState.mInfo.getId(),
1563187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                                inputState.mState, null);
1564187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                    }
1565187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                }
1566187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim
1567187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                if (serviceState.mIsHardware) {
15684f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                    List<TvInputHardwareInfo> hardwareInfoList =
15694f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                            mTvInputHardwareManager.getHardwareList();
1570187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                    for (TvInputHardwareInfo hardwareInfo : hardwareInfoList) {
1571187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                        try {
1572187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                            serviceState.mService.notifyHardwareAdded(hardwareInfo);
1573187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                        } catch (RemoteException e) {
1574187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                            Slog.e(TAG, "error in notifyHardwareAdded", e);
1575187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                        }
1576187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                    }
1577187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim
15784f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                    List<HdmiCecDeviceInfo> cecDeviceInfoList =
15794f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                            mTvInputHardwareManager.getHdmiCecInputDeviceList();
15804f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                    for (HdmiCecDeviceInfo cecDeviceInfo : cecDeviceInfoList) {
15814f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                        try {
15824f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                            serviceState.mService.notifyHdmiCecDeviceAdded(cecDeviceInfo);
15834f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                        } catch (RemoteException e) {
15844f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                            Slog.e(TAG, "error in notifyHdmiCecDeviceAdded", e);
15854f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                        }
15864f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                    }
1587969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                }
15883957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            }
15893957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
15903957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
15913957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        @Override
15923957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        public void onServiceDisconnected(ComponentName name) {
15933957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            if (DEBUG) {
1594187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                Slog.d(TAG, "onServiceDisconnected(name=" + name + ")");
15953957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            }
1596187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim            if (!mName.equals(name)) {
15972b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                throw new IllegalArgumentException("Mismatched ComponentName: "
1598187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                        + mName + " (expected), " + name + " (actual).");
15992b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim            }
16002b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim            synchronized (mLock) {
16012b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                UserState userState = getUserStateLocked(mUserId);
1602187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                ServiceState serviceState = userState.serviceStateMap.get(mName);
16032b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                if (serviceState != null) {
16042b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                    serviceState.mReconnecting = true;
16052b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                    serviceState.mBound = false;
16062b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                    serviceState.mService = null;
16072b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                    serviceState.mCallback = null;
16082b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim
16092b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                    // Send null tokens for not finishing create session events.
16102b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                    for (IBinder sessionToken : serviceState.mSessionTokens) {
16112b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                        SessionState sessionState = userState.sessionStateMap.get(sessionToken);
16122b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                        if (sessionState.mSession == null) {
16132b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                            removeSessionStateLocked(sessionToken, sessionState.mUserId);
16142b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                            sendSessionTokenToClientLocked(sessionState.mClient,
1615187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                                    sessionState.mInfo.getId(), null, null, sessionState.mSeq);
16162b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                        }
16172b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                    }
16182b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim
1619187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                    for (TvInputState inputState : userState.inputMap.values()) {
1620187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                        if (inputState.mInfo.getComponent().equals(name)) {
16218e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim                            notifyInputStateChangedLocked(userState, inputState.mInfo.getId(),
1622187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                                    INPUT_STATE_DISCONNECTED, null);
1623187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                        }
1624187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                    }
1625187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                    updateServiceConnectionLocked(mName, mUserId);
16262b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                }
16272b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim            }
16283957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
16293957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    }
16303957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
16313957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    private final class ServiceCallback extends ITvInputServiceCallback.Stub {
1632187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim        private final ComponentName mName;
16333957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        private final int mUserId;
16343957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
1635187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim        ServiceCallback(ComponentName name, int userId) {
1636187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim            mName = name;
16373957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            mUserId = userId;
16383957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
16393957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
16404f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee        private void ensureHardwarePermission() {
16414f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee            if (mContext.checkCallingPermission(android.Manifest.permission.TV_INPUT_HARDWARE)
16424f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                    != PackageManager.PERMISSION_GRANTED) {
16434f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                throw new SecurityException("The caller does not have hardware permission");
16444f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee            }
16454f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee        }
16464f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee
16474f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee        private void ensureValidInput(TvInputInfo inputInfo) {
16484f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee            if (inputInfo.getId() == null || !mName.equals(inputInfo.getComponent())) {
16494f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                throw new IllegalArgumentException("Invalid TvInputInfo");
16504f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee            }
16514f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee        }
16524f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee
16534f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee        private void addTvInputLocked(TvInputInfo inputInfo) {
16544f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee            ServiceState serviceState = getServiceStateLocked(mName, mUserId);
16554f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee            serviceState.mInputList.add(inputInfo);
16564f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee            buildTvInputListLocked(mUserId);
16574f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee        }
16584f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee
16593957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        @Override
16604f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee        public void addHardwareTvInput(int deviceId, TvInputInfo inputInfo) {
16614f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee            ensureHardwarePermission();
16624f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee            ensureValidInput(inputInfo);
1663187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim            synchronized (mLock) {
16644f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                mTvInputHardwareManager.addHardwareTvInput(deviceId, inputInfo);
16654f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                addTvInputLocked(inputInfo);
16664f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee            }
16674f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee        }
1668187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim
16694f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee        @Override
16704f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee        public void addHdmiCecTvInput(int logicalAddress, TvInputInfo inputInfo) {
16714f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee            ensureHardwarePermission();
16724f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee            ensureValidInput(inputInfo);
16734f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee            synchronized (mLock) {
16744f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                mTvInputHardwareManager.addHdmiCecTvInput(logicalAddress, inputInfo);
16754f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                addTvInputLocked(inputInfo);
16763957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            }
1677187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim        }
1678187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim
1679187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim        @Override
1680187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim        public void removeTvInput(String inputId) {
16814f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee            ensureHardwarePermission();
16823957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            synchronized (mLock) {
1683187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                ServiceState serviceState = getServiceStateLocked(mName, mUserId);
1684187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                boolean removed = false;
1685187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                for (Iterator<TvInputInfo> it = serviceState.mInputList.iterator();
1686187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                        it.hasNext(); ) {
1687187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                    if (it.next().getId().equals(inputId)) {
1688187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                        it.remove();
1689187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                        removed = true;
1690187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                        break;
1691187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                    }
1692187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                }
1693187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                if (removed) {
1694187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                    buildTvInputListLocked(mUserId);
16954f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                    mTvInputHardwareManager.removeTvInput(inputId);
1696187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                } else {
1697187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                    Slog.e(TAG, "TvInputInfo with inputId=" + inputId + " not found.");
1698187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                }
16993957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            }
17003957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
17013957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    }
170231dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo
170331dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo    private final class LogHandler extends Handler {
170431dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo        private static final int MSG_OPEN_ENTRY = 1;
170531dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo        private static final int MSG_UPDATE_ENTRY = 2;
170631dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo        private static final int MSG_CLOSE_ENTRY = 3;
170731dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo
170831dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo        public LogHandler(Looper looper) {
170931dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo            super(looper);
171031dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo        }
171131dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo
171231dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo        @Override
171331dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo        public void handleMessage(Message msg) {
171431dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo            switch (msg.what) {
171531dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                case MSG_OPEN_ENTRY: {
171631dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                    SomeArgs args = (SomeArgs) msg.obj;
171731dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                    Uri uri = (Uri) args.arg1;
171831dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                    long channelId = (long) args.arg2;
171931dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                    long time = (long) args.arg3;
172031dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                    onOpenEntry(uri, channelId, time);
172131dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                    args.recycle();
172231dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                    return;
172331dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                }
172431dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                case MSG_UPDATE_ENTRY: {
172531dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                    SomeArgs args = (SomeArgs) msg.obj;
172631dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                    Uri uri = (Uri) args.arg1;
172731dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                    long channelId = (long) args.arg2;
172831dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                    long time = (long) args.arg3;
172931dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                    onUpdateEntry(uri, channelId, time);
173031dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                    args.recycle();
173131dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                    return;
173231dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                }
173331dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                case MSG_CLOSE_ENTRY: {
173431dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                    SomeArgs args = (SomeArgs) msg.obj;
173531dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                    Uri uri = (Uri) args.arg1;
173631dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                    long time = (long) args.arg2;
173731dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                    onCloseEntry(uri, time);
173831dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                    args.recycle();
173931dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                    return;
174031dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                }
174131dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                default: {
17426a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                    Slog.w(TAG, "Unhandled message code: " + msg.what);
174331dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                    return;
174431dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                }
174531dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo            }
174631dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo        }
174731dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo
174831dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo        private void onOpenEntry(Uri uri, long channelId, long watchStarttime) {
174931dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo            String[] projection = {
1750f5cd0b388ac31104e014f9193d06080851a09e18Jae Seo                    TvContract.Programs.COLUMN_TITLE,
1751f5cd0b388ac31104e014f9193d06080851a09e18Jae Seo                    TvContract.Programs.COLUMN_START_TIME_UTC_MILLIS,
1752f5cd0b388ac31104e014f9193d06080851a09e18Jae Seo                    TvContract.Programs.COLUMN_END_TIME_UTC_MILLIS,
1753bd23fa0ba1460a8d5194fd7c700030bf9c3f6fcbJae Seo                    TvContract.Programs.COLUMN_SHORT_DESCRIPTION
175431dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo            };
1755f5cd0b388ac31104e014f9193d06080851a09e18Jae Seo            String selection = TvContract.Programs.COLUMN_CHANNEL_ID + "=? AND "
1756f5cd0b388ac31104e014f9193d06080851a09e18Jae Seo                    + TvContract.Programs.COLUMN_START_TIME_UTC_MILLIS + "<=? AND "
1757f5cd0b388ac31104e014f9193d06080851a09e18Jae Seo                    + TvContract.Programs.COLUMN_END_TIME_UTC_MILLIS + ">?";
175831dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo            String[] selectionArgs = {
175931dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                    String.valueOf(channelId),
176031dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                    String.valueOf(watchStarttime),
176131dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                    String.valueOf(watchStarttime)
176231dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo            };
1763f5cd0b388ac31104e014f9193d06080851a09e18Jae Seo            String sortOrder = TvContract.Programs.COLUMN_START_TIME_UTC_MILLIS + " ASC";
176431dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo            Cursor cursor = null;
176531dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo            try {
176631dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                cursor = mContentResolver.query(TvContract.Programs.CONTENT_URI, projection,
176731dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                        selection, selectionArgs, sortOrder);
176831dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                if (cursor != null && cursor.moveToNext()) {
176931dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                    ContentValues values = new ContentValues();
1770f5cd0b388ac31104e014f9193d06080851a09e18Jae Seo                    values.put(TvContract.WatchedPrograms.COLUMN_TITLE, cursor.getString(0));
1771f5cd0b388ac31104e014f9193d06080851a09e18Jae Seo                    values.put(TvContract.WatchedPrograms.COLUMN_START_TIME_UTC_MILLIS,
1772f5cd0b388ac31104e014f9193d06080851a09e18Jae Seo                            cursor.getLong(1));
177331dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                    long endTime = cursor.getLong(2);
1774f5cd0b388ac31104e014f9193d06080851a09e18Jae Seo                    values.put(TvContract.WatchedPrograms.COLUMN_END_TIME_UTC_MILLIS, endTime);
1775f5cd0b388ac31104e014f9193d06080851a09e18Jae Seo                    values.put(TvContract.WatchedPrograms.COLUMN_DESCRIPTION, cursor.getString(3));
177631dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                    mContentResolver.update(uri, values, null, null);
177731dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo
177831dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                    // Schedule an update when the current program ends.
177931dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                    SomeArgs args = SomeArgs.obtain();
178031dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                    args.arg1 = uri;
178131dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                    args.arg2 = channelId;
178231dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                    args.arg3 = endTime;
178331dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                    Message msg = obtainMessage(LogHandler.MSG_UPDATE_ENTRY, args);
178431dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                    sendMessageDelayed(msg, endTime - System.currentTimeMillis());
178531dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                }
178631dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo            } finally {
178731dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                if (cursor != null) {
178831dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                    cursor.close();
178931dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                }
179031dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo            }
179131dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo        }
179231dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo
179331dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo        private void onUpdateEntry(Uri uri, long channelId, long time) {
179431dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo            String[] projection = {
1795f5cd0b388ac31104e014f9193d06080851a09e18Jae Seo                    TvContract.WatchedPrograms.COLUMN_WATCH_START_TIME_UTC_MILLIS,
1796f5cd0b388ac31104e014f9193d06080851a09e18Jae Seo                    TvContract.WatchedPrograms.COLUMN_WATCH_END_TIME_UTC_MILLIS,
1797f5cd0b388ac31104e014f9193d06080851a09e18Jae Seo                    TvContract.WatchedPrograms.COLUMN_TITLE,
1798f5cd0b388ac31104e014f9193d06080851a09e18Jae Seo                    TvContract.WatchedPrograms.COLUMN_START_TIME_UTC_MILLIS,
1799f5cd0b388ac31104e014f9193d06080851a09e18Jae Seo                    TvContract.WatchedPrograms.COLUMN_END_TIME_UTC_MILLIS,
1800f5cd0b388ac31104e014f9193d06080851a09e18Jae Seo                    TvContract.WatchedPrograms.COLUMN_DESCRIPTION
180131dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo            };
180231dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo            Cursor cursor = null;
180331dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo            try {
180431dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                cursor = mContentResolver.query(uri, projection, null, null, null);
180531dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                if (cursor != null && cursor.moveToNext()) {
180631dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                    long watchStartTime = cursor.getLong(0);
180731dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                    long watchEndTime = cursor.getLong(1);
180831dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                    String title = cursor.getString(2);
180931dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                    long startTime = cursor.getLong(3);
181031dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                    long endTime = cursor.getLong(4);
181131dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                    String description = cursor.getString(5);
181231dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo
181331dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                    // Do nothing if the current log entry is already closed.
181431dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                    if (watchEndTime > 0) {
181531dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                        return;
181631dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                    }
181731dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo
181831dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                    // The current program has just ended. Create a (complete) log entry off the
181931dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                    // current entry.
182031dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                    ContentValues values = new ContentValues();
1821f5cd0b388ac31104e014f9193d06080851a09e18Jae Seo                    values.put(TvContract.WatchedPrograms.COLUMN_WATCH_START_TIME_UTC_MILLIS,
182231dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                            watchStartTime);
1823f5cd0b388ac31104e014f9193d06080851a09e18Jae Seo                    values.put(TvContract.WatchedPrograms.COLUMN_WATCH_END_TIME_UTC_MILLIS, time);
1824f5cd0b388ac31104e014f9193d06080851a09e18Jae Seo                    values.put(TvContract.WatchedPrograms.COLUMN_CHANNEL_ID, channelId);
1825f5cd0b388ac31104e014f9193d06080851a09e18Jae Seo                    values.put(TvContract.WatchedPrograms.COLUMN_TITLE, title);
1826f5cd0b388ac31104e014f9193d06080851a09e18Jae Seo                    values.put(TvContract.WatchedPrograms.COLUMN_START_TIME_UTC_MILLIS, startTime);
1827f5cd0b388ac31104e014f9193d06080851a09e18Jae Seo                    values.put(TvContract.WatchedPrograms.COLUMN_END_TIME_UTC_MILLIS, endTime);
1828f5cd0b388ac31104e014f9193d06080851a09e18Jae Seo                    values.put(TvContract.WatchedPrograms.COLUMN_DESCRIPTION, description);
182931dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                    mContentResolver.insert(TvContract.WatchedPrograms.CONTENT_URI, values);
183031dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                }
183131dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo            } finally {
183231dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                if (cursor != null) {
183331dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                    cursor.close();
183431dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                }
183531dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo            }
183631dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo            // Re-open the current log entry with the next program information.
183731dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo            onOpenEntry(uri, channelId, time);
183831dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo        }
183931dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo
184031dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo        private void onCloseEntry(Uri uri, long watchEndTime) {
184131dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo            ContentValues values = new ContentValues();
1842f5cd0b388ac31104e014f9193d06080851a09e18Jae Seo            values.put(TvContract.WatchedPrograms.COLUMN_WATCH_END_TIME_UTC_MILLIS, watchEndTime);
184331dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo            mContentResolver.update(uri, values, null, null);
184431dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo        }
184531dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo    }
1846969167dc05a6485a32d160895871cff46fd81884Wonsik Kim
1847187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim    final class HardwareListener implements TvInputHardwareManager.Listener {
1848187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim        @Override
1849187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim        public void onStateChanged(String inputId, int state) {
1850969167dc05a6485a32d160895871cff46fd81884Wonsik Kim            synchronized (mLock) {
1851969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                setStateLocked(inputId, state, mCurrentUserId);
1852969167dc05a6485a32d160895871cff46fd81884Wonsik Kim            }
1853969167dc05a6485a32d160895871cff46fd81884Wonsik Kim        }
1854187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim
1855187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim        @Override
1856187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim        public void onHardwareDeviceAdded(TvInputHardwareInfo info) {
1857187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim            synchronized (mLock) {
1858187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                UserState userState = getUserStateLocked(mCurrentUserId);
1859187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                // Broadcast the event to all hardware inputs.
1860187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                for (ServiceState serviceState : userState.serviceStateMap.values()) {
1861187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                    if (!serviceState.mIsHardware || serviceState.mService == null) continue;
1862187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                    try {
1863187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                        serviceState.mService.notifyHardwareAdded(info);
1864187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                    } catch (RemoteException e) {
1865187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                        Slog.e(TAG, "error in notifyHardwareAdded", e);
1866187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                    }
1867187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                }
1868187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim            }
1869187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim        }
1870187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim
1871187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim        @Override
18724f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee        public void onHardwareDeviceRemoved(TvInputHardwareInfo info) {
1873187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim            synchronized (mLock) {
1874187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                UserState userState = getUserStateLocked(mCurrentUserId);
1875187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                // Broadcast the event to all hardware inputs.
1876187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                for (ServiceState serviceState : userState.serviceStateMap.values()) {
1877187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                    if (!serviceState.mIsHardware || serviceState.mService == null) continue;
1878187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                    try {
18794f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                        serviceState.mService.notifyHardwareRemoved(info);
1880187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                    } catch (RemoteException e) {
1881187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                        Slog.e(TAG, "error in notifyHardwareRemoved", e);
1882187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                    }
1883187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                }
1884187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim            }
1885187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim        }
1886187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim
1887187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim        @Override
18884f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee        public void onHdmiCecDeviceAdded(HdmiCecDeviceInfo cecDeviceInfo) {
1889187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim            synchronized (mLock) {
18904f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                UserState userState = getUserStateLocked(mCurrentUserId);
18914f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                // Broadcast the event to all hardware inputs.
18924f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                for (ServiceState serviceState : userState.serviceStateMap.values()) {
18934f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                    if (!serviceState.mIsHardware || serviceState.mService == null) continue;
18944f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                    try {
18954f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                        serviceState.mService.notifyHdmiCecDeviceAdded(cecDeviceInfo);
18964f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                    } catch (RemoteException e) {
18974f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                        Slog.e(TAG, "error in notifyHdmiCecDeviceAdded", e);
18984f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                    }
18994f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                }
1900187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim            }
1901187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim        }
1902187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim
1903187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim        @Override
19044f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee        public void onHdmiCecDeviceRemoved(HdmiCecDeviceInfo cecDeviceInfo) {
1905187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim            synchronized (mLock) {
19064f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                UserState userState = getUserStateLocked(mCurrentUserId);
19074f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                // Broadcast the event to all hardware inputs.
19084f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                for (ServiceState serviceState : userState.serviceStateMap.values()) {
19094f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                    if (!serviceState.mIsHardware || serviceState.mService == null) continue;
19104f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                    try {
19114f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                        serviceState.mService.notifyHdmiCecDeviceRemoved(cecDeviceInfo);
19124f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                    } catch (RemoteException e) {
19134f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                        Slog.e(TAG, "error in notifyHdmiCecDeviceRemoved", e);
19144f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                    }
19154f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                }
1916187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim            }
1917187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim        }
1918969167dc05a6485a32d160895871cff46fd81884Wonsik Kim    }
19193957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo}
1920