TvInputManagerService.java revision 15c56aac985bc8d75f38fb4ecb92dda12d2ca06c
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() {
1493957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                synchronized (mLock) {
1503957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    buildTvInputListLocked(mCurrentUserId);
1513957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                }
1523957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            }
1535c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo
1545c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo            @Override
1555c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo            public void onPackageRemoved(String packageName, int uid) {
1565c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo                synchronized (mLock) {
1575c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo                    UserState userState = getUserStateLocked(mCurrentUserId);
158969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                    if (!userState.packageSet.contains(packageName)) {
1595c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo                        // Not a TV input package.
1605c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo                        return;
1615c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo                    }
1625c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo                }
1635c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo
1645c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo                ArrayList<ContentProviderOperation> operations =
1655c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo                        new ArrayList<ContentProviderOperation>();
1665c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo
1675c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo                String selection = TvContract.BaseTvColumns.COLUMN_PACKAGE_NAME + "=?";
1685c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo                String[] selectionArgs = { packageName };
1695c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo
1705c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo                operations.add(ContentProviderOperation.newDelete(TvContract.Channels.CONTENT_URI)
1715c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo                        .withSelection(selection, selectionArgs).build());
1725c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo                operations.add(ContentProviderOperation.newDelete(TvContract.Programs.CONTENT_URI)
1735c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo                        .withSelection(selection, selectionArgs).build());
1745c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo                operations.add(ContentProviderOperation
1755c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo                        .newDelete(TvContract.WatchedPrograms.CONTENT_URI)
1765c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo                        .withSelection(selection, selectionArgs).build());
1775c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo
1785c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo                ContentProviderResult[] results = null;
1795c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo                try {
1805c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo                    results = mContentResolver.applyBatch(TvContract.AUTHORITY, operations);
1815c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo                } catch (RemoteException | OperationApplicationException e) {
1825c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo                    Slog.e(TAG, "error in applyBatch" + e);
1835c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo                }
1845c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo
1855c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo                if (DEBUG) {
1865c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo                    Slog.d(TAG, "onPackageRemoved(packageName=" + packageName + ", uid=" + uid
1875c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo                            + ")");
1885c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo                    Slog.d(TAG, "results=" + results);
1895c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo                }
1905c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo            }
1913957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        };
1923957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        monitor.register(mContext, null, UserHandle.ALL, true);
1933957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
1943957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        IntentFilter intentFilter = new IntentFilter();
1953957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        intentFilter.addAction(Intent.ACTION_USER_SWITCHED);
1963957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        intentFilter.addAction(Intent.ACTION_USER_REMOVED);
1973957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        mContext.registerReceiverAsUser(new BroadcastReceiver() {
1983957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            @Override
1993957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            public void onReceive(Context context, Intent intent) {
2003957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                String action = intent.getAction();
2013957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                if (Intent.ACTION_USER_SWITCHED.equals(action)) {
2023957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    switchUser(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0));
2033957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                } else if (Intent.ACTION_USER_REMOVED.equals(action)) {
2043957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    removeUser(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0));
2053957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                }
2063957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            }
2073957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }, UserHandle.ALL, intentFilter, null, null);
2083957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    }
2093957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
2109e8ade2eb7ee835963473c9cf6faaf5423b0b048Ji-Hwan Lee    private static boolean hasHardwarePermission(PackageManager pm, ComponentName component) {
211187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim        return pm.checkPermission(android.Manifest.permission.TV_INPUT_HARDWARE,
2129e8ade2eb7ee835963473c9cf6faaf5423b0b048Ji-Hwan Lee                component.getPackageName()) == PackageManager.PERMISSION_GRANTED;
213187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim    }
214187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim
2153957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    private void buildTvInputListLocked(int userId) {
2163957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        UserState userState = getUserStateLocked(userId);
217969167dc05a6485a32d160895871cff46fd81884Wonsik Kim        userState.packageSet.clear();
2183957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
2199a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho        if (DEBUG) Slog.d(TAG, "buildTvInputList");
2203957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        PackageManager pm = mContext.getPackageManager();
2213957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        List<ResolveInfo> services = pm.queryIntentServices(
222e7bb7d6bb2257c24076f5a4b9f536f90a6637f58Chulwoo Lee                new Intent(TvInputService.SERVICE_INTERFACE),
223e7bb7d6bb2257c24076f5a4b9f536f90a6637f58Chulwoo Lee                PackageManager.GET_SERVICES | PackageManager.GET_META_DATA);
2244f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee        List<TvInputInfo> inputList = new ArrayList<TvInputInfo>();
2253957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        for (ResolveInfo ri : services) {
2263957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            ServiceInfo si = ri.serviceInfo;
2273957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            if (!android.Manifest.permission.BIND_TV_INPUT.equals(si.permission)) {
2289a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                Slog.w(TAG, "Skipping TV input " + si.name + ": it does not require the permission "
2293957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                        + android.Manifest.permission.BIND_TV_INPUT);
2303957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                continue;
2313957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            }
2329cc28e5175e1391646b29469d329c9c1c9311ee1Jae Seo
2339cc28e5175e1391646b29469d329c9c1c9311ee1Jae Seo            ComponentName component = new ComponentName(si.packageName, si.name);
2349cc28e5175e1391646b29469d329c9c1c9311ee1Jae Seo            if (hasHardwarePermission(pm, component)) {
2359cc28e5175e1391646b29469d329c9c1c9311ee1Jae Seo                ServiceState serviceState = userState.serviceStateMap.get(component);
2369cc28e5175e1391646b29469d329c9c1c9311ee1Jae Seo                if (serviceState == null) {
2379cc28e5175e1391646b29469d329c9c1c9311ee1Jae Seo                    // We see this hardware TV input service for the first time; we need to
2389cc28e5175e1391646b29469d329c9c1c9311ee1Jae Seo                    // prepare the ServiceState object so that we can connect to the service and
2399cc28e5175e1391646b29469d329c9c1c9311ee1Jae Seo                    // let it add TvInputInfo objects to mInputList if there's any.
2409cc28e5175e1391646b29469d329c9c1c9311ee1Jae Seo                    serviceState = new ServiceState(component, userId);
2419cc28e5175e1391646b29469d329c9c1c9311ee1Jae Seo                    userState.serviceStateMap.put(component, serviceState);
242187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                } else {
2439cc28e5175e1391646b29469d329c9c1c9311ee1Jae Seo                    inputList.addAll(serviceState.mInputList);
244187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                }
2459cc28e5175e1391646b29469d329c9c1c9311ee1Jae Seo            } else {
2469cc28e5175e1391646b29469d329c9c1c9311ee1Jae Seo                try {
2479cc28e5175e1391646b29469d329c9c1c9311ee1Jae Seo                    inputList.add(TvInputInfo.createTvInputInfo(mContext, ri));
2489cc28e5175e1391646b29469d329c9c1c9311ee1Jae Seo                } catch (XmlPullParserException | IOException e) {
2499cc28e5175e1391646b29469d329c9c1c9311ee1Jae Seo                    Slog.e(TAG, "Failed to load TV input " + si.name, e);
2509cc28e5175e1391646b29469d329c9c1c9311ee1Jae Seo                    continue;
251969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                }
2529cc28e5175e1391646b29469d329c9c1c9311ee1Jae Seo            }
253226a51958d645a8e2be3e40a6b6daaca558b4913Jaewan Kim
2549cc28e5175e1391646b29469d329c9c1c9311ee1Jae Seo            // Reconnect the service if existing input is updated.
2559cc28e5175e1391646b29469d329c9c1c9311ee1Jae Seo            updateServiceConnectionLocked(component, userId);
2569cc28e5175e1391646b29469d329c9c1c9311ee1Jae Seo            userState.packageSet.add(si.packageName);
2579cc28e5175e1391646b29469d329c9c1c9311ee1Jae Seo        }
258187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim
2599cc28e5175e1391646b29469d329c9c1c9311ee1Jae Seo        Map<String, TvInputState> inputMap = new HashMap<String, TvInputState>();
2609cc28e5175e1391646b29469d329c9c1c9311ee1Jae Seo        for (TvInputInfo info : inputList) {
2619cc28e5175e1391646b29469d329c9c1c9311ee1Jae Seo            if (DEBUG) Slog.d(TAG, "add " + info.getId());
2629cc28e5175e1391646b29469d329c9c1c9311ee1Jae Seo            TvInputState state = userState.inputMap.get(info.getId());
2639cc28e5175e1391646b29469d329c9c1c9311ee1Jae Seo            if (state == null) {
2649cc28e5175e1391646b29469d329c9c1c9311ee1Jae Seo                state = new TvInputState();
265e7bb7d6bb2257c24076f5a4b9f536f90a6637f58Chulwoo Lee            }
2669cc28e5175e1391646b29469d329c9c1c9311ee1Jae Seo            state.mInfo = info;
2679cc28e5175e1391646b29469d329c9c1c9311ee1Jae Seo            inputMap.put(info.getId(), state);
2683957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
2698e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim
2708e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim        for (String inputId : inputMap.keySet()) {
2718e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim            if (!userState.inputMap.containsKey(inputId)) {
2728e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim                notifyInputAddedLocked(userState, inputId);
2738e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim            }
2748e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim        }
2758e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim
2768e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim        for (String inputId : userState.inputMap.keySet()) {
2778e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim            if (!inputMap.containsKey(inputId)) {
2788e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim                notifyInputRemovedLocked(userState, inputId);
2798e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim            }
2808e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim        }
2818e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim
2828e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim        userState.inputMap.clear();
2838e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim        userState.inputMap = inputMap;
2845c5b83fcd58d21c9ab7ac986bf84f604ec5bb4b5Sungsoo Lim
2855c5b83fcd58d21c9ab7ac986bf84f604ec5bb4b5Sungsoo Lim        userState.ratingSystemXmlUriSet.clear();
2865c5b83fcd58d21c9ab7ac986bf84f604ec5bb4b5Sungsoo Lim        userState.ratingSystemXmlUriSet.add(TvContentRating.SYSTEM_CONTENT_RATING_SYSTEM_XML);
2875c5b83fcd58d21c9ab7ac986bf84f604ec5bb4b5Sungsoo Lim        for (TvInputState state : userState.inputMap.values()) {
2885c5b83fcd58d21c9ab7ac986bf84f604ec5bb4b5Sungsoo Lim            Uri ratingSystemXmlUri = state.mInfo.getRatingSystemXmlUri();
2895c5b83fcd58d21c9ab7ac986bf84f604ec5bb4b5Sungsoo Lim            if (ratingSystemXmlUri != null) {
2905c5b83fcd58d21c9ab7ac986bf84f604ec5bb4b5Sungsoo Lim                // TODO: need to check the validation of xml format and the duplication of rating
2915c5b83fcd58d21c9ab7ac986bf84f604ec5bb4b5Sungsoo Lim                // systems.
2925c5b83fcd58d21c9ab7ac986bf84f604ec5bb4b5Sungsoo Lim                userState.ratingSystemXmlUriSet.add(state.mInfo.getRatingSystemXmlUri());
2935c5b83fcd58d21c9ab7ac986bf84f604ec5bb4b5Sungsoo Lim            }
2945c5b83fcd58d21c9ab7ac986bf84f604ec5bb4b5Sungsoo Lim        }
2953957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    }
2963957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
2973957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    private void switchUser(int userId) {
2983957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        synchronized (mLock) {
2993957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            if (mCurrentUserId == userId) {
3003957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                return;
3013957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            }
3023957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            // final int oldUserId = mCurrentUserId;
3033957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            // TODO: Release services and sessions in the old user state, if needed.
3043957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            mCurrentUserId = userId;
3053957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
3063957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            UserState userState = mUserStates.get(userId);
3073957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            if (userState == null) {
308783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                userState = new UserState(mContext, userId);
3093957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            }
3103957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            mUserStates.put(userId, userState);
3113957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            buildTvInputListLocked(userId);
3123957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
3133957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    }
3143957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
3153957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    private void removeUser(int userId) {
3163957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        synchronized (mLock) {
317b06cb8870f0407f18bb1225065a93aba2a5de2bfJae Seo            UserState userState = mUserStates.get(userId);
318b06cb8870f0407f18bb1225065a93aba2a5de2bfJae Seo            if (userState == null) {
319b06cb8870f0407f18bb1225065a93aba2a5de2bfJae Seo                return;
320b06cb8870f0407f18bb1225065a93aba2a5de2bfJae Seo            }
3213957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            // Release created sessions.
3223957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            for (SessionState state : userState.sessionStateMap.values()) {
323d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim                if (state.mSession != null) {
3243957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    try {
325d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim                        state.mSession.release();
3263957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    } catch (RemoteException e) {
3279a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                        Slog.e(TAG, "error in release", e);
3283957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    }
3293957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                }
3303957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            }
3313957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            userState.sessionStateMap.clear();
3323957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
3333957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            // Unregister all callbacks and unbind all services.
3343957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            for (ServiceState serviceState : userState.serviceStateMap.values()) {
335d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim                if (serviceState.mCallback != null) {
3363957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    try {
337d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim                        serviceState.mService.unregisterCallback(serviceState.mCallback);
3383957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    } catch (RemoteException e) {
3399a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                        Slog.e(TAG, "error in unregisterCallback", e);
3403957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    }
3413957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                }
342d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim                mContext.unbindService(serviceState.mConnection);
3433957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            }
3443957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            userState.serviceStateMap.clear();
3453957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
34672ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim            userState.clientStateMap.clear();
34772ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim
3483957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            mUserStates.remove(userId);
3493957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
3503957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    }
3513957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
3523957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    private UserState getUserStateLocked(int userId) {
3533957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        UserState userState = mUserStates.get(userId);
3543957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        if (userState == null) {
3553957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            throw new IllegalStateException("User state not found for user ID " + userId);
3563957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
3573957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        return userState;
3583957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    }
3593957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
3609e8ade2eb7ee835963473c9cf6faaf5423b0b048Ji-Hwan Lee    private ServiceState getServiceStateLocked(ComponentName component, int userId) {
3613957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        UserState userState = getUserStateLocked(userId);
3629e8ade2eb7ee835963473c9cf6faaf5423b0b048Ji-Hwan Lee        ServiceState serviceState = userState.serviceStateMap.get(component);
3633957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        if (serviceState == null) {
3649e8ade2eb7ee835963473c9cf6faaf5423b0b048Ji-Hwan Lee            throw new IllegalStateException("Service state not found for " + component + " (userId="
3657de5e234715a3baa8905afa3dd0c5009af64541fSungsoo Lim                    + userId + ")");
3663957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
3673957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        return serviceState;
3683957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    }
3693957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
3702b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim    private SessionState getSessionStateLocked(IBinder sessionToken, int callingUid, int userId) {
3713957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        UserState userState = getUserStateLocked(userId);
3723957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        SessionState sessionState = userState.sessionStateMap.get(sessionToken);
3733957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        if (sessionState == null) {
3743957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            throw new IllegalArgumentException("Session state not found for token " + sessionToken);
3753957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
3763957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        // Only the application that requested this session or the system can access it.
377d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim        if (callingUid != Process.SYSTEM_UID && callingUid != sessionState.mCallingUid) {
3783957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            throw new SecurityException("Illegal access to the session with token " + sessionToken
3793957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    + " from uid " + callingUid);
3803957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
3812b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim        return sessionState;
3822b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim    }
3832b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim
3842b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim    private ITvInputSession getSessionLocked(IBinder sessionToken, int callingUid, int userId) {
3854c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee        return getSessionLocked(getSessionStateLocked(sessionToken, callingUid, userId));
3864c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee    }
3874c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee
3884c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee    private ITvInputSession getSessionLocked(SessionState sessionState) {
389d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim        ITvInputSession session = sessionState.mSession;
3903957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        if (session == null) {
3914c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee            throw new IllegalStateException("Session not yet created for token "
3924c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee                    + sessionState.mSessionToken);
3933957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
3943957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        return session;
3953957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    }
3963957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
3973957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    private int resolveCallingUserId(int callingPid, int callingUid, int requestedUserId,
3983957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            String methodName) {
3993957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        return ActivityManager.handleIncomingUser(callingPid, callingUid, requestedUserId, false,
4003957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                false, methodName, null);
4013957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    }
4023957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
403187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim    private static boolean shouldMaintainConnection(ServiceState serviceState) {
4049cc28e5175e1391646b29469d329c9c1c9311ee1Jae Seo        return !serviceState.mSessionTokens.isEmpty() || serviceState.mIsHardware;
405187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim        // TODO: Find a way to maintain connection only when necessary.
406187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim    }
407187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim
4089e8ade2eb7ee835963473c9cf6faaf5423b0b048Ji-Hwan Lee    private void updateServiceConnectionLocked(ComponentName component, int userId) {
4093957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        UserState userState = getUserStateLocked(userId);
4109e8ade2eb7ee835963473c9cf6faaf5423b0b048Ji-Hwan Lee        ServiceState serviceState = userState.serviceStateMap.get(component);
4113957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        if (serviceState == null) {
4123957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            return;
4133957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
4142b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim        if (serviceState.mReconnecting) {
4152b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim            if (!serviceState.mSessionTokens.isEmpty()) {
4162b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                // wait until all the sessions are removed.
4172b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                return;
4182b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim            }
4192b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim            serviceState.mReconnecting = false;
4202b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim        }
421187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim        boolean maintainConnection = shouldMaintainConnection(serviceState);
422187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim        if (serviceState.mService == null && maintainConnection && userId == mCurrentUserId) {
4233957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            // This means that the service is not yet connected but its state indicates that we
4243957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            // have pending requests. Then, connect the service.
425d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim            if (serviceState.mBound) {
4263957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                // We have already bound to the service so we don't try to bind again until after we
4273957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                // unbind later on.
4283957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                return;
4293957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            }
4303957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            if (DEBUG) {
4319e8ade2eb7ee835963473c9cf6faaf5423b0b048Ji-Hwan Lee                Slog.d(TAG, "bindServiceAsUser(service=" + component + ", userId=" + userId + ")");
4323957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            }
433d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim
4349e8ade2eb7ee835963473c9cf6faaf5423b0b048Ji-Hwan Lee            Intent i = new Intent(TvInputService.SERVICE_INTERFACE).setComponent(component);
435226a51958d645a8e2be3e40a6b6daaca558b4913Jaewan Kim            // Binding service may fail if the service is updating.
436226a51958d645a8e2be3e40a6b6daaca558b4913Jaewan Kim            // In that case, the connection will be revived in buildTvInputListLocked called by
437226a51958d645a8e2be3e40a6b6daaca558b4913Jaewan Kim            // onSomePackagesChanged.
438e17b2dd7bcc137bf4d842a779e8d62c63957a978Ji-Hwan Lee            serviceState.mBound = mContext.bindServiceAsUser(
439e17b2dd7bcc137bf4d842a779e8d62c63957a978Ji-Hwan Lee                    i, serviceState.mConnection, Context.BIND_AUTO_CREATE, new UserHandle(userId));
440187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim        } else if (serviceState.mService != null && !maintainConnection) {
4413957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            // This means that the service is already connected but its state indicates that we have
4423957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            // nothing to do with it. Then, disconnect the service.
4433957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            if (DEBUG) {
4449e8ade2eb7ee835963473c9cf6faaf5423b0b048Ji-Hwan Lee                Slog.d(TAG, "unbindService(service=" + component + ")");
4453957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            }
446d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim            mContext.unbindService(serviceState.mConnection);
4479e8ade2eb7ee835963473c9cf6faaf5423b0b048Ji-Hwan Lee            userState.serviceStateMap.remove(component);
4483957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
4493957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    }
4503957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
45172ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim    private ClientState createClientStateLocked(IBinder clientToken, int userId) {
45272ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim        UserState userState = getUserStateLocked(userId);
45372ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim        ClientState clientState = new ClientState(clientToken, userId);
45472ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim        try {
45572ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim            clientToken.linkToDeath(clientState, 0);
45672ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim        } catch (RemoteException e) {
45772ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim            Slog.e(TAG, "Client is already died.");
45872ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim        }
45972ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim        userState.clientStateMap.put(clientToken, clientState);
46072ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim        return clientState;
46172ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim    }
46272ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim
4633957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    private void createSessionInternalLocked(ITvInputService service, final IBinder sessionToken,
4647de5e234715a3baa8905afa3dd0c5009af64541fSungsoo Lim            final int userId) {
46572ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim        final UserState userState = getUserStateLocked(userId);
46672ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim        final SessionState sessionState = userState.sessionStateMap.get(sessionToken);
4673957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        if (DEBUG) {
468187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim            Slog.d(TAG, "createSessionInternalLocked(inputId=" + sessionState.mInfo.getId() + ")");
4693957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
4706a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo
4716a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo        final InputChannel[] channels = InputChannel.openInputChannelPair(sessionToken.toString());
4726a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo
4733957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        // Set up a callback to send the session token.
4743957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        ITvInputSessionCallback callback = new ITvInputSessionCallback.Stub() {
4753957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            @Override
476bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang            public void onSessionCreated(ITvInputSession session, IBinder harewareSessionToken) {
4773957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                if (DEBUG) {
478187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                    Slog.d(TAG, "onSessionCreated(inputId=" + sessionState.mInfo.getId() + ")");
4793957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                }
4803957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                synchronized (mLock) {
481d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim                    sessionState.mSession = session;
482bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                    sessionState.mHardwareSessionToken = harewareSessionToken;
483fd5b72f1ed2ee74a4204eef65f560fc82f0b62feDongwon Kang                    if (session == null) {
484fd5b72f1ed2ee74a4204eef65f560fc82f0b62feDongwon Kang                        removeSessionStateLocked(sessionToken, userId);
485187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                        sendSessionTokenToClientLocked(sessionState.mClient,
486187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                                sessionState.mInfo.getId(), null, null, sessionState.mSeq);
487fd5b72f1ed2ee74a4204eef65f560fc82f0b62feDongwon Kang                    } else {
4882b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                        try {
4892b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                            session.asBinder().linkToDeath(sessionState, 0);
4902b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                        } catch (RemoteException e) {
4912b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                            Slog.e(TAG, "Session is already died.");
4922b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                        }
49372ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim
49472ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim                        IBinder clientToken = sessionState.mClient.asBinder();
49572ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim                        ClientState clientState = userState.clientStateMap.get(clientToken);
49672ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim                        if (clientState == null) {
49772ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim                            clientState = createClientStateLocked(clientToken, userId);
49872ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim                        }
49972ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim                        clientState.mSessionTokens.add(sessionState.mSessionToken);
50072ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim
501187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                        sendSessionTokenToClientLocked(sessionState.mClient,
502187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                                sessionState.mInfo.getId(), sessionToken, channels[0],
503187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                                sessionState.mSeq);
504fd5b72f1ed2ee74a4204eef65f560fc82f0b62feDongwon Kang                    }
5056a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                    channels[0].dispose();
5063957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                }
5073957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            }
508832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho
509832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho            @Override
5101f213914c45c23c653f721690da2ce0718e63139Dongwon Kang            public void onChannelRetuned(Uri channelUri) {
511a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang                synchronized (mLock) {
512a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang                    if (DEBUG) {
5131f213914c45c23c653f721690da2ce0718e63139Dongwon Kang                        Slog.d(TAG, "onChannelRetuned(" + channelUri + ")");
514a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang                    }
515a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang                    if (sessionState.mSession == null || sessionState.mClient == null) {
516a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang                        return;
517a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang                    }
518a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang                    try {
5191f213914c45c23c653f721690da2ce0718e63139Dongwon Kang                        // TODO: Consider adding this channel change in the watch log. When we do
5201f213914c45c23c653f721690da2ce0718e63139Dongwon Kang                        // that, how we can protect the watch log from malicious tv inputs should
5211f213914c45c23c653f721690da2ce0718e63139Dongwon Kang                        // be addressed. e.g. add a field which represents where the channel change
5221f213914c45c23c653f721690da2ce0718e63139Dongwon Kang                        // originated from.
5231f213914c45c23c653f721690da2ce0718e63139Dongwon Kang                        sessionState.mClient.onChannelRetuned(channelUri, sessionState.mSeq);
524a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang                    } catch (RemoteException e) {
5251f213914c45c23c653f721690da2ce0718e63139Dongwon Kang                        Slog.e(TAG, "error in onChannelRetuned");
526a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang                    }
527a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang                }
528a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang            }
529a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang
530a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang            @Override
53110d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo            public void onTracksChanged(List<TvTrackInfo> tracks) {
532a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang                synchronized (mLock) {
533a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang                    if (DEBUG) {
53410d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo                        Slog.d(TAG, "onTracksChanged(" + tracks + ")");
535a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang                    }
536a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang                    if (sessionState.mSession == null || sessionState.mClient == null) {
537a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang                        return;
538a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang                    }
539a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang                    try {
54010d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo                        sessionState.mClient.onTracksChanged(tracks, sessionState.mSeq);
541a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang                    } catch (RemoteException e) {
54210d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo                        Slog.e(TAG, "error in onTracksChanged");
543b93ccca6139a7ee2dba5c110e5f8213a2bd231e5Dongwon Kang                    }
544b93ccca6139a7ee2dba5c110e5f8213a2bd231e5Dongwon Kang                }
545b93ccca6139a7ee2dba5c110e5f8213a2bd231e5Dongwon Kang            }
546b93ccca6139a7ee2dba5c110e5f8213a2bd231e5Dongwon Kang
547b93ccca6139a7ee2dba5c110e5f8213a2bd231e5Dongwon Kang            @Override
54810d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo            public void onTrackSelected(int type, String trackId) {
549d5ce9759524740cfb02638fd1d7b44315957b422Jae Seo                synchronized (mLock) {
550d5ce9759524740cfb02638fd1d7b44315957b422Jae Seo                    if (DEBUG) {
55110d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo                        Slog.d(TAG, "onTrackSelected(type=" + type + ", trackId=" + trackId + ")");
552d5ce9759524740cfb02638fd1d7b44315957b422Jae Seo                    }
553d5ce9759524740cfb02638fd1d7b44315957b422Jae Seo                    if (sessionState.mSession == null || sessionState.mClient == null) {
554d5ce9759524740cfb02638fd1d7b44315957b422Jae Seo                        return;
555d5ce9759524740cfb02638fd1d7b44315957b422Jae Seo                    }
556d5ce9759524740cfb02638fd1d7b44315957b422Jae Seo                    try {
55710d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo                        sessionState.mClient.onTrackSelected(type, trackId, sessionState.mSeq);
558d5ce9759524740cfb02638fd1d7b44315957b422Jae Seo                    } catch (RemoteException e) {
55910d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo                        Slog.e(TAG, "error in onTrackSelected");
560d5ce9759524740cfb02638fd1d7b44315957b422Jae Seo                    }
561d5ce9759524740cfb02638fd1d7b44315957b422Jae Seo                }
562d5ce9759524740cfb02638fd1d7b44315957b422Jae Seo            }
563d5ce9759524740cfb02638fd1d7b44315957b422Jae Seo
564d5ce9759524740cfb02638fd1d7b44315957b422Jae Seo            @Override
5659b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang            public void onVideoAvailable() {
5669b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                synchronized (mLock) {
5679b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                    if (DEBUG) {
5689b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                        Slog.d(TAG, "onVideoAvailable()");
5699b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                    }
5709b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                    if (sessionState.mSession == null || sessionState.mClient == null) {
5719b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                        return;
5729b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                    }
5739b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                    try {
5749b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                        sessionState.mClient.onVideoAvailable(sessionState.mSeq);
5759b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                    } catch (RemoteException e) {
5769b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                        Slog.e(TAG, "error in onVideoAvailable");
5779b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                    }
5789b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                }
5799b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang            }
5809b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang
5819b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang            @Override
5829b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang            public void onVideoUnavailable(int reason) {
5839b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                synchronized (mLock) {
5849b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                    if (DEBUG) {
5859b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                        Slog.d(TAG, "onVideoUnavailable(" + reason + ")");
5869b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                    }
5879b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                    if (sessionState.mSession == null || sessionState.mClient == null) {
5889b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                        return;
5899b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                    }
5909b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                    try {
5919b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                        sessionState.mClient.onVideoUnavailable(reason, sessionState.mSeq);
5929b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                    } catch (RemoteException e) {
5939b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                        Slog.e(TAG, "error in onVideoUnavailable");
5949b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                    }
5959b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang                }
5969b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang            }
5979b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang
5989b08edff236fc68d836eccfaa1a5f028dc390cecDongwon Kang            @Override
599bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo            public void onContentAllowed() {
600bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo                synchronized (mLock) {
601bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo                    if (DEBUG) {
602bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo                        Slog.d(TAG, "onContentAllowed()");
603bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo                    }
604bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo                    if (sessionState.mSession == null || sessionState.mClient == null) {
605bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo                        return;
606bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo                    }
607bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo                    try {
608bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo                        sessionState.mClient.onContentAllowed(sessionState.mSeq);
609bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo                    } catch (RemoteException e) {
610bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo                        Slog.e(TAG, "error in onContentAllowed");
611bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo                    }
612bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo                }
613bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo            }
614bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo
615bbcd206a798c8c2845200daf7a2d4cb7b29056f3Jae Seo            @Override
6166057102dbb746593a7d59cf377c969b62e38c664Jae Seo            public void onContentBlocked(String rating) {
6176057102dbb746593a7d59cf377c969b62e38c664Jae Seo                synchronized (mLock) {
6186057102dbb746593a7d59cf377c969b62e38c664Jae Seo                    if (DEBUG) {
6196057102dbb746593a7d59cf377c969b62e38c664Jae Seo                        Slog.d(TAG, "onContentBlocked()");
6206057102dbb746593a7d59cf377c969b62e38c664Jae Seo                    }
6216057102dbb746593a7d59cf377c969b62e38c664Jae Seo                    if (sessionState.mSession == null || sessionState.mClient == null) {
6226057102dbb746593a7d59cf377c969b62e38c664Jae Seo                        return;
6236057102dbb746593a7d59cf377c969b62e38c664Jae Seo                    }
6246057102dbb746593a7d59cf377c969b62e38c664Jae Seo                    try {
6256057102dbb746593a7d59cf377c969b62e38c664Jae Seo                        sessionState.mClient.onContentBlocked(rating, sessionState.mSeq);
6266057102dbb746593a7d59cf377c969b62e38c664Jae Seo                    } catch (RemoteException e) {
6276057102dbb746593a7d59cf377c969b62e38c664Jae Seo                        Slog.e(TAG, "error in onContentBlocked");
6286057102dbb746593a7d59cf377c969b62e38c664Jae Seo                    }
6296057102dbb746593a7d59cf377c969b62e38c664Jae Seo                }
6306057102dbb746593a7d59cf377c969b62e38c664Jae Seo            }
6316057102dbb746593a7d59cf377c969b62e38c664Jae Seo
6326057102dbb746593a7d59cf377c969b62e38c664Jae Seo            @Override
633ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho            public void onLayoutSurface(int left, int top, int right, int bottom) {
634ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho                synchronized (mLock) {
635ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho                    if (DEBUG) {
636ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho                        Slog.d(TAG, "onLayoutSurface (left=" + left + ", top=" + top
637ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho                                + ", right=" + right + ", bottom=" + bottom + ",)");
638ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho                    }
639ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho                    if (sessionState.mSession == null || sessionState.mClient == null) {
640ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho                        return;
641ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho                    }
642ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho                    try {
643ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho                        sessionState.mClient.onLayoutSurface(left, top, right, bottom,
644ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho                                sessionState.mSeq);
645ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho                    } catch (RemoteException e) {
646ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho                        Slog.e(TAG, "error in onLayoutSurface");
647ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho                    }
648ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho                }
649ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho            }
650ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho
651ff04ae757a5542d2d5633e75b7adacc4fce1ce7eYoungsang Cho            @Override
652832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho            public void onSessionEvent(String eventType, Bundle eventArgs) {
653832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho                synchronized (mLock) {
654832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho                    if (DEBUG) {
655832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho                        Slog.d(TAG, "onEvent(what=" + eventType + ", data=" + eventArgs + ")");
656832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho                    }
657832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho                    if (sessionState.mSession == null || sessionState.mClient == null) {
658832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho                        return;
659832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho                    }
660832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho                    try {
661832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho                        sessionState.mClient.onSessionEvent(eventType, eventArgs,
662832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho                                sessionState.mSeq);
663832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho                    } catch (RemoteException e) {
664832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho                        Slog.e(TAG, "error in onSessionEvent");
665832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho                    }
666832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho                }
667832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho            }
6683957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        };
6693957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
6703957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        // Create a session. When failed, send a null token immediately.
6713957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        try {
672187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim            service.createSession(channels[1], callback, sessionState.mInfo.getId());
6733957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        } catch (RemoteException e) {
6749a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            Slog.e(TAG, "error in createSession", e);
675fd5b72f1ed2ee74a4204eef65f560fc82f0b62feDongwon Kang            removeSessionStateLocked(sessionToken, userId);
676187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim            sendSessionTokenToClientLocked(sessionState.mClient, sessionState.mInfo.getId(), null,
677187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                    null, sessionState.mSeq);
6783957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
6796a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo        channels[1].dispose();
6803957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    }
6813957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
682d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim    private void sendSessionTokenToClientLocked(ITvInputClient client, String inputId,
6835c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo            IBinder sessionToken, InputChannel channel, int seq) {
6843957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        try {
685d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim            client.onSessionCreated(inputId, sessionToken, channel, seq);
6863957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        } catch (RemoteException exception) {
6879a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            Slog.e(TAG, "error in onSessionCreated", exception);
6883957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
6892b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim    }
6903957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
6912b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim    private void releaseSessionLocked(IBinder sessionToken, int callingUid, int userId) {
6922b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim        SessionState sessionState = getSessionStateLocked(sessionToken, callingUid, userId);
6932b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim        if (sessionState.mSession != null) {
69415c56aac985bc8d75f38fb4ecb92dda12d2ca06cJi-Hwan Lee            UserState userState = getUserStateLocked(userId);
69515c56aac985bc8d75f38fb4ecb92dda12d2ca06cJi-Hwan Lee            if (sessionToken == userState.mainSessionToken) {
69615c56aac985bc8d75f38fb4ecb92dda12d2ca06cJi-Hwan Lee                setMainLocked(sessionToken, false, callingUid, userId);
69715c56aac985bc8d75f38fb4ecb92dda12d2ca06cJi-Hwan Lee            }
6982b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim            try {
6992b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                sessionState.mSession.release();
7002b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim            } catch (RemoteException e) {
7012b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                Slog.w(TAG, "session is already disapeared", e);
7022b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim            }
7032b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim            sessionState.mSession = null;
7043957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
7052b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim        removeSessionStateLocked(sessionToken, userId);
7063957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    }
7073957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
708fd5b72f1ed2ee74a4204eef65f560fc82f0b62feDongwon Kang    private void removeSessionStateLocked(IBinder sessionToken, int userId) {
709fd5b72f1ed2ee74a4204eef65f560fc82f0b62feDongwon Kang        UserState userState = getUserStateLocked(userId);
710abca0ee7949f59e72b8d2764dafa23af18eb51dbJi-Hwan Lee        if (sessionToken == userState.mainSessionToken) {
71115c56aac985bc8d75f38fb4ecb92dda12d2ca06cJi-Hwan Lee            if (DEBUG) {
71215c56aac985bc8d75f38fb4ecb92dda12d2ca06cJi-Hwan Lee                Slog.d(TAG, "mainSessionToken=null");
71315c56aac985bc8d75f38fb4ecb92dda12d2ca06cJi-Hwan Lee            }
714abca0ee7949f59e72b8d2764dafa23af18eb51dbJi-Hwan Lee            userState.mainSessionToken = null;
715abca0ee7949f59e72b8d2764dafa23af18eb51dbJi-Hwan Lee        }
716abca0ee7949f59e72b8d2764dafa23af18eb51dbJi-Hwan Lee
717abca0ee7949f59e72b8d2764dafa23af18eb51dbJi-Hwan Lee        // Remove the session state from the global session state map of the current user.
718fd5b72f1ed2ee74a4204eef65f560fc82f0b62feDongwon Kang        SessionState sessionState = userState.sessionStateMap.remove(sessionToken);
719fd5b72f1ed2ee74a4204eef65f560fc82f0b62feDongwon Kang
7208d4ded0058de5c573ccf79c4596bf5eb1b14fad3Chulwoo Lee        if (sessionState == null) {
7218d4ded0058de5c573ccf79c4596bf5eb1b14fad3Chulwoo Lee            return;
7228d4ded0058de5c573ccf79c4596bf5eb1b14fad3Chulwoo Lee        }
7238d4ded0058de5c573ccf79c4596bf5eb1b14fad3Chulwoo Lee
72472ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim        // Also remove the session token from the session token list of the current client and
72572ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim        // service.
72672ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim        ClientState clientState = userState.clientStateMap.get(sessionState.mClient.asBinder());
72772ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim        if (clientState != null) {
72872ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim            clientState.mSessionTokens.remove(sessionToken);
72972ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim            if (clientState.isEmpty()) {
73072ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim                userState.clientStateMap.remove(sessionState.mClient.asBinder());
73172ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim            }
73272ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim        }
73372ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim
734187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim        TvInputInfo info = sessionState.mInfo;
735187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim        if (info != null) {
736187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim            ServiceState serviceState = userState.serviceStateMap.get(info.getComponent());
737187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim            if (serviceState != null) {
738187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                serviceState.mSessionTokens.remove(sessionToken);
739187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim            }
740fd5b72f1ed2ee74a4204eef65f560fc82f0b62feDongwon Kang        }
741187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim        updateServiceConnectionLocked(sessionState.mInfo.getComponent(), userId);
7427eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo
7437eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo        // Log the end of watch.
7447eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo        SomeArgs args = SomeArgs.obtain();
7457eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo        args.arg1 = sessionToken;
7467eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo        args.arg2 = System.currentTimeMillis();
7477eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo        mWatchLogHandler.obtainMessage(WatchLogHandler.MSG_LOG_WATCH_END, args).sendToTarget();
748fd5b72f1ed2ee74a4204eef65f560fc82f0b62feDongwon Kang    }
749fd5b72f1ed2ee74a4204eef65f560fc82f0b62feDongwon Kang
75015c56aac985bc8d75f38fb4ecb92dda12d2ca06cJi-Hwan Lee    private void setMainLocked(IBinder sessionToken, boolean isMain, int callingUid, int userId) {
75115c56aac985bc8d75f38fb4ecb92dda12d2ca06cJi-Hwan Lee        SessionState sessionState = getSessionStateLocked(sessionToken, callingUid, userId);
75215c56aac985bc8d75f38fb4ecb92dda12d2ca06cJi-Hwan Lee        if (sessionState.mHardwareSessionToken != null) {
75315c56aac985bc8d75f38fb4ecb92dda12d2ca06cJi-Hwan Lee            sessionState = getSessionStateLocked(sessionState.mHardwareSessionToken,
75415c56aac985bc8d75f38fb4ecb92dda12d2ca06cJi-Hwan Lee                    Process.SYSTEM_UID, userId);
75515c56aac985bc8d75f38fb4ecb92dda12d2ca06cJi-Hwan Lee        }
75615c56aac985bc8d75f38fb4ecb92dda12d2ca06cJi-Hwan Lee        ServiceState serviceState = getServiceStateLocked(sessionState.mInfo.getComponent(),
75715c56aac985bc8d75f38fb4ecb92dda12d2ca06cJi-Hwan Lee                userId);
75815c56aac985bc8d75f38fb4ecb92dda12d2ca06cJi-Hwan Lee        if (!serviceState.mIsHardware) {
75915c56aac985bc8d75f38fb4ecb92dda12d2ca06cJi-Hwan Lee            return;
76015c56aac985bc8d75f38fb4ecb92dda12d2ca06cJi-Hwan Lee        }
76115c56aac985bc8d75f38fb4ecb92dda12d2ca06cJi-Hwan Lee        ITvInputSession session = getSessionLocked(sessionState);
76215c56aac985bc8d75f38fb4ecb92dda12d2ca06cJi-Hwan Lee        try {
76315c56aac985bc8d75f38fb4ecb92dda12d2ca06cJi-Hwan Lee            session.setMain(isMain);
76415c56aac985bc8d75f38fb4ecb92dda12d2ca06cJi-Hwan Lee        } catch (RemoteException e) {
76515c56aac985bc8d75f38fb4ecb92dda12d2ca06cJi-Hwan Lee            Slog.e(TAG, "error in setMain", e);
76615c56aac985bc8d75f38fb4ecb92dda12d2ca06cJi-Hwan Lee        }
76715c56aac985bc8d75f38fb4ecb92dda12d2ca06cJi-Hwan Lee    }
76815c56aac985bc8d75f38fb4ecb92dda12d2ca06cJi-Hwan Lee
7698e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim    private void notifyInputAddedLocked(UserState userState, String inputId) {
7708e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim        if (DEBUG) {
7718e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim            Slog.d(TAG, "notifyInputAdded: inputId = " + inputId);
7728e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim        }
7738e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim        for (ITvInputManagerCallback callback : userState.callbackSet) {
7748e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim            try {
7758e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim                callback.onInputAdded(inputId);
7768e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim            } catch (RemoteException e) {
7778e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim                Slog.e(TAG, "Failed to report added input to callback.");
7788e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim            }
7798e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim        }
7808e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim    }
7818e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim
7828e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim    private void notifyInputRemovedLocked(UserState userState, String inputId) {
7838e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim        if (DEBUG) {
7848e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim            Slog.d(TAG, "notifyInputRemovedLocked: inputId = " + inputId);
7858e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim        }
7868e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim        for (ITvInputManagerCallback callback : userState.callbackSet) {
7878e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim            try {
7888e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim                callback.onInputRemoved(inputId);
7898e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim            } catch (RemoteException e) {
7908e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim                Slog.e(TAG, "Failed to report removed input to callback.");
7918e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim            }
7928e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim        }
7938e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim    }
7948e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim
7958e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim    private void notifyInputStateChangedLocked(UserState userState, String inputId,
796969167dc05a6485a32d160895871cff46fd81884Wonsik Kim            int state, ITvInputManagerCallback targetCallback) {
797969167dc05a6485a32d160895871cff46fd81884Wonsik Kim        if (DEBUG) {
7988e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim            Slog.d(TAG, "notifyInputStateChangedLocked: inputId = " + inputId
799969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                    + "; state = " + state);
800969167dc05a6485a32d160895871cff46fd81884Wonsik Kim        }
801969167dc05a6485a32d160895871cff46fd81884Wonsik Kim        if (targetCallback == null) {
802969167dc05a6485a32d160895871cff46fd81884Wonsik Kim            for (ITvInputManagerCallback callback : userState.callbackSet) {
803969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                try {
804969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                    callback.onInputStateChanged(inputId, state);
805969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                } catch (RemoteException e) {
806969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                    Slog.e(TAG, "Failed to report state change to callback.");
807969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                }
808969167dc05a6485a32d160895871cff46fd81884Wonsik Kim            }
809969167dc05a6485a32d160895871cff46fd81884Wonsik Kim        } else {
8102b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim            try {
811969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                targetCallback.onInputStateChanged(inputId, state);
8122b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim            } catch (RemoteException e) {
813969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                Slog.e(TAG, "Failed to report state change to callback.");
8142b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim            }
8152b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim        }
8162b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim    }
8172b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim
818969167dc05a6485a32d160895871cff46fd81884Wonsik Kim    private void setStateLocked(String inputId, int state, int userId) {
819969167dc05a6485a32d160895871cff46fd81884Wonsik Kim        UserState userState = getUserStateLocked(userId);
820969167dc05a6485a32d160895871cff46fd81884Wonsik Kim        TvInputState inputState = userState.inputMap.get(inputId);
821c88f1916b8ab7f5f75a00375c6fb4873ea5044afJi-Hwan Lee        ServiceState serviceState = userState.serviceStateMap.get(inputState.mInfo.getComponent());
822969167dc05a6485a32d160895871cff46fd81884Wonsik Kim        int oldState = inputState.mState;
823969167dc05a6485a32d160895871cff46fd81884Wonsik Kim        inputState.mState = state;
824187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim        if (serviceState != null && serviceState.mService == null
825187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                && shouldMaintainConnection(serviceState)) {
826969167dc05a6485a32d160895871cff46fd81884Wonsik Kim            // We don't notify state change while reconnecting. It should remain disconnected.
827969167dc05a6485a32d160895871cff46fd81884Wonsik Kim            return;
828969167dc05a6485a32d160895871cff46fd81884Wonsik Kim        }
829969167dc05a6485a32d160895871cff46fd81884Wonsik Kim        if (oldState != state) {
8308e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim            notifyInputStateChangedLocked(userState, inputId, state, null);
831969167dc05a6485a32d160895871cff46fd81884Wonsik Kim        }
832969167dc05a6485a32d160895871cff46fd81884Wonsik Kim    }
833969167dc05a6485a32d160895871cff46fd81884Wonsik Kim
8343957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    private final class BinderService extends ITvInputManager.Stub {
8353957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        @Override
8363957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        public List<TvInputInfo> getTvInputList(int userId) {
8373957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(),
8383957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    Binder.getCallingUid(), userId, "getTvInputList");
8393957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            final long identity = Binder.clearCallingIdentity();
8403957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            try {
8413957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                synchronized (mLock) {
8423957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    UserState userState = getUserStateLocked(resolvedUserId);
843969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                    List<TvInputInfo> inputList = new ArrayList<TvInputInfo>();
844969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                    for (TvInputState state : userState.inputMap.values()) {
845969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                        inputList.add(state.mInfo);
8463957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    }
847969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                    return inputList;
8483957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                }
8493957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            } finally {
8503957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                Binder.restoreCallingIdentity(identity);
8513957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            }
852b375805f3b1672e68d1511565af4700e5fa8491dJae Seo        }
853b375805f3b1672e68d1511565af4700e5fa8491dJae Seo
854b375805f3b1672e68d1511565af4700e5fa8491dJae Seo        @Override
855b375805f3b1672e68d1511565af4700e5fa8491dJae Seo        public TvInputInfo getTvInputInfo(String inputId, int userId) {
856b375805f3b1672e68d1511565af4700e5fa8491dJae Seo            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(),
857b375805f3b1672e68d1511565af4700e5fa8491dJae Seo                    Binder.getCallingUid(), userId, "getTvInputInfo");
858b375805f3b1672e68d1511565af4700e5fa8491dJae Seo            final long identity = Binder.clearCallingIdentity();
859b375805f3b1672e68d1511565af4700e5fa8491dJae Seo            try {
860b375805f3b1672e68d1511565af4700e5fa8491dJae Seo                synchronized (mLock) {
861b375805f3b1672e68d1511565af4700e5fa8491dJae Seo                    UserState userState = getUserStateLocked(resolvedUserId);
862b375805f3b1672e68d1511565af4700e5fa8491dJae Seo                    TvInputState state = userState.inputMap.get(inputId);
863b375805f3b1672e68d1511565af4700e5fa8491dJae Seo                    return state == null ? null : state.mInfo;
864b375805f3b1672e68d1511565af4700e5fa8491dJae Seo                }
865b375805f3b1672e68d1511565af4700e5fa8491dJae Seo            } finally {
866b375805f3b1672e68d1511565af4700e5fa8491dJae Seo                Binder.restoreCallingIdentity(identity);
867b375805f3b1672e68d1511565af4700e5fa8491dJae Seo            }
8683957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
8693957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
8703957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        @Override
8715c5b83fcd58d21c9ab7ac986bf84f604ec5bb4b5Sungsoo Lim        public List<Uri> getTvContentRatingSystemXmls(int userId) {
8725c5b83fcd58d21c9ab7ac986bf84f604ec5bb4b5Sungsoo Lim            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(),
8735c5b83fcd58d21c9ab7ac986bf84f604ec5bb4b5Sungsoo Lim                    Binder.getCallingUid(), userId, "getTvContentRatingSystemXmls");
8745c5b83fcd58d21c9ab7ac986bf84f604ec5bb4b5Sungsoo Lim            final long identity = Binder.clearCallingIdentity();
8755c5b83fcd58d21c9ab7ac986bf84f604ec5bb4b5Sungsoo Lim            try {
8765c5b83fcd58d21c9ab7ac986bf84f604ec5bb4b5Sungsoo Lim                synchronized (mLock) {
8775c5b83fcd58d21c9ab7ac986bf84f604ec5bb4b5Sungsoo Lim                    UserState userState = getUserStateLocked(resolvedUserId);
8785c5b83fcd58d21c9ab7ac986bf84f604ec5bb4b5Sungsoo Lim                    List<Uri> ratingSystemXmlUriList = new ArrayList<Uri>();
8795c5b83fcd58d21c9ab7ac986bf84f604ec5bb4b5Sungsoo Lim                    ratingSystemXmlUriList.addAll(userState.ratingSystemXmlUriSet);
8805c5b83fcd58d21c9ab7ac986bf84f604ec5bb4b5Sungsoo Lim                    return ratingSystemXmlUriList;
8815c5b83fcd58d21c9ab7ac986bf84f604ec5bb4b5Sungsoo Lim                }
8825c5b83fcd58d21c9ab7ac986bf84f604ec5bb4b5Sungsoo Lim            } finally {
8835c5b83fcd58d21c9ab7ac986bf84f604ec5bb4b5Sungsoo Lim                Binder.restoreCallingIdentity(identity);
8845c5b83fcd58d21c9ab7ac986bf84f604ec5bb4b5Sungsoo Lim            }
8855c5b83fcd58d21c9ab7ac986bf84f604ec5bb4b5Sungsoo Lim        }
8865c5b83fcd58d21c9ab7ac986bf84f604ec5bb4b5Sungsoo Lim
8875c5b83fcd58d21c9ab7ac986bf84f604ec5bb4b5Sungsoo Lim        @Override
888969167dc05a6485a32d160895871cff46fd81884Wonsik Kim        public void registerCallback(final ITvInputManagerCallback callback, int userId) {
8893957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(),
8903957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    Binder.getCallingUid(), userId, "registerCallback");
8913957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            final long identity = Binder.clearCallingIdentity();
8923957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            try {
8933957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                synchronized (mLock) {
8943957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    UserState userState = getUserStateLocked(resolvedUserId);
895969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                    userState.callbackSet.add(callback);
896969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                    for (TvInputState state : userState.inputMap.values()) {
8978e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim                        notifyInputStateChangedLocked(userState, state.mInfo.getId(),
898969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                                state.mState, callback);
8993957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    }
9003957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                }
9013957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            } finally {
9023957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                Binder.restoreCallingIdentity(identity);
9033957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            }
9043957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
9053957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
9063957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        @Override
907969167dc05a6485a32d160895871cff46fd81884Wonsik Kim        public void unregisterCallback(ITvInputManagerCallback callback, int userId) {
9083957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(),
9093957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    Binder.getCallingUid(), userId, "unregisterCallback");
9103957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            final long identity = Binder.clearCallingIdentity();
9113957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            try {
9123957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                synchronized (mLock) {
913969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                    UserState userState = getUserStateLocked(resolvedUserId);
914969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                    userState.callbackSet.remove(callback);
9153957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                }
9163957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            } finally {
9173957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                Binder.restoreCallingIdentity(identity);
9183957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            }
9193957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
9203957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
9213957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        @Override
922783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo        public boolean isParentalControlsEnabled(int userId) {
923783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(),
924783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                    Binder.getCallingUid(), userId, "isParentalControlsEnabled");
925783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo            final long identity = Binder.clearCallingIdentity();
926783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo            try {
927783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                synchronized (mLock) {
928783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                    UserState userState = getUserStateLocked(resolvedUserId);
929783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                    return userState.persistentDataStore.isParentalControlsEnabled();
930783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                }
931783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo            } finally {
932783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                Binder.restoreCallingIdentity(identity);
933783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo            }
934783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo        }
935783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo
936783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo        @Override
937783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo        public void setParentalControlsEnabled(boolean enabled, int userId) {
938783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo            ensureParentalControlsPermission();
939783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(),
940783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                    Binder.getCallingUid(), userId, "setParentalControlsEnabled");
941783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo            final long identity = Binder.clearCallingIdentity();
942783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo            try {
943783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                synchronized (mLock) {
944783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                    UserState userState = getUserStateLocked(resolvedUserId);
945783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                    userState.persistentDataStore.setParentalControlsEnabled(enabled);
946783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                }
947783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo            } finally {
948783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                Binder.restoreCallingIdentity(identity);
949783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo            }
950783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo        }
951783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo
952783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo        @Override
953783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo        public boolean isRatingBlocked(String rating, int userId) {
954783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(),
955783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                    Binder.getCallingUid(), userId, "isRatingBlocked");
956783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo            final long identity = Binder.clearCallingIdentity();
957783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo            try {
958783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                synchronized (mLock) {
959783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                    UserState userState = getUserStateLocked(resolvedUserId);
960783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                    return userState.persistentDataStore.isRatingBlocked(
961783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                            TvContentRating.unflattenFromString(rating));
962783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                }
963783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo            } finally {
964783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                Binder.restoreCallingIdentity(identity);
965783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo            }
966783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo        }
967783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo
968783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo        @Override
969783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo        public List<String> getBlockedRatings(int userId) {
970783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(),
971783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                    Binder.getCallingUid(), userId, "getBlockedRatings");
972783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo            final long identity = Binder.clearCallingIdentity();
973783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo            try {
974783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                synchronized (mLock) {
975783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                    UserState userState = getUserStateLocked(resolvedUserId);
976783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                    List<String> ratings = new ArrayList<String>();
977783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                    for (TvContentRating rating
978783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                            : userState.persistentDataStore.getBlockedRatings()) {
979783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                        ratings.add(rating.flattenToString());
980783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                    }
981783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                    return ratings;
982783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                }
983783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo            } finally {
984783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                Binder.restoreCallingIdentity(identity);
985783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo            }
986783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo        }
987783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo
988783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo        @Override
989783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo        public void addBlockedRating(String rating, int userId) {
990783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo            ensureParentalControlsPermission();
991783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(),
992783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                    Binder.getCallingUid(), userId, "addBlockedRating");
993783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo            final long identity = Binder.clearCallingIdentity();
994783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo            try {
995783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                synchronized (mLock) {
996783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                    UserState userState = getUserStateLocked(resolvedUserId);
997783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                    userState.persistentDataStore.addBlockedRating(
998783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                            TvContentRating.unflattenFromString(rating));
999783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                }
1000783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo            } finally {
1001783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                Binder.restoreCallingIdentity(identity);
1002783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo            }
1003783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo        }
1004783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo
1005783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo        @Override
1006783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo        public void removeBlockedRating(String rating, int userId) {
1007783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo            ensureParentalControlsPermission();
1008783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(),
1009783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                    Binder.getCallingUid(), userId, "removeBlockedRating");
1010783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo            final long identity = Binder.clearCallingIdentity();
1011783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo            try {
1012783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                synchronized (mLock) {
1013783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                    UserState userState = getUserStateLocked(resolvedUserId);
1014783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                    userState.persistentDataStore.removeBlockedRating(
1015783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                            TvContentRating.unflattenFromString(rating));
1016783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                }
1017783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo            } finally {
1018783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo                Binder.restoreCallingIdentity(identity);
1019783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo            }
1020783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo        }
1021783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo
1022783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo        private void ensureParentalControlsPermission() {
1023550c4b0d4dc6f3e2ef388b4250c758829c8255bcJae Seo            // STOPSHIP: Uncomment when b/16984416 is resolved.
1024550c4b0d4dc6f3e2ef388b4250c758829c8255bcJae Seo            //if (mContext.checkCallingPermission(
1025550c4b0d4dc6f3e2ef388b4250c758829c8255bcJae Seo            //        android.Manifest.permission.MODIFY_PARENTAL_CONTROLS)
1026550c4b0d4dc6f3e2ef388b4250c758829c8255bcJae Seo            //        != PackageManager.PERMISSION_GRANTED) {
1027550c4b0d4dc6f3e2ef388b4250c758829c8255bcJae Seo            //    throw new SecurityException(
1028550c4b0d4dc6f3e2ef388b4250c758829c8255bcJae Seo            //            "The caller does not have parental controls permission");
1029550c4b0d4dc6f3e2ef388b4250c758829c8255bcJae Seo            //}
1030783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo        }
1031783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo
1032783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo        @Override
1033d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim        public void createSession(final ITvInputClient client, final String inputId,
10343957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                int seq, int userId) {
10353957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            final int callingUid = Binder.getCallingUid();
10363957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
10373957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    userId, "createSession");
10383957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            final long identity = Binder.clearCallingIdentity();
10393957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            try {
10403957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                synchronized (mLock) {
10413957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    UserState userState = getUserStateLocked(resolvedUserId);
1042187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                    TvInputInfo info = userState.inputMap.get(inputId).mInfo;
1043187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                    ServiceState serviceState = userState.serviceStateMap.get(info.getComponent());
10443957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    if (serviceState == null) {
1045187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                        serviceState = new ServiceState(info.getComponent(), resolvedUserId);
1046187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                        userState.serviceStateMap.put(info.getComponent(), serviceState);
10473957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    }
10482b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                    // Send a null token immediately while reconnecting.
10492b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                    if (serviceState.mReconnecting == true) {
10505c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo                        sendSessionTokenToClientLocked(client, inputId, null, null, seq);
10512b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                        return;
10522b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                    }
10532b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim
10542b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                    // Create a new session token and a session state.
10552b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                    IBinder sessionToken = new Binder();
1056187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                    SessionState sessionState = new SessionState(sessionToken, info, client,
105772ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim                            seq, callingUid, resolvedUserId);
10582b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim
10592b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                    // Add them to the global session state map of the current user.
10602b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                    userState.sessionStateMap.put(sessionToken, sessionState);
10612b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim
10622b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                    // Also, add them to the session state map of the current service.
1063d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim                    serviceState.mSessionTokens.add(sessionToken);
10643957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
1065d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim                    if (serviceState.mService != null) {
1066d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim                        createSessionInternalLocked(serviceState.mService, sessionToken,
10677de5e234715a3baa8905afa3dd0c5009af64541fSungsoo Lim                                resolvedUserId);
10683957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    } else {
1069187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                        updateServiceConnectionLocked(info.getComponent(), resolvedUserId);
10703957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    }
10713957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                }
10723957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            } finally {
10733957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                Binder.restoreCallingIdentity(identity);
10743957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            }
10753957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
10763957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
10773957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        @Override
10783957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        public void releaseSession(IBinder sessionToken, int userId) {
107915c56aac985bc8d75f38fb4ecb92dda12d2ca06cJi-Hwan Lee            if (DEBUG) {
108015c56aac985bc8d75f38fb4ecb92dda12d2ca06cJi-Hwan Lee                Slog.d(TAG, "releaseSession(): " + sessionToken);
108115c56aac985bc8d75f38fb4ecb92dda12d2ca06cJi-Hwan Lee            }
10823957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            final int callingUid = Binder.getCallingUid();
10833957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
10843957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    userId, "releaseSession");
10853957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            final long identity = Binder.clearCallingIdentity();
10863957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            try {
10873957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                synchronized (mLock) {
10882b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                    releaseSessionLocked(sessionToken, callingUid, resolvedUserId);
10893957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                }
10903957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            } finally {
10913957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                Binder.restoreCallingIdentity(identity);
10923957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            }
10933957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
10943957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
10953957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        @Override
10964c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee        public void setMainSession(IBinder sessionToken, int userId) {
109715c56aac985bc8d75f38fb4ecb92dda12d2ca06cJi-Hwan Lee            if (DEBUG) {
109815c56aac985bc8d75f38fb4ecb92dda12d2ca06cJi-Hwan Lee                Slog.d(TAG, "setMainSession(): " + sessionToken);
109915c56aac985bc8d75f38fb4ecb92dda12d2ca06cJi-Hwan Lee            }
11004c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee            final int callingUid = Binder.getCallingUid();
11014c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
11024c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee                    userId, "setMainSession");
11034c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee            final long identity = Binder.clearCallingIdentity();
11044c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee            try {
11054c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee                synchronized (mLock) {
1106982abe693f66037ca265b88057eceb5a3e815182Ji-Hwan Lee                    UserState userState = getUserStateLocked(resolvedUserId);
1107956afc2ba79f50bb8025c6d334653e3c3419b480Ji-Hwan Lee                    if (userState.mainSessionToken == sessionToken) {
11084c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee                        return;
11094c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee                    }
111015c56aac985bc8d75f38fb4ecb92dda12d2ca06cJi-Hwan Lee                    if (DEBUG) {
111115c56aac985bc8d75f38fb4ecb92dda12d2ca06cJi-Hwan Lee                        Slog.d(TAG, "mainSessionToken=" + sessionToken);
1112abca0ee7949f59e72b8d2764dafa23af18eb51dbJi-Hwan Lee                    }
111315c56aac985bc8d75f38fb4ecb92dda12d2ca06cJi-Hwan Lee                    IBinder oldMainSessionToken = userState.mainSessionToken;
11144c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee                    userState.mainSessionToken = sessionToken;
11154c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee
1116956afc2ba79f50bb8025c6d334653e3c3419b480Ji-Hwan Lee                    // Inform the new main session first.
111715c56aac985bc8d75f38fb4ecb92dda12d2ca06cJi-Hwan Lee                    // See {@link TvInputService.Session#onSetMain}.
111815c56aac985bc8d75f38fb4ecb92dda12d2ca06cJi-Hwan Lee                    if (sessionToken != null) {
111915c56aac985bc8d75f38fb4ecb92dda12d2ca06cJi-Hwan Lee                        setMainLocked(sessionToken, true, callingUid, userId);
11204c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee                    }
112115c56aac985bc8d75f38fb4ecb92dda12d2ca06cJi-Hwan Lee                    if (oldMainSessionToken != null) {
112215c56aac985bc8d75f38fb4ecb92dda12d2ca06cJi-Hwan Lee                        setMainLocked(oldMainSessionToken, false, Process.SYSTEM_UID, userId);
11234c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee                    }
11244c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee                }
11254c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee            } finally {
11264c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee                Binder.restoreCallingIdentity(identity);
11274c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee            }
11284c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee        }
11294c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee
11304c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee        @Override
11313957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        public void setSurface(IBinder sessionToken, Surface surface, int userId) {
11323957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            final int callingUid = Binder.getCallingUid();
11333957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
11343957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    userId, "setSurface");
11353957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            final long identity = Binder.clearCallingIdentity();
11363957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            try {
11373957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                synchronized (mLock) {
11383957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    try {
1139bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                        SessionState sessionState = getSessionStateLocked(sessionToken, callingUid,
1140bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                                resolvedUserId);
1141bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                        if (sessionState.mHardwareSessionToken == null) {
1142bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                            getSessionLocked(sessionState).setSurface(surface);
1143bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                        } else {
1144bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                            getSessionLocked(sessionState.mHardwareSessionToken,
1145bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                                    Process.SYSTEM_UID, resolvedUserId).setSurface(surface);
1146bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                        }
11473957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    } catch (RemoteException e) {
11489a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                        Slog.e(TAG, "error in setSurface", e);
11493957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    }
11503957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                }
11513957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            } finally {
1152f836206818ce338db83a3c23c486fb8cab29cb6dYoungsang Cho                if (surface != null) {
1153f836206818ce338db83a3c23c486fb8cab29cb6dYoungsang Cho                    // surface is not used in TvInputManagerService.
1154f836206818ce338db83a3c23c486fb8cab29cb6dYoungsang Cho                    surface.release();
1155f836206818ce338db83a3c23c486fb8cab29cb6dYoungsang Cho                }
11563957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                Binder.restoreCallingIdentity(identity);
11573957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            }
11583957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
11593957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
11603957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        @Override
1161e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho        public void dispatchSurfaceChanged(IBinder sessionToken, int format, int width,
1162e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho                int height, int userId) {
1163e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho            final int callingUid = Binder.getCallingUid();
1164e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
1165e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho                    userId, "dispatchSurfaceChanged");
1166e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho            final long identity = Binder.clearCallingIdentity();
1167e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho            try {
1168e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho                synchronized (mLock) {
1169e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho                    try {
1170bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                        SessionState sessionState = getSessionStateLocked(sessionToken, callingUid,
1171bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                                resolvedUserId);
1172bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                        getSessionLocked(sessionState).dispatchSurfaceChanged(format, width, height);
1173bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                        if (sessionState.mHardwareSessionToken != null) {
1174bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                            getSessionLocked(sessionState.mHardwareSessionToken, Process.SYSTEM_UID,
1175bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                                    resolvedUserId).dispatchSurfaceChanged(format, width, height);
1176bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                        }
1177e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho                    } catch (RemoteException e) {
1178e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho                        Slog.e(TAG, "error in dispatchSurfaceChanged", e);
1179e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho                    }
1180e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho                }
1181e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho            } finally {
1182e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho                Binder.restoreCallingIdentity(identity);
1183e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho            }
1184e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho        }
1185e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho
1186e821d711db1799dc51661a3ed6188f3cd942bae7Youngsang Cho        @Override
11873957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        public void setVolume(IBinder sessionToken, float volume, int userId) {
1188bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang            final float REMOTE_VOLUME_ON = 1.0f;
1189bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang            final float REMOTE_VOLUME_OFF = 0f;
11903957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            final int callingUid = Binder.getCallingUid();
11913957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
11923957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    userId, "setVolume");
11933957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            final long identity = Binder.clearCallingIdentity();
11943957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            try {
11953957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                synchronized (mLock) {
11963957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    try {
1197bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                        SessionState sessionState = getSessionStateLocked(sessionToken, callingUid,
1198bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                                resolvedUserId);
1199bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                        getSessionLocked(sessionState).setVolume(volume);
1200bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                        if (sessionState.mHardwareSessionToken != null) {
1201bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                            // Here, we let the hardware session know only whether volume is on or
1202bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                            // off to prevent that the volume is controlled in the both side.
1203bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                            getSessionLocked(sessionState.mHardwareSessionToken,
1204bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                                    Process.SYSTEM_UID, resolvedUserId).setVolume((volume > 0.0f)
1205bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                                            ? REMOTE_VOLUME_ON : REMOTE_VOLUME_OFF);
1206bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                        }
12073957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    } catch (RemoteException e) {
12089a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                        Slog.e(TAG, "error in setVolume", e);
12093957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    }
12103957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                }
12113957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            } finally {
12123957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                Binder.restoreCallingIdentity(identity);
12133957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            }
12143957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
12153957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
12163957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        @Override
12171a6b25eabcc1fb66e6e8d76f91fd413e18b793a9Sungsoo Lim        public void tune(IBinder sessionToken, final Uri channelUri, Bundle params, int userId) {
12183957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            final int callingUid = Binder.getCallingUid();
12193957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
12203957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    userId, "tune");
12213957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            final long identity = Binder.clearCallingIdentity();
12223957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            try {
12233957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                synchronized (mLock) {
12243957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    try {
12251a6b25eabcc1fb66e6e8d76f91fd413e18b793a9Sungsoo Lim                        getSessionLocked(sessionToken, callingUid, resolvedUserId).tune(
12261a6b25eabcc1fb66e6e8d76f91fd413e18b793a9Sungsoo Lim                                channelUri, params);
1227c22d0c0941ab65ca69977d002c4431394a735c7dJae Seo                        if (TvContract.isChannelUriForPassthroughInput(channelUri)) {
1228008f6d4e326f6372e165bdf342178ecd1e834e2fYoungsang Cho                            // Do not log the watch history for passthrough inputs.
1229008f6d4e326f6372e165bdf342178ecd1e834e2fYoungsang Cho                            return;
1230008f6d4e326f6372e165bdf342178ecd1e834e2fYoungsang Cho                        }
123131dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo
123231dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                        UserState userState = getUserStateLocked(resolvedUserId);
123331dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                        SessionState sessionState = userState.sessionStateMap.get(sessionToken);
123431dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo
12357eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo                        // Log the start of watch.
123631dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                        SomeArgs args = SomeArgs.obtain();
12377eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo                        args.arg1 = sessionState.mInfo.getComponent().getPackageName();
12387eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo                        args.arg2 = System.currentTimeMillis();
12397eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo                        args.arg3 = ContentUris.parseId(channelUri);
12407eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo                        args.arg4 = params;
12417eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo                        args.arg5 = sessionToken;
12427eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo                        mWatchLogHandler.obtainMessage(WatchLogHandler.MSG_LOG_WATCH_START, args)
12437eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo                                .sendToTarget();
12443957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    } catch (RemoteException e) {
12459a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                        Slog.e(TAG, "error in tune", e);
12463957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                        return;
12473957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    }
12483957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                }
12493957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            } finally {
12503957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                Binder.restoreCallingIdentity(identity);
12513957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            }
12523957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
12539a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho
12549a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho        @Override
12559bf671f8ee72b156f16fcf05a3d1c6e093ecba67Sungsoo Lim        public void requestUnblockContent(
12569bf671f8ee72b156f16fcf05a3d1c6e093ecba67Sungsoo Lim                IBinder sessionToken, String unblockedRating, int userId) {
1257903d6b72cd572665309633e925485464d08bb25aJaewan Kim            final int callingUid = Binder.getCallingUid();
1258903d6b72cd572665309633e925485464d08bb25aJaewan Kim            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
1259903d6b72cd572665309633e925485464d08bb25aJaewan Kim                    userId, "unblockContent");
1260903d6b72cd572665309633e925485464d08bb25aJaewan Kim            final long identity = Binder.clearCallingIdentity();
1261903d6b72cd572665309633e925485464d08bb25aJaewan Kim            try {
1262903d6b72cd572665309633e925485464d08bb25aJaewan Kim                synchronized (mLock) {
1263903d6b72cd572665309633e925485464d08bb25aJaewan Kim                    try {
1264903d6b72cd572665309633e925485464d08bb25aJaewan Kim                        getSessionLocked(sessionToken, callingUid, resolvedUserId)
12659bf671f8ee72b156f16fcf05a3d1c6e093ecba67Sungsoo Lim                                .requestUnblockContent(unblockedRating);
1266903d6b72cd572665309633e925485464d08bb25aJaewan Kim                    } catch (RemoteException e) {
1267903d6b72cd572665309633e925485464d08bb25aJaewan Kim                        Slog.e(TAG, "error in unblockContent", e);
1268903d6b72cd572665309633e925485464d08bb25aJaewan Kim                    }
1269903d6b72cd572665309633e925485464d08bb25aJaewan Kim                }
1270903d6b72cd572665309633e925485464d08bb25aJaewan Kim            } finally {
1271903d6b72cd572665309633e925485464d08bb25aJaewan Kim                Binder.restoreCallingIdentity(identity);
1272903d6b72cd572665309633e925485464d08bb25aJaewan Kim            }
1273903d6b72cd572665309633e925485464d08bb25aJaewan Kim        }
1274903d6b72cd572665309633e925485464d08bb25aJaewan Kim
1275903d6b72cd572665309633e925485464d08bb25aJaewan Kim        @Override
12762c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo        public void setCaptionEnabled(IBinder sessionToken, boolean enabled, int userId) {
12772c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo            final int callingUid = Binder.getCallingUid();
12782c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
12792c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo                    userId, "setCaptionEnabled");
12802c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo            final long identity = Binder.clearCallingIdentity();
12812c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo            try {
12822c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo                synchronized (mLock) {
12832c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo                    try {
12842c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo                        getSessionLocked(sessionToken, callingUid, resolvedUserId)
12852c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo                                .setCaptionEnabled(enabled);
12862c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo                    } catch (RemoteException e) {
12872c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo                        Slog.e(TAG, "error in setCaptionEnabled", e);
12882c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo                    }
12892c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo                }
12902c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo            } finally {
12912c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo                Binder.restoreCallingIdentity(identity);
12922c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo            }
12932c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo        }
12942c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo
12952c1c31c7ae9bd972b974a5cc2d8b0942746af612Jae Seo        @Override
129610d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo        public void selectTrack(IBinder sessionToken, int type, String trackId, int userId) {
12971f213914c45c23c653f721690da2ce0718e63139Dongwon Kang            final int callingUid = Binder.getCallingUid();
12981f213914c45c23c653f721690da2ce0718e63139Dongwon Kang            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
12991f213914c45c23c653f721690da2ce0718e63139Dongwon Kang                    userId, "selectTrack");
13001f213914c45c23c653f721690da2ce0718e63139Dongwon Kang            final long identity = Binder.clearCallingIdentity();
13011f213914c45c23c653f721690da2ce0718e63139Dongwon Kang            try {
13021f213914c45c23c653f721690da2ce0718e63139Dongwon Kang                synchronized (mLock) {
13031f213914c45c23c653f721690da2ce0718e63139Dongwon Kang                    try {
13041f213914c45c23c653f721690da2ce0718e63139Dongwon Kang                        getSessionLocked(sessionToken, callingUid, resolvedUserId).selectTrack(
130510d285ac06b3d3060c7d90d3dc196d4ac8367467Jae Seo                                type, trackId);
13061f213914c45c23c653f721690da2ce0718e63139Dongwon Kang                    } catch (RemoteException e) {
13071f213914c45c23c653f721690da2ce0718e63139Dongwon Kang                        Slog.e(TAG, "error in selectTrack", e);
13081f213914c45c23c653f721690da2ce0718e63139Dongwon Kang                    }
13091f213914c45c23c653f721690da2ce0718e63139Dongwon Kang                }
13101f213914c45c23c653f721690da2ce0718e63139Dongwon Kang            } finally {
13111f213914c45c23c653f721690da2ce0718e63139Dongwon Kang                Binder.restoreCallingIdentity(identity);
13121f213914c45c23c653f721690da2ce0718e63139Dongwon Kang            }
13131f213914c45c23c653f721690da2ce0718e63139Dongwon Kang        }
13141f213914c45c23c653f721690da2ce0718e63139Dongwon Kang
13151f213914c45c23c653f721690da2ce0718e63139Dongwon Kang        @Override
1316a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo        public void sendAppPrivateCommand(IBinder sessionToken, String command, Bundle data,
1317a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo                int userId) {
1318a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo            final int callingUid = Binder.getCallingUid();
1319a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
1320a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo                    userId, "sendAppPrivateCommand");
1321a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo            final long identity = Binder.clearCallingIdentity();
1322a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo            try {
1323a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo                synchronized (mLock) {
1324a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo                    try {
1325a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo                        getSessionLocked(sessionToken, callingUid, resolvedUserId)
1326a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo                                .appPrivateCommand(command, data);
1327a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo                    } catch (RemoteException e) {
1328a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo                        Slog.e(TAG, "error in sendAppPrivateCommand", e);
1329a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo                    }
1330a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo                }
1331a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo            } finally {
1332a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo                Binder.restoreCallingIdentity(identity);
1333a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo            }
1334a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo        }
1335a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo
1336a759b111a1c9cb00284038f8a1554bf29709b952Jae Seo        @Override
13379a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho        public void createOverlayView(IBinder sessionToken, IBinder windowToken, Rect frame,
13389a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                int userId) {
13399a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            final int callingUid = Binder.getCallingUid();
13409a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
13419a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                    userId, "createOverlayView");
13429a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            final long identity = Binder.clearCallingIdentity();
13439a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            try {
13449a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                synchronized (mLock) {
13459a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                    try {
13469a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                        getSessionLocked(sessionToken, callingUid, resolvedUserId)
13479a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                                .createOverlayView(windowToken, frame);
13489a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                    } catch (RemoteException e) {
13499a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                        Slog.e(TAG, "error in createOverlayView", e);
13509a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                    }
13519a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                }
13529a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            } finally {
13539a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                Binder.restoreCallingIdentity(identity);
13549a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            }
13559a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho        }
13569a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho
13579a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho        @Override
13589a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho        public void relayoutOverlayView(IBinder sessionToken, Rect frame, int userId) {
13599a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            final int callingUid = Binder.getCallingUid();
13609a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
13619a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                    userId, "relayoutOverlayView");
13629a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            final long identity = Binder.clearCallingIdentity();
13639a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            try {
13649a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                synchronized (mLock) {
13659a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                    try {
13669a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                        getSessionLocked(sessionToken, callingUid, resolvedUserId)
13679a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                                .relayoutOverlayView(frame);
13689a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                    } catch (RemoteException e) {
13699a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                        Slog.e(TAG, "error in relayoutOverlayView", e);
13709a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                    }
13719a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                }
13729a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            } finally {
13739a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                Binder.restoreCallingIdentity(identity);
13749a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            }
13759a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho        }
13769a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho
13779a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho        @Override
13789a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho        public void removeOverlayView(IBinder sessionToken, int userId) {
13799a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            final int callingUid = Binder.getCallingUid();
13809a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
13819a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                    userId, "removeOverlayView");
13829a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            final long identity = Binder.clearCallingIdentity();
13839a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            try {
13849a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                synchronized (mLock) {
13859a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                    try {
13869a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                        getSessionLocked(sessionToken, callingUid, resolvedUserId)
13879a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                                .removeOverlayView();
13889a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                    } catch (RemoteException e) {
13899a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                        Slog.e(TAG, "error in removeOverlayView", e);
13909a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                    }
13919a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                }
13929a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            } finally {
13939a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                Binder.restoreCallingIdentity(identity);
13949a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho            }
13959a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho        }
1396c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim
1397c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim        @Override
1398c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim        public List<TvInputHardwareInfo> getHardwareList() throws RemoteException {
1399969167dc05a6485a32d160895871cff46fd81884Wonsik Kim            if (mContext.checkCallingPermission(android.Manifest.permission.TV_INPUT_HARDWARE)
1400c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim                    != PackageManager.PERMISSION_GRANTED) {
1401c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim                return null;
1402c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim            }
1403c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim
1404c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim            final long identity = Binder.clearCallingIdentity();
1405c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim            try {
1406c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim                return mTvInputHardwareManager.getHardwareList();
1407c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim            } finally {
1408c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim                Binder.restoreCallingIdentity(identity);
1409c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim            }
1410c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim        }
1411c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim
1412c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim        @Override
1413c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim        public ITvInputHardware acquireTvInputHardware(int deviceId,
1414969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                ITvInputHardwareCallback callback, TvInputInfo info, int userId)
1415969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                throws RemoteException {
1416969167dc05a6485a32d160895871cff46fd81884Wonsik Kim            if (mContext.checkCallingPermission(android.Manifest.permission.TV_INPUT_HARDWARE)
1417c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim                    != PackageManager.PERMISSION_GRANTED) {
1418c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim                return null;
1419c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim            }
1420c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim
1421c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim            final long identity = Binder.clearCallingIdentity();
1422c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim            final int callingUid = Binder.getCallingUid();
1423c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
1424c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim                    userId, "acquireTvInputHardware");
1425c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim            try {
1426c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim                return mTvInputHardwareManager.acquireHardware(
1427969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                        deviceId, callback, info, callingUid, resolvedUserId);
1428c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim            } finally {
1429c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim                Binder.restoreCallingIdentity(identity);
1430c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim            }
1431c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim        }
1432c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim
1433c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim        @Override
1434c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim        public void releaseTvInputHardware(int deviceId, ITvInputHardware hardware, int userId)
1435c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim                throws RemoteException {
1436969167dc05a6485a32d160895871cff46fd81884Wonsik Kim            if (mContext.checkCallingPermission(android.Manifest.permission.TV_INPUT_HARDWARE)
1437c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim                    != PackageManager.PERMISSION_GRANTED) {
1438c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim                return;
1439c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim            }
1440c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim
1441c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim            final long identity = Binder.clearCallingIdentity();
1442c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim            final int callingUid = Binder.getCallingUid();
1443c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
1444c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim                    userId, "releaseTvInputHardware");
1445c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim            try {
1446c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim                mTvInputHardwareManager.releaseHardware(
1447c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim                        deviceId, hardware, callingUid, resolvedUserId);
1448c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim            } finally {
1449c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim                Binder.restoreCallingIdentity(identity);
1450c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim            }
1451c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim        }
1452e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim
1453e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim        @Override
1454c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo        public List<TvStreamConfig> getAvailableTvStreamConfigList(String inputId, int userId)
1455c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo                throws RemoteException {
1456c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo            if (mContext.checkCallingPermission(
1457c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo                    android.Manifest.permission.CAPTURE_TV_INPUT)
1458c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo                    != PackageManager.PERMISSION_GRANTED) {
1459c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo                throw new SecurityException("Requires CAPTURE_TV_INPUT permission");
1460c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo            }
1461c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo
1462c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo            final long identity = Binder.clearCallingIdentity();
1463c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo            final int callingUid = Binder.getCallingUid();
1464c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
1465c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo                    userId, "getAvailableTvStreamConfigList");
1466c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo            try {
1467c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo                return mTvInputHardwareManager.getAvailableTvStreamConfigList(
1468c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo                        inputId, callingUid, resolvedUserId);
1469c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo            } finally {
1470c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo                Binder.restoreCallingIdentity(identity);
1471c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo            }
1472c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo        }
1473c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo
1474c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo        @Override
1475c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo        public boolean captureFrame(String inputId, Surface surface, TvStreamConfig config,
1476c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo                int userId)
1477c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo                throws RemoteException {
1478c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo            if (mContext.checkCallingPermission(
1479c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo                    android.Manifest.permission.CAPTURE_TV_INPUT)
1480c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo                    != PackageManager.PERMISSION_GRANTED) {
1481c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo                throw new SecurityException("Requires CAPTURE_TV_INPUT permission");
1482c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo            }
1483c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo
1484c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo            final long identity = Binder.clearCallingIdentity();
1485c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo            final int callingUid = Binder.getCallingUid();
1486c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
1487c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo                    userId, "captureFrame");
1488c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo            try {
1489bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                String hardwareInputId = null;
149079124a717c09f12c74d587d3977bf33ca37e6420Terry Heo                synchronized (mLock) {
149179124a717c09f12c74d587d3977bf33ca37e6420Terry Heo                    UserState userState = getUserStateLocked(resolvedUserId);
1492bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                    if (userState.inputMap.get(inputId) == null) {
1493bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                        Slog.e(TAG, "Input not found for " + inputId);
1494bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                        return false;
1495bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                    }
1496bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                    for (SessionState sessionState : userState.sessionStateMap.values()) {
1497bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                        if (sessionState.mInfo.getId().equals(inputId)
1498bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                                && sessionState.mHardwareSessionToken != null) {
1499bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                            hardwareInputId = userState.sessionStateMap.get(
1500bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                                    sessionState.mHardwareSessionToken).mInfo.getId();
1501bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                            break;
1502bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                        }
1503bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                    }
150479124a717c09f12c74d587d3977bf33ca37e6420Terry Heo                }
1505c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo                return mTvInputHardwareManager.captureFrame(
1506bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                        (hardwareInputId != null) ? hardwareInputId : inputId,
150779124a717c09f12c74d587d3977bf33ca37e6420Terry Heo                        surface, config, callingUid, resolvedUserId);
1508c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo            } finally {
1509c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo                Binder.restoreCallingIdentity(identity);
1510c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo            }
1511c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo        }
1512c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo
1513c086a3df3b28996cd10ebe42c5f59035d054aa0dTerry Heo        @Override
1514df9f0a321e0cb2958c9d170395a0367a106fa0e6Terry Heo        public boolean isSingleSessionActive(int userId) throws RemoteException {
1515df9f0a321e0cb2958c9d170395a0367a106fa0e6Terry Heo            final long identity = Binder.clearCallingIdentity();
1516df9f0a321e0cb2958c9d170395a0367a106fa0e6Terry Heo            final int callingUid = Binder.getCallingUid();
1517df9f0a321e0cb2958c9d170395a0367a106fa0e6Terry Heo            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
1518df9f0a321e0cb2958c9d170395a0367a106fa0e6Terry Heo                    userId, "isSingleSessionActive");
1519df9f0a321e0cb2958c9d170395a0367a106fa0e6Terry Heo            try {
1520df9f0a321e0cb2958c9d170395a0367a106fa0e6Terry Heo                synchronized (mLock) {
1521df9f0a321e0cb2958c9d170395a0367a106fa0e6Terry Heo                    UserState userState = getUserStateLocked(resolvedUserId);
1522df9f0a321e0cb2958c9d170395a0367a106fa0e6Terry Heo                    if (userState.sessionStateMap.size() == 1) {
1523df9f0a321e0cb2958c9d170395a0367a106fa0e6Terry Heo                        return true;
1524df9f0a321e0cb2958c9d170395a0367a106fa0e6Terry Heo                    }
1525df9f0a321e0cb2958c9d170395a0367a106fa0e6Terry Heo                    else if (userState.sessionStateMap.size() == 2) {
1526df9f0a321e0cb2958c9d170395a0367a106fa0e6Terry Heo                        SessionState[] sessionStates = userState.sessionStateMap.values().toArray(
1527df9f0a321e0cb2958c9d170395a0367a106fa0e6Terry Heo                                new SessionState[0]);
1528df9f0a321e0cb2958c9d170395a0367a106fa0e6Terry Heo                        // Check if there is a wrapper input.
1529df9f0a321e0cb2958c9d170395a0367a106fa0e6Terry Heo                        if (sessionStates[0].mHardwareSessionToken != null
1530df9f0a321e0cb2958c9d170395a0367a106fa0e6Terry Heo                                || sessionStates[1].mHardwareSessionToken != null) {
1531df9f0a321e0cb2958c9d170395a0367a106fa0e6Terry Heo                            return true;
1532df9f0a321e0cb2958c9d170395a0367a106fa0e6Terry Heo                        }
1533df9f0a321e0cb2958c9d170395a0367a106fa0e6Terry Heo                    }
1534df9f0a321e0cb2958c9d170395a0367a106fa0e6Terry Heo                    return false;
1535df9f0a321e0cb2958c9d170395a0367a106fa0e6Terry Heo                }
1536df9f0a321e0cb2958c9d170395a0367a106fa0e6Terry Heo            } finally {
1537df9f0a321e0cb2958c9d170395a0367a106fa0e6Terry Heo                Binder.restoreCallingIdentity(identity);
1538df9f0a321e0cb2958c9d170395a0367a106fa0e6Terry Heo            }
1539df9f0a321e0cb2958c9d170395a0367a106fa0e6Terry Heo        }
1540df9f0a321e0cb2958c9d170395a0367a106fa0e6Terry Heo
1541df9f0a321e0cb2958c9d170395a0367a106fa0e6Terry Heo        @Override
15420f8fc345ea61928265fdd6d461bf1babe353fbe4Jae Seo        @SuppressWarnings("resource")
1543e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim        protected void dump(FileDescriptor fd, final PrintWriter writer, String[] args) {
1544e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim            final IndentingPrintWriter pw = new IndentingPrintWriter(writer, "  ");
15450f8fc345ea61928265fdd6d461bf1babe353fbe4Jae Seo            if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
1546e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                    != PackageManager.PERMISSION_GRANTED) {
15470f8fc345ea61928265fdd6d461bf1babe353fbe4Jae Seo                pw.println("Permission Denial: can't dump TvInputManager from pid="
15480f8fc345ea61928265fdd6d461bf1babe353fbe4Jae Seo                        + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid());
1549e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                return;
1550e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim            }
1551e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim
1552e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim            synchronized (mLock) {
1553e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                pw.println("User Ids (Current user: " + mCurrentUserId + "):");
1554e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                pw.increaseIndent();
1555e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                for (int i = 0; i < mUserStates.size(); i++) {
1556e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                    int userId = mUserStates.keyAt(i);
1557e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                    pw.println(Integer.valueOf(userId));
1558e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                }
1559e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                pw.decreaseIndent();
1560e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim
1561e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                for (int i = 0; i < mUserStates.size(); i++) {
1562e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                    int userId = mUserStates.keyAt(i);
1563e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                    UserState userState = getUserStateLocked(userId);
1564e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                    pw.println("UserState (" + userId + "):");
1565e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                    pw.increaseIndent();
1566e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim
1567969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                    pw.println("inputMap: inputId -> TvInputState");
1568e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                    pw.increaseIndent();
15698e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim                    for (Map.Entry<String, TvInputState> entry: userState.inputMap.entrySet()) {
15708e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim                        pw.println(entry.getKey() + ": " + entry.getValue());
1571e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                    }
1572e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                    pw.decreaseIndent();
1573e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim
1574969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                    pw.println("packageSet:");
1575e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                    pw.increaseIndent();
1576969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                    for (String packageName : userState.packageSet) {
1577e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        pw.println(packageName);
1578e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                    }
1579e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                    pw.decreaseIndent();
1580e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim
1581e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                    pw.println("clientStateMap: ITvInputClient -> ClientState");
1582e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                    pw.increaseIndent();
1583e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                    for (Map.Entry<IBinder, ClientState> entry :
1584e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                            userState.clientStateMap.entrySet()) {
1585e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        ClientState client = entry.getValue();
1586e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        pw.println(entry.getKey() + ": " + client);
1587e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim
1588e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        pw.increaseIndent();
1589e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim
1590e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        pw.println("mSessionTokens:");
1591e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        pw.increaseIndent();
1592e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        for (IBinder token : client.mSessionTokens) {
1593e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                            pw.println("" + token);
1594e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        }
1595e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        pw.decreaseIndent();
1596e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim
1597e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        pw.println("mClientTokens: " + client.mClientToken);
1598e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        pw.println("mUserId: " + client.mUserId);
1599e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim
1600e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        pw.decreaseIndent();
1601e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                    }
1602e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                    pw.decreaseIndent();
1603e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim
1604187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                    pw.println("serviceStateMap: ComponentName -> ServiceState");
1605e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                    pw.increaseIndent();
1606187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                    for (Map.Entry<ComponentName, ServiceState> entry :
1607e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                            userState.serviceStateMap.entrySet()) {
1608e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        ServiceState service = entry.getValue();
1609e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        pw.println(entry.getKey() + ": " + service);
1610e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim
1611e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        pw.increaseIndent();
1612e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim
1613e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        pw.println("mSessionTokens:");
1614e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        pw.increaseIndent();
1615e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        for (IBinder token : service.mSessionTokens) {
1616e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                            pw.println("" + token);
1617e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        }
1618e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        pw.decreaseIndent();
1619e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim
1620e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        pw.println("mService: " + service.mService);
1621e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        pw.println("mCallback: " + service.mCallback);
1622e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        pw.println("mBound: " + service.mBound);
1623e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        pw.println("mReconnecting: " + service.mReconnecting);
1624e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim
1625e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        pw.decreaseIndent();
1626e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                    }
1627e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                    pw.decreaseIndent();
1628e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim
1629e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                    pw.println("sessionStateMap: ITvInputSession -> SessionState");
1630e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                    pw.increaseIndent();
1631e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                    for (Map.Entry<IBinder, SessionState> entry :
1632e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                            userState.sessionStateMap.entrySet()) {
1633e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        SessionState session = entry.getValue();
1634e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        pw.println(entry.getKey() + ": " + session);
1635e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim
1636e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        pw.increaseIndent();
1637187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                        pw.println("mInfo: " + session.mInfo);
1638e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        pw.println("mClient: " + session.mClient);
1639e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        pw.println("mSeq: " + session.mSeq);
1640e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        pw.println("mCallingUid: " + session.mCallingUid);
1641e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        pw.println("mUserId: " + session.mUserId);
1642e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        pw.println("mSessionToken: " + session.mSessionToken);
1643e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        pw.println("mSession: " + session.mSession);
1644e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        pw.println("mLogUri: " + session.mLogUri);
1645bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                        pw.println("mHardwareSessionToken: " + session.mHardwareSessionToken);
1646e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                        pw.decreaseIndent();
1647e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                    }
1648e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                    pw.decreaseIndent();
1649e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim
1650969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                    pw.println("callbackSet:");
1651969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                    pw.increaseIndent();
1652969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                    for (ITvInputManagerCallback callback : userState.callbackSet) {
1653969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                        pw.println(callback.toString());
1654969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                    }
1655969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                    pw.decreaseIndent();
1656969167dc05a6485a32d160895871cff46fd81884Wonsik Kim
1657956afc2ba79f50bb8025c6d334653e3c3419b480Ji-Hwan Lee                    pw.println("mainSessionToken: " + userState.mainSessionToken);
1658e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                    pw.decreaseIndent();
1659e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim                }
1660e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim            }
1661e14c3f4fc42e2dc83cf4aba711c5ff52d8bbe3eaJaewan Kim        }
16623957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    }
16633957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
1664969167dc05a6485a32d160895871cff46fd81884Wonsik Kim    private static final class TvInputState {
1665969167dc05a6485a32d160895871cff46fd81884Wonsik Kim        // A TvInputInfo object which represents the TV input.
1666969167dc05a6485a32d160895871cff46fd81884Wonsik Kim        private TvInputInfo mInfo;
1667969167dc05a6485a32d160895871cff46fd81884Wonsik Kim
1668969167dc05a6485a32d160895871cff46fd81884Wonsik Kim        // The state of TV input. Connected by default.
1669969167dc05a6485a32d160895871cff46fd81884Wonsik Kim        private int mState = INPUT_STATE_CONNECTED;
1670969167dc05a6485a32d160895871cff46fd81884Wonsik Kim
1671969167dc05a6485a32d160895871cff46fd81884Wonsik Kim        @Override
1672969167dc05a6485a32d160895871cff46fd81884Wonsik Kim        public String toString() {
1673969167dc05a6485a32d160895871cff46fd81884Wonsik Kim            return "mInfo: " + mInfo + "; mState: " + mState;
1674969167dc05a6485a32d160895871cff46fd81884Wonsik Kim        }
1675969167dc05a6485a32d160895871cff46fd81884Wonsik Kim    }
1676969167dc05a6485a32d160895871cff46fd81884Wonsik Kim
16773957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    private static final class UserState {
1678969167dc05a6485a32d160895871cff46fd81884Wonsik Kim        // A mapping from the TV input id to its TvInputState.
1679969167dc05a6485a32d160895871cff46fd81884Wonsik Kim        private Map<String, TvInputState> inputMap = new HashMap<String, TvInputState>();
16803957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
1681969167dc05a6485a32d160895871cff46fd81884Wonsik Kim        // A set of all TV input packages.
1682969167dc05a6485a32d160895871cff46fd81884Wonsik Kim        private final Set<String> packageSet = new HashSet<String>();
16835c80ad2077f3e755413ea47a35f51e9d25dbb083Jae Seo
16845c5b83fcd58d21c9ab7ac986bf84f604ec5bb4b5Sungsoo Lim        // A set of all TV content rating system xml uris.
16855c5b83fcd58d21c9ab7ac986bf84f604ec5bb4b5Sungsoo Lim        private final Set<Uri> ratingSystemXmlUriSet = new HashSet<Uri>();
16865c5b83fcd58d21c9ab7ac986bf84f604ec5bb4b5Sungsoo Lim
168772ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim        // A mapping from the token of a client to its state.
168872ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim        private final Map<IBinder, ClientState> clientStateMap =
168972ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim                new HashMap<IBinder, ClientState>();
169072ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim
16913957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        // A mapping from the name of a TV input service to its state.
1692187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim        private final Map<ComponentName, ServiceState> serviceStateMap =
1693187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                new HashMap<ComponentName, ServiceState>();
16943957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
16953957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        // A mapping from the token of a TV input session to its state.
16963957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        private final Map<IBinder, SessionState> sessionStateMap =
16973957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                new HashMap<IBinder, SessionState>();
1698969167dc05a6485a32d160895871cff46fd81884Wonsik Kim
1699969167dc05a6485a32d160895871cff46fd81884Wonsik Kim        // A set of callbacks.
1700969167dc05a6485a32d160895871cff46fd81884Wonsik Kim        private final Set<ITvInputManagerCallback> callbackSet =
1701969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                new HashSet<ITvInputManagerCallback>();
170279124a717c09f12c74d587d3977bf33ca37e6420Terry Heo
17034c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee        // The token of a "main" TV input session.
17044c52697dbed682a19dacc78b0c08931ea8dbc6b5Ji-Hwan Lee        private IBinder mainSessionToken = null;
1705783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo
1706783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo        // Persistent data store for all internal settings maintained by the TV input manager
1707783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo        // service.
1708783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo        private final PersistentDataStore persistentDataStore;
1709783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo
1710783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo        private UserState(Context context, int userId) {
1711783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo            persistentDataStore = new PersistentDataStore(context, userId);
1712783645e99f909ffc7a2d5d2fca9324cc0e9b7362Jae Seo        }
17133957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    }
17143957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
171572ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim    private final class ClientState implements IBinder.DeathRecipient {
171672ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim        private final List<IBinder> mSessionTokens = new ArrayList<IBinder>();
171772ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim
171872ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim        private IBinder mClientToken;
171972ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim        private final int mUserId;
172072ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim
172172ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim        ClientState(IBinder clientToken, int userId) {
172272ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim            mClientToken = clientToken;
172372ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim            mUserId = userId;
172472ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim        }
172572ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim
172672ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim        public boolean isEmpty() {
1727a65118e13b5ceb54454b48f67ea754a38a08f27aJi-Hwan Lee            return mSessionTokens.isEmpty();
172872ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim        }
172972ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim
173072ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim        @Override
173172ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim        public void binderDied() {
173272ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim            synchronized (mLock) {
173372ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim                UserState userState = getUserStateLocked(mUserId);
173472ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim                // DO NOT remove the client state of clientStateMap in this method. It will be
1735a65118e13b5ceb54454b48f67ea754a38a08f27aJi-Hwan Lee                // removed in releaseSessionLocked().
173672ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim                ClientState clientState = userState.clientStateMap.get(mClientToken);
173772ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim                if (clientState != null) {
173872ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim                    while (clientState.mSessionTokens.size() > 0) {
173972ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim                        releaseSessionLocked(
174072ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim                                clientState.mSessionTokens.get(0), Process.SYSTEM_UID, mUserId);
174172ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim                    }
174272ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim                }
174372ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim                mClientToken = null;
174472ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim            }
174572ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim        }
174672ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim    }
174772ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim
17483957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    private final class ServiceState {
1749d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim        private final List<IBinder> mSessionTokens = new ArrayList<IBinder>();
1750d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim        private final ServiceConnection mConnection;
17519e8ade2eb7ee835963473c9cf6faaf5423b0b048Ji-Hwan Lee        private final ComponentName mComponent;
1752187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim        private final boolean mIsHardware;
1753187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim        private final List<TvInputInfo> mInputList = new ArrayList<TvInputInfo>();
17543957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
1755d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim        private ITvInputService mService;
1756d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim        private ServiceCallback mCallback;
1757d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim        private boolean mBound;
17582b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim        private boolean mReconnecting;
17593957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
17609e8ade2eb7ee835963473c9cf6faaf5423b0b048Ji-Hwan Lee        private ServiceState(ComponentName component, int userId) {
17619e8ade2eb7ee835963473c9cf6faaf5423b0b048Ji-Hwan Lee            mComponent = component;
17629e8ade2eb7ee835963473c9cf6faaf5423b0b048Ji-Hwan Lee            mConnection = new InputServiceConnection(component, userId);
17639e8ade2eb7ee835963473c9cf6faaf5423b0b048Ji-Hwan Lee            mIsHardware = hasHardwarePermission(mContext.getPackageManager(), mComponent);
17643957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
17653957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    }
17663957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
17672b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim    private final class SessionState implements IBinder.DeathRecipient {
1768187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim        private final TvInputInfo mInfo;
1769d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim        private final ITvInputClient mClient;
1770d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim        private final int mSeq;
1771d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim        private final int mCallingUid;
17722b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim        private final int mUserId;
177372ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim        private final IBinder mSessionToken;
1774d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim        private ITvInputSession mSession;
1775d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim        private Uri mLogUri;
1776bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang        // Not null if this session represents an external device connected to a hardware TV input.
1777bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang        private IBinder mHardwareSessionToken;
17783957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
1779bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang        private SessionState(IBinder sessionToken, TvInputInfo info, ITvInputClient client,
1780bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                int seq, int callingUid, int userId) {
178172ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim            mSessionToken = sessionToken;
1782187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim            mInfo = info;
17832b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim            mClient = client;
17842b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim            mSeq = seq;
17852b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim            mCallingUid = callingUid;
17862b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim            mUserId = userId;
17872b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim        }
17882b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim
17892b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim        @Override
17902b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim        public void binderDied() {
17912b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim            synchronized (mLock) {
17922b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                mSession = null;
17932b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                if (mClient != null) {
17942b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                    try {
17952b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                        mClient.onSessionReleased(mSeq);
17962b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                    } catch(RemoteException e) {
17972b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                        Slog.e(TAG, "error in onSessionReleased", e);
17982b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                    }
17992b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                }
1800bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                // If there are any other sessions based on this session, they should be released.
1801bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                UserState userState = getUserStateLocked(mUserId);
1802bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                for (SessionState sessionState : userState.sessionStateMap.values()) {
18030c38fc764b0e1c5c8b880872d9b4a647a76955cdJi-Hwan Lee                    if (mSessionToken == sessionState.mHardwareSessionToken) {
18044835497886ee876b16e1144d32f5bdcfbb7e9062Ji-Hwan Lee                        releaseSessionLocked(sessionState.mSessionToken, Process.SYSTEM_UID,
18054835497886ee876b16e1144d32f5bdcfbb7e9062Ji-Hwan Lee                                mUserId);
1806bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                        try {
1807bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                            sessionState.mClient.onSessionReleased(sessionState.mSeq);
1808bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                        } catch (RemoteException e) {
1809bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                            Slog.e(TAG, "error in onSessionReleased", e);
1810bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                        }
1811bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                    }
1812bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                }
181372ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim                removeSessionStateLocked(mSessionToken, mUserId);
18142b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim            }
18153957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
18163957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    }
18173957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
18183957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    private final class InputServiceConnection implements ServiceConnection {
18199e8ade2eb7ee835963473c9cf6faaf5423b0b048Ji-Hwan Lee        private final ComponentName mComponent;
18203957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        private final int mUserId;
18213957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
18229e8ade2eb7ee835963473c9cf6faaf5423b0b048Ji-Hwan Lee        private InputServiceConnection(ComponentName component, int userId) {
18239e8ade2eb7ee835963473c9cf6faaf5423b0b048Ji-Hwan Lee            mComponent = component;
18243957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            mUserId = userId;
18253957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
18263957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
18273957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        @Override
18289e8ade2eb7ee835963473c9cf6faaf5423b0b048Ji-Hwan Lee        public void onServiceConnected(ComponentName component, IBinder service) {
18293957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            if (DEBUG) {
18309e8ade2eb7ee835963473c9cf6faaf5423b0b048Ji-Hwan Lee                Slog.d(TAG, "onServiceConnected(component=" + component + ")");
18313957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            }
18323957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            synchronized (mLock) {
1833969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                UserState userState = getUserStateLocked(mUserId);
18349e8ade2eb7ee835963473c9cf6faaf5423b0b048Ji-Hwan Lee                ServiceState serviceState = userState.serviceStateMap.get(mComponent);
1835d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim                serviceState.mService = ITvInputService.Stub.asInterface(service);
18363957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
18373957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                // Register a callback, if we need to.
1838187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                if (serviceState.mIsHardware && serviceState.mCallback == null) {
18399e8ade2eb7ee835963473c9cf6faaf5423b0b048Ji-Hwan Lee                    serviceState.mCallback = new ServiceCallback(mComponent, mUserId);
18403957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    try {
1841d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim                        serviceState.mService.registerCallback(serviceState.mCallback);
18423957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    } catch (RemoteException e) {
18439a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho                        Slog.e(TAG, "error in registerCallback", e);
18443957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                    }
18453957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                }
18463957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
18473957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                // And create sessions, if any.
1848d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim                for (IBinder sessionToken : serviceState.mSessionTokens) {
1849d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim                    createSessionInternalLocked(serviceState.mService, sessionToken, mUserId);
18503957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo                }
1851969167dc05a6485a32d160895871cff46fd81884Wonsik Kim
1852187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                for (TvInputState inputState : userState.inputMap.values()) {
18539e8ade2eb7ee835963473c9cf6faaf5423b0b048Ji-Hwan Lee                    if (inputState.mInfo.getComponent().equals(component)
1854187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                            && inputState.mState != INPUT_STATE_DISCONNECTED) {
18558e6b51b0fb810ac990c863cc0579e2b2700ab7d6Jaewan Kim                        notifyInputStateChangedLocked(userState, inputState.mInfo.getId(),
1856187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                                inputState.mState, null);
1857187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                    }
1858187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                }
1859187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim
1860187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                if (serviceState.mIsHardware) {
18614f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                    List<TvInputHardwareInfo> hardwareInfoList =
18624f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                            mTvInputHardwareManager.getHardwareList();
1863187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                    for (TvInputHardwareInfo hardwareInfo : hardwareInfoList) {
1864187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                        try {
1865187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                            serviceState.mService.notifyHardwareAdded(hardwareInfo);
1866187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                        } catch (RemoteException e) {
1867187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                            Slog.e(TAG, "error in notifyHardwareAdded", e);
1868187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                        }
1869187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                    }
1870187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim
1871546c635ad9a26421fbdf54efa765b5ab0a63c191Jae Seo                    List<HdmiDeviceInfo> deviceInfoList =
1872546c635ad9a26421fbdf54efa765b5ab0a63c191Jae Seo                            mTvInputHardwareManager.getHdmiDeviceList();
1873546c635ad9a26421fbdf54efa765b5ab0a63c191Jae Seo                    for (HdmiDeviceInfo deviceInfo : deviceInfoList) {
18744f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                        try {
1875546c635ad9a26421fbdf54efa765b5ab0a63c191Jae Seo                            serviceState.mService.notifyHdmiDeviceAdded(deviceInfo);
18764f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                        } catch (RemoteException e) {
1877546c635ad9a26421fbdf54efa765b5ab0a63c191Jae Seo                            Slog.e(TAG, "error in notifyHdmiDeviceAdded", e);
18784f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                        }
18794f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                    }
1880969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                }
18813957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            }
18823957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
18833957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
18843957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        @Override
18859e8ade2eb7ee835963473c9cf6faaf5423b0b048Ji-Hwan Lee        public void onServiceDisconnected(ComponentName component) {
18863957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            if (DEBUG) {
18879e8ade2eb7ee835963473c9cf6faaf5423b0b048Ji-Hwan Lee                Slog.d(TAG, "onServiceDisconnected(component=" + component + ")");
18883957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            }
18899e8ade2eb7ee835963473c9cf6faaf5423b0b048Ji-Hwan Lee            if (!mComponent.equals(component)) {
18902b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                throw new IllegalArgumentException("Mismatched ComponentName: "
18919e8ade2eb7ee835963473c9cf6faaf5423b0b048Ji-Hwan Lee                        + mComponent + " (expected), " + component + " (actual).");
18922b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim            }
18932b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim            synchronized (mLock) {
18942b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                UserState userState = getUserStateLocked(mUserId);
18959e8ade2eb7ee835963473c9cf6faaf5423b0b048Ji-Hwan Lee                ServiceState serviceState = userState.serviceStateMap.get(mComponent);
18962b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                if (serviceState != null) {
18972b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                    serviceState.mReconnecting = true;
18982b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                    serviceState.mBound = false;
18992b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                    serviceState.mService = null;
19002b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                    serviceState.mCallback = null;
19012b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim
19022b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                    // Send null tokens for not finishing create session events.
19032b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                    for (IBinder sessionToken : serviceState.mSessionTokens) {
19042b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                        SessionState sessionState = userState.sessionStateMap.get(sessionToken);
19052b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                        if (sessionState.mSession == null) {
19062b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                            removeSessionStateLocked(sessionToken, sessionState.mUserId);
19072b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                            sendSessionTokenToClientLocked(sessionState.mClient,
1908187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                                    sessionState.mInfo.getId(), null, null, sessionState.mSeq);
19092b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                        }
19102b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                    }
19112b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim
1912187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                    for (TvInputState inputState : userState.inputMap.values()) {
19139e8ade2eb7ee835963473c9cf6faaf5423b0b048Ji-Hwan Lee                        if (inputState.mInfo.getComponent().equals(component)) {
1914bd2fa2c02d916a9b6c62f8fd8701d779c00bd68dDongwon Kang                            notifyInputStateChangedLocked(userState, inputState.mInfo.getId(),
1915187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                                    INPUT_STATE_DISCONNECTED, null);
1916187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                        }
1917187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                    }
19189e8ade2eb7ee835963473c9cf6faaf5423b0b048Ji-Hwan Lee                    updateServiceConnectionLocked(mComponent, mUserId);
19192b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim                }
19202b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim            }
19213957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
19223957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    }
19233957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
19243957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    private final class ServiceCallback extends ITvInputServiceCallback.Stub {
19259e8ade2eb7ee835963473c9cf6faaf5423b0b048Ji-Hwan Lee        private final ComponentName mComponent;
19263957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        private final int mUserId;
19273957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
19289e8ade2eb7ee835963473c9cf6faaf5423b0b048Ji-Hwan Lee        ServiceCallback(ComponentName component, int userId) {
19299e8ade2eb7ee835963473c9cf6faaf5423b0b048Ji-Hwan Lee            mComponent = component;
19303957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            mUserId = userId;
19313957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
19323957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo
19334f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee        private void ensureHardwarePermission() {
19344f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee            if (mContext.checkCallingPermission(android.Manifest.permission.TV_INPUT_HARDWARE)
19354f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                    != PackageManager.PERMISSION_GRANTED) {
19364f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                throw new SecurityException("The caller does not have hardware permission");
19374f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee            }
19384f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee        }
19394f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee
19404f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee        private void ensureValidInput(TvInputInfo inputInfo) {
19419e8ade2eb7ee835963473c9cf6faaf5423b0b048Ji-Hwan Lee            if (inputInfo.getId() == null || !mComponent.equals(inputInfo.getComponent())) {
19424f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                throw new IllegalArgumentException("Invalid TvInputInfo");
19434f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee            }
19444f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee        }
19454f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee
19464f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee        private void addTvInputLocked(TvInputInfo inputInfo) {
19479e8ade2eb7ee835963473c9cf6faaf5423b0b048Ji-Hwan Lee            ServiceState serviceState = getServiceStateLocked(mComponent, mUserId);
19484f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee            serviceState.mInputList.add(inputInfo);
19494f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee            buildTvInputListLocked(mUserId);
19504f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee        }
19514f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee
19523957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        @Override
19534f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee        public void addHardwareTvInput(int deviceId, TvInputInfo inputInfo) {
19544f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee            ensureHardwarePermission();
19554f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee            ensureValidInput(inputInfo);
1956187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim            synchronized (mLock) {
19574f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                mTvInputHardwareManager.addHardwareTvInput(deviceId, inputInfo);
19584f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                addTvInputLocked(inputInfo);
19594f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee            }
19604f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee        }
1961187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim
19624f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee        @Override
19638960d1b1552729e3dfd33deee951ac75933ad8e5Jinsuk Kim        public void addHdmiTvInput(int id, TvInputInfo inputInfo) {
19644f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee            ensureHardwarePermission();
19654f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee            ensureValidInput(inputInfo);
19664f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee            synchronized (mLock) {
19678960d1b1552729e3dfd33deee951ac75933ad8e5Jinsuk Kim                mTvInputHardwareManager.addHdmiTvInput(id, inputInfo);
19684f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                addTvInputLocked(inputInfo);
19693957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            }
1970187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim        }
1971187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim
1972187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim        @Override
1973187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim        public void removeTvInput(String inputId) {
19744f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee            ensureHardwarePermission();
19753957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            synchronized (mLock) {
19769e8ade2eb7ee835963473c9cf6faaf5423b0b048Ji-Hwan Lee                ServiceState serviceState = getServiceStateLocked(mComponent, mUserId);
1977187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                boolean removed = false;
1978187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                for (Iterator<TvInputInfo> it = serviceState.mInputList.iterator();
1979187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                        it.hasNext(); ) {
1980187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                    if (it.next().getId().equals(inputId)) {
1981187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                        it.remove();
1982187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                        removed = true;
1983187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                        break;
1984187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                    }
1985187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                }
1986187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                if (removed) {
1987187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                    buildTvInputListLocked(mUserId);
19884f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                    mTvInputHardwareManager.removeTvInput(inputId);
1989187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                } else {
1990187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                    Slog.e(TAG, "TvInputInfo with inputId=" + inputId + " not found.");
1991187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                }
19923957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo            }
19933957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo        }
19943957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo    }
199531dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo
19967eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo    private final class WatchLogHandler extends Handler {
19977eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo        // There are only two kinds of watch events that can happen on the system:
19987eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo        // 1. The current TV input session is tuned to a new channel.
19997eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo        // 2. The session is released for some reason.
20007eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo        // The former indicates the end of the previous log entry, if any, followed by the start of
20017eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo        // a new entry. The latter indicates the end of the most recent entry for the given session.
20027eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo        // Here the system supplies the database the smallest set of information only that is
20037eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo        // sufficient to consolidate the log entries while minimizing database operations in the
20047eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo        // system service.
20057eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo        private static final int MSG_LOG_WATCH_START = 1;
20067eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo        private static final int MSG_LOG_WATCH_END = 2;
20077eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo
20087eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo        public WatchLogHandler(Looper looper) {
200931dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo            super(looper);
201031dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo        }
201131dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo
201231dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo        @Override
201331dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo        public void handleMessage(Message msg) {
201431dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo            switch (msg.what) {
20157eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo                case MSG_LOG_WATCH_START: {
201631dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                    SomeArgs args = (SomeArgs) msg.obj;
20177eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo                    String packageName = (String) args.arg1;
20187eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo                    long watchStartTime = (long) args.arg2;
20197eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo                    long channelId = (long) args.arg3;
20207eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo                    Bundle tuneParams = (Bundle) args.arg4;
20217eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo                    IBinder sessionToken = (IBinder) args.arg5;
20227eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo
20237eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo                    ContentValues values = new ContentValues();
20247eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo                    values.put(TvContract.WatchedPrograms.COLUMN_PACKAGE_NAME, packageName);
20257eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo                    values.put(TvContract.WatchedPrograms.COLUMN_WATCH_START_TIME_UTC_MILLIS,
20267eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo                            watchStartTime);
20277eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo                    values.put(TvContract.WatchedPrograms.COLUMN_CHANNEL_ID, channelId);
20287eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo                    if (tuneParams != null) {
20297eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo                        values.put(TvContract.WatchedPrograms.COLUMN_INTERNAL_TUNE_PARAMS,
20307eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo                                encodeTuneParams(tuneParams));
20317eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo                    }
20327eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo                    values.put(TvContract.WatchedPrograms.COLUMN_INTERNAL_SESSION_TOKEN,
20337eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo                            sessionToken.toString());
20347eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo
20357eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo                    mContentResolver.insert(TvContract.WatchedPrograms.CONTENT_URI, values);
203631dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                    args.recycle();
203731dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                    return;
203831dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                }
20397eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo                case MSG_LOG_WATCH_END: {
204031dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                    SomeArgs args = (SomeArgs) msg.obj;
20417eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo                    IBinder sessionToken = (IBinder) args.arg1;
20427eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo                    long watchEndTime = (long) args.arg2;
20437eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo
20447eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo                    ContentValues values = new ContentValues();
20457eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo                    values.put(TvContract.WatchedPrograms.COLUMN_WATCH_END_TIME_UTC_MILLIS,
20467eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo                            watchEndTime);
20477eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo                    values.put(TvContract.WatchedPrograms.COLUMN_INTERNAL_SESSION_TOKEN,
20487eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo                            sessionToken.toString());
20497eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo
20507eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo                    mContentResolver.insert(TvContract.WatchedPrograms.CONTENT_URI, values);
205131dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                    args.recycle();
205231dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                    return;
205331dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                }
205431dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                default: {
20556a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo                    Slog.w(TAG, "Unhandled message code: " + msg.what);
205631dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                    return;
205731dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                }
205831dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo            }
205931dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo        }
206031dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo
20617eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo        private String encodeTuneParams(Bundle tuneParams) {
20627eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo            StringBuilder builder = new StringBuilder();
20637eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo            Set<String> keySet = tuneParams.keySet();
20647eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo            Iterator<String> it = keySet.iterator();
20657eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo            while (it.hasNext()) {
20667eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo                String key = it.next();
20677eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo                Object value = tuneParams.get(key);
20687eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo                if (value == null) {
20697eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo                    continue;
207031dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                }
20717eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo                builder.append(replaceEscapeCharacters(key));
20727eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo                builder.append("=");
20737eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo                builder.append(replaceEscapeCharacters(value.toString()));
20747eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo                if (it.hasNext()) {
20757eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo                    builder.append(", ");
207631dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo                }
207731dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo            }
20787eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo            return builder.toString();
207931dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo        }
208031dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo
20817eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo        private String replaceEscapeCharacters(String src) {
20827eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo            final char ESCAPE_CHARACTER = '%';
20837eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo            final String ENCODING_TARGET_CHARACTERS = "%=,";
20847eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo            StringBuilder builder = new StringBuilder();
20857eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo            for (char ch : src.toCharArray()) {
20867eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo                if (ENCODING_TARGET_CHARACTERS.indexOf(ch) >= 0) {
20877eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo                    builder.append(ESCAPE_CHARACTER);
2088579befecb248162021929ab58ffd23f1724cc6beJae Seo                }
20897eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo                builder.append(ch);
2090579befecb248162021929ab58ffd23f1724cc6beJae Seo            }
20917eb75dff7a0fb4b19c3e801cd388483d7d471f41Jae Seo            return builder.toString();
2092579befecb248162021929ab58ffd23f1724cc6beJae Seo        }
209331dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo    }
2094969167dc05a6485a32d160895871cff46fd81884Wonsik Kim
2095187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim    final class HardwareListener implements TvInputHardwareManager.Listener {
2096187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim        @Override
2097187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim        public void onStateChanged(String inputId, int state) {
2098969167dc05a6485a32d160895871cff46fd81884Wonsik Kim            synchronized (mLock) {
2099969167dc05a6485a32d160895871cff46fd81884Wonsik Kim                setStateLocked(inputId, state, mCurrentUserId);
2100969167dc05a6485a32d160895871cff46fd81884Wonsik Kim            }
2101969167dc05a6485a32d160895871cff46fd81884Wonsik Kim        }
2102187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim
2103187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim        @Override
2104187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim        public void onHardwareDeviceAdded(TvInputHardwareInfo info) {
2105187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim            synchronized (mLock) {
2106187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                UserState userState = getUserStateLocked(mCurrentUserId);
2107187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                // Broadcast the event to all hardware inputs.
2108187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                for (ServiceState serviceState : userState.serviceStateMap.values()) {
2109187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                    if (!serviceState.mIsHardware || serviceState.mService == null) continue;
2110187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                    try {
2111187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                        serviceState.mService.notifyHardwareAdded(info);
2112187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                    } catch (RemoteException e) {
2113187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                        Slog.e(TAG, "error in notifyHardwareAdded", e);
2114187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                    }
2115187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                }
2116187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim            }
2117187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim        }
2118187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim
2119187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim        @Override
21204f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee        public void onHardwareDeviceRemoved(TvInputHardwareInfo info) {
2121187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim            synchronized (mLock) {
2122187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                UserState userState = getUserStateLocked(mCurrentUserId);
2123187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                // Broadcast the event to all hardware inputs.
2124187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                for (ServiceState serviceState : userState.serviceStateMap.values()) {
2125187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                    if (!serviceState.mIsHardware || serviceState.mService == null) continue;
2126187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                    try {
21274f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                        serviceState.mService.notifyHardwareRemoved(info);
2128187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                    } catch (RemoteException e) {
2129187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                        Slog.e(TAG, "error in notifyHardwareRemoved", e);
2130187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                    }
2131187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim                }
2132187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim            }
2133187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim        }
2134187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim
2135187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim        @Override
2136546c635ad9a26421fbdf54efa765b5ab0a63c191Jae Seo        public void onHdmiDeviceAdded(HdmiDeviceInfo deviceInfo) {
2137187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim            synchronized (mLock) {
21384f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                UserState userState = getUserStateLocked(mCurrentUserId);
21394f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                // Broadcast the event to all hardware inputs.
21404f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                for (ServiceState serviceState : userState.serviceStateMap.values()) {
21414f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                    if (!serviceState.mIsHardware || serviceState.mService == null) continue;
21424f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                    try {
2143546c635ad9a26421fbdf54efa765b5ab0a63c191Jae Seo                        serviceState.mService.notifyHdmiDeviceAdded(deviceInfo);
21444f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                    } catch (RemoteException e) {
2145546c635ad9a26421fbdf54efa765b5ab0a63c191Jae Seo                        Slog.e(TAG, "error in notifyHdmiDeviceAdded", e);
21464f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                    }
21474f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                }
2148187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim            }
2149187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim        }
2150187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim
2151187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim        @Override
2152546c635ad9a26421fbdf54efa765b5ab0a63c191Jae Seo        public void onHdmiDeviceRemoved(HdmiDeviceInfo deviceInfo) {
2153187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim            synchronized (mLock) {
21544f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                UserState userState = getUserStateLocked(mCurrentUserId);
21554f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                // Broadcast the event to all hardware inputs.
21564f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                for (ServiceState serviceState : userState.serviceStateMap.values()) {
21574f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                    if (!serviceState.mIsHardware || serviceState.mService == null) continue;
21584f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                    try {
2159546c635ad9a26421fbdf54efa765b5ab0a63c191Jae Seo                        serviceState.mService.notifyHdmiDeviceRemoved(deviceInfo);
21604f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                    } catch (RemoteException e) {
2161546c635ad9a26421fbdf54efa765b5ab0a63c191Jae Seo                        Slog.e(TAG, "error in notifyHdmiDeviceRemoved", e);
21624f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                    }
21634f9f57cede3de2e2aa3045e04b485b176ab22dbdJi-Hwan Lee                }
2164187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim            }
2165187423c0bc4b27479bc8c23bd86969429094b296Wonsik Kim        }
216661daf6b38e7a7ada2a6ca5a60539a54b9c6810bdJungshik Jang
216761daf6b38e7a7ada2a6ca5a60539a54b9c6810bdJungshik Jang        @Override
2168e92f857d50d7259a4cf7ef5b88309e098338c9c1Wonsik Kim        public void onHdmiDeviceUpdated(String inputId, HdmiDeviceInfo deviceInfo) {
2169e92f857d50d7259a4cf7ef5b88309e098338c9c1Wonsik Kim            synchronized (mLock) {
2170e92f857d50d7259a4cf7ef5b88309e098338c9c1Wonsik Kim                Integer state = null;
2171e92f857d50d7259a4cf7ef5b88309e098338c9c1Wonsik Kim                switch (deviceInfo.getDevicePowerStatus()) {
2172e92f857d50d7259a4cf7ef5b88309e098338c9c1Wonsik Kim                    case HdmiControlManager.POWER_STATUS_ON:
2173e92f857d50d7259a4cf7ef5b88309e098338c9c1Wonsik Kim                        state = INPUT_STATE_CONNECTED;
2174e92f857d50d7259a4cf7ef5b88309e098338c9c1Wonsik Kim                        break;
2175e92f857d50d7259a4cf7ef5b88309e098338c9c1Wonsik Kim                    case HdmiControlManager.POWER_STATUS_STANDBY:
2176e92f857d50d7259a4cf7ef5b88309e098338c9c1Wonsik Kim                    case HdmiControlManager.POWER_STATUS_TRANSIENT_TO_ON:
2177e92f857d50d7259a4cf7ef5b88309e098338c9c1Wonsik Kim                    case HdmiControlManager.POWER_STATUS_TRANSIENT_TO_STANDBY:
2178e92f857d50d7259a4cf7ef5b88309e098338c9c1Wonsik Kim                        state = INPUT_STATE_CONNECTED_STANDBY;
2179e92f857d50d7259a4cf7ef5b88309e098338c9c1Wonsik Kim                        break;
2180e92f857d50d7259a4cf7ef5b88309e098338c9c1Wonsik Kim                    case HdmiControlManager.POWER_STATUS_UNKNOWN:
2181e92f857d50d7259a4cf7ef5b88309e098338c9c1Wonsik Kim                    default:
2182e92f857d50d7259a4cf7ef5b88309e098338c9c1Wonsik Kim                        state = null;
2183e92f857d50d7259a4cf7ef5b88309e098338c9c1Wonsik Kim                        break;
2184e92f857d50d7259a4cf7ef5b88309e098338c9c1Wonsik Kim                }
2185e92f857d50d7259a4cf7ef5b88309e098338c9c1Wonsik Kim                if (state != null) {
2186e92f857d50d7259a4cf7ef5b88309e098338c9c1Wonsik Kim                    setStateLocked(inputId, state.intValue(), mCurrentUserId);
2187e92f857d50d7259a4cf7ef5b88309e098338c9c1Wonsik Kim                }
2188e92f857d50d7259a4cf7ef5b88309e098338c9c1Wonsik Kim            }
218961daf6b38e7a7ada2a6ca5a60539a54b9c6810bdJungshik Jang        }
2190969167dc05a6485a32d160895871cff46fd81884Wonsik Kim    }
21913957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo}
2192