TvInputManagerService.java revision 9c165d6e9a2f085fbdc87b9221f2d52d851b2652
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;
20e92f857d50d7259a4cf7ef5b88309e098338c9c1Wonsik Kimimport static android.media.tv.TvInputManager.INPUT_STATE_CONNECTED_STANDBY;
21969167dc05a6485a32d160895871cff46fd81884Wonsik Kimimport static android.media.tv.TvInputManager.INPUT_STATE_DISCONNECTED;
22969167dc05a6485a32d160895871cff46fd81884Wonsik Kim
233957091ba8f08c02b5e781098cb955a5f697a1ffJae Seoimport android.app.ActivityManager;
243957091ba8f08c02b5e781098cb955a5f697a1ffJae Seoimport android.content.BroadcastReceiver;
253957091ba8f08c02b5e781098cb955a5f697a1ffJae Seoimport android.content.ComponentName;
265c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seoimport android.content.ContentProviderOperation;
275c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seoimport android.content.ContentProviderResult;
2831dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seoimport android.content.ContentResolver;
2931dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seoimport android.content.ContentUris;
3031dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seoimport android.content.ContentValues;
313957091ba8f08c02b5e781098cb955a5f697a1ffJae Seoimport android.content.Context;
323957091ba8f08c02b5e781098cb955a5f697a1ffJae Seoimport android.content.Intent;
333957091ba8f08c02b5e781098cb955a5f697a1ffJae Seoimport android.content.IntentFilter;
345c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seoimport android.content.OperationApplicationException;
353957091ba8f08c02b5e781098cb955a5f697a1ffJae Seoimport android.content.ServiceConnection;
369c165d6e9a2f085fbdc87b9221f2d52d851b2652Jae Seoimport android.content.pm.ActivityInfo;
373957091ba8f08c02b5e781098cb955a5f697a1ffJae Seoimport android.content.pm.PackageManager;
383957091ba8f08c02b5e781098cb955a5f697a1ffJae Seoimport android.content.pm.ResolveInfo;
393957091ba8f08c02b5e781098cb955a5f697a1ffJae Seoimport android.content.pm.ServiceInfo;
409a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Choimport android.graphics.Rect;
41e92f857d50d7259a4cf7ef5b88309e098338c9c1Wonsik Kimimport android.hardware.hdmi.HdmiControlManager;
4261f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jangimport android.hardware.hdmi.HdmiDeviceInfo;
43d5cc4a281e7ce29d1e8687ff3394b57a3a549260Jae Seoimport android.media.tv.ITvInputClient;
44d5cc4a281e7ce29d1e8687ff3394b57a3a549260Jae Seoimport android.media.tv.ITvInputHardware;
45d5cc4a281e7ce29d1e8687ff3394b57a3a549260Jae Seoimport android.media.tv.ITvInputHardwareCallback;
46d5cc4a281e7ce29d1e8687ff3394b57a3a549260Jae Seoimport android.media.tv.ITvInputManager;
47969167dc05a6485a32d160895871cff46fd81884Wonsik Kimimport android.media.tv.ITvInputManagerCallback;
48d5cc4a281e7ce29d1e8687ff3394b57a3a549260Jae Seoimport android.media.tv.ITvInputService;
49d5cc4a281e7ce29d1e8687ff3394b57a3a549260Jae Seoimport android.media.tv.ITvInputServiceCallback;
50d5cc4a281e7ce29d1e8687ff3394b57a3a549260Jae Seoimport android.media.tv.ITvInputSession;
51d5cc4a281e7ce29d1e8687ff3394b57a3a549260Jae Seoimport android.media.tv.ITvInputSessionCallback;
52783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seoimport android.media.tv.TvContentRating;
539c165d6e9a2f085fbdc87b9221f2d52d851b2652Jae Seoimport android.media.tv.TvContentRatingSystemInfo;
54d5cc4a281e7ce29d1e8687ff3394b57a3a549260Jae Seoimport android.media.tv.TvContract;
55d5cc4a281e7ce29d1e8687ff3394b57a3a549260Jae Seoimport android.media.tv.TvInputHardwareInfo;
56d5cc4a281e7ce29d1e8687ff3394b57a3a549260Jae Seoimport android.media.tv.TvInputInfo;
579c165d6e9a2f085fbdc87b9221f2d52d851b2652Jae Seoimport android.media.tv.TvInputManager;
58d5cc4a281e7ce29d1e8687ff3394b57a3a549260Jae Seoimport android.media.tv.TvInputService;
59c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heoimport android.media.tv.TvStreamConfig;
601f213914c45c23c653f721690da2ce0718e63139Dongwon Kangimport android.media.tv.TvTrackInfo;
613957091ba8f08c02b5e781098cb955a5f697a1ffJae Seoimport android.net.Uri;
623957091ba8f08c02b5e781098cb955a5f697a1ffJae Seoimport android.os.Binder;
63832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Choimport android.os.Bundle;
6431dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seoimport android.os.Handler;
653957091ba8f08c02b5e781098cb955a5f697a1ffJae Seoimport android.os.IBinder;
6631dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seoimport android.os.Looper;
6731dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seoimport android.os.Message;
683957091ba8f08c02b5e781098cb955a5f697a1ffJae Seoimport android.os.Process;
693957091ba8f08c02b5e781098cb955a5f697a1ffJae Seoimport android.os.RemoteException;
703957091ba8f08c02b5e781098cb955a5f697a1ffJae Seoimport android.os.UserHandle;
719a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Choimport android.util.Slog;
723957091ba8f08c02b5e781098cb955a5f697a1ffJae Seoimport android.util.SparseArray;
736a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seoimport android.view.InputChannel;
743957091ba8f08c02b5e781098cb955a5f697a1ffJae Seoimport android.view.Surface;
753957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
763957091ba8f08c02b5e781098cb955a5f697a1ffJae Seoimport com.android.internal.content.PackageMonitor;
7731dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seoimport com.android.internal.os.SomeArgs;
78e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kimimport com.android.internal.util.IndentingPrintWriter;
7931dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seoimport com.android.server.IoThread;
803957091ba8f08c02b5e781098cb955a5f697a1ffJae Seoimport com.android.server.SystemService;
813957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
82e7bb7d6bb2257c24076f5a4b9f536f90a6637f58Chulwoo Leeimport org.xmlpull.v1.XmlPullParserException;
83e7bb7d6bb2257c24076f5a4b9f536f90a6637f58Chulwoo Lee
84e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kimimport java.io.FileDescriptor;
85e7bb7d6bb2257c24076f5a4b9f536f90a6637f58Chulwoo Leeimport java.io.IOException;
86e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kimimport java.io.PrintWriter;
873957091ba8f08c02b5e781098cb955a5f697a1ffJae Seoimport java.util.ArrayList;
883957091ba8f08c02b5e781098cb955a5f697a1ffJae Seoimport java.util.HashMap;
895c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seoimport java.util.HashSet;
90187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kimimport java.util.Iterator;
913957091ba8f08c02b5e781098cb955a5f697a1ffJae Seoimport java.util.List;
923957091ba8f08c02b5e781098cb955a5f697a1ffJae Seoimport java.util.Map;
935c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seoimport java.util.Set;
943957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
953957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo/** This class provides a system service that manages television inputs. */
963957091ba8f08c02b5e781098cb955a5f697a1ffJae Seopublic final class TvInputManagerService extends SystemService {
973957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    // STOPSHIP: Turn debugging off.
983957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    private static final boolean DEBUG = true;
993957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    private static final String TAG = "TvInputManagerService";
1003957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
1013957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    private final Context mContext;
102c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim    private final TvInputHardwareManager mTvInputHardwareManager;
1033957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
10431dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo    private final ContentResolver mContentResolver;
10531dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo
1063957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    // A global lock.
1073957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    private final Object mLock = new Object();
1083957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
1093957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    // ID of the current user.
1103957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    private int mCurrentUserId = UserHandle.USER_OWNER;
1113957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
1123957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    // A map from user id to UserState.
1133957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    private final SparseArray<UserState> mUserStates = new SparseArray<UserState>();
1143957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
1157eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo    private final WatchLogHandler mWatchLogHandler;
11631dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo
1173957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    public TvInputManagerService(Context context) {
1183957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        super(context);
11931dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo
1203957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        mContext = context;
12131dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo        mContentResolver = context.getContentResolver();
1227eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo        mWatchLogHandler = new WatchLogHandler(IoThread.get().getLooper());
12331dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo
124187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim        mTvInputHardwareManager = new TvInputHardwareManager(context, new HardwareListener());
12531dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo
1263957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        synchronized (mLock) {
127783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo            mUserStates.put(mCurrentUserId, new UserState(mContext, mCurrentUserId));
1283957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
1293957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    }
1303957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
1313957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    @Override
1323957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    public void onStart() {
1333957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        publishBinderService(Context.TV_INPUT_SERVICE, new BinderService());
1343957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    }
1353957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
1360ceb7e4755015eafda29c251eac285620788a51bJi-Hwan Lee    @Override
1370ceb7e4755015eafda29c251eac285620788a51bJi-Hwan Lee    public void onBootPhase(int phase) {
1380ceb7e4755015eafda29c251eac285620788a51bJi-Hwan Lee        if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY) {
1390ceb7e4755015eafda29c251eac285620788a51bJi-Hwan Lee            registerBroadcastReceivers();
140187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim        } else if (phase == SystemService.PHASE_THIRD_PARTY_APPS_CAN_START) {
1410ceb7e4755015eafda29c251eac285620788a51bJi-Hwan Lee            synchronized (mLock) {
1420ceb7e4755015eafda29c251eac285620788a51bJi-Hwan Lee                buildTvInputListLocked(mCurrentUserId);
1439c165d6e9a2f085fbdc87b9221f2d52d851b2652Jae Seo                buildTvContentRatingSystemListLocked(mCurrentUserId);
1440ceb7e4755015eafda29c251eac285620788a51bJi-Hwan Lee            }
1450ceb7e4755015eafda29c251eac285620788a51bJi-Hwan Lee        }
146969167dc05a6485a32d160895871cff46fd81884Wonsik Kim        mTvInputHardwareManager.onBootPhase(phase);
1470ceb7e4755015eafda29c251eac285620788a51bJi-Hwan Lee    }
1480ceb7e4755015eafda29c251eac285620788a51bJi-Hwan Lee
1493957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    private void registerBroadcastReceivers() {
1503957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        PackageMonitor monitor = new PackageMonitor() {
1513957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            @Override
1523957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            public void onSomePackagesChanged() {
153426c9a4008b75b93cbfea15aa4b8c47c5fdb49b9Dongwon Kang                if (DEBUG) Slog.d(TAG, "onSomePackagesChanged()");
1543957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                synchronized (mLock) {
1553957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    buildTvInputListLocked(mCurrentUserId);
1569c165d6e9a2f085fbdc87b9221f2d52d851b2652Jae Seo                    buildTvContentRatingSystemListLocked(mCurrentUserId);
1573957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                }
1583957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            }
1595c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo
1605c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo            @Override
1615c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo            public void onPackageRemoved(String packageName, int uid) {
1625c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo                synchronized (mLock) {
1635c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo                    UserState userState = getUserStateLocked(mCurrentUserId);
164969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                    if (!userState.packageSet.contains(packageName)) {
1655c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo                        // Not a TV input package.
1665c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo                        return;
1675c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo                    }
1685c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo                }
1695c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo
1705c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo                ArrayList<ContentProviderOperation> operations =
1715c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo                        new ArrayList<ContentProviderOperation>();
1725c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo
1735c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo                String selection = TvContract.BaseTvColumns.COLUMN_PACKAGE_NAME + "=?";
1745c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo                String[] selectionArgs = { packageName };
1755c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo
1765c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo                operations.add(ContentProviderOperation.newDelete(TvContract.Channels.CONTENT_URI)
1775c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo                        .withSelection(selection, selectionArgs).build());
1785c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo                operations.add(ContentProviderOperation.newDelete(TvContract.Programs.CONTENT_URI)
1795c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo                        .withSelection(selection, selectionArgs).build());
1805c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo                operations.add(ContentProviderOperation
1815c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo                        .newDelete(TvContract.WatchedPrograms.CONTENT_URI)
1825c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo                        .withSelection(selection, selectionArgs).build());
1835c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo
1845c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo                ContentProviderResult[] results = null;
1855c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo                try {
1865c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo                    results = mContentResolver.applyBatch(TvContract.AUTHORITY, operations);
1875c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo                } catch (RemoteException | OperationApplicationException e) {
188fea8dd45f4955b4b4b6536bf51453e19288deba2Jae Seo                    Slog.e(TAG, "error in applyBatch", e);
1895c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo                }
1905c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo
1915c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo                if (DEBUG) {
1925c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo                    Slog.d(TAG, "onPackageRemoved(packageName=" + packageName + ", uid=" + uid
1935c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo                            + ")");
1945c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo                    Slog.d(TAG, "results=" + results);
1955c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo                }
1965c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo            }
1973957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        };
1983957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        monitor.register(mContext, null, UserHandle.ALL, true);
1993957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
2003957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        IntentFilter intentFilter = new IntentFilter();
2013957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        intentFilter.addAction(Intent.ACTION_USER_SWITCHED);
2023957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        intentFilter.addAction(Intent.ACTION_USER_REMOVED);
2033957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        mContext.registerReceiverAsUser(new BroadcastReceiver() {
2043957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            @Override
2053957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            public void onReceive(Context context, Intent intent) {
2063957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                String action = intent.getAction();
2073957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                if (Intent.ACTION_USER_SWITCHED.equals(action)) {
2083957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    switchUser(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0));
2093957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                } else if (Intent.ACTION_USER_REMOVED.equals(action)) {
2103957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    removeUser(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0));
2113957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                }
2123957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            }
2133957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }, UserHandle.ALL, intentFilter, null, null);
2143957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    }
2153957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
2169e8ade2eb7ee835963473c9cf6faaf5423b0b048Ji-Hwan Lee    private static boolean hasHardwarePermission(PackageManager pm, ComponentName component) {
217187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim        return pm.checkPermission(android.Manifest.permission.TV_INPUT_HARDWARE,
2189e8ade2eb7ee835963473c9cf6faaf5423b0b048Ji-Hwan Lee                component.getPackageName()) == PackageManager.PERMISSION_GRANTED;
219187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim    }
220187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim
2213957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    private void buildTvInputListLocked(int userId) {
2223957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        UserState userState = getUserStateLocked(userId);
223969167dc05a6485a32d160895871cff46fd81884Wonsik Kim        userState.packageSet.clear();
2243957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
225fea8dd45f4955b4b4b6536bf51453e19288deba2Jae Seo        if (DEBUG) {
226fea8dd45f4955b4b4b6536bf51453e19288deba2Jae Seo            Slog.d(TAG, "buildTvInputList");
227fea8dd45f4955b4b4b6536bf51453e19288deba2Jae Seo        }
2283957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        PackageManager pm = mContext.getPackageManager();
2293957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        List<ResolveInfo> services = pm.queryIntentServices(
230e7bb7d6bb2257c24076f5a4b9f536f90a6637f58Chulwoo Lee                new Intent(TvInputService.SERVICE_INTERFACE),
231e7bb7d6bb2257c24076f5a4b9f536f90a6637f58Chulwoo Lee                PackageManager.GET_SERVICES | PackageManager.GET_META_DATA);
2324f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee        List<TvInputInfo> inputList = new ArrayList<TvInputInfo>();
2333957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        for (ResolveInfo ri : services) {
2343957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            ServiceInfo si = ri.serviceInfo;
2353957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            if (!android.Manifest.permission.BIND_TV_INPUT.equals(si.permission)) {
2369a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                Slog.w(TAG, "Skipping TV input " + si.name + ": it does not require the permission "
2373957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                        + android.Manifest.permission.BIND_TV_INPUT);
2383957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                continue;
2393957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            }
2409cc28e5175e1391646b29469d329c9c1c9311ee1Jae Seo
2419cc28e5175e1391646b29469d329c9c1c9311ee1Jae Seo            ComponentName component = new ComponentName(si.packageName, si.name);
2429cc28e5175e1391646b29469d329c9c1c9311ee1Jae Seo            if (hasHardwarePermission(pm, component)) {
2439cc28e5175e1391646b29469d329c9c1c9311ee1Jae Seo                ServiceState serviceState = userState.serviceStateMap.get(component);
2449cc28e5175e1391646b29469d329c9c1c9311ee1Jae Seo                if (serviceState == null) {
2459cc28e5175e1391646b29469d329c9c1c9311ee1Jae Seo                    // We see this hardware TV input service for the first time; we need to
2469cc28e5175e1391646b29469d329c9c1c9311ee1Jae Seo                    // prepare the ServiceState object so that we can connect to the service and
2479cc28e5175e1391646b29469d329c9c1c9311ee1Jae Seo                    // let it add TvInputInfo objects to mInputList if there's any.
2489cc28e5175e1391646b29469d329c9c1c9311ee1Jae Seo                    serviceState = new ServiceState(component, userId);
2499cc28e5175e1391646b29469d329c9c1c9311ee1Jae Seo                    userState.serviceStateMap.put(component, serviceState);
250187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                } else {
2519cc28e5175e1391646b29469d329c9c1c9311ee1Jae Seo                    inputList.addAll(serviceState.mInputList);
252187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                }
2539cc28e5175e1391646b29469d329c9c1c9311ee1Jae Seo            } else {
2549cc28e5175e1391646b29469d329c9c1c9311ee1Jae Seo                try {
2559cc28e5175e1391646b29469d329c9c1c9311ee1Jae Seo                    inputList.add(TvInputInfo.createTvInputInfo(mContext, ri));
2569cc28e5175e1391646b29469d329c9c1c9311ee1Jae Seo                } catch (XmlPullParserException | IOException e) {
257fea8dd45f4955b4b4b6536bf51453e19288deba2Jae Seo                    Slog.e(TAG, "failed to load TV input " + si.name, e);
2589cc28e5175e1391646b29469d329c9c1c9311ee1Jae Seo                    continue;
259969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                }
2609cc28e5175e1391646b29469d329c9c1c9311ee1Jae Seo            }
261226a51958d645a8e2be3e40a6b6daaca558b4913Jaewan Kim
2629cc28e5175e1391646b29469d329c9c1c9311ee1Jae Seo            // Reconnect the service if existing input is updated.
2639cc28e5175e1391646b29469d329c9c1c9311ee1Jae Seo            updateServiceConnectionLocked(component, userId);
2649cc28e5175e1391646b29469d329c9c1c9311ee1Jae Seo            userState.packageSet.add(si.packageName);
2659cc28e5175e1391646b29469d329c9c1c9311ee1Jae Seo        }
266187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim
2679cc28e5175e1391646b29469d329c9c1c9311ee1Jae Seo        Map<String, TvInputState> inputMap = new HashMap<String, TvInputState>();
2689cc28e5175e1391646b29469d329c9c1c9311ee1Jae Seo        for (TvInputInfo info : inputList) {
269fea8dd45f4955b4b4b6536bf51453e19288deba2Jae Seo            if (DEBUG) {
270fea8dd45f4955b4b4b6536bf51453e19288deba2Jae Seo                Slog.d(TAG, "add " + info.getId());
271fea8dd45f4955b4b4b6536bf51453e19288deba2Jae Seo            }
2729cc28e5175e1391646b29469d329c9c1c9311ee1Jae Seo            TvInputState state = userState.inputMap.get(info.getId());
2739cc28e5175e1391646b29469d329c9c1c9311ee1Jae Seo            if (state == null) {
2749cc28e5175e1391646b29469d329c9c1c9311ee1Jae Seo                state = new TvInputState();
275e7bb7d6bb2257c24076f5a4b9f536f90a6637f58Chulwoo Lee            }
2769cc28e5175e1391646b29469d329c9c1c9311ee1Jae Seo            state.mInfo = info;
2779cc28e5175e1391646b29469d329c9c1c9311ee1Jae Seo            inputMap.put(info.getId(), state);
2783957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
2798e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim
2808e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim        for (String inputId : inputMap.keySet()) {
2818e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim            if (!userState.inputMap.containsKey(inputId)) {
2828e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim                notifyInputAddedLocked(userState, inputId);
2838e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim            }
2848e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim        }
2858e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim
2868e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim        for (String inputId : userState.inputMap.keySet()) {
2878e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim            if (!inputMap.containsKey(inputId)) {
288426c9a4008b75b93cbfea15aa4b8c47c5fdb49b9Dongwon Kang                TvInputInfo info = userState.inputMap.get(inputId).mInfo;
289426c9a4008b75b93cbfea15aa4b8c47c5fdb49b9Dongwon Kang                ServiceState serviceState = userState.serviceStateMap.get(info.getComponent());
290426c9a4008b75b93cbfea15aa4b8c47c5fdb49b9Dongwon Kang                if (serviceState != null) {
291426c9a4008b75b93cbfea15aa4b8c47c5fdb49b9Dongwon Kang                    abortPendingCreateSessionRequestsLocked(serviceState, inputId, userId);
292426c9a4008b75b93cbfea15aa4b8c47c5fdb49b9Dongwon Kang                }
2938e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim                notifyInputRemovedLocked(userState, inputId);
2948e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim            }
2958e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim        }
2968e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim
2978e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim        userState.inputMap.clear();
2988e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim        userState.inputMap = inputMap;
2999c165d6e9a2f085fbdc87b9221f2d52d851b2652Jae Seo    }
3009c165d6e9a2f085fbdc87b9221f2d52d851b2652Jae Seo
3019c165d6e9a2f085fbdc87b9221f2d52d851b2652Jae Seo    private void buildTvContentRatingSystemListLocked(int userId) {
3029c165d6e9a2f085fbdc87b9221f2d52d851b2652Jae Seo        UserState userState = getUserStateLocked(userId);
3039c165d6e9a2f085fbdc87b9221f2d52d851b2652Jae Seo        userState.contentRatingSystemList.clear();
3049c165d6e9a2f085fbdc87b9221f2d52d851b2652Jae Seo
3059c165d6e9a2f085fbdc87b9221f2d52d851b2652Jae Seo        final PackageManager pm = mContext.getPackageManager();
3069c165d6e9a2f085fbdc87b9221f2d52d851b2652Jae Seo        Intent intent = new Intent(TvInputManager.ACTION_QUERY_CONTENT_RATING_SYSTEMS);
3079c165d6e9a2f085fbdc87b9221f2d52d851b2652Jae Seo        for (ResolveInfo resolveInfo :
3089c165d6e9a2f085fbdc87b9221f2d52d851b2652Jae Seo                pm.queryBroadcastReceivers(intent, PackageManager.GET_META_DATA)) {
3099c165d6e9a2f085fbdc87b9221f2d52d851b2652Jae Seo            ActivityInfo receiver = resolveInfo.activityInfo;
3109c165d6e9a2f085fbdc87b9221f2d52d851b2652Jae Seo            Bundle metaData = receiver.metaData;
3119c165d6e9a2f085fbdc87b9221f2d52d851b2652Jae Seo            if (metaData == null) {
3129c165d6e9a2f085fbdc87b9221f2d52d851b2652Jae Seo                continue;
3139c165d6e9a2f085fbdc87b9221f2d52d851b2652Jae Seo            }
3145c5b83fcd58d21c9ab7ac986bf84f604ec5bb4b5Sungsoo Lim
3159c165d6e9a2f085fbdc87b9221f2d52d851b2652Jae Seo            int xmlResId = metaData.getInt(TvInputManager.META_DATA_CONTENT_RATING_SYSTEMS);
3169c165d6e9a2f085fbdc87b9221f2d52d851b2652Jae Seo            if (xmlResId == 0) {
3179c165d6e9a2f085fbdc87b9221f2d52d851b2652Jae Seo                Slog.w(TAG, "Missing meta-data '"
3189c165d6e9a2f085fbdc87b9221f2d52d851b2652Jae Seo                        + TvInputManager.META_DATA_CONTENT_RATING_SYSTEMS + "' on receiver "
3199c165d6e9a2f085fbdc87b9221f2d52d851b2652Jae Seo                        + receiver.packageName + "/" + receiver.name);
3209c165d6e9a2f085fbdc87b9221f2d52d851b2652Jae Seo                continue;
3215c5b83fcd58d21c9ab7ac986bf84f604ec5bb4b5Sungsoo Lim            }
3229c165d6e9a2f085fbdc87b9221f2d52d851b2652Jae Seo            userState.contentRatingSystemList.add(
3239c165d6e9a2f085fbdc87b9221f2d52d851b2652Jae Seo                    TvContentRatingSystemInfo.createTvContentRatingSystemInfo(xmlResId,
3249c165d6e9a2f085fbdc87b9221f2d52d851b2652Jae Seo                            receiver.applicationInfo));
3255c5b83fcd58d21c9ab7ac986bf84f604ec5bb4b5Sungsoo Lim        }
3263957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    }
3273957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
3283957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    private void switchUser(int userId) {
3293957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        synchronized (mLock) {
3303957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            if (mCurrentUserId == userId) {
3313957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                return;
3323957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            }
3333957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            // final int oldUserId = mCurrentUserId;
3343957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            // TODO: Release services and sessions in the old user state, if needed.
3353957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            mCurrentUserId = userId;
3363957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
3373957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            UserState userState = mUserStates.get(userId);
3383957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            if (userState == null) {
339783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                userState = new UserState(mContext, userId);
3403957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            }
3413957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            mUserStates.put(userId, userState);
3423957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            buildTvInputListLocked(userId);
3439c165d6e9a2f085fbdc87b9221f2d52d851b2652Jae Seo            buildTvContentRatingSystemListLocked(userId);
3443957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
3453957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    }
3463957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
3473957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    private void removeUser(int userId) {
3483957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        synchronized (mLock) {
349b06cb8870f0407f18bb1225065a93aba2a5de2bfJae Seo            UserState userState = mUserStates.get(userId);
350b06cb8870f0407f18bb1225065a93aba2a5de2bfJae Seo            if (userState == null) {
351b06cb8870f0407f18bb1225065a93aba2a5de2bfJae Seo                return;
352b06cb8870f0407f18bb1225065a93aba2a5de2bfJae Seo            }
3533957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            // Release created sessions.
3543957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            for (SessionState state : userState.sessionStateMap.values()) {
355d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim                if (state.mSession != null) {
3563957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    try {
357d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim                        state.mSession.release();
3583957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    } catch (RemoteException e) {
3599a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                        Slog.e(TAG, "error in release", e);
3603957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    }
3613957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                }
3623957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            }
3633957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            userState.sessionStateMap.clear();
3643957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
3653957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            // Unregister all callbacks and unbind all services.
3663957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            for (ServiceState serviceState : userState.serviceStateMap.values()) {
367d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim                if (serviceState.mCallback != null) {
3683957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    try {
369d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim                        serviceState.mService.unregisterCallback(serviceState.mCallback);
3703957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    } catch (RemoteException e) {
3719a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                        Slog.e(TAG, "error in unregisterCallback", e);
3723957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    }
3733957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                }
374d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim                mContext.unbindService(serviceState.mConnection);
3753957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            }
3763957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            userState.serviceStateMap.clear();
3773957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
378fea8dd45f4955b4b4b6536bf51453e19288deba2Jae Seo            // Clear everything else.
379fea8dd45f4955b4b4b6536bf51453e19288deba2Jae Seo            userState.inputMap.clear();
380fea8dd45f4955b4b4b6536bf51453e19288deba2Jae Seo            userState.packageSet.clear();
3819c165d6e9a2f085fbdc87b9221f2d52d851b2652Jae Seo            userState.contentRatingSystemList.clear();
38272ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim            userState.clientStateMap.clear();
383fea8dd45f4955b4b4b6536bf51453e19288deba2Jae Seo            userState.callbackSet.clear();
384fea8dd45f4955b4b4b6536bf51453e19288deba2Jae Seo            userState.mainSessionToken = null;
38572ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim
3863957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            mUserStates.remove(userId);
3873957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
3883957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    }
3893957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
3903957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    private UserState getUserStateLocked(int userId) {
3913957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        UserState userState = mUserStates.get(userId);
3923957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        if (userState == null) {
3933957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            throw new IllegalStateException("User state not found for user ID " + userId);
3943957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
3953957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        return userState;
3963957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    }
3973957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
3989e8ade2eb7ee835963473c9cf6faaf5423b0b048Ji-Hwan Lee    private ServiceState getServiceStateLocked(ComponentName component, int userId) {
3993957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        UserState userState = getUserStateLocked(userId);
4009e8ade2eb7ee835963473c9cf6faaf5423b0b048Ji-Hwan Lee        ServiceState serviceState = userState.serviceStateMap.get(component);
4013957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        if (serviceState == null) {
4029e8ade2eb7ee835963473c9cf6faaf5423b0b048Ji-Hwan Lee            throw new IllegalStateException("Service state not found for " + component + " (userId="
4037de5e234715a3baa8905afa3dd0c5009af64541fSungsoo Lim                    + userId + ")");
4043957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
4053957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        return serviceState;
4063957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    }
4073957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
4082b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim    private SessionState getSessionStateLocked(IBinder sessionToken, int callingUid, int userId) {
4093957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        UserState userState = getUserStateLocked(userId);
4103957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        SessionState sessionState = userState.sessionStateMap.get(sessionToken);
4113957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        if (sessionState == null) {
4123957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            throw new IllegalArgumentException("Session state not found for token " + sessionToken);
4133957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
4143957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        // Only the application that requested this session or the system can access it.
415d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim        if (callingUid != Process.SYSTEM_UID && callingUid != sessionState.mCallingUid) {
4163957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            throw new SecurityException("Illegal access to the session with token " + sessionToken
4173957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    + " from uid " + callingUid);
4183957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
4192b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim        return sessionState;
4202b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim    }
4212b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim
4222b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim    private ITvInputSession getSessionLocked(IBinder sessionToken, int callingUid, int userId) {
4234c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee        return getSessionLocked(getSessionStateLocked(sessionToken, callingUid, userId));
4244c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee    }
4254c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee
4264c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee    private ITvInputSession getSessionLocked(SessionState sessionState) {
427d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim        ITvInputSession session = sessionState.mSession;
4283957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        if (session == null) {
4294c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee            throw new IllegalStateException("Session not yet created for token "
4304c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee                    + sessionState.mSessionToken);
4313957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
4323957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        return session;
4333957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    }
4343957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
4353957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    private int resolveCallingUserId(int callingPid, int callingUid, int requestedUserId,
4363957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            String methodName) {
4373957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        return ActivityManager.handleIncomingUser(callingPid, callingUid, requestedUserId, false,
4383957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                false, methodName, null);
4393957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    }
4403957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
441187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim    private static boolean shouldMaintainConnection(ServiceState serviceState) {
4429cc28e5175e1391646b29469d329c9c1c9311ee1Jae Seo        return !serviceState.mSessionTokens.isEmpty() || serviceState.mIsHardware;
443187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim        // TODO: Find a way to maintain connection only when necessary.
444187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim    }
445187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim
4469e8ade2eb7ee835963473c9cf6faaf5423b0b048Ji-Hwan Lee    private void updateServiceConnectionLocked(ComponentName component, int userId) {
4473957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        UserState userState = getUserStateLocked(userId);
4489e8ade2eb7ee835963473c9cf6faaf5423b0b048Ji-Hwan Lee        ServiceState serviceState = userState.serviceStateMap.get(component);
4493957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        if (serviceState == null) {
4503957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            return;
4513957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
4522b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim        if (serviceState.mReconnecting) {
4532b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim            if (!serviceState.mSessionTokens.isEmpty()) {
4542b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                // wait until all the sessions are removed.
4552b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                return;
4562b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim            }
4572b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim            serviceState.mReconnecting = false;
4582b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim        }
459187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim        boolean maintainConnection = shouldMaintainConnection(serviceState);
460187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim        if (serviceState.mService == null && maintainConnection && userId == mCurrentUserId) {
4613957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            // This means that the service is not yet connected but its state indicates that we
4623957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            // have pending requests. Then, connect the service.
463d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim            if (serviceState.mBound) {
4643957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                // We have already bound to the service so we don't try to bind again until after we
4653957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                // unbind later on.
4663957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                return;
4673957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            }
4683957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            if (DEBUG) {
4699e8ade2eb7ee835963473c9cf6faaf5423b0b048Ji-Hwan Lee                Slog.d(TAG, "bindServiceAsUser(service=" + component + ", userId=" + userId + ")");
4703957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            }
471d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim
4729e8ade2eb7ee835963473c9cf6faaf5423b0b048Ji-Hwan Lee            Intent i = new Intent(TvInputService.SERVICE_INTERFACE).setComponent(component);
473226a51958d645a8e2be3e40a6b6daaca558b4913Jaewan Kim            // Binding service may fail if the service is updating.
474226a51958d645a8e2be3e40a6b6daaca558b4913Jaewan Kim            // In that case, the connection will be revived in buildTvInputListLocked called by
475226a51958d645a8e2be3e40a6b6daaca558b4913Jaewan Kim            // onSomePackagesChanged.
476e17b2dd7bcc137bf4d842a779e8d62c63957a978Ji-Hwan Lee            serviceState.mBound = mContext.bindServiceAsUser(
477e17b2dd7bcc137bf4d842a779e8d62c63957a978Ji-Hwan Lee                    i, serviceState.mConnection, Context.BIND_AUTO_CREATE, new UserHandle(userId));
478187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim        } else if (serviceState.mService != null && !maintainConnection) {
4793957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            // This means that the service is already connected but its state indicates that we have
4803957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            // nothing to do with it. Then, disconnect the service.
4813957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            if (DEBUG) {
4829e8ade2eb7ee835963473c9cf6faaf5423b0b048Ji-Hwan Lee                Slog.d(TAG, "unbindService(service=" + component + ")");
4833957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            }
484d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim            mContext.unbindService(serviceState.mConnection);
4859e8ade2eb7ee835963473c9cf6faaf5423b0b048Ji-Hwan Lee            userState.serviceStateMap.remove(component);
4863957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
4873957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    }
4883957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
489426c9a4008b75b93cbfea15aa4b8c47c5fdb49b9Dongwon Kang    private void abortPendingCreateSessionRequestsLocked(ServiceState serviceState,
490426c9a4008b75b93cbfea15aa4b8c47c5fdb49b9Dongwon Kang            String inputId, int userId) {
491426c9a4008b75b93cbfea15aa4b8c47c5fdb49b9Dongwon Kang        // Let clients know the create session requests are failed.
492426c9a4008b75b93cbfea15aa4b8c47c5fdb49b9Dongwon Kang        UserState userState = getUserStateLocked(userId);
493f7f49ddade34744d5386f9bf52ab9ba4f981fce7Dongwon Kang        List<SessionState> sessionsToAbort = new ArrayList<>();
494426c9a4008b75b93cbfea15aa4b8c47c5fdb49b9Dongwon Kang        for (IBinder sessionToken : serviceState.mSessionTokens) {
495426c9a4008b75b93cbfea15aa4b8c47c5fdb49b9Dongwon Kang            SessionState sessionState = userState.sessionStateMap.get(sessionToken);
496426c9a4008b75b93cbfea15aa4b8c47c5fdb49b9Dongwon Kang            if (sessionState.mSession == null && (inputId == null
497426c9a4008b75b93cbfea15aa4b8c47c5fdb49b9Dongwon Kang                    || sessionState.mInfo.getId().equals(inputId))) {
498f7f49ddade34744d5386f9bf52ab9ba4f981fce7Dongwon Kang                sessionsToAbort.add(sessionState);
499426c9a4008b75b93cbfea15aa4b8c47c5fdb49b9Dongwon Kang            }
500426c9a4008b75b93cbfea15aa4b8c47c5fdb49b9Dongwon Kang        }
501f7f49ddade34744d5386f9bf52ab9ba4f981fce7Dongwon Kang        for (SessionState sessionState : sessionsToAbort) {
502f7f49ddade34744d5386f9bf52ab9ba4f981fce7Dongwon Kang            removeSessionStateLocked(sessionState.mSessionToken, sessionState.mUserId);
503f7f49ddade34744d5386f9bf52ab9ba4f981fce7Dongwon Kang            sendSessionTokenToClientLocked(sessionState.mClient,
504f7f49ddade34744d5386f9bf52ab9ba4f981fce7Dongwon Kang                    sessionState.mInfo.getId(), null, null, sessionState.mSeq);
505f7f49ddade34744d5386f9bf52ab9ba4f981fce7Dongwon Kang        }
506426c9a4008b75b93cbfea15aa4b8c47c5fdb49b9Dongwon Kang        updateServiceConnectionLocked(serviceState.mComponent, userId);
507426c9a4008b75b93cbfea15aa4b8c47c5fdb49b9Dongwon Kang    }
508426c9a4008b75b93cbfea15aa4b8c47c5fdb49b9Dongwon Kang
50972ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim    private ClientState createClientStateLocked(IBinder clientToken, int userId) {
51072ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim        UserState userState = getUserStateLocked(userId);
51172ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim        ClientState clientState = new ClientState(clientToken, userId);
51272ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim        try {
51372ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim            clientToken.linkToDeath(clientState, 0);
51472ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim        } catch (RemoteException e) {
515fea8dd45f4955b4b4b6536bf51453e19288deba2Jae Seo            Slog.e(TAG, "client process has already died", e);
51672ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim        }
51772ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim        userState.clientStateMap.put(clientToken, clientState);
51872ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim        return clientState;
51972ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim    }
52072ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim
5213957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    private void createSessionInternalLocked(ITvInputService service, final IBinder sessionToken,
5227de5e234715a3baa8905afa3dd0c5009af64541fSungsoo Lim            final int userId) {
52372ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim        final UserState userState = getUserStateLocked(userId);
52472ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim        final SessionState sessionState = userState.sessionStateMap.get(sessionToken);
5253957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        if (DEBUG) {
526187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim            Slog.d(TAG, "createSessionInternalLocked(inputId=" + sessionState.mInfo.getId() + ")");
5273957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
5286a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo
5296a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo        final InputChannel[] channels = InputChannel.openInputChannelPair(sessionToken.toString());
5306a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo
5313957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        // Set up a callback to send the session token.
5323957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        ITvInputSessionCallback callback = new ITvInputSessionCallback.Stub() {
5333957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            @Override
534bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang            public void onSessionCreated(ITvInputSession session, IBinder harewareSessionToken) {
5353957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                if (DEBUG) {
536187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                    Slog.d(TAG, "onSessionCreated(inputId=" + sessionState.mInfo.getId() + ")");
5373957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                }
5383957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                synchronized (mLock) {
539d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim                    sessionState.mSession = session;
540bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                    sessionState.mHardwareSessionToken = harewareSessionToken;
541fd5b72f1ed2ee74a4204eef65f560fc82f0b62feDongwon Kang                    if (session == null) {
542fd5b72f1ed2ee74a4204eef65f560fc82f0b62feDongwon Kang                        removeSessionStateLocked(sessionToken, userId);
543187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                        sendSessionTokenToClientLocked(sessionState.mClient,
544187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                                sessionState.mInfo.getId(), null, null, sessionState.mSeq);
545fd5b72f1ed2ee74a4204eef65f560fc82f0b62feDongwon Kang                    } else {
5462b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                        try {
5472b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                            session.asBinder().linkToDeath(sessionState, 0);
5482b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                        } catch (RemoteException e) {
549fea8dd45f4955b4b4b6536bf51453e19288deba2Jae Seo                            Slog.e(TAG, "session process has already died", e);
5502b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                        }
55172ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim
55272ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim                        IBinder clientToken = sessionState.mClient.asBinder();
55372ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim                        ClientState clientState = userState.clientStateMap.get(clientToken);
55472ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim                        if (clientState == null) {
55572ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim                            clientState = createClientStateLocked(clientToken, userId);
55672ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim                        }
55772ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim                        clientState.mSessionTokens.add(sessionState.mSessionToken);
55872ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim
559187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                        sendSessionTokenToClientLocked(sessionState.mClient,
560187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                                sessionState.mInfo.getId(), sessionToken, channels[0],
561187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                                sessionState.mSeq);
562fd5b72f1ed2ee74a4204eef65f560fc82f0b62feDongwon Kang                    }
5636a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                    channels[0].dispose();
5643957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                }
5653957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            }
566832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho
567832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho            @Override
5681f213914c45c23c653f721690da2ce0718e63139Dongwon Kang            public void onChannelRetuned(Uri channelUri) {
569a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang                synchronized (mLock) {
570a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang                    if (DEBUG) {
5711f213914c45c23c653f721690da2ce0718e63139Dongwon Kang                        Slog.d(TAG, "onChannelRetuned(" + channelUri + ")");
572a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang                    }
573a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang                    if (sessionState.mSession == null || sessionState.mClient == null) {
574a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang                        return;
575a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang                    }
576a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang                    try {
5771f213914c45c23c653f721690da2ce0718e63139Dongwon Kang                        // TODO: Consider adding this channel change in the watch log. When we do
5781f213914c45c23c653f721690da2ce0718e63139Dongwon Kang                        // that, how we can protect the watch log from malicious tv inputs should
5791f213914c45c23c653f721690da2ce0718e63139Dongwon Kang                        // be addressed. e.g. add a field which represents where the channel change
5801f213914c45c23c653f721690da2ce0718e63139Dongwon Kang                        // originated from.
5811f213914c45c23c653f721690da2ce0718e63139Dongwon Kang                        sessionState.mClient.onChannelRetuned(channelUri, sessionState.mSeq);
582a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang                    } catch (RemoteException e) {
583fea8dd45f4955b4b4b6536bf51453e19288deba2Jae Seo                        Slog.e(TAG, "error in onChannelRetuned", e);
584a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang                    }
585a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang                }
586a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang            }
587a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang
588a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang            @Override
58910d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo            public void onTracksChanged(List<TvTrackInfo> tracks) {
590a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang                synchronized (mLock) {
591a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang                    if (DEBUG) {
59210d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo                        Slog.d(TAG, "onTracksChanged(" + tracks + ")");
593a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang                    }
594a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang                    if (sessionState.mSession == null || sessionState.mClient == null) {
595a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang                        return;
596a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang                    }
597a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang                    try {
59810d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo                        sessionState.mClient.onTracksChanged(tracks, sessionState.mSeq);
599a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang                    } catch (RemoteException e) {
600fea8dd45f4955b4b4b6536bf51453e19288deba2Jae Seo                        Slog.e(TAG, "error in onTracksChanged", e);
601b93ccca6139a7ee2dba5c110e5f8213a2bd231e5Dongwon Kang                    }
602b93ccca6139a7ee2dba5c110e5f8213a2bd231e5Dongwon Kang                }
603b93ccca6139a7ee2dba5c110e5f8213a2bd231e5Dongwon Kang            }
604b93ccca6139a7ee2dba5c110e5f8213a2bd231e5Dongwon Kang
605b93ccca6139a7ee2dba5c110e5f8213a2bd231e5Dongwon Kang            @Override
60610d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo            public void onTrackSelected(int type, String trackId) {
607d5ce9759524740cfb02638fd1d7b44315957b422Jae Seo                synchronized (mLock) {
608d5ce9759524740cfb02638fd1d7b44315957b422Jae Seo                    if (DEBUG) {
60910d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo                        Slog.d(TAG, "onTrackSelected(type=" + type + ", trackId=" + trackId + ")");
610d5ce9759524740cfb02638fd1d7b44315957b422Jae Seo                    }
611d5ce9759524740cfb02638fd1d7b44315957b422Jae Seo                    if (sessionState.mSession == null || sessionState.mClient == null) {
612d5ce9759524740cfb02638fd1d7b44315957b422Jae Seo                        return;
613d5ce9759524740cfb02638fd1d7b44315957b422Jae Seo                    }
614d5ce9759524740cfb02638fd1d7b44315957b422Jae Seo                    try {
61510d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo                        sessionState.mClient.onTrackSelected(type, trackId, sessionState.mSeq);
616d5ce9759524740cfb02638fd1d7b44315957b422Jae Seo                    } catch (RemoteException e) {
617fea8dd45f4955b4b4b6536bf51453e19288deba2Jae Seo                        Slog.e(TAG, "error in onTrackSelected", e);
618d5ce9759524740cfb02638fd1d7b44315957b422Jae Seo                    }
619d5ce9759524740cfb02638fd1d7b44315957b422Jae Seo                }
620d5ce9759524740cfb02638fd1d7b44315957b422Jae Seo            }
621d5ce9759524740cfb02638fd1d7b44315957b422Jae Seo
622d5ce9759524740cfb02638fd1d7b44315957b422Jae Seo            @Override
6239b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang            public void onVideoAvailable() {
6249b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                synchronized (mLock) {
6259b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                    if (DEBUG) {
6269b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                        Slog.d(TAG, "onVideoAvailable()");
6279b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                    }
6289b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                    if (sessionState.mSession == null || sessionState.mClient == null) {
6299b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                        return;
6309b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                    }
6319b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                    try {
6329b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                        sessionState.mClient.onVideoAvailable(sessionState.mSeq);
6339b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                    } catch (RemoteException e) {
634fea8dd45f4955b4b4b6536bf51453e19288deba2Jae Seo                        Slog.e(TAG, "error in onVideoAvailable", e);
6359b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                    }
6369b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                }
6379b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang            }
6389b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang
6399b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang            @Override
6409b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang            public void onVideoUnavailable(int reason) {
6419b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                synchronized (mLock) {
6429b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                    if (DEBUG) {
6439b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                        Slog.d(TAG, "onVideoUnavailable(" + reason + ")");
6449b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                    }
6459b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                    if (sessionState.mSession == null || sessionState.mClient == null) {
6469b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                        return;
6479b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                    }
6489b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                    try {
6499b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                        sessionState.mClient.onVideoUnavailable(reason, sessionState.mSeq);
6509b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                    } catch (RemoteException e) {
651fea8dd45f4955b4b4b6536bf51453e19288deba2Jae Seo                        Slog.e(TAG, "error in onVideoUnavailable", e);
6529b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                    }
6539b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                }
6549b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang            }
6559b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang
6569b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang            @Override
657bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo            public void onContentAllowed() {
658bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo                synchronized (mLock) {
659bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo                    if (DEBUG) {
660bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo                        Slog.d(TAG, "onContentAllowed()");
661bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo                    }
662bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo                    if (sessionState.mSession == null || sessionState.mClient == null) {
663bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo                        return;
664bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo                    }
665bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo                    try {
666bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo                        sessionState.mClient.onContentAllowed(sessionState.mSeq);
667bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo                    } catch (RemoteException e) {
668fea8dd45f4955b4b4b6536bf51453e19288deba2Jae Seo                        Slog.e(TAG, "error in onContentAllowed", e);
669bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo                    }
670bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo                }
671bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo            }
672bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo
673bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo            @Override
6746057102dbb746593a7d59cf377c969b62e38c664Jae Seo            public void onContentBlocked(String rating) {
6756057102dbb746593a7d59cf377c969b62e38c664Jae Seo                synchronized (mLock) {
6766057102dbb746593a7d59cf377c969b62e38c664Jae Seo                    if (DEBUG) {
6776057102dbb746593a7d59cf377c969b62e38c664Jae Seo                        Slog.d(TAG, "onContentBlocked()");
6786057102dbb746593a7d59cf377c969b62e38c664Jae Seo                    }
6796057102dbb746593a7d59cf377c969b62e38c664Jae Seo                    if (sessionState.mSession == null || sessionState.mClient == null) {
6806057102dbb746593a7d59cf377c969b62e38c664Jae Seo                        return;
6816057102dbb746593a7d59cf377c969b62e38c664Jae Seo                    }
6826057102dbb746593a7d59cf377c969b62e38c664Jae Seo                    try {
6836057102dbb746593a7d59cf377c969b62e38c664Jae Seo                        sessionState.mClient.onContentBlocked(rating, sessionState.mSeq);
6846057102dbb746593a7d59cf377c969b62e38c664Jae Seo                    } catch (RemoteException e) {
685fea8dd45f4955b4b4b6536bf51453e19288deba2Jae Seo                        Slog.e(TAG, "error in onContentBlocked", e);
6866057102dbb746593a7d59cf377c969b62e38c664Jae Seo                    }
6876057102dbb746593a7d59cf377c969b62e38c664Jae Seo                }
6886057102dbb746593a7d59cf377c969b62e38c664Jae Seo            }
6896057102dbb746593a7d59cf377c969b62e38c664Jae Seo
6906057102dbb746593a7d59cf377c969b62e38c664Jae Seo            @Override
691ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho            public void onLayoutSurface(int left, int top, int right, int bottom) {
692ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho                synchronized (mLock) {
693ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho                    if (DEBUG) {
694ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho                        Slog.d(TAG, "onLayoutSurface (left=" + left + ", top=" + top
695ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho                                + ", right=" + right + ", bottom=" + bottom + ",)");
696ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho                    }
697ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho                    if (sessionState.mSession == null || sessionState.mClient == null) {
698ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho                        return;
699ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho                    }
700ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho                    try {
701ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho                        sessionState.mClient.onLayoutSurface(left, top, right, bottom,
702ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho                                sessionState.mSeq);
703ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho                    } catch (RemoteException e) {
704fea8dd45f4955b4b4b6536bf51453e19288deba2Jae Seo                        Slog.e(TAG, "error in onLayoutSurface", e);
705ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho                    }
706ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho                }
707ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho            }
708ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho
709ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho            @Override
710832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho            public void onSessionEvent(String eventType, Bundle eventArgs) {
711832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho                synchronized (mLock) {
712832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho                    if (DEBUG) {
713832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho                        Slog.d(TAG, "onEvent(what=" + eventType + ", data=" + eventArgs + ")");
714832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho                    }
715832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho                    if (sessionState.mSession == null || sessionState.mClient == null) {
716832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho                        return;
717832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho                    }
718832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho                    try {
719832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho                        sessionState.mClient.onSessionEvent(eventType, eventArgs,
720832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho                                sessionState.mSeq);
721832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho                    } catch (RemoteException e) {
722fea8dd45f4955b4b4b6536bf51453e19288deba2Jae Seo                        Slog.e(TAG, "error in onSessionEvent", e);
723832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho                    }
724832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho                }
725832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho            }
7263957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        };
7273957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
7283957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        // Create a session. When failed, send a null token immediately.
7293957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        try {
730187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim            service.createSession(channels[1], callback, sessionState.mInfo.getId());
7313957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        } catch (RemoteException e) {
7329a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            Slog.e(TAG, "error in createSession", e);
733fd5b72f1ed2ee74a4204eef65f560fc82f0b62feDongwon Kang            removeSessionStateLocked(sessionToken, userId);
734187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim            sendSessionTokenToClientLocked(sessionState.mClient, sessionState.mInfo.getId(), null,
735187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                    null, sessionState.mSeq);
7363957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
7376a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo        channels[1].dispose();
7383957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    }
7393957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
740d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim    private void sendSessionTokenToClientLocked(ITvInputClient client, String inputId,
7415c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo            IBinder sessionToken, InputChannel channel, int seq) {
7423957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        try {
743d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim            client.onSessionCreated(inputId, sessionToken, channel, seq);
744fea8dd45f4955b4b4b6536bf51453e19288deba2Jae Seo        } catch (RemoteException e) {
745fea8dd45f4955b4b4b6536bf51453e19288deba2Jae Seo            Slog.e(TAG, "error in onSessionCreated", e);
7463957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
7472b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim    }
7483957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
7492b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim    private void releaseSessionLocked(IBinder sessionToken, int callingUid, int userId) {
7502b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim        SessionState sessionState = getSessionStateLocked(sessionToken, callingUid, userId);
7512b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim        if (sessionState.mSession != null) {
75215c56aac985bc8d75f38fb4ecb92dda12d2ca06cJi-Hwan Lee            UserState userState = getUserStateLocked(userId);
75315c56aac985bc8d75f38fb4ecb92dda12d2ca06cJi-Hwan Lee            if (sessionToken == userState.mainSessionToken) {
75415c56aac985bc8d75f38fb4ecb92dda12d2ca06cJi-Hwan Lee                setMainLocked(sessionToken, false, callingUid, userId);
75515c56aac985bc8d75f38fb4ecb92dda12d2ca06cJi-Hwan Lee            }
7562b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim            try {
7572b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                sessionState.mSession.release();
7582b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim            } catch (RemoteException e) {
759fea8dd45f4955b4b4b6536bf51453e19288deba2Jae Seo                Slog.e(TAG, "session process has already died", e);
7602b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim            }
7612b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim            sessionState.mSession = null;
7623957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
7632b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim        removeSessionStateLocked(sessionToken, userId);
7643957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    }
7653957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
766fd5b72f1ed2ee74a4204eef65f560fc82f0b62feDongwon Kang    private void removeSessionStateLocked(IBinder sessionToken, int userId) {
767fd5b72f1ed2ee74a4204eef65f560fc82f0b62feDongwon Kang        UserState userState = getUserStateLocked(userId);
768abca0ee7949f59e72b8d2764dafa23af18eb51dbJi-Hwan Lee        if (sessionToken == userState.mainSessionToken) {
76915c56aac985bc8d75f38fb4ecb92dda12d2ca06cJi-Hwan Lee            if (DEBUG) {
77015c56aac985bc8d75f38fb4ecb92dda12d2ca06cJi-Hwan Lee                Slog.d(TAG, "mainSessionToken=null");
77115c56aac985bc8d75f38fb4ecb92dda12d2ca06cJi-Hwan Lee            }
772abca0ee7949f59e72b8d2764dafa23af18eb51dbJi-Hwan Lee            userState.mainSessionToken = null;
773abca0ee7949f59e72b8d2764dafa23af18eb51dbJi-Hwan Lee        }
774abca0ee7949f59e72b8d2764dafa23af18eb51dbJi-Hwan Lee
775abca0ee7949f59e72b8d2764dafa23af18eb51dbJi-Hwan Lee        // Remove the session state from the global session state map of the current user.
776fd5b72f1ed2ee74a4204eef65f560fc82f0b62feDongwon Kang        SessionState sessionState = userState.sessionStateMap.remove(sessionToken);
777fd5b72f1ed2ee74a4204eef65f560fc82f0b62feDongwon Kang
7788d4ded0058de5c573ccf79c4596bf5eb1b14fad3Chulwoo Lee        if (sessionState == null) {
7798d4ded0058de5c573ccf79c4596bf5eb1b14fad3Chulwoo Lee            return;
7808d4ded0058de5c573ccf79c4596bf5eb1b14fad3Chulwoo Lee        }
7818d4ded0058de5c573ccf79c4596bf5eb1b14fad3Chulwoo Lee
78272ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim        // Also remove the session token from the session token list of the current client and
78372ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim        // service.
78472ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim        ClientState clientState = userState.clientStateMap.get(sessionState.mClient.asBinder());
78572ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim        if (clientState != null) {
78672ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim            clientState.mSessionTokens.remove(sessionToken);
78772ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim            if (clientState.isEmpty()) {
78872ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim                userState.clientStateMap.remove(sessionState.mClient.asBinder());
78972ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim            }
79072ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim        }
79172ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim
792187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim        TvInputInfo info = sessionState.mInfo;
793187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim        if (info != null) {
794187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim            ServiceState serviceState = userState.serviceStateMap.get(info.getComponent());
795187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim            if (serviceState != null) {
796187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                serviceState.mSessionTokens.remove(sessionToken);
797187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim            }
798fd5b72f1ed2ee74a4204eef65f560fc82f0b62feDongwon Kang        }
799187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim        updateServiceConnectionLocked(sessionState.mInfo.getComponent(), userId);
8007eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo
8017eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo        // Log the end of watch.
8027eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo        SomeArgs args = SomeArgs.obtain();
8037eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo        args.arg1 = sessionToken;
8047eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo        args.arg2 = System.currentTimeMillis();
8057eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo        mWatchLogHandler.obtainMessage(WatchLogHandler.MSG_LOG_WATCH_END, args).sendToTarget();
806fd5b72f1ed2ee74a4204eef65f560fc82f0b62feDongwon Kang    }
807fd5b72f1ed2ee74a4204eef65f560fc82f0b62feDongwon Kang
80815c56aac985bc8d75f38fb4ecb92dda12d2ca06cJi-Hwan Lee    private void setMainLocked(IBinder sessionToken, boolean isMain, int callingUid, int userId) {
80915c56aac985bc8d75f38fb4ecb92dda12d2ca06cJi-Hwan Lee        SessionState sessionState = getSessionStateLocked(sessionToken, callingUid, userId);
81015c56aac985bc8d75f38fb4ecb92dda12d2ca06cJi-Hwan Lee        if (sessionState.mHardwareSessionToken != null) {
81115c56aac985bc8d75f38fb4ecb92dda12d2ca06cJi-Hwan Lee            sessionState = getSessionStateLocked(sessionState.mHardwareSessionToken,
81215c56aac985bc8d75f38fb4ecb92dda12d2ca06cJi-Hwan Lee                    Process.SYSTEM_UID, userId);
81315c56aac985bc8d75f38fb4ecb92dda12d2ca06cJi-Hwan Lee        }
81415c56aac985bc8d75f38fb4ecb92dda12d2ca06cJi-Hwan Lee        ServiceState serviceState = getServiceStateLocked(sessionState.mInfo.getComponent(),
81515c56aac985bc8d75f38fb4ecb92dda12d2ca06cJi-Hwan Lee                userId);
81615c56aac985bc8d75f38fb4ecb92dda12d2ca06cJi-Hwan Lee        if (!serviceState.mIsHardware) {
81715c56aac985bc8d75f38fb4ecb92dda12d2ca06cJi-Hwan Lee            return;
81815c56aac985bc8d75f38fb4ecb92dda12d2ca06cJi-Hwan Lee        }
81915c56aac985bc8d75f38fb4ecb92dda12d2ca06cJi-Hwan Lee        ITvInputSession session = getSessionLocked(sessionState);
82015c56aac985bc8d75f38fb4ecb92dda12d2ca06cJi-Hwan Lee        try {
82115c56aac985bc8d75f38fb4ecb92dda12d2ca06cJi-Hwan Lee            session.setMain(isMain);
82215c56aac985bc8d75f38fb4ecb92dda12d2ca06cJi-Hwan Lee        } catch (RemoteException e) {
82315c56aac985bc8d75f38fb4ecb92dda12d2ca06cJi-Hwan Lee            Slog.e(TAG, "error in setMain", e);
82415c56aac985bc8d75f38fb4ecb92dda12d2ca06cJi-Hwan Lee        }
82515c56aac985bc8d75f38fb4ecb92dda12d2ca06cJi-Hwan Lee    }
82615c56aac985bc8d75f38fb4ecb92dda12d2ca06cJi-Hwan Lee
8278e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim    private void notifyInputAddedLocked(UserState userState, String inputId) {
8288e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim        if (DEBUG) {
829fea8dd45f4955b4b4b6536bf51453e19288deba2Jae Seo            Slog.d(TAG, "notifyInputAddedLocked(inputId=" + inputId + ")");
8308e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim        }
8318e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim        for (ITvInputManagerCallback callback : userState.callbackSet) {
8328e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim            try {
8338e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim                callback.onInputAdded(inputId);
8348e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim            } catch (RemoteException e) {
835fea8dd45f4955b4b4b6536bf51453e19288deba2Jae Seo                Slog.e(TAG, "failed to report added input to callback", e);
8368e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim            }
8378e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim        }
8388e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim    }
8398e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim
8408e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim    private void notifyInputRemovedLocked(UserState userState, String inputId) {
8418e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim        if (DEBUG) {
842fea8dd45f4955b4b4b6536bf51453e19288deba2Jae Seo            Slog.d(TAG, "notifyInputRemovedLocked(inputId=" + inputId + ")");
8438e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim        }
8448e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim        for (ITvInputManagerCallback callback : userState.callbackSet) {
8458e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim            try {
8468e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim                callback.onInputRemoved(inputId);
8478e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim            } catch (RemoteException e) {
848fea8dd45f4955b4b4b6536bf51453e19288deba2Jae Seo                Slog.e(TAG, "failed to report removed input to callback", e);
8498e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim            }
8508e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim        }
8518e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim    }
8528e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim
8538e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim    private void notifyInputStateChangedLocked(UserState userState, String inputId,
854969167dc05a6485a32d160895871cff46fd81884Wonsik Kim            int state, ITvInputManagerCallback targetCallback) {
855969167dc05a6485a32d160895871cff46fd81884Wonsik Kim        if (DEBUG) {
856fea8dd45f4955b4b4b6536bf51453e19288deba2Jae Seo            Slog.d(TAG, "notifyInputStateChangedLocked(inputId=" + inputId
857fea8dd45f4955b4b4b6536bf51453e19288deba2Jae Seo                    + ", state=" + state + ")");
858969167dc05a6485a32d160895871cff46fd81884Wonsik Kim        }
859969167dc05a6485a32d160895871cff46fd81884Wonsik Kim        if (targetCallback == null) {
860969167dc05a6485a32d160895871cff46fd81884Wonsik Kim            for (ITvInputManagerCallback callback : userState.callbackSet) {
861969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                try {
862969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                    callback.onInputStateChanged(inputId, state);
863969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                } catch (RemoteException e) {
864fea8dd45f4955b4b4b6536bf51453e19288deba2Jae Seo                    Slog.e(TAG, "failed to report state change to callback", e);
865969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                }
866969167dc05a6485a32d160895871cff46fd81884Wonsik Kim            }
867969167dc05a6485a32d160895871cff46fd81884Wonsik Kim        } else {
8682b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim            try {
869969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                targetCallback.onInputStateChanged(inputId, state);
8702b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim            } catch (RemoteException e) {
871fea8dd45f4955b4b4b6536bf51453e19288deba2Jae Seo                Slog.e(TAG, "failed to report state change to callback", e);
8722b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim            }
8732b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim        }
8742b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim    }
8752b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim
876969167dc05a6485a32d160895871cff46fd81884Wonsik Kim    private void setStateLocked(String inputId, int state, int userId) {
877969167dc05a6485a32d160895871cff46fd81884Wonsik Kim        UserState userState = getUserStateLocked(userId);
878969167dc05a6485a32d160895871cff46fd81884Wonsik Kim        TvInputState inputState = userState.inputMap.get(inputId);
879c88f1916b8ab7f5f75a00375c6fb4873ea5044afJi-Hwan Lee        ServiceState serviceState = userState.serviceStateMap.get(inputState.mInfo.getComponent());
880969167dc05a6485a32d160895871cff46fd81884Wonsik Kim        int oldState = inputState.mState;
881969167dc05a6485a32d160895871cff46fd81884Wonsik Kim        inputState.mState = state;
882187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim        if (serviceState != null && serviceState.mService == null
883187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                && shouldMaintainConnection(serviceState)) {
884969167dc05a6485a32d160895871cff46fd81884Wonsik Kim            // We don't notify state change while reconnecting. It should remain disconnected.
885969167dc05a6485a32d160895871cff46fd81884Wonsik Kim            return;
886969167dc05a6485a32d160895871cff46fd81884Wonsik Kim        }
887969167dc05a6485a32d160895871cff46fd81884Wonsik Kim        if (oldState != state) {
8888e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim            notifyInputStateChangedLocked(userState, inputId, state, null);
889969167dc05a6485a32d160895871cff46fd81884Wonsik Kim        }
890969167dc05a6485a32d160895871cff46fd81884Wonsik Kim    }
891969167dc05a6485a32d160895871cff46fd81884Wonsik Kim
8923957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    private final class BinderService extends ITvInputManager.Stub {
8933957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        @Override
8943957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        public List<TvInputInfo> getTvInputList(int userId) {
8953957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(),
8963957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    Binder.getCallingUid(), userId, "getTvInputList");
8973957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            final long identity = Binder.clearCallingIdentity();
8983957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            try {
8993957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                synchronized (mLock) {
9003957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    UserState userState = getUserStateLocked(resolvedUserId);
901969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                    List<TvInputInfo> inputList = new ArrayList<TvInputInfo>();
902969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                    for (TvInputState state : userState.inputMap.values()) {
903969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                        inputList.add(state.mInfo);
9043957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    }
905969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                    return inputList;
9063957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                }
9073957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            } finally {
9083957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                Binder.restoreCallingIdentity(identity);
9093957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            }
910b375805f3b1672e68d1511565af4700e5fa8491dJae Seo        }
911b375805f3b1672e68d1511565af4700e5fa8491dJae Seo
912b375805f3b1672e68d1511565af4700e5fa8491dJae Seo        @Override
913b375805f3b1672e68d1511565af4700e5fa8491dJae Seo        public TvInputInfo getTvInputInfo(String inputId, int userId) {
914b375805f3b1672e68d1511565af4700e5fa8491dJae Seo            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(),
915b375805f3b1672e68d1511565af4700e5fa8491dJae Seo                    Binder.getCallingUid(), userId, "getTvInputInfo");
916b375805f3b1672e68d1511565af4700e5fa8491dJae Seo            final long identity = Binder.clearCallingIdentity();
917b375805f3b1672e68d1511565af4700e5fa8491dJae Seo            try {
918b375805f3b1672e68d1511565af4700e5fa8491dJae Seo                synchronized (mLock) {
919b375805f3b1672e68d1511565af4700e5fa8491dJae Seo                    UserState userState = getUserStateLocked(resolvedUserId);
920b375805f3b1672e68d1511565af4700e5fa8491dJae Seo                    TvInputState state = userState.inputMap.get(inputId);
921b375805f3b1672e68d1511565af4700e5fa8491dJae Seo                    return state == null ? null : state.mInfo;
922b375805f3b1672e68d1511565af4700e5fa8491dJae Seo                }
923b375805f3b1672e68d1511565af4700e5fa8491dJae Seo            } finally {
924b375805f3b1672e68d1511565af4700e5fa8491dJae Seo                Binder.restoreCallingIdentity(identity);
925b375805f3b1672e68d1511565af4700e5fa8491dJae Seo            }
9263957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
9273957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
9283957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        @Override
9299c165d6e9a2f085fbdc87b9221f2d52d851b2652Jae Seo        public List<TvContentRatingSystemInfo> getTvContentRatingSystemList(int userId) {
9305c5b83fcd58d21c9ab7ac986bf84f604ec5bb4b5Sungsoo Lim            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(),
9319c165d6e9a2f085fbdc87b9221f2d52d851b2652Jae Seo                    Binder.getCallingUid(), userId, "getTvContentRatingSystemList");
9325c5b83fcd58d21c9ab7ac986bf84f604ec5bb4b5Sungsoo Lim            final long identity = Binder.clearCallingIdentity();
9335c5b83fcd58d21c9ab7ac986bf84f604ec5bb4b5Sungsoo Lim            try {
9345c5b83fcd58d21c9ab7ac986bf84f604ec5bb4b5Sungsoo Lim                synchronized (mLock) {
9355c5b83fcd58d21c9ab7ac986bf84f604ec5bb4b5Sungsoo Lim                    UserState userState = getUserStateLocked(resolvedUserId);
9369c165d6e9a2f085fbdc87b9221f2d52d851b2652Jae Seo                    return userState.contentRatingSystemList;
9375c5b83fcd58d21c9ab7ac986bf84f604ec5bb4b5Sungsoo Lim                }
9385c5b83fcd58d21c9ab7ac986bf84f604ec5bb4b5Sungsoo Lim            } finally {
9395c5b83fcd58d21c9ab7ac986bf84f604ec5bb4b5Sungsoo Lim                Binder.restoreCallingIdentity(identity);
9405c5b83fcd58d21c9ab7ac986bf84f604ec5bb4b5Sungsoo Lim            }
9415c5b83fcd58d21c9ab7ac986bf84f604ec5bb4b5Sungsoo Lim        }
9425c5b83fcd58d21c9ab7ac986bf84f604ec5bb4b5Sungsoo Lim
9435c5b83fcd58d21c9ab7ac986bf84f604ec5bb4b5Sungsoo Lim        @Override
944969167dc05a6485a32d160895871cff46fd81884Wonsik Kim        public void registerCallback(final ITvInputManagerCallback callback, int userId) {
9453957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(),
9463957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    Binder.getCallingUid(), userId, "registerCallback");
9473957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            final long identity = Binder.clearCallingIdentity();
9483957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            try {
9493957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                synchronized (mLock) {
950fea8dd45f4955b4b4b6536bf51453e19288deba2Jae Seo                    final UserState userState = getUserStateLocked(resolvedUserId);
951969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                    userState.callbackSet.add(callback);
952fea8dd45f4955b4b4b6536bf51453e19288deba2Jae Seo                    try {
953fea8dd45f4955b4b4b6536bf51453e19288deba2Jae Seo                        callback.asBinder().linkToDeath(new IBinder.DeathRecipient() {
954fea8dd45f4955b4b4b6536bf51453e19288deba2Jae Seo                            @Override
955fea8dd45f4955b4b4b6536bf51453e19288deba2Jae Seo                            public void binderDied() {
956fea8dd45f4955b4b4b6536bf51453e19288deba2Jae Seo                                synchronized (mLock) {
957fea8dd45f4955b4b4b6536bf51453e19288deba2Jae Seo                                    if (userState.callbackSet != null) {
958fea8dd45f4955b4b4b6536bf51453e19288deba2Jae Seo                                        userState.callbackSet.remove(callback);
959fea8dd45f4955b4b4b6536bf51453e19288deba2Jae Seo                                    }
960fea8dd45f4955b4b4b6536bf51453e19288deba2Jae Seo                                }
961fea8dd45f4955b4b4b6536bf51453e19288deba2Jae Seo                            }
962fea8dd45f4955b4b4b6536bf51453e19288deba2Jae Seo                        }, 0);
963fea8dd45f4955b4b4b6536bf51453e19288deba2Jae Seo                    } catch (RemoteException e) {
964fea8dd45f4955b4b4b6536bf51453e19288deba2Jae Seo                        Slog.e(TAG, "client process has already died", e);
965fea8dd45f4955b4b4b6536bf51453e19288deba2Jae Seo                    }
966969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                    for (TvInputState state : userState.inputMap.values()) {
9678e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim                        notifyInputStateChangedLocked(userState, state.mInfo.getId(),
968969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                                state.mState, callback);
9693957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    }
9703957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                }
9713957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            } finally {
9723957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                Binder.restoreCallingIdentity(identity);
9733957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            }
9743957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
9753957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
9763957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        @Override
977969167dc05a6485a32d160895871cff46fd81884Wonsik Kim        public void unregisterCallback(ITvInputManagerCallback callback, int userId) {
9783957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(),
9793957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    Binder.getCallingUid(), userId, "unregisterCallback");
9803957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            final long identity = Binder.clearCallingIdentity();
9813957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            try {
9823957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                synchronized (mLock) {
983969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                    UserState userState = getUserStateLocked(resolvedUserId);
984969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                    userState.callbackSet.remove(callback);
9853957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                }
9863957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            } finally {
9873957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                Binder.restoreCallingIdentity(identity);
9883957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            }
9893957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
9903957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
9913957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        @Override
992783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo        public boolean isParentalControlsEnabled(int userId) {
993783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(),
994783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                    Binder.getCallingUid(), userId, "isParentalControlsEnabled");
995783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo            final long identity = Binder.clearCallingIdentity();
996783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo            try {
997783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                synchronized (mLock) {
998783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                    UserState userState = getUserStateLocked(resolvedUserId);
999783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                    return userState.persistentDataStore.isParentalControlsEnabled();
1000783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                }
1001783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo            } finally {
1002783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                Binder.restoreCallingIdentity(identity);
1003783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo            }
1004783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo        }
1005783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo
1006783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo        @Override
1007783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo        public void setParentalControlsEnabled(boolean enabled, int userId) {
1008783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo            ensureParentalControlsPermission();
1009783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(),
1010783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                    Binder.getCallingUid(), userId, "setParentalControlsEnabled");
1011783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo            final long identity = Binder.clearCallingIdentity();
1012783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo            try {
1013783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                synchronized (mLock) {
1014783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                    UserState userState = getUserStateLocked(resolvedUserId);
1015783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                    userState.persistentDataStore.setParentalControlsEnabled(enabled);
1016783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                }
1017783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo            } finally {
1018783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                Binder.restoreCallingIdentity(identity);
1019783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo            }
1020783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo        }
1021783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo
1022783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo        @Override
1023783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo        public boolean isRatingBlocked(String rating, int userId) {
1024783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(),
1025783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                    Binder.getCallingUid(), userId, "isRatingBlocked");
1026783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo            final long identity = Binder.clearCallingIdentity();
1027783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo            try {
1028783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                synchronized (mLock) {
1029783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                    UserState userState = getUserStateLocked(resolvedUserId);
1030783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                    return userState.persistentDataStore.isRatingBlocked(
1031783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                            TvContentRating.unflattenFromString(rating));
1032783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                }
1033783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo            } finally {
1034783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                Binder.restoreCallingIdentity(identity);
1035783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo            }
1036783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo        }
1037783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo
1038783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo        @Override
1039783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo        public List<String> getBlockedRatings(int userId) {
1040783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(),
1041783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                    Binder.getCallingUid(), userId, "getBlockedRatings");
1042783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo            final long identity = Binder.clearCallingIdentity();
1043783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo            try {
1044783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                synchronized (mLock) {
1045783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                    UserState userState = getUserStateLocked(resolvedUserId);
1046783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                    List<String> ratings = new ArrayList<String>();
1047783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                    for (TvContentRating rating
1048783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                            : userState.persistentDataStore.getBlockedRatings()) {
1049783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                        ratings.add(rating.flattenToString());
1050783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                    }
1051783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                    return ratings;
1052783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                }
1053783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo            } finally {
1054783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                Binder.restoreCallingIdentity(identity);
1055783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo            }
1056783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo        }
1057783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo
1058783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo        @Override
1059783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo        public void addBlockedRating(String rating, int userId) {
1060783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo            ensureParentalControlsPermission();
1061783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(),
1062783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                    Binder.getCallingUid(), userId, "addBlockedRating");
1063783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo            final long identity = Binder.clearCallingIdentity();
1064783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo            try {
1065783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                synchronized (mLock) {
1066783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                    UserState userState = getUserStateLocked(resolvedUserId);
1067783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                    userState.persistentDataStore.addBlockedRating(
1068783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                            TvContentRating.unflattenFromString(rating));
1069783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                }
1070783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo            } finally {
1071783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                Binder.restoreCallingIdentity(identity);
1072783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo            }
1073783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo        }
1074783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo
1075783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo        @Override
1076783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo        public void removeBlockedRating(String rating, int userId) {
1077783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo            ensureParentalControlsPermission();
1078783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(),
1079783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                    Binder.getCallingUid(), userId, "removeBlockedRating");
1080783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo            final long identity = Binder.clearCallingIdentity();
1081783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo            try {
1082783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                synchronized (mLock) {
1083783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                    UserState userState = getUserStateLocked(resolvedUserId);
1084783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                    userState.persistentDataStore.removeBlockedRating(
1085783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                            TvContentRating.unflattenFromString(rating));
1086783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                }
1087783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo            } finally {
1088783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                Binder.restoreCallingIdentity(identity);
1089783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo            }
1090783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo        }
1091783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo
1092783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo        private void ensureParentalControlsPermission() {
1093fc836f6684f6e142fe53dc16e1552ffd19bd95bcJae Seo            if (mContext.checkCallingPermission(
1094fc836f6684f6e142fe53dc16e1552ffd19bd95bcJae Seo                    android.Manifest.permission.MODIFY_PARENTAL_CONTROLS)
1095fc836f6684f6e142fe53dc16e1552ffd19bd95bcJae Seo                    != PackageManager.PERMISSION_GRANTED) {
1096fc836f6684f6e142fe53dc16e1552ffd19bd95bcJae Seo                throw new SecurityException(
1097fc836f6684f6e142fe53dc16e1552ffd19bd95bcJae Seo                        "The caller does not have parental controls permission");
1098fc836f6684f6e142fe53dc16e1552ffd19bd95bcJae Seo            }
1099783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo        }
1100783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo
1101783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo        @Override
1102d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim        public void createSession(final ITvInputClient client, final String inputId,
11033957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                int seq, int userId) {
11043957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            final int callingUid = Binder.getCallingUid();
11053957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
11063957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    userId, "createSession");
11073957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            final long identity = Binder.clearCallingIdentity();
11083957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            try {
11093957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                synchronized (mLock) {
11103957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    UserState userState = getUserStateLocked(resolvedUserId);
1111426c9a4008b75b93cbfea15aa4b8c47c5fdb49b9Dongwon Kang                    TvInputState inputState = userState.inputMap.get(inputId);
1112426c9a4008b75b93cbfea15aa4b8c47c5fdb49b9Dongwon Kang                    if (inputState == null) {
1113426c9a4008b75b93cbfea15aa4b8c47c5fdb49b9Dongwon Kang                        Slog.w(TAG, "Failed to find input state for inputId=" + inputId);
1114426c9a4008b75b93cbfea15aa4b8c47c5fdb49b9Dongwon Kang                        sendSessionTokenToClientLocked(client, inputId, null, null, seq);
1115426c9a4008b75b93cbfea15aa4b8c47c5fdb49b9Dongwon Kang                        return;
1116426c9a4008b75b93cbfea15aa4b8c47c5fdb49b9Dongwon Kang                    }
1117426c9a4008b75b93cbfea15aa4b8c47c5fdb49b9Dongwon Kang                    TvInputInfo info = inputState.mInfo;
1118187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                    ServiceState serviceState = userState.serviceStateMap.get(info.getComponent());
11193957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    if (serviceState == null) {
1120187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                        serviceState = new ServiceState(info.getComponent(), resolvedUserId);
1121187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                        userState.serviceStateMap.put(info.getComponent(), serviceState);
11223957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    }
11232b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                    // Send a null token immediately while reconnecting.
11242b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                    if (serviceState.mReconnecting == true) {
11255c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo                        sendSessionTokenToClientLocked(client, inputId, null, null, seq);
11262b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                        return;
11272b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                    }
11282b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim
11292b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                    // Create a new session token and a session state.
11302b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                    IBinder sessionToken = new Binder();
1131187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                    SessionState sessionState = new SessionState(sessionToken, info, client,
113272ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim                            seq, callingUid, resolvedUserId);
11332b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim
11342b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                    // Add them to the global session state map of the current user.
11352b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                    userState.sessionStateMap.put(sessionToken, sessionState);
11362b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim
11372b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                    // Also, add them to the session state map of the current service.
1138d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim                    serviceState.mSessionTokens.add(sessionToken);
11393957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
1140d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim                    if (serviceState.mService != null) {
1141d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim                        createSessionInternalLocked(serviceState.mService, sessionToken,
11427de5e234715a3baa8905afa3dd0c5009af64541fSungsoo Lim                                resolvedUserId);
11433957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    } else {
1144187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                        updateServiceConnectionLocked(info.getComponent(), resolvedUserId);
11453957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    }
11463957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                }
11473957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            } finally {
11483957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                Binder.restoreCallingIdentity(identity);
11493957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            }
11503957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
11513957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
11523957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        @Override
11533957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        public void releaseSession(IBinder sessionToken, int userId) {
115415c56aac985bc8d75f38fb4ecb92dda12d2ca06cJi-Hwan Lee            if (DEBUG) {
1155fea8dd45f4955b4b4b6536bf51453e19288deba2Jae Seo                Slog.d(TAG, "releaseSession(sessionToken=" + sessionToken + ")");
115615c56aac985bc8d75f38fb4ecb92dda12d2ca06cJi-Hwan Lee            }
11573957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            final int callingUid = Binder.getCallingUid();
11583957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
11593957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    userId, "releaseSession");
11603957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            final long identity = Binder.clearCallingIdentity();
11613957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            try {
11623957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                synchronized (mLock) {
11632b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                    releaseSessionLocked(sessionToken, callingUid, resolvedUserId);
11643957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                }
11653957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            } finally {
11663957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                Binder.restoreCallingIdentity(identity);
11673957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            }
11683957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
11693957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
11703957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        @Override
11714c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee        public void setMainSession(IBinder sessionToken, int userId) {
117215c56aac985bc8d75f38fb4ecb92dda12d2ca06cJi-Hwan Lee            if (DEBUG) {
1173fea8dd45f4955b4b4b6536bf51453e19288deba2Jae Seo                Slog.d(TAG, "setMainSession(sessionToken=" + sessionToken + ")");
117415c56aac985bc8d75f38fb4ecb92dda12d2ca06cJi-Hwan Lee            }
11754c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee            final int callingUid = Binder.getCallingUid();
11764c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
11774c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee                    userId, "setMainSession");
11784c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee            final long identity = Binder.clearCallingIdentity();
11794c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee            try {
11804c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee                synchronized (mLock) {
1181982abe693f66037ca265b88057eceb5a3e815182Ji-Hwan Lee                    UserState userState = getUserStateLocked(resolvedUserId);
1182956afc2ba79f50bb8025c6d334653e3c3419b480Ji-Hwan Lee                    if (userState.mainSessionToken == sessionToken) {
11834c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee                        return;
11844c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee                    }
118515c56aac985bc8d75f38fb4ecb92dda12d2ca06cJi-Hwan Lee                    if (DEBUG) {
118615c56aac985bc8d75f38fb4ecb92dda12d2ca06cJi-Hwan Lee                        Slog.d(TAG, "mainSessionToken=" + sessionToken);
1187abca0ee7949f59e72b8d2764dafa23af18eb51dbJi-Hwan Lee                    }
118815c56aac985bc8d75f38fb4ecb92dda12d2ca06cJi-Hwan Lee                    IBinder oldMainSessionToken = userState.mainSessionToken;
11894c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee                    userState.mainSessionToken = sessionToken;
11904c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee
1191956afc2ba79f50bb8025c6d334653e3c3419b480Ji-Hwan Lee                    // Inform the new main session first.
119215c56aac985bc8d75f38fb4ecb92dda12d2ca06cJi-Hwan Lee                    // See {@link TvInputService.Session#onSetMain}.
119315c56aac985bc8d75f38fb4ecb92dda12d2ca06cJi-Hwan Lee                    if (sessionToken != null) {
119415c56aac985bc8d75f38fb4ecb92dda12d2ca06cJi-Hwan Lee                        setMainLocked(sessionToken, true, callingUid, userId);
11954c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee                    }
119615c56aac985bc8d75f38fb4ecb92dda12d2ca06cJi-Hwan Lee                    if (oldMainSessionToken != null) {
119715c56aac985bc8d75f38fb4ecb92dda12d2ca06cJi-Hwan Lee                        setMainLocked(oldMainSessionToken, false, Process.SYSTEM_UID, userId);
11984c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee                    }
11994c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee                }
12004c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee            } finally {
12014c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee                Binder.restoreCallingIdentity(identity);
12024c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee            }
12034c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee        }
12044c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee
12054c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee        @Override
12063957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        public void setSurface(IBinder sessionToken, Surface surface, int userId) {
12073957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            final int callingUid = Binder.getCallingUid();
12083957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
12093957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    userId, "setSurface");
12103957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            final long identity = Binder.clearCallingIdentity();
12113957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            try {
12123957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                synchronized (mLock) {
12133957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    try {
1214bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                        SessionState sessionState = getSessionStateLocked(sessionToken, callingUid,
1215bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                                resolvedUserId);
1216bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                        if (sessionState.mHardwareSessionToken == null) {
1217bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                            getSessionLocked(sessionState).setSurface(surface);
1218bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                        } else {
1219bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                            getSessionLocked(sessionState.mHardwareSessionToken,
1220bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                                    Process.SYSTEM_UID, resolvedUserId).setSurface(surface);
1221bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                        }
12223957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    } catch (RemoteException e) {
12239a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                        Slog.e(TAG, "error in setSurface", e);
12243957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    }
12253957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                }
12263957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            } finally {
1227f836206818ce338db83a3c23c486fb8cab29cb6dYoungsang Cho                if (surface != null) {
1228f836206818ce338db83a3c23c486fb8cab29cb6dYoungsang Cho                    // surface is not used in TvInputManagerService.
1229f836206818ce338db83a3c23c486fb8cab29cb6dYoungsang Cho                    surface.release();
1230f836206818ce338db83a3c23c486fb8cab29cb6dYoungsang Cho                }
12313957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                Binder.restoreCallingIdentity(identity);
12323957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            }
12333957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
12343957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
12353957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        @Override
1236e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho        public void dispatchSurfaceChanged(IBinder sessionToken, int format, int width,
1237e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho                int height, int userId) {
1238e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho            final int callingUid = Binder.getCallingUid();
1239e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
1240e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho                    userId, "dispatchSurfaceChanged");
1241e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho            final long identity = Binder.clearCallingIdentity();
1242e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho            try {
1243e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho                synchronized (mLock) {
1244e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho                    try {
1245bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                        SessionState sessionState = getSessionStateLocked(sessionToken, callingUid,
1246bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                                resolvedUserId);
1247bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                        getSessionLocked(sessionState).dispatchSurfaceChanged(format, width, height);
1248bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                        if (sessionState.mHardwareSessionToken != null) {
1249bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                            getSessionLocked(sessionState.mHardwareSessionToken, Process.SYSTEM_UID,
1250bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                                    resolvedUserId).dispatchSurfaceChanged(format, width, height);
1251bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                        }
1252e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho                    } catch (RemoteException e) {
1253e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho                        Slog.e(TAG, "error in dispatchSurfaceChanged", e);
1254e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho                    }
1255e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho                }
1256e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho            } finally {
1257e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho                Binder.restoreCallingIdentity(identity);
1258e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho            }
1259e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho        }
1260e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho
1261e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho        @Override
12623957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        public void setVolume(IBinder sessionToken, float volume, int userId) {
1263bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang            final float REMOTE_VOLUME_ON = 1.0f;
1264bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang            final float REMOTE_VOLUME_OFF = 0f;
12653957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            final int callingUid = Binder.getCallingUid();
12663957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
12673957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    userId, "setVolume");
12683957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            final long identity = Binder.clearCallingIdentity();
12693957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            try {
12703957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                synchronized (mLock) {
12713957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    try {
1272bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                        SessionState sessionState = getSessionStateLocked(sessionToken, callingUid,
1273bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                                resolvedUserId);
1274bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                        getSessionLocked(sessionState).setVolume(volume);
1275bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                        if (sessionState.mHardwareSessionToken != null) {
1276bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                            // Here, we let the hardware session know only whether volume is on or
1277bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                            // off to prevent that the volume is controlled in the both side.
1278bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                            getSessionLocked(sessionState.mHardwareSessionToken,
1279bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                                    Process.SYSTEM_UID, resolvedUserId).setVolume((volume > 0.0f)
1280bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                                            ? REMOTE_VOLUME_ON : REMOTE_VOLUME_OFF);
1281bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                        }
12823957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    } catch (RemoteException e) {
12839a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                        Slog.e(TAG, "error in setVolume", e);
12843957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    }
12853957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                }
12863957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            } finally {
12873957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                Binder.restoreCallingIdentity(identity);
12883957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            }
12893957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
12903957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
12913957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        @Override
12921a6b25eabcc1fb66e6e8d76f91fd413e18b793a9Sungsoo Lim        public void tune(IBinder sessionToken, final Uri channelUri, Bundle params, int userId) {
12933957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            final int callingUid = Binder.getCallingUid();
12943957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
12953957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    userId, "tune");
12963957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            final long identity = Binder.clearCallingIdentity();
12973957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            try {
12983957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                synchronized (mLock) {
12993957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    try {
13001a6b25eabcc1fb66e6e8d76f91fd413e18b793a9Sungsoo Lim                        getSessionLocked(sessionToken, callingUid, resolvedUserId).tune(
13011a6b25eabcc1fb66e6e8d76f91fd413e18b793a9Sungsoo Lim                                channelUri, params);
1302c22d0c0941ab65ca69977d002c4431394a735c7dJae Seo                        if (TvContract.isChannelUriForPassthroughInput(channelUri)) {
1303008f6d4e326f6372e165bdf342178ecd1e834e2fYoungsang Cho                            // Do not log the watch history for passthrough inputs.
1304008f6d4e326f6372e165bdf342178ecd1e834e2fYoungsang Cho                            return;
1305008f6d4e326f6372e165bdf342178ecd1e834e2fYoungsang Cho                        }
130631dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo
130731dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                        UserState userState = getUserStateLocked(resolvedUserId);
130831dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                        SessionState sessionState = userState.sessionStateMap.get(sessionToken);
130931dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo
13107eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo                        // Log the start of watch.
131131dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                        SomeArgs args = SomeArgs.obtain();
13127eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo                        args.arg1 = sessionState.mInfo.getComponent().getPackageName();
13137eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo                        args.arg2 = System.currentTimeMillis();
13147eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo                        args.arg3 = ContentUris.parseId(channelUri);
13157eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo                        args.arg4 = params;
13167eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo                        args.arg5 = sessionToken;
13177eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo                        mWatchLogHandler.obtainMessage(WatchLogHandler.MSG_LOG_WATCH_START, args)
13187eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo                                .sendToTarget();
13193957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    } catch (RemoteException e) {
13209a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                        Slog.e(TAG, "error in tune", e);
13213957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                        return;
13223957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    }
13233957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                }
13243957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            } finally {
13253957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                Binder.restoreCallingIdentity(identity);
13263957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            }
13273957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
13289a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho
13299a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho        @Override
13309bf671f8ee72b156f16fcf05a3d1c6e093ecba67Sungsoo Lim        public void requestUnblockContent(
13319bf671f8ee72b156f16fcf05a3d1c6e093ecba67Sungsoo Lim                IBinder sessionToken, String unblockedRating, int userId) {
1332903d6b72cd572665309633e925485464d08bb25aJaewan Kim            final int callingUid = Binder.getCallingUid();
1333903d6b72cd572665309633e925485464d08bb25aJaewan Kim            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
1334903d6b72cd572665309633e925485464d08bb25aJaewan Kim                    userId, "unblockContent");
1335903d6b72cd572665309633e925485464d08bb25aJaewan Kim            final long identity = Binder.clearCallingIdentity();
1336903d6b72cd572665309633e925485464d08bb25aJaewan Kim            try {
1337903d6b72cd572665309633e925485464d08bb25aJaewan Kim                synchronized (mLock) {
1338903d6b72cd572665309633e925485464d08bb25aJaewan Kim                    try {
1339903d6b72cd572665309633e925485464d08bb25aJaewan Kim                        getSessionLocked(sessionToken, callingUid, resolvedUserId)
13409bf671f8ee72b156f16fcf05a3d1c6e093ecba67Sungsoo Lim                                .requestUnblockContent(unblockedRating);
1341903d6b72cd572665309633e925485464d08bb25aJaewan Kim                    } catch (RemoteException e) {
1342fea8dd45f4955b4b4b6536bf51453e19288deba2Jae Seo                        Slog.e(TAG, "error in requestUnblockContent", e);
1343903d6b72cd572665309633e925485464d08bb25aJaewan Kim                    }
1344903d6b72cd572665309633e925485464d08bb25aJaewan Kim                }
1345903d6b72cd572665309633e925485464d08bb25aJaewan Kim            } finally {
1346903d6b72cd572665309633e925485464d08bb25aJaewan Kim                Binder.restoreCallingIdentity(identity);
1347903d6b72cd572665309633e925485464d08bb25aJaewan Kim            }
1348903d6b72cd572665309633e925485464d08bb25aJaewan Kim        }
1349903d6b72cd572665309633e925485464d08bb25aJaewan Kim
1350903d6b72cd572665309633e925485464d08bb25aJaewan Kim        @Override
13512c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo        public void setCaptionEnabled(IBinder sessionToken, boolean enabled, int userId) {
13522c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo            final int callingUid = Binder.getCallingUid();
13532c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
13542c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo                    userId, "setCaptionEnabled");
13552c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo            final long identity = Binder.clearCallingIdentity();
13562c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo            try {
13572c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo                synchronized (mLock) {
13582c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo                    try {
13592c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo                        getSessionLocked(sessionToken, callingUid, resolvedUserId)
13602c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo                                .setCaptionEnabled(enabled);
13612c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo                    } catch (RemoteException e) {
13622c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo                        Slog.e(TAG, "error in setCaptionEnabled", e);
13632c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo                    }
13642c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo                }
13652c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo            } finally {
13662c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo                Binder.restoreCallingIdentity(identity);
13672c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo            }
13682c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo        }
13692c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo
13702c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo        @Override
137110d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo        public void selectTrack(IBinder sessionToken, int type, String trackId, int userId) {
13721f213914c45c23c653f721690da2ce0718e63139Dongwon Kang            final int callingUid = Binder.getCallingUid();
13731f213914c45c23c653f721690da2ce0718e63139Dongwon Kang            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
13741f213914c45c23c653f721690da2ce0718e63139Dongwon Kang                    userId, "selectTrack");
13751f213914c45c23c653f721690da2ce0718e63139Dongwon Kang            final long identity = Binder.clearCallingIdentity();
13761f213914c45c23c653f721690da2ce0718e63139Dongwon Kang            try {
13771f213914c45c23c653f721690da2ce0718e63139Dongwon Kang                synchronized (mLock) {
13781f213914c45c23c653f721690da2ce0718e63139Dongwon Kang                    try {
13791f213914c45c23c653f721690da2ce0718e63139Dongwon Kang                        getSessionLocked(sessionToken, callingUid, resolvedUserId).selectTrack(
138010d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo                                type, trackId);
13811f213914c45c23c653f721690da2ce0718e63139Dongwon Kang                    } catch (RemoteException e) {
13821f213914c45c23c653f721690da2ce0718e63139Dongwon Kang                        Slog.e(TAG, "error in selectTrack", e);
13831f213914c45c23c653f721690da2ce0718e63139Dongwon Kang                    }
13841f213914c45c23c653f721690da2ce0718e63139Dongwon Kang                }
13851f213914c45c23c653f721690da2ce0718e63139Dongwon Kang            } finally {
13861f213914c45c23c653f721690da2ce0718e63139Dongwon Kang                Binder.restoreCallingIdentity(identity);
13871f213914c45c23c653f721690da2ce0718e63139Dongwon Kang            }
13881f213914c45c23c653f721690da2ce0718e63139Dongwon Kang        }
13891f213914c45c23c653f721690da2ce0718e63139Dongwon Kang
13901f213914c45c23c653f721690da2ce0718e63139Dongwon Kang        @Override
1391a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo        public void sendAppPrivateCommand(IBinder sessionToken, String command, Bundle data,
1392a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo                int userId) {
1393a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo            final int callingUid = Binder.getCallingUid();
1394a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
1395a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo                    userId, "sendAppPrivateCommand");
1396a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo            final long identity = Binder.clearCallingIdentity();
1397a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo            try {
1398a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo                synchronized (mLock) {
1399a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo                    try {
1400a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo                        getSessionLocked(sessionToken, callingUid, resolvedUserId)
1401a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo                                .appPrivateCommand(command, data);
1402a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo                    } catch (RemoteException e) {
1403fea8dd45f4955b4b4b6536bf51453e19288deba2Jae Seo                        Slog.e(TAG, "error in appPrivateCommand", e);
1404a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo                    }
1405a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo                }
1406a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo            } finally {
1407a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo                Binder.restoreCallingIdentity(identity);
1408a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo            }
1409a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo        }
1410a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo
1411a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo        @Override
14129a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho        public void createOverlayView(IBinder sessionToken, IBinder windowToken, Rect frame,
14139a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                int userId) {
14149a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            final int callingUid = Binder.getCallingUid();
14159a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
14169a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                    userId, "createOverlayView");
14179a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            final long identity = Binder.clearCallingIdentity();
14189a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            try {
14199a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                synchronized (mLock) {
14209a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                    try {
14219a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                        getSessionLocked(sessionToken, callingUid, resolvedUserId)
14229a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                                .createOverlayView(windowToken, frame);
14239a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                    } catch (RemoteException e) {
14249a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                        Slog.e(TAG, "error in createOverlayView", e);
14259a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                    }
14269a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                }
14279a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            } finally {
14289a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                Binder.restoreCallingIdentity(identity);
14299a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            }
14309a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho        }
14319a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho
14329a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho        @Override
14339a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho        public void relayoutOverlayView(IBinder sessionToken, Rect frame, int userId) {
14349a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            final int callingUid = Binder.getCallingUid();
14359a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
14369a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                    userId, "relayoutOverlayView");
14379a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            final long identity = Binder.clearCallingIdentity();
14389a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            try {
14399a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                synchronized (mLock) {
14409a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                    try {
14419a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                        getSessionLocked(sessionToken, callingUid, resolvedUserId)
14429a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                                .relayoutOverlayView(frame);
14439a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                    } catch (RemoteException e) {
14449a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                        Slog.e(TAG, "error in relayoutOverlayView", e);
14459a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                    }
14469a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                }
14479a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            } finally {
14489a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                Binder.restoreCallingIdentity(identity);
14499a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            }
14509a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho        }
14519a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho
14529a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho        @Override
14539a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho        public void removeOverlayView(IBinder sessionToken, int userId) {
14549a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            final int callingUid = Binder.getCallingUid();
14559a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
14569a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                    userId, "removeOverlayView");
14579a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            final long identity = Binder.clearCallingIdentity();
14589a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            try {
14599a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                synchronized (mLock) {
14609a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                    try {
14619a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                        getSessionLocked(sessionToken, callingUid, resolvedUserId)
14629a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                                .removeOverlayView();
14639a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                    } catch (RemoteException e) {
14649a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                        Slog.e(TAG, "error in removeOverlayView", e);
14659a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                    }
14669a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                }
14679a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            } finally {
14689a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                Binder.restoreCallingIdentity(identity);
14699a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            }
14709a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho        }
1471c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim
1472c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim        @Override
1473c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim        public List<TvInputHardwareInfo> getHardwareList() throws RemoteException {
1474969167dc05a6485a32d160895871cff46fd81884Wonsik Kim            if (mContext.checkCallingPermission(android.Manifest.permission.TV_INPUT_HARDWARE)
1475c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim                    != PackageManager.PERMISSION_GRANTED) {
1476c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim                return null;
1477c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim            }
1478c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim
1479c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim            final long identity = Binder.clearCallingIdentity();
1480c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim            try {
1481c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim                return mTvInputHardwareManager.getHardwareList();
1482c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim            } finally {
1483c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim                Binder.restoreCallingIdentity(identity);
1484c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim            }
1485c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim        }
1486c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim
1487c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim        @Override
1488c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim        public ITvInputHardware acquireTvInputHardware(int deviceId,
1489969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                ITvInputHardwareCallback callback, TvInputInfo info, int userId)
1490969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                throws RemoteException {
1491969167dc05a6485a32d160895871cff46fd81884Wonsik Kim            if (mContext.checkCallingPermission(android.Manifest.permission.TV_INPUT_HARDWARE)
1492c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim                    != PackageManager.PERMISSION_GRANTED) {
1493c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim                return null;
1494c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim            }
1495c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim
1496c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim            final long identity = Binder.clearCallingIdentity();
1497c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim            final int callingUid = Binder.getCallingUid();
1498c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
1499c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim                    userId, "acquireTvInputHardware");
1500c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim            try {
1501c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim                return mTvInputHardwareManager.acquireHardware(
1502969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                        deviceId, callback, info, callingUid, resolvedUserId);
1503c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim            } finally {
1504c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim                Binder.restoreCallingIdentity(identity);
1505c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim            }
1506c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim        }
1507c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim
1508c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim        @Override
1509c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim        public void releaseTvInputHardware(int deviceId, ITvInputHardware hardware, int userId)
1510c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim                throws RemoteException {
1511969167dc05a6485a32d160895871cff46fd81884Wonsik Kim            if (mContext.checkCallingPermission(android.Manifest.permission.TV_INPUT_HARDWARE)
1512c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim                    != PackageManager.PERMISSION_GRANTED) {
1513c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim                return;
1514c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim            }
1515c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim
1516c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim            final long identity = Binder.clearCallingIdentity();
1517c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim            final int callingUid = Binder.getCallingUid();
1518c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
1519c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim                    userId, "releaseTvInputHardware");
1520c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim            try {
1521c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim                mTvInputHardwareManager.releaseHardware(
1522c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim                        deviceId, hardware, callingUid, resolvedUserId);
1523c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim            } finally {
1524c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim                Binder.restoreCallingIdentity(identity);
1525c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim            }
1526c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim        }
1527e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim
1528e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim        @Override
1529c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo        public List<TvStreamConfig> getAvailableTvStreamConfigList(String inputId, int userId)
1530c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo                throws RemoteException {
1531c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo            if (mContext.checkCallingPermission(
1532c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo                    android.Manifest.permission.CAPTURE_TV_INPUT)
1533c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo                    != PackageManager.PERMISSION_GRANTED) {
1534c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo                throw new SecurityException("Requires CAPTURE_TV_INPUT permission");
1535c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo            }
1536c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo
1537c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo            final long identity = Binder.clearCallingIdentity();
1538c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo            final int callingUid = Binder.getCallingUid();
1539c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
1540c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo                    userId, "getAvailableTvStreamConfigList");
1541c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo            try {
1542c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo                return mTvInputHardwareManager.getAvailableTvStreamConfigList(
1543c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo                        inputId, callingUid, resolvedUserId);
1544c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo            } finally {
1545c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo                Binder.restoreCallingIdentity(identity);
1546c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo            }
1547c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo        }
1548c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo
1549c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo        @Override
1550c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo        public boolean captureFrame(String inputId, Surface surface, TvStreamConfig config,
1551c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo                int userId)
1552c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo                throws RemoteException {
1553c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo            if (mContext.checkCallingPermission(
1554c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo                    android.Manifest.permission.CAPTURE_TV_INPUT)
1555c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo                    != PackageManager.PERMISSION_GRANTED) {
1556c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo                throw new SecurityException("Requires CAPTURE_TV_INPUT permission");
1557c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo            }
1558c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo
1559c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo            final long identity = Binder.clearCallingIdentity();
1560c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo            final int callingUid = Binder.getCallingUid();
1561c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
1562c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo                    userId, "captureFrame");
1563c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo            try {
1564bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                String hardwareInputId = null;
156579124a717c09f12c74d587d3977bf33ca37e6420Terry Heo                synchronized (mLock) {
156679124a717c09f12c74d587d3977bf33ca37e6420Terry Heo                    UserState userState = getUserStateLocked(resolvedUserId);
1567bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                    if (userState.inputMap.get(inputId) == null) {
1568fea8dd45f4955b4b4b6536bf51453e19288deba2Jae Seo                        Slog.e(TAG, "input not found for " + inputId);
1569bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                        return false;
1570bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                    }
1571bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                    for (SessionState sessionState : userState.sessionStateMap.values()) {
1572bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                        if (sessionState.mInfo.getId().equals(inputId)
1573bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                                && sessionState.mHardwareSessionToken != null) {
1574bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                            hardwareInputId = userState.sessionStateMap.get(
1575bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                                    sessionState.mHardwareSessionToken).mInfo.getId();
1576bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                            break;
1577bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                        }
1578bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                    }
157979124a717c09f12c74d587d3977bf33ca37e6420Terry Heo                }
1580c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo                return mTvInputHardwareManager.captureFrame(
1581bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                        (hardwareInputId != null) ? hardwareInputId : inputId,
158279124a717c09f12c74d587d3977bf33ca37e6420Terry Heo                        surface, config, callingUid, resolvedUserId);
1583c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo            } finally {
1584c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo                Binder.restoreCallingIdentity(identity);
1585c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo            }
1586c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo        }
1587c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo
1588c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo        @Override
1589df9f0a321e0cb2958c9d170395a0367a106fa0e6Terry Heo        public boolean isSingleSessionActive(int userId) throws RemoteException {
1590df9f0a321e0cb2958c9d170395a0367a106fa0e6Terry Heo            final long identity = Binder.clearCallingIdentity();
1591df9f0a321e0cb2958c9d170395a0367a106fa0e6Terry Heo            final int callingUid = Binder.getCallingUid();
1592df9f0a321e0cb2958c9d170395a0367a106fa0e6Terry Heo            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
1593df9f0a321e0cb2958c9d170395a0367a106fa0e6Terry Heo                    userId, "isSingleSessionActive");
1594df9f0a321e0cb2958c9d170395a0367a106fa0e6Terry Heo            try {
1595df9f0a321e0cb2958c9d170395a0367a106fa0e6Terry Heo                synchronized (mLock) {
1596df9f0a321e0cb2958c9d170395a0367a106fa0e6Terry Heo                    UserState userState = getUserStateLocked(resolvedUserId);
1597df9f0a321e0cb2958c9d170395a0367a106fa0e6Terry Heo                    if (userState.sessionStateMap.size() == 1) {
1598df9f0a321e0cb2958c9d170395a0367a106fa0e6Terry Heo                        return true;
1599df9f0a321e0cb2958c9d170395a0367a106fa0e6Terry Heo                    }
1600df9f0a321e0cb2958c9d170395a0367a106fa0e6Terry Heo                    else if (userState.sessionStateMap.size() == 2) {
1601df9f0a321e0cb2958c9d170395a0367a106fa0e6Terry Heo                        SessionState[] sessionStates = userState.sessionStateMap.values().toArray(
1602df9f0a321e0cb2958c9d170395a0367a106fa0e6Terry Heo                                new SessionState[0]);
1603df9f0a321e0cb2958c9d170395a0367a106fa0e6Terry Heo                        // Check if there is a wrapper input.
1604df9f0a321e0cb2958c9d170395a0367a106fa0e6Terry Heo                        if (sessionStates[0].mHardwareSessionToken != null
1605df9f0a321e0cb2958c9d170395a0367a106fa0e6Terry Heo                                || sessionStates[1].mHardwareSessionToken != null) {
1606df9f0a321e0cb2958c9d170395a0367a106fa0e6Terry Heo                            return true;
1607df9f0a321e0cb2958c9d170395a0367a106fa0e6Terry Heo                        }
1608df9f0a321e0cb2958c9d170395a0367a106fa0e6Terry Heo                    }
1609df9f0a321e0cb2958c9d170395a0367a106fa0e6Terry Heo                    return false;
1610df9f0a321e0cb2958c9d170395a0367a106fa0e6Terry Heo                }
1611df9f0a321e0cb2958c9d170395a0367a106fa0e6Terry Heo            } finally {
1612df9f0a321e0cb2958c9d170395a0367a106fa0e6Terry Heo                Binder.restoreCallingIdentity(identity);
1613df9f0a321e0cb2958c9d170395a0367a106fa0e6Terry Heo            }
1614df9f0a321e0cb2958c9d170395a0367a106fa0e6Terry Heo        }
1615df9f0a321e0cb2958c9d170395a0367a106fa0e6Terry Heo
1616df9f0a321e0cb2958c9d170395a0367a106fa0e6Terry Heo        @Override
16170f8fc345ea61928265fdd6d461bf1babe353fbe4Jae Seo        @SuppressWarnings("resource")
1618e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim        protected void dump(FileDescriptor fd, final PrintWriter writer, String[] args) {
1619e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim            final IndentingPrintWriter pw = new IndentingPrintWriter(writer, "  ");
16200f8fc345ea61928265fdd6d461bf1babe353fbe4Jae Seo            if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
1621e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                    != PackageManager.PERMISSION_GRANTED) {
16220f8fc345ea61928265fdd6d461bf1babe353fbe4Jae Seo                pw.println("Permission Denial: can't dump TvInputManager from pid="
16230f8fc345ea61928265fdd6d461bf1babe353fbe4Jae Seo                        + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid());
1624e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                return;
1625e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim            }
1626e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim
1627e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim            synchronized (mLock) {
1628e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                pw.println("User Ids (Current user: " + mCurrentUserId + "):");
1629e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                pw.increaseIndent();
1630e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                for (int i = 0; i < mUserStates.size(); i++) {
1631e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                    int userId = mUserStates.keyAt(i);
1632e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                    pw.println(Integer.valueOf(userId));
1633e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                }
1634e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                pw.decreaseIndent();
1635e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim
1636e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                for (int i = 0; i < mUserStates.size(); i++) {
1637e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                    int userId = mUserStates.keyAt(i);
1638e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                    UserState userState = getUserStateLocked(userId);
1639e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                    pw.println("UserState (" + userId + "):");
1640e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                    pw.increaseIndent();
1641e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim
1642969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                    pw.println("inputMap: inputId -> TvInputState");
1643e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                    pw.increaseIndent();
16448e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim                    for (Map.Entry<String, TvInputState> entry: userState.inputMap.entrySet()) {
16458e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim                        pw.println(entry.getKey() + ": " + entry.getValue());
1646e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                    }
1647e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                    pw.decreaseIndent();
1648e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim
1649969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                    pw.println("packageSet:");
1650e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                    pw.increaseIndent();
1651969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                    for (String packageName : userState.packageSet) {
1652e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        pw.println(packageName);
1653e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                    }
1654e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                    pw.decreaseIndent();
1655e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim
1656e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                    pw.println("clientStateMap: ITvInputClient -> ClientState");
1657e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                    pw.increaseIndent();
1658e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                    for (Map.Entry<IBinder, ClientState> entry :
1659e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                            userState.clientStateMap.entrySet()) {
1660e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        ClientState client = entry.getValue();
1661e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        pw.println(entry.getKey() + ": " + client);
1662e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim
1663e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        pw.increaseIndent();
1664e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim
1665e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        pw.println("mSessionTokens:");
1666e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        pw.increaseIndent();
1667e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        for (IBinder token : client.mSessionTokens) {
1668e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                            pw.println("" + token);
1669e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        }
1670e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        pw.decreaseIndent();
1671e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim
1672e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        pw.println("mClientTokens: " + client.mClientToken);
1673e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        pw.println("mUserId: " + client.mUserId);
1674e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim
1675e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        pw.decreaseIndent();
1676e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                    }
1677e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                    pw.decreaseIndent();
1678e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim
1679187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                    pw.println("serviceStateMap: ComponentName -> ServiceState");
1680e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                    pw.increaseIndent();
1681187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                    for (Map.Entry<ComponentName, ServiceState> entry :
1682e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                            userState.serviceStateMap.entrySet()) {
1683e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        ServiceState service = entry.getValue();
1684e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        pw.println(entry.getKey() + ": " + service);
1685e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim
1686e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        pw.increaseIndent();
1687e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim
1688e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        pw.println("mSessionTokens:");
1689e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        pw.increaseIndent();
1690e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        for (IBinder token : service.mSessionTokens) {
1691e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                            pw.println("" + token);
1692e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        }
1693e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        pw.decreaseIndent();
1694e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim
1695e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        pw.println("mService: " + service.mService);
1696e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        pw.println("mCallback: " + service.mCallback);
1697e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        pw.println("mBound: " + service.mBound);
1698e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        pw.println("mReconnecting: " + service.mReconnecting);
1699e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim
1700e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        pw.decreaseIndent();
1701e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                    }
1702e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                    pw.decreaseIndent();
1703e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim
1704e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                    pw.println("sessionStateMap: ITvInputSession -> SessionState");
1705e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                    pw.increaseIndent();
1706e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                    for (Map.Entry<IBinder, SessionState> entry :
1707e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                            userState.sessionStateMap.entrySet()) {
1708e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        SessionState session = entry.getValue();
1709e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        pw.println(entry.getKey() + ": " + session);
1710e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim
1711e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        pw.increaseIndent();
1712187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                        pw.println("mInfo: " + session.mInfo);
1713e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        pw.println("mClient: " + session.mClient);
1714e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        pw.println("mSeq: " + session.mSeq);
1715e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        pw.println("mCallingUid: " + session.mCallingUid);
1716e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        pw.println("mUserId: " + session.mUserId);
1717e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        pw.println("mSessionToken: " + session.mSessionToken);
1718e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        pw.println("mSession: " + session.mSession);
1719e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        pw.println("mLogUri: " + session.mLogUri);
1720bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                        pw.println("mHardwareSessionToken: " + session.mHardwareSessionToken);
1721e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        pw.decreaseIndent();
1722e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                    }
1723e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                    pw.decreaseIndent();
1724e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim
1725969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                    pw.println("callbackSet:");
1726969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                    pw.increaseIndent();
1727969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                    for (ITvInputManagerCallback callback : userState.callbackSet) {
1728969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                        pw.println(callback.toString());
1729969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                    }
1730969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                    pw.decreaseIndent();
1731969167dc05a6485a32d160895871cff46fd81884Wonsik Kim
1732956afc2ba79f50bb8025c6d334653e3c3419b480Ji-Hwan Lee                    pw.println("mainSessionToken: " + userState.mainSessionToken);
1733e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                    pw.decreaseIndent();
1734e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                }
1735e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim            }
1736e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim        }
17373957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    }
17383957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
1739969167dc05a6485a32d160895871cff46fd81884Wonsik Kim    private static final class TvInputState {
1740969167dc05a6485a32d160895871cff46fd81884Wonsik Kim        // A TvInputInfo object which represents the TV input.
1741969167dc05a6485a32d160895871cff46fd81884Wonsik Kim        private TvInputInfo mInfo;
1742969167dc05a6485a32d160895871cff46fd81884Wonsik Kim
1743969167dc05a6485a32d160895871cff46fd81884Wonsik Kim        // The state of TV input. Connected by default.
1744969167dc05a6485a32d160895871cff46fd81884Wonsik Kim        private int mState = INPUT_STATE_CONNECTED;
1745969167dc05a6485a32d160895871cff46fd81884Wonsik Kim
1746969167dc05a6485a32d160895871cff46fd81884Wonsik Kim        @Override
1747969167dc05a6485a32d160895871cff46fd81884Wonsik Kim        public String toString() {
1748969167dc05a6485a32d160895871cff46fd81884Wonsik Kim            return "mInfo: " + mInfo + "; mState: " + mState;
1749969167dc05a6485a32d160895871cff46fd81884Wonsik Kim        }
1750969167dc05a6485a32d160895871cff46fd81884Wonsik Kim    }
1751969167dc05a6485a32d160895871cff46fd81884Wonsik Kim
17523957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    private static final class UserState {
1753969167dc05a6485a32d160895871cff46fd81884Wonsik Kim        // A mapping from the TV input id to its TvInputState.
1754969167dc05a6485a32d160895871cff46fd81884Wonsik Kim        private Map<String, TvInputState> inputMap = new HashMap<String, TvInputState>();
17553957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
1756969167dc05a6485a32d160895871cff46fd81884Wonsik Kim        // A set of all TV input packages.
1757969167dc05a6485a32d160895871cff46fd81884Wonsik Kim        private final Set<String> packageSet = new HashSet<String>();
17585c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo
17599c165d6e9a2f085fbdc87b9221f2d52d851b2652Jae Seo        // A list of all TV content rating systems defined.
17609c165d6e9a2f085fbdc87b9221f2d52d851b2652Jae Seo        private final List<TvContentRatingSystemInfo>
17619c165d6e9a2f085fbdc87b9221f2d52d851b2652Jae Seo                contentRatingSystemList = new ArrayList<TvContentRatingSystemInfo>();
17625c5b83fcd58d21c9ab7ac986bf84f604ec5bb4b5Sungsoo Lim
176372ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim        // A mapping from the token of a client to its state.
176472ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim        private final Map<IBinder, ClientState> clientStateMap =
176572ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim                new HashMap<IBinder, ClientState>();
176672ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim
17673957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        // A mapping from the name of a TV input service to its state.
1768187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim        private final Map<ComponentName, ServiceState> serviceStateMap =
1769187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                new HashMap<ComponentName, ServiceState>();
17703957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
17713957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        // A mapping from the token of a TV input session to its state.
17723957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        private final Map<IBinder, SessionState> sessionStateMap =
17733957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                new HashMap<IBinder, SessionState>();
1774969167dc05a6485a32d160895871cff46fd81884Wonsik Kim
1775969167dc05a6485a32d160895871cff46fd81884Wonsik Kim        // A set of callbacks.
1776969167dc05a6485a32d160895871cff46fd81884Wonsik Kim        private final Set<ITvInputManagerCallback> callbackSet =
1777969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                new HashSet<ITvInputManagerCallback>();
177879124a717c09f12c74d587d3977bf33ca37e6420Terry Heo
17794c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee        // The token of a "main" TV input session.
17804c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee        private IBinder mainSessionToken = null;
1781783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo
1782783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo        // Persistent data store for all internal settings maintained by the TV input manager
1783783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo        // service.
1784783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo        private final PersistentDataStore persistentDataStore;
1785783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo
1786783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo        private UserState(Context context, int userId) {
1787783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo            persistentDataStore = new PersistentDataStore(context, userId);
1788783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo        }
17893957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    }
17903957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
179172ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim    private final class ClientState implements IBinder.DeathRecipient {
179272ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim        private final List<IBinder> mSessionTokens = new ArrayList<IBinder>();
179372ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim
179472ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim        private IBinder mClientToken;
179572ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim        private final int mUserId;
179672ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim
179772ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim        ClientState(IBinder clientToken, int userId) {
179872ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim            mClientToken = clientToken;
179972ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim            mUserId = userId;
180072ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim        }
180172ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim
180272ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim        public boolean isEmpty() {
1803a65118e13b5ceb54454b48f67ea754a38a08f27aJi-Hwan Lee            return mSessionTokens.isEmpty();
180472ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim        }
180572ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim
180672ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim        @Override
180772ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim        public void binderDied() {
180872ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim            synchronized (mLock) {
180972ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim                UserState userState = getUserStateLocked(mUserId);
181072ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim                // DO NOT remove the client state of clientStateMap in this method. It will be
1811a65118e13b5ceb54454b48f67ea754a38a08f27aJi-Hwan Lee                // removed in releaseSessionLocked().
181272ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim                ClientState clientState = userState.clientStateMap.get(mClientToken);
181372ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim                if (clientState != null) {
181472ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim                    while (clientState.mSessionTokens.size() > 0) {
181572ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim                        releaseSessionLocked(
181672ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim                                clientState.mSessionTokens.get(0), Process.SYSTEM_UID, mUserId);
181772ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim                    }
181872ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim                }
181972ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim                mClientToken = null;
182072ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim            }
182172ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim        }
182272ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim    }
182372ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim
18243957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    private final class ServiceState {
1825d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim        private final List<IBinder> mSessionTokens = new ArrayList<IBinder>();
1826d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim        private final ServiceConnection mConnection;
18279e8ade2eb7ee835963473c9cf6faaf5423b0b048Ji-Hwan Lee        private final ComponentName mComponent;
1828187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim        private final boolean mIsHardware;
1829187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim        private final List<TvInputInfo> mInputList = new ArrayList<TvInputInfo>();
18303957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
1831d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim        private ITvInputService mService;
1832d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim        private ServiceCallback mCallback;
1833d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim        private boolean mBound;
18342b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim        private boolean mReconnecting;
18353957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
18369e8ade2eb7ee835963473c9cf6faaf5423b0b048Ji-Hwan Lee        private ServiceState(ComponentName component, int userId) {
18379e8ade2eb7ee835963473c9cf6faaf5423b0b048Ji-Hwan Lee            mComponent = component;
18389e8ade2eb7ee835963473c9cf6faaf5423b0b048Ji-Hwan Lee            mConnection = new InputServiceConnection(component, userId);
18399e8ade2eb7ee835963473c9cf6faaf5423b0b048Ji-Hwan Lee            mIsHardware = hasHardwarePermission(mContext.getPackageManager(), mComponent);
18403957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
18413957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    }
18423957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
18432b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim    private final class SessionState implements IBinder.DeathRecipient {
1844187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim        private final TvInputInfo mInfo;
1845d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim        private final ITvInputClient mClient;
1846d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim        private final int mSeq;
1847d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim        private final int mCallingUid;
18482b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim        private final int mUserId;
184972ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim        private final IBinder mSessionToken;
1850d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim        private ITvInputSession mSession;
1851d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim        private Uri mLogUri;
1852bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang        // Not null if this session represents an external device connected to a hardware TV input.
1853bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang        private IBinder mHardwareSessionToken;
18543957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
1855bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang        private SessionState(IBinder sessionToken, TvInputInfo info, ITvInputClient client,
1856bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                int seq, int callingUid, int userId) {
185772ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim            mSessionToken = sessionToken;
1858187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim            mInfo = info;
18592b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim            mClient = client;
18602b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim            mSeq = seq;
18612b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim            mCallingUid = callingUid;
18622b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim            mUserId = userId;
18632b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim        }
18642b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim
18652b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim        @Override
18662b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim        public void binderDied() {
18672b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim            synchronized (mLock) {
18682b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                mSession = null;
18692b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                if (mClient != null) {
18702b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                    try {
18712b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                        mClient.onSessionReleased(mSeq);
18722b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                    } catch(RemoteException e) {
18732b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                        Slog.e(TAG, "error in onSessionReleased", e);
18742b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                    }
18752b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                }
1876bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                // If there are any other sessions based on this session, they should be released.
1877bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                UserState userState = getUserStateLocked(mUserId);
1878bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                for (SessionState sessionState : userState.sessionStateMap.values()) {
18790c38fc764b0e1c5c8b880872d9b4a647a76955cdJi-Hwan Lee                    if (mSessionToken == sessionState.mHardwareSessionToken) {
18804835497886ee876b16e1144d32f5bdcfbb7e9062Ji-Hwan Lee                        releaseSessionLocked(sessionState.mSessionToken, Process.SYSTEM_UID,
18814835497886ee876b16e1144d32f5bdcfbb7e9062Ji-Hwan Lee                                mUserId);
1882bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                        try {
1883bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                            sessionState.mClient.onSessionReleased(sessionState.mSeq);
1884bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                        } catch (RemoteException e) {
1885bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                            Slog.e(TAG, "error in onSessionReleased", e);
1886bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                        }
1887bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                    }
1888bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                }
188972ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim                removeSessionStateLocked(mSessionToken, mUserId);
18902b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim            }
18913957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
18923957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    }
18933957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
18943957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    private final class InputServiceConnection implements ServiceConnection {
18959e8ade2eb7ee835963473c9cf6faaf5423b0b048Ji-Hwan Lee        private final ComponentName mComponent;
18963957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        private final int mUserId;
18973957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
18989e8ade2eb7ee835963473c9cf6faaf5423b0b048Ji-Hwan Lee        private InputServiceConnection(ComponentName component, int userId) {
18999e8ade2eb7ee835963473c9cf6faaf5423b0b048Ji-Hwan Lee            mComponent = component;
19003957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            mUserId = userId;
19013957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
19023957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
19033957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        @Override
19049e8ade2eb7ee835963473c9cf6faaf5423b0b048Ji-Hwan Lee        public void onServiceConnected(ComponentName component, IBinder service) {
19053957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            if (DEBUG) {
19069e8ade2eb7ee835963473c9cf6faaf5423b0b048Ji-Hwan Lee                Slog.d(TAG, "onServiceConnected(component=" + component + ")");
19073957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            }
19083957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            synchronized (mLock) {
1909969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                UserState userState = getUserStateLocked(mUserId);
19109e8ade2eb7ee835963473c9cf6faaf5423b0b048Ji-Hwan Lee                ServiceState serviceState = userState.serviceStateMap.get(mComponent);
1911d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim                serviceState.mService = ITvInputService.Stub.asInterface(service);
19123957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
19133957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                // Register a callback, if we need to.
1914187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                if (serviceState.mIsHardware && serviceState.mCallback == null) {
19159e8ade2eb7ee835963473c9cf6faaf5423b0b048Ji-Hwan Lee                    serviceState.mCallback = new ServiceCallback(mComponent, mUserId);
19163957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    try {
1917d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim                        serviceState.mService.registerCallback(serviceState.mCallback);
19183957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    } catch (RemoteException e) {
19199a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                        Slog.e(TAG, "error in registerCallback", e);
19203957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    }
19213957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                }
19223957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
19233957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                // And create sessions, if any.
1924d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim                for (IBinder sessionToken : serviceState.mSessionTokens) {
1925d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim                    createSessionInternalLocked(serviceState.mService, sessionToken, mUserId);
19263957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                }
1927969167dc05a6485a32d160895871cff46fd81884Wonsik Kim
1928187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                for (TvInputState inputState : userState.inputMap.values()) {
19299e8ade2eb7ee835963473c9cf6faaf5423b0b048Ji-Hwan Lee                    if (inputState.mInfo.getComponent().equals(component)
1930187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                            && inputState.mState != INPUT_STATE_DISCONNECTED) {
19318e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim                        notifyInputStateChangedLocked(userState, inputState.mInfo.getId(),
1932187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                                inputState.mState, null);
1933187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                    }
1934187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                }
1935187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim
1936187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                if (serviceState.mIsHardware) {
19374f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                    List<TvInputHardwareInfo> hardwareInfoList =
19384f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                            mTvInputHardwareManager.getHardwareList();
1939187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                    for (TvInputHardwareInfo hardwareInfo : hardwareInfoList) {
1940187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                        try {
1941187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                            serviceState.mService.notifyHardwareAdded(hardwareInfo);
1942187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                        } catch (RemoteException e) {
1943187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                            Slog.e(TAG, "error in notifyHardwareAdded", e);
1944187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                        }
1945187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                    }
1946187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim
1947546c635ad9a26421fbdf54efa765b5ab0a63c191Jae Seo                    List<HdmiDeviceInfo> deviceInfoList =
1948546c635ad9a26421fbdf54efa765b5ab0a63c191Jae Seo                            mTvInputHardwareManager.getHdmiDeviceList();
1949546c635ad9a26421fbdf54efa765b5ab0a63c191Jae Seo                    for (HdmiDeviceInfo deviceInfo : deviceInfoList) {
19504f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                        try {
1951546c635ad9a26421fbdf54efa765b5ab0a63c191Jae Seo                            serviceState.mService.notifyHdmiDeviceAdded(deviceInfo);
19524f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                        } catch (RemoteException e) {
1953546c635ad9a26421fbdf54efa765b5ab0a63c191Jae Seo                            Slog.e(TAG, "error in notifyHdmiDeviceAdded", e);
19544f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                        }
19554f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                    }
1956969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                }
19573957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            }
19583957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
19593957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
19603957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        @Override
19619e8ade2eb7ee835963473c9cf6faaf5423b0b048Ji-Hwan Lee        public void onServiceDisconnected(ComponentName component) {
19623957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            if (DEBUG) {
19639e8ade2eb7ee835963473c9cf6faaf5423b0b048Ji-Hwan Lee                Slog.d(TAG, "onServiceDisconnected(component=" + component + ")");
19643957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            }
19659e8ade2eb7ee835963473c9cf6faaf5423b0b048Ji-Hwan Lee            if (!mComponent.equals(component)) {
19662b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                throw new IllegalArgumentException("Mismatched ComponentName: "
19679e8ade2eb7ee835963473c9cf6faaf5423b0b048Ji-Hwan Lee                        + mComponent + " (expected), " + component + " (actual).");
19682b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim            }
19692b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim            synchronized (mLock) {
19702b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                UserState userState = getUserStateLocked(mUserId);
19719e8ade2eb7ee835963473c9cf6faaf5423b0b048Ji-Hwan Lee                ServiceState serviceState = userState.serviceStateMap.get(mComponent);
19722b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                if (serviceState != null) {
19732b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                    serviceState.mReconnecting = true;
19742b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                    serviceState.mBound = false;
19752b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                    serviceState.mService = null;
19762b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                    serviceState.mCallback = null;
19772b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim
1978426c9a4008b75b93cbfea15aa4b8c47c5fdb49b9Dongwon Kang                    abortPendingCreateSessionRequestsLocked(serviceState, null, mUserId);
19792b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim
1980187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                    for (TvInputState inputState : userState.inputMap.values()) {
19819e8ade2eb7ee835963473c9cf6faaf5423b0b048Ji-Hwan Lee                        if (inputState.mInfo.getComponent().equals(component)) {
1982bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                            notifyInputStateChangedLocked(userState, inputState.mInfo.getId(),
1983187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                                    INPUT_STATE_DISCONNECTED, null);
1984187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                        }
1985187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                    }
19862b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                }
19872b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim            }
19883957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
19893957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    }
19903957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
19913957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    private final class ServiceCallback extends ITvInputServiceCallback.Stub {
19929e8ade2eb7ee835963473c9cf6faaf5423b0b048Ji-Hwan Lee        private final ComponentName mComponent;
19933957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        private final int mUserId;
19943957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
19959e8ade2eb7ee835963473c9cf6faaf5423b0b048Ji-Hwan Lee        ServiceCallback(ComponentName component, int userId) {
19969e8ade2eb7ee835963473c9cf6faaf5423b0b048Ji-Hwan Lee            mComponent = component;
19973957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            mUserId = userId;
19983957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
19993957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
20004f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee        private void ensureHardwarePermission() {
20014f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee            if (mContext.checkCallingPermission(android.Manifest.permission.TV_INPUT_HARDWARE)
20024f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                    != PackageManager.PERMISSION_GRANTED) {
20034f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                throw new SecurityException("The caller does not have hardware permission");
20044f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee            }
20054f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee        }
20064f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee
20074f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee        private void ensureValidInput(TvInputInfo inputInfo) {
20089e8ade2eb7ee835963473c9cf6faaf5423b0b048Ji-Hwan Lee            if (inputInfo.getId() == null || !mComponent.equals(inputInfo.getComponent())) {
20094f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                throw new IllegalArgumentException("Invalid TvInputInfo");
20104f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee            }
20114f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee        }
20124f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee
20134f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee        private void addTvInputLocked(TvInputInfo inputInfo) {
20149e8ade2eb7ee835963473c9cf6faaf5423b0b048Ji-Hwan Lee            ServiceState serviceState = getServiceStateLocked(mComponent, mUserId);
20154f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee            serviceState.mInputList.add(inputInfo);
20164f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee            buildTvInputListLocked(mUserId);
20174f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee        }
20184f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee
20193957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        @Override
20204f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee        public void addHardwareTvInput(int deviceId, TvInputInfo inputInfo) {
20214f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee            ensureHardwarePermission();
20224f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee            ensureValidInput(inputInfo);
2023187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim            synchronized (mLock) {
20244f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                mTvInputHardwareManager.addHardwareTvInput(deviceId, inputInfo);
20254f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                addTvInputLocked(inputInfo);
20264f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee            }
20274f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee        }
2028187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim
20294f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee        @Override
20308960d1b1552729e3dfd33deee951ac75933ad8e5Jinsuk Kim        public void addHdmiTvInput(int id, TvInputInfo inputInfo) {
20314f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee            ensureHardwarePermission();
20324f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee            ensureValidInput(inputInfo);
20334f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee            synchronized (mLock) {
20348960d1b1552729e3dfd33deee951ac75933ad8e5Jinsuk Kim                mTvInputHardwareManager.addHdmiTvInput(id, inputInfo);
20354f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                addTvInputLocked(inputInfo);
20363957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            }
2037187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim        }
2038187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim
2039187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim        @Override
2040187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim        public void removeTvInput(String inputId) {
20414f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee            ensureHardwarePermission();
20423957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            synchronized (mLock) {
20439e8ade2eb7ee835963473c9cf6faaf5423b0b048Ji-Hwan Lee                ServiceState serviceState = getServiceStateLocked(mComponent, mUserId);
2044187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                boolean removed = false;
2045187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                for (Iterator<TvInputInfo> it = serviceState.mInputList.iterator();
2046187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                        it.hasNext(); ) {
2047187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                    if (it.next().getId().equals(inputId)) {
2048187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                        it.remove();
2049187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                        removed = true;
2050187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                        break;
2051187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                    }
2052187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                }
2053187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                if (removed) {
2054187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                    buildTvInputListLocked(mUserId);
20554f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                    mTvInputHardwareManager.removeTvInput(inputId);
2056187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                } else {
2057fea8dd45f4955b4b4b6536bf51453e19288deba2Jae Seo                    Slog.e(TAG, "failed to remove input " + inputId);
2058187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                }
20593957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            }
20603957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
20613957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    }
206231dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo
20637eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo    private final class WatchLogHandler extends Handler {
20647eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo        // There are only two kinds of watch events that can happen on the system:
20657eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo        // 1. The current TV input session is tuned to a new channel.
20667eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo        // 2. The session is released for some reason.
20677eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo        // The former indicates the end of the previous log entry, if any, followed by the start of
20687eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo        // a new entry. The latter indicates the end of the most recent entry for the given session.
20697eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo        // Here the system supplies the database the smallest set of information only that is
20707eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo        // sufficient to consolidate the log entries while minimizing database operations in the
20717eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo        // system service.
20727eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo        private static final int MSG_LOG_WATCH_START = 1;
20737eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo        private static final int MSG_LOG_WATCH_END = 2;
20747eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo
20757eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo        public WatchLogHandler(Looper looper) {
207631dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo            super(looper);
207731dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo        }
207831dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo
207931dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo        @Override
208031dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo        public void handleMessage(Message msg) {
208131dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo            switch (msg.what) {
20827eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo                case MSG_LOG_WATCH_START: {
208331dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                    SomeArgs args = (SomeArgs) msg.obj;
20847eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo                    String packageName = (String) args.arg1;
20857eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo                    long watchStartTime = (long) args.arg2;
20867eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo                    long channelId = (long) args.arg3;
20877eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo                    Bundle tuneParams = (Bundle) args.arg4;
20887eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo                    IBinder sessionToken = (IBinder) args.arg5;
20897eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo
20907eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo                    ContentValues values = new ContentValues();
20917eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo                    values.put(TvContract.WatchedPrograms.COLUMN_PACKAGE_NAME, packageName);
20927eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo                    values.put(TvContract.WatchedPrograms.COLUMN_WATCH_START_TIME_UTC_MILLIS,
20937eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo                            watchStartTime);
20947eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo                    values.put(TvContract.WatchedPrograms.COLUMN_CHANNEL_ID, channelId);
20957eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo                    if (tuneParams != null) {
20967eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo                        values.put(TvContract.WatchedPrograms.COLUMN_INTERNAL_TUNE_PARAMS,
20977eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo                                encodeTuneParams(tuneParams));
20987eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo                    }
20997eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo                    values.put(TvContract.WatchedPrograms.COLUMN_INTERNAL_SESSION_TOKEN,
21007eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo                            sessionToken.toString());
21017eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo
21027eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo                    mContentResolver.insert(TvContract.WatchedPrograms.CONTENT_URI, values);
210331dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                    args.recycle();
210431dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                    return;
210531dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                }
21067eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo                case MSG_LOG_WATCH_END: {
210731dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                    SomeArgs args = (SomeArgs) msg.obj;
21087eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo                    IBinder sessionToken = (IBinder) args.arg1;
21097eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo                    long watchEndTime = (long) args.arg2;
21107eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo
21117eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo                    ContentValues values = new ContentValues();
21127eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo                    values.put(TvContract.WatchedPrograms.COLUMN_WATCH_END_TIME_UTC_MILLIS,
21137eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo                            watchEndTime);
21147eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo                    values.put(TvContract.WatchedPrograms.COLUMN_INTERNAL_SESSION_TOKEN,
21157eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo                            sessionToken.toString());
21167eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo
21177eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo                    mContentResolver.insert(TvContract.WatchedPrograms.CONTENT_URI, values);
211831dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                    args.recycle();
211931dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                    return;
212031dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                }
212131dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                default: {
21226a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                    Slog.w(TAG, "Unhandled message code: " + msg.what);
212331dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                    return;
212431dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                }
212531dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo            }
212631dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo        }
212731dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo
21287eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo        private String encodeTuneParams(Bundle tuneParams) {
21297eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo            StringBuilder builder = new StringBuilder();
21307eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo            Set<String> keySet = tuneParams.keySet();
21317eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo            Iterator<String> it = keySet.iterator();
21327eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo            while (it.hasNext()) {
21337eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo                String key = it.next();
21347eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo                Object value = tuneParams.get(key);
21357eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo                if (value == null) {
21367eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo                    continue;
213731dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                }
21387eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo                builder.append(replaceEscapeCharacters(key));
21397eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo                builder.append("=");
21407eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo                builder.append(replaceEscapeCharacters(value.toString()));
21417eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo                if (it.hasNext()) {
21427eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo                    builder.append(", ");
214331dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                }
214431dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo            }
21457eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo            return builder.toString();
214631dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo        }
214731dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo
21487eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo        private String replaceEscapeCharacters(String src) {
21497eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo            final char ESCAPE_CHARACTER = '%';
21507eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo            final String ENCODING_TARGET_CHARACTERS = "%=,";
21517eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo            StringBuilder builder = new StringBuilder();
21527eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo            for (char ch : src.toCharArray()) {
21537eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo                if (ENCODING_TARGET_CHARACTERS.indexOf(ch) >= 0) {
21547eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo                    builder.append(ESCAPE_CHARACTER);
2155579befecb248162021929ab58ffd23f1724cc6beJae Seo                }
21567eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo                builder.append(ch);
2157579befecb248162021929ab58ffd23f1724cc6beJae Seo            }
21587eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo            return builder.toString();
2159579befecb248162021929ab58ffd23f1724cc6beJae Seo        }
216031dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo    }
2161969167dc05a6485a32d160895871cff46fd81884Wonsik Kim
2162187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim    final class HardwareListener implements TvInputHardwareManager.Listener {
2163187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim        @Override
2164187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim        public void onStateChanged(String inputId, int state) {
2165969167dc05a6485a32d160895871cff46fd81884Wonsik Kim            synchronized (mLock) {
2166969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                setStateLocked(inputId, state, mCurrentUserId);
2167969167dc05a6485a32d160895871cff46fd81884Wonsik Kim            }
2168969167dc05a6485a32d160895871cff46fd81884Wonsik Kim        }
2169187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim
2170187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim        @Override
2171187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim        public void onHardwareDeviceAdded(TvInputHardwareInfo info) {
2172187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim            synchronized (mLock) {
2173187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                UserState userState = getUserStateLocked(mCurrentUserId);
2174187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                // Broadcast the event to all hardware inputs.
2175187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                for (ServiceState serviceState : userState.serviceStateMap.values()) {
2176187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                    if (!serviceState.mIsHardware || serviceState.mService == null) continue;
2177187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                    try {
2178187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                        serviceState.mService.notifyHardwareAdded(info);
2179187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                    } catch (RemoteException e) {
2180187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                        Slog.e(TAG, "error in notifyHardwareAdded", e);
2181187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                    }
2182187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                }
2183187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim            }
2184187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim        }
2185187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim
2186187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim        @Override
21874f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee        public void onHardwareDeviceRemoved(TvInputHardwareInfo info) {
2188187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim            synchronized (mLock) {
2189187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                UserState userState = getUserStateLocked(mCurrentUserId);
2190187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                // Broadcast the event to all hardware inputs.
2191187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                for (ServiceState serviceState : userState.serviceStateMap.values()) {
2192187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                    if (!serviceState.mIsHardware || serviceState.mService == null) continue;
2193187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                    try {
21944f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                        serviceState.mService.notifyHardwareRemoved(info);
2195187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                    } catch (RemoteException e) {
2196187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                        Slog.e(TAG, "error in notifyHardwareRemoved", e);
2197187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                    }
2198187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                }
2199187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim            }
2200187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim        }
2201187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim
2202187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim        @Override
2203546c635ad9a26421fbdf54efa765b5ab0a63c191Jae Seo        public void onHdmiDeviceAdded(HdmiDeviceInfo deviceInfo) {
2204187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim            synchronized (mLock) {
22054f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                UserState userState = getUserStateLocked(mCurrentUserId);
22064f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                // Broadcast the event to all hardware inputs.
22074f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                for (ServiceState serviceState : userState.serviceStateMap.values()) {
22084f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                    if (!serviceState.mIsHardware || serviceState.mService == null) continue;
22094f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                    try {
2210546c635ad9a26421fbdf54efa765b5ab0a63c191Jae Seo                        serviceState.mService.notifyHdmiDeviceAdded(deviceInfo);
22114f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                    } catch (RemoteException e) {
2212546c635ad9a26421fbdf54efa765b5ab0a63c191Jae Seo                        Slog.e(TAG, "error in notifyHdmiDeviceAdded", e);
22134f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                    }
22144f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                }
2215187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim            }
2216187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim        }
2217187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim
2218187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim        @Override
2219546c635ad9a26421fbdf54efa765b5ab0a63c191Jae Seo        public void onHdmiDeviceRemoved(HdmiDeviceInfo deviceInfo) {
2220187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim            synchronized (mLock) {
22214f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                UserState userState = getUserStateLocked(mCurrentUserId);
22224f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                // Broadcast the event to all hardware inputs.
22234f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                for (ServiceState serviceState : userState.serviceStateMap.values()) {
22244f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                    if (!serviceState.mIsHardware || serviceState.mService == null) continue;
22254f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                    try {
2226546c635ad9a26421fbdf54efa765b5ab0a63c191Jae Seo                        serviceState.mService.notifyHdmiDeviceRemoved(deviceInfo);
22274f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                    } catch (RemoteException e) {
2228546c635ad9a26421fbdf54efa765b5ab0a63c191Jae Seo                        Slog.e(TAG, "error in notifyHdmiDeviceRemoved", e);
22294f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                    }
22304f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                }
2231187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim            }
2232187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim        }
223361daf6b38e7a7ada2a6ca5a60539a54b9c6810bdJungshik Jang
223461daf6b38e7a7ada2a6ca5a60539a54b9c6810bdJungshik Jang        @Override
2235e92f857d50d7259a4cf7ef5b88309e098338c9c1Wonsik Kim        public void onHdmiDeviceUpdated(String inputId, HdmiDeviceInfo deviceInfo) {
2236e92f857d50d7259a4cf7ef5b88309e098338c9c1Wonsik Kim            synchronized (mLock) {
2237e92f857d50d7259a4cf7ef5b88309e098338c9c1Wonsik Kim                Integer state = null;
2238e92f857d50d7259a4cf7ef5b88309e098338c9c1Wonsik Kim                switch (deviceInfo.getDevicePowerStatus()) {
2239e92f857d50d7259a4cf7ef5b88309e098338c9c1Wonsik Kim                    case HdmiControlManager.POWER_STATUS_ON:
2240e92f857d50d7259a4cf7ef5b88309e098338c9c1Wonsik Kim                        state = INPUT_STATE_CONNECTED;
2241e92f857d50d7259a4cf7ef5b88309e098338c9c1Wonsik Kim                        break;
2242e92f857d50d7259a4cf7ef5b88309e098338c9c1Wonsik Kim                    case HdmiControlManager.POWER_STATUS_STANDBY:
2243e92f857d50d7259a4cf7ef5b88309e098338c9c1Wonsik Kim                    case HdmiControlManager.POWER_STATUS_TRANSIENT_TO_ON:
2244e92f857d50d7259a4cf7ef5b88309e098338c9c1Wonsik Kim                    case HdmiControlManager.POWER_STATUS_TRANSIENT_TO_STANDBY:
2245e92f857d50d7259a4cf7ef5b88309e098338c9c1Wonsik Kim                        state = INPUT_STATE_CONNECTED_STANDBY;
2246e92f857d50d7259a4cf7ef5b88309e098338c9c1Wonsik Kim                        break;
2247e92f857d50d7259a4cf7ef5b88309e098338c9c1Wonsik Kim                    case HdmiControlManager.POWER_STATUS_UNKNOWN:
2248e92f857d50d7259a4cf7ef5b88309e098338c9c1Wonsik Kim                    default:
2249e92f857d50d7259a4cf7ef5b88309e098338c9c1Wonsik Kim                        state = null;
2250e92f857d50d7259a4cf7ef5b88309e098338c9c1Wonsik Kim                        break;
2251e92f857d50d7259a4cf7ef5b88309e098338c9c1Wonsik Kim                }
2252e92f857d50d7259a4cf7ef5b88309e098338c9c1Wonsik Kim                if (state != null) {
2253e92f857d50d7259a4cf7ef5b88309e098338c9c1Wonsik Kim                    setStateLocked(inputId, state.intValue(), mCurrentUserId);
2254e92f857d50d7259a4cf7ef5b88309e098338c9c1Wonsik Kim                }
2255e92f857d50d7259a4cf7ef5b88309e098338c9c1Wonsik Kim            }
225661daf6b38e7a7ada2a6ca5a60539a54b9c6810bdJungshik Jang        }
2257969167dc05a6485a32d160895871cff46fd81884Wonsik Kim    }
22583957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo}
2259