TvInputManagerService.java revision 8d4ded0058de5c573ccf79c4596bf5eb1b14fad3
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;
4061f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jangimport android.hardware.hdmi.HdmiDeviceInfo;
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;
50783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seoimport android.media.tv.TvContentRating;
51d5cc4a281e7ce29d1e8687ff3394b57a3a549260Jae Seoimport android.media.tv.TvContract;
52d5cc4a281e7ce29d1e8687ff3394b57a3a549260Jae Seoimport android.media.tv.TvInputHardwareInfo;
53d5cc4a281e7ce29d1e8687ff3394b57a3a549260Jae Seoimport android.media.tv.TvInputInfo;
54d5cc4a281e7ce29d1e8687ff3394b57a3a549260Jae Seoimport android.media.tv.TvInputService;
55c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heoimport android.media.tv.TvStreamConfig;
561f213914c45c23c653f721690da2ce0718e63139Dongwon Kangimport android.media.tv.TvTrackInfo;
573957091ba8f08c02b5e781098cb955a5f697a1ffJae Seoimport android.net.Uri;
583957091ba8f08c02b5e781098cb955a5f697a1ffJae Seoimport android.os.Binder;
59832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Choimport android.os.Bundle;
6031dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seoimport android.os.Handler;
613957091ba8f08c02b5e781098cb955a5f697a1ffJae Seoimport android.os.IBinder;
6231dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seoimport android.os.Looper;
6331dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seoimport android.os.Message;
643957091ba8f08c02b5e781098cb955a5f697a1ffJae Seoimport android.os.Process;
653957091ba8f08c02b5e781098cb955a5f697a1ffJae Seoimport android.os.RemoteException;
663957091ba8f08c02b5e781098cb955a5f697a1ffJae Seoimport android.os.UserHandle;
679a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Choimport android.util.Slog;
683957091ba8f08c02b5e781098cb955a5f697a1ffJae Seoimport android.util.SparseArray;
696a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seoimport android.view.InputChannel;
703957091ba8f08c02b5e781098cb955a5f697a1ffJae Seoimport android.view.Surface;
713957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
723957091ba8f08c02b5e781098cb955a5f697a1ffJae Seoimport com.android.internal.content.PackageMonitor;
7331dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seoimport com.android.internal.os.SomeArgs;
74e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kimimport com.android.internal.util.IndentingPrintWriter;
7531dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seoimport com.android.server.IoThread;
763957091ba8f08c02b5e781098cb955a5f697a1ffJae Seoimport com.android.server.SystemService;
773957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
78e7bb7d6bb2257c24076f5a4b9f536f90a6637f58Chulwoo Leeimport org.xmlpull.v1.XmlPullParserException;
79e7bb7d6bb2257c24076f5a4b9f536f90a6637f58Chulwoo Lee
80e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kimimport java.io.FileDescriptor;
81e7bb7d6bb2257c24076f5a4b9f536f90a6637f58Chulwoo Leeimport java.io.IOException;
82e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kimimport java.io.PrintWriter;
833957091ba8f08c02b5e781098cb955a5f697a1ffJae Seoimport java.util.ArrayList;
843957091ba8f08c02b5e781098cb955a5f697a1ffJae Seoimport java.util.HashMap;
855c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seoimport java.util.HashSet;
86187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kimimport java.util.Iterator;
873957091ba8f08c02b5e781098cb955a5f697a1ffJae Seoimport java.util.List;
883957091ba8f08c02b5e781098cb955a5f697a1ffJae Seoimport java.util.Map;
895c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seoimport java.util.Set;
903957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
913957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo/** This class provides a system service that manages television inputs. */
923957091ba8f08c02b5e781098cb955a5f697a1ffJae Seopublic final class TvInputManagerService extends SystemService {
933957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    // STOPSHIP: Turn debugging off.
943957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    private static final boolean DEBUG = true;
953957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    private static final String TAG = "TvInputManagerService";
963957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
973957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    private final Context mContext;
98c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim    private final TvInputHardwareManager mTvInputHardwareManager;
993957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
10031dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo    private final ContentResolver mContentResolver;
10131dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo
1023957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    // A global lock.
1033957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    private final Object mLock = new Object();
1043957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
1053957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    // ID of the current user.
1063957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    private int mCurrentUserId = UserHandle.USER_OWNER;
1073957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
1083957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    // A map from user id to UserState.
1093957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    private final SparseArray<UserState> mUserStates = new SparseArray<UserState>();
1103957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
11131dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo    private final Handler mLogHandler;
11231dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo
1133957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    public TvInputManagerService(Context context) {
1143957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        super(context);
11531dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo
1163957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        mContext = context;
11731dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo        mContentResolver = context.getContentResolver();
11831dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo        mLogHandler = new LogHandler(IoThread.get().getLooper());
11931dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo
120187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim        mTvInputHardwareManager = new TvInputHardwareManager(context, new HardwareListener());
12131dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo
1223957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        synchronized (mLock) {
123783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo            mUserStates.put(mCurrentUserId, new UserState(mContext, mCurrentUserId));
1243957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
1253957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    }
1263957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
1273957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    @Override
1283957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    public void onStart() {
1293957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        publishBinderService(Context.TV_INPUT_SERVICE, new BinderService());
1303957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    }
1313957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
1320ceb7e4755015eafda29c251eac285620788a51bJi-Hwan Lee    @Override
1330ceb7e4755015eafda29c251eac285620788a51bJi-Hwan Lee    public void onBootPhase(int phase) {
1340ceb7e4755015eafda29c251eac285620788a51bJi-Hwan Lee        if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY) {
1350ceb7e4755015eafda29c251eac285620788a51bJi-Hwan Lee            registerBroadcastReceivers();
136187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim        } else if (phase == SystemService.PHASE_THIRD_PARTY_APPS_CAN_START) {
1370ceb7e4755015eafda29c251eac285620788a51bJi-Hwan Lee            synchronized (mLock) {
1380ceb7e4755015eafda29c251eac285620788a51bJi-Hwan Lee                buildTvInputListLocked(mCurrentUserId);
1390ceb7e4755015eafda29c251eac285620788a51bJi-Hwan Lee            }
1400ceb7e4755015eafda29c251eac285620788a51bJi-Hwan Lee        }
141969167dc05a6485a32d160895871cff46fd81884Wonsik Kim        mTvInputHardwareManager.onBootPhase(phase);
1420ceb7e4755015eafda29c251eac285620788a51bJi-Hwan Lee    }
1430ceb7e4755015eafda29c251eac285620788a51bJi-Hwan Lee
1443957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    private void registerBroadcastReceivers() {
1453957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        PackageMonitor monitor = new PackageMonitor() {
1463957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            @Override
1473957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            public void onSomePackagesChanged() {
1483957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                synchronized (mLock) {
1493957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    buildTvInputListLocked(mCurrentUserId);
1503957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                }
1513957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            }
1525c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo
1535c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo            @Override
1545c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo            public void onPackageRemoved(String packageName, int uid) {
1555c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo                synchronized (mLock) {
1565c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo                    UserState userState = getUserStateLocked(mCurrentUserId);
157969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                    if (!userState.packageSet.contains(packageName)) {
1585c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo                        // Not a TV input package.
1595c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo                        return;
1605c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo                    }
1615c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo                }
1625c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo
1635c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo                ArrayList<ContentProviderOperation> operations =
1645c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo                        new ArrayList<ContentProviderOperation>();
1655c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo
1665c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo                String selection = TvContract.BaseTvColumns.COLUMN_PACKAGE_NAME + "=?";
1675c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo                String[] selectionArgs = { packageName };
1685c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo
1695c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo                operations.add(ContentProviderOperation.newDelete(TvContract.Channels.CONTENT_URI)
1705c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo                        .withSelection(selection, selectionArgs).build());
1715c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo                operations.add(ContentProviderOperation.newDelete(TvContract.Programs.CONTENT_URI)
1725c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo                        .withSelection(selection, selectionArgs).build());
1735c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo                operations.add(ContentProviderOperation
1745c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo                        .newDelete(TvContract.WatchedPrograms.CONTENT_URI)
1755c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo                        .withSelection(selection, selectionArgs).build());
1765c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo
1775c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo                ContentProviderResult[] results = null;
1785c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo                try {
1795c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo                    results = mContentResolver.applyBatch(TvContract.AUTHORITY, operations);
1805c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo                } catch (RemoteException | OperationApplicationException e) {
1815c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo                    Slog.e(TAG, "error in applyBatch" + e);
1825c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo                }
1835c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo
1845c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo                if (DEBUG) {
1855c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo                    Slog.d(TAG, "onPackageRemoved(packageName=" + packageName + ", uid=" + uid
1865c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo                            + ")");
1875c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo                    Slog.d(TAG, "results=" + results);
1885c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo                }
1895c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo            }
1903957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        };
1913957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        monitor.register(mContext, null, UserHandle.ALL, true);
1923957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
1933957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        IntentFilter intentFilter = new IntentFilter();
1943957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        intentFilter.addAction(Intent.ACTION_USER_SWITCHED);
1953957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        intentFilter.addAction(Intent.ACTION_USER_REMOVED);
1963957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        mContext.registerReceiverAsUser(new BroadcastReceiver() {
1973957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            @Override
1983957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            public void onReceive(Context context, Intent intent) {
1993957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                String action = intent.getAction();
2003957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                if (Intent.ACTION_USER_SWITCHED.equals(action)) {
2013957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    switchUser(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0));
2023957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                } else if (Intent.ACTION_USER_REMOVED.equals(action)) {
2033957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    removeUser(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0));
2043957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                }
2053957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            }
2063957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }, UserHandle.ALL, intentFilter, null, null);
2073957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    }
2083957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
2099e8ade2eb7ee835963473c9cf6faaf5423b0b048Ji-Hwan Lee    private static boolean hasHardwarePermission(PackageManager pm, ComponentName component) {
210187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim        return pm.checkPermission(android.Manifest.permission.TV_INPUT_HARDWARE,
2119e8ade2eb7ee835963473c9cf6faaf5423b0b048Ji-Hwan Lee                component.getPackageName()) == PackageManager.PERMISSION_GRANTED;
212187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim    }
213187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim
2143957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    private void buildTvInputListLocked(int userId) {
2153957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        UserState userState = getUserStateLocked(userId);
216969167dc05a6485a32d160895871cff46fd81884Wonsik Kim
2178e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim        Map<String, TvInputState> inputMap = new HashMap<String, TvInputState>();
218969167dc05a6485a32d160895871cff46fd81884Wonsik Kim        userState.packageSet.clear();
2193957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
2209a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho        if (DEBUG) Slog.d(TAG, "buildTvInputList");
2213957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        PackageManager pm = mContext.getPackageManager();
2223957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        List<ResolveInfo> services = pm.queryIntentServices(
223e7bb7d6bb2257c24076f5a4b9f536f90a6637f58Chulwoo Lee                new Intent(TvInputService.SERVICE_INTERFACE),
224e7bb7d6bb2257c24076f5a4b9f536f90a6637f58Chulwoo Lee                PackageManager.GET_SERVICES | PackageManager.GET_META_DATA);
2254f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee        List<TvInputInfo> inputList = new ArrayList<TvInputInfo>();
2263957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        for (ResolveInfo ri : services) {
2273957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            ServiceInfo si = ri.serviceInfo;
2283957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            if (!android.Manifest.permission.BIND_TV_INPUT.equals(si.permission)) {
2299a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                Slog.w(TAG, "Skipping TV input " + si.name + ": it does not require the permission "
2303957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                        + android.Manifest.permission.BIND_TV_INPUT);
2313957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                continue;
2323957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            }
233e7bb7d6bb2257c24076f5a4b9f536f90a6637f58Chulwoo Lee            try {
2344f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                inputList.clear();
2359e8ade2eb7ee835963473c9cf6faaf5423b0b048Ji-Hwan Lee                ComponentName component = new ComponentName(si.packageName, si.name);
2369e8ade2eb7ee835963473c9cf6faaf5423b0b048Ji-Hwan Lee                if (hasHardwarePermission(pm, component)) {
2379e8ade2eb7ee835963473c9cf6faaf5423b0b048Ji-Hwan Lee                    ServiceState serviceState = userState.serviceStateMap.get(component);
238187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                    if (serviceState == null) {
239187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                        // We see this hardware TV input service for the first time; we need to
240187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                        // prepare the ServiceState object so that we can connect to the service and
241187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                        // let it add TvInputInfo objects to mInputList if there's any.
2429e8ade2eb7ee835963473c9cf6faaf5423b0b048Ji-Hwan Lee                        serviceState = new ServiceState(component, userId);
2439e8ade2eb7ee835963473c9cf6faaf5423b0b048Ji-Hwan Lee                        userState.serviceStateMap.put(component, serviceState);
244187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                    } else {
2454f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                        inputList.addAll(serviceState.mInputList);
246187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                    }
247187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                } else {
2484f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                    inputList.add(TvInputInfo.createTvInputInfo(mContext, ri));
249187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                }
250187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim
2514f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                for (TvInputInfo info : inputList) {
252187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                    if (DEBUG) Slog.d(TAG, "add " + info.getId());
2538e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim                    TvInputState state = userState.inputMap.get(info.getId());
254187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                    if (state == null) {
255187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                        state = new TvInputState();
256187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                    }
257187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                    state.mInfo = info;
2588e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim                    inputMap.put(info.getId(), state);
259969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                }
260226a51958d645a8e2be3e40a6b6daaca558b4913Jaewan Kim
261226a51958d645a8e2be3e40a6b6daaca558b4913Jaewan Kim                // Reconnect the service if existing input is updated.
2629e8ade2eb7ee835963473c9cf6faaf5423b0b048Ji-Hwan Lee                updateServiceConnectionLocked(component, userId);
263187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim
264187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                userState.packageSet.add(si.packageName);
265e7bb7d6bb2257c24076f5a4b9f536f90a6637f58Chulwoo Lee            } catch (IOException | XmlPullParserException e) {
266e7bb7d6bb2257c24076f5a4b9f536f90a6637f58Chulwoo Lee                Slog.e(TAG, "Can't load TV input " + si.name, e);
267e7bb7d6bb2257c24076f5a4b9f536f90a6637f58Chulwoo Lee            }
2683957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
2698e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim
2708e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim        for (String inputId : inputMap.keySet()) {
2718e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim            if (!userState.inputMap.containsKey(inputId)) {
2728e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim                notifyInputAddedLocked(userState, inputId);
2738e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim            }
2748e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim        }
2758e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim
2768e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim        for (String inputId : userState.inputMap.keySet()) {
2778e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim            if (!inputMap.containsKey(inputId)) {
2788e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim                notifyInputRemovedLocked(userState, inputId);
2798e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim            }
2808e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim        }
2818e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim
2828e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim        userState.inputMap.clear();
2838e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim        userState.inputMap = inputMap;
2845c5b83fcd58d21c9ab7ac986bf84f604ec5bb4b5Sungsoo Lim
2855c5b83fcd58d21c9ab7ac986bf84f604ec5bb4b5Sungsoo Lim        userState.ratingSystemXmlUriSet.clear();
2865c5b83fcd58d21c9ab7ac986bf84f604ec5bb4b5Sungsoo Lim        userState.ratingSystemXmlUriSet.add(TvContentRating.SYSTEM_CONTENT_RATING_SYSTEM_XML);
2875c5b83fcd58d21c9ab7ac986bf84f604ec5bb4b5Sungsoo Lim        for (TvInputState state : userState.inputMap.values()) {
2885c5b83fcd58d21c9ab7ac986bf84f604ec5bb4b5Sungsoo Lim            Uri ratingSystemXmlUri = state.mInfo.getRatingSystemXmlUri();
2895c5b83fcd58d21c9ab7ac986bf84f604ec5bb4b5Sungsoo Lim            if (ratingSystemXmlUri != null) {
2905c5b83fcd58d21c9ab7ac986bf84f604ec5bb4b5Sungsoo Lim                // TODO: need to check the validation of xml format and the duplication of rating
2915c5b83fcd58d21c9ab7ac986bf84f604ec5bb4b5Sungsoo Lim                // systems.
2925c5b83fcd58d21c9ab7ac986bf84f604ec5bb4b5Sungsoo Lim                userState.ratingSystemXmlUriSet.add(state.mInfo.getRatingSystemXmlUri());
2935c5b83fcd58d21c9ab7ac986bf84f604ec5bb4b5Sungsoo Lim            }
2945c5b83fcd58d21c9ab7ac986bf84f604ec5bb4b5Sungsoo Lim        }
2953957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    }
2963957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
2973957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    private void switchUser(int userId) {
2983957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        synchronized (mLock) {
2993957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            if (mCurrentUserId == userId) {
3003957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                return;
3013957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            }
3023957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            // final int oldUserId = mCurrentUserId;
3033957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            // TODO: Release services and sessions in the old user state, if needed.
3043957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            mCurrentUserId = userId;
3053957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
3063957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            UserState userState = mUserStates.get(userId);
3073957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            if (userState == null) {
308783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                userState = new UserState(mContext, userId);
3093957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            }
3103957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            mUserStates.put(userId, userState);
3113957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            buildTvInputListLocked(userId);
3123957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
3133957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    }
3143957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
3153957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    private void removeUser(int userId) {
3163957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        synchronized (mLock) {
317b06cb8870f0407f18bb1225065a93aba2a5de2bfJae Seo            UserState userState = mUserStates.get(userId);
318b06cb8870f0407f18bb1225065a93aba2a5de2bfJae Seo            if (userState == null) {
319b06cb8870f0407f18bb1225065a93aba2a5de2bfJae Seo                return;
320b06cb8870f0407f18bb1225065a93aba2a5de2bfJae Seo            }
3213957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            // Release created sessions.
3223957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            for (SessionState state : userState.sessionStateMap.values()) {
323d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim                if (state.mSession != null) {
3243957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    try {
325d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim                        state.mSession.release();
3263957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    } catch (RemoteException e) {
3279a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                        Slog.e(TAG, "error in release", e);
3283957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    }
3293957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                }
3303957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            }
3313957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            userState.sessionStateMap.clear();
3323957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
3333957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            // Unregister all callbacks and unbind all services.
3343957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            for (ServiceState serviceState : userState.serviceStateMap.values()) {
335d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim                if (serviceState.mCallback != null) {
3363957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    try {
337d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim                        serviceState.mService.unregisterCallback(serviceState.mCallback);
3383957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    } catch (RemoteException e) {
3399a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                        Slog.e(TAG, "error in unregisterCallback", e);
3403957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    }
3413957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                }
34272ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim                serviceState.mClientTokens.clear();
343d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim                mContext.unbindService(serviceState.mConnection);
3443957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            }
3453957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            userState.serviceStateMap.clear();
3463957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
34772ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim            userState.clientStateMap.clear();
34872ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim
3493957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            mUserStates.remove(userId);
3503957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
3513957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    }
3523957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
3533957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    private UserState getUserStateLocked(int userId) {
3543957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        UserState userState = mUserStates.get(userId);
3553957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        if (userState == null) {
3563957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            throw new IllegalStateException("User state not found for user ID " + userId);
3573957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
3583957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        return userState;
3593957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    }
3603957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
3619e8ade2eb7ee835963473c9cf6faaf5423b0b048Ji-Hwan Lee    private ServiceState getServiceStateLocked(ComponentName component, int userId) {
3623957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        UserState userState = getUserStateLocked(userId);
3639e8ade2eb7ee835963473c9cf6faaf5423b0b048Ji-Hwan Lee        ServiceState serviceState = userState.serviceStateMap.get(component);
3643957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        if (serviceState == null) {
3659e8ade2eb7ee835963473c9cf6faaf5423b0b048Ji-Hwan Lee            throw new IllegalStateException("Service state not found for " + component + " (userId="
3667de5e234715a3baa8905afa3dd0c5009af64541fSungsoo Lim                    + userId + ")");
3673957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
3683957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        return serviceState;
3693957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    }
3703957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
3712b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim    private SessionState getSessionStateLocked(IBinder sessionToken, int callingUid, int userId) {
3723957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        UserState userState = getUserStateLocked(userId);
3733957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        SessionState sessionState = userState.sessionStateMap.get(sessionToken);
3743957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        if (sessionState == null) {
3753957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            throw new IllegalArgumentException("Session state not found for token " + sessionToken);
3763957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
3773957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        // Only the application that requested this session or the system can access it.
378d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim        if (callingUid != Process.SYSTEM_UID && callingUid != sessionState.mCallingUid) {
3793957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            throw new SecurityException("Illegal access to the session with token " + sessionToken
3803957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    + " from uid " + callingUid);
3813957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
3822b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim        return sessionState;
3832b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim    }
3842b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim
3852b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim    private ITvInputSession getSessionLocked(IBinder sessionToken, int callingUid, int userId) {
3864c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee        return getSessionLocked(getSessionStateLocked(sessionToken, callingUid, userId));
3874c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee    }
3884c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee
3894c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee    private ITvInputSession getSessionLocked(SessionState sessionState) {
390d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim        ITvInputSession session = sessionState.mSession;
3913957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        if (session == null) {
3924c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee            throw new IllegalStateException("Session not yet created for token "
3934c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee                    + sessionState.mSessionToken);
3943957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
3953957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        return session;
3963957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    }
3973957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
3983957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    private int resolveCallingUserId(int callingPid, int callingUid, int requestedUserId,
3993957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            String methodName) {
4003957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        return ActivityManager.handleIncomingUser(callingPid, callingUid, requestedUserId, false,
4013957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                false, methodName, null);
4023957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    }
4033957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
404187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim    private static boolean shouldMaintainConnection(ServiceState serviceState) {
405187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim        return !serviceState.mClientTokens.isEmpty()
406187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                || !serviceState.mSessionTokens.isEmpty()
407187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                || serviceState.mIsHardware;
408187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim        // TODO: Find a way to maintain connection only when necessary.
409187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim    }
410187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim
4119e8ade2eb7ee835963473c9cf6faaf5423b0b048Ji-Hwan Lee    private void updateServiceConnectionLocked(ComponentName component, int userId) {
4123957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        UserState userState = getUserStateLocked(userId);
4139e8ade2eb7ee835963473c9cf6faaf5423b0b048Ji-Hwan Lee        ServiceState serviceState = userState.serviceStateMap.get(component);
4143957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        if (serviceState == null) {
4153957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            return;
4163957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
4172b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim        if (serviceState.mReconnecting) {
4182b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim            if (!serviceState.mSessionTokens.isEmpty()) {
4192b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                // wait until all the sessions are removed.
4202b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                return;
4212b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim            }
4222b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim            serviceState.mReconnecting = false;
4232b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim        }
424187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim        boolean maintainConnection = shouldMaintainConnection(serviceState);
425187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim        if (serviceState.mService == null && maintainConnection && userId == mCurrentUserId) {
4263957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            // This means that the service is not yet connected but its state indicates that we
4273957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            // have pending requests. Then, connect the service.
428d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim            if (serviceState.mBound) {
4293957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                // We have already bound to the service so we don't try to bind again until after we
4303957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                // unbind later on.
4313957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                return;
4323957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            }
4333957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            if (DEBUG) {
4349e8ade2eb7ee835963473c9cf6faaf5423b0b048Ji-Hwan Lee                Slog.d(TAG, "bindServiceAsUser(service=" + component + ", userId=" + userId + ")");
4353957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            }
436d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim
4379e8ade2eb7ee835963473c9cf6faaf5423b0b048Ji-Hwan Lee            Intent i = new Intent(TvInputService.SERVICE_INTERFACE).setComponent(component);
438226a51958d645a8e2be3e40a6b6daaca558b4913Jaewan Kim            // Binding service may fail if the service is updating.
439226a51958d645a8e2be3e40a6b6daaca558b4913Jaewan Kim            // In that case, the connection will be revived in buildTvInputListLocked called by
440226a51958d645a8e2be3e40a6b6daaca558b4913Jaewan Kim            // onSomePackagesChanged.
441e17b2dd7bcc137bf4d842a779e8d62c63957a978Ji-Hwan Lee            serviceState.mBound = mContext.bindServiceAsUser(
442e17b2dd7bcc137bf4d842a779e8d62c63957a978Ji-Hwan Lee                    i, serviceState.mConnection, Context.BIND_AUTO_CREATE, new UserHandle(userId));
443187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim        } else if (serviceState.mService != null && !maintainConnection) {
4443957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            // This means that the service is already connected but its state indicates that we have
4453957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            // nothing to do with it. Then, disconnect the service.
4463957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            if (DEBUG) {
4479e8ade2eb7ee835963473c9cf6faaf5423b0b048Ji-Hwan Lee                Slog.d(TAG, "unbindService(service=" + component + ")");
4483957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            }
449d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim            mContext.unbindService(serviceState.mConnection);
4509e8ade2eb7ee835963473c9cf6faaf5423b0b048Ji-Hwan Lee            userState.serviceStateMap.remove(component);
4513957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
4523957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    }
4533957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
45472ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim    private ClientState createClientStateLocked(IBinder clientToken, int userId) {
45572ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim        UserState userState = getUserStateLocked(userId);
45672ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim        ClientState clientState = new ClientState(clientToken, userId);
45772ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim        try {
45872ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim            clientToken.linkToDeath(clientState, 0);
45972ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim        } catch (RemoteException e) {
46072ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim            Slog.e(TAG, "Client is already died.");
46172ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim        }
46272ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim        userState.clientStateMap.put(clientToken, clientState);
46372ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim        return clientState;
46472ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim    }
46572ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim
4663957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    private void createSessionInternalLocked(ITvInputService service, final IBinder sessionToken,
4677de5e234715a3baa8905afa3dd0c5009af64541fSungsoo Lim            final int userId) {
46872ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim        final UserState userState = getUserStateLocked(userId);
46972ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim        final SessionState sessionState = userState.sessionStateMap.get(sessionToken);
4703957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        if (DEBUG) {
471187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim            Slog.d(TAG, "createSessionInternalLocked(inputId=" + sessionState.mInfo.getId() + ")");
4723957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
4736a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo
4746a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo        final InputChannel[] channels = InputChannel.openInputChannelPair(sessionToken.toString());
4756a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo
4763957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        // Set up a callback to send the session token.
4773957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        ITvInputSessionCallback callback = new ITvInputSessionCallback.Stub() {
4783957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            @Override
479bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang            public void onSessionCreated(ITvInputSession session, IBinder harewareSessionToken) {
4803957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                if (DEBUG) {
481187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                    Slog.d(TAG, "onSessionCreated(inputId=" + sessionState.mInfo.getId() + ")");
4823957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                }
4833957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                synchronized (mLock) {
484d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim                    sessionState.mSession = session;
485bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                    sessionState.mHardwareSessionToken = harewareSessionToken;
486fd5b72f1ed2ee74a4204eef65f560fc82f0b62feDongwon Kang                    if (session == null) {
487fd5b72f1ed2ee74a4204eef65f560fc82f0b62feDongwon Kang                        removeSessionStateLocked(sessionToken, userId);
488187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                        sendSessionTokenToClientLocked(sessionState.mClient,
489187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                                sessionState.mInfo.getId(), null, null, sessionState.mSeq);
490fd5b72f1ed2ee74a4204eef65f560fc82f0b62feDongwon Kang                    } else {
4912b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                        try {
4922b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                            session.asBinder().linkToDeath(sessionState, 0);
4932b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                        } catch (RemoteException e) {
4942b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                            Slog.e(TAG, "Session is already died.");
4952b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                        }
49672ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim
49772ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim                        IBinder clientToken = sessionState.mClient.asBinder();
49872ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim                        ClientState clientState = userState.clientStateMap.get(clientToken);
49972ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim                        if (clientState == null) {
50072ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim                            clientState = createClientStateLocked(clientToken, userId);
50172ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim                        }
50272ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim                        clientState.mSessionTokens.add(sessionState.mSessionToken);
50372ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim
504187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                        sendSessionTokenToClientLocked(sessionState.mClient,
505187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                                sessionState.mInfo.getId(), sessionToken, channels[0],
506187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                                sessionState.mSeq);
507fd5b72f1ed2ee74a4204eef65f560fc82f0b62feDongwon Kang                    }
5086a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                    channels[0].dispose();
5093957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                }
5103957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            }
511832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho
512832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho            @Override
5131f213914c45c23c653f721690da2ce0718e63139Dongwon Kang            public void onChannelRetuned(Uri channelUri) {
514a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang                synchronized (mLock) {
515a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang                    if (DEBUG) {
5161f213914c45c23c653f721690da2ce0718e63139Dongwon Kang                        Slog.d(TAG, "onChannelRetuned(" + channelUri + ")");
517a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang                    }
518a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang                    if (sessionState.mSession == null || sessionState.mClient == null) {
519a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang                        return;
520a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang                    }
521a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang                    try {
5221f213914c45c23c653f721690da2ce0718e63139Dongwon Kang                        // TODO: Consider adding this channel change in the watch log. When we do
5231f213914c45c23c653f721690da2ce0718e63139Dongwon Kang                        // that, how we can protect the watch log from malicious tv inputs should
5241f213914c45c23c653f721690da2ce0718e63139Dongwon Kang                        // be addressed. e.g. add a field which represents where the channel change
5251f213914c45c23c653f721690da2ce0718e63139Dongwon Kang                        // originated from.
5261f213914c45c23c653f721690da2ce0718e63139Dongwon Kang                        sessionState.mClient.onChannelRetuned(channelUri, sessionState.mSeq);
527a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang                    } catch (RemoteException e) {
5281f213914c45c23c653f721690da2ce0718e63139Dongwon Kang                        Slog.e(TAG, "error in onChannelRetuned");
529a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang                    }
530a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang                }
531a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang            }
532a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang
533a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang            @Override
53410d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo            public void onTracksChanged(List<TvTrackInfo> tracks) {
535a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang                synchronized (mLock) {
536a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang                    if (DEBUG) {
53710d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo                        Slog.d(TAG, "onTracksChanged(" + tracks + ")");
538a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang                    }
539a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang                    if (sessionState.mSession == null || sessionState.mClient == null) {
540a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang                        return;
541a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang                    }
542a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang                    try {
54310d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo                        sessionState.mClient.onTracksChanged(tracks, sessionState.mSeq);
544a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang                    } catch (RemoteException e) {
54510d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo                        Slog.e(TAG, "error in onTracksChanged");
546b93ccca6139a7ee2dba5c110e5f8213a2bd231e5Dongwon Kang                    }
547b93ccca6139a7ee2dba5c110e5f8213a2bd231e5Dongwon Kang                }
548b93ccca6139a7ee2dba5c110e5f8213a2bd231e5Dongwon Kang            }
549b93ccca6139a7ee2dba5c110e5f8213a2bd231e5Dongwon Kang
550b93ccca6139a7ee2dba5c110e5f8213a2bd231e5Dongwon Kang            @Override
55110d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo            public void onTrackSelected(int type, String trackId) {
552d5ce9759524740cfb02638fd1d7b44315957b422Jae Seo                synchronized (mLock) {
553d5ce9759524740cfb02638fd1d7b44315957b422Jae Seo                    if (DEBUG) {
55410d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo                        Slog.d(TAG, "onTrackSelected(type=" + type + ", trackId=" + trackId + ")");
555d5ce9759524740cfb02638fd1d7b44315957b422Jae Seo                    }
556d5ce9759524740cfb02638fd1d7b44315957b422Jae Seo                    if (sessionState.mSession == null || sessionState.mClient == null) {
557d5ce9759524740cfb02638fd1d7b44315957b422Jae Seo                        return;
558d5ce9759524740cfb02638fd1d7b44315957b422Jae Seo                    }
559d5ce9759524740cfb02638fd1d7b44315957b422Jae Seo                    try {
56010d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo                        sessionState.mClient.onTrackSelected(type, trackId, sessionState.mSeq);
561d5ce9759524740cfb02638fd1d7b44315957b422Jae Seo                    } catch (RemoteException e) {
56210d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo                        Slog.e(TAG, "error in onTrackSelected");
563d5ce9759524740cfb02638fd1d7b44315957b422Jae Seo                    }
564d5ce9759524740cfb02638fd1d7b44315957b422Jae Seo                }
565d5ce9759524740cfb02638fd1d7b44315957b422Jae Seo            }
566d5ce9759524740cfb02638fd1d7b44315957b422Jae Seo
567d5ce9759524740cfb02638fd1d7b44315957b422Jae Seo            @Override
5689b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang            public void onVideoAvailable() {
5699b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                synchronized (mLock) {
5709b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                    if (DEBUG) {
5719b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                        Slog.d(TAG, "onVideoAvailable()");
5729b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                    }
5739b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                    if (sessionState.mSession == null || sessionState.mClient == null) {
5749b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                        return;
5759b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                    }
5769b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                    try {
5779b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                        sessionState.mClient.onVideoAvailable(sessionState.mSeq);
5789b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                    } catch (RemoteException e) {
5799b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                        Slog.e(TAG, "error in onVideoAvailable");
5809b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                    }
5819b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                }
5829b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang            }
5839b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang
5849b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang            @Override
5859b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang            public void onVideoUnavailable(int reason) {
5869b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                synchronized (mLock) {
5879b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                    if (DEBUG) {
5889b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                        Slog.d(TAG, "onVideoUnavailable(" + reason + ")");
5899b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                    }
5909b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                    if (sessionState.mSession == null || sessionState.mClient == null) {
5919b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                        return;
5929b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                    }
5939b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                    try {
5949b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                        sessionState.mClient.onVideoUnavailable(reason, sessionState.mSeq);
5959b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                    } catch (RemoteException e) {
5969b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                        Slog.e(TAG, "error in onVideoUnavailable");
5979b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                    }
5989b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                }
5999b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang            }
6009b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang
6019b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang            @Override
602bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo            public void onContentAllowed() {
603bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo                synchronized (mLock) {
604bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo                    if (DEBUG) {
605bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo                        Slog.d(TAG, "onContentAllowed()");
606bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo                    }
607bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo                    if (sessionState.mSession == null || sessionState.mClient == null) {
608bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo                        return;
609bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo                    }
610bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo                    try {
611bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo                        sessionState.mClient.onContentAllowed(sessionState.mSeq);
612bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo                    } catch (RemoteException e) {
613bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo                        Slog.e(TAG, "error in onContentAllowed");
614bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo                    }
615bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo                }
616bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo            }
617bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo
618bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo            @Override
6196057102dbb746593a7d59cf377c969b62e38c664Jae Seo            public void onContentBlocked(String rating) {
6206057102dbb746593a7d59cf377c969b62e38c664Jae Seo                synchronized (mLock) {
6216057102dbb746593a7d59cf377c969b62e38c664Jae Seo                    if (DEBUG) {
6226057102dbb746593a7d59cf377c969b62e38c664Jae Seo                        Slog.d(TAG, "onContentBlocked()");
6236057102dbb746593a7d59cf377c969b62e38c664Jae Seo                    }
6246057102dbb746593a7d59cf377c969b62e38c664Jae Seo                    if (sessionState.mSession == null || sessionState.mClient == null) {
6256057102dbb746593a7d59cf377c969b62e38c664Jae Seo                        return;
6266057102dbb746593a7d59cf377c969b62e38c664Jae Seo                    }
6276057102dbb746593a7d59cf377c969b62e38c664Jae Seo                    try {
6286057102dbb746593a7d59cf377c969b62e38c664Jae Seo                        sessionState.mClient.onContentBlocked(rating, sessionState.mSeq);
6296057102dbb746593a7d59cf377c969b62e38c664Jae Seo                    } catch (RemoteException e) {
6306057102dbb746593a7d59cf377c969b62e38c664Jae Seo                        Slog.e(TAG, "error in onContentBlocked");
6316057102dbb746593a7d59cf377c969b62e38c664Jae Seo                    }
6326057102dbb746593a7d59cf377c969b62e38c664Jae Seo                }
6336057102dbb746593a7d59cf377c969b62e38c664Jae Seo            }
6346057102dbb746593a7d59cf377c969b62e38c664Jae Seo
6356057102dbb746593a7d59cf377c969b62e38c664Jae Seo            @Override
636ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho            public void onLayoutSurface(int left, int top, int right, int bottom) {
637ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho                synchronized (mLock) {
638ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho                    if (DEBUG) {
639ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho                        Slog.d(TAG, "onLayoutSurface (left=" + left + ", top=" + top
640ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho                                + ", right=" + right + ", bottom=" + bottom + ",)");
641ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho                    }
642ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho                    if (sessionState.mSession == null || sessionState.mClient == null) {
643ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho                        return;
644ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho                    }
645ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho                    try {
646ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho                        sessionState.mClient.onLayoutSurface(left, top, right, bottom,
647ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho                                sessionState.mSeq);
648ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho                    } catch (RemoteException e) {
649ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho                        Slog.e(TAG, "error in onLayoutSurface");
650ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho                    }
651ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho                }
652ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho            }
653ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho
654ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho            @Override
655832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho            public void onSessionEvent(String eventType, Bundle eventArgs) {
656832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho                synchronized (mLock) {
657832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho                    if (DEBUG) {
658832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho                        Slog.d(TAG, "onEvent(what=" + eventType + ", data=" + eventArgs + ")");
659832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho                    }
660832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho                    if (sessionState.mSession == null || sessionState.mClient == null) {
661832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho                        return;
662832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho                    }
663832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho                    try {
664832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho                        sessionState.mClient.onSessionEvent(eventType, eventArgs,
665832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho                                sessionState.mSeq);
666832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho                    } catch (RemoteException e) {
667832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho                        Slog.e(TAG, "error in onSessionEvent");
668832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho                    }
669832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho                }
670832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho            }
6713957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        };
6723957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
6733957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        // Create a session. When failed, send a null token immediately.
6743957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        try {
675187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim            service.createSession(channels[1], callback, sessionState.mInfo.getId());
6763957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        } catch (RemoteException e) {
6779a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            Slog.e(TAG, "error in createSession", e);
678fd5b72f1ed2ee74a4204eef65f560fc82f0b62feDongwon Kang            removeSessionStateLocked(sessionToken, userId);
679187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim            sendSessionTokenToClientLocked(sessionState.mClient, sessionState.mInfo.getId(), null,
680187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                    null, sessionState.mSeq);
6813957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
6826a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo        channels[1].dispose();
6833957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    }
6843957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
685d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim    private void sendSessionTokenToClientLocked(ITvInputClient client, String inputId,
6865c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo            IBinder sessionToken, InputChannel channel, int seq) {
6873957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        try {
688d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim            client.onSessionCreated(inputId, sessionToken, channel, seq);
6893957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        } catch (RemoteException exception) {
6909a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            Slog.e(TAG, "error in onSessionCreated", exception);
6913957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
6922b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim    }
6933957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
6942b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim    private void releaseSessionLocked(IBinder sessionToken, int callingUid, int userId) {
6952b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim        SessionState sessionState = getSessionStateLocked(sessionToken, callingUid, userId);
6962b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim        if (sessionState.mSession != null) {
6972b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim            try {
6982b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                sessionState.mSession.release();
6992b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim            } catch (RemoteException e) {
7002b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                Slog.w(TAG, "session is already disapeared", e);
7012b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim            }
7022b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim            sessionState.mSession = null;
7033957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
7042b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim        removeSessionStateLocked(sessionToken, userId);
7053957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    }
7063957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
707fd5b72f1ed2ee74a4204eef65f560fc82f0b62feDongwon Kang    private void removeSessionStateLocked(IBinder sessionToken, int userId) {
708fd5b72f1ed2ee74a4204eef65f560fc82f0b62feDongwon Kang        UserState userState = getUserStateLocked(userId);
709abca0ee7949f59e72b8d2764dafa23af18eb51dbJi-Hwan Lee        if (sessionToken == userState.mainSessionToken) {
710abca0ee7949f59e72b8d2764dafa23af18eb51dbJi-Hwan Lee            userState.mainSessionToken = null;
711abca0ee7949f59e72b8d2764dafa23af18eb51dbJi-Hwan Lee        }
712abca0ee7949f59e72b8d2764dafa23af18eb51dbJi-Hwan Lee
713abca0ee7949f59e72b8d2764dafa23af18eb51dbJi-Hwan Lee        // Remove the session state from the global session state map of the current user.
714fd5b72f1ed2ee74a4204eef65f560fc82f0b62feDongwon Kang        SessionState sessionState = userState.sessionStateMap.remove(sessionToken);
715fd5b72f1ed2ee74a4204eef65f560fc82f0b62feDongwon Kang
7168d4ded0058de5c573ccf79c4596bf5eb1b14fad3Chulwoo Lee        if (sessionState == null) {
7178d4ded0058de5c573ccf79c4596bf5eb1b14fad3Chulwoo Lee            return;
7188d4ded0058de5c573ccf79c4596bf5eb1b14fad3Chulwoo Lee        }
7198d4ded0058de5c573ccf79c4596bf5eb1b14fad3Chulwoo Lee
72031dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo        // Close the open log entry, if any.
721d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim        if (sessionState.mLogUri != null) {
72231dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo            SomeArgs args = SomeArgs.obtain();
723d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim            args.arg1 = sessionState.mLogUri;
72431dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo            args.arg2 = System.currentTimeMillis();
72531dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo            mLogHandler.obtainMessage(LogHandler.MSG_CLOSE_ENTRY, args).sendToTarget();
72631dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo        }
72731dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo
72872ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim        // Also remove the session token from the session token list of the current client and
72972ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim        // service.
73072ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim        ClientState clientState = userState.clientStateMap.get(sessionState.mClient.asBinder());
73172ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim        if (clientState != null) {
73272ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim            clientState.mSessionTokens.remove(sessionToken);
73372ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim            if (clientState.isEmpty()) {
73472ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim                userState.clientStateMap.remove(sessionState.mClient.asBinder());
73572ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim            }
73672ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim        }
73772ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim
738187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim        TvInputInfo info = sessionState.mInfo;
739187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim        if (info != null) {
740187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim            ServiceState serviceState = userState.serviceStateMap.get(info.getComponent());
741187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim            if (serviceState != null) {
742187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                serviceState.mSessionTokens.remove(sessionToken);
743187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim            }
744fd5b72f1ed2ee74a4204eef65f560fc82f0b62feDongwon Kang        }
745187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim        updateServiceConnectionLocked(sessionState.mInfo.getComponent(), userId);
746fd5b72f1ed2ee74a4204eef65f560fc82f0b62feDongwon Kang    }
747fd5b72f1ed2ee74a4204eef65f560fc82f0b62feDongwon Kang
7488e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim    private void notifyInputAddedLocked(UserState userState, String inputId) {
7498e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim        if (DEBUG) {
7508e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim            Slog.d(TAG, "notifyInputAdded: inputId = " + inputId);
7518e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim        }
7528e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim        for (ITvInputManagerCallback callback : userState.callbackSet) {
7538e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim            try {
7548e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim                callback.onInputAdded(inputId);
7558e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim            } catch (RemoteException e) {
7568e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim                Slog.e(TAG, "Failed to report added input to callback.");
7578e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim            }
7588e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim        }
7598e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim    }
7608e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim
7618e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim    private void notifyInputRemovedLocked(UserState userState, String inputId) {
7628e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim        if (DEBUG) {
7638e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim            Slog.d(TAG, "notifyInputRemovedLocked: inputId = " + inputId);
7648e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim        }
7658e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim        for (ITvInputManagerCallback callback : userState.callbackSet) {
7668e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim            try {
7678e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim                callback.onInputRemoved(inputId);
7688e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim            } catch (RemoteException e) {
7698e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim                Slog.e(TAG, "Failed to report removed input to callback.");
7708e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim            }
7718e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim        }
7728e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim    }
7738e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim
7748e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim    private void notifyInputStateChangedLocked(UserState userState, String inputId,
775969167dc05a6485a32d160895871cff46fd81884Wonsik Kim            int state, ITvInputManagerCallback targetCallback) {
776969167dc05a6485a32d160895871cff46fd81884Wonsik Kim        if (DEBUG) {
7778e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim            Slog.d(TAG, "notifyInputStateChangedLocked: inputId = " + inputId
778969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                    + "; state = " + state);
779969167dc05a6485a32d160895871cff46fd81884Wonsik Kim        }
780969167dc05a6485a32d160895871cff46fd81884Wonsik Kim        if (targetCallback == null) {
781969167dc05a6485a32d160895871cff46fd81884Wonsik Kim            for (ITvInputManagerCallback callback : userState.callbackSet) {
782969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                try {
783969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                    callback.onInputStateChanged(inputId, state);
784969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                } catch (RemoteException e) {
785969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                    Slog.e(TAG, "Failed to report state change to callback.");
786969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                }
787969167dc05a6485a32d160895871cff46fd81884Wonsik Kim            }
788969167dc05a6485a32d160895871cff46fd81884Wonsik Kim        } else {
7892b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim            try {
790969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                targetCallback.onInputStateChanged(inputId, state);
7912b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim            } catch (RemoteException e) {
792969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                Slog.e(TAG, "Failed to report state change to callback.");
7932b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim            }
7942b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim        }
7952b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim    }
7962b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim
797969167dc05a6485a32d160895871cff46fd81884Wonsik Kim    private void setStateLocked(String inputId, int state, int userId) {
798969167dc05a6485a32d160895871cff46fd81884Wonsik Kim        UserState userState = getUserStateLocked(userId);
799969167dc05a6485a32d160895871cff46fd81884Wonsik Kim        TvInputState inputState = userState.inputMap.get(inputId);
800c88f1916b8ab7f5f75a00375c6fb4873ea5044afJi-Hwan Lee        ServiceState serviceState = userState.serviceStateMap.get(inputState.mInfo.getComponent());
801969167dc05a6485a32d160895871cff46fd81884Wonsik Kim        int oldState = inputState.mState;
802969167dc05a6485a32d160895871cff46fd81884Wonsik Kim        inputState.mState = state;
803187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim        if (serviceState != null && serviceState.mService == null
804187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                && shouldMaintainConnection(serviceState)) {
805969167dc05a6485a32d160895871cff46fd81884Wonsik Kim            // We don't notify state change while reconnecting. It should remain disconnected.
806969167dc05a6485a32d160895871cff46fd81884Wonsik Kim            return;
807969167dc05a6485a32d160895871cff46fd81884Wonsik Kim        }
808969167dc05a6485a32d160895871cff46fd81884Wonsik Kim        if (oldState != state) {
8098e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim            notifyInputStateChangedLocked(userState, inputId, state, null);
810969167dc05a6485a32d160895871cff46fd81884Wonsik Kim        }
811969167dc05a6485a32d160895871cff46fd81884Wonsik Kim    }
812969167dc05a6485a32d160895871cff46fd81884Wonsik Kim
8133957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    private final class BinderService extends ITvInputManager.Stub {
8143957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        @Override
8153957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        public List<TvInputInfo> getTvInputList(int userId) {
8163957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(),
8173957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    Binder.getCallingUid(), userId, "getTvInputList");
8183957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            final long identity = Binder.clearCallingIdentity();
8193957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            try {
8203957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                synchronized (mLock) {
8213957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    UserState userState = getUserStateLocked(resolvedUserId);
822969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                    List<TvInputInfo> inputList = new ArrayList<TvInputInfo>();
823969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                    for (TvInputState state : userState.inputMap.values()) {
824969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                        inputList.add(state.mInfo);
8253957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    }
826969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                    return inputList;
8273957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                }
8283957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            } finally {
8293957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                Binder.restoreCallingIdentity(identity);
8303957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            }
831b375805f3b1672e68d1511565af4700e5fa8491dJae Seo        }
832b375805f3b1672e68d1511565af4700e5fa8491dJae Seo
833b375805f3b1672e68d1511565af4700e5fa8491dJae Seo        @Override
834b375805f3b1672e68d1511565af4700e5fa8491dJae Seo        public TvInputInfo getTvInputInfo(String inputId, int userId) {
835b375805f3b1672e68d1511565af4700e5fa8491dJae Seo            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(),
836b375805f3b1672e68d1511565af4700e5fa8491dJae Seo                    Binder.getCallingUid(), userId, "getTvInputInfo");
837b375805f3b1672e68d1511565af4700e5fa8491dJae Seo            final long identity = Binder.clearCallingIdentity();
838b375805f3b1672e68d1511565af4700e5fa8491dJae Seo            try {
839b375805f3b1672e68d1511565af4700e5fa8491dJae Seo                synchronized (mLock) {
840b375805f3b1672e68d1511565af4700e5fa8491dJae Seo                    UserState userState = getUserStateLocked(resolvedUserId);
841b375805f3b1672e68d1511565af4700e5fa8491dJae Seo                    TvInputState state = userState.inputMap.get(inputId);
842b375805f3b1672e68d1511565af4700e5fa8491dJae Seo                    return state == null ? null : state.mInfo;
843b375805f3b1672e68d1511565af4700e5fa8491dJae Seo                }
844b375805f3b1672e68d1511565af4700e5fa8491dJae Seo            } finally {
845b375805f3b1672e68d1511565af4700e5fa8491dJae Seo                Binder.restoreCallingIdentity(identity);
846b375805f3b1672e68d1511565af4700e5fa8491dJae Seo            }
8473957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
8483957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
8493957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        @Override
8505c5b83fcd58d21c9ab7ac986bf84f604ec5bb4b5Sungsoo Lim        public List<Uri> getTvContentRatingSystemXmls(int userId) {
8515c5b83fcd58d21c9ab7ac986bf84f604ec5bb4b5Sungsoo Lim            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(),
8525c5b83fcd58d21c9ab7ac986bf84f604ec5bb4b5Sungsoo Lim                    Binder.getCallingUid(), userId, "getTvContentRatingSystemXmls");
8535c5b83fcd58d21c9ab7ac986bf84f604ec5bb4b5Sungsoo Lim            final long identity = Binder.clearCallingIdentity();
8545c5b83fcd58d21c9ab7ac986bf84f604ec5bb4b5Sungsoo Lim            try {
8555c5b83fcd58d21c9ab7ac986bf84f604ec5bb4b5Sungsoo Lim                synchronized (mLock) {
8565c5b83fcd58d21c9ab7ac986bf84f604ec5bb4b5Sungsoo Lim                    UserState userState = getUserStateLocked(resolvedUserId);
8575c5b83fcd58d21c9ab7ac986bf84f604ec5bb4b5Sungsoo Lim                    List<Uri> ratingSystemXmlUriList = new ArrayList<Uri>();
8585c5b83fcd58d21c9ab7ac986bf84f604ec5bb4b5Sungsoo Lim                    ratingSystemXmlUriList.addAll(userState.ratingSystemXmlUriSet);
8595c5b83fcd58d21c9ab7ac986bf84f604ec5bb4b5Sungsoo Lim                    return ratingSystemXmlUriList;
8605c5b83fcd58d21c9ab7ac986bf84f604ec5bb4b5Sungsoo Lim                }
8615c5b83fcd58d21c9ab7ac986bf84f604ec5bb4b5Sungsoo Lim            } finally {
8625c5b83fcd58d21c9ab7ac986bf84f604ec5bb4b5Sungsoo Lim                Binder.restoreCallingIdentity(identity);
8635c5b83fcd58d21c9ab7ac986bf84f604ec5bb4b5Sungsoo Lim            }
8645c5b83fcd58d21c9ab7ac986bf84f604ec5bb4b5Sungsoo Lim        }
8655c5b83fcd58d21c9ab7ac986bf84f604ec5bb4b5Sungsoo Lim
8665c5b83fcd58d21c9ab7ac986bf84f604ec5bb4b5Sungsoo Lim        @Override
867969167dc05a6485a32d160895871cff46fd81884Wonsik Kim        public void registerCallback(final ITvInputManagerCallback callback, int userId) {
8683957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(),
8693957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    Binder.getCallingUid(), userId, "registerCallback");
8703957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            final long identity = Binder.clearCallingIdentity();
8713957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            try {
8723957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                synchronized (mLock) {
8733957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    UserState userState = getUserStateLocked(resolvedUserId);
874969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                    userState.callbackSet.add(callback);
875969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                    for (TvInputState state : userState.inputMap.values()) {
8768e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim                        notifyInputStateChangedLocked(userState, state.mInfo.getId(),
877969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                                state.mState, callback);
8783957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    }
8793957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                }
8803957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            } finally {
8813957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                Binder.restoreCallingIdentity(identity);
8823957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            }
8833957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
8843957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
8853957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        @Override
886969167dc05a6485a32d160895871cff46fd81884Wonsik Kim        public void unregisterCallback(ITvInputManagerCallback callback, int userId) {
8873957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(),
8883957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    Binder.getCallingUid(), userId, "unregisterCallback");
8893957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            final long identity = Binder.clearCallingIdentity();
8903957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            try {
8913957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                synchronized (mLock) {
892969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                    UserState userState = getUserStateLocked(resolvedUserId);
893969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                    userState.callbackSet.remove(callback);
8943957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                }
8953957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            } finally {
8963957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                Binder.restoreCallingIdentity(identity);
8973957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            }
8983957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
8993957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
9003957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        @Override
901783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo        public boolean isParentalControlsEnabled(int userId) {
902783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(),
903783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                    Binder.getCallingUid(), userId, "isParentalControlsEnabled");
904783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo            final long identity = Binder.clearCallingIdentity();
905783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo            try {
906783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                synchronized (mLock) {
907783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                    UserState userState = getUserStateLocked(resolvedUserId);
908783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                    return userState.persistentDataStore.isParentalControlsEnabled();
909783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                }
910783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo            } finally {
911783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                Binder.restoreCallingIdentity(identity);
912783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo            }
913783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo        }
914783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo
915783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo        @Override
916783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo        public void setParentalControlsEnabled(boolean enabled, int userId) {
917783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo            ensureParentalControlsPermission();
918783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(),
919783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                    Binder.getCallingUid(), userId, "setParentalControlsEnabled");
920783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo            final long identity = Binder.clearCallingIdentity();
921783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo            try {
922783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                synchronized (mLock) {
923783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                    UserState userState = getUserStateLocked(resolvedUserId);
924783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                    userState.persistentDataStore.setParentalControlsEnabled(enabled);
925783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                }
926783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo            } finally {
927783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                Binder.restoreCallingIdentity(identity);
928783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo            }
929783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo        }
930783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo
931783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo        @Override
932783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo        public boolean isRatingBlocked(String rating, int userId) {
933783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(),
934783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                    Binder.getCallingUid(), userId, "isRatingBlocked");
935783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo            final long identity = Binder.clearCallingIdentity();
936783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo            try {
937783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                synchronized (mLock) {
938783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                    UserState userState = getUserStateLocked(resolvedUserId);
939783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                    return userState.persistentDataStore.isRatingBlocked(
940783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                            TvContentRating.unflattenFromString(rating));
941783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                }
942783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo            } finally {
943783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                Binder.restoreCallingIdentity(identity);
944783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo            }
945783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo        }
946783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo
947783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo        @Override
948783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo        public List<String> getBlockedRatings(int userId) {
949783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(),
950783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                    Binder.getCallingUid(), userId, "getBlockedRatings");
951783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo            final long identity = Binder.clearCallingIdentity();
952783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo            try {
953783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                synchronized (mLock) {
954783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                    UserState userState = getUserStateLocked(resolvedUserId);
955783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                    List<String> ratings = new ArrayList<String>();
956783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                    for (TvContentRating rating
957783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                            : userState.persistentDataStore.getBlockedRatings()) {
958783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                        ratings.add(rating.flattenToString());
959783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                    }
960783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                    return ratings;
961783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                }
962783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo            } finally {
963783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                Binder.restoreCallingIdentity(identity);
964783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo            }
965783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo        }
966783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo
967783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo        @Override
968783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo        public void addBlockedRating(String rating, int userId) {
969783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo            ensureParentalControlsPermission();
970783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(),
971783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                    Binder.getCallingUid(), userId, "addBlockedRating");
972783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo            final long identity = Binder.clearCallingIdentity();
973783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo            try {
974783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                synchronized (mLock) {
975783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                    UserState userState = getUserStateLocked(resolvedUserId);
976783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                    userState.persistentDataStore.addBlockedRating(
977783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                            TvContentRating.unflattenFromString(rating));
978783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                }
979783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo            } finally {
980783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                Binder.restoreCallingIdentity(identity);
981783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo            }
982783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo        }
983783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo
984783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo        @Override
985783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo        public void removeBlockedRating(String rating, int userId) {
986783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo            ensureParentalControlsPermission();
987783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(),
988783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                    Binder.getCallingUid(), userId, "removeBlockedRating");
989783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo            final long identity = Binder.clearCallingIdentity();
990783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo            try {
991783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                synchronized (mLock) {
992783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                    UserState userState = getUserStateLocked(resolvedUserId);
993783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                    userState.persistentDataStore.removeBlockedRating(
994783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                            TvContentRating.unflattenFromString(rating));
995783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                }
996783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo            } finally {
997783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                Binder.restoreCallingIdentity(identity);
998783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo            }
999783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo        }
1000783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo
1001783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo        private void ensureParentalControlsPermission() {
1002783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo            if (mContext.checkCallingPermission(
1003783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                    android.Manifest.permission.MODIFY_PARENTAL_CONTROLS)
1004783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                    != PackageManager.PERMISSION_GRANTED) {
1005783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                throw new SecurityException(
1006783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                        "The caller does not have parental controls permission");
1007783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo            }
1008783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo        }
1009783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo
1010783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo        @Override
1011d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim        public void createSession(final ITvInputClient client, final String inputId,
10123957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                int seq, int userId) {
10133957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            final int callingUid = Binder.getCallingUid();
10143957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
10153957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    userId, "createSession");
10163957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            final long identity = Binder.clearCallingIdentity();
10173957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            try {
10183957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                synchronized (mLock) {
10193957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    UserState userState = getUserStateLocked(resolvedUserId);
1020187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                    TvInputInfo info = userState.inputMap.get(inputId).mInfo;
1021187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                    ServiceState serviceState = userState.serviceStateMap.get(info.getComponent());
10223957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    if (serviceState == null) {
1023187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                        serviceState = new ServiceState(info.getComponent(), resolvedUserId);
1024187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                        userState.serviceStateMap.put(info.getComponent(), serviceState);
10253957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    }
10262b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                    // Send a null token immediately while reconnecting.
10272b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                    if (serviceState.mReconnecting == true) {
10285c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo                        sendSessionTokenToClientLocked(client, inputId, null, null, seq);
10292b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                        return;
10302b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                    }
10312b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim
10322b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                    // Create a new session token and a session state.
10332b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                    IBinder sessionToken = new Binder();
1034187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                    SessionState sessionState = new SessionState(sessionToken, info, client,
103572ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim                            seq, callingUid, resolvedUserId);
10362b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim
10372b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                    // Add them to the global session state map of the current user.
10382b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                    userState.sessionStateMap.put(sessionToken, sessionState);
10392b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim
10402b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                    // Also, add them to the session state map of the current service.
1041d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim                    serviceState.mSessionTokens.add(sessionToken);
10423957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
1043d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim                    if (serviceState.mService != null) {
1044d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim                        createSessionInternalLocked(serviceState.mService, sessionToken,
10457de5e234715a3baa8905afa3dd0c5009af64541fSungsoo Lim                                resolvedUserId);
10463957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    } else {
1047187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                        updateServiceConnectionLocked(info.getComponent(), resolvedUserId);
10483957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    }
10493957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                }
10503957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            } finally {
10513957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                Binder.restoreCallingIdentity(identity);
10523957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            }
10533957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
10543957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
10553957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        @Override
10563957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        public void releaseSession(IBinder sessionToken, int userId) {
10573957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            final int callingUid = Binder.getCallingUid();
10583957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
10593957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    userId, "releaseSession");
10603957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            final long identity = Binder.clearCallingIdentity();
10613957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            try {
10623957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                synchronized (mLock) {
10632b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                    releaseSessionLocked(sessionToken, callingUid, resolvedUserId);
10643957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                }
10653957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            } finally {
10663957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                Binder.restoreCallingIdentity(identity);
10673957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            }
10683957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
10693957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
10703957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        @Override
10714c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee        public void setMainSession(IBinder sessionToken, int userId) {
10724c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee            final int callingUid = Binder.getCallingUid();
10734c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
10744c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee                    userId, "setMainSession");
10754c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee            final long identity = Binder.clearCallingIdentity();
10764c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee            try {
10774c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee                synchronized (mLock) {
1078982abe693f66037ca265b88057eceb5a3e815182Ji-Hwan Lee                    UserState userState = getUserStateLocked(resolvedUserId);
1079956afc2ba79f50bb8025c6d334653e3c3419b480Ji-Hwan Lee                    if (userState.mainSessionToken == sessionToken) {
10804c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee                        return;
10814c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee                    }
10824c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee
1083956afc2ba79f50bb8025c6d334653e3c3419b480Ji-Hwan Lee                    SessionState newMainSessionState = getSessionStateLocked(
1084956afc2ba79f50bb8025c6d334653e3c3419b480Ji-Hwan Lee                            sessionToken, callingUid, resolvedUserId);
1085956afc2ba79f50bb8025c6d334653e3c3419b480Ji-Hwan Lee                    if (newMainSessionState.mHardwareSessionToken != null) {
1086956afc2ba79f50bb8025c6d334653e3c3419b480Ji-Hwan Lee                        newMainSessionState = getSessionStateLocked(
1087956afc2ba79f50bb8025c6d334653e3c3419b480Ji-Hwan Lee                                newMainSessionState.mHardwareSessionToken,
1088956afc2ba79f50bb8025c6d334653e3c3419b480Ji-Hwan Lee                                Process.SYSTEM_UID, resolvedUserId);
1089956afc2ba79f50bb8025c6d334653e3c3419b480Ji-Hwan Lee                    }
1090956afc2ba79f50bb8025c6d334653e3c3419b480Ji-Hwan Lee                    ServiceState newMainServiceState = getServiceStateLocked(
1091956afc2ba79f50bb8025c6d334653e3c3419b480Ji-Hwan Lee                            newMainSessionState.mInfo.getComponent(), resolvedUserId);
1092956afc2ba79f50bb8025c6d334653e3c3419b480Ji-Hwan Lee                    ITvInputSession newMainSession = getSessionLocked(newMainSessionState);
10934c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee
1094956afc2ba79f50bb8025c6d334653e3c3419b480Ji-Hwan Lee                    ServiceState oldMainServiceState = null;
1095956afc2ba79f50bb8025c6d334653e3c3419b480Ji-Hwan Lee                    ITvInputSession oldMainSession = null;
1096abca0ee7949f59e72b8d2764dafa23af18eb51dbJi-Hwan Lee                    if (userState.mainSessionToken != null) {
1097956afc2ba79f50bb8025c6d334653e3c3419b480Ji-Hwan Lee                        SessionState oldMainSessionState = getSessionStateLocked(
1098abca0ee7949f59e72b8d2764dafa23af18eb51dbJi-Hwan Lee                                userState.mainSessionToken, Process.SYSTEM_UID, resolvedUserId);
1099956afc2ba79f50bb8025c6d334653e3c3419b480Ji-Hwan Lee                        if (oldMainSessionState.mHardwareSessionToken != null) {
1100956afc2ba79f50bb8025c6d334653e3c3419b480Ji-Hwan Lee                            oldMainSessionState = getSessionStateLocked(
1101956afc2ba79f50bb8025c6d334653e3c3419b480Ji-Hwan Lee                                    oldMainSessionState.mHardwareSessionToken,
1102956afc2ba79f50bb8025c6d334653e3c3419b480Ji-Hwan Lee                                    Process.SYSTEM_UID, resolvedUserId);
1103956afc2ba79f50bb8025c6d334653e3c3419b480Ji-Hwan Lee                        }
1104956afc2ba79f50bb8025c6d334653e3c3419b480Ji-Hwan Lee                        oldMainServiceState = getServiceStateLocked(
1105956afc2ba79f50bb8025c6d334653e3c3419b480Ji-Hwan Lee                                oldMainSessionState.mInfo.getComponent(), resolvedUserId);
1106956afc2ba79f50bb8025c6d334653e3c3419b480Ji-Hwan Lee                        oldMainSession = getSessionLocked(oldMainSessionState);
1107abca0ee7949f59e72b8d2764dafa23af18eb51dbJi-Hwan Lee                    }
1108abca0ee7949f59e72b8d2764dafa23af18eb51dbJi-Hwan Lee
11094c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee                    userState.mainSessionToken = sessionToken;
11104c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee
1111956afc2ba79f50bb8025c6d334653e3c3419b480Ji-Hwan Lee                    // Inform the new main session first.
1112956afc2ba79f50bb8025c6d334653e3c3419b480Ji-Hwan Lee                    // See {@link TvInputService#onSetMainSession}.
1113956afc2ba79f50bb8025c6d334653e3c3419b480Ji-Hwan Lee                    if (newMainServiceState.mIsHardware) {
11144c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee                        try {
1115956afc2ba79f50bb8025c6d334653e3c3419b480Ji-Hwan Lee                            newMainSession.setMainSession(true);
11164c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee                        } catch (RemoteException e) {
11174c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee                            Slog.e(TAG, "error in setMainSession", e);
11184c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee                        }
11194c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee                    }
1120956afc2ba79f50bb8025c6d334653e3c3419b480Ji-Hwan Lee                    if (oldMainSession != null && oldMainServiceState.mIsHardware) {
11214c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee                        try {
1122956afc2ba79f50bb8025c6d334653e3c3419b480Ji-Hwan Lee                            oldMainSession.setMainSession(false);
11234c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee                        } catch (RemoteException e) {
11244c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee                            Slog.e(TAG, "error in setMainSession", e);
11254c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee                        }
11264c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee                    }
11274c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee                }
11284c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee            } finally {
11294c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee                Binder.restoreCallingIdentity(identity);
11304c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee            }
11314c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee        }
11324c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee
11334c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee        @Override
11343957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        public void setSurface(IBinder sessionToken, Surface surface, int userId) {
11353957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            final int callingUid = Binder.getCallingUid();
11363957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
11373957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    userId, "setSurface");
11383957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            final long identity = Binder.clearCallingIdentity();
11393957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            try {
11403957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                synchronized (mLock) {
11413957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    try {
1142bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                        SessionState sessionState = getSessionStateLocked(sessionToken, callingUid,
1143bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                                resolvedUserId);
1144bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                        if (sessionState.mHardwareSessionToken == null) {
1145bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                            getSessionLocked(sessionState).setSurface(surface);
1146bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                        } else {
1147bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                            getSessionLocked(sessionState.mHardwareSessionToken,
1148bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                                    Process.SYSTEM_UID, resolvedUserId).setSurface(surface);
1149bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                        }
11503957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    } catch (RemoteException e) {
11519a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                        Slog.e(TAG, "error in setSurface", e);
11523957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    }
11533957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                }
11543957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            } finally {
1155f836206818ce338db83a3c23c486fb8cab29cb6dYoungsang Cho                if (surface != null) {
1156f836206818ce338db83a3c23c486fb8cab29cb6dYoungsang Cho                    // surface is not used in TvInputManagerService.
1157f836206818ce338db83a3c23c486fb8cab29cb6dYoungsang Cho                    surface.release();
1158f836206818ce338db83a3c23c486fb8cab29cb6dYoungsang Cho                }
11593957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                Binder.restoreCallingIdentity(identity);
11603957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            }
11613957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
11623957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
11633957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        @Override
1164e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho        public void dispatchSurfaceChanged(IBinder sessionToken, int format, int width,
1165e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho                int height, int userId) {
1166e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho            final int callingUid = Binder.getCallingUid();
1167e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
1168e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho                    userId, "dispatchSurfaceChanged");
1169e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho            final long identity = Binder.clearCallingIdentity();
1170e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho            try {
1171e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho                synchronized (mLock) {
1172e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho                    try {
1173bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                        SessionState sessionState = getSessionStateLocked(sessionToken, callingUid,
1174bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                                resolvedUserId);
1175bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                        getSessionLocked(sessionState).dispatchSurfaceChanged(format, width, height);
1176bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                        if (sessionState.mHardwareSessionToken != null) {
1177bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                            getSessionLocked(sessionState.mHardwareSessionToken, Process.SYSTEM_UID,
1178bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                                    resolvedUserId).dispatchSurfaceChanged(format, width, height);
1179bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                        }
1180e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho                    } catch (RemoteException e) {
1181e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho                        Slog.e(TAG, "error in dispatchSurfaceChanged", e);
1182e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho                    }
1183e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho                }
1184e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho            } finally {
1185e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho                Binder.restoreCallingIdentity(identity);
1186e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho            }
1187e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho        }
1188e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho
1189e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho        @Override
11903957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        public void setVolume(IBinder sessionToken, float volume, int userId) {
1191bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang            final float REMOTE_VOLUME_ON = 1.0f;
1192bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang            final float REMOTE_VOLUME_OFF = 0f;
11933957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            final int callingUid = Binder.getCallingUid();
11943957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
11953957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    userId, "setVolume");
11963957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            final long identity = Binder.clearCallingIdentity();
11973957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            try {
11983957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                synchronized (mLock) {
11993957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    try {
1200bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                        SessionState sessionState = getSessionStateLocked(sessionToken, callingUid,
1201bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                                resolvedUserId);
1202bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                        getSessionLocked(sessionState).setVolume(volume);
1203bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                        if (sessionState.mHardwareSessionToken != null) {
1204bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                            // Here, we let the hardware session know only whether volume is on or
1205bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                            // off to prevent that the volume is controlled in the both side.
1206bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                            getSessionLocked(sessionState.mHardwareSessionToken,
1207bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                                    Process.SYSTEM_UID, resolvedUserId).setVolume((volume > 0.0f)
1208bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                                            ? REMOTE_VOLUME_ON : REMOTE_VOLUME_OFF);
1209bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                        }
12103957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    } catch (RemoteException e) {
12119a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                        Slog.e(TAG, "error in setVolume", e);
12123957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    }
12133957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                }
12143957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            } finally {
12153957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                Binder.restoreCallingIdentity(identity);
12163957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            }
12173957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
12183957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
12193957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        @Override
12201a6b25eabcc1fb66e6e8d76f91fd413e18b793a9Sungsoo Lim        public void tune(IBinder sessionToken, final Uri channelUri, Bundle params, int userId) {
12213957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            final int callingUid = Binder.getCallingUid();
12223957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
12233957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    userId, "tune");
12243957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            final long identity = Binder.clearCallingIdentity();
12253957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            try {
12263957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                synchronized (mLock) {
12273957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    try {
12281a6b25eabcc1fb66e6e8d76f91fd413e18b793a9Sungsoo Lim                        getSessionLocked(sessionToken, callingUid, resolvedUserId).tune(
12291a6b25eabcc1fb66e6e8d76f91fd413e18b793a9Sungsoo Lim                                channelUri, params);
1230008f6d4e326f6372e165bdf342178ecd1e834e2fYoungsang Cho                        if (TvContract.isChannelUriForPassthroughTvInput(channelUri)) {
1231008f6d4e326f6372e165bdf342178ecd1e834e2fYoungsang Cho                            // Do not log the watch history for passthrough inputs.
1232008f6d4e326f6372e165bdf342178ecd1e834e2fYoungsang Cho                            return;
1233008f6d4e326f6372e165bdf342178ecd1e834e2fYoungsang Cho                        }
123431dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                        long currentTime = System.currentTimeMillis();
123531dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                        long channelId = ContentUris.parseId(channelUri);
123631dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo
123731dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                        // Close the open log entry first, if any.
123831dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                        UserState userState = getUserStateLocked(resolvedUserId);
123931dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                        SessionState sessionState = userState.sessionStateMap.get(sessionToken);
1240d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim                        if (sessionState.mLogUri != null) {
124131dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                            SomeArgs args = SomeArgs.obtain();
1242d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim                            args.arg1 = sessionState.mLogUri;
124331dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                            args.arg2 = currentTime;
124431dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                            mLogHandler.obtainMessage(LogHandler.MSG_CLOSE_ENTRY, args)
124531dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                                    .sendToTarget();
124631dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                        }
124731dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo
124831dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                        // Create a log entry and fill it later.
1249187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                        String packageName = sessionState.mInfo.getServiceInfo().packageName;
125031dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                        ContentValues values = new ContentValues();
12515c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo                        values.put(TvContract.WatchedPrograms.COLUMN_PACKAGE_NAME, packageName);
1252f5cd0b388ac31104e014f9193d06080851a09e18Jae Seo                        values.put(TvContract.WatchedPrograms.COLUMN_WATCH_START_TIME_UTC_MILLIS,
125331dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                                currentTime);
1254f5cd0b388ac31104e014f9193d06080851a09e18Jae Seo                        values.put(TvContract.WatchedPrograms.COLUMN_WATCH_END_TIME_UTC_MILLIS, 0);
1255f5cd0b388ac31104e014f9193d06080851a09e18Jae Seo                        values.put(TvContract.WatchedPrograms.COLUMN_CHANNEL_ID, channelId);
12561a6b25eabcc1fb66e6e8d76f91fd413e18b793a9Sungsoo Lim                        if (params != null) {
12571a6b25eabcc1fb66e6e8d76f91fd413e18b793a9Sungsoo Lim                            values.put(TvContract.WatchedPrograms.COLUMN_TUNE_PARAMS,
12581a6b25eabcc1fb66e6e8d76f91fd413e18b793a9Sungsoo Lim                                    encodeTuneParams(params));
12591a6b25eabcc1fb66e6e8d76f91fd413e18b793a9Sungsoo Lim                        }
126031dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo
1261d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim                        sessionState.mLogUri = mContentResolver.insert(
126231dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                                TvContract.WatchedPrograms.CONTENT_URI, values);
126331dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                        SomeArgs args = SomeArgs.obtain();
1264d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim                        args.arg1 = sessionState.mLogUri;
126531dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                        args.arg2 = ContentUris.parseId(channelUri);
126631dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                        args.arg3 = currentTime;
1267579befecb248162021929ab58ffd23f1724cc6beJae Seo                        args.arg4 = sessionState;
126831dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                        mLogHandler.obtainMessage(LogHandler.MSG_OPEN_ENTRY, args).sendToTarget();
12693957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    } catch (RemoteException e) {
12709a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                        Slog.e(TAG, "error in tune", e);
12713957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                        return;
12723957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    }
12733957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                }
12743957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            } finally {
12753957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                Binder.restoreCallingIdentity(identity);
12763957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            }
12773957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
12789a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho
12799a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho        @Override
12809bf671f8ee72b156f16fcf05a3d1c6e093ecba67Sungsoo Lim        public void requestUnblockContent(
12819bf671f8ee72b156f16fcf05a3d1c6e093ecba67Sungsoo Lim                IBinder sessionToken, String unblockedRating, int userId) {
1282903d6b72cd572665309633e925485464d08bb25aJaewan Kim            final int callingUid = Binder.getCallingUid();
1283903d6b72cd572665309633e925485464d08bb25aJaewan Kim            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
1284903d6b72cd572665309633e925485464d08bb25aJaewan Kim                    userId, "unblockContent");
1285903d6b72cd572665309633e925485464d08bb25aJaewan Kim            final long identity = Binder.clearCallingIdentity();
1286903d6b72cd572665309633e925485464d08bb25aJaewan Kim            try {
1287903d6b72cd572665309633e925485464d08bb25aJaewan Kim                synchronized (mLock) {
1288903d6b72cd572665309633e925485464d08bb25aJaewan Kim                    try {
1289903d6b72cd572665309633e925485464d08bb25aJaewan Kim                        getSessionLocked(sessionToken, callingUid, resolvedUserId)
12909bf671f8ee72b156f16fcf05a3d1c6e093ecba67Sungsoo Lim                                .requestUnblockContent(unblockedRating);
1291903d6b72cd572665309633e925485464d08bb25aJaewan Kim                    } catch (RemoteException e) {
1292903d6b72cd572665309633e925485464d08bb25aJaewan Kim                        Slog.e(TAG, "error in unblockContent", e);
1293903d6b72cd572665309633e925485464d08bb25aJaewan Kim                    }
1294903d6b72cd572665309633e925485464d08bb25aJaewan Kim                }
1295903d6b72cd572665309633e925485464d08bb25aJaewan Kim            } finally {
1296903d6b72cd572665309633e925485464d08bb25aJaewan Kim                Binder.restoreCallingIdentity(identity);
1297903d6b72cd572665309633e925485464d08bb25aJaewan Kim            }
1298903d6b72cd572665309633e925485464d08bb25aJaewan Kim        }
1299903d6b72cd572665309633e925485464d08bb25aJaewan Kim
1300903d6b72cd572665309633e925485464d08bb25aJaewan Kim        @Override
13012c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo        public void setCaptionEnabled(IBinder sessionToken, boolean enabled, int userId) {
13022c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo            final int callingUid = Binder.getCallingUid();
13032c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
13042c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo                    userId, "setCaptionEnabled");
13052c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo            final long identity = Binder.clearCallingIdentity();
13062c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo            try {
13072c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo                synchronized (mLock) {
13082c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo                    try {
13092c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo                        getSessionLocked(sessionToken, callingUid, resolvedUserId)
13102c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo                                .setCaptionEnabled(enabled);
13112c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo                    } catch (RemoteException e) {
13122c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo                        Slog.e(TAG, "error in setCaptionEnabled", e);
13132c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo                    }
13142c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo                }
13152c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo            } finally {
13162c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo                Binder.restoreCallingIdentity(identity);
13172c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo            }
13182c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo        }
13192c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo
13202c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo        @Override
132110d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo        public void selectTrack(IBinder sessionToken, int type, String trackId, int userId) {
13221f213914c45c23c653f721690da2ce0718e63139Dongwon Kang            final int callingUid = Binder.getCallingUid();
13231f213914c45c23c653f721690da2ce0718e63139Dongwon Kang            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
13241f213914c45c23c653f721690da2ce0718e63139Dongwon Kang                    userId, "selectTrack");
13251f213914c45c23c653f721690da2ce0718e63139Dongwon Kang            final long identity = Binder.clearCallingIdentity();
13261f213914c45c23c653f721690da2ce0718e63139Dongwon Kang            try {
13271f213914c45c23c653f721690da2ce0718e63139Dongwon Kang                synchronized (mLock) {
13281f213914c45c23c653f721690da2ce0718e63139Dongwon Kang                    try {
13291f213914c45c23c653f721690da2ce0718e63139Dongwon Kang                        getSessionLocked(sessionToken, callingUid, resolvedUserId).selectTrack(
133010d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo                                type, trackId);
13311f213914c45c23c653f721690da2ce0718e63139Dongwon Kang                    } catch (RemoteException e) {
13321f213914c45c23c653f721690da2ce0718e63139Dongwon Kang                        Slog.e(TAG, "error in selectTrack", e);
13331f213914c45c23c653f721690da2ce0718e63139Dongwon Kang                    }
13341f213914c45c23c653f721690da2ce0718e63139Dongwon Kang                }
13351f213914c45c23c653f721690da2ce0718e63139Dongwon Kang            } finally {
13361f213914c45c23c653f721690da2ce0718e63139Dongwon Kang                Binder.restoreCallingIdentity(identity);
13371f213914c45c23c653f721690da2ce0718e63139Dongwon Kang            }
13381f213914c45c23c653f721690da2ce0718e63139Dongwon Kang        }
13391f213914c45c23c653f721690da2ce0718e63139Dongwon Kang
13401f213914c45c23c653f721690da2ce0718e63139Dongwon Kang        @Override
1341a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo        public void sendAppPrivateCommand(IBinder sessionToken, String command, Bundle data,
1342a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo                int userId) {
1343a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo            final int callingUid = Binder.getCallingUid();
1344a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
1345a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo                    userId, "sendAppPrivateCommand");
1346a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo            final long identity = Binder.clearCallingIdentity();
1347a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo            try {
1348a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo                synchronized (mLock) {
1349a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo                    try {
1350a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo                        getSessionLocked(sessionToken, callingUid, resolvedUserId)
1351a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo                                .appPrivateCommand(command, data);
1352a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo                    } catch (RemoteException e) {
1353a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo                        Slog.e(TAG, "error in sendAppPrivateCommand", e);
1354a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo                    }
1355a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo                }
1356a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo            } finally {
1357a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo                Binder.restoreCallingIdentity(identity);
1358a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo            }
1359a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo        }
1360a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo
1361a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo        @Override
13629a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho        public void createOverlayView(IBinder sessionToken, IBinder windowToken, Rect frame,
13639a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                int userId) {
13649a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            final int callingUid = Binder.getCallingUid();
13659a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
13669a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                    userId, "createOverlayView");
13679a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            final long identity = Binder.clearCallingIdentity();
13689a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            try {
13699a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                synchronized (mLock) {
13709a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                    try {
13719a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                        getSessionLocked(sessionToken, callingUid, resolvedUserId)
13729a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                                .createOverlayView(windowToken, frame);
13739a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                    } catch (RemoteException e) {
13749a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                        Slog.e(TAG, "error in createOverlayView", e);
13759a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                    }
13769a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                }
13779a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            } finally {
13789a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                Binder.restoreCallingIdentity(identity);
13799a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            }
13809a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho        }
13819a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho
13829a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho        @Override
13839a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho        public void relayoutOverlayView(IBinder sessionToken, Rect frame, int userId) {
13849a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            final int callingUid = Binder.getCallingUid();
13859a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
13869a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                    userId, "relayoutOverlayView");
13879a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            final long identity = Binder.clearCallingIdentity();
13889a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            try {
13899a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                synchronized (mLock) {
13909a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                    try {
13919a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                        getSessionLocked(sessionToken, callingUid, resolvedUserId)
13929a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                                .relayoutOverlayView(frame);
13939a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                    } catch (RemoteException e) {
13949a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                        Slog.e(TAG, "error in relayoutOverlayView", e);
13959a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                    }
13969a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                }
13979a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            } finally {
13989a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                Binder.restoreCallingIdentity(identity);
13999a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            }
14009a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho        }
14019a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho
14029a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho        @Override
14039a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho        public void removeOverlayView(IBinder sessionToken, int userId) {
14049a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            final int callingUid = Binder.getCallingUid();
14059a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
14069a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                    userId, "removeOverlayView");
14079a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            final long identity = Binder.clearCallingIdentity();
14089a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            try {
14099a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                synchronized (mLock) {
14109a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                    try {
14119a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                        getSessionLocked(sessionToken, callingUid, resolvedUserId)
14129a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                                .removeOverlayView();
14139a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                    } catch (RemoteException e) {
14149a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                        Slog.e(TAG, "error in removeOverlayView", e);
14159a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                    }
14169a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                }
14179a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            } finally {
14189a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                Binder.restoreCallingIdentity(identity);
14199a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            }
14209a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho        }
1421c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim
1422c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim        @Override
1423c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim        public List<TvInputHardwareInfo> getHardwareList() throws RemoteException {
1424969167dc05a6485a32d160895871cff46fd81884Wonsik Kim            if (mContext.checkCallingPermission(android.Manifest.permission.TV_INPUT_HARDWARE)
1425c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim                    != PackageManager.PERMISSION_GRANTED) {
1426c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim                return null;
1427c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim            }
1428c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim
1429c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim            final long identity = Binder.clearCallingIdentity();
1430c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim            try {
1431c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim                return mTvInputHardwareManager.getHardwareList();
1432c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim            } finally {
1433c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim                Binder.restoreCallingIdentity(identity);
1434c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim            }
1435c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim        }
1436c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim
1437c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim        @Override
1438c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim        public ITvInputHardware acquireTvInputHardware(int deviceId,
1439969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                ITvInputHardwareCallback callback, TvInputInfo info, int userId)
1440969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                throws RemoteException {
1441969167dc05a6485a32d160895871cff46fd81884Wonsik Kim            if (mContext.checkCallingPermission(android.Manifest.permission.TV_INPUT_HARDWARE)
1442c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim                    != PackageManager.PERMISSION_GRANTED) {
1443c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim                return null;
1444c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim            }
1445c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim
1446c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim            final long identity = Binder.clearCallingIdentity();
1447c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim            final int callingUid = Binder.getCallingUid();
1448c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
1449c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim                    userId, "acquireTvInputHardware");
1450c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim            try {
1451c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim                return mTvInputHardwareManager.acquireHardware(
1452969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                        deviceId, callback, info, callingUid, resolvedUserId);
1453c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim            } finally {
1454c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim                Binder.restoreCallingIdentity(identity);
1455c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim            }
1456c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim        }
1457c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim
1458c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim        @Override
1459c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim        public void releaseTvInputHardware(int deviceId, ITvInputHardware hardware, int userId)
1460c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim                throws RemoteException {
1461969167dc05a6485a32d160895871cff46fd81884Wonsik Kim            if (mContext.checkCallingPermission(android.Manifest.permission.TV_INPUT_HARDWARE)
1462c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim                    != PackageManager.PERMISSION_GRANTED) {
1463c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim                return;
1464c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim            }
1465c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim
1466c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim            final long identity = Binder.clearCallingIdentity();
1467c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim            final int callingUid = Binder.getCallingUid();
1468c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
1469c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim                    userId, "releaseTvInputHardware");
1470c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim            try {
1471c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim                mTvInputHardwareManager.releaseHardware(
1472c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim                        deviceId, hardware, callingUid, resolvedUserId);
1473c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim            } finally {
1474c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim                Binder.restoreCallingIdentity(identity);
1475c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim            }
1476c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim        }
1477e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim
1478e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim        @Override
1479c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo        public List<TvStreamConfig> getAvailableTvStreamConfigList(String inputId, int userId)
1480c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo                throws RemoteException {
1481c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo            if (mContext.checkCallingPermission(
1482c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo                    android.Manifest.permission.CAPTURE_TV_INPUT)
1483c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo                    != PackageManager.PERMISSION_GRANTED) {
1484c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo                throw new SecurityException("Requires CAPTURE_TV_INPUT permission");
1485c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo            }
1486c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo
1487c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo            final long identity = Binder.clearCallingIdentity();
1488c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo            final int callingUid = Binder.getCallingUid();
1489c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
1490c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo                    userId, "getAvailableTvStreamConfigList");
1491c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo            try {
1492c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo                return mTvInputHardwareManager.getAvailableTvStreamConfigList(
1493c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo                        inputId, callingUid, resolvedUserId);
1494c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo            } finally {
1495c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo                Binder.restoreCallingIdentity(identity);
1496c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo            }
1497c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo        }
1498c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo
1499c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo        @Override
1500c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo        public boolean captureFrame(String inputId, Surface surface, TvStreamConfig config,
1501c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo                int userId)
1502c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo                throws RemoteException {
1503c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo            if (mContext.checkCallingPermission(
1504c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo                    android.Manifest.permission.CAPTURE_TV_INPUT)
1505c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo                    != PackageManager.PERMISSION_GRANTED) {
1506c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo                throw new SecurityException("Requires CAPTURE_TV_INPUT permission");
1507c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo            }
1508c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo
1509c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo            final long identity = Binder.clearCallingIdentity();
1510c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo            final int callingUid = Binder.getCallingUid();
1511c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
1512c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo                    userId, "captureFrame");
1513c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo            try {
1514bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                String hardwareInputId = null;
151579124a717c09f12c74d587d3977bf33ca37e6420Terry Heo                synchronized (mLock) {
151679124a717c09f12c74d587d3977bf33ca37e6420Terry Heo                    UserState userState = getUserStateLocked(resolvedUserId);
1517bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                    if (userState.inputMap.get(inputId) == null) {
1518bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                        Slog.e(TAG, "Input not found for " + inputId);
1519bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                        return false;
1520bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                    }
1521bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                    for (SessionState sessionState : userState.sessionStateMap.values()) {
1522bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                        if (sessionState.mInfo.getId().equals(inputId)
1523bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                                && sessionState.mHardwareSessionToken != null) {
1524bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                            hardwareInputId = userState.sessionStateMap.get(
1525bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                                    sessionState.mHardwareSessionToken).mInfo.getId();
1526bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                            break;
1527bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                        }
1528bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                    }
152979124a717c09f12c74d587d3977bf33ca37e6420Terry Heo                }
1530c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo                return mTvInputHardwareManager.captureFrame(
1531bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                        (hardwareInputId != null) ? hardwareInputId : inputId,
153279124a717c09f12c74d587d3977bf33ca37e6420Terry Heo                        surface, config, callingUid, resolvedUserId);
1533c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo            } finally {
1534c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo                Binder.restoreCallingIdentity(identity);
1535c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo            }
1536c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo        }
1537c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo
1538c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo        @Override
1539df9f0a321e0cb2958c9d170395a0367a106fa0e6Terry Heo        public boolean isSingleSessionActive(int userId) throws RemoteException {
1540df9f0a321e0cb2958c9d170395a0367a106fa0e6Terry Heo            final long identity = Binder.clearCallingIdentity();
1541df9f0a321e0cb2958c9d170395a0367a106fa0e6Terry Heo            final int callingUid = Binder.getCallingUid();
1542df9f0a321e0cb2958c9d170395a0367a106fa0e6Terry Heo            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
1543df9f0a321e0cb2958c9d170395a0367a106fa0e6Terry Heo                    userId, "isSingleSessionActive");
1544df9f0a321e0cb2958c9d170395a0367a106fa0e6Terry Heo            try {
1545df9f0a321e0cb2958c9d170395a0367a106fa0e6Terry Heo                synchronized (mLock) {
1546df9f0a321e0cb2958c9d170395a0367a106fa0e6Terry Heo                    UserState userState = getUserStateLocked(resolvedUserId);
1547df9f0a321e0cb2958c9d170395a0367a106fa0e6Terry Heo                    if (userState.sessionStateMap.size() == 1) {
1548df9f0a321e0cb2958c9d170395a0367a106fa0e6Terry Heo                        return true;
1549df9f0a321e0cb2958c9d170395a0367a106fa0e6Terry Heo                    }
1550df9f0a321e0cb2958c9d170395a0367a106fa0e6Terry Heo                    else if (userState.sessionStateMap.size() == 2) {
1551df9f0a321e0cb2958c9d170395a0367a106fa0e6Terry Heo                        SessionState[] sessionStates = userState.sessionStateMap.values().toArray(
1552df9f0a321e0cb2958c9d170395a0367a106fa0e6Terry Heo                                new SessionState[0]);
1553df9f0a321e0cb2958c9d170395a0367a106fa0e6Terry Heo                        // Check if there is a wrapper input.
1554df9f0a321e0cb2958c9d170395a0367a106fa0e6Terry Heo                        if (sessionStates[0].mHardwareSessionToken != null
1555df9f0a321e0cb2958c9d170395a0367a106fa0e6Terry Heo                                || sessionStates[1].mHardwareSessionToken != null) {
1556df9f0a321e0cb2958c9d170395a0367a106fa0e6Terry Heo                            return true;
1557df9f0a321e0cb2958c9d170395a0367a106fa0e6Terry Heo                        }
1558df9f0a321e0cb2958c9d170395a0367a106fa0e6Terry Heo                    }
1559df9f0a321e0cb2958c9d170395a0367a106fa0e6Terry Heo                    return false;
1560df9f0a321e0cb2958c9d170395a0367a106fa0e6Terry Heo                }
1561df9f0a321e0cb2958c9d170395a0367a106fa0e6Terry Heo            } finally {
1562df9f0a321e0cb2958c9d170395a0367a106fa0e6Terry Heo                Binder.restoreCallingIdentity(identity);
1563df9f0a321e0cb2958c9d170395a0367a106fa0e6Terry Heo            }
1564df9f0a321e0cb2958c9d170395a0367a106fa0e6Terry Heo        }
1565df9f0a321e0cb2958c9d170395a0367a106fa0e6Terry Heo
1566df9f0a321e0cb2958c9d170395a0367a106fa0e6Terry Heo        @Override
15670f8fc345ea61928265fdd6d461bf1babe353fbe4Jae Seo        @SuppressWarnings("resource")
1568e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim        protected void dump(FileDescriptor fd, final PrintWriter writer, String[] args) {
1569e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim            final IndentingPrintWriter pw = new IndentingPrintWriter(writer, "  ");
15700f8fc345ea61928265fdd6d461bf1babe353fbe4Jae Seo            if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
1571e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                    != PackageManager.PERMISSION_GRANTED) {
15720f8fc345ea61928265fdd6d461bf1babe353fbe4Jae Seo                pw.println("Permission Denial: can't dump TvInputManager from pid="
15730f8fc345ea61928265fdd6d461bf1babe353fbe4Jae Seo                        + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid());
1574e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                return;
1575e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim            }
1576e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim
1577e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim            synchronized (mLock) {
1578e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                pw.println("User Ids (Current user: " + mCurrentUserId + "):");
1579e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                pw.increaseIndent();
1580e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                for (int i = 0; i < mUserStates.size(); i++) {
1581e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                    int userId = mUserStates.keyAt(i);
1582e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                    pw.println(Integer.valueOf(userId));
1583e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                }
1584e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                pw.decreaseIndent();
1585e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim
1586e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                for (int i = 0; i < mUserStates.size(); i++) {
1587e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                    int userId = mUserStates.keyAt(i);
1588e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                    UserState userState = getUserStateLocked(userId);
1589e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                    pw.println("UserState (" + userId + "):");
1590e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                    pw.increaseIndent();
1591e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim
1592969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                    pw.println("inputMap: inputId -> TvInputState");
1593e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                    pw.increaseIndent();
15948e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim                    for (Map.Entry<String, TvInputState> entry: userState.inputMap.entrySet()) {
15958e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim                        pw.println(entry.getKey() + ": " + entry.getValue());
1596e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                    }
1597e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                    pw.decreaseIndent();
1598e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim
1599969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                    pw.println("packageSet:");
1600e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                    pw.increaseIndent();
1601969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                    for (String packageName : userState.packageSet) {
1602e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        pw.println(packageName);
1603e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                    }
1604e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                    pw.decreaseIndent();
1605e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim
1606e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                    pw.println("clientStateMap: ITvInputClient -> ClientState");
1607e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                    pw.increaseIndent();
1608e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                    for (Map.Entry<IBinder, ClientState> entry :
1609e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                            userState.clientStateMap.entrySet()) {
1610e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        ClientState client = entry.getValue();
1611e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        pw.println(entry.getKey() + ": " + client);
1612e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim
1613e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        pw.increaseIndent();
1614e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim
1615e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        pw.println("mSessionTokens:");
1616e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        pw.increaseIndent();
1617e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        for (IBinder token : client.mSessionTokens) {
1618e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                            pw.println("" + token);
1619e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        }
1620e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        pw.decreaseIndent();
1621e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim
1622e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        pw.println("mClientTokens: " + client.mClientToken);
1623e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        pw.println("mUserId: " + client.mUserId);
1624e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim
1625e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        pw.decreaseIndent();
1626e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                    }
1627e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                    pw.decreaseIndent();
1628e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim
1629187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                    pw.println("serviceStateMap: ComponentName -> ServiceState");
1630e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                    pw.increaseIndent();
1631187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                    for (Map.Entry<ComponentName, ServiceState> entry :
1632e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                            userState.serviceStateMap.entrySet()) {
1633e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        ServiceState service = entry.getValue();
1634e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        pw.println(entry.getKey() + ": " + service);
1635e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim
1636e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        pw.increaseIndent();
1637e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim
1638e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        pw.println("mClientTokens:");
1639e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        pw.increaseIndent();
1640e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        for (IBinder token : service.mClientTokens) {
1641e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                            pw.println("" + token);
1642e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        }
1643e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        pw.decreaseIndent();
1644e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim
1645e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        pw.println("mSessionTokens:");
1646e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        pw.increaseIndent();
1647e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        for (IBinder token : service.mSessionTokens) {
1648e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                            pw.println("" + token);
1649e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        }
1650e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        pw.decreaseIndent();
1651e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim
1652e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        pw.println("mService: " + service.mService);
1653e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        pw.println("mCallback: " + service.mCallback);
1654e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        pw.println("mBound: " + service.mBound);
1655e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        pw.println("mReconnecting: " + service.mReconnecting);
1656e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim
1657e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        pw.decreaseIndent();
1658e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                    }
1659e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                    pw.decreaseIndent();
1660e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim
1661e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                    pw.println("sessionStateMap: ITvInputSession -> SessionState");
1662e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                    pw.increaseIndent();
1663e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                    for (Map.Entry<IBinder, SessionState> entry :
1664e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                            userState.sessionStateMap.entrySet()) {
1665e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        SessionState session = entry.getValue();
1666e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        pw.println(entry.getKey() + ": " + session);
1667e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim
1668e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        pw.increaseIndent();
1669187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                        pw.println("mInfo: " + session.mInfo);
1670e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        pw.println("mClient: " + session.mClient);
1671e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        pw.println("mSeq: " + session.mSeq);
1672e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        pw.println("mCallingUid: " + session.mCallingUid);
1673e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        pw.println("mUserId: " + session.mUserId);
1674e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        pw.println("mSessionToken: " + session.mSessionToken);
1675e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        pw.println("mSession: " + session.mSession);
1676e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        pw.println("mLogUri: " + session.mLogUri);
1677bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                        pw.println("mHardwareSessionToken: " + session.mHardwareSessionToken);
1678e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        pw.decreaseIndent();
1679e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                    }
1680e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                    pw.decreaseIndent();
1681e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim
1682969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                    pw.println("callbackSet:");
1683969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                    pw.increaseIndent();
1684969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                    for (ITvInputManagerCallback callback : userState.callbackSet) {
1685969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                        pw.println(callback.toString());
1686969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                    }
1687969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                    pw.decreaseIndent();
1688969167dc05a6485a32d160895871cff46fd81884Wonsik Kim
1689956afc2ba79f50bb8025c6d334653e3c3419b480Ji-Hwan Lee                    pw.println("mainSessionToken: " + userState.mainSessionToken);
1690e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                    pw.decreaseIndent();
1691e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                }
1692e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim            }
1693e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim        }
16941a6b25eabcc1fb66e6e8d76f91fd413e18b793a9Sungsoo Lim
16951a6b25eabcc1fb66e6e8d76f91fd413e18b793a9Sungsoo Lim        private String encodeTuneParams(Bundle tuneParams) {
16961a6b25eabcc1fb66e6e8d76f91fd413e18b793a9Sungsoo Lim            StringBuilder builder = new StringBuilder();
16971a6b25eabcc1fb66e6e8d76f91fd413e18b793a9Sungsoo Lim            Set<String> keySet = tuneParams.keySet();
16981a6b25eabcc1fb66e6e8d76f91fd413e18b793a9Sungsoo Lim            Iterator<String> it = keySet.iterator();
16991a6b25eabcc1fb66e6e8d76f91fd413e18b793a9Sungsoo Lim            while (it.hasNext()) {
17001a6b25eabcc1fb66e6e8d76f91fd413e18b793a9Sungsoo Lim                String key = it.next();
17011a6b25eabcc1fb66e6e8d76f91fd413e18b793a9Sungsoo Lim                Object value = tuneParams.get(key);
17021a6b25eabcc1fb66e6e8d76f91fd413e18b793a9Sungsoo Lim                if (value == null) {
17031a6b25eabcc1fb66e6e8d76f91fd413e18b793a9Sungsoo Lim                    continue;
17041a6b25eabcc1fb66e6e8d76f91fd413e18b793a9Sungsoo Lim                }
17051a6b25eabcc1fb66e6e8d76f91fd413e18b793a9Sungsoo Lim                builder.append(replaceEscapeCharacters(key));
17061a6b25eabcc1fb66e6e8d76f91fd413e18b793a9Sungsoo Lim                builder.append("=");
17071a6b25eabcc1fb66e6e8d76f91fd413e18b793a9Sungsoo Lim                builder.append(replaceEscapeCharacters(value.toString()));
17081a6b25eabcc1fb66e6e8d76f91fd413e18b793a9Sungsoo Lim                if (it.hasNext()) {
17091a6b25eabcc1fb66e6e8d76f91fd413e18b793a9Sungsoo Lim                    builder.append(", ");
17101a6b25eabcc1fb66e6e8d76f91fd413e18b793a9Sungsoo Lim                }
17111a6b25eabcc1fb66e6e8d76f91fd413e18b793a9Sungsoo Lim            }
17121a6b25eabcc1fb66e6e8d76f91fd413e18b793a9Sungsoo Lim            return builder.toString();
17131a6b25eabcc1fb66e6e8d76f91fd413e18b793a9Sungsoo Lim        }
17141a6b25eabcc1fb66e6e8d76f91fd413e18b793a9Sungsoo Lim
17151a6b25eabcc1fb66e6e8d76f91fd413e18b793a9Sungsoo Lim        private String replaceEscapeCharacters(String src) {
17161a6b25eabcc1fb66e6e8d76f91fd413e18b793a9Sungsoo Lim            final char ESCAPE_CHARACTER = '%';
17171a6b25eabcc1fb66e6e8d76f91fd413e18b793a9Sungsoo Lim            final String ENCODING_TARGET_CHARACTERS = "%=,";
17181a6b25eabcc1fb66e6e8d76f91fd413e18b793a9Sungsoo Lim            StringBuilder builder = new StringBuilder();
17191a6b25eabcc1fb66e6e8d76f91fd413e18b793a9Sungsoo Lim            for (char ch : src.toCharArray()) {
17201a6b25eabcc1fb66e6e8d76f91fd413e18b793a9Sungsoo Lim                if (ENCODING_TARGET_CHARACTERS.indexOf(ch) >= 0) {
17211a6b25eabcc1fb66e6e8d76f91fd413e18b793a9Sungsoo Lim                    builder.append(ESCAPE_CHARACTER);
17221a6b25eabcc1fb66e6e8d76f91fd413e18b793a9Sungsoo Lim                }
17231a6b25eabcc1fb66e6e8d76f91fd413e18b793a9Sungsoo Lim                builder.append(ch);
17241a6b25eabcc1fb66e6e8d76f91fd413e18b793a9Sungsoo Lim            }
17251a6b25eabcc1fb66e6e8d76f91fd413e18b793a9Sungsoo Lim            return builder.toString();
17261a6b25eabcc1fb66e6e8d76f91fd413e18b793a9Sungsoo Lim        }
17273957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    }
17283957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
1729969167dc05a6485a32d160895871cff46fd81884Wonsik Kim    private static final class TvInputState {
1730969167dc05a6485a32d160895871cff46fd81884Wonsik Kim        // A TvInputInfo object which represents the TV input.
1731969167dc05a6485a32d160895871cff46fd81884Wonsik Kim        private TvInputInfo mInfo;
1732969167dc05a6485a32d160895871cff46fd81884Wonsik Kim
1733969167dc05a6485a32d160895871cff46fd81884Wonsik Kim        // The state of TV input. Connected by default.
1734969167dc05a6485a32d160895871cff46fd81884Wonsik Kim        private int mState = INPUT_STATE_CONNECTED;
1735969167dc05a6485a32d160895871cff46fd81884Wonsik Kim
1736969167dc05a6485a32d160895871cff46fd81884Wonsik Kim        @Override
1737969167dc05a6485a32d160895871cff46fd81884Wonsik Kim        public String toString() {
1738969167dc05a6485a32d160895871cff46fd81884Wonsik Kim            return "mInfo: " + mInfo + "; mState: " + mState;
1739969167dc05a6485a32d160895871cff46fd81884Wonsik Kim        }
1740969167dc05a6485a32d160895871cff46fd81884Wonsik Kim    }
1741969167dc05a6485a32d160895871cff46fd81884Wonsik Kim
17423957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    private static final class UserState {
1743969167dc05a6485a32d160895871cff46fd81884Wonsik Kim        // A mapping from the TV input id to its TvInputState.
1744969167dc05a6485a32d160895871cff46fd81884Wonsik Kim        private Map<String, TvInputState> inputMap = new HashMap<String, TvInputState>();
17453957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
1746969167dc05a6485a32d160895871cff46fd81884Wonsik Kim        // A set of all TV input packages.
1747969167dc05a6485a32d160895871cff46fd81884Wonsik Kim        private final Set<String> packageSet = new HashSet<String>();
17485c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo
17495c5b83fcd58d21c9ab7ac986bf84f604ec5bb4b5Sungsoo Lim        // A set of all TV content rating system xml uris.
17505c5b83fcd58d21c9ab7ac986bf84f604ec5bb4b5Sungsoo Lim        private final Set<Uri> ratingSystemXmlUriSet = new HashSet<Uri>();
17515c5b83fcd58d21c9ab7ac986bf84f604ec5bb4b5Sungsoo Lim
175272ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim        // A mapping from the token of a client to its state.
175372ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim        private final Map<IBinder, ClientState> clientStateMap =
175472ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim                new HashMap<IBinder, ClientState>();
175572ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim
17563957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        // A mapping from the name of a TV input service to its state.
1757187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim        private final Map<ComponentName, ServiceState> serviceStateMap =
1758187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                new HashMap<ComponentName, ServiceState>();
17593957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
17603957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        // A mapping from the token of a TV input session to its state.
17613957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        private final Map<IBinder, SessionState> sessionStateMap =
17623957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                new HashMap<IBinder, SessionState>();
1763969167dc05a6485a32d160895871cff46fd81884Wonsik Kim
1764969167dc05a6485a32d160895871cff46fd81884Wonsik Kim        // A set of callbacks.
1765969167dc05a6485a32d160895871cff46fd81884Wonsik Kim        private final Set<ITvInputManagerCallback> callbackSet =
1766969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                new HashSet<ITvInputManagerCallback>();
176779124a717c09f12c74d587d3977bf33ca37e6420Terry Heo
17684c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee        // The token of a "main" TV input session.
17694c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee        private IBinder mainSessionToken = null;
1770783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo
1771783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo        // Persistent data store for all internal settings maintained by the TV input manager
1772783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo        // service.
1773783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo        private final PersistentDataStore persistentDataStore;
1774783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo
1775783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo        private UserState(Context context, int userId) {
1776783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo            persistentDataStore = new PersistentDataStore(context, userId);
1777783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo        }
17783957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    }
17793957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
178072ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim    private final class ClientState implements IBinder.DeathRecipient {
178172ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim        private final List<IBinder> mSessionTokens = new ArrayList<IBinder>();
178272ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim
178372ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim        private IBinder mClientToken;
178472ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim        private final int mUserId;
178572ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim
178672ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim        ClientState(IBinder clientToken, int userId) {
178772ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim            mClientToken = clientToken;
178872ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim            mUserId = userId;
178972ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim        }
179072ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim
179172ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim        public boolean isEmpty() {
1792a65118e13b5ceb54454b48f67ea754a38a08f27aJi-Hwan Lee            return mSessionTokens.isEmpty();
179372ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim        }
179472ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim
179572ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim        @Override
179672ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim        public void binderDied() {
179772ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim            synchronized (mLock) {
179872ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim                UserState userState = getUserStateLocked(mUserId);
179972ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim                // DO NOT remove the client state of clientStateMap in this method. It will be
1800a65118e13b5ceb54454b48f67ea754a38a08f27aJi-Hwan Lee                // removed in releaseSessionLocked().
180172ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim                ClientState clientState = userState.clientStateMap.get(mClientToken);
180272ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim                if (clientState != null) {
180372ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim                    while (clientState.mSessionTokens.size() > 0) {
180472ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim                        releaseSessionLocked(
180572ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim                                clientState.mSessionTokens.get(0), Process.SYSTEM_UID, mUserId);
180672ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim                    }
180772ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim                }
180872ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim                mClientToken = null;
180972ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim            }
181072ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim        }
181172ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim    }
181272ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim
18133957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    private final class ServiceState {
181472ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim        private final List<IBinder> mClientTokens = new ArrayList<IBinder>();
1815d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim        private final List<IBinder> mSessionTokens = new ArrayList<IBinder>();
1816d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim        private final ServiceConnection mConnection;
18179e8ade2eb7ee835963473c9cf6faaf5423b0b048Ji-Hwan Lee        private final ComponentName mComponent;
1818187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim        private final boolean mIsHardware;
1819187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim        private final List<TvInputInfo> mInputList = new ArrayList<TvInputInfo>();
18203957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
1821d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim        private ITvInputService mService;
1822d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim        private ServiceCallback mCallback;
1823d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim        private boolean mBound;
18242b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim        private boolean mReconnecting;
18253957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
18269e8ade2eb7ee835963473c9cf6faaf5423b0b048Ji-Hwan Lee        private ServiceState(ComponentName component, int userId) {
18279e8ade2eb7ee835963473c9cf6faaf5423b0b048Ji-Hwan Lee            mComponent = component;
18289e8ade2eb7ee835963473c9cf6faaf5423b0b048Ji-Hwan Lee            mConnection = new InputServiceConnection(component, userId);
18299e8ade2eb7ee835963473c9cf6faaf5423b0b048Ji-Hwan Lee            mIsHardware = hasHardwarePermission(mContext.getPackageManager(), mComponent);
18303957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
18313957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    }
18323957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
18332b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim    private final class SessionState implements IBinder.DeathRecipient {
1834187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim        private final TvInputInfo mInfo;
1835d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim        private final ITvInputClient mClient;
1836d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim        private final int mSeq;
1837d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim        private final int mCallingUid;
18382b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim        private final int mUserId;
183972ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim        private final IBinder mSessionToken;
1840d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim        private ITvInputSession mSession;
1841d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim        private Uri mLogUri;
1842bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang        // Not null if this session represents an external device connected to a hardware TV input.
1843bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang        private IBinder mHardwareSessionToken;
18443957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
1845bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang        private SessionState(IBinder sessionToken, TvInputInfo info, ITvInputClient client,
1846bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                int seq, int callingUid, int userId) {
184772ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim            mSessionToken = sessionToken;
1848187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim            mInfo = info;
18492b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim            mClient = client;
18502b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim            mSeq = seq;
18512b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim            mCallingUid = callingUid;
18522b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim            mUserId = userId;
18532b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim        }
18542b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim
18552b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim        @Override
18562b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim        public void binderDied() {
18572b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim            synchronized (mLock) {
18582b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                mSession = null;
18592b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                if (mClient != null) {
18602b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                    try {
18612b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                        mClient.onSessionReleased(mSeq);
18622b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                    } catch(RemoteException e) {
18632b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                        Slog.e(TAG, "error in onSessionReleased", e);
18642b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                    }
18652b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                }
1866bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                // If there are any other sessions based on this session, they should be released.
1867bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                UserState userState = getUserStateLocked(mUserId);
1868bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                for (SessionState sessionState : userState.sessionStateMap.values()) {
1869bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                    if (mSession != null && mSession == sessionState.mHardwareSessionToken) {
1870bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                        try {
1871bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                            sessionState.mSession.release();
1872bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                        } catch (RemoteException e) {
1873bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                            Slog.e(TAG, "error in release", e);
1874bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                        }
1875bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                        try {
1876bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                            sessionState.mClient.onSessionReleased(sessionState.mSeq);
1877bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                        } catch (RemoteException e) {
1878bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                            Slog.e(TAG, "error in onSessionReleased", e);
1879bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                        }
1880bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                    }
1881bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                }
188272ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim                removeSessionStateLocked(mSessionToken, mUserId);
18832b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim            }
18843957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
18853957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    }
18863957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
18873957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    private final class InputServiceConnection implements ServiceConnection {
18889e8ade2eb7ee835963473c9cf6faaf5423b0b048Ji-Hwan Lee        private final ComponentName mComponent;
18893957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        private final int mUserId;
18903957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
18919e8ade2eb7ee835963473c9cf6faaf5423b0b048Ji-Hwan Lee        private InputServiceConnection(ComponentName component, int userId) {
18929e8ade2eb7ee835963473c9cf6faaf5423b0b048Ji-Hwan Lee            mComponent = component;
18933957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            mUserId = userId;
18943957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
18953957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
18963957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        @Override
18979e8ade2eb7ee835963473c9cf6faaf5423b0b048Ji-Hwan Lee        public void onServiceConnected(ComponentName component, IBinder service) {
18983957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            if (DEBUG) {
18999e8ade2eb7ee835963473c9cf6faaf5423b0b048Ji-Hwan Lee                Slog.d(TAG, "onServiceConnected(component=" + component + ")");
19003957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            }
19013957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            synchronized (mLock) {
1902969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                UserState userState = getUserStateLocked(mUserId);
19039e8ade2eb7ee835963473c9cf6faaf5423b0b048Ji-Hwan Lee                ServiceState serviceState = userState.serviceStateMap.get(mComponent);
1904d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim                serviceState.mService = ITvInputService.Stub.asInterface(service);
19053957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
19063957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                // Register a callback, if we need to.
1907187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                if (serviceState.mIsHardware && serviceState.mCallback == null) {
19089e8ade2eb7ee835963473c9cf6faaf5423b0b048Ji-Hwan Lee                    serviceState.mCallback = new ServiceCallback(mComponent, mUserId);
19093957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    try {
1910d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim                        serviceState.mService.registerCallback(serviceState.mCallback);
19113957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    } catch (RemoteException e) {
19129a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                        Slog.e(TAG, "error in registerCallback", e);
19133957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    }
19143957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                }
19153957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
19163957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                // And create sessions, if any.
1917d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim                for (IBinder sessionToken : serviceState.mSessionTokens) {
1918d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim                    createSessionInternalLocked(serviceState.mService, sessionToken, mUserId);
19193957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                }
1920969167dc05a6485a32d160895871cff46fd81884Wonsik Kim
1921187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                for (TvInputState inputState : userState.inputMap.values()) {
19229e8ade2eb7ee835963473c9cf6faaf5423b0b048Ji-Hwan Lee                    if (inputState.mInfo.getComponent().equals(component)
1923187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                            && inputState.mState != INPUT_STATE_DISCONNECTED) {
19248e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim                        notifyInputStateChangedLocked(userState, inputState.mInfo.getId(),
1925187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                                inputState.mState, null);
1926187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                    }
1927187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                }
1928187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim
1929187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                if (serviceState.mIsHardware) {
19304f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                    List<TvInputHardwareInfo> hardwareInfoList =
19314f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                            mTvInputHardwareManager.getHardwareList();
1932187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                    for (TvInputHardwareInfo hardwareInfo : hardwareInfoList) {
1933187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                        try {
1934187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                            serviceState.mService.notifyHardwareAdded(hardwareInfo);
1935187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                        } catch (RemoteException e) {
1936187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                            Slog.e(TAG, "error in notifyHardwareAdded", e);
1937187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                        }
1938187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                    }
1939187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim
1940546c635ad9a26421fbdf54efa765b5ab0a63c191Jae Seo                    List<HdmiDeviceInfo> deviceInfoList =
1941546c635ad9a26421fbdf54efa765b5ab0a63c191Jae Seo                            mTvInputHardwareManager.getHdmiDeviceList();
1942546c635ad9a26421fbdf54efa765b5ab0a63c191Jae Seo                    for (HdmiDeviceInfo deviceInfo : deviceInfoList) {
19434f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                        try {
1944546c635ad9a26421fbdf54efa765b5ab0a63c191Jae Seo                            serviceState.mService.notifyHdmiDeviceAdded(deviceInfo);
19454f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                        } catch (RemoteException e) {
1946546c635ad9a26421fbdf54efa765b5ab0a63c191Jae Seo                            Slog.e(TAG, "error in notifyHdmiDeviceAdded", e);
19474f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                        }
19484f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                    }
1949969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                }
19503957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            }
19513957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
19523957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
19533957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        @Override
19549e8ade2eb7ee835963473c9cf6faaf5423b0b048Ji-Hwan Lee        public void onServiceDisconnected(ComponentName component) {
19553957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            if (DEBUG) {
19569e8ade2eb7ee835963473c9cf6faaf5423b0b048Ji-Hwan Lee                Slog.d(TAG, "onServiceDisconnected(component=" + component + ")");
19573957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            }
19589e8ade2eb7ee835963473c9cf6faaf5423b0b048Ji-Hwan Lee            if (!mComponent.equals(component)) {
19592b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                throw new IllegalArgumentException("Mismatched ComponentName: "
19609e8ade2eb7ee835963473c9cf6faaf5423b0b048Ji-Hwan Lee                        + mComponent + " (expected), " + component + " (actual).");
19612b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim            }
19622b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim            synchronized (mLock) {
19632b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                UserState userState = getUserStateLocked(mUserId);
19649e8ade2eb7ee835963473c9cf6faaf5423b0b048Ji-Hwan Lee                ServiceState serviceState = userState.serviceStateMap.get(mComponent);
19652b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                if (serviceState != null) {
19662b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                    serviceState.mReconnecting = true;
19672b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                    serviceState.mBound = false;
19682b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                    serviceState.mService = null;
19692b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                    serviceState.mCallback = null;
19702b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim
19712b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                    // Send null tokens for not finishing create session events.
19722b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                    for (IBinder sessionToken : serviceState.mSessionTokens) {
19732b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                        SessionState sessionState = userState.sessionStateMap.get(sessionToken);
19742b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                        if (sessionState.mSession == null) {
19752b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                            removeSessionStateLocked(sessionToken, sessionState.mUserId);
19762b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                            sendSessionTokenToClientLocked(sessionState.mClient,
1977187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                                    sessionState.mInfo.getId(), null, null, sessionState.mSeq);
19782b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                        }
19792b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                    }
19802b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim
1981187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                    for (TvInputState inputState : userState.inputMap.values()) {
19829e8ade2eb7ee835963473c9cf6faaf5423b0b048Ji-Hwan Lee                        if (inputState.mInfo.getComponent().equals(component)) {
1983bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                            notifyInputStateChangedLocked(userState, inputState.mInfo.getId(),
1984187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                                    INPUT_STATE_DISCONNECTED, null);
1985187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                        }
1986187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                    }
19879e8ade2eb7ee835963473c9cf6faaf5423b0b048Ji-Hwan Lee                    updateServiceConnectionLocked(mComponent, mUserId);
19882b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                }
19892b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim            }
19903957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
19913957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    }
19923957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
19933957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    private final class ServiceCallback extends ITvInputServiceCallback.Stub {
19949e8ade2eb7ee835963473c9cf6faaf5423b0b048Ji-Hwan Lee        private final ComponentName mComponent;
19953957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        private final int mUserId;
19963957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
19979e8ade2eb7ee835963473c9cf6faaf5423b0b048Ji-Hwan Lee        ServiceCallback(ComponentName component, int userId) {
19989e8ade2eb7ee835963473c9cf6faaf5423b0b048Ji-Hwan Lee            mComponent = component;
19993957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            mUserId = userId;
20003957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
20013957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
20024f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee        private void ensureHardwarePermission() {
20034f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee            if (mContext.checkCallingPermission(android.Manifest.permission.TV_INPUT_HARDWARE)
20044f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                    != PackageManager.PERMISSION_GRANTED) {
20054f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                throw new SecurityException("The caller does not have hardware permission");
20064f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee            }
20074f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee        }
20084f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee
20094f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee        private void ensureValidInput(TvInputInfo inputInfo) {
20109e8ade2eb7ee835963473c9cf6faaf5423b0b048Ji-Hwan Lee            if (inputInfo.getId() == null || !mComponent.equals(inputInfo.getComponent())) {
20114f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                throw new IllegalArgumentException("Invalid TvInputInfo");
20124f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee            }
20134f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee        }
20144f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee
20154f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee        private void addTvInputLocked(TvInputInfo inputInfo) {
20169e8ade2eb7ee835963473c9cf6faaf5423b0b048Ji-Hwan Lee            ServiceState serviceState = getServiceStateLocked(mComponent, mUserId);
20174f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee            serviceState.mInputList.add(inputInfo);
20184f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee            buildTvInputListLocked(mUserId);
20194f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee        }
20204f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee
20213957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        @Override
20224f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee        public void addHardwareTvInput(int deviceId, TvInputInfo inputInfo) {
20234f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee            ensureHardwarePermission();
20244f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee            ensureValidInput(inputInfo);
2025187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim            synchronized (mLock) {
20264f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                mTvInputHardwareManager.addHardwareTvInput(deviceId, inputInfo);
20274f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                addTvInputLocked(inputInfo);
20284f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee            }
20294f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee        }
2030187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim
20314f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee        @Override
2032546c635ad9a26421fbdf54efa765b5ab0a63c191Jae Seo        public void addHdmiTvInput(int logicalAddress, TvInputInfo inputInfo) {
20334f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee            ensureHardwarePermission();
20344f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee            ensureValidInput(inputInfo);
20354f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee            synchronized (mLock) {
2036546c635ad9a26421fbdf54efa765b5ab0a63c191Jae Seo                mTvInputHardwareManager.addHdmiTvInput(logicalAddress, inputInfo);
20374f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                addTvInputLocked(inputInfo);
20383957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            }
2039187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim        }
2040187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim
2041187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim        @Override
2042187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim        public void removeTvInput(String inputId) {
20434f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee            ensureHardwarePermission();
20443957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            synchronized (mLock) {
20459e8ade2eb7ee835963473c9cf6faaf5423b0b048Ji-Hwan Lee                ServiceState serviceState = getServiceStateLocked(mComponent, mUserId);
2046187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                boolean removed = false;
2047187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                for (Iterator<TvInputInfo> it = serviceState.mInputList.iterator();
2048187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                        it.hasNext(); ) {
2049187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                    if (it.next().getId().equals(inputId)) {
2050187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                        it.remove();
2051187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                        removed = true;
2052187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                        break;
2053187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                    }
2054187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                }
2055187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                if (removed) {
2056187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                    buildTvInputListLocked(mUserId);
20574f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                    mTvInputHardwareManager.removeTvInput(inputId);
2058187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                } else {
2059187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                    Slog.e(TAG, "TvInputInfo with inputId=" + inputId + " not found.");
2060187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                }
20613957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            }
20623957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
20633957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    }
206431dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo
206531dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo    private final class LogHandler extends Handler {
206631dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo        private static final int MSG_OPEN_ENTRY = 1;
206731dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo        private static final int MSG_UPDATE_ENTRY = 2;
206831dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo        private static final int MSG_CLOSE_ENTRY = 3;
206931dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo
207031dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo        public LogHandler(Looper looper) {
207131dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo            super(looper);
207231dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo        }
207331dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo
207431dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo        @Override
207531dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo        public void handleMessage(Message msg) {
207631dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo            switch (msg.what) {
207731dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                case MSG_OPEN_ENTRY: {
207831dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                    SomeArgs args = (SomeArgs) msg.obj;
207931dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                    Uri uri = (Uri) args.arg1;
208031dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                    long channelId = (long) args.arg2;
208131dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                    long time = (long) args.arg3;
2082579befecb248162021929ab58ffd23f1724cc6beJae Seo                    SessionState sessionState = (SessionState) args.arg4;
2083579befecb248162021929ab58ffd23f1724cc6beJae Seo                    onOpenEntry(uri, channelId, time, sessionState);
208431dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                    args.recycle();
208531dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                    return;
208631dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                }
208731dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                case MSG_UPDATE_ENTRY: {
208831dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                    SomeArgs args = (SomeArgs) msg.obj;
208931dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                    Uri uri = (Uri) args.arg1;
209031dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                    long channelId = (long) args.arg2;
209131dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                    long time = (long) args.arg3;
2092579befecb248162021929ab58ffd23f1724cc6beJae Seo                    SessionState sessionState = (SessionState) args.arg4;
2093579befecb248162021929ab58ffd23f1724cc6beJae Seo                    onUpdateEntry(uri, channelId, time, sessionState);
209431dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                    args.recycle();
209531dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                    return;
209631dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                }
209731dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                case MSG_CLOSE_ENTRY: {
209831dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                    SomeArgs args = (SomeArgs) msg.obj;
209931dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                    Uri uri = (Uri) args.arg1;
210031dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                    long time = (long) args.arg2;
210131dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                    onCloseEntry(uri, time);
210231dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                    args.recycle();
210331dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                    return;
210431dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                }
210531dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                default: {
21066a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                    Slog.w(TAG, "Unhandled message code: " + msg.what);
210731dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                    return;
210831dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                }
210931dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo            }
211031dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo        }
211131dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo
2112579befecb248162021929ab58ffd23f1724cc6beJae Seo        private void onOpenEntry(Uri logUri, long channelId, long watchStarttime,
2113579befecb248162021929ab58ffd23f1724cc6beJae Seo                SessionState sessionState) {
2114579befecb248162021929ab58ffd23f1724cc6beJae Seo            if (!isChannelSearchable(channelId)) {
2115579befecb248162021929ab58ffd23f1724cc6beJae Seo                // Do not log anything about non-searchable channels.
2116579befecb248162021929ab58ffd23f1724cc6beJae Seo                synchronized (mLock) {
2117579befecb248162021929ab58ffd23f1724cc6beJae Seo                    sessionState.mLogUri = null;
2118579befecb248162021929ab58ffd23f1724cc6beJae Seo                }
2119579befecb248162021929ab58ffd23f1724cc6beJae Seo                mContentResolver.delete(logUri, null, null);
2120579befecb248162021929ab58ffd23f1724cc6beJae Seo                return;
2121579befecb248162021929ab58ffd23f1724cc6beJae Seo            }
2122579befecb248162021929ab58ffd23f1724cc6beJae Seo
212331dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo            String[] projection = {
2124f5cd0b388ac31104e014f9193d06080851a09e18Jae Seo                    TvContract.Programs.COLUMN_TITLE,
2125f5cd0b388ac31104e014f9193d06080851a09e18Jae Seo                    TvContract.Programs.COLUMN_START_TIME_UTC_MILLIS,
2126f5cd0b388ac31104e014f9193d06080851a09e18Jae Seo                    TvContract.Programs.COLUMN_END_TIME_UTC_MILLIS,
2127bd23fa0ba1460a8d5194fd7c700030bf9c3f6fcbJae Seo                    TvContract.Programs.COLUMN_SHORT_DESCRIPTION
212831dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo            };
2129f5cd0b388ac31104e014f9193d06080851a09e18Jae Seo            String selection = TvContract.Programs.COLUMN_CHANNEL_ID + "=? AND "
2130f5cd0b388ac31104e014f9193d06080851a09e18Jae Seo                    + TvContract.Programs.COLUMN_START_TIME_UTC_MILLIS + "<=? AND "
2131f5cd0b388ac31104e014f9193d06080851a09e18Jae Seo                    + TvContract.Programs.COLUMN_END_TIME_UTC_MILLIS + ">?";
213231dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo            String[] selectionArgs = {
213331dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                    String.valueOf(channelId),
213431dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                    String.valueOf(watchStarttime),
213531dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                    String.valueOf(watchStarttime)
213631dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo            };
2137f5cd0b388ac31104e014f9193d06080851a09e18Jae Seo            String sortOrder = TvContract.Programs.COLUMN_START_TIME_UTC_MILLIS + " ASC";
213831dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo            Cursor cursor = null;
213931dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo            try {
214031dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                cursor = mContentResolver.query(TvContract.Programs.CONTENT_URI, projection,
214131dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                        selection, selectionArgs, sortOrder);
214231dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                if (cursor != null && cursor.moveToNext()) {
214331dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                    ContentValues values = new ContentValues();
2144f5cd0b388ac31104e014f9193d06080851a09e18Jae Seo                    values.put(TvContract.WatchedPrograms.COLUMN_TITLE, cursor.getString(0));
2145f5cd0b388ac31104e014f9193d06080851a09e18Jae Seo                    values.put(TvContract.WatchedPrograms.COLUMN_START_TIME_UTC_MILLIS,
2146f5cd0b388ac31104e014f9193d06080851a09e18Jae Seo                            cursor.getLong(1));
214731dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                    long endTime = cursor.getLong(2);
2148f5cd0b388ac31104e014f9193d06080851a09e18Jae Seo                    values.put(TvContract.WatchedPrograms.COLUMN_END_TIME_UTC_MILLIS, endTime);
2149f5cd0b388ac31104e014f9193d06080851a09e18Jae Seo                    values.put(TvContract.WatchedPrograms.COLUMN_DESCRIPTION, cursor.getString(3));
2150579befecb248162021929ab58ffd23f1724cc6beJae Seo                    mContentResolver.update(logUri, values, null, null);
215131dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo
215231dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                    // Schedule an update when the current program ends.
215331dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                    SomeArgs args = SomeArgs.obtain();
2154579befecb248162021929ab58ffd23f1724cc6beJae Seo                    args.arg1 = logUri;
215531dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                    args.arg2 = channelId;
215631dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                    args.arg3 = endTime;
21578d4ded0058de5c573ccf79c4596bf5eb1b14fad3Chulwoo Lee                    args.arg4 = sessionState;
215831dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                    Message msg = obtainMessage(LogHandler.MSG_UPDATE_ENTRY, args);
215931dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                    sendMessageDelayed(msg, endTime - System.currentTimeMillis());
216031dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                }
216131dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo            } finally {
216231dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                if (cursor != null) {
216331dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                    cursor.close();
216431dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                }
216531dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo            }
216631dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo        }
216731dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo
2168579befecb248162021929ab58ffd23f1724cc6beJae Seo        private void onUpdateEntry(Uri uri, long channelId, long time, SessionState sessionState) {
216931dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo            String[] projection = {
21708d4ded0058de5c573ccf79c4596bf5eb1b14fad3Chulwoo Lee                    TvContract.WatchedPrograms.COLUMN_WATCH_END_TIME_UTC_MILLIS
217131dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo            };
217231dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo            Cursor cursor = null;
217331dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo            try {
217431dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                cursor = mContentResolver.query(uri, projection, null, null, null);
217531dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                if (cursor != null && cursor.moveToNext()) {
21768d4ded0058de5c573ccf79c4596bf5eb1b14fad3Chulwoo Lee                    long watchEndTime = cursor.getLong(0);
217731dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                    // Do nothing if the current log entry is already closed.
217831dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                    if (watchEndTime > 0) {
217931dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                        return;
218031dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                    }
218131dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo
21828d4ded0058de5c573ccf79c4596bf5eb1b14fad3Chulwoo Lee                    // Update the watch end time for the current log entry.
218331dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                    ContentValues values = new ContentValues();
2184f5cd0b388ac31104e014f9193d06080851a09e18Jae Seo                    values.put(TvContract.WatchedPrograms.COLUMN_WATCH_END_TIME_UTC_MILLIS, time);
21858d4ded0058de5c573ccf79c4596bf5eb1b14fad3Chulwoo Lee                    int c = mContentResolver.update(uri, values, null, null);
21868d4ded0058de5c573ccf79c4596bf5eb1b14fad3Chulwoo Lee                } else {
21878d4ded0058de5c573ccf79c4596bf5eb1b14fad3Chulwoo Lee                    // The record has been deleted.
21888d4ded0058de5c573ccf79c4596bf5eb1b14fad3Chulwoo Lee                    synchronized (mLock) {
21898d4ded0058de5c573ccf79c4596bf5eb1b14fad3Chulwoo Lee                        if (!uri.equals(sessionState.mLogUri)) {
21908d4ded0058de5c573ccf79c4596bf5eb1b14fad3Chulwoo Lee                            // If the deleted record is not for the current channel, do not re-open
21918d4ded0058de5c573ccf79c4596bf5eb1b14fad3Chulwoo Lee                            // a log entry for the next program.
21928d4ded0058de5c573ccf79c4596bf5eb1b14fad3Chulwoo Lee                            return;
21938d4ded0058de5c573ccf79c4596bf5eb1b14fad3Chulwoo Lee                        }
21948d4ded0058de5c573ccf79c4596bf5eb1b14fad3Chulwoo Lee                    }
21958d4ded0058de5c573ccf79c4596bf5eb1b14fad3Chulwoo Lee                }
21968d4ded0058de5c573ccf79c4596bf5eb1b14fad3Chulwoo Lee                if (cursor != null) {
21978d4ded0058de5c573ccf79c4596bf5eb1b14fad3Chulwoo Lee                    cursor.close();
21988d4ded0058de5c573ccf79c4596bf5eb1b14fad3Chulwoo Lee                    cursor = null;
21998d4ded0058de5c573ccf79c4596bf5eb1b14fad3Chulwoo Lee                }
22008d4ded0058de5c573ccf79c4596bf5eb1b14fad3Chulwoo Lee
22018d4ded0058de5c573ccf79c4596bf5eb1b14fad3Chulwoo Lee                // The current program has just ended. Create a new log entry for the next program.
22028d4ded0058de5c573ccf79c4596bf5eb1b14fad3Chulwoo Lee                uri = ContentUris.withAppendedId(TvContract.Channels.CONTENT_URI, channelId);
22038d4ded0058de5c573ccf79c4596bf5eb1b14fad3Chulwoo Lee                projection = new String[] {
22048d4ded0058de5c573ccf79c4596bf5eb1b14fad3Chulwoo Lee                        TvContract.Channels.COLUMN_PACKAGE_NAME
22058d4ded0058de5c573ccf79c4596bf5eb1b14fad3Chulwoo Lee                };
22068d4ded0058de5c573ccf79c4596bf5eb1b14fad3Chulwoo Lee                cursor = mContentResolver.query(uri, projection, null, null, null);
22078d4ded0058de5c573ccf79c4596bf5eb1b14fad3Chulwoo Lee                if (cursor != null && cursor.moveToNext()) {
22088d4ded0058de5c573ccf79c4596bf5eb1b14fad3Chulwoo Lee                    ContentValues values = new ContentValues();
22098d4ded0058de5c573ccf79c4596bf5eb1b14fad3Chulwoo Lee                    values.put(TvContract.WatchedPrograms.COLUMN_PACKAGE_NAME, cursor.getString(0));
22108d4ded0058de5c573ccf79c4596bf5eb1b14fad3Chulwoo Lee                    values.put(TvContract.WatchedPrograms.COLUMN_WATCH_START_TIME_UTC_MILLIS, time);
22118d4ded0058de5c573ccf79c4596bf5eb1b14fad3Chulwoo Lee                    values.put(TvContract.WatchedPrograms.COLUMN_WATCH_END_TIME_UTC_MILLIS, 0);
2212f5cd0b388ac31104e014f9193d06080851a09e18Jae Seo                    values.put(TvContract.WatchedPrograms.COLUMN_CHANNEL_ID, channelId);
22138d4ded0058de5c573ccf79c4596bf5eb1b14fad3Chulwoo Lee                    Uri newUri = mContentResolver.insert(TvContract.WatchedPrograms.CONTENT_URI,
22148d4ded0058de5c573ccf79c4596bf5eb1b14fad3Chulwoo Lee                            values);
22158d4ded0058de5c573ccf79c4596bf5eb1b14fad3Chulwoo Lee
22168d4ded0058de5c573ccf79c4596bf5eb1b14fad3Chulwoo Lee                    synchronized (mLock) {
22178d4ded0058de5c573ccf79c4596bf5eb1b14fad3Chulwoo Lee                        sessionState.mLogUri = newUri;
22188d4ded0058de5c573ccf79c4596bf5eb1b14fad3Chulwoo Lee                    }
22198d4ded0058de5c573ccf79c4596bf5eb1b14fad3Chulwoo Lee
22208d4ded0058de5c573ccf79c4596bf5eb1b14fad3Chulwoo Lee                    // Re-open the current log entry with the next program information.
22218d4ded0058de5c573ccf79c4596bf5eb1b14fad3Chulwoo Lee                    onOpenEntry(newUri, channelId, time, sessionState);
222231dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                }
222331dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo            } finally {
222431dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                if (cursor != null) {
222531dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                    cursor.close();
222631dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                }
222731dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo            }
222831dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo        }
222931dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo
223031dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo        private void onCloseEntry(Uri uri, long watchEndTime) {
223131dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo            ContentValues values = new ContentValues();
2232f5cd0b388ac31104e014f9193d06080851a09e18Jae Seo            values.put(TvContract.WatchedPrograms.COLUMN_WATCH_END_TIME_UTC_MILLIS, watchEndTime);
223331dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo            mContentResolver.update(uri, values, null, null);
223431dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo        }
2235579befecb248162021929ab58ffd23f1724cc6beJae Seo
2236579befecb248162021929ab58ffd23f1724cc6beJae Seo        private boolean isChannelSearchable(long channelId) {
2237579befecb248162021929ab58ffd23f1724cc6beJae Seo            String[] projection = { TvContract.Channels.COLUMN_SEARCHABLE };
2238579befecb248162021929ab58ffd23f1724cc6beJae Seo            String selection = TvContract.Channels._ID + "=?";
2239579befecb248162021929ab58ffd23f1724cc6beJae Seo            String[] selectionArgs = { String.valueOf(channelId) };
2240579befecb248162021929ab58ffd23f1724cc6beJae Seo            Cursor cursor = null;
2241579befecb248162021929ab58ffd23f1724cc6beJae Seo            try {
2242579befecb248162021929ab58ffd23f1724cc6beJae Seo                cursor = mContentResolver.query(TvContract.Channels.CONTENT_URI, projection,
2243579befecb248162021929ab58ffd23f1724cc6beJae Seo                        selection, selectionArgs, null);
2244579befecb248162021929ab58ffd23f1724cc6beJae Seo                if (cursor != null && cursor.moveToNext()) {
2245579befecb248162021929ab58ffd23f1724cc6beJae Seo                    return cursor.getLong(0) == 1 ? true : false;
2246579befecb248162021929ab58ffd23f1724cc6beJae Seo                }
2247579befecb248162021929ab58ffd23f1724cc6beJae Seo            } finally {
2248579befecb248162021929ab58ffd23f1724cc6beJae Seo                if (cursor != null) {
2249579befecb248162021929ab58ffd23f1724cc6beJae Seo                    cursor.close();
2250579befecb248162021929ab58ffd23f1724cc6beJae Seo                }
2251579befecb248162021929ab58ffd23f1724cc6beJae Seo            }
2252579befecb248162021929ab58ffd23f1724cc6beJae Seo            // Unless explicitly specified non-searchable, by default the channel is searchable.
2253579befecb248162021929ab58ffd23f1724cc6beJae Seo            return true;
2254579befecb248162021929ab58ffd23f1724cc6beJae Seo        }
225531dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo    }
2256969167dc05a6485a32d160895871cff46fd81884Wonsik Kim
2257187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim    final class HardwareListener implements TvInputHardwareManager.Listener {
2258187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim        @Override
2259187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim        public void onStateChanged(String inputId, int state) {
2260969167dc05a6485a32d160895871cff46fd81884Wonsik Kim            synchronized (mLock) {
2261969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                setStateLocked(inputId, state, mCurrentUserId);
2262969167dc05a6485a32d160895871cff46fd81884Wonsik Kim            }
2263969167dc05a6485a32d160895871cff46fd81884Wonsik Kim        }
2264187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim
2265187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim        @Override
2266187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim        public void onHardwareDeviceAdded(TvInputHardwareInfo info) {
2267187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim            synchronized (mLock) {
2268187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                UserState userState = getUserStateLocked(mCurrentUserId);
2269187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                // Broadcast the event to all hardware inputs.
2270187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                for (ServiceState serviceState : userState.serviceStateMap.values()) {
2271187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                    if (!serviceState.mIsHardware || serviceState.mService == null) continue;
2272187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                    try {
2273187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                        serviceState.mService.notifyHardwareAdded(info);
2274187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                    } catch (RemoteException e) {
2275187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                        Slog.e(TAG, "error in notifyHardwareAdded", e);
2276187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                    }
2277187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                }
2278187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim            }
2279187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim        }
2280187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim
2281187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim        @Override
22824f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee        public void onHardwareDeviceRemoved(TvInputHardwareInfo info) {
2283187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim            synchronized (mLock) {
2284187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                UserState userState = getUserStateLocked(mCurrentUserId);
2285187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                // Broadcast the event to all hardware inputs.
2286187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                for (ServiceState serviceState : userState.serviceStateMap.values()) {
2287187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                    if (!serviceState.mIsHardware || serviceState.mService == null) continue;
2288187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                    try {
22894f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                        serviceState.mService.notifyHardwareRemoved(info);
2290187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                    } catch (RemoteException e) {
2291187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                        Slog.e(TAG, "error in notifyHardwareRemoved", e);
2292187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                    }
2293187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                }
2294187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim            }
2295187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim        }
2296187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim
2297187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim        @Override
2298546c635ad9a26421fbdf54efa765b5ab0a63c191Jae Seo        public void onHdmiDeviceAdded(HdmiDeviceInfo deviceInfo) {
2299187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim            synchronized (mLock) {
23004f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                UserState userState = getUserStateLocked(mCurrentUserId);
23014f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                // Broadcast the event to all hardware inputs.
23024f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                for (ServiceState serviceState : userState.serviceStateMap.values()) {
23034f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                    if (!serviceState.mIsHardware || serviceState.mService == null) continue;
23044f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                    try {
2305546c635ad9a26421fbdf54efa765b5ab0a63c191Jae Seo                        serviceState.mService.notifyHdmiDeviceAdded(deviceInfo);
23064f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                    } catch (RemoteException e) {
2307546c635ad9a26421fbdf54efa765b5ab0a63c191Jae Seo                        Slog.e(TAG, "error in notifyHdmiDeviceAdded", e);
23084f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                    }
23094f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                }
2310187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim            }
2311187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim        }
2312187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim
2313187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim        @Override
2314546c635ad9a26421fbdf54efa765b5ab0a63c191Jae Seo        public void onHdmiDeviceRemoved(HdmiDeviceInfo deviceInfo) {
2315187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim            synchronized (mLock) {
23164f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                UserState userState = getUserStateLocked(mCurrentUserId);
23174f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                // Broadcast the event to all hardware inputs.
23184f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                for (ServiceState serviceState : userState.serviceStateMap.values()) {
23194f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                    if (!serviceState.mIsHardware || serviceState.mService == null) continue;
23204f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                    try {
2321546c635ad9a26421fbdf54efa765b5ab0a63c191Jae Seo                        serviceState.mService.notifyHdmiDeviceRemoved(deviceInfo);
23224f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                    } catch (RemoteException e) {
2323546c635ad9a26421fbdf54efa765b5ab0a63c191Jae Seo                        Slog.e(TAG, "error in notifyHdmiDeviceRemoved", e);
23244f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                    }
23254f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                }
2326187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim            }
2327187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim        }
2328969167dc05a6485a32d160895871cff46fd81884Wonsik Kim    }
23293957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo}
2330