TvInputManagerService.java revision 426c9a4008b75b93cbfea15aa4b8c47c5fdb49b9
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;
363957091ba8f08c02b5e781098cb955a5f697a1ffJae Seoimport android.content.pm.PackageManager;
373957091ba8f08c02b5e781098cb955a5f697a1ffJae Seoimport android.content.pm.ResolveInfo;
383957091ba8f08c02b5e781098cb955a5f697a1ffJae Seoimport android.content.pm.ServiceInfo;
399a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Choimport android.graphics.Rect;
40e92f857d50d7259a4cf7ef5b88309e098338c9c1Wonsik Kimimport android.hardware.hdmi.HdmiControlManager;
4161f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jangimport android.hardware.hdmi.HdmiDeviceInfo;
42d5cc4a281e7ce29d1e8687ff3394b57a3a549260Jae Seoimport android.media.tv.ITvInputClient;
43d5cc4a281e7ce29d1e8687ff3394b57a3a549260Jae Seoimport android.media.tv.ITvInputHardware;
44d5cc4a281e7ce29d1e8687ff3394b57a3a549260Jae Seoimport android.media.tv.ITvInputHardwareCallback;
45d5cc4a281e7ce29d1e8687ff3394b57a3a549260Jae Seoimport android.media.tv.ITvInputManager;
46969167dc05a6485a32d160895871cff46fd81884Wonsik Kimimport android.media.tv.ITvInputManagerCallback;
47d5cc4a281e7ce29d1e8687ff3394b57a3a549260Jae Seoimport android.media.tv.ITvInputService;
48d5cc4a281e7ce29d1e8687ff3394b57a3a549260Jae Seoimport android.media.tv.ITvInputServiceCallback;
49d5cc4a281e7ce29d1e8687ff3394b57a3a549260Jae Seoimport android.media.tv.ITvInputSession;
50d5cc4a281e7ce29d1e8687ff3394b57a3a549260Jae Seoimport android.media.tv.ITvInputSessionCallback;
51783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seoimport android.media.tv.TvContentRating;
52d5cc4a281e7ce29d1e8687ff3394b57a3a549260Jae Seoimport android.media.tv.TvContract;
53d5cc4a281e7ce29d1e8687ff3394b57a3a549260Jae Seoimport android.media.tv.TvInputHardwareInfo;
54d5cc4a281e7ce29d1e8687ff3394b57a3a549260Jae Seoimport android.media.tv.TvInputInfo;
55d5cc4a281e7ce29d1e8687ff3394b57a3a549260Jae Seoimport android.media.tv.TvInputService;
56c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heoimport android.media.tv.TvStreamConfig;
571f213914c45c23c653f721690da2ce0718e63139Dongwon Kangimport android.media.tv.TvTrackInfo;
583957091ba8f08c02b5e781098cb955a5f697a1ffJae Seoimport android.net.Uri;
593957091ba8f08c02b5e781098cb955a5f697a1ffJae Seoimport android.os.Binder;
60832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Choimport android.os.Bundle;
6131dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seoimport android.os.Handler;
623957091ba8f08c02b5e781098cb955a5f697a1ffJae Seoimport android.os.IBinder;
6331dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seoimport android.os.Looper;
6431dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seoimport android.os.Message;
653957091ba8f08c02b5e781098cb955a5f697a1ffJae Seoimport android.os.Process;
663957091ba8f08c02b5e781098cb955a5f697a1ffJae Seoimport android.os.RemoteException;
673957091ba8f08c02b5e781098cb955a5f697a1ffJae Seoimport android.os.UserHandle;
689a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Choimport android.util.Slog;
693957091ba8f08c02b5e781098cb955a5f697a1ffJae Seoimport android.util.SparseArray;
706a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seoimport android.view.InputChannel;
713957091ba8f08c02b5e781098cb955a5f697a1ffJae Seoimport android.view.Surface;
723957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
733957091ba8f08c02b5e781098cb955a5f697a1ffJae Seoimport com.android.internal.content.PackageMonitor;
7431dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seoimport com.android.internal.os.SomeArgs;
75e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kimimport com.android.internal.util.IndentingPrintWriter;
7631dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seoimport com.android.server.IoThread;
773957091ba8f08c02b5e781098cb955a5f697a1ffJae Seoimport com.android.server.SystemService;
783957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
79e7bb7d6bb2257c24076f5a4b9f536f90a6637f58Chulwoo Leeimport org.xmlpull.v1.XmlPullParserException;
80e7bb7d6bb2257c24076f5a4b9f536f90a6637f58Chulwoo Lee
81e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kimimport java.io.FileDescriptor;
82e7bb7d6bb2257c24076f5a4b9f536f90a6637f58Chulwoo Leeimport java.io.IOException;
83e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kimimport java.io.PrintWriter;
843957091ba8f08c02b5e781098cb955a5f697a1ffJae Seoimport java.util.ArrayList;
853957091ba8f08c02b5e781098cb955a5f697a1ffJae Seoimport java.util.HashMap;
865c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seoimport java.util.HashSet;
87187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kimimport java.util.Iterator;
883957091ba8f08c02b5e781098cb955a5f697a1ffJae Seoimport java.util.List;
893957091ba8f08c02b5e781098cb955a5f697a1ffJae Seoimport java.util.Map;
905c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seoimport java.util.Set;
913957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
923957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo/** This class provides a system service that manages television inputs. */
933957091ba8f08c02b5e781098cb955a5f697a1ffJae Seopublic final class TvInputManagerService extends SystemService {
943957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    // STOPSHIP: Turn debugging off.
953957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    private static final boolean DEBUG = true;
963957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    private static final String TAG = "TvInputManagerService";
973957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
983957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    private final Context mContext;
99c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim    private final TvInputHardwareManager mTvInputHardwareManager;
1003957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
10131dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo    private final ContentResolver mContentResolver;
10231dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo
1033957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    // A global lock.
1043957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    private final Object mLock = new Object();
1053957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
1063957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    // ID of the current user.
1073957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    private int mCurrentUserId = UserHandle.USER_OWNER;
1083957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
1093957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    // A map from user id to UserState.
1103957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    private final SparseArray<UserState> mUserStates = new SparseArray<UserState>();
1113957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
1127eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo    private final WatchLogHandler mWatchLogHandler;
11331dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo
1143957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    public TvInputManagerService(Context context) {
1153957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        super(context);
11631dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo
1173957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        mContext = context;
11831dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo        mContentResolver = context.getContentResolver();
1197eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo        mWatchLogHandler = new WatchLogHandler(IoThread.get().getLooper());
12031dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo
121187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim        mTvInputHardwareManager = new TvInputHardwareManager(context, new HardwareListener());
12231dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo
1233957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        synchronized (mLock) {
124783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo            mUserStates.put(mCurrentUserId, new UserState(mContext, mCurrentUserId));
1253957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
1263957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    }
1273957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
1283957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    @Override
1293957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    public void onStart() {
1303957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        publishBinderService(Context.TV_INPUT_SERVICE, new BinderService());
1313957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    }
1323957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
1330ceb7e4755015eafda29c251eac285620788a51bJi-Hwan Lee    @Override
1340ceb7e4755015eafda29c251eac285620788a51bJi-Hwan Lee    public void onBootPhase(int phase) {
1350ceb7e4755015eafda29c251eac285620788a51bJi-Hwan Lee        if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY) {
1360ceb7e4755015eafda29c251eac285620788a51bJi-Hwan Lee            registerBroadcastReceivers();
137187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim        } else if (phase == SystemService.PHASE_THIRD_PARTY_APPS_CAN_START) {
1380ceb7e4755015eafda29c251eac285620788a51bJi-Hwan Lee            synchronized (mLock) {
1390ceb7e4755015eafda29c251eac285620788a51bJi-Hwan Lee                buildTvInputListLocked(mCurrentUserId);
1400ceb7e4755015eafda29c251eac285620788a51bJi-Hwan Lee            }
1410ceb7e4755015eafda29c251eac285620788a51bJi-Hwan Lee        }
142969167dc05a6485a32d160895871cff46fd81884Wonsik Kim        mTvInputHardwareManager.onBootPhase(phase);
1430ceb7e4755015eafda29c251eac285620788a51bJi-Hwan Lee    }
1440ceb7e4755015eafda29c251eac285620788a51bJi-Hwan Lee
1453957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    private void registerBroadcastReceivers() {
1463957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        PackageMonitor monitor = new PackageMonitor() {
1473957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            @Override
1483957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            public void onSomePackagesChanged() {
149426c9a4008b75b93cbfea15aa4b8c47c5fdb49b9Dongwon Kang                if (DEBUG) Slog.d(TAG, "onSomePackagesChanged()");
1503957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                synchronized (mLock) {
1513957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    buildTvInputListLocked(mCurrentUserId);
1523957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                }
1533957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            }
1545c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo
1555c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo            @Override
1565c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo            public void onPackageRemoved(String packageName, int uid) {
1575c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo                synchronized (mLock) {
1585c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo                    UserState userState = getUserStateLocked(mCurrentUserId);
159969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                    if (!userState.packageSet.contains(packageName)) {
1605c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo                        // Not a TV input package.
1615c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo                        return;
1625c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo                    }
1635c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo                }
1645c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo
1655c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo                ArrayList<ContentProviderOperation> operations =
1665c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo                        new ArrayList<ContentProviderOperation>();
1675c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo
1685c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo                String selection = TvContract.BaseTvColumns.COLUMN_PACKAGE_NAME + "=?";
1695c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo                String[] selectionArgs = { packageName };
1705c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo
1715c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo                operations.add(ContentProviderOperation.newDelete(TvContract.Channels.CONTENT_URI)
1725c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo                        .withSelection(selection, selectionArgs).build());
1735c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo                operations.add(ContentProviderOperation.newDelete(TvContract.Programs.CONTENT_URI)
1745c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo                        .withSelection(selection, selectionArgs).build());
1755c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo                operations.add(ContentProviderOperation
1765c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo                        .newDelete(TvContract.WatchedPrograms.CONTENT_URI)
1775c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo                        .withSelection(selection, selectionArgs).build());
1785c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo
1795c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo                ContentProviderResult[] results = null;
1805c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo                try {
1815c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo                    results = mContentResolver.applyBatch(TvContract.AUTHORITY, operations);
1825c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo                } catch (RemoteException | OperationApplicationException e) {
1835c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo                    Slog.e(TAG, "error in applyBatch" + e);
1845c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo                }
1855c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo
1865c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo                if (DEBUG) {
1875c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo                    Slog.d(TAG, "onPackageRemoved(packageName=" + packageName + ", uid=" + uid
1885c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo                            + ")");
1895c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo                    Slog.d(TAG, "results=" + results);
1905c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo                }
1915c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo            }
1923957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        };
1933957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        monitor.register(mContext, null, UserHandle.ALL, true);
1943957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
1953957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        IntentFilter intentFilter = new IntentFilter();
1963957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        intentFilter.addAction(Intent.ACTION_USER_SWITCHED);
1973957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        intentFilter.addAction(Intent.ACTION_USER_REMOVED);
1983957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        mContext.registerReceiverAsUser(new BroadcastReceiver() {
1993957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            @Override
2003957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            public void onReceive(Context context, Intent intent) {
2013957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                String action = intent.getAction();
2023957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                if (Intent.ACTION_USER_SWITCHED.equals(action)) {
2033957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    switchUser(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0));
2043957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                } else if (Intent.ACTION_USER_REMOVED.equals(action)) {
2053957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    removeUser(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0));
2063957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                }
2073957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            }
2083957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }, UserHandle.ALL, intentFilter, null, null);
2093957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    }
2103957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
2119e8ade2eb7ee835963473c9cf6faaf5423b0b048Ji-Hwan Lee    private static boolean hasHardwarePermission(PackageManager pm, ComponentName component) {
212187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim        return pm.checkPermission(android.Manifest.permission.TV_INPUT_HARDWARE,
2139e8ade2eb7ee835963473c9cf6faaf5423b0b048Ji-Hwan Lee                component.getPackageName()) == PackageManager.PERMISSION_GRANTED;
214187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim    }
215187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim
2163957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    private void buildTvInputListLocked(int userId) {
2173957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        UserState userState = getUserStateLocked(userId);
218969167dc05a6485a32d160895871cff46fd81884Wonsik Kim        userState.packageSet.clear();
2193957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
2209a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho        if (DEBUG) Slog.d(TAG, "buildTvInputList");
2213957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        PackageManager pm = mContext.getPackageManager();
2223957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        List<ResolveInfo> services = pm.queryIntentServices(
223e7bb7d6bb2257c24076f5a4b9f536f90a6637f58Chulwoo Lee                new Intent(TvInputService.SERVICE_INTERFACE),
224e7bb7d6bb2257c24076f5a4b9f536f90a6637f58Chulwoo Lee                PackageManager.GET_SERVICES | PackageManager.GET_META_DATA);
2254f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee        List<TvInputInfo> inputList = new ArrayList<TvInputInfo>();
2263957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        for (ResolveInfo ri : services) {
2273957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            ServiceInfo si = ri.serviceInfo;
2283957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            if (!android.Manifest.permission.BIND_TV_INPUT.equals(si.permission)) {
2299a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                Slog.w(TAG, "Skipping TV input " + si.name + ": it does not require the permission "
2303957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                        + android.Manifest.permission.BIND_TV_INPUT);
2313957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                continue;
2323957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            }
2339cc28e5175e1391646b29469d329c9c1c9311ee1Jae Seo
2349cc28e5175e1391646b29469d329c9c1c9311ee1Jae Seo            ComponentName component = new ComponentName(si.packageName, si.name);
2359cc28e5175e1391646b29469d329c9c1c9311ee1Jae Seo            if (hasHardwarePermission(pm, component)) {
2369cc28e5175e1391646b29469d329c9c1c9311ee1Jae Seo                ServiceState serviceState = userState.serviceStateMap.get(component);
2379cc28e5175e1391646b29469d329c9c1c9311ee1Jae Seo                if (serviceState == null) {
2389cc28e5175e1391646b29469d329c9c1c9311ee1Jae Seo                    // We see this hardware TV input service for the first time; we need to
2399cc28e5175e1391646b29469d329c9c1c9311ee1Jae Seo                    // prepare the ServiceState object so that we can connect to the service and
2409cc28e5175e1391646b29469d329c9c1c9311ee1Jae Seo                    // let it add TvInputInfo objects to mInputList if there's any.
2419cc28e5175e1391646b29469d329c9c1c9311ee1Jae Seo                    serviceState = new ServiceState(component, userId);
2429cc28e5175e1391646b29469d329c9c1c9311ee1Jae Seo                    userState.serviceStateMap.put(component, serviceState);
243187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                } else {
2449cc28e5175e1391646b29469d329c9c1c9311ee1Jae Seo                    inputList.addAll(serviceState.mInputList);
245187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                }
2469cc28e5175e1391646b29469d329c9c1c9311ee1Jae Seo            } else {
2479cc28e5175e1391646b29469d329c9c1c9311ee1Jae Seo                try {
2489cc28e5175e1391646b29469d329c9c1c9311ee1Jae Seo                    inputList.add(TvInputInfo.createTvInputInfo(mContext, ri));
2499cc28e5175e1391646b29469d329c9c1c9311ee1Jae Seo                } catch (XmlPullParserException | IOException e) {
2509cc28e5175e1391646b29469d329c9c1c9311ee1Jae Seo                    Slog.e(TAG, "Failed to load TV input " + si.name, e);
2519cc28e5175e1391646b29469d329c9c1c9311ee1Jae Seo                    continue;
252969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                }
2539cc28e5175e1391646b29469d329c9c1c9311ee1Jae Seo            }
254226a51958d645a8e2be3e40a6b6daaca558b4913Jaewan Kim
2559cc28e5175e1391646b29469d329c9c1c9311ee1Jae Seo            // Reconnect the service if existing input is updated.
2569cc28e5175e1391646b29469d329c9c1c9311ee1Jae Seo            updateServiceConnectionLocked(component, userId);
2579cc28e5175e1391646b29469d329c9c1c9311ee1Jae Seo            userState.packageSet.add(si.packageName);
2589cc28e5175e1391646b29469d329c9c1c9311ee1Jae Seo        }
259187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim
2609cc28e5175e1391646b29469d329c9c1c9311ee1Jae Seo        Map<String, TvInputState> inputMap = new HashMap<String, TvInputState>();
2619cc28e5175e1391646b29469d329c9c1c9311ee1Jae Seo        for (TvInputInfo info : inputList) {
2629cc28e5175e1391646b29469d329c9c1c9311ee1Jae Seo            if (DEBUG) Slog.d(TAG, "add " + info.getId());
2639cc28e5175e1391646b29469d329c9c1c9311ee1Jae Seo            TvInputState state = userState.inputMap.get(info.getId());
2649cc28e5175e1391646b29469d329c9c1c9311ee1Jae Seo            if (state == null) {
2659cc28e5175e1391646b29469d329c9c1c9311ee1Jae Seo                state = new TvInputState();
266e7bb7d6bb2257c24076f5a4b9f536f90a6637f58Chulwoo Lee            }
2679cc28e5175e1391646b29469d329c9c1c9311ee1Jae Seo            state.mInfo = info;
2689cc28e5175e1391646b29469d329c9c1c9311ee1Jae Seo            inputMap.put(info.getId(), state);
2693957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
2708e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim
2718e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim        for (String inputId : inputMap.keySet()) {
2728e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim            if (!userState.inputMap.containsKey(inputId)) {
2738e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim                notifyInputAddedLocked(userState, inputId);
2748e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim            }
2758e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim        }
2768e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim
2778e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim        for (String inputId : userState.inputMap.keySet()) {
2788e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim            if (!inputMap.containsKey(inputId)) {
279426c9a4008b75b93cbfea15aa4b8c47c5fdb49b9Dongwon Kang                TvInputInfo info = userState.inputMap.get(inputId).mInfo;
280426c9a4008b75b93cbfea15aa4b8c47c5fdb49b9Dongwon Kang                ServiceState serviceState = userState.serviceStateMap.get(info.getComponent());
281426c9a4008b75b93cbfea15aa4b8c47c5fdb49b9Dongwon Kang                if (serviceState != null) {
282426c9a4008b75b93cbfea15aa4b8c47c5fdb49b9Dongwon Kang                    abortPendingCreateSessionRequestsLocked(serviceState, inputId, userId);
283426c9a4008b75b93cbfea15aa4b8c47c5fdb49b9Dongwon Kang                }
2848e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim                notifyInputRemovedLocked(userState, inputId);
2858e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim            }
2868e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim        }
2878e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim
2888e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim        userState.inputMap.clear();
2898e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim        userState.inputMap = inputMap;
2905c5b83fcd58d21c9ab7ac986bf84f604ec5bb4b5Sungsoo Lim
2915c5b83fcd58d21c9ab7ac986bf84f604ec5bb4b5Sungsoo Lim        userState.ratingSystemXmlUriSet.clear();
2925c5b83fcd58d21c9ab7ac986bf84f604ec5bb4b5Sungsoo Lim        for (TvInputState state : userState.inputMap.values()) {
2935c5b83fcd58d21c9ab7ac986bf84f604ec5bb4b5Sungsoo Lim            Uri ratingSystemXmlUri = state.mInfo.getRatingSystemXmlUri();
2945c5b83fcd58d21c9ab7ac986bf84f604ec5bb4b5Sungsoo Lim            if (ratingSystemXmlUri != null) {
2955c5b83fcd58d21c9ab7ac986bf84f604ec5bb4b5Sungsoo Lim                // TODO: need to check the validation of xml format and the duplication of rating
2965c5b83fcd58d21c9ab7ac986bf84f604ec5bb4b5Sungsoo Lim                // systems.
2975c5b83fcd58d21c9ab7ac986bf84f604ec5bb4b5Sungsoo Lim                userState.ratingSystemXmlUriSet.add(state.mInfo.getRatingSystemXmlUri());
2985c5b83fcd58d21c9ab7ac986bf84f604ec5bb4b5Sungsoo Lim            }
2995c5b83fcd58d21c9ab7ac986bf84f604ec5bb4b5Sungsoo Lim        }
3003957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    }
3013957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
3023957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    private void switchUser(int userId) {
3033957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        synchronized (mLock) {
3043957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            if (mCurrentUserId == userId) {
3053957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                return;
3063957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            }
3073957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            // final int oldUserId = mCurrentUserId;
3083957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            // TODO: Release services and sessions in the old user state, if needed.
3093957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            mCurrentUserId = userId;
3103957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
3113957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            UserState userState = mUserStates.get(userId);
3123957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            if (userState == null) {
313783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                userState = new UserState(mContext, userId);
3143957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            }
3153957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            mUserStates.put(userId, userState);
3163957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            buildTvInputListLocked(userId);
3173957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
3183957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    }
3193957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
3203957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    private void removeUser(int userId) {
3213957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        synchronized (mLock) {
322b06cb8870f0407f18bb1225065a93aba2a5de2bfJae Seo            UserState userState = mUserStates.get(userId);
323b06cb8870f0407f18bb1225065a93aba2a5de2bfJae Seo            if (userState == null) {
324b06cb8870f0407f18bb1225065a93aba2a5de2bfJae Seo                return;
325b06cb8870f0407f18bb1225065a93aba2a5de2bfJae Seo            }
3263957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            // Release created sessions.
3273957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            for (SessionState state : userState.sessionStateMap.values()) {
328d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim                if (state.mSession != null) {
3293957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    try {
330d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim                        state.mSession.release();
3313957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    } catch (RemoteException e) {
3329a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                        Slog.e(TAG, "error in release", e);
3333957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    }
3343957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                }
3353957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            }
3363957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            userState.sessionStateMap.clear();
3373957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
3383957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            // Unregister all callbacks and unbind all services.
3393957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            for (ServiceState serviceState : userState.serviceStateMap.values()) {
340d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim                if (serviceState.mCallback != null) {
3413957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    try {
342d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim                        serviceState.mService.unregisterCallback(serviceState.mCallback);
3433957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    } catch (RemoteException e) {
3449a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                        Slog.e(TAG, "error in unregisterCallback", e);
3453957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    }
3463957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                }
347d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim                mContext.unbindService(serviceState.mConnection);
3483957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            }
3493957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            userState.serviceStateMap.clear();
3503957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
35172ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim            userState.clientStateMap.clear();
35272ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim
3533957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            mUserStates.remove(userId);
3543957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
3553957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    }
3563957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
3573957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    private UserState getUserStateLocked(int userId) {
3583957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        UserState userState = mUserStates.get(userId);
3593957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        if (userState == null) {
3603957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            throw new IllegalStateException("User state not found for user ID " + userId);
3613957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
3623957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        return userState;
3633957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    }
3643957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
3659e8ade2eb7ee835963473c9cf6faaf5423b0b048Ji-Hwan Lee    private ServiceState getServiceStateLocked(ComponentName component, int userId) {
3663957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        UserState userState = getUserStateLocked(userId);
3679e8ade2eb7ee835963473c9cf6faaf5423b0b048Ji-Hwan Lee        ServiceState serviceState = userState.serviceStateMap.get(component);
3683957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        if (serviceState == null) {
3699e8ade2eb7ee835963473c9cf6faaf5423b0b048Ji-Hwan Lee            throw new IllegalStateException("Service state not found for " + component + " (userId="
3707de5e234715a3baa8905afa3dd0c5009af64541fSungsoo Lim                    + userId + ")");
3713957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
3723957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        return serviceState;
3733957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    }
3743957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
3752b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim    private SessionState getSessionStateLocked(IBinder sessionToken, int callingUid, int userId) {
3763957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        UserState userState = getUserStateLocked(userId);
3773957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        SessionState sessionState = userState.sessionStateMap.get(sessionToken);
3783957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        if (sessionState == null) {
3793957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            throw new IllegalArgumentException("Session state not found for token " + sessionToken);
3803957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
3813957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        // Only the application that requested this session or the system can access it.
382d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim        if (callingUid != Process.SYSTEM_UID && callingUid != sessionState.mCallingUid) {
3833957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            throw new SecurityException("Illegal access to the session with token " + sessionToken
3843957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    + " from uid " + callingUid);
3853957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
3862b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim        return sessionState;
3872b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim    }
3882b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim
3892b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim    private ITvInputSession getSessionLocked(IBinder sessionToken, int callingUid, int userId) {
3904c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee        return getSessionLocked(getSessionStateLocked(sessionToken, callingUid, userId));
3914c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee    }
3924c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee
3934c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee    private ITvInputSession getSessionLocked(SessionState sessionState) {
394d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim        ITvInputSession session = sessionState.mSession;
3953957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        if (session == null) {
3964c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee            throw new IllegalStateException("Session not yet created for token "
3974c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee                    + sessionState.mSessionToken);
3983957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
3993957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        return session;
4003957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    }
4013957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
4023957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    private int resolveCallingUserId(int callingPid, int callingUid, int requestedUserId,
4033957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            String methodName) {
4043957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        return ActivityManager.handleIncomingUser(callingPid, callingUid, requestedUserId, false,
4053957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                false, methodName, null);
4063957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    }
4073957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
408187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim    private static boolean shouldMaintainConnection(ServiceState serviceState) {
4099cc28e5175e1391646b29469d329c9c1c9311ee1Jae Seo        return !serviceState.mSessionTokens.isEmpty() || serviceState.mIsHardware;
410187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim        // TODO: Find a way to maintain connection only when necessary.
411187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim    }
412187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim
4139e8ade2eb7ee835963473c9cf6faaf5423b0b048Ji-Hwan Lee    private void updateServiceConnectionLocked(ComponentName component, int userId) {
4143957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        UserState userState = getUserStateLocked(userId);
4159e8ade2eb7ee835963473c9cf6faaf5423b0b048Ji-Hwan Lee        ServiceState serviceState = userState.serviceStateMap.get(component);
4163957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        if (serviceState == null) {
4173957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            return;
4183957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
4192b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim        if (serviceState.mReconnecting) {
4202b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim            if (!serviceState.mSessionTokens.isEmpty()) {
4212b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                // wait until all the sessions are removed.
4222b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                return;
4232b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim            }
4242b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim            serviceState.mReconnecting = false;
4252b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim        }
426187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim        boolean maintainConnection = shouldMaintainConnection(serviceState);
427187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim        if (serviceState.mService == null && maintainConnection && userId == mCurrentUserId) {
4283957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            // This means that the service is not yet connected but its state indicates that we
4293957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            // have pending requests. Then, connect the service.
430d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim            if (serviceState.mBound) {
4313957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                // We have already bound to the service so we don't try to bind again until after we
4323957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                // unbind later on.
4333957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                return;
4343957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            }
4353957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            if (DEBUG) {
4369e8ade2eb7ee835963473c9cf6faaf5423b0b048Ji-Hwan Lee                Slog.d(TAG, "bindServiceAsUser(service=" + component + ", userId=" + userId + ")");
4373957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            }
438d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim
4399e8ade2eb7ee835963473c9cf6faaf5423b0b048Ji-Hwan Lee            Intent i = new Intent(TvInputService.SERVICE_INTERFACE).setComponent(component);
440226a51958d645a8e2be3e40a6b6daaca558b4913Jaewan Kim            // Binding service may fail if the service is updating.
441226a51958d645a8e2be3e40a6b6daaca558b4913Jaewan Kim            // In that case, the connection will be revived in buildTvInputListLocked called by
442226a51958d645a8e2be3e40a6b6daaca558b4913Jaewan Kim            // onSomePackagesChanged.
443e17b2dd7bcc137bf4d842a779e8d62c63957a978Ji-Hwan Lee            serviceState.mBound = mContext.bindServiceAsUser(
444e17b2dd7bcc137bf4d842a779e8d62c63957a978Ji-Hwan Lee                    i, serviceState.mConnection, Context.BIND_AUTO_CREATE, new UserHandle(userId));
445187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim        } else if (serviceState.mService != null && !maintainConnection) {
4463957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            // This means that the service is already connected but its state indicates that we have
4473957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            // nothing to do with it. Then, disconnect the service.
4483957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            if (DEBUG) {
4499e8ade2eb7ee835963473c9cf6faaf5423b0b048Ji-Hwan Lee                Slog.d(TAG, "unbindService(service=" + component + ")");
4503957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            }
451d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim            mContext.unbindService(serviceState.mConnection);
4529e8ade2eb7ee835963473c9cf6faaf5423b0b048Ji-Hwan Lee            userState.serviceStateMap.remove(component);
4533957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
4543957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    }
4553957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
456426c9a4008b75b93cbfea15aa4b8c47c5fdb49b9Dongwon Kang    private void abortPendingCreateSessionRequestsLocked(ServiceState serviceState,
457426c9a4008b75b93cbfea15aa4b8c47c5fdb49b9Dongwon Kang            String inputId, int userId) {
458426c9a4008b75b93cbfea15aa4b8c47c5fdb49b9Dongwon Kang        // Let clients know the create session requests are failed.
459426c9a4008b75b93cbfea15aa4b8c47c5fdb49b9Dongwon Kang        UserState userState = getUserStateLocked(userId);
460426c9a4008b75b93cbfea15aa4b8c47c5fdb49b9Dongwon Kang        for (IBinder sessionToken : serviceState.mSessionTokens) {
461426c9a4008b75b93cbfea15aa4b8c47c5fdb49b9Dongwon Kang            SessionState sessionState = userState.sessionStateMap.get(sessionToken);
462426c9a4008b75b93cbfea15aa4b8c47c5fdb49b9Dongwon Kang            if (sessionState.mSession == null && (inputId == null
463426c9a4008b75b93cbfea15aa4b8c47c5fdb49b9Dongwon Kang                    || sessionState.mInfo.getId().equals(inputId))) {
464426c9a4008b75b93cbfea15aa4b8c47c5fdb49b9Dongwon Kang                removeSessionStateLocked(sessionToken, sessionState.mUserId);
465426c9a4008b75b93cbfea15aa4b8c47c5fdb49b9Dongwon Kang                sendSessionTokenToClientLocked(sessionState.mClient,
466426c9a4008b75b93cbfea15aa4b8c47c5fdb49b9Dongwon Kang                        sessionState.mInfo.getId(), null, null, sessionState.mSeq);
467426c9a4008b75b93cbfea15aa4b8c47c5fdb49b9Dongwon Kang            }
468426c9a4008b75b93cbfea15aa4b8c47c5fdb49b9Dongwon Kang        }
469426c9a4008b75b93cbfea15aa4b8c47c5fdb49b9Dongwon Kang        updateServiceConnectionLocked(serviceState.mComponent, userId);
470426c9a4008b75b93cbfea15aa4b8c47c5fdb49b9Dongwon Kang    }
471426c9a4008b75b93cbfea15aa4b8c47c5fdb49b9Dongwon Kang
47272ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim    private ClientState createClientStateLocked(IBinder clientToken, int userId) {
47372ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim        UserState userState = getUserStateLocked(userId);
47472ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim        ClientState clientState = new ClientState(clientToken, userId);
47572ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim        try {
47672ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim            clientToken.linkToDeath(clientState, 0);
47772ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim        } catch (RemoteException e) {
47872ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim            Slog.e(TAG, "Client is already died.");
47972ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim        }
48072ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim        userState.clientStateMap.put(clientToken, clientState);
48172ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim        return clientState;
48272ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim    }
48372ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim
4843957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    private void createSessionInternalLocked(ITvInputService service, final IBinder sessionToken,
4857de5e234715a3baa8905afa3dd0c5009af64541fSungsoo Lim            final int userId) {
48672ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim        final UserState userState = getUserStateLocked(userId);
48772ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim        final SessionState sessionState = userState.sessionStateMap.get(sessionToken);
4883957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        if (DEBUG) {
489187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim            Slog.d(TAG, "createSessionInternalLocked(inputId=" + sessionState.mInfo.getId() + ")");
4903957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
4916a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo
4926a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo        final InputChannel[] channels = InputChannel.openInputChannelPair(sessionToken.toString());
4936a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo
4943957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        // Set up a callback to send the session token.
4953957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        ITvInputSessionCallback callback = new ITvInputSessionCallback.Stub() {
4963957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            @Override
497bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang            public void onSessionCreated(ITvInputSession session, IBinder harewareSessionToken) {
4983957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                if (DEBUG) {
499187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                    Slog.d(TAG, "onSessionCreated(inputId=" + sessionState.mInfo.getId() + ")");
5003957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                }
5013957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                synchronized (mLock) {
502d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim                    sessionState.mSession = session;
503bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                    sessionState.mHardwareSessionToken = harewareSessionToken;
504fd5b72f1ed2ee74a4204eef65f560fc82f0b62feDongwon Kang                    if (session == null) {
505fd5b72f1ed2ee74a4204eef65f560fc82f0b62feDongwon Kang                        removeSessionStateLocked(sessionToken, userId);
506187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                        sendSessionTokenToClientLocked(sessionState.mClient,
507187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                                sessionState.mInfo.getId(), null, null, sessionState.mSeq);
508fd5b72f1ed2ee74a4204eef65f560fc82f0b62feDongwon Kang                    } else {
5092b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                        try {
5102b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                            session.asBinder().linkToDeath(sessionState, 0);
5112b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                        } catch (RemoteException e) {
5122b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                            Slog.e(TAG, "Session is already died.");
5132b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                        }
51472ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim
51572ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim                        IBinder clientToken = sessionState.mClient.asBinder();
51672ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim                        ClientState clientState = userState.clientStateMap.get(clientToken);
51772ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim                        if (clientState == null) {
51872ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim                            clientState = createClientStateLocked(clientToken, userId);
51972ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim                        }
52072ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim                        clientState.mSessionTokens.add(sessionState.mSessionToken);
52172ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim
522187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                        sendSessionTokenToClientLocked(sessionState.mClient,
523187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                                sessionState.mInfo.getId(), sessionToken, channels[0],
524187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                                sessionState.mSeq);
525fd5b72f1ed2ee74a4204eef65f560fc82f0b62feDongwon Kang                    }
5266a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                    channels[0].dispose();
5273957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                }
5283957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            }
529832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho
530832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho            @Override
5311f213914c45c23c653f721690da2ce0718e63139Dongwon Kang            public void onChannelRetuned(Uri channelUri) {
532a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang                synchronized (mLock) {
533a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang                    if (DEBUG) {
5341f213914c45c23c653f721690da2ce0718e63139Dongwon Kang                        Slog.d(TAG, "onChannelRetuned(" + channelUri + ")");
535a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang                    }
536a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang                    if (sessionState.mSession == null || sessionState.mClient == null) {
537a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang                        return;
538a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang                    }
539a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang                    try {
5401f213914c45c23c653f721690da2ce0718e63139Dongwon Kang                        // TODO: Consider adding this channel change in the watch log. When we do
5411f213914c45c23c653f721690da2ce0718e63139Dongwon Kang                        // that, how we can protect the watch log from malicious tv inputs should
5421f213914c45c23c653f721690da2ce0718e63139Dongwon Kang                        // be addressed. e.g. add a field which represents where the channel change
5431f213914c45c23c653f721690da2ce0718e63139Dongwon Kang                        // originated from.
5441f213914c45c23c653f721690da2ce0718e63139Dongwon Kang                        sessionState.mClient.onChannelRetuned(channelUri, sessionState.mSeq);
545a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang                    } catch (RemoteException e) {
5461f213914c45c23c653f721690da2ce0718e63139Dongwon Kang                        Slog.e(TAG, "error in onChannelRetuned");
547a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang                    }
548a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang                }
549a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang            }
550a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang
551a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang            @Override
55210d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo            public void onTracksChanged(List<TvTrackInfo> tracks) {
553a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang                synchronized (mLock) {
554a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang                    if (DEBUG) {
55510d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo                        Slog.d(TAG, "onTracksChanged(" + tracks + ")");
556a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang                    }
557a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang                    if (sessionState.mSession == null || sessionState.mClient == null) {
558a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang                        return;
559a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang                    }
560a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang                    try {
56110d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo                        sessionState.mClient.onTracksChanged(tracks, sessionState.mSeq);
562a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang                    } catch (RemoteException e) {
56310d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo                        Slog.e(TAG, "error in onTracksChanged");
564b93ccca6139a7ee2dba5c110e5f8213a2bd231e5Dongwon Kang                    }
565b93ccca6139a7ee2dba5c110e5f8213a2bd231e5Dongwon Kang                }
566b93ccca6139a7ee2dba5c110e5f8213a2bd231e5Dongwon Kang            }
567b93ccca6139a7ee2dba5c110e5f8213a2bd231e5Dongwon Kang
568b93ccca6139a7ee2dba5c110e5f8213a2bd231e5Dongwon Kang            @Override
56910d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo            public void onTrackSelected(int type, String trackId) {
570d5ce9759524740cfb02638fd1d7b44315957b422Jae Seo                synchronized (mLock) {
571d5ce9759524740cfb02638fd1d7b44315957b422Jae Seo                    if (DEBUG) {
57210d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo                        Slog.d(TAG, "onTrackSelected(type=" + type + ", trackId=" + trackId + ")");
573d5ce9759524740cfb02638fd1d7b44315957b422Jae Seo                    }
574d5ce9759524740cfb02638fd1d7b44315957b422Jae Seo                    if (sessionState.mSession == null || sessionState.mClient == null) {
575d5ce9759524740cfb02638fd1d7b44315957b422Jae Seo                        return;
576d5ce9759524740cfb02638fd1d7b44315957b422Jae Seo                    }
577d5ce9759524740cfb02638fd1d7b44315957b422Jae Seo                    try {
57810d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo                        sessionState.mClient.onTrackSelected(type, trackId, sessionState.mSeq);
579d5ce9759524740cfb02638fd1d7b44315957b422Jae Seo                    } catch (RemoteException e) {
58010d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo                        Slog.e(TAG, "error in onTrackSelected");
581d5ce9759524740cfb02638fd1d7b44315957b422Jae Seo                    }
582d5ce9759524740cfb02638fd1d7b44315957b422Jae Seo                }
583d5ce9759524740cfb02638fd1d7b44315957b422Jae Seo            }
584d5ce9759524740cfb02638fd1d7b44315957b422Jae Seo
585d5ce9759524740cfb02638fd1d7b44315957b422Jae Seo            @Override
5869b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang            public void onVideoAvailable() {
5879b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                synchronized (mLock) {
5889b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                    if (DEBUG) {
5899b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                        Slog.d(TAG, "onVideoAvailable()");
5909b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                    }
5919b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                    if (sessionState.mSession == null || sessionState.mClient == null) {
5929b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                        return;
5939b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                    }
5949b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                    try {
5959b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                        sessionState.mClient.onVideoAvailable(sessionState.mSeq);
5969b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                    } catch (RemoteException e) {
5979b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                        Slog.e(TAG, "error in onVideoAvailable");
5989b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                    }
5999b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                }
6009b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang            }
6019b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang
6029b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang            @Override
6039b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang            public void onVideoUnavailable(int reason) {
6049b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                synchronized (mLock) {
6059b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                    if (DEBUG) {
6069b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                        Slog.d(TAG, "onVideoUnavailable(" + reason + ")");
6079b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                    }
6089b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                    if (sessionState.mSession == null || sessionState.mClient == null) {
6099b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                        return;
6109b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                    }
6119b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                    try {
6129b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                        sessionState.mClient.onVideoUnavailable(reason, sessionState.mSeq);
6139b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                    } catch (RemoteException e) {
6149b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                        Slog.e(TAG, "error in onVideoUnavailable");
6159b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                    }
6169b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                }
6179b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang            }
6189b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang
6199b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang            @Override
620bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo            public void onContentAllowed() {
621bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo                synchronized (mLock) {
622bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo                    if (DEBUG) {
623bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo                        Slog.d(TAG, "onContentAllowed()");
624bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo                    }
625bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo                    if (sessionState.mSession == null || sessionState.mClient == null) {
626bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo                        return;
627bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo                    }
628bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo                    try {
629bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo                        sessionState.mClient.onContentAllowed(sessionState.mSeq);
630bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo                    } catch (RemoteException e) {
631bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo                        Slog.e(TAG, "error in onContentAllowed");
632bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo                    }
633bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo                }
634bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo            }
635bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo
636bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo            @Override
6376057102dbb746593a7d59cf377c969b62e38c664Jae Seo            public void onContentBlocked(String rating) {
6386057102dbb746593a7d59cf377c969b62e38c664Jae Seo                synchronized (mLock) {
6396057102dbb746593a7d59cf377c969b62e38c664Jae Seo                    if (DEBUG) {
6406057102dbb746593a7d59cf377c969b62e38c664Jae Seo                        Slog.d(TAG, "onContentBlocked()");
6416057102dbb746593a7d59cf377c969b62e38c664Jae Seo                    }
6426057102dbb746593a7d59cf377c969b62e38c664Jae Seo                    if (sessionState.mSession == null || sessionState.mClient == null) {
6436057102dbb746593a7d59cf377c969b62e38c664Jae Seo                        return;
6446057102dbb746593a7d59cf377c969b62e38c664Jae Seo                    }
6456057102dbb746593a7d59cf377c969b62e38c664Jae Seo                    try {
6466057102dbb746593a7d59cf377c969b62e38c664Jae Seo                        sessionState.mClient.onContentBlocked(rating, sessionState.mSeq);
6476057102dbb746593a7d59cf377c969b62e38c664Jae Seo                    } catch (RemoteException e) {
6486057102dbb746593a7d59cf377c969b62e38c664Jae Seo                        Slog.e(TAG, "error in onContentBlocked");
6496057102dbb746593a7d59cf377c969b62e38c664Jae Seo                    }
6506057102dbb746593a7d59cf377c969b62e38c664Jae Seo                }
6516057102dbb746593a7d59cf377c969b62e38c664Jae Seo            }
6526057102dbb746593a7d59cf377c969b62e38c664Jae Seo
6536057102dbb746593a7d59cf377c969b62e38c664Jae Seo            @Override
654ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho            public void onLayoutSurface(int left, int top, int right, int bottom) {
655ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho                synchronized (mLock) {
656ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho                    if (DEBUG) {
657ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho                        Slog.d(TAG, "onLayoutSurface (left=" + left + ", top=" + top
658ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho                                + ", right=" + right + ", bottom=" + bottom + ",)");
659ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho                    }
660ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho                    if (sessionState.mSession == null || sessionState.mClient == null) {
661ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho                        return;
662ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho                    }
663ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho                    try {
664ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho                        sessionState.mClient.onLayoutSurface(left, top, right, bottom,
665ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho                                sessionState.mSeq);
666ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho                    } catch (RemoteException e) {
667ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho                        Slog.e(TAG, "error in onLayoutSurface");
668ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho                    }
669ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho                }
670ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho            }
671ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho
672ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho            @Override
673832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho            public void onSessionEvent(String eventType, Bundle eventArgs) {
674832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho                synchronized (mLock) {
675832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho                    if (DEBUG) {
676832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho                        Slog.d(TAG, "onEvent(what=" + eventType + ", data=" + eventArgs + ")");
677832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho                    }
678832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho                    if (sessionState.mSession == null || sessionState.mClient == null) {
679832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho                        return;
680832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho                    }
681832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho                    try {
682832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho                        sessionState.mClient.onSessionEvent(eventType, eventArgs,
683832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho                                sessionState.mSeq);
684832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho                    } catch (RemoteException e) {
685832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho                        Slog.e(TAG, "error in onSessionEvent");
686832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho                    }
687832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho                }
688832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho            }
6893957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        };
6903957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
6913957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        // Create a session. When failed, send a null token immediately.
6923957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        try {
693187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim            service.createSession(channels[1], callback, sessionState.mInfo.getId());
6943957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        } catch (RemoteException e) {
6959a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            Slog.e(TAG, "error in createSession", e);
696fd5b72f1ed2ee74a4204eef65f560fc82f0b62feDongwon Kang            removeSessionStateLocked(sessionToken, userId);
697187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim            sendSessionTokenToClientLocked(sessionState.mClient, sessionState.mInfo.getId(), null,
698187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                    null, sessionState.mSeq);
6993957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
7006a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo        channels[1].dispose();
7013957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    }
7023957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
703d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim    private void sendSessionTokenToClientLocked(ITvInputClient client, String inputId,
7045c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo            IBinder sessionToken, InputChannel channel, int seq) {
7053957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        try {
706d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim            client.onSessionCreated(inputId, sessionToken, channel, seq);
7073957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        } catch (RemoteException exception) {
7089a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            Slog.e(TAG, "error in onSessionCreated", exception);
7093957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
7102b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim    }
7113957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
7122b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim    private void releaseSessionLocked(IBinder sessionToken, int callingUid, int userId) {
7132b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim        SessionState sessionState = getSessionStateLocked(sessionToken, callingUid, userId);
7142b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim        if (sessionState.mSession != null) {
71515c56aac985bc8d75f38fb4ecb92dda12d2ca06cJi-Hwan Lee            UserState userState = getUserStateLocked(userId);
71615c56aac985bc8d75f38fb4ecb92dda12d2ca06cJi-Hwan Lee            if (sessionToken == userState.mainSessionToken) {
71715c56aac985bc8d75f38fb4ecb92dda12d2ca06cJi-Hwan Lee                setMainLocked(sessionToken, false, callingUid, userId);
71815c56aac985bc8d75f38fb4ecb92dda12d2ca06cJi-Hwan Lee            }
7192b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim            try {
7202b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                sessionState.mSession.release();
7212b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim            } catch (RemoteException e) {
7222b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                Slog.w(TAG, "session is already disapeared", e);
7232b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim            }
7242b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim            sessionState.mSession = null;
7253957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
7262b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim        removeSessionStateLocked(sessionToken, userId);
7273957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    }
7283957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
729fd5b72f1ed2ee74a4204eef65f560fc82f0b62feDongwon Kang    private void removeSessionStateLocked(IBinder sessionToken, int userId) {
730fd5b72f1ed2ee74a4204eef65f560fc82f0b62feDongwon Kang        UserState userState = getUserStateLocked(userId);
731abca0ee7949f59e72b8d2764dafa23af18eb51dbJi-Hwan Lee        if (sessionToken == userState.mainSessionToken) {
73215c56aac985bc8d75f38fb4ecb92dda12d2ca06cJi-Hwan Lee            if (DEBUG) {
73315c56aac985bc8d75f38fb4ecb92dda12d2ca06cJi-Hwan Lee                Slog.d(TAG, "mainSessionToken=null");
73415c56aac985bc8d75f38fb4ecb92dda12d2ca06cJi-Hwan Lee            }
735abca0ee7949f59e72b8d2764dafa23af18eb51dbJi-Hwan Lee            userState.mainSessionToken = null;
736abca0ee7949f59e72b8d2764dafa23af18eb51dbJi-Hwan Lee        }
737abca0ee7949f59e72b8d2764dafa23af18eb51dbJi-Hwan Lee
738abca0ee7949f59e72b8d2764dafa23af18eb51dbJi-Hwan Lee        // Remove the session state from the global session state map of the current user.
739fd5b72f1ed2ee74a4204eef65f560fc82f0b62feDongwon Kang        SessionState sessionState = userState.sessionStateMap.remove(sessionToken);
740fd5b72f1ed2ee74a4204eef65f560fc82f0b62feDongwon Kang
7418d4ded0058de5c573ccf79c4596bf5eb1b14fad3Chulwoo Lee        if (sessionState == null) {
7428d4ded0058de5c573ccf79c4596bf5eb1b14fad3Chulwoo Lee            return;
7438d4ded0058de5c573ccf79c4596bf5eb1b14fad3Chulwoo Lee        }
7448d4ded0058de5c573ccf79c4596bf5eb1b14fad3Chulwoo Lee
74572ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim        // Also remove the session token from the session token list of the current client and
74672ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim        // service.
74772ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim        ClientState clientState = userState.clientStateMap.get(sessionState.mClient.asBinder());
74872ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim        if (clientState != null) {
74972ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim            clientState.mSessionTokens.remove(sessionToken);
75072ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim            if (clientState.isEmpty()) {
75172ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim                userState.clientStateMap.remove(sessionState.mClient.asBinder());
75272ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim            }
75372ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim        }
75472ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim
755187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim        TvInputInfo info = sessionState.mInfo;
756187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim        if (info != null) {
757187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim            ServiceState serviceState = userState.serviceStateMap.get(info.getComponent());
758187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim            if (serviceState != null) {
759187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                serviceState.mSessionTokens.remove(sessionToken);
760187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim            }
761fd5b72f1ed2ee74a4204eef65f560fc82f0b62feDongwon Kang        }
762187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim        updateServiceConnectionLocked(sessionState.mInfo.getComponent(), userId);
7637eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo
7647eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo        // Log the end of watch.
7657eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo        SomeArgs args = SomeArgs.obtain();
7667eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo        args.arg1 = sessionToken;
7677eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo        args.arg2 = System.currentTimeMillis();
7687eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo        mWatchLogHandler.obtainMessage(WatchLogHandler.MSG_LOG_WATCH_END, args).sendToTarget();
769fd5b72f1ed2ee74a4204eef65f560fc82f0b62feDongwon Kang    }
770fd5b72f1ed2ee74a4204eef65f560fc82f0b62feDongwon Kang
77115c56aac985bc8d75f38fb4ecb92dda12d2ca06cJi-Hwan Lee    private void setMainLocked(IBinder sessionToken, boolean isMain, int callingUid, int userId) {
77215c56aac985bc8d75f38fb4ecb92dda12d2ca06cJi-Hwan Lee        SessionState sessionState = getSessionStateLocked(sessionToken, callingUid, userId);
77315c56aac985bc8d75f38fb4ecb92dda12d2ca06cJi-Hwan Lee        if (sessionState.mHardwareSessionToken != null) {
77415c56aac985bc8d75f38fb4ecb92dda12d2ca06cJi-Hwan Lee            sessionState = getSessionStateLocked(sessionState.mHardwareSessionToken,
77515c56aac985bc8d75f38fb4ecb92dda12d2ca06cJi-Hwan Lee                    Process.SYSTEM_UID, userId);
77615c56aac985bc8d75f38fb4ecb92dda12d2ca06cJi-Hwan Lee        }
77715c56aac985bc8d75f38fb4ecb92dda12d2ca06cJi-Hwan Lee        ServiceState serviceState = getServiceStateLocked(sessionState.mInfo.getComponent(),
77815c56aac985bc8d75f38fb4ecb92dda12d2ca06cJi-Hwan Lee                userId);
77915c56aac985bc8d75f38fb4ecb92dda12d2ca06cJi-Hwan Lee        if (!serviceState.mIsHardware) {
78015c56aac985bc8d75f38fb4ecb92dda12d2ca06cJi-Hwan Lee            return;
78115c56aac985bc8d75f38fb4ecb92dda12d2ca06cJi-Hwan Lee        }
78215c56aac985bc8d75f38fb4ecb92dda12d2ca06cJi-Hwan Lee        ITvInputSession session = getSessionLocked(sessionState);
78315c56aac985bc8d75f38fb4ecb92dda12d2ca06cJi-Hwan Lee        try {
78415c56aac985bc8d75f38fb4ecb92dda12d2ca06cJi-Hwan Lee            session.setMain(isMain);
78515c56aac985bc8d75f38fb4ecb92dda12d2ca06cJi-Hwan Lee        } catch (RemoteException e) {
78615c56aac985bc8d75f38fb4ecb92dda12d2ca06cJi-Hwan Lee            Slog.e(TAG, "error in setMain", e);
78715c56aac985bc8d75f38fb4ecb92dda12d2ca06cJi-Hwan Lee        }
78815c56aac985bc8d75f38fb4ecb92dda12d2ca06cJi-Hwan Lee    }
78915c56aac985bc8d75f38fb4ecb92dda12d2ca06cJi-Hwan Lee
7908e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim    private void notifyInputAddedLocked(UserState userState, String inputId) {
7918e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim        if (DEBUG) {
7928e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim            Slog.d(TAG, "notifyInputAdded: inputId = " + inputId);
7938e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim        }
7948e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim        for (ITvInputManagerCallback callback : userState.callbackSet) {
7958e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim            try {
7968e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim                callback.onInputAdded(inputId);
7978e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim            } catch (RemoteException e) {
7988e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim                Slog.e(TAG, "Failed to report added input to callback.");
7998e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim            }
8008e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim        }
8018e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim    }
8028e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim
8038e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim    private void notifyInputRemovedLocked(UserState userState, String inputId) {
8048e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim        if (DEBUG) {
8058e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim            Slog.d(TAG, "notifyInputRemovedLocked: inputId = " + inputId);
8068e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim        }
8078e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim        for (ITvInputManagerCallback callback : userState.callbackSet) {
8088e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim            try {
8098e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim                callback.onInputRemoved(inputId);
8108e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim            } catch (RemoteException e) {
8118e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim                Slog.e(TAG, "Failed to report removed input to callback.");
8128e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim            }
8138e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim        }
8148e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim    }
8158e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim
8168e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim    private void notifyInputStateChangedLocked(UserState userState, String inputId,
817969167dc05a6485a32d160895871cff46fd81884Wonsik Kim            int state, ITvInputManagerCallback targetCallback) {
818969167dc05a6485a32d160895871cff46fd81884Wonsik Kim        if (DEBUG) {
8198e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim            Slog.d(TAG, "notifyInputStateChangedLocked: inputId = " + inputId
820969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                    + "; state = " + state);
821969167dc05a6485a32d160895871cff46fd81884Wonsik Kim        }
822969167dc05a6485a32d160895871cff46fd81884Wonsik Kim        if (targetCallback == null) {
823969167dc05a6485a32d160895871cff46fd81884Wonsik Kim            for (ITvInputManagerCallback callback : userState.callbackSet) {
824969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                try {
825969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                    callback.onInputStateChanged(inputId, state);
826969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                } catch (RemoteException e) {
827969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                    Slog.e(TAG, "Failed to report state change to callback.");
828969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                }
829969167dc05a6485a32d160895871cff46fd81884Wonsik Kim            }
830969167dc05a6485a32d160895871cff46fd81884Wonsik Kim        } else {
8312b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim            try {
832969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                targetCallback.onInputStateChanged(inputId, state);
8332b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim            } catch (RemoteException e) {
834969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                Slog.e(TAG, "Failed to report state change to callback.");
8352b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim            }
8362b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim        }
8372b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim    }
8382b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim
839969167dc05a6485a32d160895871cff46fd81884Wonsik Kim    private void setStateLocked(String inputId, int state, int userId) {
840969167dc05a6485a32d160895871cff46fd81884Wonsik Kim        UserState userState = getUserStateLocked(userId);
841969167dc05a6485a32d160895871cff46fd81884Wonsik Kim        TvInputState inputState = userState.inputMap.get(inputId);
842c88f1916b8ab7f5f75a00375c6fb4873ea5044afJi-Hwan Lee        ServiceState serviceState = userState.serviceStateMap.get(inputState.mInfo.getComponent());
843969167dc05a6485a32d160895871cff46fd81884Wonsik Kim        int oldState = inputState.mState;
844969167dc05a6485a32d160895871cff46fd81884Wonsik Kim        inputState.mState = state;
845187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim        if (serviceState != null && serviceState.mService == null
846187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                && shouldMaintainConnection(serviceState)) {
847969167dc05a6485a32d160895871cff46fd81884Wonsik Kim            // We don't notify state change while reconnecting. It should remain disconnected.
848969167dc05a6485a32d160895871cff46fd81884Wonsik Kim            return;
849969167dc05a6485a32d160895871cff46fd81884Wonsik Kim        }
850969167dc05a6485a32d160895871cff46fd81884Wonsik Kim        if (oldState != state) {
8518e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim            notifyInputStateChangedLocked(userState, inputId, state, null);
852969167dc05a6485a32d160895871cff46fd81884Wonsik Kim        }
853969167dc05a6485a32d160895871cff46fd81884Wonsik Kim    }
854969167dc05a6485a32d160895871cff46fd81884Wonsik Kim
8553957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    private final class BinderService extends ITvInputManager.Stub {
8563957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        @Override
8573957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        public List<TvInputInfo> getTvInputList(int userId) {
8583957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(),
8593957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    Binder.getCallingUid(), userId, "getTvInputList");
8603957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            final long identity = Binder.clearCallingIdentity();
8613957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            try {
8623957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                synchronized (mLock) {
8633957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    UserState userState = getUserStateLocked(resolvedUserId);
864969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                    List<TvInputInfo> inputList = new ArrayList<TvInputInfo>();
865969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                    for (TvInputState state : userState.inputMap.values()) {
866969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                        inputList.add(state.mInfo);
8673957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    }
868969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                    return inputList;
8693957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                }
8703957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            } finally {
8713957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                Binder.restoreCallingIdentity(identity);
8723957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            }
873b375805f3b1672e68d1511565af4700e5fa8491dJae Seo        }
874b375805f3b1672e68d1511565af4700e5fa8491dJae Seo
875b375805f3b1672e68d1511565af4700e5fa8491dJae Seo        @Override
876b375805f3b1672e68d1511565af4700e5fa8491dJae Seo        public TvInputInfo getTvInputInfo(String inputId, int userId) {
877b375805f3b1672e68d1511565af4700e5fa8491dJae Seo            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(),
878b375805f3b1672e68d1511565af4700e5fa8491dJae Seo                    Binder.getCallingUid(), userId, "getTvInputInfo");
879b375805f3b1672e68d1511565af4700e5fa8491dJae Seo            final long identity = Binder.clearCallingIdentity();
880b375805f3b1672e68d1511565af4700e5fa8491dJae Seo            try {
881b375805f3b1672e68d1511565af4700e5fa8491dJae Seo                synchronized (mLock) {
882b375805f3b1672e68d1511565af4700e5fa8491dJae Seo                    UserState userState = getUserStateLocked(resolvedUserId);
883b375805f3b1672e68d1511565af4700e5fa8491dJae Seo                    TvInputState state = userState.inputMap.get(inputId);
884b375805f3b1672e68d1511565af4700e5fa8491dJae Seo                    return state == null ? null : state.mInfo;
885b375805f3b1672e68d1511565af4700e5fa8491dJae Seo                }
886b375805f3b1672e68d1511565af4700e5fa8491dJae Seo            } finally {
887b375805f3b1672e68d1511565af4700e5fa8491dJae Seo                Binder.restoreCallingIdentity(identity);
888b375805f3b1672e68d1511565af4700e5fa8491dJae Seo            }
8893957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
8903957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
8913957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        @Override
8925c5b83fcd58d21c9ab7ac986bf84f604ec5bb4b5Sungsoo Lim        public List<Uri> getTvContentRatingSystemXmls(int userId) {
8935c5b83fcd58d21c9ab7ac986bf84f604ec5bb4b5Sungsoo Lim            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(),
8945c5b83fcd58d21c9ab7ac986bf84f604ec5bb4b5Sungsoo Lim                    Binder.getCallingUid(), userId, "getTvContentRatingSystemXmls");
8955c5b83fcd58d21c9ab7ac986bf84f604ec5bb4b5Sungsoo Lim            final long identity = Binder.clearCallingIdentity();
8965c5b83fcd58d21c9ab7ac986bf84f604ec5bb4b5Sungsoo Lim            try {
8975c5b83fcd58d21c9ab7ac986bf84f604ec5bb4b5Sungsoo Lim                synchronized (mLock) {
8985c5b83fcd58d21c9ab7ac986bf84f604ec5bb4b5Sungsoo Lim                    UserState userState = getUserStateLocked(resolvedUserId);
8995c5b83fcd58d21c9ab7ac986bf84f604ec5bb4b5Sungsoo Lim                    List<Uri> ratingSystemXmlUriList = new ArrayList<Uri>();
9005c5b83fcd58d21c9ab7ac986bf84f604ec5bb4b5Sungsoo Lim                    ratingSystemXmlUriList.addAll(userState.ratingSystemXmlUriSet);
9015c5b83fcd58d21c9ab7ac986bf84f604ec5bb4b5Sungsoo Lim                    return ratingSystemXmlUriList;
9025c5b83fcd58d21c9ab7ac986bf84f604ec5bb4b5Sungsoo Lim                }
9035c5b83fcd58d21c9ab7ac986bf84f604ec5bb4b5Sungsoo Lim            } finally {
9045c5b83fcd58d21c9ab7ac986bf84f604ec5bb4b5Sungsoo Lim                Binder.restoreCallingIdentity(identity);
9055c5b83fcd58d21c9ab7ac986bf84f604ec5bb4b5Sungsoo Lim            }
9065c5b83fcd58d21c9ab7ac986bf84f604ec5bb4b5Sungsoo Lim        }
9075c5b83fcd58d21c9ab7ac986bf84f604ec5bb4b5Sungsoo Lim
9085c5b83fcd58d21c9ab7ac986bf84f604ec5bb4b5Sungsoo Lim        @Override
909969167dc05a6485a32d160895871cff46fd81884Wonsik Kim        public void registerCallback(final ITvInputManagerCallback callback, int userId) {
9103957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(),
9113957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    Binder.getCallingUid(), userId, "registerCallback");
9123957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            final long identity = Binder.clearCallingIdentity();
9133957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            try {
9143957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                synchronized (mLock) {
9153957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    UserState userState = getUserStateLocked(resolvedUserId);
916969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                    userState.callbackSet.add(callback);
917969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                    for (TvInputState state : userState.inputMap.values()) {
9188e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim                        notifyInputStateChangedLocked(userState, state.mInfo.getId(),
919969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                                state.mState, callback);
9203957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    }
9213957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                }
9223957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            } finally {
9233957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                Binder.restoreCallingIdentity(identity);
9243957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            }
9253957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
9263957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
9273957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        @Override
928969167dc05a6485a32d160895871cff46fd81884Wonsik Kim        public void unregisterCallback(ITvInputManagerCallback callback, int userId) {
9293957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(),
9303957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    Binder.getCallingUid(), userId, "unregisterCallback");
9313957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            final long identity = Binder.clearCallingIdentity();
9323957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            try {
9333957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                synchronized (mLock) {
934969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                    UserState userState = getUserStateLocked(resolvedUserId);
935969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                    userState.callbackSet.remove(callback);
9363957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                }
9373957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            } finally {
9383957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                Binder.restoreCallingIdentity(identity);
9393957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            }
9403957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
9413957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
9423957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        @Override
943783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo        public boolean isParentalControlsEnabled(int userId) {
944783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(),
945783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                    Binder.getCallingUid(), userId, "isParentalControlsEnabled");
946783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo            final long identity = Binder.clearCallingIdentity();
947783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo            try {
948783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                synchronized (mLock) {
949783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                    UserState userState = getUserStateLocked(resolvedUserId);
950783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                    return userState.persistentDataStore.isParentalControlsEnabled();
951783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                }
952783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo            } finally {
953783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                Binder.restoreCallingIdentity(identity);
954783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo            }
955783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo        }
956783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo
957783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo        @Override
958783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo        public void setParentalControlsEnabled(boolean enabled, int userId) {
959783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo            ensureParentalControlsPermission();
960783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(),
961783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                    Binder.getCallingUid(), userId, "setParentalControlsEnabled");
962783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo            final long identity = Binder.clearCallingIdentity();
963783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo            try {
964783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                synchronized (mLock) {
965783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                    UserState userState = getUserStateLocked(resolvedUserId);
966783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                    userState.persistentDataStore.setParentalControlsEnabled(enabled);
967783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                }
968783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo            } finally {
969783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                Binder.restoreCallingIdentity(identity);
970783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo            }
971783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo        }
972783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo
973783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo        @Override
974783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo        public boolean isRatingBlocked(String rating, int userId) {
975783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(),
976783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                    Binder.getCallingUid(), userId, "isRatingBlocked");
977783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo            final long identity = Binder.clearCallingIdentity();
978783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo            try {
979783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                synchronized (mLock) {
980783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                    UserState userState = getUserStateLocked(resolvedUserId);
981783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                    return userState.persistentDataStore.isRatingBlocked(
982783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                            TvContentRating.unflattenFromString(rating));
983783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                }
984783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo            } finally {
985783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                Binder.restoreCallingIdentity(identity);
986783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo            }
987783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo        }
988783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo
989783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo        @Override
990783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo        public List<String> getBlockedRatings(int userId) {
991783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(),
992783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                    Binder.getCallingUid(), userId, "getBlockedRatings");
993783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo            final long identity = Binder.clearCallingIdentity();
994783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo            try {
995783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                synchronized (mLock) {
996783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                    UserState userState = getUserStateLocked(resolvedUserId);
997783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                    List<String> ratings = new ArrayList<String>();
998783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                    for (TvContentRating rating
999783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                            : userState.persistentDataStore.getBlockedRatings()) {
1000783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                        ratings.add(rating.flattenToString());
1001783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                    }
1002783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                    return ratings;
1003783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                }
1004783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo            } finally {
1005783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                Binder.restoreCallingIdentity(identity);
1006783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo            }
1007783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo        }
1008783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo
1009783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo        @Override
1010783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo        public void addBlockedRating(String rating, int userId) {
1011783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo            ensureParentalControlsPermission();
1012783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(),
1013783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                    Binder.getCallingUid(), userId, "addBlockedRating");
1014783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo            final long identity = Binder.clearCallingIdentity();
1015783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo            try {
1016783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                synchronized (mLock) {
1017783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                    UserState userState = getUserStateLocked(resolvedUserId);
1018783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                    userState.persistentDataStore.addBlockedRating(
1019783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                            TvContentRating.unflattenFromString(rating));
1020783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                }
1021783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo            } finally {
1022783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                Binder.restoreCallingIdentity(identity);
1023783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo            }
1024783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo        }
1025783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo
1026783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo        @Override
1027783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo        public void removeBlockedRating(String rating, int userId) {
1028783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo            ensureParentalControlsPermission();
1029783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(),
1030783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                    Binder.getCallingUid(), userId, "removeBlockedRating");
1031783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo            final long identity = Binder.clearCallingIdentity();
1032783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo            try {
1033783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                synchronized (mLock) {
1034783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                    UserState userState = getUserStateLocked(resolvedUserId);
1035783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                    userState.persistentDataStore.removeBlockedRating(
1036783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                            TvContentRating.unflattenFromString(rating));
1037783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                }
1038783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo            } finally {
1039783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                Binder.restoreCallingIdentity(identity);
1040783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo            }
1041783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo        }
1042783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo
1043783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo        private void ensureParentalControlsPermission() {
1044550c4b0d4dc6f3e2ef388b4250c758829c8255bcJae Seo            // STOPSHIP: Uncomment when b/16984416 is resolved.
1045550c4b0d4dc6f3e2ef388b4250c758829c8255bcJae Seo            //if (mContext.checkCallingPermission(
1046550c4b0d4dc6f3e2ef388b4250c758829c8255bcJae Seo            //        android.Manifest.permission.MODIFY_PARENTAL_CONTROLS)
1047550c4b0d4dc6f3e2ef388b4250c758829c8255bcJae Seo            //        != PackageManager.PERMISSION_GRANTED) {
1048550c4b0d4dc6f3e2ef388b4250c758829c8255bcJae Seo            //    throw new SecurityException(
1049550c4b0d4dc6f3e2ef388b4250c758829c8255bcJae Seo            //            "The caller does not have parental controls permission");
1050550c4b0d4dc6f3e2ef388b4250c758829c8255bcJae Seo            //}
1051783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo        }
1052783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo
1053783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo        @Override
1054d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim        public void createSession(final ITvInputClient client, final String inputId,
10553957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                int seq, int userId) {
10563957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            final int callingUid = Binder.getCallingUid();
10573957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
10583957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    userId, "createSession");
10593957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            final long identity = Binder.clearCallingIdentity();
10603957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            try {
10613957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                synchronized (mLock) {
10623957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    UserState userState = getUserStateLocked(resolvedUserId);
1063426c9a4008b75b93cbfea15aa4b8c47c5fdb49b9Dongwon Kang                    TvInputState inputState = userState.inputMap.get(inputId);
1064426c9a4008b75b93cbfea15aa4b8c47c5fdb49b9Dongwon Kang                    if (inputState == null) {
1065426c9a4008b75b93cbfea15aa4b8c47c5fdb49b9Dongwon Kang                        Slog.w(TAG, "Failed to find input state for inputId=" + inputId);
1066426c9a4008b75b93cbfea15aa4b8c47c5fdb49b9Dongwon Kang                        sendSessionTokenToClientLocked(client, inputId, null, null, seq);
1067426c9a4008b75b93cbfea15aa4b8c47c5fdb49b9Dongwon Kang                        return;
1068426c9a4008b75b93cbfea15aa4b8c47c5fdb49b9Dongwon Kang                    }
1069426c9a4008b75b93cbfea15aa4b8c47c5fdb49b9Dongwon Kang                    TvInputInfo info = inputState.mInfo;
1070187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                    ServiceState serviceState = userState.serviceStateMap.get(info.getComponent());
10713957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    if (serviceState == null) {
1072187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                        serviceState = new ServiceState(info.getComponent(), resolvedUserId);
1073187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                        userState.serviceStateMap.put(info.getComponent(), serviceState);
10743957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    }
10752b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                    // Send a null token immediately while reconnecting.
10762b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                    if (serviceState.mReconnecting == true) {
10775c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo                        sendSessionTokenToClientLocked(client, inputId, null, null, seq);
10782b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                        return;
10792b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                    }
10802b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim
10812b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                    // Create a new session token and a session state.
10822b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                    IBinder sessionToken = new Binder();
1083187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                    SessionState sessionState = new SessionState(sessionToken, info, client,
108472ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim                            seq, callingUid, resolvedUserId);
10852b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim
10862b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                    // Add them to the global session state map of the current user.
10872b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                    userState.sessionStateMap.put(sessionToken, sessionState);
10882b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim
10892b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                    // Also, add them to the session state map of the current service.
1090d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim                    serviceState.mSessionTokens.add(sessionToken);
10913957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
1092d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim                    if (serviceState.mService != null) {
1093d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim                        createSessionInternalLocked(serviceState.mService, sessionToken,
10947de5e234715a3baa8905afa3dd0c5009af64541fSungsoo Lim                                resolvedUserId);
10953957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    } else {
1096187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                        updateServiceConnectionLocked(info.getComponent(), resolvedUserId);
10973957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    }
10983957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                }
10993957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            } finally {
11003957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                Binder.restoreCallingIdentity(identity);
11013957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            }
11023957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
11033957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
11043957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        @Override
11053957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        public void releaseSession(IBinder sessionToken, int userId) {
110615c56aac985bc8d75f38fb4ecb92dda12d2ca06cJi-Hwan Lee            if (DEBUG) {
110715c56aac985bc8d75f38fb4ecb92dda12d2ca06cJi-Hwan Lee                Slog.d(TAG, "releaseSession(): " + sessionToken);
110815c56aac985bc8d75f38fb4ecb92dda12d2ca06cJi-Hwan Lee            }
11093957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            final int callingUid = Binder.getCallingUid();
11103957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
11113957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    userId, "releaseSession");
11123957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            final long identity = Binder.clearCallingIdentity();
11133957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            try {
11143957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                synchronized (mLock) {
11152b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                    releaseSessionLocked(sessionToken, callingUid, resolvedUserId);
11163957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                }
11173957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            } finally {
11183957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                Binder.restoreCallingIdentity(identity);
11193957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            }
11203957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
11213957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
11223957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        @Override
11234c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee        public void setMainSession(IBinder sessionToken, int userId) {
112415c56aac985bc8d75f38fb4ecb92dda12d2ca06cJi-Hwan Lee            if (DEBUG) {
112515c56aac985bc8d75f38fb4ecb92dda12d2ca06cJi-Hwan Lee                Slog.d(TAG, "setMainSession(): " + sessionToken);
112615c56aac985bc8d75f38fb4ecb92dda12d2ca06cJi-Hwan Lee            }
11274c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee            final int callingUid = Binder.getCallingUid();
11284c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
11294c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee                    userId, "setMainSession");
11304c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee            final long identity = Binder.clearCallingIdentity();
11314c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee            try {
11324c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee                synchronized (mLock) {
1133982abe693f66037ca265b88057eceb5a3e815182Ji-Hwan Lee                    UserState userState = getUserStateLocked(resolvedUserId);
1134956afc2ba79f50bb8025c6d334653e3c3419b480Ji-Hwan Lee                    if (userState.mainSessionToken == sessionToken) {
11354c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee                        return;
11364c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee                    }
113715c56aac985bc8d75f38fb4ecb92dda12d2ca06cJi-Hwan Lee                    if (DEBUG) {
113815c56aac985bc8d75f38fb4ecb92dda12d2ca06cJi-Hwan Lee                        Slog.d(TAG, "mainSessionToken=" + sessionToken);
1139abca0ee7949f59e72b8d2764dafa23af18eb51dbJi-Hwan Lee                    }
114015c56aac985bc8d75f38fb4ecb92dda12d2ca06cJi-Hwan Lee                    IBinder oldMainSessionToken = userState.mainSessionToken;
11414c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee                    userState.mainSessionToken = sessionToken;
11424c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee
1143956afc2ba79f50bb8025c6d334653e3c3419b480Ji-Hwan Lee                    // Inform the new main session first.
114415c56aac985bc8d75f38fb4ecb92dda12d2ca06cJi-Hwan Lee                    // See {@link TvInputService.Session#onSetMain}.
114515c56aac985bc8d75f38fb4ecb92dda12d2ca06cJi-Hwan Lee                    if (sessionToken != null) {
114615c56aac985bc8d75f38fb4ecb92dda12d2ca06cJi-Hwan Lee                        setMainLocked(sessionToken, true, callingUid, userId);
11474c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee                    }
114815c56aac985bc8d75f38fb4ecb92dda12d2ca06cJi-Hwan Lee                    if (oldMainSessionToken != null) {
114915c56aac985bc8d75f38fb4ecb92dda12d2ca06cJi-Hwan Lee                        setMainLocked(oldMainSessionToken, false, Process.SYSTEM_UID, userId);
11504c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee                    }
11514c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee                }
11524c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee            } finally {
11534c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee                Binder.restoreCallingIdentity(identity);
11544c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee            }
11554c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee        }
11564c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee
11574c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee        @Override
11583957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        public void setSurface(IBinder sessionToken, Surface surface, int userId) {
11593957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            final int callingUid = Binder.getCallingUid();
11603957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
11613957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    userId, "setSurface");
11623957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            final long identity = Binder.clearCallingIdentity();
11633957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            try {
11643957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                synchronized (mLock) {
11653957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    try {
1166bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                        SessionState sessionState = getSessionStateLocked(sessionToken, callingUid,
1167bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                                resolvedUserId);
1168bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                        if (sessionState.mHardwareSessionToken == null) {
1169bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                            getSessionLocked(sessionState).setSurface(surface);
1170bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                        } else {
1171bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                            getSessionLocked(sessionState.mHardwareSessionToken,
1172bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                                    Process.SYSTEM_UID, resolvedUserId).setSurface(surface);
1173bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                        }
11743957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    } catch (RemoteException e) {
11759a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                        Slog.e(TAG, "error in setSurface", e);
11763957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    }
11773957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                }
11783957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            } finally {
1179f836206818ce338db83a3c23c486fb8cab29cb6dYoungsang Cho                if (surface != null) {
1180f836206818ce338db83a3c23c486fb8cab29cb6dYoungsang Cho                    // surface is not used in TvInputManagerService.
1181f836206818ce338db83a3c23c486fb8cab29cb6dYoungsang Cho                    surface.release();
1182f836206818ce338db83a3c23c486fb8cab29cb6dYoungsang Cho                }
11833957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                Binder.restoreCallingIdentity(identity);
11843957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            }
11853957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
11863957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
11873957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        @Override
1188e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho        public void dispatchSurfaceChanged(IBinder sessionToken, int format, int width,
1189e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho                int height, int userId) {
1190e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho            final int callingUid = Binder.getCallingUid();
1191e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
1192e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho                    userId, "dispatchSurfaceChanged");
1193e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho            final long identity = Binder.clearCallingIdentity();
1194e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho            try {
1195e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho                synchronized (mLock) {
1196e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho                    try {
1197bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                        SessionState sessionState = getSessionStateLocked(sessionToken, callingUid,
1198bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                                resolvedUserId);
1199bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                        getSessionLocked(sessionState).dispatchSurfaceChanged(format, width, height);
1200bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                        if (sessionState.mHardwareSessionToken != null) {
1201bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                            getSessionLocked(sessionState.mHardwareSessionToken, Process.SYSTEM_UID,
1202bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                                    resolvedUserId).dispatchSurfaceChanged(format, width, height);
1203bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                        }
1204e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho                    } catch (RemoteException e) {
1205e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho                        Slog.e(TAG, "error in dispatchSurfaceChanged", e);
1206e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho                    }
1207e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho                }
1208e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho            } finally {
1209e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho                Binder.restoreCallingIdentity(identity);
1210e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho            }
1211e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho        }
1212e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho
1213e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho        @Override
12143957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        public void setVolume(IBinder sessionToken, float volume, int userId) {
1215bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang            final float REMOTE_VOLUME_ON = 1.0f;
1216bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang            final float REMOTE_VOLUME_OFF = 0f;
12173957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            final int callingUid = Binder.getCallingUid();
12183957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
12193957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    userId, "setVolume");
12203957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            final long identity = Binder.clearCallingIdentity();
12213957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            try {
12223957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                synchronized (mLock) {
12233957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    try {
1224bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                        SessionState sessionState = getSessionStateLocked(sessionToken, callingUid,
1225bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                                resolvedUserId);
1226bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                        getSessionLocked(sessionState).setVolume(volume);
1227bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                        if (sessionState.mHardwareSessionToken != null) {
1228bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                            // Here, we let the hardware session know only whether volume is on or
1229bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                            // off to prevent that the volume is controlled in the both side.
1230bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                            getSessionLocked(sessionState.mHardwareSessionToken,
1231bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                                    Process.SYSTEM_UID, resolvedUserId).setVolume((volume > 0.0f)
1232bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                                            ? REMOTE_VOLUME_ON : REMOTE_VOLUME_OFF);
1233bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                        }
12343957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    } catch (RemoteException e) {
12359a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                        Slog.e(TAG, "error in setVolume", e);
12363957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    }
12373957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                }
12383957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            } finally {
12393957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                Binder.restoreCallingIdentity(identity);
12403957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            }
12413957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
12423957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
12433957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        @Override
12441a6b25eabcc1fb66e6e8d76f91fd413e18b793a9Sungsoo Lim        public void tune(IBinder sessionToken, final Uri channelUri, Bundle params, int userId) {
12453957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            final int callingUid = Binder.getCallingUid();
12463957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
12473957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    userId, "tune");
12483957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            final long identity = Binder.clearCallingIdentity();
12493957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            try {
12503957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                synchronized (mLock) {
12513957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    try {
12521a6b25eabcc1fb66e6e8d76f91fd413e18b793a9Sungsoo Lim                        getSessionLocked(sessionToken, callingUid, resolvedUserId).tune(
12531a6b25eabcc1fb66e6e8d76f91fd413e18b793a9Sungsoo Lim                                channelUri, params);
1254c22d0c0941ab65ca69977d002c4431394a735c7dJae Seo                        if (TvContract.isChannelUriForPassthroughInput(channelUri)) {
1255008f6d4e326f6372e165bdf342178ecd1e834e2fYoungsang Cho                            // Do not log the watch history for passthrough inputs.
1256008f6d4e326f6372e165bdf342178ecd1e834e2fYoungsang Cho                            return;
1257008f6d4e326f6372e165bdf342178ecd1e834e2fYoungsang Cho                        }
125831dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo
125931dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                        UserState userState = getUserStateLocked(resolvedUserId);
126031dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                        SessionState sessionState = userState.sessionStateMap.get(sessionToken);
126131dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo
12627eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo                        // Log the start of watch.
126331dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                        SomeArgs args = SomeArgs.obtain();
12647eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo                        args.arg1 = sessionState.mInfo.getComponent().getPackageName();
12657eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo                        args.arg2 = System.currentTimeMillis();
12667eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo                        args.arg3 = ContentUris.parseId(channelUri);
12677eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo                        args.arg4 = params;
12687eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo                        args.arg5 = sessionToken;
12697eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo                        mWatchLogHandler.obtainMessage(WatchLogHandler.MSG_LOG_WATCH_START, args)
12707eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo                                .sendToTarget();
12713957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    } catch (RemoteException e) {
12729a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                        Slog.e(TAG, "error in tune", e);
12733957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                        return;
12743957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    }
12753957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                }
12763957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            } finally {
12773957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                Binder.restoreCallingIdentity(identity);
12783957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            }
12793957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
12809a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho
12819a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho        @Override
12829bf671f8ee72b156f16fcf05a3d1c6e093ecba67Sungsoo Lim        public void requestUnblockContent(
12839bf671f8ee72b156f16fcf05a3d1c6e093ecba67Sungsoo Lim                IBinder sessionToken, String unblockedRating, int userId) {
1284903d6b72cd572665309633e925485464d08bb25aJaewan Kim            final int callingUid = Binder.getCallingUid();
1285903d6b72cd572665309633e925485464d08bb25aJaewan Kim            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
1286903d6b72cd572665309633e925485464d08bb25aJaewan Kim                    userId, "unblockContent");
1287903d6b72cd572665309633e925485464d08bb25aJaewan Kim            final long identity = Binder.clearCallingIdentity();
1288903d6b72cd572665309633e925485464d08bb25aJaewan Kim            try {
1289903d6b72cd572665309633e925485464d08bb25aJaewan Kim                synchronized (mLock) {
1290903d6b72cd572665309633e925485464d08bb25aJaewan Kim                    try {
1291903d6b72cd572665309633e925485464d08bb25aJaewan Kim                        getSessionLocked(sessionToken, callingUid, resolvedUserId)
12929bf671f8ee72b156f16fcf05a3d1c6e093ecba67Sungsoo Lim                                .requestUnblockContent(unblockedRating);
1293903d6b72cd572665309633e925485464d08bb25aJaewan Kim                    } catch (RemoteException e) {
1294903d6b72cd572665309633e925485464d08bb25aJaewan Kim                        Slog.e(TAG, "error in unblockContent", e);
1295903d6b72cd572665309633e925485464d08bb25aJaewan Kim                    }
1296903d6b72cd572665309633e925485464d08bb25aJaewan Kim                }
1297903d6b72cd572665309633e925485464d08bb25aJaewan Kim            } finally {
1298903d6b72cd572665309633e925485464d08bb25aJaewan Kim                Binder.restoreCallingIdentity(identity);
1299903d6b72cd572665309633e925485464d08bb25aJaewan Kim            }
1300903d6b72cd572665309633e925485464d08bb25aJaewan Kim        }
1301903d6b72cd572665309633e925485464d08bb25aJaewan Kim
1302903d6b72cd572665309633e925485464d08bb25aJaewan Kim        @Override
13032c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo        public void setCaptionEnabled(IBinder sessionToken, boolean enabled, int userId) {
13042c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo            final int callingUid = Binder.getCallingUid();
13052c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
13062c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo                    userId, "setCaptionEnabled");
13072c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo            final long identity = Binder.clearCallingIdentity();
13082c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo            try {
13092c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo                synchronized (mLock) {
13102c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo                    try {
13112c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo                        getSessionLocked(sessionToken, callingUid, resolvedUserId)
13122c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo                                .setCaptionEnabled(enabled);
13132c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo                    } catch (RemoteException e) {
13142c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo                        Slog.e(TAG, "error in setCaptionEnabled", e);
13152c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo                    }
13162c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo                }
13172c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo            } finally {
13182c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo                Binder.restoreCallingIdentity(identity);
13192c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo            }
13202c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo        }
13212c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo
13222c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo        @Override
132310d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo        public void selectTrack(IBinder sessionToken, int type, String trackId, int userId) {
13241f213914c45c23c653f721690da2ce0718e63139Dongwon Kang            final int callingUid = Binder.getCallingUid();
13251f213914c45c23c653f721690da2ce0718e63139Dongwon Kang            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
13261f213914c45c23c653f721690da2ce0718e63139Dongwon Kang                    userId, "selectTrack");
13271f213914c45c23c653f721690da2ce0718e63139Dongwon Kang            final long identity = Binder.clearCallingIdentity();
13281f213914c45c23c653f721690da2ce0718e63139Dongwon Kang            try {
13291f213914c45c23c653f721690da2ce0718e63139Dongwon Kang                synchronized (mLock) {
13301f213914c45c23c653f721690da2ce0718e63139Dongwon Kang                    try {
13311f213914c45c23c653f721690da2ce0718e63139Dongwon Kang                        getSessionLocked(sessionToken, callingUid, resolvedUserId).selectTrack(
133210d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo                                type, trackId);
13331f213914c45c23c653f721690da2ce0718e63139Dongwon Kang                    } catch (RemoteException e) {
13341f213914c45c23c653f721690da2ce0718e63139Dongwon Kang                        Slog.e(TAG, "error in selectTrack", e);
13351f213914c45c23c653f721690da2ce0718e63139Dongwon Kang                    }
13361f213914c45c23c653f721690da2ce0718e63139Dongwon Kang                }
13371f213914c45c23c653f721690da2ce0718e63139Dongwon Kang            } finally {
13381f213914c45c23c653f721690da2ce0718e63139Dongwon Kang                Binder.restoreCallingIdentity(identity);
13391f213914c45c23c653f721690da2ce0718e63139Dongwon Kang            }
13401f213914c45c23c653f721690da2ce0718e63139Dongwon Kang        }
13411f213914c45c23c653f721690da2ce0718e63139Dongwon Kang
13421f213914c45c23c653f721690da2ce0718e63139Dongwon Kang        @Override
1343a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo        public void sendAppPrivateCommand(IBinder sessionToken, String command, Bundle data,
1344a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo                int userId) {
1345a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo            final int callingUid = Binder.getCallingUid();
1346a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
1347a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo                    userId, "sendAppPrivateCommand");
1348a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo            final long identity = Binder.clearCallingIdentity();
1349a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo            try {
1350a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo                synchronized (mLock) {
1351a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo                    try {
1352a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo                        getSessionLocked(sessionToken, callingUid, resolvedUserId)
1353a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo                                .appPrivateCommand(command, data);
1354a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo                    } catch (RemoteException e) {
1355a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo                        Slog.e(TAG, "error in sendAppPrivateCommand", e);
1356a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo                    }
1357a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo                }
1358a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo            } finally {
1359a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo                Binder.restoreCallingIdentity(identity);
1360a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo            }
1361a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo        }
1362a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo
1363a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo        @Override
13649a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho        public void createOverlayView(IBinder sessionToken, IBinder windowToken, Rect frame,
13659a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                int userId) {
13669a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            final int callingUid = Binder.getCallingUid();
13679a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
13689a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                    userId, "createOverlayView");
13699a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            final long identity = Binder.clearCallingIdentity();
13709a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            try {
13719a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                synchronized (mLock) {
13729a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                    try {
13739a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                        getSessionLocked(sessionToken, callingUid, resolvedUserId)
13749a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                                .createOverlayView(windowToken, frame);
13759a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                    } catch (RemoteException e) {
13769a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                        Slog.e(TAG, "error in createOverlayView", e);
13779a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                    }
13789a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                }
13799a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            } finally {
13809a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                Binder.restoreCallingIdentity(identity);
13819a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            }
13829a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho        }
13839a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho
13849a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho        @Override
13859a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho        public void relayoutOverlayView(IBinder sessionToken, Rect frame, int userId) {
13869a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            final int callingUid = Binder.getCallingUid();
13879a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
13889a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                    userId, "relayoutOverlayView");
13899a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            final long identity = Binder.clearCallingIdentity();
13909a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            try {
13919a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                synchronized (mLock) {
13929a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                    try {
13939a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                        getSessionLocked(sessionToken, callingUid, resolvedUserId)
13949a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                                .relayoutOverlayView(frame);
13959a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                    } catch (RemoteException e) {
13969a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                        Slog.e(TAG, "error in relayoutOverlayView", e);
13979a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                    }
13989a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                }
13999a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            } finally {
14009a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                Binder.restoreCallingIdentity(identity);
14019a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            }
14029a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho        }
14039a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho
14049a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho        @Override
14059a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho        public void removeOverlayView(IBinder sessionToken, int userId) {
14069a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            final int callingUid = Binder.getCallingUid();
14079a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
14089a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                    userId, "removeOverlayView");
14099a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            final long identity = Binder.clearCallingIdentity();
14109a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            try {
14119a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                synchronized (mLock) {
14129a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                    try {
14139a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                        getSessionLocked(sessionToken, callingUid, resolvedUserId)
14149a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                                .removeOverlayView();
14159a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                    } catch (RemoteException e) {
14169a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                        Slog.e(TAG, "error in removeOverlayView", e);
14179a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                    }
14189a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                }
14199a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            } finally {
14209a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                Binder.restoreCallingIdentity(identity);
14219a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            }
14229a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho        }
1423c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim
1424c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim        @Override
1425c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim        public List<TvInputHardwareInfo> getHardwareList() throws RemoteException {
1426969167dc05a6485a32d160895871cff46fd81884Wonsik Kim            if (mContext.checkCallingPermission(android.Manifest.permission.TV_INPUT_HARDWARE)
1427c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim                    != PackageManager.PERMISSION_GRANTED) {
1428c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim                return null;
1429c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim            }
1430c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim
1431c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim            final long identity = Binder.clearCallingIdentity();
1432c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim            try {
1433c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim                return mTvInputHardwareManager.getHardwareList();
1434c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim            } finally {
1435c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim                Binder.restoreCallingIdentity(identity);
1436c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim            }
1437c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim        }
1438c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim
1439c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim        @Override
1440c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim        public ITvInputHardware acquireTvInputHardware(int deviceId,
1441969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                ITvInputHardwareCallback callback, TvInputInfo info, int userId)
1442969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                throws RemoteException {
1443969167dc05a6485a32d160895871cff46fd81884Wonsik Kim            if (mContext.checkCallingPermission(android.Manifest.permission.TV_INPUT_HARDWARE)
1444c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim                    != PackageManager.PERMISSION_GRANTED) {
1445c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim                return null;
1446c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim            }
1447c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim
1448c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim            final long identity = Binder.clearCallingIdentity();
1449c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim            final int callingUid = Binder.getCallingUid();
1450c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
1451c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim                    userId, "acquireTvInputHardware");
1452c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim            try {
1453c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim                return mTvInputHardwareManager.acquireHardware(
1454969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                        deviceId, callback, info, callingUid, resolvedUserId);
1455c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim            } finally {
1456c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim                Binder.restoreCallingIdentity(identity);
1457c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim            }
1458c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim        }
1459c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim
1460c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim        @Override
1461c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim        public void releaseTvInputHardware(int deviceId, ITvInputHardware hardware, int userId)
1462c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim                throws RemoteException {
1463969167dc05a6485a32d160895871cff46fd81884Wonsik Kim            if (mContext.checkCallingPermission(android.Manifest.permission.TV_INPUT_HARDWARE)
1464c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim                    != PackageManager.PERMISSION_GRANTED) {
1465c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim                return;
1466c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim            }
1467c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim
1468c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim            final long identity = Binder.clearCallingIdentity();
1469c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim            final int callingUid = Binder.getCallingUid();
1470c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
1471c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim                    userId, "releaseTvInputHardware");
1472c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim            try {
1473c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim                mTvInputHardwareManager.releaseHardware(
1474c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim                        deviceId, hardware, callingUid, resolvedUserId);
1475c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim            } finally {
1476c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim                Binder.restoreCallingIdentity(identity);
1477c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim            }
1478c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim        }
1479e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim
1480e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim        @Override
1481c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo        public List<TvStreamConfig> getAvailableTvStreamConfigList(String inputId, int userId)
1482c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo                throws RemoteException {
1483c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo            if (mContext.checkCallingPermission(
1484c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo                    android.Manifest.permission.CAPTURE_TV_INPUT)
1485c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo                    != PackageManager.PERMISSION_GRANTED) {
1486c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo                throw new SecurityException("Requires CAPTURE_TV_INPUT permission");
1487c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo            }
1488c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo
1489c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo            final long identity = Binder.clearCallingIdentity();
1490c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo            final int callingUid = Binder.getCallingUid();
1491c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
1492c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo                    userId, "getAvailableTvStreamConfigList");
1493c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo            try {
1494c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo                return mTvInputHardwareManager.getAvailableTvStreamConfigList(
1495c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo                        inputId, callingUid, resolvedUserId);
1496c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo            } finally {
1497c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo                Binder.restoreCallingIdentity(identity);
1498c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo            }
1499c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo        }
1500c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo
1501c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo        @Override
1502c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo        public boolean captureFrame(String inputId, Surface surface, TvStreamConfig config,
1503c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo                int userId)
1504c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo                throws RemoteException {
1505c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo            if (mContext.checkCallingPermission(
1506c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo                    android.Manifest.permission.CAPTURE_TV_INPUT)
1507c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo                    != PackageManager.PERMISSION_GRANTED) {
1508c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo                throw new SecurityException("Requires CAPTURE_TV_INPUT permission");
1509c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo            }
1510c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo
1511c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo            final long identity = Binder.clearCallingIdentity();
1512c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo            final int callingUid = Binder.getCallingUid();
1513c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
1514c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo                    userId, "captureFrame");
1515c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo            try {
1516bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                String hardwareInputId = null;
151779124a717c09f12c74d587d3977bf33ca37e6420Terry Heo                synchronized (mLock) {
151879124a717c09f12c74d587d3977bf33ca37e6420Terry Heo                    UserState userState = getUserStateLocked(resolvedUserId);
1519bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                    if (userState.inputMap.get(inputId) == null) {
1520bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                        Slog.e(TAG, "Input not found for " + inputId);
1521bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                        return false;
1522bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                    }
1523bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                    for (SessionState sessionState : userState.sessionStateMap.values()) {
1524bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                        if (sessionState.mInfo.getId().equals(inputId)
1525bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                                && sessionState.mHardwareSessionToken != null) {
1526bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                            hardwareInputId = userState.sessionStateMap.get(
1527bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                                    sessionState.mHardwareSessionToken).mInfo.getId();
1528bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                            break;
1529bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                        }
1530bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                    }
153179124a717c09f12c74d587d3977bf33ca37e6420Terry Heo                }
1532c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo                return mTvInputHardwareManager.captureFrame(
1533bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                        (hardwareInputId != null) ? hardwareInputId : inputId,
153479124a717c09f12c74d587d3977bf33ca37e6420Terry Heo                        surface, config, callingUid, resolvedUserId);
1535c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo            } finally {
1536c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo                Binder.restoreCallingIdentity(identity);
1537c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo            }
1538c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo        }
1539c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo
1540c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo        @Override
1541df9f0a321e0cb2958c9d170395a0367a106fa0e6Terry Heo        public boolean isSingleSessionActive(int userId) throws RemoteException {
1542df9f0a321e0cb2958c9d170395a0367a106fa0e6Terry Heo            final long identity = Binder.clearCallingIdentity();
1543df9f0a321e0cb2958c9d170395a0367a106fa0e6Terry Heo            final int callingUid = Binder.getCallingUid();
1544df9f0a321e0cb2958c9d170395a0367a106fa0e6Terry Heo            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
1545df9f0a321e0cb2958c9d170395a0367a106fa0e6Terry Heo                    userId, "isSingleSessionActive");
1546df9f0a321e0cb2958c9d170395a0367a106fa0e6Terry Heo            try {
1547df9f0a321e0cb2958c9d170395a0367a106fa0e6Terry Heo                synchronized (mLock) {
1548df9f0a321e0cb2958c9d170395a0367a106fa0e6Terry Heo                    UserState userState = getUserStateLocked(resolvedUserId);
1549df9f0a321e0cb2958c9d170395a0367a106fa0e6Terry Heo                    if (userState.sessionStateMap.size() == 1) {
1550df9f0a321e0cb2958c9d170395a0367a106fa0e6Terry Heo                        return true;
1551df9f0a321e0cb2958c9d170395a0367a106fa0e6Terry Heo                    }
1552df9f0a321e0cb2958c9d170395a0367a106fa0e6Terry Heo                    else if (userState.sessionStateMap.size() == 2) {
1553df9f0a321e0cb2958c9d170395a0367a106fa0e6Terry Heo                        SessionState[] sessionStates = userState.sessionStateMap.values().toArray(
1554df9f0a321e0cb2958c9d170395a0367a106fa0e6Terry Heo                                new SessionState[0]);
1555df9f0a321e0cb2958c9d170395a0367a106fa0e6Terry Heo                        // Check if there is a wrapper input.
1556df9f0a321e0cb2958c9d170395a0367a106fa0e6Terry Heo                        if (sessionStates[0].mHardwareSessionToken != null
1557df9f0a321e0cb2958c9d170395a0367a106fa0e6Terry Heo                                || sessionStates[1].mHardwareSessionToken != null) {
1558df9f0a321e0cb2958c9d170395a0367a106fa0e6Terry Heo                            return true;
1559df9f0a321e0cb2958c9d170395a0367a106fa0e6Terry Heo                        }
1560df9f0a321e0cb2958c9d170395a0367a106fa0e6Terry Heo                    }
1561df9f0a321e0cb2958c9d170395a0367a106fa0e6Terry Heo                    return false;
1562df9f0a321e0cb2958c9d170395a0367a106fa0e6Terry Heo                }
1563df9f0a321e0cb2958c9d170395a0367a106fa0e6Terry Heo            } finally {
1564df9f0a321e0cb2958c9d170395a0367a106fa0e6Terry Heo                Binder.restoreCallingIdentity(identity);
1565df9f0a321e0cb2958c9d170395a0367a106fa0e6Terry Heo            }
1566df9f0a321e0cb2958c9d170395a0367a106fa0e6Terry Heo        }
1567df9f0a321e0cb2958c9d170395a0367a106fa0e6Terry Heo
1568df9f0a321e0cb2958c9d170395a0367a106fa0e6Terry Heo        @Override
15690f8fc345ea61928265fdd6d461bf1babe353fbe4Jae Seo        @SuppressWarnings("resource")
1570e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim        protected void dump(FileDescriptor fd, final PrintWriter writer, String[] args) {
1571e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim            final IndentingPrintWriter pw = new IndentingPrintWriter(writer, "  ");
15720f8fc345ea61928265fdd6d461bf1babe353fbe4Jae Seo            if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
1573e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                    != PackageManager.PERMISSION_GRANTED) {
15740f8fc345ea61928265fdd6d461bf1babe353fbe4Jae Seo                pw.println("Permission Denial: can't dump TvInputManager from pid="
15750f8fc345ea61928265fdd6d461bf1babe353fbe4Jae Seo                        + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid());
1576e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                return;
1577e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim            }
1578e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim
1579e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim            synchronized (mLock) {
1580e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                pw.println("User Ids (Current user: " + mCurrentUserId + "):");
1581e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                pw.increaseIndent();
1582e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                for (int i = 0; i < mUserStates.size(); i++) {
1583e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                    int userId = mUserStates.keyAt(i);
1584e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                    pw.println(Integer.valueOf(userId));
1585e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                }
1586e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                pw.decreaseIndent();
1587e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim
1588e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                for (int i = 0; i < mUserStates.size(); i++) {
1589e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                    int userId = mUserStates.keyAt(i);
1590e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                    UserState userState = getUserStateLocked(userId);
1591e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                    pw.println("UserState (" + userId + "):");
1592e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                    pw.increaseIndent();
1593e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim
1594969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                    pw.println("inputMap: inputId -> TvInputState");
1595e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                    pw.increaseIndent();
15968e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim                    for (Map.Entry<String, TvInputState> entry: userState.inputMap.entrySet()) {
15978e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim                        pw.println(entry.getKey() + ": " + entry.getValue());
1598e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                    }
1599e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                    pw.decreaseIndent();
1600e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim
1601969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                    pw.println("packageSet:");
1602e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                    pw.increaseIndent();
1603969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                    for (String packageName : userState.packageSet) {
1604e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        pw.println(packageName);
1605e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                    }
1606e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                    pw.decreaseIndent();
1607e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim
1608e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                    pw.println("clientStateMap: ITvInputClient -> ClientState");
1609e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                    pw.increaseIndent();
1610e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                    for (Map.Entry<IBinder, ClientState> entry :
1611e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                            userState.clientStateMap.entrySet()) {
1612e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        ClientState client = entry.getValue();
1613e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        pw.println(entry.getKey() + ": " + client);
1614e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim
1615e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        pw.increaseIndent();
1616e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim
1617e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        pw.println("mSessionTokens:");
1618e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        pw.increaseIndent();
1619e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        for (IBinder token : client.mSessionTokens) {
1620e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                            pw.println("" + token);
1621e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        }
1622e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        pw.decreaseIndent();
1623e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim
1624e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        pw.println("mClientTokens: " + client.mClientToken);
1625e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        pw.println("mUserId: " + client.mUserId);
1626e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim
1627e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        pw.decreaseIndent();
1628e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                    }
1629e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                    pw.decreaseIndent();
1630e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim
1631187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                    pw.println("serviceStateMap: ComponentName -> ServiceState");
1632e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                    pw.increaseIndent();
1633187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                    for (Map.Entry<ComponentName, ServiceState> entry :
1634e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                            userState.serviceStateMap.entrySet()) {
1635e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        ServiceState service = entry.getValue();
1636e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        pw.println(entry.getKey() + ": " + service);
1637e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim
1638e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        pw.increaseIndent();
1639e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim
1640e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        pw.println("mSessionTokens:");
1641e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        pw.increaseIndent();
1642e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        for (IBinder token : service.mSessionTokens) {
1643e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                            pw.println("" + token);
1644e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        }
1645e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        pw.decreaseIndent();
1646e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim
1647e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        pw.println("mService: " + service.mService);
1648e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        pw.println("mCallback: " + service.mCallback);
1649e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        pw.println("mBound: " + service.mBound);
1650e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        pw.println("mReconnecting: " + service.mReconnecting);
1651e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim
1652e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        pw.decreaseIndent();
1653e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                    }
1654e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                    pw.decreaseIndent();
1655e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim
1656e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                    pw.println("sessionStateMap: ITvInputSession -> SessionState");
1657e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                    pw.increaseIndent();
1658e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                    for (Map.Entry<IBinder, SessionState> entry :
1659e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                            userState.sessionStateMap.entrySet()) {
1660e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        SessionState session = entry.getValue();
1661e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        pw.println(entry.getKey() + ": " + session);
1662e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim
1663e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        pw.increaseIndent();
1664187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                        pw.println("mInfo: " + session.mInfo);
1665e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        pw.println("mClient: " + session.mClient);
1666e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        pw.println("mSeq: " + session.mSeq);
1667e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        pw.println("mCallingUid: " + session.mCallingUid);
1668e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        pw.println("mUserId: " + session.mUserId);
1669e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        pw.println("mSessionToken: " + session.mSessionToken);
1670e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        pw.println("mSession: " + session.mSession);
1671e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        pw.println("mLogUri: " + session.mLogUri);
1672bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                        pw.println("mHardwareSessionToken: " + session.mHardwareSessionToken);
1673e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        pw.decreaseIndent();
1674e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                    }
1675e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                    pw.decreaseIndent();
1676e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim
1677969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                    pw.println("callbackSet:");
1678969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                    pw.increaseIndent();
1679969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                    for (ITvInputManagerCallback callback : userState.callbackSet) {
1680969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                        pw.println(callback.toString());
1681969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                    }
1682969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                    pw.decreaseIndent();
1683969167dc05a6485a32d160895871cff46fd81884Wonsik Kim
1684956afc2ba79f50bb8025c6d334653e3c3419b480Ji-Hwan Lee                    pw.println("mainSessionToken: " + userState.mainSessionToken);
1685e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                    pw.decreaseIndent();
1686e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                }
1687e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim            }
1688e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim        }
16893957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    }
16903957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
1691969167dc05a6485a32d160895871cff46fd81884Wonsik Kim    private static final class TvInputState {
1692969167dc05a6485a32d160895871cff46fd81884Wonsik Kim        // A TvInputInfo object which represents the TV input.
1693969167dc05a6485a32d160895871cff46fd81884Wonsik Kim        private TvInputInfo mInfo;
1694969167dc05a6485a32d160895871cff46fd81884Wonsik Kim
1695969167dc05a6485a32d160895871cff46fd81884Wonsik Kim        // The state of TV input. Connected by default.
1696969167dc05a6485a32d160895871cff46fd81884Wonsik Kim        private int mState = INPUT_STATE_CONNECTED;
1697969167dc05a6485a32d160895871cff46fd81884Wonsik Kim
1698969167dc05a6485a32d160895871cff46fd81884Wonsik Kim        @Override
1699969167dc05a6485a32d160895871cff46fd81884Wonsik Kim        public String toString() {
1700969167dc05a6485a32d160895871cff46fd81884Wonsik Kim            return "mInfo: " + mInfo + "; mState: " + mState;
1701969167dc05a6485a32d160895871cff46fd81884Wonsik Kim        }
1702969167dc05a6485a32d160895871cff46fd81884Wonsik Kim    }
1703969167dc05a6485a32d160895871cff46fd81884Wonsik Kim
17043957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    private static final class UserState {
1705969167dc05a6485a32d160895871cff46fd81884Wonsik Kim        // A mapping from the TV input id to its TvInputState.
1706969167dc05a6485a32d160895871cff46fd81884Wonsik Kim        private Map<String, TvInputState> inputMap = new HashMap<String, TvInputState>();
17073957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
1708969167dc05a6485a32d160895871cff46fd81884Wonsik Kim        // A set of all TV input packages.
1709969167dc05a6485a32d160895871cff46fd81884Wonsik Kim        private final Set<String> packageSet = new HashSet<String>();
17105c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo
17115c5b83fcd58d21c9ab7ac986bf84f604ec5bb4b5Sungsoo Lim        // A set of all TV content rating system xml uris.
17125c5b83fcd58d21c9ab7ac986bf84f604ec5bb4b5Sungsoo Lim        private final Set<Uri> ratingSystemXmlUriSet = new HashSet<Uri>();
17135c5b83fcd58d21c9ab7ac986bf84f604ec5bb4b5Sungsoo Lim
171472ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim        // A mapping from the token of a client to its state.
171572ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim        private final Map<IBinder, ClientState> clientStateMap =
171672ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim                new HashMap<IBinder, ClientState>();
171772ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim
17183957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        // A mapping from the name of a TV input service to its state.
1719187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim        private final Map<ComponentName, ServiceState> serviceStateMap =
1720187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                new HashMap<ComponentName, ServiceState>();
17213957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
17223957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        // A mapping from the token of a TV input session to its state.
17233957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        private final Map<IBinder, SessionState> sessionStateMap =
17243957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                new HashMap<IBinder, SessionState>();
1725969167dc05a6485a32d160895871cff46fd81884Wonsik Kim
1726969167dc05a6485a32d160895871cff46fd81884Wonsik Kim        // A set of callbacks.
1727969167dc05a6485a32d160895871cff46fd81884Wonsik Kim        private final Set<ITvInputManagerCallback> callbackSet =
1728969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                new HashSet<ITvInputManagerCallback>();
172979124a717c09f12c74d587d3977bf33ca37e6420Terry Heo
17304c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee        // The token of a "main" TV input session.
17314c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee        private IBinder mainSessionToken = null;
1732783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo
1733783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo        // Persistent data store for all internal settings maintained by the TV input manager
1734783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo        // service.
1735783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo        private final PersistentDataStore persistentDataStore;
1736783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo
1737783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo        private UserState(Context context, int userId) {
1738783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo            persistentDataStore = new PersistentDataStore(context, userId);
1739783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo        }
17403957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    }
17413957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
174272ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim    private final class ClientState implements IBinder.DeathRecipient {
174372ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim        private final List<IBinder> mSessionTokens = new ArrayList<IBinder>();
174472ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim
174572ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim        private IBinder mClientToken;
174672ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim        private final int mUserId;
174772ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim
174872ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim        ClientState(IBinder clientToken, int userId) {
174972ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim            mClientToken = clientToken;
175072ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim            mUserId = userId;
175172ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim        }
175272ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim
175372ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim        public boolean isEmpty() {
1754a65118e13b5ceb54454b48f67ea754a38a08f27aJi-Hwan Lee            return mSessionTokens.isEmpty();
175572ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim        }
175672ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim
175772ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim        @Override
175872ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim        public void binderDied() {
175972ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim            synchronized (mLock) {
176072ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim                UserState userState = getUserStateLocked(mUserId);
176172ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim                // DO NOT remove the client state of clientStateMap in this method. It will be
1762a65118e13b5ceb54454b48f67ea754a38a08f27aJi-Hwan Lee                // removed in releaseSessionLocked().
176372ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim                ClientState clientState = userState.clientStateMap.get(mClientToken);
176472ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim                if (clientState != null) {
176572ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim                    while (clientState.mSessionTokens.size() > 0) {
176672ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim                        releaseSessionLocked(
176772ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim                                clientState.mSessionTokens.get(0), Process.SYSTEM_UID, mUserId);
176872ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim                    }
176972ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim                }
177072ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim                mClientToken = null;
177172ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim            }
177272ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim        }
177372ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim    }
177472ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim
17753957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    private final class ServiceState {
1776d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim        private final List<IBinder> mSessionTokens = new ArrayList<IBinder>();
1777d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim        private final ServiceConnection mConnection;
17789e8ade2eb7ee835963473c9cf6faaf5423b0b048Ji-Hwan Lee        private final ComponentName mComponent;
1779187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim        private final boolean mIsHardware;
1780187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim        private final List<TvInputInfo> mInputList = new ArrayList<TvInputInfo>();
17813957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
1782d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim        private ITvInputService mService;
1783d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim        private ServiceCallback mCallback;
1784d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim        private boolean mBound;
17852b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim        private boolean mReconnecting;
17863957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
17879e8ade2eb7ee835963473c9cf6faaf5423b0b048Ji-Hwan Lee        private ServiceState(ComponentName component, int userId) {
17889e8ade2eb7ee835963473c9cf6faaf5423b0b048Ji-Hwan Lee            mComponent = component;
17899e8ade2eb7ee835963473c9cf6faaf5423b0b048Ji-Hwan Lee            mConnection = new InputServiceConnection(component, userId);
17909e8ade2eb7ee835963473c9cf6faaf5423b0b048Ji-Hwan Lee            mIsHardware = hasHardwarePermission(mContext.getPackageManager(), mComponent);
17913957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
17923957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    }
17933957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
17942b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim    private final class SessionState implements IBinder.DeathRecipient {
1795187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim        private final TvInputInfo mInfo;
1796d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim        private final ITvInputClient mClient;
1797d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim        private final int mSeq;
1798d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim        private final int mCallingUid;
17992b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim        private final int mUserId;
180072ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim        private final IBinder mSessionToken;
1801d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim        private ITvInputSession mSession;
1802d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim        private Uri mLogUri;
1803bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang        // Not null if this session represents an external device connected to a hardware TV input.
1804bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang        private IBinder mHardwareSessionToken;
18053957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
1806bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang        private SessionState(IBinder sessionToken, TvInputInfo info, ITvInputClient client,
1807bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                int seq, int callingUid, int userId) {
180872ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim            mSessionToken = sessionToken;
1809187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim            mInfo = info;
18102b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim            mClient = client;
18112b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim            mSeq = seq;
18122b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim            mCallingUid = callingUid;
18132b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim            mUserId = userId;
18142b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim        }
18152b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim
18162b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim        @Override
18172b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim        public void binderDied() {
18182b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim            synchronized (mLock) {
18192b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                mSession = null;
18202b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                if (mClient != null) {
18212b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                    try {
18222b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                        mClient.onSessionReleased(mSeq);
18232b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                    } catch(RemoteException e) {
18242b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                        Slog.e(TAG, "error in onSessionReleased", e);
18252b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                    }
18262b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                }
1827bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                // If there are any other sessions based on this session, they should be released.
1828bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                UserState userState = getUserStateLocked(mUserId);
1829bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                for (SessionState sessionState : userState.sessionStateMap.values()) {
18300c38fc764b0e1c5c8b880872d9b4a647a76955cdJi-Hwan Lee                    if (mSessionToken == sessionState.mHardwareSessionToken) {
18314835497886ee876b16e1144d32f5bdcfbb7e9062Ji-Hwan Lee                        releaseSessionLocked(sessionState.mSessionToken, Process.SYSTEM_UID,
18324835497886ee876b16e1144d32f5bdcfbb7e9062Ji-Hwan Lee                                mUserId);
1833bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                        try {
1834bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                            sessionState.mClient.onSessionReleased(sessionState.mSeq);
1835bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                        } catch (RemoteException e) {
1836bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                            Slog.e(TAG, "error in onSessionReleased", e);
1837bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                        }
1838bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                    }
1839bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                }
184072ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim                removeSessionStateLocked(mSessionToken, mUserId);
18412b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim            }
18423957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
18433957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    }
18443957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
18453957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    private final class InputServiceConnection implements ServiceConnection {
18469e8ade2eb7ee835963473c9cf6faaf5423b0b048Ji-Hwan Lee        private final ComponentName mComponent;
18473957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        private final int mUserId;
18483957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
18499e8ade2eb7ee835963473c9cf6faaf5423b0b048Ji-Hwan Lee        private InputServiceConnection(ComponentName component, int userId) {
18509e8ade2eb7ee835963473c9cf6faaf5423b0b048Ji-Hwan Lee            mComponent = component;
18513957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            mUserId = userId;
18523957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
18533957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
18543957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        @Override
18559e8ade2eb7ee835963473c9cf6faaf5423b0b048Ji-Hwan Lee        public void onServiceConnected(ComponentName component, IBinder service) {
18563957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            if (DEBUG) {
18579e8ade2eb7ee835963473c9cf6faaf5423b0b048Ji-Hwan Lee                Slog.d(TAG, "onServiceConnected(component=" + component + ")");
18583957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            }
18593957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            synchronized (mLock) {
1860969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                UserState userState = getUserStateLocked(mUserId);
18619e8ade2eb7ee835963473c9cf6faaf5423b0b048Ji-Hwan Lee                ServiceState serviceState = userState.serviceStateMap.get(mComponent);
1862d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim                serviceState.mService = ITvInputService.Stub.asInterface(service);
18633957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
18643957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                // Register a callback, if we need to.
1865187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                if (serviceState.mIsHardware && serviceState.mCallback == null) {
18669e8ade2eb7ee835963473c9cf6faaf5423b0b048Ji-Hwan Lee                    serviceState.mCallback = new ServiceCallback(mComponent, mUserId);
18673957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    try {
1868d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim                        serviceState.mService.registerCallback(serviceState.mCallback);
18693957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    } catch (RemoteException e) {
18709a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                        Slog.e(TAG, "error in registerCallback", e);
18713957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    }
18723957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                }
18733957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
18743957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                // And create sessions, if any.
1875d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim                for (IBinder sessionToken : serviceState.mSessionTokens) {
1876d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim                    createSessionInternalLocked(serviceState.mService, sessionToken, mUserId);
18773957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                }
1878969167dc05a6485a32d160895871cff46fd81884Wonsik Kim
1879187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                for (TvInputState inputState : userState.inputMap.values()) {
18809e8ade2eb7ee835963473c9cf6faaf5423b0b048Ji-Hwan Lee                    if (inputState.mInfo.getComponent().equals(component)
1881187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                            && inputState.mState != INPUT_STATE_DISCONNECTED) {
18828e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim                        notifyInputStateChangedLocked(userState, inputState.mInfo.getId(),
1883187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                                inputState.mState, null);
1884187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                    }
1885187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                }
1886187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim
1887187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                if (serviceState.mIsHardware) {
18884f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                    List<TvInputHardwareInfo> hardwareInfoList =
18894f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                            mTvInputHardwareManager.getHardwareList();
1890187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                    for (TvInputHardwareInfo hardwareInfo : hardwareInfoList) {
1891187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                        try {
1892187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                            serviceState.mService.notifyHardwareAdded(hardwareInfo);
1893187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                        } catch (RemoteException e) {
1894187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                            Slog.e(TAG, "error in notifyHardwareAdded", e);
1895187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                        }
1896187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                    }
1897187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim
1898546c635ad9a26421fbdf54efa765b5ab0a63c191Jae Seo                    List<HdmiDeviceInfo> deviceInfoList =
1899546c635ad9a26421fbdf54efa765b5ab0a63c191Jae Seo                            mTvInputHardwareManager.getHdmiDeviceList();
1900546c635ad9a26421fbdf54efa765b5ab0a63c191Jae Seo                    for (HdmiDeviceInfo deviceInfo : deviceInfoList) {
19014f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                        try {
1902546c635ad9a26421fbdf54efa765b5ab0a63c191Jae Seo                            serviceState.mService.notifyHdmiDeviceAdded(deviceInfo);
19034f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                        } catch (RemoteException e) {
1904546c635ad9a26421fbdf54efa765b5ab0a63c191Jae Seo                            Slog.e(TAG, "error in notifyHdmiDeviceAdded", e);
19054f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                        }
19064f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                    }
1907969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                }
19083957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            }
19093957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
19103957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
19113957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        @Override
19129e8ade2eb7ee835963473c9cf6faaf5423b0b048Ji-Hwan Lee        public void onServiceDisconnected(ComponentName component) {
19133957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            if (DEBUG) {
19149e8ade2eb7ee835963473c9cf6faaf5423b0b048Ji-Hwan Lee                Slog.d(TAG, "onServiceDisconnected(component=" + component + ")");
19153957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            }
19169e8ade2eb7ee835963473c9cf6faaf5423b0b048Ji-Hwan Lee            if (!mComponent.equals(component)) {
19172b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                throw new IllegalArgumentException("Mismatched ComponentName: "
19189e8ade2eb7ee835963473c9cf6faaf5423b0b048Ji-Hwan Lee                        + mComponent + " (expected), " + component + " (actual).");
19192b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim            }
19202b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim            synchronized (mLock) {
19212b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                UserState userState = getUserStateLocked(mUserId);
19229e8ade2eb7ee835963473c9cf6faaf5423b0b048Ji-Hwan Lee                ServiceState serviceState = userState.serviceStateMap.get(mComponent);
19232b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                if (serviceState != null) {
19242b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                    serviceState.mReconnecting = true;
19252b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                    serviceState.mBound = false;
19262b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                    serviceState.mService = null;
19272b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                    serviceState.mCallback = null;
19282b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim
1929426c9a4008b75b93cbfea15aa4b8c47c5fdb49b9Dongwon Kang                    abortPendingCreateSessionRequestsLocked(serviceState, null, mUserId);
19302b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim
1931187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                    for (TvInputState inputState : userState.inputMap.values()) {
19329e8ade2eb7ee835963473c9cf6faaf5423b0b048Ji-Hwan Lee                        if (inputState.mInfo.getComponent().equals(component)) {
1933bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                            notifyInputStateChangedLocked(userState, inputState.mInfo.getId(),
1934187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                                    INPUT_STATE_DISCONNECTED, null);
1935187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                        }
1936187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                    }
19372b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                }
19382b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim            }
19393957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
19403957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    }
19413957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
19423957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    private final class ServiceCallback extends ITvInputServiceCallback.Stub {
19439e8ade2eb7ee835963473c9cf6faaf5423b0b048Ji-Hwan Lee        private final ComponentName mComponent;
19443957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        private final int mUserId;
19453957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
19469e8ade2eb7ee835963473c9cf6faaf5423b0b048Ji-Hwan Lee        ServiceCallback(ComponentName component, int userId) {
19479e8ade2eb7ee835963473c9cf6faaf5423b0b048Ji-Hwan Lee            mComponent = component;
19483957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            mUserId = userId;
19493957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
19503957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
19514f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee        private void ensureHardwarePermission() {
19524f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee            if (mContext.checkCallingPermission(android.Manifest.permission.TV_INPUT_HARDWARE)
19534f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                    != PackageManager.PERMISSION_GRANTED) {
19544f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                throw new SecurityException("The caller does not have hardware permission");
19554f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee            }
19564f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee        }
19574f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee
19584f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee        private void ensureValidInput(TvInputInfo inputInfo) {
19599e8ade2eb7ee835963473c9cf6faaf5423b0b048Ji-Hwan Lee            if (inputInfo.getId() == null || !mComponent.equals(inputInfo.getComponent())) {
19604f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                throw new IllegalArgumentException("Invalid TvInputInfo");
19614f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee            }
19624f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee        }
19634f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee
19644f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee        private void addTvInputLocked(TvInputInfo inputInfo) {
19659e8ade2eb7ee835963473c9cf6faaf5423b0b048Ji-Hwan Lee            ServiceState serviceState = getServiceStateLocked(mComponent, mUserId);
19664f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee            serviceState.mInputList.add(inputInfo);
19674f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee            buildTvInputListLocked(mUserId);
19684f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee        }
19694f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee
19703957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        @Override
19714f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee        public void addHardwareTvInput(int deviceId, TvInputInfo inputInfo) {
19724f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee            ensureHardwarePermission();
19734f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee            ensureValidInput(inputInfo);
1974187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim            synchronized (mLock) {
19754f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                mTvInputHardwareManager.addHardwareTvInput(deviceId, inputInfo);
19764f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                addTvInputLocked(inputInfo);
19774f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee            }
19784f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee        }
1979187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim
19804f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee        @Override
19818960d1b1552729e3dfd33deee951ac75933ad8e5Jinsuk Kim        public void addHdmiTvInput(int id, TvInputInfo inputInfo) {
19824f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee            ensureHardwarePermission();
19834f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee            ensureValidInput(inputInfo);
19844f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee            synchronized (mLock) {
19858960d1b1552729e3dfd33deee951ac75933ad8e5Jinsuk Kim                mTvInputHardwareManager.addHdmiTvInput(id, inputInfo);
19864f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                addTvInputLocked(inputInfo);
19873957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            }
1988187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim        }
1989187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim
1990187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim        @Override
1991187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim        public void removeTvInput(String inputId) {
19924f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee            ensureHardwarePermission();
19933957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            synchronized (mLock) {
19949e8ade2eb7ee835963473c9cf6faaf5423b0b048Ji-Hwan Lee                ServiceState serviceState = getServiceStateLocked(mComponent, mUserId);
1995187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                boolean removed = false;
1996187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                for (Iterator<TvInputInfo> it = serviceState.mInputList.iterator();
1997187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                        it.hasNext(); ) {
1998187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                    if (it.next().getId().equals(inputId)) {
1999187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                        it.remove();
2000187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                        removed = true;
2001187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                        break;
2002187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                    }
2003187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                }
2004187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                if (removed) {
2005187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                    buildTvInputListLocked(mUserId);
20064f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                    mTvInputHardwareManager.removeTvInput(inputId);
2007187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                } else {
2008187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                    Slog.e(TAG, "TvInputInfo with inputId=" + inputId + " not found.");
2009187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                }
20103957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            }
20113957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
20123957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    }
201331dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo
20147eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo    private final class WatchLogHandler extends Handler {
20157eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo        // There are only two kinds of watch events that can happen on the system:
20167eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo        // 1. The current TV input session is tuned to a new channel.
20177eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo        // 2. The session is released for some reason.
20187eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo        // The former indicates the end of the previous log entry, if any, followed by the start of
20197eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo        // a new entry. The latter indicates the end of the most recent entry for the given session.
20207eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo        // Here the system supplies the database the smallest set of information only that is
20217eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo        // sufficient to consolidate the log entries while minimizing database operations in the
20227eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo        // system service.
20237eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo        private static final int MSG_LOG_WATCH_START = 1;
20247eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo        private static final int MSG_LOG_WATCH_END = 2;
20257eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo
20267eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo        public WatchLogHandler(Looper looper) {
202731dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo            super(looper);
202831dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo        }
202931dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo
203031dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo        @Override
203131dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo        public void handleMessage(Message msg) {
203231dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo            switch (msg.what) {
20337eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo                case MSG_LOG_WATCH_START: {
203431dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                    SomeArgs args = (SomeArgs) msg.obj;
20357eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo                    String packageName = (String) args.arg1;
20367eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo                    long watchStartTime = (long) args.arg2;
20377eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo                    long channelId = (long) args.arg3;
20387eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo                    Bundle tuneParams = (Bundle) args.arg4;
20397eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo                    IBinder sessionToken = (IBinder) args.arg5;
20407eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo
20417eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo                    ContentValues values = new ContentValues();
20427eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo                    values.put(TvContract.WatchedPrograms.COLUMN_PACKAGE_NAME, packageName);
20437eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo                    values.put(TvContract.WatchedPrograms.COLUMN_WATCH_START_TIME_UTC_MILLIS,
20447eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo                            watchStartTime);
20457eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo                    values.put(TvContract.WatchedPrograms.COLUMN_CHANNEL_ID, channelId);
20467eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo                    if (tuneParams != null) {
20477eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo                        values.put(TvContract.WatchedPrograms.COLUMN_INTERNAL_TUNE_PARAMS,
20487eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo                                encodeTuneParams(tuneParams));
20497eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo                    }
20507eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo                    values.put(TvContract.WatchedPrograms.COLUMN_INTERNAL_SESSION_TOKEN,
20517eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo                            sessionToken.toString());
20527eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo
20537eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo                    mContentResolver.insert(TvContract.WatchedPrograms.CONTENT_URI, values);
205431dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                    args.recycle();
205531dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                    return;
205631dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                }
20577eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo                case MSG_LOG_WATCH_END: {
205831dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                    SomeArgs args = (SomeArgs) msg.obj;
20597eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo                    IBinder sessionToken = (IBinder) args.arg1;
20607eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo                    long watchEndTime = (long) args.arg2;
20617eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo
20627eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo                    ContentValues values = new ContentValues();
20637eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo                    values.put(TvContract.WatchedPrograms.COLUMN_WATCH_END_TIME_UTC_MILLIS,
20647eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo                            watchEndTime);
20657eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo                    values.put(TvContract.WatchedPrograms.COLUMN_INTERNAL_SESSION_TOKEN,
20667eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo                            sessionToken.toString());
20677eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo
20687eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo                    mContentResolver.insert(TvContract.WatchedPrograms.CONTENT_URI, values);
206931dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                    args.recycle();
207031dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                    return;
207131dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                }
207231dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                default: {
20736a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                    Slog.w(TAG, "Unhandled message code: " + msg.what);
207431dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                    return;
207531dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                }
207631dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo            }
207731dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo        }
207831dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo
20797eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo        private String encodeTuneParams(Bundle tuneParams) {
20807eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo            StringBuilder builder = new StringBuilder();
20817eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo            Set<String> keySet = tuneParams.keySet();
20827eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo            Iterator<String> it = keySet.iterator();
20837eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo            while (it.hasNext()) {
20847eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo                String key = it.next();
20857eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo                Object value = tuneParams.get(key);
20867eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo                if (value == null) {
20877eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo                    continue;
208831dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                }
20897eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo                builder.append(replaceEscapeCharacters(key));
20907eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo                builder.append("=");
20917eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo                builder.append(replaceEscapeCharacters(value.toString()));
20927eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo                if (it.hasNext()) {
20937eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo                    builder.append(", ");
209431dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                }
209531dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo            }
20967eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo            return builder.toString();
209731dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo        }
209831dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo
20997eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo        private String replaceEscapeCharacters(String src) {
21007eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo            final char ESCAPE_CHARACTER = '%';
21017eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo            final String ENCODING_TARGET_CHARACTERS = "%=,";
21027eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo            StringBuilder builder = new StringBuilder();
21037eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo            for (char ch : src.toCharArray()) {
21047eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo                if (ENCODING_TARGET_CHARACTERS.indexOf(ch) >= 0) {
21057eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo                    builder.append(ESCAPE_CHARACTER);
2106579befecb248162021929ab58ffd23f1724cc6beJae Seo                }
21077eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo                builder.append(ch);
2108579befecb248162021929ab58ffd23f1724cc6beJae Seo            }
21097eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo            return builder.toString();
2110579befecb248162021929ab58ffd23f1724cc6beJae Seo        }
211131dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo    }
2112969167dc05a6485a32d160895871cff46fd81884Wonsik Kim
2113187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim    final class HardwareListener implements TvInputHardwareManager.Listener {
2114187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim        @Override
2115187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim        public void onStateChanged(String inputId, int state) {
2116969167dc05a6485a32d160895871cff46fd81884Wonsik Kim            synchronized (mLock) {
2117969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                setStateLocked(inputId, state, mCurrentUserId);
2118969167dc05a6485a32d160895871cff46fd81884Wonsik Kim            }
2119969167dc05a6485a32d160895871cff46fd81884Wonsik Kim        }
2120187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim
2121187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim        @Override
2122187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim        public void onHardwareDeviceAdded(TvInputHardwareInfo info) {
2123187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim            synchronized (mLock) {
2124187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                UserState userState = getUserStateLocked(mCurrentUserId);
2125187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                // Broadcast the event to all hardware inputs.
2126187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                for (ServiceState serviceState : userState.serviceStateMap.values()) {
2127187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                    if (!serviceState.mIsHardware || serviceState.mService == null) continue;
2128187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                    try {
2129187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                        serviceState.mService.notifyHardwareAdded(info);
2130187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                    } catch (RemoteException e) {
2131187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                        Slog.e(TAG, "error in notifyHardwareAdded", e);
2132187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                    }
2133187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                }
2134187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim            }
2135187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim        }
2136187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim
2137187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim        @Override
21384f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee        public void onHardwareDeviceRemoved(TvInputHardwareInfo info) {
2139187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim            synchronized (mLock) {
2140187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                UserState userState = getUserStateLocked(mCurrentUserId);
2141187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                // Broadcast the event to all hardware inputs.
2142187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                for (ServiceState serviceState : userState.serviceStateMap.values()) {
2143187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                    if (!serviceState.mIsHardware || serviceState.mService == null) continue;
2144187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                    try {
21454f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                        serviceState.mService.notifyHardwareRemoved(info);
2146187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                    } catch (RemoteException e) {
2147187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                        Slog.e(TAG, "error in notifyHardwareRemoved", e);
2148187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                    }
2149187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                }
2150187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim            }
2151187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim        }
2152187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim
2153187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim        @Override
2154546c635ad9a26421fbdf54efa765b5ab0a63c191Jae Seo        public void onHdmiDeviceAdded(HdmiDeviceInfo deviceInfo) {
2155187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim            synchronized (mLock) {
21564f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                UserState userState = getUserStateLocked(mCurrentUserId);
21574f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                // Broadcast the event to all hardware inputs.
21584f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                for (ServiceState serviceState : userState.serviceStateMap.values()) {
21594f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                    if (!serviceState.mIsHardware || serviceState.mService == null) continue;
21604f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                    try {
2161546c635ad9a26421fbdf54efa765b5ab0a63c191Jae Seo                        serviceState.mService.notifyHdmiDeviceAdded(deviceInfo);
21624f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                    } catch (RemoteException e) {
2163546c635ad9a26421fbdf54efa765b5ab0a63c191Jae Seo                        Slog.e(TAG, "error in notifyHdmiDeviceAdded", e);
21644f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                    }
21654f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                }
2166187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim            }
2167187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim        }
2168187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim
2169187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim        @Override
2170546c635ad9a26421fbdf54efa765b5ab0a63c191Jae Seo        public void onHdmiDeviceRemoved(HdmiDeviceInfo deviceInfo) {
2171187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim            synchronized (mLock) {
21724f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                UserState userState = getUserStateLocked(mCurrentUserId);
21734f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                // Broadcast the event to all hardware inputs.
21744f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                for (ServiceState serviceState : userState.serviceStateMap.values()) {
21754f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                    if (!serviceState.mIsHardware || serviceState.mService == null) continue;
21764f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                    try {
2177546c635ad9a26421fbdf54efa765b5ab0a63c191Jae Seo                        serviceState.mService.notifyHdmiDeviceRemoved(deviceInfo);
21784f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                    } catch (RemoteException e) {
2179546c635ad9a26421fbdf54efa765b5ab0a63c191Jae Seo                        Slog.e(TAG, "error in notifyHdmiDeviceRemoved", e);
21804f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                    }
21814f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                }
2182187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim            }
2183187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim        }
218461daf6b38e7a7ada2a6ca5a60539a54b9c6810bdJungshik Jang
218561daf6b38e7a7ada2a6ca5a60539a54b9c6810bdJungshik Jang        @Override
2186e92f857d50d7259a4cf7ef5b88309e098338c9c1Wonsik Kim        public void onHdmiDeviceUpdated(String inputId, HdmiDeviceInfo deviceInfo) {
2187e92f857d50d7259a4cf7ef5b88309e098338c9c1Wonsik Kim            synchronized (mLock) {
2188e92f857d50d7259a4cf7ef5b88309e098338c9c1Wonsik Kim                Integer state = null;
2189e92f857d50d7259a4cf7ef5b88309e098338c9c1Wonsik Kim                switch (deviceInfo.getDevicePowerStatus()) {
2190e92f857d50d7259a4cf7ef5b88309e098338c9c1Wonsik Kim                    case HdmiControlManager.POWER_STATUS_ON:
2191e92f857d50d7259a4cf7ef5b88309e098338c9c1Wonsik Kim                        state = INPUT_STATE_CONNECTED;
2192e92f857d50d7259a4cf7ef5b88309e098338c9c1Wonsik Kim                        break;
2193e92f857d50d7259a4cf7ef5b88309e098338c9c1Wonsik Kim                    case HdmiControlManager.POWER_STATUS_STANDBY:
2194e92f857d50d7259a4cf7ef5b88309e098338c9c1Wonsik Kim                    case HdmiControlManager.POWER_STATUS_TRANSIENT_TO_ON:
2195e92f857d50d7259a4cf7ef5b88309e098338c9c1Wonsik Kim                    case HdmiControlManager.POWER_STATUS_TRANSIENT_TO_STANDBY:
2196e92f857d50d7259a4cf7ef5b88309e098338c9c1Wonsik Kim                        state = INPUT_STATE_CONNECTED_STANDBY;
2197e92f857d50d7259a4cf7ef5b88309e098338c9c1Wonsik Kim                        break;
2198e92f857d50d7259a4cf7ef5b88309e098338c9c1Wonsik Kim                    case HdmiControlManager.POWER_STATUS_UNKNOWN:
2199e92f857d50d7259a4cf7ef5b88309e098338c9c1Wonsik Kim                    default:
2200e92f857d50d7259a4cf7ef5b88309e098338c9c1Wonsik Kim                        state = null;
2201e92f857d50d7259a4cf7ef5b88309e098338c9c1Wonsik Kim                        break;
2202e92f857d50d7259a4cf7ef5b88309e098338c9c1Wonsik Kim                }
2203e92f857d50d7259a4cf7ef5b88309e098338c9c1Wonsik Kim                if (state != null) {
2204e92f857d50d7259a4cf7ef5b88309e098338c9c1Wonsik Kim                    setStateLocked(inputId, state.intValue(), mCurrentUserId);
2205e92f857d50d7259a4cf7ef5b88309e098338c9c1Wonsik Kim                }
2206e92f857d50d7259a4cf7ef5b88309e098338c9c1Wonsik Kim            }
220761daf6b38e7a7ada2a6ca5a60539a54b9c6810bdJungshik Jang        }
2208969167dc05a6485a32d160895871cff46fd81884Wonsik Kim    }
22093957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo}
2210