TvInputManagerService.java revision a3be12a236aef0d9c4ff1274075f1e7899d29153
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 193957091ba8f08c02b5e781098cb955a5f697a1ffJae Seoimport android.app.ActivityManager; 203957091ba8f08c02b5e781098cb955a5f697a1ffJae Seoimport android.content.BroadcastReceiver; 213957091ba8f08c02b5e781098cb955a5f697a1ffJae Seoimport android.content.ComponentName; 2231dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seoimport android.content.ContentResolver; 2331dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seoimport android.content.ContentUris; 2431dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seoimport android.content.ContentValues; 253957091ba8f08c02b5e781098cb955a5f697a1ffJae Seoimport android.content.Context; 263957091ba8f08c02b5e781098cb955a5f697a1ffJae Seoimport android.content.Intent; 273957091ba8f08c02b5e781098cb955a5f697a1ffJae Seoimport android.content.IntentFilter; 283957091ba8f08c02b5e781098cb955a5f697a1ffJae Seoimport android.content.ServiceConnection; 293957091ba8f08c02b5e781098cb955a5f697a1ffJae Seoimport android.content.pm.PackageManager; 303957091ba8f08c02b5e781098cb955a5f697a1ffJae Seoimport android.content.pm.ResolveInfo; 313957091ba8f08c02b5e781098cb955a5f697a1ffJae Seoimport android.content.pm.ServiceInfo; 3231dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seoimport android.database.Cursor; 339a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Choimport android.graphics.Rect; 34d5cc4a281e7ce29d1e8687ff3394b57a3a549260Jae Seoimport android.media.tv.ITvInputClient; 35d5cc4a281e7ce29d1e8687ff3394b57a3a549260Jae Seoimport android.media.tv.ITvInputHardware; 36d5cc4a281e7ce29d1e8687ff3394b57a3a549260Jae Seoimport android.media.tv.ITvInputHardwareCallback; 37d5cc4a281e7ce29d1e8687ff3394b57a3a549260Jae Seoimport android.media.tv.ITvInputManager; 38d5cc4a281e7ce29d1e8687ff3394b57a3a549260Jae Seoimport android.media.tv.ITvInputService; 39d5cc4a281e7ce29d1e8687ff3394b57a3a549260Jae Seoimport android.media.tv.ITvInputServiceCallback; 40d5cc4a281e7ce29d1e8687ff3394b57a3a549260Jae Seoimport android.media.tv.ITvInputSession; 41d5cc4a281e7ce29d1e8687ff3394b57a3a549260Jae Seoimport android.media.tv.ITvInputSessionCallback; 42d5cc4a281e7ce29d1e8687ff3394b57a3a549260Jae Seoimport android.media.tv.TvContract; 43d5cc4a281e7ce29d1e8687ff3394b57a3a549260Jae Seoimport android.media.tv.TvInputHardwareInfo; 44d5cc4a281e7ce29d1e8687ff3394b57a3a549260Jae Seoimport android.media.tv.TvInputInfo; 45d5cc4a281e7ce29d1e8687ff3394b57a3a549260Jae Seoimport android.media.tv.TvInputService; 463957091ba8f08c02b5e781098cb955a5f697a1ffJae Seoimport android.net.Uri; 473957091ba8f08c02b5e781098cb955a5f697a1ffJae Seoimport android.os.Binder; 48832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Choimport android.os.Bundle; 4931dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seoimport android.os.Handler; 503957091ba8f08c02b5e781098cb955a5f697a1ffJae Seoimport android.os.IBinder; 5131dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seoimport android.os.Looper; 5231dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seoimport android.os.Message; 533957091ba8f08c02b5e781098cb955a5f697a1ffJae Seoimport android.os.Process; 543957091ba8f08c02b5e781098cb955a5f697a1ffJae Seoimport android.os.RemoteException; 553957091ba8f08c02b5e781098cb955a5f697a1ffJae Seoimport android.os.UserHandle; 569a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Choimport android.util.Slog; 573957091ba8f08c02b5e781098cb955a5f697a1ffJae Seoimport android.util.SparseArray; 586a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seoimport android.view.InputChannel; 593957091ba8f08c02b5e781098cb955a5f697a1ffJae Seoimport android.view.Surface; 603957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo 613957091ba8f08c02b5e781098cb955a5f697a1ffJae Seoimport com.android.internal.content.PackageMonitor; 6231dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seoimport com.android.internal.os.SomeArgs; 6331dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seoimport com.android.server.IoThread; 643957091ba8f08c02b5e781098cb955a5f697a1ffJae Seoimport com.android.server.SystemService; 653957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo 66e7bb7d6bb2257c24076f5a4b9f536f90a6637f58Chulwoo Leeimport org.xmlpull.v1.XmlPullParserException; 67e7bb7d6bb2257c24076f5a4b9f536f90a6637f58Chulwoo Lee 68e7bb7d6bb2257c24076f5a4b9f536f90a6637f58Chulwoo Leeimport java.io.IOException; 69e7bb7d6bb2257c24076f5a4b9f536f90a6637f58Chulwoo Lee 703957091ba8f08c02b5e781098cb955a5f697a1ffJae Seoimport java.util.ArrayList; 713957091ba8f08c02b5e781098cb955a5f697a1ffJae Seoimport java.util.HashMap; 723957091ba8f08c02b5e781098cb955a5f697a1ffJae Seoimport java.util.List; 733957091ba8f08c02b5e781098cb955a5f697a1ffJae Seoimport java.util.Map; 743957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo 753957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo/** This class provides a system service that manages television inputs. */ 763957091ba8f08c02b5e781098cb955a5f697a1ffJae Seopublic final class TvInputManagerService extends SystemService { 773957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo // STOPSHIP: Turn debugging off. 783957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo private static final boolean DEBUG = true; 793957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo private static final String TAG = "TvInputManagerService"; 803957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo 813957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo private final Context mContext; 82c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim private final TvInputHardwareManager mTvInputHardwareManager; 833957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo 8431dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo private final ContentResolver mContentResolver; 8531dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo 863957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo // A global lock. 873957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo private final Object mLock = new Object(); 883957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo 893957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo // ID of the current user. 903957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo private int mCurrentUserId = UserHandle.USER_OWNER; 913957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo 923957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo // A map from user id to UserState. 933957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo private final SparseArray<UserState> mUserStates = new SparseArray<UserState>(); 943957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo 9531dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo private final Handler mLogHandler; 9631dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo 973957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo public TvInputManagerService(Context context) { 983957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo super(context); 9931dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo 1003957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo mContext = context; 10131dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo mContentResolver = context.getContentResolver(); 10231dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo mLogHandler = new LogHandler(IoThread.get().getLooper()); 10331dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo 104c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim mTvInputHardwareManager = new TvInputHardwareManager(context); 1053957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo registerBroadcastReceivers(); 10631dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo 1073957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo synchronized (mLock) { 1083957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo mUserStates.put(mCurrentUserId, new UserState()); 1093957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo buildTvInputListLocked(mCurrentUserId); 1103957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 1113957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 1123957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo 1133957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo @Override 1143957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo public void onStart() { 1153957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo publishBinderService(Context.TV_INPUT_SERVICE, new BinderService()); 1163957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 1173957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo 1183957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo private void registerBroadcastReceivers() { 1193957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo PackageMonitor monitor = new PackageMonitor() { 1203957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo @Override 1213957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo public void onSomePackagesChanged() { 1223957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo synchronized (mLock) { 1233957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo buildTvInputListLocked(mCurrentUserId); 1243957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 1253957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 1263957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo }; 1273957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo monitor.register(mContext, null, UserHandle.ALL, true); 1283957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo 1293957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo IntentFilter intentFilter = new IntentFilter(); 1303957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo intentFilter.addAction(Intent.ACTION_USER_SWITCHED); 1313957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo intentFilter.addAction(Intent.ACTION_USER_REMOVED); 1323957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo mContext.registerReceiverAsUser(new BroadcastReceiver() { 1333957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo @Override 1343957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo public void onReceive(Context context, Intent intent) { 1353957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo String action = intent.getAction(); 1363957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo if (Intent.ACTION_USER_SWITCHED.equals(action)) { 1373957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo switchUser(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0)); 1383957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } else if (Intent.ACTION_USER_REMOVED.equals(action)) { 1393957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo removeUser(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0)); 1403957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 1413957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 1423957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo }, UserHandle.ALL, intentFilter, null, null); 1433957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 1443957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo 1453957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo private void buildTvInputListLocked(int userId) { 1463957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo UserState userState = getUserStateLocked(userId); 147d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim userState.inputMap.clear(); 1483957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo 1499a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho if (DEBUG) Slog.d(TAG, "buildTvInputList"); 1503957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo PackageManager pm = mContext.getPackageManager(); 1513957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo List<ResolveInfo> services = pm.queryIntentServices( 152e7bb7d6bb2257c24076f5a4b9f536f90a6637f58Chulwoo Lee new Intent(TvInputService.SERVICE_INTERFACE), 153e7bb7d6bb2257c24076f5a4b9f536f90a6637f58Chulwoo Lee PackageManager.GET_SERVICES | PackageManager.GET_META_DATA); 1543957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo for (ResolveInfo ri : services) { 1553957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo ServiceInfo si = ri.serviceInfo; 1563957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo if (!android.Manifest.permission.BIND_TV_INPUT.equals(si.permission)) { 1579a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho Slog.w(TAG, "Skipping TV input " + si.name + ": it does not require the permission " 1583957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo + android.Manifest.permission.BIND_TV_INPUT); 1593957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo continue; 1603957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 161e7bb7d6bb2257c24076f5a4b9f536f90a6637f58Chulwoo Lee try { 162e7bb7d6bb2257c24076f5a4b9f536f90a6637f58Chulwoo Lee TvInputInfo info = TvInputInfo.createTvInputInfo(mContext, ri); 163e7bb7d6bb2257c24076f5a4b9f536f90a6637f58Chulwoo Lee if (DEBUG) Slog.d(TAG, "add " + info.getId()); 164e7bb7d6bb2257c24076f5a4b9f536f90a6637f58Chulwoo Lee userState.inputMap.put(info.getId(), info); 165e7bb7d6bb2257c24076f5a4b9f536f90a6637f58Chulwoo Lee } catch (IOException | XmlPullParserException e) { 166e7bb7d6bb2257c24076f5a4b9f536f90a6637f58Chulwoo Lee Slog.e(TAG, "Can't load TV input " + si.name, e); 167e7bb7d6bb2257c24076f5a4b9f536f90a6637f58Chulwoo Lee } 1683957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 1693957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 1703957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo 1713957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo private void switchUser(int userId) { 1723957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo synchronized (mLock) { 1733957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo if (mCurrentUserId == userId) { 1743957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo return; 1753957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 1763957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo // final int oldUserId = mCurrentUserId; 1773957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo // TODO: Release services and sessions in the old user state, if needed. 1783957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo mCurrentUserId = userId; 1793957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo 1803957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo UserState userState = mUserStates.get(userId); 1813957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo if (userState == null) { 1823957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo userState = new UserState(); 1833957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 1843957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo mUserStates.put(userId, userState); 1853957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo buildTvInputListLocked(userId); 1863957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 1873957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 1883957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo 1893957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo private void removeUser(int userId) { 1903957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo synchronized (mLock) { 191b06cb8870f0407f18bb1225065a93aba2a5de2bfJae Seo UserState userState = mUserStates.get(userId); 192b06cb8870f0407f18bb1225065a93aba2a5de2bfJae Seo if (userState == null) { 193b06cb8870f0407f18bb1225065a93aba2a5de2bfJae Seo return; 194b06cb8870f0407f18bb1225065a93aba2a5de2bfJae Seo } 1953957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo // Release created sessions. 1963957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo for (SessionState state : userState.sessionStateMap.values()) { 197d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim if (state.mSession != null) { 1983957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo try { 199d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim state.mSession.release(); 2003957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } catch (RemoteException e) { 2019a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho Slog.e(TAG, "error in release", e); 2023957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 2033957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 2043957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 2053957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo userState.sessionStateMap.clear(); 2063957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo 2073957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo // Unregister all callbacks and unbind all services. 2083957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo for (ServiceState serviceState : userState.serviceStateMap.values()) { 209d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim if (serviceState.mCallback != null) { 2103957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo try { 211d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim serviceState.mService.unregisterCallback(serviceState.mCallback); 2123957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } catch (RemoteException e) { 2139a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho Slog.e(TAG, "error in unregisterCallback", e); 2143957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 2153957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 216d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim serviceState.mClients.clear(); 217d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim mContext.unbindService(serviceState.mConnection); 2183957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 2193957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo userState.serviceStateMap.clear(); 2203957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo 2213957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo mUserStates.remove(userId); 2223957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 2233957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 2243957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo 2253957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo private UserState getUserStateLocked(int userId) { 2263957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo UserState userState = mUserStates.get(userId); 2273957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo if (userState == null) { 2283957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo throw new IllegalStateException("User state not found for user ID " + userId); 2293957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 2303957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo return userState; 2313957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 2323957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo 233d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim private ServiceState getServiceStateLocked(String inputId, int userId) { 2343957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo UserState userState = getUserStateLocked(userId); 235d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim ServiceState serviceState = userState.serviceStateMap.get(inputId); 2363957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo if (serviceState == null) { 237d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim throw new IllegalStateException("Service state not found for " + inputId + " (userId=" 2387de5e234715a3baa8905afa3dd0c5009af64541fSungsoo Lim + userId + ")"); 2393957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 2403957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo return serviceState; 2413957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 2423957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo 2432b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim private SessionState getSessionStateLocked(IBinder sessionToken, int callingUid, int userId) { 2443957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo UserState userState = getUserStateLocked(userId); 2453957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo SessionState sessionState = userState.sessionStateMap.get(sessionToken); 2463957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo if (sessionState == null) { 2473957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo throw new IllegalArgumentException("Session state not found for token " + sessionToken); 2483957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 2493957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo // Only the application that requested this session or the system can access it. 250d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim if (callingUid != Process.SYSTEM_UID && callingUid != sessionState.mCallingUid) { 2513957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo throw new SecurityException("Illegal access to the session with token " + sessionToken 2523957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo + " from uid " + callingUid); 2533957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 2542b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim return sessionState; 2552b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim } 2562b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim 2572b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim private ITvInputSession getSessionLocked(IBinder sessionToken, int callingUid, int userId) { 2582b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim SessionState sessionState = getSessionStateLocked(sessionToken, callingUid, userId); 259d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim ITvInputSession session = sessionState.mSession; 2603957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo if (session == null) { 2613957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo throw new IllegalStateException("Session not yet created for token " + sessionToken); 2623957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 2633957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo return session; 2643957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 2653957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo 2663957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo private int resolveCallingUserId(int callingPid, int callingUid, int requestedUserId, 2673957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo String methodName) { 2683957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo return ActivityManager.handleIncomingUser(callingPid, callingUid, requestedUserId, false, 2693957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo false, methodName, null); 2703957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 2713957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo 272d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim private void updateServiceConnectionLocked(String inputId, int userId) { 2733957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo UserState userState = getUserStateLocked(userId); 274d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim ServiceState serviceState = userState.serviceStateMap.get(inputId); 2753957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo if (serviceState == null) { 2763957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo return; 2773957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 2782b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim if (serviceState.mReconnecting) { 2792b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim if (!serviceState.mSessionTokens.isEmpty()) { 2802b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim // wait until all the sessions are removed. 2812b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim return; 2822b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim } 2832b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim serviceState.mReconnecting = false; 2842b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim } 285d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim boolean isStateEmpty = serviceState.mClients.isEmpty() 286d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim && serviceState.mSessionTokens.isEmpty(); 287d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim if (serviceState.mService == null && !isStateEmpty && userId == mCurrentUserId) { 2883957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo // This means that the service is not yet connected but its state indicates that we 2893957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo // have pending requests. Then, connect the service. 290d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim if (serviceState.mBound) { 2913957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo // We have already bound to the service so we don't try to bind again until after we 2923957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo // unbind later on. 2933957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo return; 2943957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 2953957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo if (DEBUG) { 296d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim Slog.d(TAG, "bindServiceAsUser(inputId=" + inputId + ", userId=" + userId 2973957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo + ")"); 2983957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 299d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim 300d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim Intent i = new Intent(TvInputService.SERVICE_INTERFACE).setComponent( 301d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim userState.inputMap.get(inputId).getComponent()); 302d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim mContext.bindServiceAsUser(i, serviceState.mConnection, Context.BIND_AUTO_CREATE, 3033957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo new UserHandle(userId)); 304d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim serviceState.mBound = true; 305d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim } else if (serviceState.mService != null && isStateEmpty) { 3063957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo // This means that the service is already connected but its state indicates that we have 3073957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo // nothing to do with it. Then, disconnect the service. 3083957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo if (DEBUG) { 309d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim Slog.d(TAG, "unbindService(inputId=" + inputId + ")"); 3103957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 311d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim mContext.unbindService(serviceState.mConnection); 312d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim userState.serviceStateMap.remove(inputId); 3133957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 3143957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 3153957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo 3163957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo private void createSessionInternalLocked(ITvInputService service, final IBinder sessionToken, 3177de5e234715a3baa8905afa3dd0c5009af64541fSungsoo Lim final int userId) { 3187de5e234715a3baa8905afa3dd0c5009af64541fSungsoo Lim final SessionState sessionState = 3197de5e234715a3baa8905afa3dd0c5009af64541fSungsoo Lim getUserStateLocked(userId).sessionStateMap.get(sessionToken); 3203957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo if (DEBUG) { 321d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim Slog.d(TAG, "createSessionInternalLocked(inputId=" + sessionState.mInputId + ")"); 3223957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 3236a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo 3246a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo final InputChannel[] channels = InputChannel.openInputChannelPair(sessionToken.toString()); 3256a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo 3263957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo // Set up a callback to send the session token. 3273957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo ITvInputSessionCallback callback = new ITvInputSessionCallback.Stub() { 3283957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo @Override 3293957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo public void onSessionCreated(ITvInputSession session) { 3303957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo if (DEBUG) { 331d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim Slog.d(TAG, "onSessionCreated(inputId=" + sessionState.mInputId + ")"); 3323957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 3333957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo synchronized (mLock) { 334d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim sessionState.mSession = session; 335fd5b72f1ed2ee74a4204eef65f560fc82f0b62feDongwon Kang if (session == null) { 336fd5b72f1ed2ee74a4204eef65f560fc82f0b62feDongwon Kang removeSessionStateLocked(sessionToken, userId); 3372b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim sendSessionTokenToClientLocked(sessionState.mClient, sessionState.mInputId, 3382b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim null, null, sessionState.mSeq, userId); 339fd5b72f1ed2ee74a4204eef65f560fc82f0b62feDongwon Kang } else { 3402b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim try { 3412b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim session.asBinder().linkToDeath(sessionState, 0); 3422b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim } catch (RemoteException e) { 3432b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim Slog.e(TAG, "Session is already died."); 3442b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim } 345d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim sendSessionTokenToClientLocked(sessionState.mClient, sessionState.mInputId, 346d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim sessionToken, channels[0], sessionState.mSeq, userId); 347fd5b72f1ed2ee74a4204eef65f560fc82f0b62feDongwon Kang } 3486a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo channels[0].dispose(); 3493957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 3503957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 351832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho 352832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho @Override 353a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang public void onVideoStreamChanged(int width, int height, boolean interlaced) { 354832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho synchronized (mLock) { 355832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho if (DEBUG) { 356a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang Slog.d(TAG, "onVideoStreamChanged(" + width + ", " + height + ")"); 357832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho } 358832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho if (sessionState.mSession == null || sessionState.mClient == null) { 359832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho return; 360832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho } 361832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho try { 362a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang sessionState.mClient.onVideoStreamChanged(width, height, interlaced, 363a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang sessionState.mSeq); 364832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho } catch (RemoteException e) { 365a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang Slog.e(TAG, "error in onVideoStreamChanged"); 366a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang } 367a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang } 368a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang } 369a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang 370a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang @Override 371a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang public void onAudioStreamChanged(int channelCount) { 372a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang synchronized (mLock) { 373a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang if (DEBUG) { 374a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang Slog.d(TAG, "onAudioStreamChanged(" + channelCount + ")"); 375a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang } 376a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang if (sessionState.mSession == null || sessionState.mClient == null) { 377a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang return; 378a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang } 379a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang try { 380a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang sessionState.mClient.onAudioStreamChanged(channelCount, sessionState.mSeq); 381a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang } catch (RemoteException e) { 382a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang Slog.e(TAG, "error in onAudioStreamChanged"); 383a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang } 384a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang } 385a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang } 386a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang 387a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang @Override 388a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang public void onClosedCaptionStreamChanged(boolean hasClosedCaption) { 389a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang synchronized (mLock) { 390a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang if (DEBUG) { 391a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang Slog.d(TAG, "onClosedCaptionStreamChanged(" + hasClosedCaption + ")"); 392a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang } 393a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang if (sessionState.mSession == null || sessionState.mClient == null) { 394a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang return; 395a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang } 396a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang try { 397a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang sessionState.mClient.onClosedCaptionStreamChanged(hasClosedCaption, 398a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang sessionState.mSeq); 399a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang } catch (RemoteException e) { 400a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang Slog.e(TAG, "error in onClosedCaptionStreamChanged"); 401832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho } 402832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho } 403832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho } 404832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho 405832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho @Override 406832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho public void onSessionEvent(String eventType, Bundle eventArgs) { 407832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho synchronized (mLock) { 408832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho if (DEBUG) { 409832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho Slog.d(TAG, "onEvent(what=" + eventType + ", data=" + eventArgs + ")"); 410832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho } 411832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho if (sessionState.mSession == null || sessionState.mClient == null) { 412832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho return; 413832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho } 414832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho try { 415832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho sessionState.mClient.onSessionEvent(eventType, eventArgs, 416832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho sessionState.mSeq); 417832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho } catch (RemoteException e) { 418832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho Slog.e(TAG, "error in onSessionEvent"); 419832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho } 420832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho } 421832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho } 4223957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo }; 4233957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo 4243957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo // Create a session. When failed, send a null token immediately. 4253957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo try { 4266a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo service.createSession(channels[1], callback); 4273957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } catch (RemoteException e) { 4289a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho Slog.e(TAG, "error in createSession", e); 429fd5b72f1ed2ee74a4204eef65f560fc82f0b62feDongwon Kang removeSessionStateLocked(sessionToken, userId); 430d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim sendSessionTokenToClientLocked(sessionState.mClient, sessionState.mInputId, null, null, 431d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim sessionState.mSeq, userId); 4323957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 4336a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo channels[1].dispose(); 4343957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 4353957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo 436d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim private void sendSessionTokenToClientLocked(ITvInputClient client, String inputId, 4376a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo IBinder sessionToken, InputChannel channel, int seq, int userId) { 4383957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo try { 439d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim client.onSessionCreated(inputId, sessionToken, channel, seq); 4403957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } catch (RemoteException exception) { 4419a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho Slog.e(TAG, "error in onSessionCreated", exception); 4423957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 4432b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim } 4443957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo 4452b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim private void releaseSessionLocked(IBinder sessionToken, int callingUid, int userId) { 4462b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim SessionState sessionState = getSessionStateLocked(sessionToken, callingUid, userId); 4472b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim if (sessionState.mSession != null) { 4482b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim try { 4492b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim sessionState.mSession.release(); 4502b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim } catch (RemoteException e) { 4512b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim Slog.w(TAG, "session is already disapeared", e); 4522b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim } 4532b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim sessionState.mSession = null; 4543957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 4552b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim removeSessionStateLocked(sessionToken, userId); 4563957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 4573957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo 458fd5b72f1ed2ee74a4204eef65f560fc82f0b62feDongwon Kang private void removeSessionStateLocked(IBinder sessionToken, int userId) { 459fd5b72f1ed2ee74a4204eef65f560fc82f0b62feDongwon Kang // Remove the session state from the global session state map of the current user. 460fd5b72f1ed2ee74a4204eef65f560fc82f0b62feDongwon Kang UserState userState = getUserStateLocked(userId); 461fd5b72f1ed2ee74a4204eef65f560fc82f0b62feDongwon Kang SessionState sessionState = userState.sessionStateMap.remove(sessionToken); 462fd5b72f1ed2ee74a4204eef65f560fc82f0b62feDongwon Kang 46331dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo // Close the open log entry, if any. 464d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim if (sessionState.mLogUri != null) { 46531dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo SomeArgs args = SomeArgs.obtain(); 466d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim args.arg1 = sessionState.mLogUri; 46731dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo args.arg2 = System.currentTimeMillis(); 46831dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo mLogHandler.obtainMessage(LogHandler.MSG_CLOSE_ENTRY, args).sendToTarget(); 46931dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo } 47031dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo 4717de5e234715a3baa8905afa3dd0c5009af64541fSungsoo Lim // Also remove the session token from the session token list of the current service. 472d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim ServiceState serviceState = userState.serviceStateMap.get(sessionState.mInputId); 473fd5b72f1ed2ee74a4204eef65f560fc82f0b62feDongwon Kang if (serviceState != null) { 474d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim serviceState.mSessionTokens.remove(sessionToken); 475fd5b72f1ed2ee74a4204eef65f560fc82f0b62feDongwon Kang } 476d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim updateServiceConnectionLocked(sessionState.mInputId, userId); 477fd5b72f1ed2ee74a4204eef65f560fc82f0b62feDongwon Kang } 478fd5b72f1ed2ee74a4204eef65f560fc82f0b62feDongwon Kang 4792b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim private void broadcastServiceAvailabilityChangedLocked(ServiceState serviceState) { 4802b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim for (IBinder iBinder : serviceState.mClients) { 4812b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim ITvInputClient client = ITvInputClient.Stub.asInterface(iBinder); 4822b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim try { 4832b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim client.onAvailabilityChanged( 4842b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim serviceState.mTvInputInfo.getId(), serviceState.mAvailable); 4852b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim } catch (RemoteException e) { 4862b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim Slog.e(TAG, "error in onAvailabilityChanged", e); 4872b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim } 4882b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim } 4892b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim } 4902b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim 4913957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo private final class BinderService extends ITvInputManager.Stub { 4923957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo @Override 4933957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo public List<TvInputInfo> getTvInputList(int userId) { 4943957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), 4953957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo Binder.getCallingUid(), userId, "getTvInputList"); 4963957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo final long identity = Binder.clearCallingIdentity(); 4973957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo try { 4983957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo synchronized (mLock) { 4993957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo UserState userState = getUserStateLocked(resolvedUserId); 500d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim return new ArrayList<TvInputInfo>(userState.inputMap.values()); 5013957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 5023957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } finally { 5033957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo Binder.restoreCallingIdentity(identity); 5043957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 5053957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 5063957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo 5073957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo @Override 508d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim public boolean getAvailability(final ITvInputClient client, final String inputId, 5093957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo int userId) { 5103957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), 5113957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo Binder.getCallingUid(), userId, "getAvailability"); 5123957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo final long identity = Binder.clearCallingIdentity(); 5133957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo try { 5143957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo synchronized (mLock) { 5153957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo UserState userState = getUserStateLocked(resolvedUserId); 516d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim ServiceState serviceState = userState.serviceStateMap.get(inputId); 5173957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo if (serviceState != null) { 5183957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo // We already know the status of this input service. Return the cached 5193957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo // status. 520d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim return serviceState.mAvailable; 5213957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 5223957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 5233957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } finally { 5243957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo Binder.restoreCallingIdentity(identity); 5253957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 5263957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo return false; 5273957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 5283957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo 5293957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo @Override 530d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim public void registerCallback(final ITvInputClient client, final String inputId, 5313957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo int userId) { 5323957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), 5333957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo Binder.getCallingUid(), userId, "registerCallback"); 5343957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo final long identity = Binder.clearCallingIdentity(); 5353957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo try { 5363957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo synchronized (mLock) { 5373957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo // Create a new service callback and add it to the callback map of the current 5383957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo // service. 5393957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo UserState userState = getUserStateLocked(resolvedUserId); 540d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim ServiceState serviceState = userState.serviceStateMap.get(inputId); 5413957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo if (serviceState == null) { 542d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim serviceState = new ServiceState( 543d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim userState.inputMap.get(inputId), resolvedUserId); 544d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim userState.serviceStateMap.put(inputId, serviceState); 5453957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 5463957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo IBinder iBinder = client.asBinder(); 547d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim if (!serviceState.mClients.contains(iBinder)) { 548d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim serviceState.mClients.add(iBinder); 5493957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 550d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim if (serviceState.mService != null) { 551d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim if (serviceState.mCallback != null) { 5523957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo // We already handled. 5533957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo return; 5543957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 555d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim serviceState.mCallback = new ServiceCallback(resolvedUserId); 5563957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo try { 557d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim serviceState.mService.registerCallback(serviceState.mCallback); 5583957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } catch (RemoteException e) { 5599a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho Slog.e(TAG, "error in registerCallback", e); 5603957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 5613957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } else { 562d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim updateServiceConnectionLocked(inputId, resolvedUserId); 5633957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 5643957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 5653957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } finally { 5663957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo Binder.restoreCallingIdentity(identity); 5673957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 5683957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 5693957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo 5703957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo @Override 571d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim public void unregisterCallback(ITvInputClient client, String inputId, int userId) { 5723957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), 5733957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo Binder.getCallingUid(), userId, "unregisterCallback"); 5743957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo final long identity = Binder.clearCallingIdentity(); 5753957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo try { 5763957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo synchronized (mLock) { 5773957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo UserState userState = getUserStateLocked(resolvedUserId); 578d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim ServiceState serviceState = userState.serviceStateMap.get(inputId); 5793957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo if (serviceState == null) { 5803957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo return; 5813957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 5823957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo 5833957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo // Remove this client from the client list and unregister the callback. 584d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim serviceState.mClients.remove(client.asBinder()); 585d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim if (!serviceState.mClients.isEmpty()) { 5863957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo // We have other clients who want to keep the callback. Do this later. 5873957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo return; 5883957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 589d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim if (serviceState.mService == null || serviceState.mCallback == null) { 5903957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo return; 5913957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 5923957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo try { 593d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim serviceState.mService.unregisterCallback(serviceState.mCallback); 5943957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } catch (RemoteException e) { 5959a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho Slog.e(TAG, "error in unregisterCallback", e); 5963957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } finally { 597d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim serviceState.mCallback = null; 598d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim updateServiceConnectionLocked(inputId, resolvedUserId); 5993957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 6003957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 6013957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } finally { 6023957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo Binder.restoreCallingIdentity(identity); 6033957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 6043957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 6053957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo 6063957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo @Override 607d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim public void createSession(final ITvInputClient client, final String inputId, 6083957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo int seq, int userId) { 6093957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo final int callingUid = Binder.getCallingUid(); 6103957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid, 6113957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo userId, "createSession"); 6123957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo final long identity = Binder.clearCallingIdentity(); 6133957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo try { 6143957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo synchronized (mLock) { 6153957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo UserState userState = getUserStateLocked(resolvedUserId); 616d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim ServiceState serviceState = userState.serviceStateMap.get(inputId); 6173957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo if (serviceState == null) { 618d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim serviceState = new ServiceState( 619d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim userState.inputMap.get(inputId), resolvedUserId); 620d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim userState.serviceStateMap.put(inputId, serviceState); 6213957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 6222b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim // Send a null token immediately while reconnecting. 6232b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim if (serviceState.mReconnecting == true) { 6242b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim sendSessionTokenToClientLocked(client, inputId, null, null, seq, userId); 6252b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim return; 6262b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim } 6272b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim 6282b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim // Create a new session token and a session state. 6292b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim IBinder sessionToken = new Binder(); 6302b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim SessionState sessionState = new SessionState( 6312b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim sessionToken, inputId, client, seq, callingUid, resolvedUserId); 6322b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim 6332b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim // Add them to the global session state map of the current user. 6342b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim userState.sessionStateMap.put(sessionToken, sessionState); 6352b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim 6362b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim // Also, add them to the session state map of the current service. 637d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim serviceState.mSessionTokens.add(sessionToken); 6383957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo 639d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim if (serviceState.mService != null) { 640d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim createSessionInternalLocked(serviceState.mService, sessionToken, 6417de5e234715a3baa8905afa3dd0c5009af64541fSungsoo Lim resolvedUserId); 6423957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } else { 643d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim updateServiceConnectionLocked(inputId, resolvedUserId); 6443957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 6453957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 6463957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } finally { 6473957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo Binder.restoreCallingIdentity(identity); 6483957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 6493957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 6503957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo 6513957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo @Override 6523957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo public void releaseSession(IBinder sessionToken, int userId) { 6533957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo final int callingUid = Binder.getCallingUid(); 6543957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid, 6553957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo userId, "releaseSession"); 6563957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo final long identity = Binder.clearCallingIdentity(); 6573957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo try { 6583957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo synchronized (mLock) { 6592b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim releaseSessionLocked(sessionToken, callingUid, resolvedUserId); 6603957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 6613957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } finally { 6623957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo Binder.restoreCallingIdentity(identity); 6633957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 6643957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 6653957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo 6663957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo @Override 6673957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo public void setSurface(IBinder sessionToken, Surface surface, int userId) { 6683957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo final int callingUid = Binder.getCallingUid(); 6693957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid, 6703957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo userId, "setSurface"); 6713957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo final long identity = Binder.clearCallingIdentity(); 6723957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo try { 6733957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo synchronized (mLock) { 6743957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo try { 6753957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo getSessionLocked(sessionToken, callingUid, resolvedUserId).setSurface( 6763957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo surface); 6773957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } catch (RemoteException e) { 6789a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho Slog.e(TAG, "error in setSurface", e); 6793957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 6803957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 6813957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } finally { 682f836206818ce338db83a3c23c486fb8cab29cb6dYoungsang Cho if (surface != null) { 683f836206818ce338db83a3c23c486fb8cab29cb6dYoungsang Cho // surface is not used in TvInputManagerService. 684f836206818ce338db83a3c23c486fb8cab29cb6dYoungsang Cho surface.release(); 685f836206818ce338db83a3c23c486fb8cab29cb6dYoungsang Cho } 6863957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo Binder.restoreCallingIdentity(identity); 6873957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 6883957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 6893957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo 6903957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo @Override 6913957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo public void setVolume(IBinder sessionToken, float volume, int userId) { 6923957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo final int callingUid = Binder.getCallingUid(); 6933957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid, 6943957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo userId, "setVolume"); 6953957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo final long identity = Binder.clearCallingIdentity(); 6963957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo try { 6973957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo synchronized (mLock) { 6983957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo try { 6993957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo getSessionLocked(sessionToken, callingUid, resolvedUserId).setVolume( 7003957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo volume); 7013957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } catch (RemoteException e) { 7029a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho Slog.e(TAG, "error in setVolume", e); 7033957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 7043957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 7053957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } finally { 7063957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo Binder.restoreCallingIdentity(identity); 7073957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 7083957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 7093957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo 7103957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo @Override 7113957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo public void tune(IBinder sessionToken, final Uri channelUri, int userId) { 7123957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo final int callingUid = Binder.getCallingUid(); 7133957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid, 7143957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo userId, "tune"); 7153957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo final long identity = Binder.clearCallingIdentity(); 7163957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo try { 7173957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo synchronized (mLock) { 7183957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo try { 7193957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo getSessionLocked(sessionToken, callingUid, resolvedUserId).tune(channelUri); 72031dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo 72131dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo long currentTime = System.currentTimeMillis(); 72231dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo long channelId = ContentUris.parseId(channelUri); 72331dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo 72431dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo // Close the open log entry first, if any. 72531dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo UserState userState = getUserStateLocked(resolvedUserId); 72631dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo SessionState sessionState = userState.sessionStateMap.get(sessionToken); 727d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim if (sessionState.mLogUri != null) { 72831dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo SomeArgs args = SomeArgs.obtain(); 729d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim args.arg1 = sessionState.mLogUri; 73031dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo args.arg2 = currentTime; 73131dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo mLogHandler.obtainMessage(LogHandler.MSG_CLOSE_ENTRY, args) 73231dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo .sendToTarget(); 73331dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo } 73431dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo 73531dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo // Create a log entry and fill it later. 73631dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo ContentValues values = new ContentValues(); 737f5cd0b388ac31104e014f9193d06080851a09e18Jae Seo values.put(TvContract.WatchedPrograms.COLUMN_WATCH_START_TIME_UTC_MILLIS, 73831dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo currentTime); 739f5cd0b388ac31104e014f9193d06080851a09e18Jae Seo values.put(TvContract.WatchedPrograms.COLUMN_WATCH_END_TIME_UTC_MILLIS, 0); 740f5cd0b388ac31104e014f9193d06080851a09e18Jae Seo values.put(TvContract.WatchedPrograms.COLUMN_CHANNEL_ID, channelId); 74131dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo 742d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim sessionState.mLogUri = mContentResolver.insert( 74331dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo TvContract.WatchedPrograms.CONTENT_URI, values); 74431dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo SomeArgs args = SomeArgs.obtain(); 745d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim args.arg1 = sessionState.mLogUri; 74631dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo args.arg2 = ContentUris.parseId(channelUri); 74731dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo args.arg3 = currentTime; 74831dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo mLogHandler.obtainMessage(LogHandler.MSG_OPEN_ENTRY, args).sendToTarget(); 7493957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } catch (RemoteException e) { 7509a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho Slog.e(TAG, "error in tune", e); 7513957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo return; 7523957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 7533957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 7543957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } finally { 7553957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo Binder.restoreCallingIdentity(identity); 7563957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 7573957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 7589a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho 7599a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho @Override 7609a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho public void createOverlayView(IBinder sessionToken, IBinder windowToken, Rect frame, 7619a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho int userId) { 7629a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho final int callingUid = Binder.getCallingUid(); 7639a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid, 7649a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho userId, "createOverlayView"); 7659a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho final long identity = Binder.clearCallingIdentity(); 7669a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho try { 7679a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho synchronized (mLock) { 7689a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho try { 7699a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho getSessionLocked(sessionToken, callingUid, resolvedUserId) 7709a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho .createOverlayView(windowToken, frame); 7719a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho } catch (RemoteException e) { 7729a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho Slog.e(TAG, "error in createOverlayView", e); 7739a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho } 7749a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho } 7759a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho } finally { 7769a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho Binder.restoreCallingIdentity(identity); 7779a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho } 7789a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho } 7799a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho 7809a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho @Override 7819a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho public void relayoutOverlayView(IBinder sessionToken, Rect frame, int userId) { 7829a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho final int callingUid = Binder.getCallingUid(); 7839a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid, 7849a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho userId, "relayoutOverlayView"); 7859a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho final long identity = Binder.clearCallingIdentity(); 7869a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho try { 7879a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho synchronized (mLock) { 7889a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho try { 7899a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho getSessionLocked(sessionToken, callingUid, resolvedUserId) 7909a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho .relayoutOverlayView(frame); 7919a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho } catch (RemoteException e) { 7929a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho Slog.e(TAG, "error in relayoutOverlayView", e); 7939a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho } 7949a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho } 7959a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho } finally { 7969a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho Binder.restoreCallingIdentity(identity); 7979a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho } 7989a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho } 7999a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho 8009a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho @Override 8019a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho public void removeOverlayView(IBinder sessionToken, int userId) { 8029a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho final int callingUid = Binder.getCallingUid(); 8039a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid, 8049a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho userId, "removeOverlayView"); 8059a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho final long identity = Binder.clearCallingIdentity(); 8069a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho try { 8079a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho synchronized (mLock) { 8089a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho try { 8099a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho getSessionLocked(sessionToken, callingUid, resolvedUserId) 8109a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho .removeOverlayView(); 8119a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho } catch (RemoteException e) { 8129a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho Slog.e(TAG, "error in removeOverlayView", e); 8139a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho } 8149a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho } 8159a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho } finally { 8169a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho Binder.restoreCallingIdentity(identity); 8179a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho } 8189a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho } 819c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim 820c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim @Override 821c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim public List<TvInputHardwareInfo> getHardwareList() throws RemoteException { 822c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim if (mContext.checkCallingPermission( 823c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim android.Manifest.permission.TV_INPUT_HARDWARE) 824c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim != PackageManager.PERMISSION_GRANTED) { 825c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim return null; 826c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 827c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim 828c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim final long identity = Binder.clearCallingIdentity(); 829c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim try { 830c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim return mTvInputHardwareManager.getHardwareList(); 831c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } finally { 832c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim Binder.restoreCallingIdentity(identity); 833c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 834c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 835c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim 836c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim @Override 837c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim public ITvInputHardware acquireTvInputHardware(int deviceId, 838c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim ITvInputHardwareCallback callback, int userId) throws RemoteException { 839c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim if (mContext.checkCallingPermission( 840c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim android.Manifest.permission.TV_INPUT_HARDWARE) 841c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim != PackageManager.PERMISSION_GRANTED) { 842c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim return null; 843c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 844c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim 845c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim final long identity = Binder.clearCallingIdentity(); 846c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim final int callingUid = Binder.getCallingUid(); 847c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid, 848c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim userId, "acquireTvInputHardware"); 849c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim try { 850c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim return mTvInputHardwareManager.acquireHardware( 851c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim deviceId, callback, callingUid, resolvedUserId); 852c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } finally { 853c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim Binder.restoreCallingIdentity(identity); 854c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 855c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 856c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim 857c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim @Override 858c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim public void releaseTvInputHardware(int deviceId, ITvInputHardware hardware, int userId) 859c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim throws RemoteException { 860c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim if (mContext.checkCallingPermission( 861c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim android.Manifest.permission.TV_INPUT_HARDWARE) 862c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim != PackageManager.PERMISSION_GRANTED) { 863c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim return; 864c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 865c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim 866c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim final long identity = Binder.clearCallingIdentity(); 867c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim final int callingUid = Binder.getCallingUid(); 868c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid, 869c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim userId, "releaseTvInputHardware"); 870c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim try { 871c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim mTvInputHardwareManager.releaseHardware( 872c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim deviceId, hardware, callingUid, resolvedUserId); 873c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } finally { 874c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim Binder.restoreCallingIdentity(identity); 875c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 876c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 8773957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 8783957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo 8793957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo private static final class UserState { 880d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim // A mapping from the TV input id to its TvInputInfo. 881d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim private final Map<String, TvInputInfo> inputMap = new HashMap<String,TvInputInfo>(); 8823957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo 8833957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo // A mapping from the name of a TV input service to its state. 884d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim private final Map<String, ServiceState> serviceStateMap = 885d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim new HashMap<String, ServiceState>(); 8863957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo 8873957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo // A mapping from the token of a TV input session to its state. 8883957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo private final Map<IBinder, SessionState> sessionStateMap = 8893957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo new HashMap<IBinder, SessionState>(); 8903957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 8913957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo 8923957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo private final class ServiceState { 8932b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim // TODO: need to implement DeathRecipient for clients. 894d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim private final List<IBinder> mClients = new ArrayList<IBinder>(); 895d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim private final List<IBinder> mSessionTokens = new ArrayList<IBinder>(); 896d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim private final ServiceConnection mConnection; 8972b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim private final TvInputInfo mTvInputInfo; 8983957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo 899d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim private ITvInputService mService; 900d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim private ServiceCallback mCallback; 901d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim private boolean mBound; 902d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim private boolean mAvailable; 9032b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim private boolean mReconnecting; 9043957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo 905d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim private ServiceState(TvInputInfo inputInfo, int userId) { 9062b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim mTvInputInfo = inputInfo; 9072b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim mConnection = new InputServiceConnection(inputInfo, userId); 9083957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 9093957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 9103957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo 9112b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim private final class SessionState implements IBinder.DeathRecipient { 912d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim private final String mInputId; 913d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim private final ITvInputClient mClient; 914d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim private final int mSeq; 915d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim private final int mCallingUid; 9162b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim private final int mUserId; 9172b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim private final IBinder mToken; 918d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim private ITvInputSession mSession; 919d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim private Uri mLogUri; 9203957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo 9212b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim private SessionState(IBinder token, String inputId, ITvInputClient client, int seq, 9222b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim int callingUid, int userId) { 9232b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim mToken = token; 9242b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim mInputId = inputId; 9252b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim mClient = client; 9262b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim mSeq = seq; 9272b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim mCallingUid = callingUid; 9282b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim mUserId = userId; 9292b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim } 9302b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim 9312b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim @Override 9322b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim public void binderDied() { 9332b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim synchronized (mLock) { 9342b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim mSession = null; 9352b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim if (mClient != null) { 9362b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim try { 9372b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim mClient.onSessionReleased(mSeq); 9382b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim } catch(RemoteException e) { 9392b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim Slog.e(TAG, "error in onSessionReleased", e); 9402b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim } 9412b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim } 9422b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim removeSessionStateLocked(mToken, mUserId); 9432b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim } 9443957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 9453957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 9463957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo 9473957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo private final class InputServiceConnection implements ServiceConnection { 948d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim private final TvInputInfo mTvInputInfo; 9493957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo private final int mUserId; 9503957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo 951d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim private InputServiceConnection(TvInputInfo inputInfo, int userId) { 9523957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo mUserId = userId; 953d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim mTvInputInfo = inputInfo; 9543957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 9553957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo 9563957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo @Override 9573957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo public void onServiceConnected(ComponentName name, IBinder service) { 9583957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo if (DEBUG) { 959d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim Slog.d(TAG, "onServiceConnected(inputId=" + mTvInputInfo.getId() + ")"); 9603957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 9613957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo synchronized (mLock) { 962d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim ServiceState serviceState = getServiceStateLocked(mTvInputInfo.getId(), mUserId); 963d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim serviceState.mService = ITvInputService.Stub.asInterface(service); 9643957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo 9653957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo // Register a callback, if we need to. 966d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim if (!serviceState.mClients.isEmpty() && serviceState.mCallback == null) { 967d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim serviceState.mCallback = new ServiceCallback(mUserId); 9683957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo try { 969d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim serviceState.mService.registerCallback(serviceState.mCallback); 9703957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } catch (RemoteException e) { 9719a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho Slog.e(TAG, "error in registerCallback", e); 9723957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 9733957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 9743957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo 9753957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo // And create sessions, if any. 976d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim for (IBinder sessionToken : serviceState.mSessionTokens) { 977d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim createSessionInternalLocked(serviceState.mService, sessionToken, mUserId); 9783957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 9793957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 9803957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 9813957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo 9823957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo @Override 9833957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo public void onServiceDisconnected(ComponentName name) { 9843957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo if (DEBUG) { 985d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim Slog.d(TAG, "onServiceDisconnected(inputId=" + mTvInputInfo.getId() + ")"); 9863957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 9872b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim if (!mTvInputInfo.getComponent().equals(name)) { 9882b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim throw new IllegalArgumentException("Mismatched ComponentName: " 9892b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim + mTvInputInfo.getComponent() + " (expected), " + name + " (actual)."); 9902b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim } 9912b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim synchronized (mLock) { 9922b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim UserState userState = getUserStateLocked(mUserId); 9932b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim ServiceState serviceState = userState.serviceStateMap.get(mTvInputInfo.getId()); 9942b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim if (serviceState != null) { 9952b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim serviceState.mReconnecting = true; 9962b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim serviceState.mBound = false; 9972b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim serviceState.mService = null; 9982b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim serviceState.mCallback = null; 9992b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim 10002b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim // Send null tokens for not finishing create session events. 10012b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim for (IBinder sessionToken : serviceState.mSessionTokens) { 10022b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim SessionState sessionState = userState.sessionStateMap.get(sessionToken); 10032b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim if (sessionState.mSession == null) { 10042b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim removeSessionStateLocked(sessionToken, sessionState.mUserId); 10052b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim sendSessionTokenToClientLocked(sessionState.mClient, 10062b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim sessionState.mInputId, null, null, sessionState.mSeq, 10072b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim sessionState.mUserId); 10082b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim } 10092b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim } 10102b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim 10112b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim if (serviceState.mAvailable) { 10122b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim serviceState.mAvailable = false; 10132b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim broadcastServiceAvailabilityChangedLocked(serviceState); 10142b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim } 10152b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim updateServiceConnectionLocked(mTvInputInfo.getId(), mUserId); 10162b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim } 10172b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim } 10183957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 10193957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 10203957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo 10213957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo private final class ServiceCallback extends ITvInputServiceCallback.Stub { 10223957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo private final int mUserId; 10233957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo 10243957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo ServiceCallback(int userId) { 10253957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo mUserId = userId; 10263957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 10273957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo 10283957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo @Override 10292b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim public void onAvailabilityChanged(String inputId, boolean isAvailable) { 10303957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo if (DEBUG) { 1031d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim Slog.d(TAG, "onAvailabilityChanged(inputId=" + inputId + ", isAvailable=" 10323957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo + isAvailable + ")"); 10333957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 10343957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo synchronized (mLock) { 1035d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim ServiceState serviceState = getServiceStateLocked(inputId, mUserId); 10362b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim if (serviceState.mAvailable != isAvailable) { 10372b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim serviceState.mAvailable = isAvailable; 10382b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim broadcastServiceAvailabilityChangedLocked(serviceState); 10393957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 10403957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 10413957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 10423957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 104331dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo 104431dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo private final class LogHandler extends Handler { 104531dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo private static final int MSG_OPEN_ENTRY = 1; 104631dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo private static final int MSG_UPDATE_ENTRY = 2; 104731dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo private static final int MSG_CLOSE_ENTRY = 3; 104831dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo 104931dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo public LogHandler(Looper looper) { 105031dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo super(looper); 105131dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo } 105231dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo 105331dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo @Override 105431dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo public void handleMessage(Message msg) { 105531dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo switch (msg.what) { 105631dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo case MSG_OPEN_ENTRY: { 105731dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo SomeArgs args = (SomeArgs) msg.obj; 105831dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo Uri uri = (Uri) args.arg1; 105931dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo long channelId = (long) args.arg2; 106031dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo long time = (long) args.arg3; 106131dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo onOpenEntry(uri, channelId, time); 106231dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo args.recycle(); 106331dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo return; 106431dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo } 106531dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo case MSG_UPDATE_ENTRY: { 106631dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo SomeArgs args = (SomeArgs) msg.obj; 106731dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo Uri uri = (Uri) args.arg1; 106831dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo long channelId = (long) args.arg2; 106931dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo long time = (long) args.arg3; 107031dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo onUpdateEntry(uri, channelId, time); 107131dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo args.recycle(); 107231dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo return; 107331dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo } 107431dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo case MSG_CLOSE_ENTRY: { 107531dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo SomeArgs args = (SomeArgs) msg.obj; 107631dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo Uri uri = (Uri) args.arg1; 107731dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo long time = (long) args.arg2; 107831dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo onCloseEntry(uri, time); 107931dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo args.recycle(); 108031dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo return; 108131dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo } 108231dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo default: { 10836a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo Slog.w(TAG, "Unhandled message code: " + msg.what); 108431dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo return; 108531dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo } 108631dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo } 108731dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo } 108831dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo 108931dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo private void onOpenEntry(Uri uri, long channelId, long watchStarttime) { 109031dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo String[] projection = { 1091f5cd0b388ac31104e014f9193d06080851a09e18Jae Seo TvContract.Programs.COLUMN_TITLE, 1092f5cd0b388ac31104e014f9193d06080851a09e18Jae Seo TvContract.Programs.COLUMN_START_TIME_UTC_MILLIS, 1093f5cd0b388ac31104e014f9193d06080851a09e18Jae Seo TvContract.Programs.COLUMN_END_TIME_UTC_MILLIS, 1094f5cd0b388ac31104e014f9193d06080851a09e18Jae Seo TvContract.Programs.COLUMN_DESCRIPTION 109531dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo }; 1096f5cd0b388ac31104e014f9193d06080851a09e18Jae Seo String selection = TvContract.Programs.COLUMN_CHANNEL_ID + "=? AND " 1097f5cd0b388ac31104e014f9193d06080851a09e18Jae Seo + TvContract.Programs.COLUMN_START_TIME_UTC_MILLIS + "<=? AND " 1098f5cd0b388ac31104e014f9193d06080851a09e18Jae Seo + TvContract.Programs.COLUMN_END_TIME_UTC_MILLIS + ">?"; 109931dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo String[] selectionArgs = { 110031dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo String.valueOf(channelId), 110131dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo String.valueOf(watchStarttime), 110231dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo String.valueOf(watchStarttime) 110331dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo }; 1104f5cd0b388ac31104e014f9193d06080851a09e18Jae Seo String sortOrder = TvContract.Programs.COLUMN_START_TIME_UTC_MILLIS + " ASC"; 110531dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo Cursor cursor = null; 110631dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo try { 110731dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo cursor = mContentResolver.query(TvContract.Programs.CONTENT_URI, projection, 110831dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo selection, selectionArgs, sortOrder); 110931dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo if (cursor != null && cursor.moveToNext()) { 111031dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo ContentValues values = new ContentValues(); 1111f5cd0b388ac31104e014f9193d06080851a09e18Jae Seo values.put(TvContract.WatchedPrograms.COLUMN_TITLE, cursor.getString(0)); 1112f5cd0b388ac31104e014f9193d06080851a09e18Jae Seo values.put(TvContract.WatchedPrograms.COLUMN_START_TIME_UTC_MILLIS, 1113f5cd0b388ac31104e014f9193d06080851a09e18Jae Seo cursor.getLong(1)); 111431dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo long endTime = cursor.getLong(2); 1115f5cd0b388ac31104e014f9193d06080851a09e18Jae Seo values.put(TvContract.WatchedPrograms.COLUMN_END_TIME_UTC_MILLIS, endTime); 1116f5cd0b388ac31104e014f9193d06080851a09e18Jae Seo values.put(TvContract.WatchedPrograms.COLUMN_DESCRIPTION, cursor.getString(3)); 111731dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo mContentResolver.update(uri, values, null, null); 111831dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo 111931dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo // Schedule an update when the current program ends. 112031dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo SomeArgs args = SomeArgs.obtain(); 112131dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo args.arg1 = uri; 112231dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo args.arg2 = channelId; 112331dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo args.arg3 = endTime; 112431dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo Message msg = obtainMessage(LogHandler.MSG_UPDATE_ENTRY, args); 112531dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo sendMessageDelayed(msg, endTime - System.currentTimeMillis()); 112631dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo } 112731dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo } finally { 112831dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo if (cursor != null) { 112931dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo cursor.close(); 113031dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo } 113131dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo } 113231dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo } 113331dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo 113431dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo private void onUpdateEntry(Uri uri, long channelId, long time) { 113531dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo String[] projection = { 1136f5cd0b388ac31104e014f9193d06080851a09e18Jae Seo TvContract.WatchedPrograms.COLUMN_WATCH_START_TIME_UTC_MILLIS, 1137f5cd0b388ac31104e014f9193d06080851a09e18Jae Seo TvContract.WatchedPrograms.COLUMN_WATCH_END_TIME_UTC_MILLIS, 1138f5cd0b388ac31104e014f9193d06080851a09e18Jae Seo TvContract.WatchedPrograms.COLUMN_TITLE, 1139f5cd0b388ac31104e014f9193d06080851a09e18Jae Seo TvContract.WatchedPrograms.COLUMN_START_TIME_UTC_MILLIS, 1140f5cd0b388ac31104e014f9193d06080851a09e18Jae Seo TvContract.WatchedPrograms.COLUMN_END_TIME_UTC_MILLIS, 1141f5cd0b388ac31104e014f9193d06080851a09e18Jae Seo TvContract.WatchedPrograms.COLUMN_DESCRIPTION 114231dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo }; 114331dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo Cursor cursor = null; 114431dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo try { 114531dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo cursor = mContentResolver.query(uri, projection, null, null, null); 114631dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo if (cursor != null && cursor.moveToNext()) { 114731dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo long watchStartTime = cursor.getLong(0); 114831dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo long watchEndTime = cursor.getLong(1); 114931dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo String title = cursor.getString(2); 115031dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo long startTime = cursor.getLong(3); 115131dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo long endTime = cursor.getLong(4); 115231dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo String description = cursor.getString(5); 115331dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo 115431dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo // Do nothing if the current log entry is already closed. 115531dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo if (watchEndTime > 0) { 115631dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo return; 115731dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo } 115831dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo 115931dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo // The current program has just ended. Create a (complete) log entry off the 116031dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo // current entry. 116131dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo ContentValues values = new ContentValues(); 1162f5cd0b388ac31104e014f9193d06080851a09e18Jae Seo values.put(TvContract.WatchedPrograms.COLUMN_WATCH_START_TIME_UTC_MILLIS, 116331dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo watchStartTime); 1164f5cd0b388ac31104e014f9193d06080851a09e18Jae Seo values.put(TvContract.WatchedPrograms.COLUMN_WATCH_END_TIME_UTC_MILLIS, time); 1165f5cd0b388ac31104e014f9193d06080851a09e18Jae Seo values.put(TvContract.WatchedPrograms.COLUMN_CHANNEL_ID, channelId); 1166f5cd0b388ac31104e014f9193d06080851a09e18Jae Seo values.put(TvContract.WatchedPrograms.COLUMN_TITLE, title); 1167f5cd0b388ac31104e014f9193d06080851a09e18Jae Seo values.put(TvContract.WatchedPrograms.COLUMN_START_TIME_UTC_MILLIS, startTime); 1168f5cd0b388ac31104e014f9193d06080851a09e18Jae Seo values.put(TvContract.WatchedPrograms.COLUMN_END_TIME_UTC_MILLIS, endTime); 1169f5cd0b388ac31104e014f9193d06080851a09e18Jae Seo values.put(TvContract.WatchedPrograms.COLUMN_DESCRIPTION, description); 117031dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo mContentResolver.insert(TvContract.WatchedPrograms.CONTENT_URI, values); 117131dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo } 117231dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo } finally { 117331dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo if (cursor != null) { 117431dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo cursor.close(); 117531dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo } 117631dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo } 117731dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo // Re-open the current log entry with the next program information. 117831dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo onOpenEntry(uri, channelId, time); 117931dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo } 118031dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo 118131dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo private void onCloseEntry(Uri uri, long watchEndTime) { 118231dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo ContentValues values = new ContentValues(); 1183f5cd0b388ac31104e014f9193d06080851a09e18Jae Seo values.put(TvContract.WatchedPrograms.COLUMN_WATCH_END_TIME_UTC_MILLIS, watchEndTime); 118431dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo mContentResolver.update(uri, values, null, null); 118531dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo } 118631dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo } 11873957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo} 1188