TvInputManagerService.java revision 9c6b5b729bd83b1d1e00428f8a76f272b609c97e
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;
8819ba61affbc0c4a4454abc6cf09f70ea428d1a62Chulwoo Leeimport java.util.Arrays;
893957091ba8f08c02b5e781098cb955a5f697a1ffJae Seoimport java.util.HashMap;
905c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seoimport java.util.HashSet;
91187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kimimport java.util.Iterator;
923957091ba8f08c02b5e781098cb955a5f697a1ffJae Seoimport java.util.List;
933957091ba8f08c02b5e781098cb955a5f697a1ffJae Seoimport java.util.Map;
945c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seoimport java.util.Set;
953957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
963957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo/** This class provides a system service that manages television inputs. */
973957091ba8f08c02b5e781098cb955a5f697a1ffJae Seopublic final class TvInputManagerService extends SystemService {
98ee2ec05ed7c0d3cb9115f4ddd7c3613269c4a57bJae Seo    private static final boolean DEBUG = false;
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();
122fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang        mWatchLogHandler = new WatchLogHandler(mContentResolver, 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) {
14219ba61affbc0c4a4454abc6cf09f70ea428d1a62Chulwoo Lee                buildTvInputListLocked(mCurrentUserId, null);
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() {
15119ba61affbc0c4a4454abc6cf09f70ea428d1a62Chulwoo Lee            private void buildTvInputList(String[] packages) {
15219ba61affbc0c4a4454abc6cf09f70ea428d1a62Chulwoo Lee                synchronized (mLock) {
15319ba61affbc0c4a4454abc6cf09f70ea428d1a62Chulwoo Lee                    buildTvInputListLocked(getChangingUserId(), packages);
15419ba61affbc0c4a4454abc6cf09f70ea428d1a62Chulwoo Lee                    buildTvContentRatingSystemListLocked(getChangingUserId());
15519ba61affbc0c4a4454abc6cf09f70ea428d1a62Chulwoo Lee                }
15619ba61affbc0c4a4454abc6cf09f70ea428d1a62Chulwoo Lee            }
15719ba61affbc0c4a4454abc6cf09f70ea428d1a62Chulwoo Lee
15819ba61affbc0c4a4454abc6cf09f70ea428d1a62Chulwoo Lee            @Override
15919ba61affbc0c4a4454abc6cf09f70ea428d1a62Chulwoo Lee            public void onPackageUpdateFinished(String packageName, int uid) {
16019ba61affbc0c4a4454abc6cf09f70ea428d1a62Chulwoo Lee                if (DEBUG) Slog.d(TAG, "onPackageUpdateFinished(packageName=" + packageName + ")");
16119ba61affbc0c4a4454abc6cf09f70ea428d1a62Chulwoo Lee                // This callback is invoked when the TV input is reinstalled.
16219ba61affbc0c4a4454abc6cf09f70ea428d1a62Chulwoo Lee                // In this case, isReplacing() always returns true.
16319ba61affbc0c4a4454abc6cf09f70ea428d1a62Chulwoo Lee                buildTvInputList(new String[] { packageName });
16419ba61affbc0c4a4454abc6cf09f70ea428d1a62Chulwoo Lee            }
16519ba61affbc0c4a4454abc6cf09f70ea428d1a62Chulwoo Lee
16619ba61affbc0c4a4454abc6cf09f70ea428d1a62Chulwoo Lee            @Override
16719ba61affbc0c4a4454abc6cf09f70ea428d1a62Chulwoo Lee            public void onPackagesAvailable(String[] packages) {
16819ba61affbc0c4a4454abc6cf09f70ea428d1a62Chulwoo Lee                if (DEBUG) {
16919ba61affbc0c4a4454abc6cf09f70ea428d1a62Chulwoo Lee                    Slog.d(TAG, "onPackagesAvailable(packages=" + Arrays.toString(packages) + ")");
17019ba61affbc0c4a4454abc6cf09f70ea428d1a62Chulwoo Lee                }
17119ba61affbc0c4a4454abc6cf09f70ea428d1a62Chulwoo Lee                // This callback is invoked when the media on which some packages exist become
17219ba61affbc0c4a4454abc6cf09f70ea428d1a62Chulwoo Lee                // available.
17319ba61affbc0c4a4454abc6cf09f70ea428d1a62Chulwoo Lee                if (isReplacing()) {
17419ba61affbc0c4a4454abc6cf09f70ea428d1a62Chulwoo Lee                    buildTvInputList(packages);
17519ba61affbc0c4a4454abc6cf09f70ea428d1a62Chulwoo Lee                }
17619ba61affbc0c4a4454abc6cf09f70ea428d1a62Chulwoo Lee            }
17719ba61affbc0c4a4454abc6cf09f70ea428d1a62Chulwoo Lee
17819ba61affbc0c4a4454abc6cf09f70ea428d1a62Chulwoo Lee            @Override
17919ba61affbc0c4a4454abc6cf09f70ea428d1a62Chulwoo Lee            public void onPackagesUnavailable(String[] packages) {
18019ba61affbc0c4a4454abc6cf09f70ea428d1a62Chulwoo Lee                // This callback is invoked when the media on which some packages exist become
18119ba61affbc0c4a4454abc6cf09f70ea428d1a62Chulwoo Lee                // unavailable.
18219ba61affbc0c4a4454abc6cf09f70ea428d1a62Chulwoo Lee                if (DEBUG)  {
18319ba61affbc0c4a4454abc6cf09f70ea428d1a62Chulwoo Lee                    Slog.d(TAG, "onPackagesUnavailable(packages=" + Arrays.toString(packages)
18419ba61affbc0c4a4454abc6cf09f70ea428d1a62Chulwoo Lee                            + ")");
18519ba61affbc0c4a4454abc6cf09f70ea428d1a62Chulwoo Lee                }
18619ba61affbc0c4a4454abc6cf09f70ea428d1a62Chulwoo Lee                if (isReplacing()) {
18719ba61affbc0c4a4454abc6cf09f70ea428d1a62Chulwoo Lee                    buildTvInputList(packages);
18819ba61affbc0c4a4454abc6cf09f70ea428d1a62Chulwoo Lee                }
18919ba61affbc0c4a4454abc6cf09f70ea428d1a62Chulwoo Lee            }
19019ba61affbc0c4a4454abc6cf09f70ea428d1a62Chulwoo Lee
1913957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            @Override
1923957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            public void onSomePackagesChanged() {
19319ba61affbc0c4a4454abc6cf09f70ea428d1a62Chulwoo Lee                // TODO: Use finer-grained methods(e.g. onPackageAdded, onPackageRemoved) to manage
19419ba61affbc0c4a4454abc6cf09f70ea428d1a62Chulwoo Lee                // the TV inputs.
195426c9a4008b75b93cbfea15aa4b8c47c5fdb49b9Dongwon Kang                if (DEBUG) Slog.d(TAG, "onSomePackagesChanged()");
19619ba61affbc0c4a4454abc6cf09f70ea428d1a62Chulwoo Lee                if (isReplacing()) {
19719ba61affbc0c4a4454abc6cf09f70ea428d1a62Chulwoo Lee                    if (DEBUG) Slog.d(TAG, "Skipped building TV input list due to replacing");
19819ba61affbc0c4a4454abc6cf09f70ea428d1a62Chulwoo Lee                    // When the package is updated, buildTvInputListLocked is called in other
19919ba61affbc0c4a4454abc6cf09f70ea428d1a62Chulwoo Lee                    // methods instead.
20019ba61affbc0c4a4454abc6cf09f70ea428d1a62Chulwoo Lee                    return;
2013957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                }
20219ba61affbc0c4a4454abc6cf09f70ea428d1a62Chulwoo Lee                buildTvInputList(null);
2033957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            }
2045c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo
2055c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo            @Override
2065c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo            public void onPackageRemoved(String packageName, int uid) {
2075c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo                synchronized (mLock) {
20819ba61affbc0c4a4454abc6cf09f70ea428d1a62Chulwoo Lee                    UserState userState = getUserStateLocked(getChangingUserId());
209969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                    if (!userState.packageSet.contains(packageName)) {
2105c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo                        // Not a TV input package.
2115c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo                        return;
2125c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo                    }
2135c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo                }
2145c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo
2155c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo                ArrayList<ContentProviderOperation> operations =
2165c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo                        new ArrayList<ContentProviderOperation>();
2175c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo
2185c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo                String selection = TvContract.BaseTvColumns.COLUMN_PACKAGE_NAME + "=?";
2195c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo                String[] selectionArgs = { packageName };
2205c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo
2215c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo                operations.add(ContentProviderOperation.newDelete(TvContract.Channels.CONTENT_URI)
2225c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo                        .withSelection(selection, selectionArgs).build());
2235c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo                operations.add(ContentProviderOperation.newDelete(TvContract.Programs.CONTENT_URI)
2245c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo                        .withSelection(selection, selectionArgs).build());
2255c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo                operations.add(ContentProviderOperation
2265c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo                        .newDelete(TvContract.WatchedPrograms.CONTENT_URI)
2275c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo                        .withSelection(selection, selectionArgs).build());
2285c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo
2295c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo                ContentProviderResult[] results = null;
2305c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo                try {
2315c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo                    results = mContentResolver.applyBatch(TvContract.AUTHORITY, operations);
2325c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo                } catch (RemoteException | OperationApplicationException e) {
233fea8dd45f4955b4b4b6536bf51453e19288deba2Jae Seo                    Slog.e(TAG, "error in applyBatch", e);
2345c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo                }
2355c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo
2365c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo                if (DEBUG) {
2375c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo                    Slog.d(TAG, "onPackageRemoved(packageName=" + packageName + ", uid=" + uid
2385c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo                            + ")");
2395c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo                    Slog.d(TAG, "results=" + results);
2405c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo                }
2415c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo            }
2423957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        };
2433957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        monitor.register(mContext, null, UserHandle.ALL, true);
2443957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
2453957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        IntentFilter intentFilter = new IntentFilter();
2463957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        intentFilter.addAction(Intent.ACTION_USER_SWITCHED);
2473957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        intentFilter.addAction(Intent.ACTION_USER_REMOVED);
2483957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        mContext.registerReceiverAsUser(new BroadcastReceiver() {
2493957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            @Override
2503957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            public void onReceive(Context context, Intent intent) {
2513957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                String action = intent.getAction();
2523957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                if (Intent.ACTION_USER_SWITCHED.equals(action)) {
2533957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    switchUser(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0));
2543957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                } else if (Intent.ACTION_USER_REMOVED.equals(action)) {
2553957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    removeUser(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0));
2563957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                }
2573957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            }
2583957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }, UserHandle.ALL, intentFilter, null, null);
2593957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    }
2603957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
2619e8ade2eb7ee835963473c9cf6faaf5423b0b048Ji-Hwan Lee    private static boolean hasHardwarePermission(PackageManager pm, ComponentName component) {
262187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim        return pm.checkPermission(android.Manifest.permission.TV_INPUT_HARDWARE,
2639e8ade2eb7ee835963473c9cf6faaf5423b0b048Ji-Hwan Lee                component.getPackageName()) == PackageManager.PERMISSION_GRANTED;
264187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim    }
265187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim
26619ba61affbc0c4a4454abc6cf09f70ea428d1a62Chulwoo Lee    private void buildTvInputListLocked(int userId, String[] updatedPackages) {
2673957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        UserState userState = getUserStateLocked(userId);
268969167dc05a6485a32d160895871cff46fd81884Wonsik Kim        userState.packageSet.clear();
2693957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
27019ba61affbc0c4a4454abc6cf09f70ea428d1a62Chulwoo Lee        if (DEBUG) Slog.d(TAG, "buildTvInputList");
2713957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        PackageManager pm = mContext.getPackageManager();
2723957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        List<ResolveInfo> services = pm.queryIntentServices(
273e7bb7d6bb2257c24076f5a4b9f536f90a6637f58Chulwoo Lee                new Intent(TvInputService.SERVICE_INTERFACE),
274e7bb7d6bb2257c24076f5a4b9f536f90a6637f58Chulwoo Lee                PackageManager.GET_SERVICES | PackageManager.GET_META_DATA);
2754f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee        List<TvInputInfo> inputList = new ArrayList<TvInputInfo>();
2763957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        for (ResolveInfo ri : services) {
2773957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            ServiceInfo si = ri.serviceInfo;
2783957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            if (!android.Manifest.permission.BIND_TV_INPUT.equals(si.permission)) {
2799a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                Slog.w(TAG, "Skipping TV input " + si.name + ": it does not require the permission "
2803957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                        + android.Manifest.permission.BIND_TV_INPUT);
2813957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                continue;
2823957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            }
2839cc28e5175e1391646b29469d329c9c1c9311ee1Jae Seo
2849cc28e5175e1391646b29469d329c9c1c9311ee1Jae Seo            ComponentName component = new ComponentName(si.packageName, si.name);
2859cc28e5175e1391646b29469d329c9c1c9311ee1Jae Seo            if (hasHardwarePermission(pm, component)) {
2869cc28e5175e1391646b29469d329c9c1c9311ee1Jae Seo                ServiceState serviceState = userState.serviceStateMap.get(component);
2879cc28e5175e1391646b29469d329c9c1c9311ee1Jae Seo                if (serviceState == null) {
2889cc28e5175e1391646b29469d329c9c1c9311ee1Jae Seo                    // We see this hardware TV input service for the first time; we need to
2899cc28e5175e1391646b29469d329c9c1c9311ee1Jae Seo                    // prepare the ServiceState object so that we can connect to the service and
2909cc28e5175e1391646b29469d329c9c1c9311ee1Jae Seo                    // let it add TvInputInfo objects to mInputList if there's any.
2919cc28e5175e1391646b29469d329c9c1c9311ee1Jae Seo                    serviceState = new ServiceState(component, userId);
2929cc28e5175e1391646b29469d329c9c1c9311ee1Jae Seo                    userState.serviceStateMap.put(component, serviceState);
293f271eacba7997d2751c336153634fac53bc4d660Wonsik Kim                    updateServiceConnectionLocked(component, userId);
294187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                } else {
295fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang                    inputList.addAll(serviceState.inputList);
296187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                }
2979cc28e5175e1391646b29469d329c9c1c9311ee1Jae Seo            } else {
2989cc28e5175e1391646b29469d329c9c1c9311ee1Jae Seo                try {
2999cc28e5175e1391646b29469d329c9c1c9311ee1Jae Seo                    inputList.add(TvInputInfo.createTvInputInfo(mContext, ri));
3009cc28e5175e1391646b29469d329c9c1c9311ee1Jae Seo                } catch (XmlPullParserException | IOException e) {
301fea8dd45f4955b4b4b6536bf51453e19288deba2Jae Seo                    Slog.e(TAG, "failed to load TV input " + si.name, e);
3029cc28e5175e1391646b29469d329c9c1c9311ee1Jae Seo                    continue;
303969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                }
3049cc28e5175e1391646b29469d329c9c1c9311ee1Jae Seo            }
3059cc28e5175e1391646b29469d329c9c1c9311ee1Jae Seo            userState.packageSet.add(si.packageName);
3069cc28e5175e1391646b29469d329c9c1c9311ee1Jae Seo        }
307187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim
3089cc28e5175e1391646b29469d329c9c1c9311ee1Jae Seo        Map<String, TvInputState> inputMap = new HashMap<String, TvInputState>();
3099cc28e5175e1391646b29469d329c9c1c9311ee1Jae Seo        for (TvInputInfo info : inputList) {
310fea8dd45f4955b4b4b6536bf51453e19288deba2Jae Seo            if (DEBUG) {
311fea8dd45f4955b4b4b6536bf51453e19288deba2Jae Seo                Slog.d(TAG, "add " + info.getId());
312fea8dd45f4955b4b4b6536bf51453e19288deba2Jae Seo            }
3139cc28e5175e1391646b29469d329c9c1c9311ee1Jae Seo            TvInputState state = userState.inputMap.get(info.getId());
3149cc28e5175e1391646b29469d329c9c1c9311ee1Jae Seo            if (state == null) {
3159cc28e5175e1391646b29469d329c9c1c9311ee1Jae Seo                state = new TvInputState();
316e7bb7d6bb2257c24076f5a4b9f536f90a6637f58Chulwoo Lee            }
317fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang            state.info = info;
3189cc28e5175e1391646b29469d329c9c1c9311ee1Jae Seo            inputMap.put(info.getId(), state);
3193957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
3208e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim
3218e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim        for (String inputId : inputMap.keySet()) {
3228e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim            if (!userState.inputMap.containsKey(inputId)) {
3238e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim                notifyInputAddedLocked(userState, inputId);
32419ba61affbc0c4a4454abc6cf09f70ea428d1a62Chulwoo Lee            } else if (updatedPackages != null) {
32519ba61affbc0c4a4454abc6cf09f70ea428d1a62Chulwoo Lee                // Notify the package updates
3269c6b5b729bd83b1d1e00428f8a76f272b609c97eJi-Hwan Lee                ComponentName component = inputMap.get(inputId).info.getComponent();
32719ba61affbc0c4a4454abc6cf09f70ea428d1a62Chulwoo Lee                for (String updatedPackage : updatedPackages) {
3289c6b5b729bd83b1d1e00428f8a76f272b609c97eJi-Hwan Lee                    if (component.getPackageName().equals(updatedPackage)) {
3299c6b5b729bd83b1d1e00428f8a76f272b609c97eJi-Hwan Lee                        updateServiceConnectionLocked(component, userId);
33019ba61affbc0c4a4454abc6cf09f70ea428d1a62Chulwoo Lee                        notifyInputUpdatedLocked(userState, inputId);
33119ba61affbc0c4a4454abc6cf09f70ea428d1a62Chulwoo Lee                        break;
33219ba61affbc0c4a4454abc6cf09f70ea428d1a62Chulwoo Lee                    }
33319ba61affbc0c4a4454abc6cf09f70ea428d1a62Chulwoo Lee                }
3348e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim            }
3358e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim        }
3368e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim
3378e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim        for (String inputId : userState.inputMap.keySet()) {
3388e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim            if (!inputMap.containsKey(inputId)) {
339fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang                TvInputInfo info = userState.inputMap.get(inputId).info;
340426c9a4008b75b93cbfea15aa4b8c47c5fdb49b9Dongwon Kang                ServiceState serviceState = userState.serviceStateMap.get(info.getComponent());
341426c9a4008b75b93cbfea15aa4b8c47c5fdb49b9Dongwon Kang                if (serviceState != null) {
342426c9a4008b75b93cbfea15aa4b8c47c5fdb49b9Dongwon Kang                    abortPendingCreateSessionRequestsLocked(serviceState, inputId, userId);
343426c9a4008b75b93cbfea15aa4b8c47c5fdb49b9Dongwon Kang                }
3448e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim                notifyInputRemovedLocked(userState, inputId);
3458e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim            }
3468e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim        }
3478e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim
3488e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim        userState.inputMap.clear();
3498e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim        userState.inputMap = inputMap;
3509c165d6e9a2f085fbdc87b9221f2d52d851b2652Jae Seo    }
3519c165d6e9a2f085fbdc87b9221f2d52d851b2652Jae Seo
3529c165d6e9a2f085fbdc87b9221f2d52d851b2652Jae Seo    private void buildTvContentRatingSystemListLocked(int userId) {
3539c165d6e9a2f085fbdc87b9221f2d52d851b2652Jae Seo        UserState userState = getUserStateLocked(userId);
3549c165d6e9a2f085fbdc87b9221f2d52d851b2652Jae Seo        userState.contentRatingSystemList.clear();
3559c165d6e9a2f085fbdc87b9221f2d52d851b2652Jae Seo
3569c165d6e9a2f085fbdc87b9221f2d52d851b2652Jae Seo        final PackageManager pm = mContext.getPackageManager();
3579c165d6e9a2f085fbdc87b9221f2d52d851b2652Jae Seo        Intent intent = new Intent(TvInputManager.ACTION_QUERY_CONTENT_RATING_SYSTEMS);
3589c165d6e9a2f085fbdc87b9221f2d52d851b2652Jae Seo        for (ResolveInfo resolveInfo :
3599c165d6e9a2f085fbdc87b9221f2d52d851b2652Jae Seo                pm.queryBroadcastReceivers(intent, PackageManager.GET_META_DATA)) {
3609c165d6e9a2f085fbdc87b9221f2d52d851b2652Jae Seo            ActivityInfo receiver = resolveInfo.activityInfo;
3619c165d6e9a2f085fbdc87b9221f2d52d851b2652Jae Seo            Bundle metaData = receiver.metaData;
3629c165d6e9a2f085fbdc87b9221f2d52d851b2652Jae Seo            if (metaData == null) {
3639c165d6e9a2f085fbdc87b9221f2d52d851b2652Jae Seo                continue;
3649c165d6e9a2f085fbdc87b9221f2d52d851b2652Jae Seo            }
3655c5b83fcd58d21c9ab7ac986bf84f604ec5bb4b5Sungsoo Lim
3669c165d6e9a2f085fbdc87b9221f2d52d851b2652Jae Seo            int xmlResId = metaData.getInt(TvInputManager.META_DATA_CONTENT_RATING_SYSTEMS);
3679c165d6e9a2f085fbdc87b9221f2d52d851b2652Jae Seo            if (xmlResId == 0) {
3689c165d6e9a2f085fbdc87b9221f2d52d851b2652Jae Seo                Slog.w(TAG, "Missing meta-data '"
3699c165d6e9a2f085fbdc87b9221f2d52d851b2652Jae Seo                        + TvInputManager.META_DATA_CONTENT_RATING_SYSTEMS + "' on receiver "
3709c165d6e9a2f085fbdc87b9221f2d52d851b2652Jae Seo                        + receiver.packageName + "/" + receiver.name);
3719c165d6e9a2f085fbdc87b9221f2d52d851b2652Jae Seo                continue;
3725c5b83fcd58d21c9ab7ac986bf84f604ec5bb4b5Sungsoo Lim            }
3739c165d6e9a2f085fbdc87b9221f2d52d851b2652Jae Seo            userState.contentRatingSystemList.add(
3749c165d6e9a2f085fbdc87b9221f2d52d851b2652Jae Seo                    TvContentRatingSystemInfo.createTvContentRatingSystemInfo(xmlResId,
3759c165d6e9a2f085fbdc87b9221f2d52d851b2652Jae Seo                            receiver.applicationInfo));
3765c5b83fcd58d21c9ab7ac986bf84f604ec5bb4b5Sungsoo Lim        }
3773957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    }
3783957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
3793957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    private void switchUser(int userId) {
3803957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        synchronized (mLock) {
3813957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            if (mCurrentUserId == userId) {
3823957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                return;
3833957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            }
3843957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            // final int oldUserId = mCurrentUserId;
3853957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            // TODO: Release services and sessions in the old user state, if needed.
3863957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            mCurrentUserId = userId;
3873957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
3883957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            UserState userState = mUserStates.get(userId);
3893957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            if (userState == null) {
390783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                userState = new UserState(mContext, userId);
3913957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            }
3923957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            mUserStates.put(userId, userState);
39319ba61affbc0c4a4454abc6cf09f70ea428d1a62Chulwoo Lee            buildTvInputListLocked(userId, null);
3949c165d6e9a2f085fbdc87b9221f2d52d851b2652Jae Seo            buildTvContentRatingSystemListLocked(userId);
3953957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
3963957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    }
3973957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
3983957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    private void removeUser(int userId) {
3993957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        synchronized (mLock) {
400b06cb8870f0407f18bb1225065a93aba2a5de2bfJae Seo            UserState userState = mUserStates.get(userId);
401b06cb8870f0407f18bb1225065a93aba2a5de2bfJae Seo            if (userState == null) {
402b06cb8870f0407f18bb1225065a93aba2a5de2bfJae Seo                return;
403b06cb8870f0407f18bb1225065a93aba2a5de2bfJae Seo            }
4043957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            // Release created sessions.
4053957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            for (SessionState state : userState.sessionStateMap.values()) {
406fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang                if (state.session != null) {
4073957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    try {
408fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang                        state.session.release();
4093957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    } catch (RemoteException e) {
4109a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                        Slog.e(TAG, "error in release", e);
4113957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    }
4123957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                }
4133957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            }
4143957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            userState.sessionStateMap.clear();
4153957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
4163957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            // Unregister all callbacks and unbind all services.
4173957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            for (ServiceState serviceState : userState.serviceStateMap.values()) {
418fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang                if (serviceState.callback != null) {
4193957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    try {
420fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang                        serviceState.service.unregisterCallback(serviceState.callback);
4213957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    } catch (RemoteException e) {
4229a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                        Slog.e(TAG, "error in unregisterCallback", e);
4233957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    }
4243957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                }
425fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang                mContext.unbindService(serviceState.connection);
4263957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            }
4273957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            userState.serviceStateMap.clear();
4283957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
429fea8dd45f4955b4b4b6536bf51453e19288deba2Jae Seo            // Clear everything else.
430fea8dd45f4955b4b4b6536bf51453e19288deba2Jae Seo            userState.inputMap.clear();
431fea8dd45f4955b4b4b6536bf51453e19288deba2Jae Seo            userState.packageSet.clear();
4329c165d6e9a2f085fbdc87b9221f2d52d851b2652Jae Seo            userState.contentRatingSystemList.clear();
43372ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim            userState.clientStateMap.clear();
434fea8dd45f4955b4b4b6536bf51453e19288deba2Jae Seo            userState.callbackSet.clear();
435fea8dd45f4955b4b4b6536bf51453e19288deba2Jae Seo            userState.mainSessionToken = null;
43672ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim
4373957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            mUserStates.remove(userId);
4383957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
4393957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    }
4403957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
4413957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    private UserState getUserStateLocked(int userId) {
4423957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        UserState userState = mUserStates.get(userId);
4433957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        if (userState == null) {
4443957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            throw new IllegalStateException("User state not found for user ID " + userId);
4453957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
4463957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        return userState;
4473957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    }
4483957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
4499e8ade2eb7ee835963473c9cf6faaf5423b0b048Ji-Hwan Lee    private ServiceState getServiceStateLocked(ComponentName component, int userId) {
4503957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        UserState userState = getUserStateLocked(userId);
4519e8ade2eb7ee835963473c9cf6faaf5423b0b048Ji-Hwan Lee        ServiceState serviceState = userState.serviceStateMap.get(component);
4523957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        if (serviceState == null) {
4539e8ade2eb7ee835963473c9cf6faaf5423b0b048Ji-Hwan Lee            throw new IllegalStateException("Service state not found for " + component + " (userId="
4547de5e234715a3baa8905afa3dd0c5009af64541fSungsoo Lim                    + userId + ")");
4553957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
4563957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        return serviceState;
4573957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    }
4583957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
4592b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim    private SessionState getSessionStateLocked(IBinder sessionToken, int callingUid, int userId) {
4603957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        UserState userState = getUserStateLocked(userId);
4613957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        SessionState sessionState = userState.sessionStateMap.get(sessionToken);
4623957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        if (sessionState == null) {
4633957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            throw new IllegalArgumentException("Session state not found for token " + sessionToken);
4643957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
4653957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        // Only the application that requested this session or the system can access it.
466fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang        if (callingUid != Process.SYSTEM_UID && callingUid != sessionState.callingUid) {
4673957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            throw new SecurityException("Illegal access to the session with token " + sessionToken
4683957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    + " from uid " + callingUid);
4693957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
4702b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim        return sessionState;
4712b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim    }
4722b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim
4732b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim    private ITvInputSession getSessionLocked(IBinder sessionToken, int callingUid, int userId) {
4744c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee        return getSessionLocked(getSessionStateLocked(sessionToken, callingUid, userId));
4754c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee    }
4764c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee
4774c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee    private ITvInputSession getSessionLocked(SessionState sessionState) {
478fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang        ITvInputSession session = sessionState.session;
4793957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        if (session == null) {
4804c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee            throw new IllegalStateException("Session not yet created for token "
481fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang                    + sessionState.sessionToken);
4823957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
4833957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        return session;
4843957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    }
4853957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
4863957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    private int resolveCallingUserId(int callingPid, int callingUid, int requestedUserId,
4873957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            String methodName) {
4883957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        return ActivityManager.handleIncomingUser(callingPid, callingUid, requestedUserId, false,
4893957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                false, methodName, null);
4903957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    }
4913957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
492187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim    private static boolean shouldMaintainConnection(ServiceState serviceState) {
493fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang        return !serviceState.sessionTokens.isEmpty() || serviceState.isHardware;
494fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang        // TODO: Find a way to maintain connection to hardware TV input service only when necessary.
495187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim    }
496187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim
4979e8ade2eb7ee835963473c9cf6faaf5423b0b048Ji-Hwan Lee    private void updateServiceConnectionLocked(ComponentName component, int userId) {
4983957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        UserState userState = getUserStateLocked(userId);
4999e8ade2eb7ee835963473c9cf6faaf5423b0b048Ji-Hwan Lee        ServiceState serviceState = userState.serviceStateMap.get(component);
5003957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        if (serviceState == null) {
5013957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            return;
5023957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
503fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang        if (serviceState.reconnecting) {
504fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang            if (!serviceState.sessionTokens.isEmpty()) {
5052b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                // wait until all the sessions are removed.
5062b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                return;
5072b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim            }
508fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang            serviceState.reconnecting = false;
5092b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim        }
510187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim        boolean maintainConnection = shouldMaintainConnection(serviceState);
511fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang        if (serviceState.service == null && maintainConnection && userId == mCurrentUserId) {
5123957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            // This means that the service is not yet connected but its state indicates that we
5133957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            // have pending requests. Then, connect the service.
514fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang            if (serviceState.bound) {
5153957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                // We have already bound to the service so we don't try to bind again until after we
5163957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                // unbind later on.
5173957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                return;
5183957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            }
5193957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            if (DEBUG) {
5209e8ade2eb7ee835963473c9cf6faaf5423b0b048Ji-Hwan Lee                Slog.d(TAG, "bindServiceAsUser(service=" + component + ", userId=" + userId + ")");
5213957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            }
522d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim
5239e8ade2eb7ee835963473c9cf6faaf5423b0b048Ji-Hwan Lee            Intent i = new Intent(TvInputService.SERVICE_INTERFACE).setComponent(component);
524fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang            serviceState.bound = mContext.bindServiceAsUser(
525fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang                    i, serviceState.connection, Context.BIND_AUTO_CREATE, new UserHandle(userId));
526fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang        } else if (serviceState.service != null && !maintainConnection) {
5273957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            // This means that the service is already connected but its state indicates that we have
5283957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            // nothing to do with it. Then, disconnect the service.
5293957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            if (DEBUG) {
5309e8ade2eb7ee835963473c9cf6faaf5423b0b048Ji-Hwan Lee                Slog.d(TAG, "unbindService(service=" + component + ")");
5313957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            }
532fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang            mContext.unbindService(serviceState.connection);
5339e8ade2eb7ee835963473c9cf6faaf5423b0b048Ji-Hwan Lee            userState.serviceStateMap.remove(component);
5343957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
5353957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    }
5363957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
537426c9a4008b75b93cbfea15aa4b8c47c5fdb49b9Dongwon Kang    private void abortPendingCreateSessionRequestsLocked(ServiceState serviceState,
538426c9a4008b75b93cbfea15aa4b8c47c5fdb49b9Dongwon Kang            String inputId, int userId) {
539426c9a4008b75b93cbfea15aa4b8c47c5fdb49b9Dongwon Kang        // Let clients know the create session requests are failed.
540426c9a4008b75b93cbfea15aa4b8c47c5fdb49b9Dongwon Kang        UserState userState = getUserStateLocked(userId);
541f7f49ddade34744d5386f9bf52ab9ba4f981fce7Dongwon Kang        List<SessionState> sessionsToAbort = new ArrayList<>();
542fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang        for (IBinder sessionToken : serviceState.sessionTokens) {
543426c9a4008b75b93cbfea15aa4b8c47c5fdb49b9Dongwon Kang            SessionState sessionState = userState.sessionStateMap.get(sessionToken);
544fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang            if (sessionState.session == null && (inputId == null
545fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang                    || sessionState.info.getId().equals(inputId))) {
546f7f49ddade34744d5386f9bf52ab9ba4f981fce7Dongwon Kang                sessionsToAbort.add(sessionState);
547426c9a4008b75b93cbfea15aa4b8c47c5fdb49b9Dongwon Kang            }
548426c9a4008b75b93cbfea15aa4b8c47c5fdb49b9Dongwon Kang        }
549f7f49ddade34744d5386f9bf52ab9ba4f981fce7Dongwon Kang        for (SessionState sessionState : sessionsToAbort) {
550fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang            removeSessionStateLocked(sessionState.sessionToken, sessionState.userId);
551fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang            sendSessionTokenToClientLocked(sessionState.client,
552fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang                    sessionState.info.getId(), null, null, sessionState.seq);
553f7f49ddade34744d5386f9bf52ab9ba4f981fce7Dongwon Kang        }
554fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang        updateServiceConnectionLocked(serviceState.component, userId);
555426c9a4008b75b93cbfea15aa4b8c47c5fdb49b9Dongwon Kang    }
556426c9a4008b75b93cbfea15aa4b8c47c5fdb49b9Dongwon Kang
557fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang    private void createSessionInternalLocked(ITvInputService service, IBinder sessionToken,
558fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang            int userId) {
559fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang        UserState userState = getUserStateLocked(userId);
560fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang        SessionState sessionState = userState.sessionStateMap.get(sessionToken);
5613957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        if (DEBUG) {
562fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang            Slog.d(TAG, "createSessionInternalLocked(inputId=" + sessionState.info.getId() + ")");
5633957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
564fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang        InputChannel[] channels = InputChannel.openInputChannelPair(sessionToken.toString());
5656a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo
5663957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        // Set up a callback to send the session token.
567fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang        ITvInputSessionCallback callback = new SessionCallback(sessionState, channels);
5683957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
5693957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        // Create a session. When failed, send a null token immediately.
5703957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        try {
571fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang            service.createSession(channels[1], callback, sessionState.info.getId());
5723957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        } catch (RemoteException e) {
5739a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            Slog.e(TAG, "error in createSession", e);
574fd5b72f1ed2ee74a4204eef65f560fc82f0b62feDongwon Kang            removeSessionStateLocked(sessionToken, userId);
575fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang            sendSessionTokenToClientLocked(sessionState.client, sessionState.info.getId(), null,
576fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang                    null, sessionState.seq);
5773957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
5786a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo        channels[1].dispose();
5793957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    }
5803957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
581d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim    private void sendSessionTokenToClientLocked(ITvInputClient client, String inputId,
5825c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo            IBinder sessionToken, InputChannel channel, int seq) {
5833957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        try {
584d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim            client.onSessionCreated(inputId, sessionToken, channel, seq);
585fea8dd45f4955b4b4b6536bf51453e19288deba2Jae Seo        } catch (RemoteException e) {
586fea8dd45f4955b4b4b6536bf51453e19288deba2Jae Seo            Slog.e(TAG, "error in onSessionCreated", e);
5873957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
5882b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim    }
5893957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
5902b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim    private void releaseSessionLocked(IBinder sessionToken, int callingUid, int userId) {
5912b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim        SessionState sessionState = getSessionStateLocked(sessionToken, callingUid, userId);
592fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang        if (sessionState.session != null) {
59315c56aac985bc8d75f38fb4ecb92dda12d2ca06cJi-Hwan Lee            UserState userState = getUserStateLocked(userId);
59415c56aac985bc8d75f38fb4ecb92dda12d2ca06cJi-Hwan Lee            if (sessionToken == userState.mainSessionToken) {
59515c56aac985bc8d75f38fb4ecb92dda12d2ca06cJi-Hwan Lee                setMainLocked(sessionToken, false, callingUid, userId);
59615c56aac985bc8d75f38fb4ecb92dda12d2ca06cJi-Hwan Lee            }
5972b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim            try {
598fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang                sessionState.session.release();
5992b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim            } catch (RemoteException e) {
600fea8dd45f4955b4b4b6536bf51453e19288deba2Jae Seo                Slog.e(TAG, "session process has already died", e);
6012b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim            }
602fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang            sessionState.session = null;
6033957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
6042b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim        removeSessionStateLocked(sessionToken, userId);
6053957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    }
6063957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
607fd5b72f1ed2ee74a4204eef65f560fc82f0b62feDongwon Kang    private void removeSessionStateLocked(IBinder sessionToken, int userId) {
608fd5b72f1ed2ee74a4204eef65f560fc82f0b62feDongwon Kang        UserState userState = getUserStateLocked(userId);
609abca0ee7949f59e72b8d2764dafa23af18eb51dbJi-Hwan Lee        if (sessionToken == userState.mainSessionToken) {
61015c56aac985bc8d75f38fb4ecb92dda12d2ca06cJi-Hwan Lee            if (DEBUG) {
61115c56aac985bc8d75f38fb4ecb92dda12d2ca06cJi-Hwan Lee                Slog.d(TAG, "mainSessionToken=null");
61215c56aac985bc8d75f38fb4ecb92dda12d2ca06cJi-Hwan Lee            }
613abca0ee7949f59e72b8d2764dafa23af18eb51dbJi-Hwan Lee            userState.mainSessionToken = null;
614abca0ee7949f59e72b8d2764dafa23af18eb51dbJi-Hwan Lee        }
615abca0ee7949f59e72b8d2764dafa23af18eb51dbJi-Hwan Lee
616abca0ee7949f59e72b8d2764dafa23af18eb51dbJi-Hwan Lee        // Remove the session state from the global session state map of the current user.
617fd5b72f1ed2ee74a4204eef65f560fc82f0b62feDongwon Kang        SessionState sessionState = userState.sessionStateMap.remove(sessionToken);
618fd5b72f1ed2ee74a4204eef65f560fc82f0b62feDongwon Kang
6198d4ded0058de5c573ccf79c4596bf5eb1b14fad3Chulwoo Lee        if (sessionState == null) {
6208d4ded0058de5c573ccf79c4596bf5eb1b14fad3Chulwoo Lee            return;
6218d4ded0058de5c573ccf79c4596bf5eb1b14fad3Chulwoo Lee        }
6228d4ded0058de5c573ccf79c4596bf5eb1b14fad3Chulwoo Lee
62372ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim        // Also remove the session token from the session token list of the current client and
62472ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim        // service.
625fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang        ClientState clientState = userState.clientStateMap.get(sessionState.client.asBinder());
62672ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim        if (clientState != null) {
627fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang            clientState.sessionTokens.remove(sessionToken);
62872ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim            if (clientState.isEmpty()) {
629fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang                userState.clientStateMap.remove(sessionState.client.asBinder());
63072ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim            }
63172ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim        }
63272ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim
633fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang        TvInputInfo info = sessionState.info;
634187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim        if (info != null) {
635187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim            ServiceState serviceState = userState.serviceStateMap.get(info.getComponent());
636187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim            if (serviceState != null) {
637fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang                serviceState.sessionTokens.remove(sessionToken);
638187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim            }
639fd5b72f1ed2ee74a4204eef65f560fc82f0b62feDongwon Kang        }
640fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang        updateServiceConnectionLocked(sessionState.info.getComponent(), userId);
6417eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo
6427eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo        // Log the end of watch.
6437eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo        SomeArgs args = SomeArgs.obtain();
6447eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo        args.arg1 = sessionToken;
6457eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo        args.arg2 = System.currentTimeMillis();
6467eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo        mWatchLogHandler.obtainMessage(WatchLogHandler.MSG_LOG_WATCH_END, args).sendToTarget();
647fd5b72f1ed2ee74a4204eef65f560fc82f0b62feDongwon Kang    }
648fd5b72f1ed2ee74a4204eef65f560fc82f0b62feDongwon Kang
64915c56aac985bc8d75f38fb4ecb92dda12d2ca06cJi-Hwan Lee    private void setMainLocked(IBinder sessionToken, boolean isMain, int callingUid, int userId) {
65015c56aac985bc8d75f38fb4ecb92dda12d2ca06cJi-Hwan Lee        SessionState sessionState = getSessionStateLocked(sessionToken, callingUid, userId);
651fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang        if (sessionState.hardwareSessionToken != null) {
652fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang            sessionState = getSessionStateLocked(sessionState.hardwareSessionToken,
65315c56aac985bc8d75f38fb4ecb92dda12d2ca06cJi-Hwan Lee                    Process.SYSTEM_UID, userId);
65415c56aac985bc8d75f38fb4ecb92dda12d2ca06cJi-Hwan Lee        }
655fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang        ServiceState serviceState = getServiceStateLocked(sessionState.info.getComponent(), userId);
656fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang        if (!serviceState.isHardware) {
65715c56aac985bc8d75f38fb4ecb92dda12d2ca06cJi-Hwan Lee            return;
65815c56aac985bc8d75f38fb4ecb92dda12d2ca06cJi-Hwan Lee        }
65915c56aac985bc8d75f38fb4ecb92dda12d2ca06cJi-Hwan Lee        ITvInputSession session = getSessionLocked(sessionState);
66015c56aac985bc8d75f38fb4ecb92dda12d2ca06cJi-Hwan Lee        try {
66115c56aac985bc8d75f38fb4ecb92dda12d2ca06cJi-Hwan Lee            session.setMain(isMain);
66215c56aac985bc8d75f38fb4ecb92dda12d2ca06cJi-Hwan Lee        } catch (RemoteException e) {
66315c56aac985bc8d75f38fb4ecb92dda12d2ca06cJi-Hwan Lee            Slog.e(TAG, "error in setMain", e);
66415c56aac985bc8d75f38fb4ecb92dda12d2ca06cJi-Hwan Lee        }
66515c56aac985bc8d75f38fb4ecb92dda12d2ca06cJi-Hwan Lee    }
66615c56aac985bc8d75f38fb4ecb92dda12d2ca06cJi-Hwan Lee
6678e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim    private void notifyInputAddedLocked(UserState userState, String inputId) {
6688e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim        if (DEBUG) {
669fea8dd45f4955b4b4b6536bf51453e19288deba2Jae Seo            Slog.d(TAG, "notifyInputAddedLocked(inputId=" + inputId + ")");
6708e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim        }
6718e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim        for (ITvInputManagerCallback callback : userState.callbackSet) {
6728e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim            try {
6738e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim                callback.onInputAdded(inputId);
6748e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim            } catch (RemoteException e) {
675fea8dd45f4955b4b4b6536bf51453e19288deba2Jae Seo                Slog.e(TAG, "failed to report added input to callback", e);
6768e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim            }
6778e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim        }
6788e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim    }
6798e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim
6808e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim    private void notifyInputRemovedLocked(UserState userState, String inputId) {
6818e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim        if (DEBUG) {
682fea8dd45f4955b4b4b6536bf51453e19288deba2Jae Seo            Slog.d(TAG, "notifyInputRemovedLocked(inputId=" + inputId + ")");
6838e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim        }
6848e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim        for (ITvInputManagerCallback callback : userState.callbackSet) {
6858e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim            try {
6868e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim                callback.onInputRemoved(inputId);
6878e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim            } catch (RemoteException e) {
688fea8dd45f4955b4b4b6536bf51453e19288deba2Jae Seo                Slog.e(TAG, "failed to report removed input to callback", e);
6898e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim            }
6908e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim        }
6918e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim    }
6928e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim
69319ba61affbc0c4a4454abc6cf09f70ea428d1a62Chulwoo Lee    private void notifyInputUpdatedLocked(UserState userState, String inputId) {
69419ba61affbc0c4a4454abc6cf09f70ea428d1a62Chulwoo Lee        if (DEBUG) {
69519ba61affbc0c4a4454abc6cf09f70ea428d1a62Chulwoo Lee            Slog.d(TAG, "notifyInputUpdatedLocked(inputId=" + inputId + ")");
69619ba61affbc0c4a4454abc6cf09f70ea428d1a62Chulwoo Lee        }
69719ba61affbc0c4a4454abc6cf09f70ea428d1a62Chulwoo Lee        for (ITvInputManagerCallback callback : userState.callbackSet) {
69819ba61affbc0c4a4454abc6cf09f70ea428d1a62Chulwoo Lee            try {
69919ba61affbc0c4a4454abc6cf09f70ea428d1a62Chulwoo Lee                callback.onInputUpdated(inputId);
70019ba61affbc0c4a4454abc6cf09f70ea428d1a62Chulwoo Lee            } catch (RemoteException e) {
70119ba61affbc0c4a4454abc6cf09f70ea428d1a62Chulwoo Lee                Slog.e(TAG, "failed to report updated input to callback", e);
70219ba61affbc0c4a4454abc6cf09f70ea428d1a62Chulwoo Lee            }
70319ba61affbc0c4a4454abc6cf09f70ea428d1a62Chulwoo Lee        }
70419ba61affbc0c4a4454abc6cf09f70ea428d1a62Chulwoo Lee    }
70519ba61affbc0c4a4454abc6cf09f70ea428d1a62Chulwoo Lee
7068e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim    private void notifyInputStateChangedLocked(UserState userState, String inputId,
707969167dc05a6485a32d160895871cff46fd81884Wonsik Kim            int state, ITvInputManagerCallback targetCallback) {
708969167dc05a6485a32d160895871cff46fd81884Wonsik Kim        if (DEBUG) {
709fea8dd45f4955b4b4b6536bf51453e19288deba2Jae Seo            Slog.d(TAG, "notifyInputStateChangedLocked(inputId=" + inputId
710fea8dd45f4955b4b4b6536bf51453e19288deba2Jae Seo                    + ", state=" + state + ")");
711969167dc05a6485a32d160895871cff46fd81884Wonsik Kim        }
712969167dc05a6485a32d160895871cff46fd81884Wonsik Kim        if (targetCallback == null) {
713969167dc05a6485a32d160895871cff46fd81884Wonsik Kim            for (ITvInputManagerCallback callback : userState.callbackSet) {
714969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                try {
715969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                    callback.onInputStateChanged(inputId, state);
716969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                } catch (RemoteException e) {
717fea8dd45f4955b4b4b6536bf51453e19288deba2Jae Seo                    Slog.e(TAG, "failed to report state change to callback", e);
718969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                }
719969167dc05a6485a32d160895871cff46fd81884Wonsik Kim            }
720969167dc05a6485a32d160895871cff46fd81884Wonsik Kim        } else {
7212b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim            try {
722969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                targetCallback.onInputStateChanged(inputId, state);
7232b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim            } catch (RemoteException e) {
724fea8dd45f4955b4b4b6536bf51453e19288deba2Jae Seo                Slog.e(TAG, "failed to report state change to callback", e);
7252b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim            }
7262b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim        }
7272b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim    }
7282b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim
729969167dc05a6485a32d160895871cff46fd81884Wonsik Kim    private void setStateLocked(String inputId, int state, int userId) {
730969167dc05a6485a32d160895871cff46fd81884Wonsik Kim        UserState userState = getUserStateLocked(userId);
731969167dc05a6485a32d160895871cff46fd81884Wonsik Kim        TvInputState inputState = userState.inputMap.get(inputId);
732fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang        ServiceState serviceState = userState.serviceStateMap.get(inputState.info.getComponent());
733fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang        int oldState = inputState.state;
734fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang        inputState.state = state;
735fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang        if (serviceState != null && serviceState.service == null
736187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                && shouldMaintainConnection(serviceState)) {
737969167dc05a6485a32d160895871cff46fd81884Wonsik Kim            // We don't notify state change while reconnecting. It should remain disconnected.
738969167dc05a6485a32d160895871cff46fd81884Wonsik Kim            return;
739969167dc05a6485a32d160895871cff46fd81884Wonsik Kim        }
740969167dc05a6485a32d160895871cff46fd81884Wonsik Kim        if (oldState != state) {
7418e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim            notifyInputStateChangedLocked(userState, inputId, state, null);
742969167dc05a6485a32d160895871cff46fd81884Wonsik Kim        }
743969167dc05a6485a32d160895871cff46fd81884Wonsik Kim    }
744969167dc05a6485a32d160895871cff46fd81884Wonsik Kim
7453957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    private final class BinderService extends ITvInputManager.Stub {
7463957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        @Override
7473957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        public List<TvInputInfo> getTvInputList(int userId) {
7483957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(),
7493957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    Binder.getCallingUid(), userId, "getTvInputList");
7503957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            final long identity = Binder.clearCallingIdentity();
7513957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            try {
7523957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                synchronized (mLock) {
7533957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    UserState userState = getUserStateLocked(resolvedUserId);
754969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                    List<TvInputInfo> inputList = new ArrayList<TvInputInfo>();
755969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                    for (TvInputState state : userState.inputMap.values()) {
756fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang                        inputList.add(state.info);
7573957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    }
758969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                    return inputList;
7593957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                }
7603957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            } finally {
7613957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                Binder.restoreCallingIdentity(identity);
7623957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            }
763b375805f3b1672e68d1511565af4700e5fa8491dJae Seo        }
764b375805f3b1672e68d1511565af4700e5fa8491dJae Seo
765b375805f3b1672e68d1511565af4700e5fa8491dJae Seo        @Override
766b375805f3b1672e68d1511565af4700e5fa8491dJae Seo        public TvInputInfo getTvInputInfo(String inputId, int userId) {
767b375805f3b1672e68d1511565af4700e5fa8491dJae Seo            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(),
768b375805f3b1672e68d1511565af4700e5fa8491dJae Seo                    Binder.getCallingUid(), userId, "getTvInputInfo");
769b375805f3b1672e68d1511565af4700e5fa8491dJae Seo            final long identity = Binder.clearCallingIdentity();
770b375805f3b1672e68d1511565af4700e5fa8491dJae Seo            try {
771b375805f3b1672e68d1511565af4700e5fa8491dJae Seo                synchronized (mLock) {
772b375805f3b1672e68d1511565af4700e5fa8491dJae Seo                    UserState userState = getUserStateLocked(resolvedUserId);
773b375805f3b1672e68d1511565af4700e5fa8491dJae Seo                    TvInputState state = userState.inputMap.get(inputId);
774fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang                    return state == null ? null : state.info;
775b375805f3b1672e68d1511565af4700e5fa8491dJae Seo                }
776b375805f3b1672e68d1511565af4700e5fa8491dJae Seo            } finally {
777b375805f3b1672e68d1511565af4700e5fa8491dJae Seo                Binder.restoreCallingIdentity(identity);
778b375805f3b1672e68d1511565af4700e5fa8491dJae Seo            }
7793957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
7803957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
7813957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        @Override
7829c165d6e9a2f085fbdc87b9221f2d52d851b2652Jae Seo        public List<TvContentRatingSystemInfo> getTvContentRatingSystemList(int userId) {
7835c5b83fcd58d21c9ab7ac986bf84f604ec5bb4b5Sungsoo Lim            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(),
7849c165d6e9a2f085fbdc87b9221f2d52d851b2652Jae Seo                    Binder.getCallingUid(), userId, "getTvContentRatingSystemList");
7855c5b83fcd58d21c9ab7ac986bf84f604ec5bb4b5Sungsoo Lim            final long identity = Binder.clearCallingIdentity();
7865c5b83fcd58d21c9ab7ac986bf84f604ec5bb4b5Sungsoo Lim            try {
7875c5b83fcd58d21c9ab7ac986bf84f604ec5bb4b5Sungsoo Lim                synchronized (mLock) {
7885c5b83fcd58d21c9ab7ac986bf84f604ec5bb4b5Sungsoo Lim                    UserState userState = getUserStateLocked(resolvedUserId);
7899c165d6e9a2f085fbdc87b9221f2d52d851b2652Jae Seo                    return userState.contentRatingSystemList;
7905c5b83fcd58d21c9ab7ac986bf84f604ec5bb4b5Sungsoo Lim                }
7915c5b83fcd58d21c9ab7ac986bf84f604ec5bb4b5Sungsoo Lim            } finally {
7925c5b83fcd58d21c9ab7ac986bf84f604ec5bb4b5Sungsoo Lim                Binder.restoreCallingIdentity(identity);
7935c5b83fcd58d21c9ab7ac986bf84f604ec5bb4b5Sungsoo Lim            }
7945c5b83fcd58d21c9ab7ac986bf84f604ec5bb4b5Sungsoo Lim        }
7955c5b83fcd58d21c9ab7ac986bf84f604ec5bb4b5Sungsoo Lim
7965c5b83fcd58d21c9ab7ac986bf84f604ec5bb4b5Sungsoo Lim        @Override
797969167dc05a6485a32d160895871cff46fd81884Wonsik Kim        public void registerCallback(final ITvInputManagerCallback callback, int userId) {
7983957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(),
7993957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    Binder.getCallingUid(), userId, "registerCallback");
8003957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            final long identity = Binder.clearCallingIdentity();
8013957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            try {
8023957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                synchronized (mLock) {
803fea8dd45f4955b4b4b6536bf51453e19288deba2Jae Seo                    final UserState userState = getUserStateLocked(resolvedUserId);
804969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                    userState.callbackSet.add(callback);
805fea8dd45f4955b4b4b6536bf51453e19288deba2Jae Seo                    try {
806fea8dd45f4955b4b4b6536bf51453e19288deba2Jae Seo                        callback.asBinder().linkToDeath(new IBinder.DeathRecipient() {
807fea8dd45f4955b4b4b6536bf51453e19288deba2Jae Seo                            @Override
808fea8dd45f4955b4b4b6536bf51453e19288deba2Jae Seo                            public void binderDied() {
809fea8dd45f4955b4b4b6536bf51453e19288deba2Jae Seo                                synchronized (mLock) {
810fea8dd45f4955b4b4b6536bf51453e19288deba2Jae Seo                                    if (userState.callbackSet != null) {
811fea8dd45f4955b4b4b6536bf51453e19288deba2Jae Seo                                        userState.callbackSet.remove(callback);
812fea8dd45f4955b4b4b6536bf51453e19288deba2Jae Seo                                    }
813fea8dd45f4955b4b4b6536bf51453e19288deba2Jae Seo                                }
814fea8dd45f4955b4b4b6536bf51453e19288deba2Jae Seo                            }
815fea8dd45f4955b4b4b6536bf51453e19288deba2Jae Seo                        }, 0);
816fea8dd45f4955b4b4b6536bf51453e19288deba2Jae Seo                    } catch (RemoteException e) {
817fea8dd45f4955b4b4b6536bf51453e19288deba2Jae Seo                        Slog.e(TAG, "client process has already died", e);
818fea8dd45f4955b4b4b6536bf51453e19288deba2Jae Seo                    }
819969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                    for (TvInputState state : userState.inputMap.values()) {
820fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang                        notifyInputStateChangedLocked(userState, state.info.getId(), state.state,
821fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang                                callback);
8223957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    }
8233957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                }
8243957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            } finally {
8253957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                Binder.restoreCallingIdentity(identity);
8263957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            }
8273957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
8283957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
8293957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        @Override
830969167dc05a6485a32d160895871cff46fd81884Wonsik Kim        public void unregisterCallback(ITvInputManagerCallback callback, int userId) {
8313957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(),
8323957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    Binder.getCallingUid(), userId, "unregisterCallback");
8333957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            final long identity = Binder.clearCallingIdentity();
8343957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            try {
8353957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                synchronized (mLock) {
836969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                    UserState userState = getUserStateLocked(resolvedUserId);
837969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                    userState.callbackSet.remove(callback);
8383957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                }
8393957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            } finally {
8403957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                Binder.restoreCallingIdentity(identity);
8413957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            }
8423957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
8433957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
8443957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        @Override
845783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo        public boolean isParentalControlsEnabled(int userId) {
846783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(),
847783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                    Binder.getCallingUid(), userId, "isParentalControlsEnabled");
848783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo            final long identity = Binder.clearCallingIdentity();
849783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo            try {
850783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                synchronized (mLock) {
851783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                    UserState userState = getUserStateLocked(resolvedUserId);
852783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                    return userState.persistentDataStore.isParentalControlsEnabled();
853783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                }
854783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo            } finally {
855783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                Binder.restoreCallingIdentity(identity);
856783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo            }
857783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo        }
858783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo
859783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo        @Override
860783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo        public void setParentalControlsEnabled(boolean enabled, int userId) {
861783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo            ensureParentalControlsPermission();
862783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(),
863783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                    Binder.getCallingUid(), userId, "setParentalControlsEnabled");
864783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo            final long identity = Binder.clearCallingIdentity();
865783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo            try {
866783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                synchronized (mLock) {
867783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                    UserState userState = getUserStateLocked(resolvedUserId);
868783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                    userState.persistentDataStore.setParentalControlsEnabled(enabled);
869783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                }
870783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo            } finally {
871783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                Binder.restoreCallingIdentity(identity);
872783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo            }
873783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo        }
874783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo
875783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo        @Override
876783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo        public boolean isRatingBlocked(String rating, int userId) {
877783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(),
878783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                    Binder.getCallingUid(), userId, "isRatingBlocked");
879783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo            final long identity = Binder.clearCallingIdentity();
880783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo            try {
881783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                synchronized (mLock) {
882783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                    UserState userState = getUserStateLocked(resolvedUserId);
883783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                    return userState.persistentDataStore.isRatingBlocked(
884783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                            TvContentRating.unflattenFromString(rating));
885783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                }
886783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo            } finally {
887783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                Binder.restoreCallingIdentity(identity);
888783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo            }
889783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo        }
890783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo
891783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo        @Override
892783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo        public List<String> getBlockedRatings(int userId) {
893783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(),
894783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                    Binder.getCallingUid(), userId, "getBlockedRatings");
895783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo            final long identity = Binder.clearCallingIdentity();
896783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo            try {
897783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                synchronized (mLock) {
898783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                    UserState userState = getUserStateLocked(resolvedUserId);
899783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                    List<String> ratings = new ArrayList<String>();
900783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                    for (TvContentRating rating
901783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                            : userState.persistentDataStore.getBlockedRatings()) {
902783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                        ratings.add(rating.flattenToString());
903783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                    }
904783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                    return ratings;
905783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                }
906783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo            } finally {
907783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                Binder.restoreCallingIdentity(identity);
908783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo            }
909783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo        }
910783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo
911783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo        @Override
912783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo        public void addBlockedRating(String rating, int userId) {
913783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo            ensureParentalControlsPermission();
914783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(),
915783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                    Binder.getCallingUid(), userId, "addBlockedRating");
916783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo            final long identity = Binder.clearCallingIdentity();
917783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo            try {
918783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                synchronized (mLock) {
919783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                    UserState userState = getUserStateLocked(resolvedUserId);
920783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                    userState.persistentDataStore.addBlockedRating(
921783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                            TvContentRating.unflattenFromString(rating));
922783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                }
923783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo            } finally {
924783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                Binder.restoreCallingIdentity(identity);
925783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo            }
926783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo        }
927783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo
928783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo        @Override
929783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo        public void removeBlockedRating(String rating, int userId) {
930783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo            ensureParentalControlsPermission();
931783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(),
932783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                    Binder.getCallingUid(), userId, "removeBlockedRating");
933783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo            final long identity = Binder.clearCallingIdentity();
934783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo            try {
935783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                synchronized (mLock) {
936783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                    UserState userState = getUserStateLocked(resolvedUserId);
937783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                    userState.persistentDataStore.removeBlockedRating(
938783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                            TvContentRating.unflattenFromString(rating));
939783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                }
940783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo            } finally {
941783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                Binder.restoreCallingIdentity(identity);
942783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo            }
943783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo        }
944783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo
945783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo        private void ensureParentalControlsPermission() {
946fc836f6684f6e142fe53dc16e1552ffd19bd95bcJae Seo            if (mContext.checkCallingPermission(
947fc836f6684f6e142fe53dc16e1552ffd19bd95bcJae Seo                    android.Manifest.permission.MODIFY_PARENTAL_CONTROLS)
948fc836f6684f6e142fe53dc16e1552ffd19bd95bcJae Seo                    != PackageManager.PERMISSION_GRANTED) {
949fc836f6684f6e142fe53dc16e1552ffd19bd95bcJae Seo                throw new SecurityException(
950fc836f6684f6e142fe53dc16e1552ffd19bd95bcJae Seo                        "The caller does not have parental controls permission");
951fc836f6684f6e142fe53dc16e1552ffd19bd95bcJae Seo            }
952783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo        }
953783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo
954783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo        @Override
955d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim        public void createSession(final ITvInputClient client, final String inputId,
9563957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                int seq, int userId) {
9573957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            final int callingUid = Binder.getCallingUid();
9583957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
9593957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    userId, "createSession");
9603957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            final long identity = Binder.clearCallingIdentity();
9613957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            try {
9623957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                synchronized (mLock) {
9633957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    UserState userState = getUserStateLocked(resolvedUserId);
964426c9a4008b75b93cbfea15aa4b8c47c5fdb49b9Dongwon Kang                    TvInputState inputState = userState.inputMap.get(inputId);
965426c9a4008b75b93cbfea15aa4b8c47c5fdb49b9Dongwon Kang                    if (inputState == null) {
966426c9a4008b75b93cbfea15aa4b8c47c5fdb49b9Dongwon Kang                        Slog.w(TAG, "Failed to find input state for inputId=" + inputId);
967426c9a4008b75b93cbfea15aa4b8c47c5fdb49b9Dongwon Kang                        sendSessionTokenToClientLocked(client, inputId, null, null, seq);
968426c9a4008b75b93cbfea15aa4b8c47c5fdb49b9Dongwon Kang                        return;
969426c9a4008b75b93cbfea15aa4b8c47c5fdb49b9Dongwon Kang                    }
970fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang                    TvInputInfo info = inputState.info;
971187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                    ServiceState serviceState = userState.serviceStateMap.get(info.getComponent());
9723957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    if (serviceState == null) {
973187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                        serviceState = new ServiceState(info.getComponent(), resolvedUserId);
974187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                        userState.serviceStateMap.put(info.getComponent(), serviceState);
9753957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    }
9762b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                    // Send a null token immediately while reconnecting.
977fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang                    if (serviceState.reconnecting == true) {
9785c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo                        sendSessionTokenToClientLocked(client, inputId, null, null, seq);
9792b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                        return;
9802b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                    }
9812b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim
9822b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                    // Create a new session token and a session state.
9832b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                    IBinder sessionToken = new Binder();
984187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                    SessionState sessionState = new SessionState(sessionToken, info, client,
98572ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim                            seq, callingUid, resolvedUserId);
9862b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim
9872b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                    // Add them to the global session state map of the current user.
9882b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                    userState.sessionStateMap.put(sessionToken, sessionState);
9892b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim
9902b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                    // Also, add them to the session state map of the current service.
991fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang                    serviceState.sessionTokens.add(sessionToken);
9923957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
993fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang                    if (serviceState.service != null) {
994fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang                        createSessionInternalLocked(serviceState.service, sessionToken,
9957de5e234715a3baa8905afa3dd0c5009af64541fSungsoo Lim                                resolvedUserId);
9963957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    } else {
997187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                        updateServiceConnectionLocked(info.getComponent(), resolvedUserId);
9983957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    }
9993957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                }
10003957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            } finally {
10013957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                Binder.restoreCallingIdentity(identity);
10023957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            }
10033957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
10043957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
10053957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        @Override
10063957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        public void releaseSession(IBinder sessionToken, int userId) {
100715c56aac985bc8d75f38fb4ecb92dda12d2ca06cJi-Hwan Lee            if (DEBUG) {
1008fea8dd45f4955b4b4b6536bf51453e19288deba2Jae Seo                Slog.d(TAG, "releaseSession(sessionToken=" + sessionToken + ")");
100915c56aac985bc8d75f38fb4ecb92dda12d2ca06cJi-Hwan Lee            }
10103957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            final int callingUid = Binder.getCallingUid();
10113957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
10123957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    userId, "releaseSession");
10133957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            final long identity = Binder.clearCallingIdentity();
10143957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            try {
10153957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                synchronized (mLock) {
10162b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                    releaseSessionLocked(sessionToken, callingUid, resolvedUserId);
10173957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                }
10183957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            } finally {
10193957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                Binder.restoreCallingIdentity(identity);
10203957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            }
10213957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
10223957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
10233957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        @Override
10244c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee        public void setMainSession(IBinder sessionToken, int userId) {
102515c56aac985bc8d75f38fb4ecb92dda12d2ca06cJi-Hwan Lee            if (DEBUG) {
1026fea8dd45f4955b4b4b6536bf51453e19288deba2Jae Seo                Slog.d(TAG, "setMainSession(sessionToken=" + sessionToken + ")");
102715c56aac985bc8d75f38fb4ecb92dda12d2ca06cJi-Hwan Lee            }
10284c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee            final int callingUid = Binder.getCallingUid();
10294c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
10304c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee                    userId, "setMainSession");
10314c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee            final long identity = Binder.clearCallingIdentity();
10324c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee            try {
10334c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee                synchronized (mLock) {
1034982abe693f66037ca265b88057eceb5a3e815182Ji-Hwan Lee                    UserState userState = getUserStateLocked(resolvedUserId);
1035956afc2ba79f50bb8025c6d334653e3c3419b480Ji-Hwan Lee                    if (userState.mainSessionToken == sessionToken) {
10364c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee                        return;
10374c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee                    }
103815c56aac985bc8d75f38fb4ecb92dda12d2ca06cJi-Hwan Lee                    if (DEBUG) {
103915c56aac985bc8d75f38fb4ecb92dda12d2ca06cJi-Hwan Lee                        Slog.d(TAG, "mainSessionToken=" + sessionToken);
1040abca0ee7949f59e72b8d2764dafa23af18eb51dbJi-Hwan Lee                    }
104115c56aac985bc8d75f38fb4ecb92dda12d2ca06cJi-Hwan Lee                    IBinder oldMainSessionToken = userState.mainSessionToken;
10424c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee                    userState.mainSessionToken = sessionToken;
10434c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee
1044956afc2ba79f50bb8025c6d334653e3c3419b480Ji-Hwan Lee                    // Inform the new main session first.
104515c56aac985bc8d75f38fb4ecb92dda12d2ca06cJi-Hwan Lee                    // See {@link TvInputService.Session#onSetMain}.
104615c56aac985bc8d75f38fb4ecb92dda12d2ca06cJi-Hwan Lee                    if (sessionToken != null) {
104715c56aac985bc8d75f38fb4ecb92dda12d2ca06cJi-Hwan Lee                        setMainLocked(sessionToken, true, callingUid, userId);
10484c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee                    }
104915c56aac985bc8d75f38fb4ecb92dda12d2ca06cJi-Hwan Lee                    if (oldMainSessionToken != null) {
105015c56aac985bc8d75f38fb4ecb92dda12d2ca06cJi-Hwan Lee                        setMainLocked(oldMainSessionToken, false, Process.SYSTEM_UID, userId);
10514c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee                    }
10524c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee                }
10534c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee            } finally {
10544c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee                Binder.restoreCallingIdentity(identity);
10554c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee            }
10564c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee        }
10574c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee
10584c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee        @Override
10593957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        public void setSurface(IBinder sessionToken, Surface surface, int userId) {
10603957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            final int callingUid = Binder.getCallingUid();
10613957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
10623957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    userId, "setSurface");
10633957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            final long identity = Binder.clearCallingIdentity();
10643957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            try {
10653957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                synchronized (mLock) {
10663957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    try {
1067bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                        SessionState sessionState = getSessionStateLocked(sessionToken, callingUid,
1068bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                                resolvedUserId);
1069fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang                        if (sessionState.hardwareSessionToken == null) {
1070bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                            getSessionLocked(sessionState).setSurface(surface);
1071bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                        } else {
1072fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang                            getSessionLocked(sessionState.hardwareSessionToken,
1073bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                                    Process.SYSTEM_UID, resolvedUserId).setSurface(surface);
1074bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                        }
10753957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    } catch (RemoteException e) {
10769a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                        Slog.e(TAG, "error in setSurface", e);
10773957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    }
10783957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                }
10793957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            } finally {
1080f836206818ce338db83a3c23c486fb8cab29cb6dYoungsang Cho                if (surface != null) {
1081f836206818ce338db83a3c23c486fb8cab29cb6dYoungsang Cho                    // surface is not used in TvInputManagerService.
1082f836206818ce338db83a3c23c486fb8cab29cb6dYoungsang Cho                    surface.release();
1083f836206818ce338db83a3c23c486fb8cab29cb6dYoungsang Cho                }
10843957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                Binder.restoreCallingIdentity(identity);
10853957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            }
10863957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
10873957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
10883957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        @Override
1089e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho        public void dispatchSurfaceChanged(IBinder sessionToken, int format, int width,
1090e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho                int height, int userId) {
1091e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho            final int callingUid = Binder.getCallingUid();
1092e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
1093e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho                    userId, "dispatchSurfaceChanged");
1094e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho            final long identity = Binder.clearCallingIdentity();
1095e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho            try {
1096e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho                synchronized (mLock) {
1097e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho                    try {
1098bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                        SessionState sessionState = getSessionStateLocked(sessionToken, callingUid,
1099bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                                resolvedUserId);
1100fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang                        getSessionLocked(sessionState).dispatchSurfaceChanged(format, width,
1101fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang                                height);
1102fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang                        if (sessionState.hardwareSessionToken != null) {
1103fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang                            getSessionLocked(sessionState.hardwareSessionToken, Process.SYSTEM_UID,
1104bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                                    resolvedUserId).dispatchSurfaceChanged(format, width, height);
1105bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                        }
1106e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho                    } catch (RemoteException e) {
1107e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho                        Slog.e(TAG, "error in dispatchSurfaceChanged", e);
1108e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho                    }
1109e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho                }
1110e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho            } finally {
1111e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho                Binder.restoreCallingIdentity(identity);
1112e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho            }
1113e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho        }
1114e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho
1115e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho        @Override
11163957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        public void setVolume(IBinder sessionToken, float volume, int userId) {
1117bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang            final float REMOTE_VOLUME_ON = 1.0f;
1118bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang            final float REMOTE_VOLUME_OFF = 0f;
11193957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            final int callingUid = Binder.getCallingUid();
11203957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
11213957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    userId, "setVolume");
11223957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            final long identity = Binder.clearCallingIdentity();
11233957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            try {
11243957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                synchronized (mLock) {
11253957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    try {
1126bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                        SessionState sessionState = getSessionStateLocked(sessionToken, callingUid,
1127bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                                resolvedUserId);
1128bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                        getSessionLocked(sessionState).setVolume(volume);
1129fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang                        if (sessionState.hardwareSessionToken != null) {
1130bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                            // Here, we let the hardware session know only whether volume is on or
1131bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                            // off to prevent that the volume is controlled in the both side.
1132fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang                            getSessionLocked(sessionState.hardwareSessionToken,
1133bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                                    Process.SYSTEM_UID, resolvedUserId).setVolume((volume > 0.0f)
1134bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                                            ? REMOTE_VOLUME_ON : REMOTE_VOLUME_OFF);
1135bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                        }
11363957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    } catch (RemoteException e) {
11379a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                        Slog.e(TAG, "error in setVolume", e);
11383957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    }
11393957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                }
11403957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            } finally {
11413957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                Binder.restoreCallingIdentity(identity);
11423957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            }
11433957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
11443957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
11453957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        @Override
11461a6b25eabcc1fb66e6e8d76f91fd413e18b793a9Sungsoo Lim        public void tune(IBinder sessionToken, final Uri channelUri, Bundle params, int userId) {
11473957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            final int callingUid = Binder.getCallingUid();
11483957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
11493957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    userId, "tune");
11503957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            final long identity = Binder.clearCallingIdentity();
11513957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            try {
11523957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                synchronized (mLock) {
11533957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    try {
11541a6b25eabcc1fb66e6e8d76f91fd413e18b793a9Sungsoo Lim                        getSessionLocked(sessionToken, callingUid, resolvedUserId).tune(
11551a6b25eabcc1fb66e6e8d76f91fd413e18b793a9Sungsoo Lim                                channelUri, params);
1156c22d0c0941ab65ca69977d002c4431394a735c7dJae Seo                        if (TvContract.isChannelUriForPassthroughInput(channelUri)) {
1157008f6d4e326f6372e165bdf342178ecd1e834e2fYoungsang Cho                            // Do not log the watch history for passthrough inputs.
1158008f6d4e326f6372e165bdf342178ecd1e834e2fYoungsang Cho                            return;
1159008f6d4e326f6372e165bdf342178ecd1e834e2fYoungsang Cho                        }
116031dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo
116131dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                        UserState userState = getUserStateLocked(resolvedUserId);
116231dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                        SessionState sessionState = userState.sessionStateMap.get(sessionToken);
116331dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo
11647eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo                        // Log the start of watch.
116531dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                        SomeArgs args = SomeArgs.obtain();
1166fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang                        args.arg1 = sessionState.info.getComponent().getPackageName();
11677eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo                        args.arg2 = System.currentTimeMillis();
11687eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo                        args.arg3 = ContentUris.parseId(channelUri);
11697eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo                        args.arg4 = params;
11707eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo                        args.arg5 = sessionToken;
11717eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo                        mWatchLogHandler.obtainMessage(WatchLogHandler.MSG_LOG_WATCH_START, args)
11727eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo                                .sendToTarget();
11733957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    } catch (RemoteException e) {
11749a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                        Slog.e(TAG, "error in tune", e);
11753957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                        return;
11763957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    }
11773957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                }
11783957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            } finally {
11793957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                Binder.restoreCallingIdentity(identity);
11803957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            }
11813957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
11829a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho
11839a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho        @Override
11849bf671f8ee72b156f16fcf05a3d1c6e093ecba67Sungsoo Lim        public void requestUnblockContent(
11859bf671f8ee72b156f16fcf05a3d1c6e093ecba67Sungsoo Lim                IBinder sessionToken, String unblockedRating, int userId) {
1186903d6b72cd572665309633e925485464d08bb25aJaewan Kim            final int callingUid = Binder.getCallingUid();
1187903d6b72cd572665309633e925485464d08bb25aJaewan Kim            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
1188903d6b72cd572665309633e925485464d08bb25aJaewan Kim                    userId, "unblockContent");
1189903d6b72cd572665309633e925485464d08bb25aJaewan Kim            final long identity = Binder.clearCallingIdentity();
1190903d6b72cd572665309633e925485464d08bb25aJaewan Kim            try {
1191903d6b72cd572665309633e925485464d08bb25aJaewan Kim                synchronized (mLock) {
1192903d6b72cd572665309633e925485464d08bb25aJaewan Kim                    try {
1193903d6b72cd572665309633e925485464d08bb25aJaewan Kim                        getSessionLocked(sessionToken, callingUid, resolvedUserId)
11949bf671f8ee72b156f16fcf05a3d1c6e093ecba67Sungsoo Lim                                .requestUnblockContent(unblockedRating);
1195903d6b72cd572665309633e925485464d08bb25aJaewan Kim                    } catch (RemoteException e) {
1196fea8dd45f4955b4b4b6536bf51453e19288deba2Jae Seo                        Slog.e(TAG, "error in requestUnblockContent", e);
1197903d6b72cd572665309633e925485464d08bb25aJaewan Kim                    }
1198903d6b72cd572665309633e925485464d08bb25aJaewan Kim                }
1199903d6b72cd572665309633e925485464d08bb25aJaewan Kim            } finally {
1200903d6b72cd572665309633e925485464d08bb25aJaewan Kim                Binder.restoreCallingIdentity(identity);
1201903d6b72cd572665309633e925485464d08bb25aJaewan Kim            }
1202903d6b72cd572665309633e925485464d08bb25aJaewan Kim        }
1203903d6b72cd572665309633e925485464d08bb25aJaewan Kim
1204903d6b72cd572665309633e925485464d08bb25aJaewan Kim        @Override
12052c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo        public void setCaptionEnabled(IBinder sessionToken, boolean enabled, int userId) {
12062c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo            final int callingUid = Binder.getCallingUid();
12072c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
12082c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo                    userId, "setCaptionEnabled");
12092c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo            final long identity = Binder.clearCallingIdentity();
12102c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo            try {
12112c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo                synchronized (mLock) {
12122c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo                    try {
12132c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo                        getSessionLocked(sessionToken, callingUid, resolvedUserId)
12142c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo                                .setCaptionEnabled(enabled);
12152c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo                    } catch (RemoteException e) {
12162c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo                        Slog.e(TAG, "error in setCaptionEnabled", e);
12172c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo                    }
12182c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo                }
12192c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo            } finally {
12202c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo                Binder.restoreCallingIdentity(identity);
12212c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo            }
12222c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo        }
12232c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo
12242c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo        @Override
122510d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo        public void selectTrack(IBinder sessionToken, int type, String trackId, int userId) {
12261f213914c45c23c653f721690da2ce0718e63139Dongwon Kang            final int callingUid = Binder.getCallingUid();
12271f213914c45c23c653f721690da2ce0718e63139Dongwon Kang            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
12281f213914c45c23c653f721690da2ce0718e63139Dongwon Kang                    userId, "selectTrack");
12291f213914c45c23c653f721690da2ce0718e63139Dongwon Kang            final long identity = Binder.clearCallingIdentity();
12301f213914c45c23c653f721690da2ce0718e63139Dongwon Kang            try {
12311f213914c45c23c653f721690da2ce0718e63139Dongwon Kang                synchronized (mLock) {
12321f213914c45c23c653f721690da2ce0718e63139Dongwon Kang                    try {
12331f213914c45c23c653f721690da2ce0718e63139Dongwon Kang                        getSessionLocked(sessionToken, callingUid, resolvedUserId).selectTrack(
123410d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo                                type, trackId);
12351f213914c45c23c653f721690da2ce0718e63139Dongwon Kang                    } catch (RemoteException e) {
12361f213914c45c23c653f721690da2ce0718e63139Dongwon Kang                        Slog.e(TAG, "error in selectTrack", e);
12371f213914c45c23c653f721690da2ce0718e63139Dongwon Kang                    }
12381f213914c45c23c653f721690da2ce0718e63139Dongwon Kang                }
12391f213914c45c23c653f721690da2ce0718e63139Dongwon Kang            } finally {
12401f213914c45c23c653f721690da2ce0718e63139Dongwon Kang                Binder.restoreCallingIdentity(identity);
12411f213914c45c23c653f721690da2ce0718e63139Dongwon Kang            }
12421f213914c45c23c653f721690da2ce0718e63139Dongwon Kang        }
12431f213914c45c23c653f721690da2ce0718e63139Dongwon Kang
12441f213914c45c23c653f721690da2ce0718e63139Dongwon Kang        @Override
1245a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo        public void sendAppPrivateCommand(IBinder sessionToken, String command, Bundle data,
1246a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo                int userId) {
1247a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo            final int callingUid = Binder.getCallingUid();
1248a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
1249a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo                    userId, "sendAppPrivateCommand");
1250a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo            final long identity = Binder.clearCallingIdentity();
1251a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo            try {
1252a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo                synchronized (mLock) {
1253a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo                    try {
1254a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo                        getSessionLocked(sessionToken, callingUid, resolvedUserId)
1255a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo                                .appPrivateCommand(command, data);
1256a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo                    } catch (RemoteException e) {
1257fea8dd45f4955b4b4b6536bf51453e19288deba2Jae Seo                        Slog.e(TAG, "error in appPrivateCommand", e);
1258a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo                    }
1259a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo                }
1260a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo            } finally {
1261a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo                Binder.restoreCallingIdentity(identity);
1262a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo            }
1263a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo        }
1264a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo
1265a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo        @Override
12669a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho        public void createOverlayView(IBinder sessionToken, IBinder windowToken, Rect frame,
12679a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                int userId) {
12689a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            final int callingUid = Binder.getCallingUid();
12699a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
12709a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                    userId, "createOverlayView");
12719a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            final long identity = Binder.clearCallingIdentity();
12729a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            try {
12739a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                synchronized (mLock) {
12749a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                    try {
12759a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                        getSessionLocked(sessionToken, callingUid, resolvedUserId)
12769a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                                .createOverlayView(windowToken, frame);
12779a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                    } catch (RemoteException e) {
12789a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                        Slog.e(TAG, "error in createOverlayView", e);
12799a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                    }
12809a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                }
12819a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            } finally {
12829a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                Binder.restoreCallingIdentity(identity);
12839a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            }
12849a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho        }
12859a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho
12869a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho        @Override
12879a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho        public void relayoutOverlayView(IBinder sessionToken, Rect frame, int userId) {
12889a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            final int callingUid = Binder.getCallingUid();
12899a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
12909a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                    userId, "relayoutOverlayView");
12919a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            final long identity = Binder.clearCallingIdentity();
12929a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            try {
12939a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                synchronized (mLock) {
12949a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                    try {
12959a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                        getSessionLocked(sessionToken, callingUid, resolvedUserId)
12969a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                                .relayoutOverlayView(frame);
12979a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                    } catch (RemoteException e) {
12989a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                        Slog.e(TAG, "error in relayoutOverlayView", e);
12999a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                    }
13009a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                }
13019a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            } finally {
13029a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                Binder.restoreCallingIdentity(identity);
13039a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            }
13049a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho        }
13059a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho
13069a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho        @Override
13079a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho        public void removeOverlayView(IBinder sessionToken, int userId) {
13089a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            final int callingUid = Binder.getCallingUid();
13099a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
13109a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                    userId, "removeOverlayView");
13119a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            final long identity = Binder.clearCallingIdentity();
13129a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            try {
13139a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                synchronized (mLock) {
13149a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                    try {
13159a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                        getSessionLocked(sessionToken, callingUid, resolvedUserId)
13169a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                                .removeOverlayView();
13179a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                    } catch (RemoteException e) {
13189a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                        Slog.e(TAG, "error in removeOverlayView", e);
13199a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                    }
13209a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                }
13219a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            } finally {
13229a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                Binder.restoreCallingIdentity(identity);
13239a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            }
13249a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho        }
1325c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim
1326c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim        @Override
1327c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim        public List<TvInputHardwareInfo> getHardwareList() throws RemoteException {
1328969167dc05a6485a32d160895871cff46fd81884Wonsik Kim            if (mContext.checkCallingPermission(android.Manifest.permission.TV_INPUT_HARDWARE)
1329c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim                    != PackageManager.PERMISSION_GRANTED) {
1330c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim                return null;
1331c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim            }
1332c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim
1333c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim            final long identity = Binder.clearCallingIdentity();
1334c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim            try {
1335c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim                return mTvInputHardwareManager.getHardwareList();
1336c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim            } finally {
1337c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim                Binder.restoreCallingIdentity(identity);
1338c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim            }
1339c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim        }
1340c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim
1341c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim        @Override
1342c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim        public ITvInputHardware acquireTvInputHardware(int deviceId,
1343969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                ITvInputHardwareCallback callback, TvInputInfo info, int userId)
1344969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                throws RemoteException {
1345969167dc05a6485a32d160895871cff46fd81884Wonsik Kim            if (mContext.checkCallingPermission(android.Manifest.permission.TV_INPUT_HARDWARE)
1346c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim                    != PackageManager.PERMISSION_GRANTED) {
1347c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim                return null;
1348c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim            }
1349c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim
1350c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim            final long identity = Binder.clearCallingIdentity();
1351c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim            final int callingUid = Binder.getCallingUid();
1352c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
1353c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim                    userId, "acquireTvInputHardware");
1354c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim            try {
1355c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim                return mTvInputHardwareManager.acquireHardware(
1356969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                        deviceId, callback, info, callingUid, resolvedUserId);
1357c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim            } finally {
1358c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim                Binder.restoreCallingIdentity(identity);
1359c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim            }
1360c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim        }
1361c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim
1362c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim        @Override
1363c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim        public void releaseTvInputHardware(int deviceId, ITvInputHardware hardware, int userId)
1364c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim                throws RemoteException {
1365969167dc05a6485a32d160895871cff46fd81884Wonsik Kim            if (mContext.checkCallingPermission(android.Manifest.permission.TV_INPUT_HARDWARE)
1366c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim                    != PackageManager.PERMISSION_GRANTED) {
1367c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim                return;
1368c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim            }
1369c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim
1370c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim            final long identity = Binder.clearCallingIdentity();
1371c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim            final int callingUid = Binder.getCallingUid();
1372c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
1373c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim                    userId, "releaseTvInputHardware");
1374c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim            try {
1375c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim                mTvInputHardwareManager.releaseHardware(
1376c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim                        deviceId, hardware, callingUid, resolvedUserId);
1377c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim            } finally {
1378c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim                Binder.restoreCallingIdentity(identity);
1379c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim            }
1380c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim        }
1381e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim
1382e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim        @Override
1383c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo        public List<TvStreamConfig> getAvailableTvStreamConfigList(String inputId, int userId)
1384c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo                throws RemoteException {
1385c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo            if (mContext.checkCallingPermission(
1386c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo                    android.Manifest.permission.CAPTURE_TV_INPUT)
1387c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo                    != PackageManager.PERMISSION_GRANTED) {
1388c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo                throw new SecurityException("Requires CAPTURE_TV_INPUT permission");
1389c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo            }
1390c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo
1391c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo            final long identity = Binder.clearCallingIdentity();
1392c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo            final int callingUid = Binder.getCallingUid();
1393c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
1394c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo                    userId, "getAvailableTvStreamConfigList");
1395c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo            try {
1396c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo                return mTvInputHardwareManager.getAvailableTvStreamConfigList(
1397c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo                        inputId, callingUid, resolvedUserId);
1398c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo            } finally {
1399c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo                Binder.restoreCallingIdentity(identity);
1400c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo            }
1401c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo        }
1402c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo
1403c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo        @Override
1404c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo        public boolean captureFrame(String inputId, Surface surface, TvStreamConfig config,
1405c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo                int userId)
1406c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo                throws RemoteException {
1407c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo            if (mContext.checkCallingPermission(
1408c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo                    android.Manifest.permission.CAPTURE_TV_INPUT)
1409c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo                    != PackageManager.PERMISSION_GRANTED) {
1410c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo                throw new SecurityException("Requires CAPTURE_TV_INPUT permission");
1411c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo            }
1412c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo
1413c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo            final long identity = Binder.clearCallingIdentity();
1414c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo            final int callingUid = Binder.getCallingUid();
1415c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
1416c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo                    userId, "captureFrame");
1417c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo            try {
1418bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                String hardwareInputId = null;
141979124a717c09f12c74d587d3977bf33ca37e6420Terry Heo                synchronized (mLock) {
142079124a717c09f12c74d587d3977bf33ca37e6420Terry Heo                    UserState userState = getUserStateLocked(resolvedUserId);
1421bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                    if (userState.inputMap.get(inputId) == null) {
1422fea8dd45f4955b4b4b6536bf51453e19288deba2Jae Seo                        Slog.e(TAG, "input not found for " + inputId);
1423bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                        return false;
1424bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                    }
1425bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                    for (SessionState sessionState : userState.sessionStateMap.values()) {
1426fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang                        if (sessionState.info.getId().equals(inputId)
1427fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang                                && sessionState.hardwareSessionToken != null) {
1428bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                            hardwareInputId = userState.sessionStateMap.get(
1429fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang                                    sessionState.hardwareSessionToken).info.getId();
1430bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                            break;
1431bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                        }
1432bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                    }
143379124a717c09f12c74d587d3977bf33ca37e6420Terry Heo                }
1434c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo                return mTvInputHardwareManager.captureFrame(
1435bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                        (hardwareInputId != null) ? hardwareInputId : inputId,
143679124a717c09f12c74d587d3977bf33ca37e6420Terry Heo                        surface, config, callingUid, resolvedUserId);
1437c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo            } finally {
1438c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo                Binder.restoreCallingIdentity(identity);
1439c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo            }
1440c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo        }
1441c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo
1442c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo        @Override
1443df9f0a321e0cb2958c9d170395a0367a106fa0e6Terry Heo        public boolean isSingleSessionActive(int userId) throws RemoteException {
1444df9f0a321e0cb2958c9d170395a0367a106fa0e6Terry Heo            final long identity = Binder.clearCallingIdentity();
1445df9f0a321e0cb2958c9d170395a0367a106fa0e6Terry Heo            final int callingUid = Binder.getCallingUid();
1446df9f0a321e0cb2958c9d170395a0367a106fa0e6Terry Heo            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
1447df9f0a321e0cb2958c9d170395a0367a106fa0e6Terry Heo                    userId, "isSingleSessionActive");
1448df9f0a321e0cb2958c9d170395a0367a106fa0e6Terry Heo            try {
1449df9f0a321e0cb2958c9d170395a0367a106fa0e6Terry Heo                synchronized (mLock) {
1450df9f0a321e0cb2958c9d170395a0367a106fa0e6Terry Heo                    UserState userState = getUserStateLocked(resolvedUserId);
1451df9f0a321e0cb2958c9d170395a0367a106fa0e6Terry Heo                    if (userState.sessionStateMap.size() == 1) {
1452df9f0a321e0cb2958c9d170395a0367a106fa0e6Terry Heo                        return true;
1453df9f0a321e0cb2958c9d170395a0367a106fa0e6Terry Heo                    }
1454df9f0a321e0cb2958c9d170395a0367a106fa0e6Terry Heo                    else if (userState.sessionStateMap.size() == 2) {
1455df9f0a321e0cb2958c9d170395a0367a106fa0e6Terry Heo                        SessionState[] sessionStates = userState.sessionStateMap.values().toArray(
1456df9f0a321e0cb2958c9d170395a0367a106fa0e6Terry Heo                                new SessionState[0]);
1457df9f0a321e0cb2958c9d170395a0367a106fa0e6Terry Heo                        // Check if there is a wrapper input.
1458fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang                        if (sessionStates[0].hardwareSessionToken != null
1459fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang                                || sessionStates[1].hardwareSessionToken != null) {
1460df9f0a321e0cb2958c9d170395a0367a106fa0e6Terry Heo                            return true;
1461df9f0a321e0cb2958c9d170395a0367a106fa0e6Terry Heo                        }
1462df9f0a321e0cb2958c9d170395a0367a106fa0e6Terry Heo                    }
1463df9f0a321e0cb2958c9d170395a0367a106fa0e6Terry Heo                    return false;
1464df9f0a321e0cb2958c9d170395a0367a106fa0e6Terry Heo                }
1465df9f0a321e0cb2958c9d170395a0367a106fa0e6Terry Heo            } finally {
1466df9f0a321e0cb2958c9d170395a0367a106fa0e6Terry Heo                Binder.restoreCallingIdentity(identity);
1467df9f0a321e0cb2958c9d170395a0367a106fa0e6Terry Heo            }
1468df9f0a321e0cb2958c9d170395a0367a106fa0e6Terry Heo        }
1469df9f0a321e0cb2958c9d170395a0367a106fa0e6Terry Heo
1470df9f0a321e0cb2958c9d170395a0367a106fa0e6Terry Heo        @Override
14710f8fc345ea61928265fdd6d461bf1babe353fbe4Jae Seo        @SuppressWarnings("resource")
1472e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim        protected void dump(FileDescriptor fd, final PrintWriter writer, String[] args) {
1473e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim            final IndentingPrintWriter pw = new IndentingPrintWriter(writer, "  ");
14740f8fc345ea61928265fdd6d461bf1babe353fbe4Jae Seo            if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
1475e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                    != PackageManager.PERMISSION_GRANTED) {
14760f8fc345ea61928265fdd6d461bf1babe353fbe4Jae Seo                pw.println("Permission Denial: can't dump TvInputManager from pid="
14770f8fc345ea61928265fdd6d461bf1babe353fbe4Jae Seo                        + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid());
1478e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                return;
1479e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim            }
1480e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim
1481e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim            synchronized (mLock) {
1482e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                pw.println("User Ids (Current user: " + mCurrentUserId + "):");
1483e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                pw.increaseIndent();
1484e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                for (int i = 0; i < mUserStates.size(); i++) {
1485e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                    int userId = mUserStates.keyAt(i);
1486e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                    pw.println(Integer.valueOf(userId));
1487e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                }
1488e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                pw.decreaseIndent();
1489e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim
1490e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                for (int i = 0; i < mUserStates.size(); i++) {
1491e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                    int userId = mUserStates.keyAt(i);
1492e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                    UserState userState = getUserStateLocked(userId);
1493e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                    pw.println("UserState (" + userId + "):");
1494e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                    pw.increaseIndent();
1495e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim
1496969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                    pw.println("inputMap: inputId -> TvInputState");
1497e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                    pw.increaseIndent();
14988e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim                    for (Map.Entry<String, TvInputState> entry: userState.inputMap.entrySet()) {
14998e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim                        pw.println(entry.getKey() + ": " + entry.getValue());
1500e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                    }
1501e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                    pw.decreaseIndent();
1502e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim
1503969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                    pw.println("packageSet:");
1504e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                    pw.increaseIndent();
1505969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                    for (String packageName : userState.packageSet) {
1506e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        pw.println(packageName);
1507e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                    }
1508e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                    pw.decreaseIndent();
1509e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim
1510e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                    pw.println("clientStateMap: ITvInputClient -> ClientState");
1511e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                    pw.increaseIndent();
1512e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                    for (Map.Entry<IBinder, ClientState> entry :
1513e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                            userState.clientStateMap.entrySet()) {
1514e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        ClientState client = entry.getValue();
1515e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        pw.println(entry.getKey() + ": " + client);
1516e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim
1517e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        pw.increaseIndent();
1518e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim
1519fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang                        pw.println("sessionTokens:");
1520e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        pw.increaseIndent();
1521fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang                        for (IBinder token : client.sessionTokens) {
1522e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                            pw.println("" + token);
1523e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        }
1524e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        pw.decreaseIndent();
1525e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim
1526fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang                        pw.println("clientTokens: " + client.clientToken);
1527fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang                        pw.println("userId: " + client.userId);
1528e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim
1529e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        pw.decreaseIndent();
1530e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                    }
1531e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                    pw.decreaseIndent();
1532e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim
1533187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                    pw.println("serviceStateMap: ComponentName -> ServiceState");
1534e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                    pw.increaseIndent();
1535187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                    for (Map.Entry<ComponentName, ServiceState> entry :
1536e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                            userState.serviceStateMap.entrySet()) {
1537e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        ServiceState service = entry.getValue();
1538e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        pw.println(entry.getKey() + ": " + service);
1539e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim
1540e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        pw.increaseIndent();
1541e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim
1542fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang                        pw.println("sessionTokens:");
1543e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        pw.increaseIndent();
1544fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang                        for (IBinder token : service.sessionTokens) {
1545e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                            pw.println("" + token);
1546e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        }
1547e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        pw.decreaseIndent();
1548e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim
1549fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang                        pw.println("service: " + service.service);
1550fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang                        pw.println("callback: " + service.callback);
1551fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang                        pw.println("bound: " + service.bound);
1552fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang                        pw.println("reconnecting: " + service.reconnecting);
1553e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim
1554e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        pw.decreaseIndent();
1555e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                    }
1556e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                    pw.decreaseIndent();
1557e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim
1558e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                    pw.println("sessionStateMap: ITvInputSession -> SessionState");
1559e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                    pw.increaseIndent();
1560e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                    for (Map.Entry<IBinder, SessionState> entry :
1561e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                            userState.sessionStateMap.entrySet()) {
1562e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        SessionState session = entry.getValue();
1563e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        pw.println(entry.getKey() + ": " + session);
1564e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim
1565e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        pw.increaseIndent();
1566fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang                        pw.println("info: " + session.info);
1567fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang                        pw.println("client: " + session.client);
1568fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang                        pw.println("seq: " + session.seq);
1569fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang                        pw.println("callingUid: " + session.callingUid);
1570fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang                        pw.println("userId: " + session.userId);
1571fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang                        pw.println("sessionToken: " + session.sessionToken);
1572fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang                        pw.println("session: " + session.session);
1573fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang                        pw.println("logUri: " + session.logUri);
1574fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang                        pw.println("hardwareSessionToken: " + session.hardwareSessionToken);
1575e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        pw.decreaseIndent();
1576e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                    }
1577e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                    pw.decreaseIndent();
1578e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim
1579969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                    pw.println("callbackSet:");
1580969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                    pw.increaseIndent();
1581969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                    for (ITvInputManagerCallback callback : userState.callbackSet) {
1582969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                        pw.println(callback.toString());
1583969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                    }
1584969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                    pw.decreaseIndent();
1585969167dc05a6485a32d160895871cff46fd81884Wonsik Kim
1586956afc2ba79f50bb8025c6d334653e3c3419b480Ji-Hwan Lee                    pw.println("mainSessionToken: " + userState.mainSessionToken);
1587e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                    pw.decreaseIndent();
1588e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                }
1589e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim            }
1590e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim        }
15913957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    }
15923957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
15933957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    private static final class UserState {
1594969167dc05a6485a32d160895871cff46fd81884Wonsik Kim        // A mapping from the TV input id to its TvInputState.
1595969167dc05a6485a32d160895871cff46fd81884Wonsik Kim        private Map<String, TvInputState> inputMap = new HashMap<String, TvInputState>();
15963957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
1597969167dc05a6485a32d160895871cff46fd81884Wonsik Kim        // A set of all TV input packages.
1598969167dc05a6485a32d160895871cff46fd81884Wonsik Kim        private final Set<String> packageSet = new HashSet<String>();
15995c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo
16009c165d6e9a2f085fbdc87b9221f2d52d851b2652Jae Seo        // A list of all TV content rating systems defined.
16019c165d6e9a2f085fbdc87b9221f2d52d851b2652Jae Seo        private final List<TvContentRatingSystemInfo>
16029c165d6e9a2f085fbdc87b9221f2d52d851b2652Jae Seo                contentRatingSystemList = new ArrayList<TvContentRatingSystemInfo>();
16035c5b83fcd58d21c9ab7ac986bf84f604ec5bb4b5Sungsoo Lim
160472ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim        // A mapping from the token of a client to its state.
160572ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim        private final Map<IBinder, ClientState> clientStateMap =
160672ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim                new HashMap<IBinder, ClientState>();
160772ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim
16083957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        // A mapping from the name of a TV input service to its state.
1609187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim        private final Map<ComponentName, ServiceState> serviceStateMap =
1610187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                new HashMap<ComponentName, ServiceState>();
16113957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
16123957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        // A mapping from the token of a TV input session to its state.
16133957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        private final Map<IBinder, SessionState> sessionStateMap =
16143957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                new HashMap<IBinder, SessionState>();
1615969167dc05a6485a32d160895871cff46fd81884Wonsik Kim
1616969167dc05a6485a32d160895871cff46fd81884Wonsik Kim        // A set of callbacks.
1617969167dc05a6485a32d160895871cff46fd81884Wonsik Kim        private final Set<ITvInputManagerCallback> callbackSet =
1618969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                new HashSet<ITvInputManagerCallback>();
161979124a717c09f12c74d587d3977bf33ca37e6420Terry Heo
16204c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee        // The token of a "main" TV input session.
16214c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee        private IBinder mainSessionToken = null;
1622783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo
1623783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo        // Persistent data store for all internal settings maintained by the TV input manager
1624783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo        // service.
1625783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo        private final PersistentDataStore persistentDataStore;
1626783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo
1627783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo        private UserState(Context context, int userId) {
1628783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo            persistentDataStore = new PersistentDataStore(context, userId);
1629783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo        }
16303957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    }
16313957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
163272ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim    private final class ClientState implements IBinder.DeathRecipient {
1633fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang        private final List<IBinder> sessionTokens = new ArrayList<IBinder>();
163472ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim
1635fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang        private IBinder clientToken;
1636fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang        private final int userId;
163772ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim
163872ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim        ClientState(IBinder clientToken, int userId) {
1639fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang            this.clientToken = clientToken;
1640fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang            this.userId = userId;
164172ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim        }
164272ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim
164372ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim        public boolean isEmpty() {
1644fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang            return sessionTokens.isEmpty();
164572ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim        }
164672ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim
164772ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim        @Override
164872ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim        public void binderDied() {
164972ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim            synchronized (mLock) {
1650fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang                UserState userState = getUserStateLocked(userId);
165172ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim                // DO NOT remove the client state of clientStateMap in this method. It will be
1652a65118e13b5ceb54454b48f67ea754a38a08f27aJi-Hwan Lee                // removed in releaseSessionLocked().
1653fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang                ClientState clientState = userState.clientStateMap.get(clientToken);
165472ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim                if (clientState != null) {
1655fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang                    while (clientState.sessionTokens.size() > 0) {
165672ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim                        releaseSessionLocked(
1657fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang                                clientState.sessionTokens.get(0), Process.SYSTEM_UID, userId);
165872ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim                    }
165972ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim                }
1660fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang                clientToken = null;
166172ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim            }
166272ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim        }
166372ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim    }
166472ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim
16653957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    private final class ServiceState {
1666fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang        private final List<IBinder> sessionTokens = new ArrayList<IBinder>();
1667fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang        private final ServiceConnection connection;
1668fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang        private final ComponentName component;
1669fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang        private final boolean isHardware;
1670fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang        private final List<TvInputInfo> inputList = new ArrayList<TvInputInfo>();
16713957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
1672fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang        private ITvInputService service;
1673fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang        private ServiceCallback callback;
1674fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang        private boolean bound;
1675fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang        private boolean reconnecting;
16763957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
16779e8ade2eb7ee835963473c9cf6faaf5423b0b048Ji-Hwan Lee        private ServiceState(ComponentName component, int userId) {
1678fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang            this.component = component;
1679fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang            this.connection = new InputServiceConnection(component, userId);
1680fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang            this.isHardware = hasHardwarePermission(mContext.getPackageManager(), component);
1681fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang        }
1682fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang    }
1683fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang
1684fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang    private static final class TvInputState {
1685fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang        // A TvInputInfo object which represents the TV input.
1686fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang        private TvInputInfo info;
1687fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang
1688fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang        // The state of TV input. Connected by default.
1689fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang        private int state = INPUT_STATE_CONNECTED;
1690fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang
1691fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang        @Override
1692fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang        public String toString() {
1693fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang            return "info: " + info + "; state: " + state;
16943957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
16953957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    }
16963957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
16972b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim    private final class SessionState implements IBinder.DeathRecipient {
1698fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang        private final TvInputInfo info;
1699fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang        private final ITvInputClient client;
1700fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang        private final int seq;
1701fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang        private final int callingUid;
1702fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang        private final int userId;
1703fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang        private final IBinder sessionToken;
1704fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang        private ITvInputSession session;
1705fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang        private Uri logUri;
1706bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang        // Not null if this session represents an external device connected to a hardware TV input.
1707fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang        private IBinder hardwareSessionToken;
17083957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
1709bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang        private SessionState(IBinder sessionToken, TvInputInfo info, ITvInputClient client,
1710bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                int seq, int callingUid, int userId) {
1711fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang            this.sessionToken = sessionToken;
1712fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang            this.info = info;
1713fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang            this.client = client;
1714fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang            this.seq = seq;
1715fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang            this.callingUid = callingUid;
1716fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang            this.userId = userId;
17172b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim        }
17182b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim
17192b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim        @Override
17202b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim        public void binderDied() {
17212b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim            synchronized (mLock) {
1722fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang                session = null;
1723fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang                if (client != null) {
17242b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                    try {
1725fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang                        client.onSessionReleased(seq);
17262b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                    } catch(RemoteException e) {
17272b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                        Slog.e(TAG, "error in onSessionReleased", e);
17282b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                    }
17292b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                }
1730bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                // If there are any other sessions based on this session, they should be released.
1731fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang                UserState userState = getUserStateLocked(userId);
1732bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                for (SessionState sessionState : userState.sessionStateMap.values()) {
1733fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang                    if (sessionToken == sessionState.hardwareSessionToken) {
1734fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang                        releaseSessionLocked(sessionState.sessionToken, Process.SYSTEM_UID,
1735fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang                                userId);
1736bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                        try {
1737fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang                            sessionState.client.onSessionReleased(sessionState.seq);
1738bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                        } catch (RemoteException e) {
1739bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                            Slog.e(TAG, "error in onSessionReleased", e);
1740bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                        }
1741bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                    }
1742bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                }
1743fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang                removeSessionStateLocked(sessionToken, userId);
17442b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim            }
17453957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
17463957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    }
17473957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
17483957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    private final class InputServiceConnection implements ServiceConnection {
17499e8ade2eb7ee835963473c9cf6faaf5423b0b048Ji-Hwan Lee        private final ComponentName mComponent;
17503957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        private final int mUserId;
17513957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
17529e8ade2eb7ee835963473c9cf6faaf5423b0b048Ji-Hwan Lee        private InputServiceConnection(ComponentName component, int userId) {
17539e8ade2eb7ee835963473c9cf6faaf5423b0b048Ji-Hwan Lee            mComponent = component;
17543957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            mUserId = userId;
17553957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
17563957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
17573957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        @Override
17589e8ade2eb7ee835963473c9cf6faaf5423b0b048Ji-Hwan Lee        public void onServiceConnected(ComponentName component, IBinder service) {
17593957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            if (DEBUG) {
17609e8ade2eb7ee835963473c9cf6faaf5423b0b048Ji-Hwan Lee                Slog.d(TAG, "onServiceConnected(component=" + component + ")");
17613957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            }
17623957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            synchronized (mLock) {
1763969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                UserState userState = getUserStateLocked(mUserId);
17649e8ade2eb7ee835963473c9cf6faaf5423b0b048Ji-Hwan Lee                ServiceState serviceState = userState.serviceStateMap.get(mComponent);
1765fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang                serviceState.service = ITvInputService.Stub.asInterface(service);
17663957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
17673957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                // Register a callback, if we need to.
1768fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang                if (serviceState.isHardware && serviceState.callback == null) {
1769fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang                    serviceState.callback = new ServiceCallback(mComponent, mUserId);
17703957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    try {
1771fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang                        serviceState.service.registerCallback(serviceState.callback);
17723957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    } catch (RemoteException e) {
17739a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                        Slog.e(TAG, "error in registerCallback", e);
17743957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    }
17753957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                }
17763957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
17773957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                // And create sessions, if any.
1778fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang                for (IBinder sessionToken : serviceState.sessionTokens) {
1779fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang                    createSessionInternalLocked(serviceState.service, sessionToken, mUserId);
17803957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                }
1781969167dc05a6485a32d160895871cff46fd81884Wonsik Kim
1782187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                for (TvInputState inputState : userState.inputMap.values()) {
1783fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang                    if (inputState.info.getComponent().equals(component)
1784fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang                            && inputState.state != INPUT_STATE_DISCONNECTED) {
1785fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang                        notifyInputStateChangedLocked(userState, inputState.info.getId(),
1786fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang                                inputState.state, null);
1787187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                    }
1788187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                }
1789187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim
1790fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang                if (serviceState.isHardware) {
17914f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                    List<TvInputHardwareInfo> hardwareInfoList =
17924f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                            mTvInputHardwareManager.getHardwareList();
1793187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                    for (TvInputHardwareInfo hardwareInfo : hardwareInfoList) {
1794187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                        try {
1795fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang                            serviceState.service.notifyHardwareAdded(hardwareInfo);
1796187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                        } catch (RemoteException e) {
1797187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                            Slog.e(TAG, "error in notifyHardwareAdded", e);
1798187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                        }
1799187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                    }
1800187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim
1801546c635ad9a26421fbdf54efa765b5ab0a63c191Jae Seo                    List<HdmiDeviceInfo> deviceInfoList =
1802546c635ad9a26421fbdf54efa765b5ab0a63c191Jae Seo                            mTvInputHardwareManager.getHdmiDeviceList();
1803546c635ad9a26421fbdf54efa765b5ab0a63c191Jae Seo                    for (HdmiDeviceInfo deviceInfo : deviceInfoList) {
18044f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                        try {
1805fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang                            serviceState.service.notifyHdmiDeviceAdded(deviceInfo);
18064f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                        } catch (RemoteException e) {
1807546c635ad9a26421fbdf54efa765b5ab0a63c191Jae Seo                            Slog.e(TAG, "error in notifyHdmiDeviceAdded", e);
18084f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                        }
18094f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                    }
1810969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                }
18113957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            }
18123957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
18133957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
18143957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        @Override
18159e8ade2eb7ee835963473c9cf6faaf5423b0b048Ji-Hwan Lee        public void onServiceDisconnected(ComponentName component) {
18163957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            if (DEBUG) {
18179e8ade2eb7ee835963473c9cf6faaf5423b0b048Ji-Hwan Lee                Slog.d(TAG, "onServiceDisconnected(component=" + component + ")");
18183957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            }
18199e8ade2eb7ee835963473c9cf6faaf5423b0b048Ji-Hwan Lee            if (!mComponent.equals(component)) {
18202b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                throw new IllegalArgumentException("Mismatched ComponentName: "
18219e8ade2eb7ee835963473c9cf6faaf5423b0b048Ji-Hwan Lee                        + mComponent + " (expected), " + component + " (actual).");
18222b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim            }
18232b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim            synchronized (mLock) {
18242b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                UserState userState = getUserStateLocked(mUserId);
18259e8ade2eb7ee835963473c9cf6faaf5423b0b048Ji-Hwan Lee                ServiceState serviceState = userState.serviceStateMap.get(mComponent);
18262b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                if (serviceState != null) {
1827fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang                    serviceState.reconnecting = true;
1828fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang                    serviceState.bound = false;
1829fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang                    serviceState.service = null;
1830fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang                    serviceState.callback = null;
18312b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim
1832426c9a4008b75b93cbfea15aa4b8c47c5fdb49b9Dongwon Kang                    abortPendingCreateSessionRequestsLocked(serviceState, null, mUserId);
18332b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim
1834187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                    for (TvInputState inputState : userState.inputMap.values()) {
1835fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang                        if (inputState.info.getComponent().equals(component)) {
1836fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang                            notifyInputStateChangedLocked(userState, inputState.info.getId(),
1837187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                                    INPUT_STATE_DISCONNECTED, null);
1838187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                        }
1839187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                    }
18402b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                }
18412b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim            }
18423957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
18433957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    }
18443957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
18453957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    private final class ServiceCallback extends ITvInputServiceCallback.Stub {
18469e8ade2eb7ee835963473c9cf6faaf5423b0b048Ji-Hwan Lee        private final ComponentName mComponent;
18473957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        private final int mUserId;
18483957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
18499e8ade2eb7ee835963473c9cf6faaf5423b0b048Ji-Hwan Lee        ServiceCallback(ComponentName component, int userId) {
18509e8ade2eb7ee835963473c9cf6faaf5423b0b048Ji-Hwan Lee            mComponent = component;
18513957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            mUserId = userId;
18523957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
18533957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
18544f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee        private void ensureHardwarePermission() {
18554f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee            if (mContext.checkCallingPermission(android.Manifest.permission.TV_INPUT_HARDWARE)
18564f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                    != PackageManager.PERMISSION_GRANTED) {
18574f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                throw new SecurityException("The caller does not have hardware permission");
18584f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee            }
18594f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee        }
18604f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee
18614f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee        private void ensureValidInput(TvInputInfo inputInfo) {
18629e8ade2eb7ee835963473c9cf6faaf5423b0b048Ji-Hwan Lee            if (inputInfo.getId() == null || !mComponent.equals(inputInfo.getComponent())) {
18634f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                throw new IllegalArgumentException("Invalid TvInputInfo");
18644f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee            }
18654f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee        }
18664f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee
18674f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee        private void addTvInputLocked(TvInputInfo inputInfo) {
18689e8ade2eb7ee835963473c9cf6faaf5423b0b048Ji-Hwan Lee            ServiceState serviceState = getServiceStateLocked(mComponent, mUserId);
1869fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang            serviceState.inputList.add(inputInfo);
187019ba61affbc0c4a4454abc6cf09f70ea428d1a62Chulwoo Lee            buildTvInputListLocked(mUserId, null);
18714f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee        }
18724f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee
18733957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        @Override
18744f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee        public void addHardwareTvInput(int deviceId, TvInputInfo inputInfo) {
18754f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee            ensureHardwarePermission();
18764f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee            ensureValidInput(inputInfo);
1877187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim            synchronized (mLock) {
18784f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                mTvInputHardwareManager.addHardwareTvInput(deviceId, inputInfo);
18794f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                addTvInputLocked(inputInfo);
18804f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee            }
18814f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee        }
1882187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim
18834f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee        @Override
18848960d1b1552729e3dfd33deee951ac75933ad8e5Jinsuk Kim        public void addHdmiTvInput(int id, TvInputInfo inputInfo) {
18854f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee            ensureHardwarePermission();
18864f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee            ensureValidInput(inputInfo);
18874f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee            synchronized (mLock) {
18888960d1b1552729e3dfd33deee951ac75933ad8e5Jinsuk Kim                mTvInputHardwareManager.addHdmiTvInput(id, inputInfo);
18894f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                addTvInputLocked(inputInfo);
18903957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            }
1891187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim        }
1892187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim
1893187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim        @Override
1894187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim        public void removeTvInput(String inputId) {
18954f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee            ensureHardwarePermission();
18963957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            synchronized (mLock) {
18979e8ade2eb7ee835963473c9cf6faaf5423b0b048Ji-Hwan Lee                ServiceState serviceState = getServiceStateLocked(mComponent, mUserId);
1898187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                boolean removed = false;
1899fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang                for (Iterator<TvInputInfo> it = serviceState.inputList.iterator();
1900187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                        it.hasNext(); ) {
1901187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                    if (it.next().getId().equals(inputId)) {
1902187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                        it.remove();
1903187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                        removed = true;
1904187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                        break;
1905187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                    }
1906187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                }
1907187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                if (removed) {
190819ba61affbc0c4a4454abc6cf09f70ea428d1a62Chulwoo Lee                    buildTvInputListLocked(mUserId, null);
19094f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                    mTvInputHardwareManager.removeTvInput(inputId);
1910187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                } else {
1911fea8dd45f4955b4b4b6536bf51453e19288deba2Jae Seo                    Slog.e(TAG, "failed to remove input " + inputId);
1912187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                }
19133957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            }
19143957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
19153957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    }
191631dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo
1917fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang    private final class SessionCallback extends ITvInputSessionCallback.Stub {
19189c6b5b729bd83b1d1e00428f8a76f272b609c97eJi-Hwan Lee        private final SessionState mSessionState;
1919fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang        private final InputChannel[] mChannels;
1920fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang
1921fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang        SessionCallback(SessionState sessionState, InputChannel[] channels) {
19229c6b5b729bd83b1d1e00428f8a76f272b609c97eJi-Hwan Lee            mSessionState = sessionState;
1923fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang            mChannels = channels;
1924fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang        }
1925fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang
1926fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang        @Override
1927fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang        public void onSessionCreated(ITvInputSession session, IBinder harewareSessionToken) {
1928fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang            if (DEBUG) {
19299c6b5b729bd83b1d1e00428f8a76f272b609c97eJi-Hwan Lee                Slog.d(TAG, "onSessionCreated(inputId=" + mSessionState.info.getId() + ")");
1930fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang            }
1931fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang            synchronized (mLock) {
19329c6b5b729bd83b1d1e00428f8a76f272b609c97eJi-Hwan Lee                mSessionState.session = session;
19339c6b5b729bd83b1d1e00428f8a76f272b609c97eJi-Hwan Lee                mSessionState.hardwareSessionToken = harewareSessionToken;
19349c6b5b729bd83b1d1e00428f8a76f272b609c97eJi-Hwan Lee                if (session != null && addSessionTokenToClientStateLocked(session)) {
19359c6b5b729bd83b1d1e00428f8a76f272b609c97eJi-Hwan Lee                    sendSessionTokenToClientLocked(mSessionState.client,
19369c6b5b729bd83b1d1e00428f8a76f272b609c97eJi-Hwan Lee                            mSessionState.info.getId(), mSessionState.sessionToken, mChannels[0],
19379c6b5b729bd83b1d1e00428f8a76f272b609c97eJi-Hwan Lee                            mSessionState.seq);
1938fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang                } else {
19399c6b5b729bd83b1d1e00428f8a76f272b609c97eJi-Hwan Lee                    removeSessionStateLocked(mSessionState.sessionToken, mSessionState.userId);
19409c6b5b729bd83b1d1e00428f8a76f272b609c97eJi-Hwan Lee                    sendSessionTokenToClientLocked(mSessionState.client,
19419c6b5b729bd83b1d1e00428f8a76f272b609c97eJi-Hwan Lee                            mSessionState.info.getId(), null, null, mSessionState.seq);
19429c6b5b729bd83b1d1e00428f8a76f272b609c97eJi-Hwan Lee                }
19439c6b5b729bd83b1d1e00428f8a76f272b609c97eJi-Hwan Lee                mChannels[0].dispose();
19449c6b5b729bd83b1d1e00428f8a76f272b609c97eJi-Hwan Lee            }
19459c6b5b729bd83b1d1e00428f8a76f272b609c97eJi-Hwan Lee        }
1946fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang
19479c6b5b729bd83b1d1e00428f8a76f272b609c97eJi-Hwan Lee        private boolean addSessionTokenToClientStateLocked(ITvInputSession session) {
19489c6b5b729bd83b1d1e00428f8a76f272b609c97eJi-Hwan Lee            try {
19499c6b5b729bd83b1d1e00428f8a76f272b609c97eJi-Hwan Lee                session.asBinder().linkToDeath(mSessionState, 0);
19509c6b5b729bd83b1d1e00428f8a76f272b609c97eJi-Hwan Lee            } catch (RemoteException e) {
19519c6b5b729bd83b1d1e00428f8a76f272b609c97eJi-Hwan Lee                Slog.e(TAG, "session process has already died", e);
19529c6b5b729bd83b1d1e00428f8a76f272b609c97eJi-Hwan Lee                return false;
19539c6b5b729bd83b1d1e00428f8a76f272b609c97eJi-Hwan Lee            }
1954fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang
19559c6b5b729bd83b1d1e00428f8a76f272b609c97eJi-Hwan Lee            IBinder clientToken = mSessionState.client.asBinder();
19569c6b5b729bd83b1d1e00428f8a76f272b609c97eJi-Hwan Lee            UserState userState = getUserStateLocked(mSessionState.userId);
19579c6b5b729bd83b1d1e00428f8a76f272b609c97eJi-Hwan Lee            ClientState clientState = userState.clientStateMap.get(clientToken);
19589c6b5b729bd83b1d1e00428f8a76f272b609c97eJi-Hwan Lee            if (clientState == null) {
19599c6b5b729bd83b1d1e00428f8a76f272b609c97eJi-Hwan Lee                clientState = new ClientState(clientToken, mSessionState.userId);
19609c6b5b729bd83b1d1e00428f8a76f272b609c97eJi-Hwan Lee                try {
19619c6b5b729bd83b1d1e00428f8a76f272b609c97eJi-Hwan Lee                    clientToken.linkToDeath(clientState, 0);
19629c6b5b729bd83b1d1e00428f8a76f272b609c97eJi-Hwan Lee                } catch (RemoteException e) {
19639c6b5b729bd83b1d1e00428f8a76f272b609c97eJi-Hwan Lee                    Slog.e(TAG, "client process has already died", e);
19649c6b5b729bd83b1d1e00428f8a76f272b609c97eJi-Hwan Lee                    return false;
1965fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang                }
19669c6b5b729bd83b1d1e00428f8a76f272b609c97eJi-Hwan Lee                userState.clientStateMap.put(clientToken, clientState);
1967fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang            }
19689c6b5b729bd83b1d1e00428f8a76f272b609c97eJi-Hwan Lee            clientState.sessionTokens.add(mSessionState.sessionToken);
19699c6b5b729bd83b1d1e00428f8a76f272b609c97eJi-Hwan Lee            return true;
1970fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang        }
1971fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang
1972fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang        @Override
1973fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang        public void onChannelRetuned(Uri channelUri) {
1974fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang            synchronized (mLock) {
1975fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang                if (DEBUG) {
1976fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang                    Slog.d(TAG, "onChannelRetuned(" + channelUri + ")");
1977fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang                }
19789c6b5b729bd83b1d1e00428f8a76f272b609c97eJi-Hwan Lee                if (mSessionState.session == null || mSessionState.client == null) {
1979fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang                    return;
1980fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang                }
1981fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang                try {
1982fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang                    // TODO: Consider adding this channel change in the watch log. When we do
1983fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang                    // that, how we can protect the watch log from malicious tv inputs should
1984fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang                    // be addressed. e.g. add a field which represents where the channel change
1985fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang                    // originated from.
19869c6b5b729bd83b1d1e00428f8a76f272b609c97eJi-Hwan Lee                    mSessionState.client.onChannelRetuned(channelUri, mSessionState.seq);
1987fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang                } catch (RemoteException e) {
1988fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang                    Slog.e(TAG, "error in onChannelRetuned", e);
1989fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang                }
1990fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang            }
1991fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang        }
1992fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang
1993fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang        @Override
1994fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang        public void onTracksChanged(List<TvTrackInfo> tracks) {
1995fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang            synchronized (mLock) {
1996fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang                if (DEBUG) {
1997fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang                    Slog.d(TAG, "onTracksChanged(" + tracks + ")");
1998fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang                }
19999c6b5b729bd83b1d1e00428f8a76f272b609c97eJi-Hwan Lee                if (mSessionState.session == null || mSessionState.client == null) {
2000fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang                    return;
2001fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang                }
2002fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang                try {
20039c6b5b729bd83b1d1e00428f8a76f272b609c97eJi-Hwan Lee                    mSessionState.client.onTracksChanged(tracks, mSessionState.seq);
2004fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang                } catch (RemoteException e) {
2005fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang                    Slog.e(TAG, "error in onTracksChanged", e);
2006fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang                }
2007fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang            }
2008fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang        }
2009fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang
2010fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang        @Override
2011fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang        public void onTrackSelected(int type, String trackId) {
2012fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang            synchronized (mLock) {
2013fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang                if (DEBUG) {
2014fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang                    Slog.d(TAG, "onTrackSelected(type=" + type + ", trackId=" + trackId + ")");
2015fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang                }
20169c6b5b729bd83b1d1e00428f8a76f272b609c97eJi-Hwan Lee                if (mSessionState.session == null || mSessionState.client == null) {
2017fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang                    return;
2018fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang                }
2019fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang                try {
20209c6b5b729bd83b1d1e00428f8a76f272b609c97eJi-Hwan Lee                    mSessionState.client.onTrackSelected(type, trackId, mSessionState.seq);
2021fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang                } catch (RemoteException e) {
2022fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang                    Slog.e(TAG, "error in onTrackSelected", e);
2023fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang                }
2024fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang            }
2025fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang        }
2026fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang
2027fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang        @Override
2028fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang        public void onVideoAvailable() {
2029fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang            synchronized (mLock) {
2030fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang                if (DEBUG) {
2031fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang                    Slog.d(TAG, "onVideoAvailable()");
2032fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang                }
20339c6b5b729bd83b1d1e00428f8a76f272b609c97eJi-Hwan Lee                if (mSessionState.session == null || mSessionState.client == null) {
2034fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang                    return;
2035fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang                }
2036fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang                try {
20379c6b5b729bd83b1d1e00428f8a76f272b609c97eJi-Hwan Lee                    mSessionState.client.onVideoAvailable(mSessionState.seq);
2038fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang                } catch (RemoteException e) {
2039fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang                    Slog.e(TAG, "error in onVideoAvailable", e);
2040fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang                }
2041fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang            }
2042fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang        }
2043fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang
2044fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang        @Override
2045fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang        public void onVideoUnavailable(int reason) {
2046fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang            synchronized (mLock) {
2047fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang                if (DEBUG) {
2048fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang                    Slog.d(TAG, "onVideoUnavailable(" + reason + ")");
2049fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang                }
20509c6b5b729bd83b1d1e00428f8a76f272b609c97eJi-Hwan Lee                if (mSessionState.session == null || mSessionState.client == null) {
2051fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang                    return;
2052fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang                }
2053fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang                try {
20549c6b5b729bd83b1d1e00428f8a76f272b609c97eJi-Hwan Lee                    mSessionState.client.onVideoUnavailable(reason, mSessionState.seq);
2055fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang                } catch (RemoteException e) {
2056fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang                    Slog.e(TAG, "error in onVideoUnavailable", e);
2057fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang                }
2058fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang            }
2059fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang        }
2060fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang
2061fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang        @Override
2062fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang        public void onContentAllowed() {
2063fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang            synchronized (mLock) {
2064fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang                if (DEBUG) {
2065fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang                    Slog.d(TAG, "onContentAllowed()");
2066fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang                }
20679c6b5b729bd83b1d1e00428f8a76f272b609c97eJi-Hwan Lee                if (mSessionState.session == null || mSessionState.client == null) {
2068fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang                    return;
2069fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang                }
2070fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang                try {
20719c6b5b729bd83b1d1e00428f8a76f272b609c97eJi-Hwan Lee                    mSessionState.client.onContentAllowed(mSessionState.seq);
2072fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang                } catch (RemoteException e) {
2073fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang                    Slog.e(TAG, "error in onContentAllowed", e);
2074fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang                }
2075fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang            }
2076fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang        }
2077fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang
2078fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang        @Override
2079fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang        public void onContentBlocked(String rating) {
2080fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang            synchronized (mLock) {
2081fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang                if (DEBUG) {
2082fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang                    Slog.d(TAG, "onContentBlocked()");
2083fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang                }
20849c6b5b729bd83b1d1e00428f8a76f272b609c97eJi-Hwan Lee                if (mSessionState.session == null || mSessionState.client == null) {
2085fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang                    return;
2086fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang                }
2087fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang                try {
20889c6b5b729bd83b1d1e00428f8a76f272b609c97eJi-Hwan Lee                    mSessionState.client.onContentBlocked(rating, mSessionState.seq);
2089fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang                } catch (RemoteException e) {
2090fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang                    Slog.e(TAG, "error in onContentBlocked", e);
2091fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang                }
2092fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang            }
2093fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang        }
2094fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang
2095fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang        @Override
2096fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang        public void onLayoutSurface(int left, int top, int right, int bottom) {
2097fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang            synchronized (mLock) {
2098fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang                if (DEBUG) {
2099fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang                    Slog.d(TAG, "onLayoutSurface (left=" + left + ", top=" + top
2100fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang                            + ", right=" + right + ", bottom=" + bottom + ",)");
2101fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang                }
21029c6b5b729bd83b1d1e00428f8a76f272b609c97eJi-Hwan Lee                if (mSessionState.session == null || mSessionState.client == null) {
2103fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang                    return;
2104fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang                }
2105fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang                try {
21069c6b5b729bd83b1d1e00428f8a76f272b609c97eJi-Hwan Lee                    mSessionState.client.onLayoutSurface(left, top, right, bottom,
21079c6b5b729bd83b1d1e00428f8a76f272b609c97eJi-Hwan Lee                            mSessionState.seq);
2108fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang                } catch (RemoteException e) {
2109fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang                    Slog.e(TAG, "error in onLayoutSurface", e);
2110fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang                }
2111fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang            }
2112fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang        }
2113fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang
2114fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang        @Override
2115fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang        public void onSessionEvent(String eventType, Bundle eventArgs) {
2116fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang            synchronized (mLock) {
2117fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang                if (DEBUG) {
2118fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang                    Slog.d(TAG, "onEvent(what=" + eventType + ", data=" + eventArgs + ")");
2119fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang                }
21209c6b5b729bd83b1d1e00428f8a76f272b609c97eJi-Hwan Lee                if (mSessionState.session == null || mSessionState.client == null) {
2121fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang                    return;
2122fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang                }
2123fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang                try {
21249c6b5b729bd83b1d1e00428f8a76f272b609c97eJi-Hwan Lee                    mSessionState.client.onSessionEvent(eventType, eventArgs, mSessionState.seq);
2125fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang                } catch (RemoteException e) {
2126fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang                    Slog.e(TAG, "error in onSessionEvent", e);
2127fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang                }
2128fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang            }
2129fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang        }
2130fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang    }
2131fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang
2132fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang    private static final class WatchLogHandler extends Handler {
21337eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo        // There are only two kinds of watch events that can happen on the system:
21347eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo        // 1. The current TV input session is tuned to a new channel.
21357eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo        // 2. The session is released for some reason.
21367eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo        // The former indicates the end of the previous log entry, if any, followed by the start of
21377eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo        // a new entry. The latter indicates the end of the most recent entry for the given session.
21387eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo        // Here the system supplies the database the smallest set of information only that is
21397eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo        // sufficient to consolidate the log entries while minimizing database operations in the
21407eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo        // system service.
21417eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo        private static final int MSG_LOG_WATCH_START = 1;
21427eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo        private static final int MSG_LOG_WATCH_END = 2;
21437eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo
2144fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang        private final ContentResolver mContentResolver;
2145fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang
2146fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang        public WatchLogHandler(ContentResolver contentResolver, Looper looper) {
214731dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo            super(looper);
2148fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang            mContentResolver = contentResolver;
214931dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo        }
215031dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo
215131dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo        @Override
215231dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo        public void handleMessage(Message msg) {
215331dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo            switch (msg.what) {
21547eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo                case MSG_LOG_WATCH_START: {
215531dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                    SomeArgs args = (SomeArgs) msg.obj;
21567eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo                    String packageName = (String) args.arg1;
21577eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo                    long watchStartTime = (long) args.arg2;
21587eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo                    long channelId = (long) args.arg3;
21597eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo                    Bundle tuneParams = (Bundle) args.arg4;
21607eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo                    IBinder sessionToken = (IBinder) args.arg5;
21617eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo
21627eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo                    ContentValues values = new ContentValues();
21637eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo                    values.put(TvContract.WatchedPrograms.COLUMN_PACKAGE_NAME, packageName);
21647eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo                    values.put(TvContract.WatchedPrograms.COLUMN_WATCH_START_TIME_UTC_MILLIS,
21657eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo                            watchStartTime);
21667eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo                    values.put(TvContract.WatchedPrograms.COLUMN_CHANNEL_ID, channelId);
21677eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo                    if (tuneParams != null) {
21687eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo                        values.put(TvContract.WatchedPrograms.COLUMN_INTERNAL_TUNE_PARAMS,
21697eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo                                encodeTuneParams(tuneParams));
21707eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo                    }
21717eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo                    values.put(TvContract.WatchedPrograms.COLUMN_INTERNAL_SESSION_TOKEN,
21727eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo                            sessionToken.toString());
21737eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo
21747eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo                    mContentResolver.insert(TvContract.WatchedPrograms.CONTENT_URI, values);
217531dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                    args.recycle();
217631dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                    return;
217731dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                }
21787eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo                case MSG_LOG_WATCH_END: {
217931dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                    SomeArgs args = (SomeArgs) msg.obj;
21807eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo                    IBinder sessionToken = (IBinder) args.arg1;
21817eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo                    long watchEndTime = (long) args.arg2;
21827eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo
21837eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo                    ContentValues values = new ContentValues();
21847eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo                    values.put(TvContract.WatchedPrograms.COLUMN_WATCH_END_TIME_UTC_MILLIS,
21857eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo                            watchEndTime);
21867eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo                    values.put(TvContract.WatchedPrograms.COLUMN_INTERNAL_SESSION_TOKEN,
21877eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo                            sessionToken.toString());
21887eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo
21897eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo                    mContentResolver.insert(TvContract.WatchedPrograms.CONTENT_URI, values);
219031dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                    args.recycle();
219131dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                    return;
219231dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                }
219331dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                default: {
21946a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                    Slog.w(TAG, "Unhandled message code: " + msg.what);
219531dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                    return;
219631dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                }
219731dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo            }
219831dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo        }
219931dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo
22007eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo        private String encodeTuneParams(Bundle tuneParams) {
22017eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo            StringBuilder builder = new StringBuilder();
22027eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo            Set<String> keySet = tuneParams.keySet();
22037eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo            Iterator<String> it = keySet.iterator();
22047eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo            while (it.hasNext()) {
22057eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo                String key = it.next();
22067eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo                Object value = tuneParams.get(key);
22077eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo                if (value == null) {
22087eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo                    continue;
220931dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                }
22107eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo                builder.append(replaceEscapeCharacters(key));
22117eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo                builder.append("=");
22127eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo                builder.append(replaceEscapeCharacters(value.toString()));
22137eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo                if (it.hasNext()) {
22147eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo                    builder.append(", ");
221531dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                }
221631dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo            }
22177eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo            return builder.toString();
221831dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo        }
221931dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo
22207eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo        private String replaceEscapeCharacters(String src) {
22217eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo            final char ESCAPE_CHARACTER = '%';
22227eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo            final String ENCODING_TARGET_CHARACTERS = "%=,";
22237eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo            StringBuilder builder = new StringBuilder();
22247eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo            for (char ch : src.toCharArray()) {
22257eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo                if (ENCODING_TARGET_CHARACTERS.indexOf(ch) >= 0) {
22267eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo                    builder.append(ESCAPE_CHARACTER);
2227579befecb248162021929ab58ffd23f1724cc6beJae Seo                }
22287eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo                builder.append(ch);
2229579befecb248162021929ab58ffd23f1724cc6beJae Seo            }
22307eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo            return builder.toString();
2231579befecb248162021929ab58ffd23f1724cc6beJae Seo        }
223231dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo    }
2233969167dc05a6485a32d160895871cff46fd81884Wonsik Kim
2234fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang    private final class HardwareListener implements TvInputHardwareManager.Listener {
2235187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim        @Override
2236187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim        public void onStateChanged(String inputId, int state) {
2237969167dc05a6485a32d160895871cff46fd81884Wonsik Kim            synchronized (mLock) {
2238969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                setStateLocked(inputId, state, mCurrentUserId);
2239969167dc05a6485a32d160895871cff46fd81884Wonsik Kim            }
2240969167dc05a6485a32d160895871cff46fd81884Wonsik Kim        }
2241187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim
2242187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim        @Override
2243187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim        public void onHardwareDeviceAdded(TvInputHardwareInfo info) {
2244187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim            synchronized (mLock) {
2245187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                UserState userState = getUserStateLocked(mCurrentUserId);
2246187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                // Broadcast the event to all hardware inputs.
2247187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                for (ServiceState serviceState : userState.serviceStateMap.values()) {
2248fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang                    if (!serviceState.isHardware || serviceState.service == null) continue;
2249187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                    try {
2250fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang                        serviceState.service.notifyHardwareAdded(info);
2251187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                    } catch (RemoteException e) {
2252187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                        Slog.e(TAG, "error in notifyHardwareAdded", e);
2253187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                    }
2254187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                }
2255187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim            }
2256187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim        }
2257187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim
2258187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim        @Override
22594f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee        public void onHardwareDeviceRemoved(TvInputHardwareInfo info) {
2260187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim            synchronized (mLock) {
2261187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                UserState userState = getUserStateLocked(mCurrentUserId);
2262187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                // Broadcast the event to all hardware inputs.
2263187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                for (ServiceState serviceState : userState.serviceStateMap.values()) {
2264fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang                    if (!serviceState.isHardware || serviceState.service == null) continue;
2265187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                    try {
2266fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang                        serviceState.service.notifyHardwareRemoved(info);
2267187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                    } catch (RemoteException e) {
2268187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                        Slog.e(TAG, "error in notifyHardwareRemoved", e);
2269187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                    }
2270187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                }
2271187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim            }
2272187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim        }
2273187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim
2274187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim        @Override
2275546c635ad9a26421fbdf54efa765b5ab0a63c191Jae Seo        public void onHdmiDeviceAdded(HdmiDeviceInfo deviceInfo) {
2276187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim            synchronized (mLock) {
22774f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                UserState userState = getUserStateLocked(mCurrentUserId);
22784f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                // Broadcast the event to all hardware inputs.
22794f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                for (ServiceState serviceState : userState.serviceStateMap.values()) {
2280fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang                    if (!serviceState.isHardware || serviceState.service == null) continue;
22814f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                    try {
2282fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang                        serviceState.service.notifyHdmiDeviceAdded(deviceInfo);
22834f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                    } catch (RemoteException e) {
2284546c635ad9a26421fbdf54efa765b5ab0a63c191Jae Seo                        Slog.e(TAG, "error in notifyHdmiDeviceAdded", e);
22854f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                    }
22864f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                }
2287187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim            }
2288187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim        }
2289187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim
2290187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim        @Override
2291546c635ad9a26421fbdf54efa765b5ab0a63c191Jae Seo        public void onHdmiDeviceRemoved(HdmiDeviceInfo deviceInfo) {
2292187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim            synchronized (mLock) {
22934f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                UserState userState = getUserStateLocked(mCurrentUserId);
22944f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                // Broadcast the event to all hardware inputs.
22954f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                for (ServiceState serviceState : userState.serviceStateMap.values()) {
2296fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang                    if (!serviceState.isHardware || serviceState.service == null) continue;
22974f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                    try {
2298fd8aa02d73ed43fb90bf44dbe4d65d378261d905Dongwon Kang                        serviceState.service.notifyHdmiDeviceRemoved(deviceInfo);
22994f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                    } catch (RemoteException e) {
2300546c635ad9a26421fbdf54efa765b5ab0a63c191Jae Seo                        Slog.e(TAG, "error in notifyHdmiDeviceRemoved", e);
23014f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                    }
23024f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                }
2303187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim            }
2304187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim        }
230561daf6b38e7a7ada2a6ca5a60539a54b9c6810bdJungshik Jang
230661daf6b38e7a7ada2a6ca5a60539a54b9c6810bdJungshik Jang        @Override
2307e92f857d50d7259a4cf7ef5b88309e098338c9c1Wonsik Kim        public void onHdmiDeviceUpdated(String inputId, HdmiDeviceInfo deviceInfo) {
2308e92f857d50d7259a4cf7ef5b88309e098338c9c1Wonsik Kim            synchronized (mLock) {
2309e92f857d50d7259a4cf7ef5b88309e098338c9c1Wonsik Kim                Integer state = null;
2310e92f857d50d7259a4cf7ef5b88309e098338c9c1Wonsik Kim                switch (deviceInfo.getDevicePowerStatus()) {
2311e92f857d50d7259a4cf7ef5b88309e098338c9c1Wonsik Kim                    case HdmiControlManager.POWER_STATUS_ON:
2312e92f857d50d7259a4cf7ef5b88309e098338c9c1Wonsik Kim                        state = INPUT_STATE_CONNECTED;
2313e92f857d50d7259a4cf7ef5b88309e098338c9c1Wonsik Kim                        break;
2314e92f857d50d7259a4cf7ef5b88309e098338c9c1Wonsik Kim                    case HdmiControlManager.POWER_STATUS_STANDBY:
2315e92f857d50d7259a4cf7ef5b88309e098338c9c1Wonsik Kim                    case HdmiControlManager.POWER_STATUS_TRANSIENT_TO_ON:
2316e92f857d50d7259a4cf7ef5b88309e098338c9c1Wonsik Kim                    case HdmiControlManager.POWER_STATUS_TRANSIENT_TO_STANDBY:
2317e92f857d50d7259a4cf7ef5b88309e098338c9c1Wonsik Kim                        state = INPUT_STATE_CONNECTED_STANDBY;
2318e92f857d50d7259a4cf7ef5b88309e098338c9c1Wonsik Kim                        break;
2319e92f857d50d7259a4cf7ef5b88309e098338c9c1Wonsik Kim                    case HdmiControlManager.POWER_STATUS_UNKNOWN:
2320e92f857d50d7259a4cf7ef5b88309e098338c9c1Wonsik Kim                    default:
2321e92f857d50d7259a4cf7ef5b88309e098338c9c1Wonsik Kim                        state = null;
2322e92f857d50d7259a4cf7ef5b88309e098338c9c1Wonsik Kim                        break;
2323e92f857d50d7259a4cf7ef5b88309e098338c9c1Wonsik Kim                }
2324e92f857d50d7259a4cf7ef5b88309e098338c9c1Wonsik Kim                if (state != null) {
2325e92f857d50d7259a4cf7ef5b88309e098338c9c1Wonsik Kim                    setStateLocked(inputId, state.intValue(), mCurrentUserId);
2326e92f857d50d7259a4cf7ef5b88309e098338c9c1Wonsik Kim                }
2327e92f857d50d7259a4cf7ef5b88309e098338c9c1Wonsik Kim            }
232861daf6b38e7a7ada2a6ca5a60539a54b9c6810bdJungshik Jang        }
2329969167dc05a6485a32d160895871cff46fd81884Wonsik Kim    }
23303957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo}
2331