TvInputManagerService.java revision 0ceb7e4755015eafda29c251eac285620788a51b
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); 10531dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo 1063957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo synchronized (mLock) { 1073957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo mUserStates.put(mCurrentUserId, new UserState()); 1083957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 1093957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 1103957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo 1113957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo @Override 1123957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo public void onStart() { 1133957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo publishBinderService(Context.TV_INPUT_SERVICE, new BinderService()); 1143957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 1153957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo 1160ceb7e4755015eafda29c251eac285620788a51bJi-Hwan Lee @Override 1170ceb7e4755015eafda29c251eac285620788a51bJi-Hwan Lee public void onBootPhase(int phase) { 1180ceb7e4755015eafda29c251eac285620788a51bJi-Hwan Lee if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY) { 1190ceb7e4755015eafda29c251eac285620788a51bJi-Hwan Lee registerBroadcastReceivers(); 1200ceb7e4755015eafda29c251eac285620788a51bJi-Hwan Lee synchronized (mLock) { 1210ceb7e4755015eafda29c251eac285620788a51bJi-Hwan Lee buildTvInputListLocked(mCurrentUserId); 1220ceb7e4755015eafda29c251eac285620788a51bJi-Hwan Lee } 1230ceb7e4755015eafda29c251eac285620788a51bJi-Hwan Lee } 1240ceb7e4755015eafda29c251eac285620788a51bJi-Hwan Lee } 1250ceb7e4755015eafda29c251eac285620788a51bJi-Hwan Lee 1263957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo private void registerBroadcastReceivers() { 1273957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo PackageMonitor monitor = new PackageMonitor() { 1283957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo @Override 1293957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo public void onSomePackagesChanged() { 1303957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo synchronized (mLock) { 1313957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo buildTvInputListLocked(mCurrentUserId); 1323957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 1333957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 1343957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo }; 1353957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo monitor.register(mContext, null, UserHandle.ALL, true); 1363957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo 1373957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo IntentFilter intentFilter = new IntentFilter(); 1383957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo intentFilter.addAction(Intent.ACTION_USER_SWITCHED); 1393957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo intentFilter.addAction(Intent.ACTION_USER_REMOVED); 1403957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo mContext.registerReceiverAsUser(new BroadcastReceiver() { 1413957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo @Override 1423957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo public void onReceive(Context context, Intent intent) { 1433957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo String action = intent.getAction(); 1443957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo if (Intent.ACTION_USER_SWITCHED.equals(action)) { 1453957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo switchUser(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0)); 1463957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } else if (Intent.ACTION_USER_REMOVED.equals(action)) { 1473957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo removeUser(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0)); 1483957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 1493957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 1503957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo }, UserHandle.ALL, intentFilter, null, null); 1513957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 1523957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo 1533957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo private void buildTvInputListLocked(int userId) { 1543957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo UserState userState = getUserStateLocked(userId); 155d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim userState.inputMap.clear(); 1563957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo 1579a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho if (DEBUG) Slog.d(TAG, "buildTvInputList"); 1583957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo PackageManager pm = mContext.getPackageManager(); 1593957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo List<ResolveInfo> services = pm.queryIntentServices( 160e7bb7d6bb2257c24076f5a4b9f536f90a6637f58Chulwoo Lee new Intent(TvInputService.SERVICE_INTERFACE), 161e7bb7d6bb2257c24076f5a4b9f536f90a6637f58Chulwoo Lee PackageManager.GET_SERVICES | PackageManager.GET_META_DATA); 1623957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo for (ResolveInfo ri : services) { 1633957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo ServiceInfo si = ri.serviceInfo; 1643957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo if (!android.Manifest.permission.BIND_TV_INPUT.equals(si.permission)) { 1659a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho Slog.w(TAG, "Skipping TV input " + si.name + ": it does not require the permission " 1663957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo + android.Manifest.permission.BIND_TV_INPUT); 1673957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo continue; 1683957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 169e7bb7d6bb2257c24076f5a4b9f536f90a6637f58Chulwoo Lee try { 170e7bb7d6bb2257c24076f5a4b9f536f90a6637f58Chulwoo Lee TvInputInfo info = TvInputInfo.createTvInputInfo(mContext, ri); 171e7bb7d6bb2257c24076f5a4b9f536f90a6637f58Chulwoo Lee if (DEBUG) Slog.d(TAG, "add " + info.getId()); 172e7bb7d6bb2257c24076f5a4b9f536f90a6637f58Chulwoo Lee userState.inputMap.put(info.getId(), info); 173e7bb7d6bb2257c24076f5a4b9f536f90a6637f58Chulwoo Lee } catch (IOException | XmlPullParserException e) { 174e7bb7d6bb2257c24076f5a4b9f536f90a6637f58Chulwoo Lee Slog.e(TAG, "Can't load TV input " + si.name, e); 175e7bb7d6bb2257c24076f5a4b9f536f90a6637f58Chulwoo Lee } 1763957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 1773957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 1783957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo 1793957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo private void switchUser(int userId) { 1803957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo synchronized (mLock) { 1813957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo if (mCurrentUserId == userId) { 1823957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo return; 1833957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 1843957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo // final int oldUserId = mCurrentUserId; 1853957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo // TODO: Release services and sessions in the old user state, if needed. 1863957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo mCurrentUserId = userId; 1873957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo 1883957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo UserState userState = mUserStates.get(userId); 1893957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo if (userState == null) { 1903957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo userState = new UserState(); 1913957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 1923957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo mUserStates.put(userId, userState); 1933957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo buildTvInputListLocked(userId); 1943957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 1953957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 1963957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo 1973957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo private void removeUser(int userId) { 1983957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo synchronized (mLock) { 199b06cb8870f0407f18bb1225065a93aba2a5de2bfJae Seo UserState userState = mUserStates.get(userId); 200b06cb8870f0407f18bb1225065a93aba2a5de2bfJae Seo if (userState == null) { 201b06cb8870f0407f18bb1225065a93aba2a5de2bfJae Seo return; 202b06cb8870f0407f18bb1225065a93aba2a5de2bfJae Seo } 2033957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo // Release created sessions. 2043957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo for (SessionState state : userState.sessionStateMap.values()) { 205d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim if (state.mSession != null) { 2063957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo try { 207d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim state.mSession.release(); 2083957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } catch (RemoteException e) { 2099a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho Slog.e(TAG, "error in release", e); 2103957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 2113957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 2123957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 2133957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo userState.sessionStateMap.clear(); 2143957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo 2153957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo // Unregister all callbacks and unbind all services. 2163957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo for (ServiceState serviceState : userState.serviceStateMap.values()) { 217d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim if (serviceState.mCallback != null) { 2183957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo try { 219d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim serviceState.mService.unregisterCallback(serviceState.mCallback); 2203957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } catch (RemoteException e) { 2219a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho Slog.e(TAG, "error in unregisterCallback", e); 2223957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 2233957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 22472ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim serviceState.mClientTokens.clear(); 225d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim mContext.unbindService(serviceState.mConnection); 2263957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 2273957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo userState.serviceStateMap.clear(); 2283957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo 22972ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim userState.clientStateMap.clear(); 23072ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim 2313957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo mUserStates.remove(userId); 2323957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 2333957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 2343957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo 2353957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo private UserState getUserStateLocked(int userId) { 2363957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo UserState userState = mUserStates.get(userId); 2373957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo if (userState == null) { 2383957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo throw new IllegalStateException("User state not found for user ID " + userId); 2393957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 2403957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo return userState; 2413957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 2423957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo 243d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim private ServiceState getServiceStateLocked(String inputId, int userId) { 2443957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo UserState userState = getUserStateLocked(userId); 245d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim ServiceState serviceState = userState.serviceStateMap.get(inputId); 2463957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo if (serviceState == null) { 247d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim throw new IllegalStateException("Service state not found for " + inputId + " (userId=" 2487de5e234715a3baa8905afa3dd0c5009af64541fSungsoo Lim + userId + ")"); 2493957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 2503957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo return serviceState; 2513957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 2523957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo 2532b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim private SessionState getSessionStateLocked(IBinder sessionToken, int callingUid, int userId) { 2543957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo UserState userState = getUserStateLocked(userId); 2553957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo SessionState sessionState = userState.sessionStateMap.get(sessionToken); 2563957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo if (sessionState == null) { 2573957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo throw new IllegalArgumentException("Session state not found for token " + sessionToken); 2583957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 2593957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo // Only the application that requested this session or the system can access it. 260d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim if (callingUid != Process.SYSTEM_UID && callingUid != sessionState.mCallingUid) { 2613957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo throw new SecurityException("Illegal access to the session with token " + sessionToken 2623957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo + " from uid " + callingUid); 2633957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 2642b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim return sessionState; 2652b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim } 2662b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim 2672b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim private ITvInputSession getSessionLocked(IBinder sessionToken, int callingUid, int userId) { 2682b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim SessionState sessionState = getSessionStateLocked(sessionToken, callingUid, userId); 269d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim ITvInputSession session = sessionState.mSession; 2703957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo if (session == null) { 2713957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo throw new IllegalStateException("Session not yet created for token " + sessionToken); 2723957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 2733957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo return session; 2743957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 2753957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo 2763957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo private int resolveCallingUserId(int callingPid, int callingUid, int requestedUserId, 2773957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo String methodName) { 2783957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo return ActivityManager.handleIncomingUser(callingPid, callingUid, requestedUserId, false, 2793957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo false, methodName, null); 2803957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 2813957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo 282d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim private void updateServiceConnectionLocked(String inputId, int userId) { 2833957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo UserState userState = getUserStateLocked(userId); 284d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim ServiceState serviceState = userState.serviceStateMap.get(inputId); 2853957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo if (serviceState == null) { 2863957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo return; 2873957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 2882b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim if (serviceState.mReconnecting) { 2892b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim if (!serviceState.mSessionTokens.isEmpty()) { 2902b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim // wait until all the sessions are removed. 2912b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim return; 2922b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim } 2932b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim serviceState.mReconnecting = false; 2942b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim } 29572ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim boolean isStateEmpty = serviceState.mClientTokens.isEmpty() 296d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim && serviceState.mSessionTokens.isEmpty(); 297d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim if (serviceState.mService == null && !isStateEmpty && userId == mCurrentUserId) { 2983957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo // This means that the service is not yet connected but its state indicates that we 2993957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo // have pending requests. Then, connect the service. 300d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim if (serviceState.mBound) { 3013957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo // We have already bound to the service so we don't try to bind again until after we 3023957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo // unbind later on. 3033957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo return; 3043957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 3053957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo if (DEBUG) { 306d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim Slog.d(TAG, "bindServiceAsUser(inputId=" + inputId + ", userId=" + userId 3073957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo + ")"); 3083957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 309d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim 310d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim Intent i = new Intent(TvInputService.SERVICE_INTERFACE).setComponent( 311d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim userState.inputMap.get(inputId).getComponent()); 312e17b2dd7bcc137bf4d842a779e8d62c63957a978Ji-Hwan Lee serviceState.mBound = mContext.bindServiceAsUser( 313e17b2dd7bcc137bf4d842a779e8d62c63957a978Ji-Hwan Lee i, serviceState.mConnection, Context.BIND_AUTO_CREATE, new UserHandle(userId)); 314d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim } else if (serviceState.mService != null && isStateEmpty) { 3153957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo // This means that the service is already connected but its state indicates that we have 3163957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo // nothing to do with it. Then, disconnect the service. 3173957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo if (DEBUG) { 318d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim Slog.d(TAG, "unbindService(inputId=" + inputId + ")"); 3193957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 320d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim mContext.unbindService(serviceState.mConnection); 321d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim userState.serviceStateMap.remove(inputId); 3223957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 3233957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 3243957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo 32572ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim private ClientState createClientStateLocked(IBinder clientToken, int userId) { 32672ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim UserState userState = getUserStateLocked(userId); 32772ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim ClientState clientState = new ClientState(clientToken, userId); 32872ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim try { 32972ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim clientToken.linkToDeath(clientState, 0); 33072ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim } catch (RemoteException e) { 33172ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim Slog.e(TAG, "Client is already died."); 33272ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim } 33372ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim userState.clientStateMap.put(clientToken, clientState); 33472ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim return clientState; 33572ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim } 33672ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim 3373957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo private void createSessionInternalLocked(ITvInputService service, final IBinder sessionToken, 3387de5e234715a3baa8905afa3dd0c5009af64541fSungsoo Lim final int userId) { 33972ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim final UserState userState = getUserStateLocked(userId); 34072ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim final SessionState sessionState = userState.sessionStateMap.get(sessionToken); 3413957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo if (DEBUG) { 342d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim Slog.d(TAG, "createSessionInternalLocked(inputId=" + sessionState.mInputId + ")"); 3433957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 3446a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo 3456a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo final InputChannel[] channels = InputChannel.openInputChannelPair(sessionToken.toString()); 3466a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo 3473957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo // Set up a callback to send the session token. 3483957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo ITvInputSessionCallback callback = new ITvInputSessionCallback.Stub() { 3493957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo @Override 3503957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo public void onSessionCreated(ITvInputSession session) { 3513957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo if (DEBUG) { 352d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim Slog.d(TAG, "onSessionCreated(inputId=" + sessionState.mInputId + ")"); 3533957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 3543957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo synchronized (mLock) { 355d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim sessionState.mSession = session; 356fd5b72f1ed2ee74a4204eef65f560fc82f0b62feDongwon Kang if (session == null) { 357fd5b72f1ed2ee74a4204eef65f560fc82f0b62feDongwon Kang removeSessionStateLocked(sessionToken, userId); 3582b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim sendSessionTokenToClientLocked(sessionState.mClient, sessionState.mInputId, 3592b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim null, null, sessionState.mSeq, userId); 360fd5b72f1ed2ee74a4204eef65f560fc82f0b62feDongwon Kang } else { 3612b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim try { 3622b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim session.asBinder().linkToDeath(sessionState, 0); 3632b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim } catch (RemoteException e) { 3642b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim Slog.e(TAG, "Session is already died."); 3652b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim } 36672ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim 36772ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim IBinder clientToken = sessionState.mClient.asBinder(); 36872ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim ClientState clientState = userState.clientStateMap.get(clientToken); 36972ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim if (clientState == null) { 37072ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim clientState = createClientStateLocked(clientToken, userId); 37172ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim } 37272ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim clientState.mSessionTokens.add(sessionState.mSessionToken); 37372ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim 374d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim sendSessionTokenToClientLocked(sessionState.mClient, sessionState.mInputId, 375d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim sessionToken, channels[0], sessionState.mSeq, userId); 376fd5b72f1ed2ee74a4204eef65f560fc82f0b62feDongwon Kang } 3776a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo channels[0].dispose(); 3783957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 3793957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 380832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho 381832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho @Override 382a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang public void onVideoStreamChanged(int width, int height, boolean interlaced) { 383832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho synchronized (mLock) { 384832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho if (DEBUG) { 385a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang Slog.d(TAG, "onVideoStreamChanged(" + width + ", " + height + ")"); 386832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho } 387832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho if (sessionState.mSession == null || sessionState.mClient == null) { 388832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho return; 389832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho } 390832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho try { 391a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang sessionState.mClient.onVideoStreamChanged(width, height, interlaced, 392a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang sessionState.mSeq); 393832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho } catch (RemoteException e) { 394a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang Slog.e(TAG, "error in onVideoStreamChanged"); 395a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang } 396a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang } 397a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang } 398a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang 399a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang @Override 400a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang public void onAudioStreamChanged(int channelCount) { 401a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang synchronized (mLock) { 402a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang if (DEBUG) { 403a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang Slog.d(TAG, "onAudioStreamChanged(" + channelCount + ")"); 404a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang } 405a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang if (sessionState.mSession == null || sessionState.mClient == null) { 406a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang return; 407a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang } 408a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang try { 409a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang sessionState.mClient.onAudioStreamChanged(channelCount, sessionState.mSeq); 410a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang } catch (RemoteException e) { 411a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang Slog.e(TAG, "error in onAudioStreamChanged"); 412a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang } 413a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang } 414a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang } 415a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang 416a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang @Override 417a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang public void onClosedCaptionStreamChanged(boolean hasClosedCaption) { 418a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang synchronized (mLock) { 419a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang if (DEBUG) { 420a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang Slog.d(TAG, "onClosedCaptionStreamChanged(" + hasClosedCaption + ")"); 421a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang } 422a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang if (sessionState.mSession == null || sessionState.mClient == null) { 423a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang return; 424a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang } 425a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang try { 426a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang sessionState.mClient.onClosedCaptionStreamChanged(hasClosedCaption, 427a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang sessionState.mSeq); 428a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang } catch (RemoteException e) { 429a3be12a236aef0d9c4ff1274075f1e7899d29153Dongwon Kang Slog.e(TAG, "error in onClosedCaptionStreamChanged"); 430832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho } 431832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho } 432832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho } 433832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho 434832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho @Override 435832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho public void onSessionEvent(String eventType, Bundle eventArgs) { 436832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho synchronized (mLock) { 437832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho if (DEBUG) { 438832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho Slog.d(TAG, "onEvent(what=" + eventType + ", data=" + eventArgs + ")"); 439832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho } 440832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho if (sessionState.mSession == null || sessionState.mClient == null) { 441832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho return; 442832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho } 443832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho try { 444832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho sessionState.mClient.onSessionEvent(eventType, eventArgs, 445832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho sessionState.mSeq); 446832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho } catch (RemoteException e) { 447832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho Slog.e(TAG, "error in onSessionEvent"); 448832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho } 449832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho } 450832860fb9f6b3a7188a6af2d5d67806593595800Youngsang Cho } 4513957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo }; 4523957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo 4533957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo // Create a session. When failed, send a null token immediately. 4543957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo try { 4556a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo service.createSession(channels[1], callback); 4563957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } catch (RemoteException e) { 4579a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho Slog.e(TAG, "error in createSession", e); 458fd5b72f1ed2ee74a4204eef65f560fc82f0b62feDongwon Kang removeSessionStateLocked(sessionToken, userId); 459d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim sendSessionTokenToClientLocked(sessionState.mClient, sessionState.mInputId, null, null, 460d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim sessionState.mSeq, userId); 4613957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 4626a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo channels[1].dispose(); 4633957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 4643957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo 465d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim private void sendSessionTokenToClientLocked(ITvInputClient client, String inputId, 4666a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo IBinder sessionToken, InputChannel channel, int seq, int userId) { 4673957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo try { 468d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim client.onSessionCreated(inputId, sessionToken, channel, seq); 4693957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } catch (RemoteException exception) { 4709a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho Slog.e(TAG, "error in onSessionCreated", exception); 4713957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 4722b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim } 4733957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo 4742b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim private void releaseSessionLocked(IBinder sessionToken, int callingUid, int userId) { 4752b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim SessionState sessionState = getSessionStateLocked(sessionToken, callingUid, userId); 4762b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim if (sessionState.mSession != null) { 4772b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim try { 4782b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim sessionState.mSession.release(); 4792b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim } catch (RemoteException e) { 4802b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim Slog.w(TAG, "session is already disapeared", e); 4812b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim } 4822b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim sessionState.mSession = null; 4833957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 4842b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim removeSessionStateLocked(sessionToken, userId); 4853957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 4863957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo 487fd5b72f1ed2ee74a4204eef65f560fc82f0b62feDongwon Kang private void removeSessionStateLocked(IBinder sessionToken, int userId) { 488fd5b72f1ed2ee74a4204eef65f560fc82f0b62feDongwon Kang // Remove the session state from the global session state map of the current user. 489fd5b72f1ed2ee74a4204eef65f560fc82f0b62feDongwon Kang UserState userState = getUserStateLocked(userId); 490fd5b72f1ed2ee74a4204eef65f560fc82f0b62feDongwon Kang SessionState sessionState = userState.sessionStateMap.remove(sessionToken); 491fd5b72f1ed2ee74a4204eef65f560fc82f0b62feDongwon Kang 49231dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo // Close the open log entry, if any. 493d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim if (sessionState.mLogUri != null) { 49431dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo SomeArgs args = SomeArgs.obtain(); 495d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim args.arg1 = sessionState.mLogUri; 49631dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo args.arg2 = System.currentTimeMillis(); 49731dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo mLogHandler.obtainMessage(LogHandler.MSG_CLOSE_ENTRY, args).sendToTarget(); 49831dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo } 49931dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo 50072ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim // Also remove the session token from the session token list of the current client and 50172ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim // service. 50272ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim ClientState clientState = userState.clientStateMap.get(sessionState.mClient.asBinder()); 50372ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim if (clientState != null) { 50472ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim clientState.mSessionTokens.remove(sessionToken); 50572ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim if (clientState.isEmpty()) { 50672ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim userState.clientStateMap.remove(sessionState.mClient.asBinder()); 50772ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim } 50872ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim } 50972ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim 510d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim ServiceState serviceState = userState.serviceStateMap.get(sessionState.mInputId); 511fd5b72f1ed2ee74a4204eef65f560fc82f0b62feDongwon Kang if (serviceState != null) { 512d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim serviceState.mSessionTokens.remove(sessionToken); 513fd5b72f1ed2ee74a4204eef65f560fc82f0b62feDongwon Kang } 514d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim updateServiceConnectionLocked(sessionState.mInputId, userId); 515fd5b72f1ed2ee74a4204eef65f560fc82f0b62feDongwon Kang } 516fd5b72f1ed2ee74a4204eef65f560fc82f0b62feDongwon Kang 51772ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim private void unregisterCallbackInternalLocked(IBinder clientToken, String inputId, 51872ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim int userId) { 51972ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim UserState userState = getUserStateLocked(userId); 52072ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim ClientState clientState = userState.clientStateMap.get(clientToken); 52172ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim if (clientState != null) { 52272ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim clientState.mInputIds.remove(inputId); 52372ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim if (clientState.isEmpty()) { 52472ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim userState.clientStateMap.remove(clientToken); 52572ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim } 52672ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim } 52772ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim 52872ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim ServiceState serviceState = userState.serviceStateMap.get(inputId); 52972ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim if (serviceState == null) { 53072ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim return; 53172ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim } 53272ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim 53372ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim // Remove this client from the client list and unregister the callback. 53472ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim serviceState.mClientTokens.remove(clientToken); 53572ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim if (!serviceState.mClientTokens.isEmpty()) { 53672ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim // We have other clients who want to keep the callback. Do this later. 53772ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim return; 53872ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim } 53972ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim if (serviceState.mService == null || serviceState.mCallback == null) { 54072ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim return; 54172ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim } 54272ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim try { 54372ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim serviceState.mService.unregisterCallback(serviceState.mCallback); 54472ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim } catch (RemoteException e) { 54572ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim Slog.e(TAG, "error in unregisterCallback", e); 54672ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim } finally { 54772ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim serviceState.mCallback = null; 54872ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim updateServiceConnectionLocked(inputId, userId); 54972ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim } 55072ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim } 55172ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim 5522b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim private void broadcastServiceAvailabilityChangedLocked(ServiceState serviceState) { 55372ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim for (IBinder clientToken : serviceState.mClientTokens) { 5542b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim try { 55572ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim ITvInputClient.Stub.asInterface(clientToken).onAvailabilityChanged( 5562b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim serviceState.mTvInputInfo.getId(), serviceState.mAvailable); 5572b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim } catch (RemoteException e) { 5582b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim Slog.e(TAG, "error in onAvailabilityChanged", e); 5592b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim } 5602b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim } 5612b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim } 5622b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim 5633957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo private final class BinderService extends ITvInputManager.Stub { 5643957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo @Override 5653957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo public List<TvInputInfo> getTvInputList(int userId) { 5663957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), 5673957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo Binder.getCallingUid(), userId, "getTvInputList"); 5683957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo final long identity = Binder.clearCallingIdentity(); 5693957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo try { 5703957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo synchronized (mLock) { 5713957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo UserState userState = getUserStateLocked(resolvedUserId); 572d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim return new ArrayList<TvInputInfo>(userState.inputMap.values()); 5733957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 5743957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } finally { 5753957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo Binder.restoreCallingIdentity(identity); 5763957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 5773957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 5783957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo 5793957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo @Override 580d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim public boolean getAvailability(final ITvInputClient client, final String inputId, 5813957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo int userId) { 5823957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), 5833957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo Binder.getCallingUid(), userId, "getAvailability"); 5843957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo final long identity = Binder.clearCallingIdentity(); 5853957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo try { 5863957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo synchronized (mLock) { 5873957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo UserState userState = getUserStateLocked(resolvedUserId); 588d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim ServiceState serviceState = userState.serviceStateMap.get(inputId); 5893957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo if (serviceState != null) { 5903957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo // We already know the status of this input service. Return the cached 5913957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo // status. 592d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim return serviceState.mAvailable; 5933957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 5943957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 5953957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } finally { 5963957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo Binder.restoreCallingIdentity(identity); 5973957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 5983957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo return false; 5993957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 6003957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo 6013957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo @Override 602d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim public void registerCallback(final ITvInputClient client, final String inputId, 6033957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo int userId) { 6043957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), 6053957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo Binder.getCallingUid(), userId, "registerCallback"); 6063957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo final long identity = Binder.clearCallingIdentity(); 6073957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo try { 6083957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo synchronized (mLock) { 6093957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo // Create a new service callback and add it to the callback map of the current 6103957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo // service. 6113957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo UserState userState = getUserStateLocked(resolvedUserId); 612d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim ServiceState serviceState = userState.serviceStateMap.get(inputId); 6133957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo if (serviceState == null) { 614d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim serviceState = new ServiceState( 615d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim userState.inputMap.get(inputId), resolvedUserId); 616d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim userState.serviceStateMap.put(inputId, serviceState); 6173957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 61872ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim IBinder clientToken = client.asBinder(); 61972ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim if (!serviceState.mClientTokens.contains(clientToken)) { 62072ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim serviceState.mClientTokens.add(clientToken); 6213957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 62272ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim 62372ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim ClientState clientState = userState.clientStateMap.get(clientToken); 62472ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim if (clientState == null) { 62572ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim clientState = createClientStateLocked(clientToken, resolvedUserId); 62672ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim } 62772ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim if (!clientState.mInputIds.contains(inputId)) { 62872ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim clientState.mInputIds.add(inputId); 62972ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim } 63072ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim 631d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim if (serviceState.mService != null) { 632d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim if (serviceState.mCallback != null) { 6333957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo // We already handled. 6343957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo return; 6353957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 636d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim serviceState.mCallback = new ServiceCallback(resolvedUserId); 6373957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo try { 638d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim serviceState.mService.registerCallback(serviceState.mCallback); 6393957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } catch (RemoteException e) { 6409a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho Slog.e(TAG, "error in registerCallback", e); 6413957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 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 652d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim public void unregisterCallback(ITvInputClient client, String inputId, int userId) { 6533957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), 6543957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo Binder.getCallingUid(), userId, "unregisterCallback"); 6553957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo final long identity = Binder.clearCallingIdentity(); 6563957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo try { 6573957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo synchronized (mLock) { 65872ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim unregisterCallbackInternalLocked(client.asBinder(), inputId, resolvedUserId); 6593957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 6603957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } finally { 6613957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo Binder.restoreCallingIdentity(identity); 6623957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 6633957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 6643957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo 6653957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo @Override 666d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim public void createSession(final ITvInputClient client, final String inputId, 6673957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo int seq, int userId) { 6683957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo final int callingUid = Binder.getCallingUid(); 6693957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid, 6703957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo userId, "createSession"); 6713957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo final long identity = Binder.clearCallingIdentity(); 6723957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo try { 6733957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo synchronized (mLock) { 6743957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo UserState userState = getUserStateLocked(resolvedUserId); 675d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim ServiceState serviceState = userState.serviceStateMap.get(inputId); 6763957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo if (serviceState == null) { 677d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim serviceState = new ServiceState( 678d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim userState.inputMap.get(inputId), resolvedUserId); 679d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim userState.serviceStateMap.put(inputId, serviceState); 6803957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 6812b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim // Send a null token immediately while reconnecting. 6822b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim if (serviceState.mReconnecting == true) { 6832b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim sendSessionTokenToClientLocked(client, inputId, null, null, seq, userId); 6842b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim return; 6852b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim } 6862b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim 6872b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim // Create a new session token and a session state. 6882b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim IBinder sessionToken = new Binder(); 68972ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim SessionState sessionState = new SessionState(sessionToken, inputId, client, 69072ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim seq, callingUid, resolvedUserId); 6912b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim 6922b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim // Add them to the global session state map of the current user. 6932b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim userState.sessionStateMap.put(sessionToken, sessionState); 6942b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim 6952b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim // Also, add them to the session state map of the current service. 696d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim serviceState.mSessionTokens.add(sessionToken); 6973957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo 698d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim if (serviceState.mService != null) { 699d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim createSessionInternalLocked(serviceState.mService, sessionToken, 7007de5e234715a3baa8905afa3dd0c5009af64541fSungsoo Lim resolvedUserId); 7013957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } else { 702d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim updateServiceConnectionLocked(inputId, resolvedUserId); 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 releaseSession(IBinder sessionToken, int userId) { 7123957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo final int callingUid = Binder.getCallingUid(); 7133957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid, 7143957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo userId, "releaseSession"); 7153957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo final long identity = Binder.clearCallingIdentity(); 7163957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo try { 7173957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo synchronized (mLock) { 7182b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim releaseSessionLocked(sessionToken, callingUid, resolvedUserId); 7193957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 7203957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } finally { 7213957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo Binder.restoreCallingIdentity(identity); 7223957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 7233957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 7243957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo 7253957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo @Override 7263957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo public void setSurface(IBinder sessionToken, Surface surface, int userId) { 7273957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo final int callingUid = Binder.getCallingUid(); 7283957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid, 7293957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo userId, "setSurface"); 7303957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo final long identity = Binder.clearCallingIdentity(); 7313957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo try { 7323957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo synchronized (mLock) { 7333957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo try { 7343957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo getSessionLocked(sessionToken, callingUid, resolvedUserId).setSurface( 7353957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo surface); 7363957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } catch (RemoteException e) { 7379a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho Slog.e(TAG, "error in setSurface", e); 7383957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 7393957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 7403957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } finally { 741f836206818ce338db83a3c23c486fb8cab29cb6dYoungsang Cho if (surface != null) { 742f836206818ce338db83a3c23c486fb8cab29cb6dYoungsang Cho // surface is not used in TvInputManagerService. 743f836206818ce338db83a3c23c486fb8cab29cb6dYoungsang Cho surface.release(); 744f836206818ce338db83a3c23c486fb8cab29cb6dYoungsang Cho } 7453957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo Binder.restoreCallingIdentity(identity); 7463957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 7473957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 7483957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo 7493957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo @Override 7503957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo public void setVolume(IBinder sessionToken, float volume, int userId) { 7513957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo final int callingUid = Binder.getCallingUid(); 7523957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid, 7533957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo userId, "setVolume"); 7543957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo final long identity = Binder.clearCallingIdentity(); 7553957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo try { 7563957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo synchronized (mLock) { 7573957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo try { 7583957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo getSessionLocked(sessionToken, callingUid, resolvedUserId).setVolume( 7593957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo volume); 7603957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } catch (RemoteException e) { 7619a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho Slog.e(TAG, "error in setVolume", e); 7623957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 7633957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 7643957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } finally { 7653957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo Binder.restoreCallingIdentity(identity); 7663957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 7673957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 7683957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo 7693957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo @Override 7703957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo public void tune(IBinder sessionToken, final Uri channelUri, int userId) { 7713957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo final int callingUid = Binder.getCallingUid(); 7723957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid, 7733957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo userId, "tune"); 7743957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo final long identity = Binder.clearCallingIdentity(); 7753957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo try { 7763957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo synchronized (mLock) { 7773957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo try { 7783957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo getSessionLocked(sessionToken, callingUid, resolvedUserId).tune(channelUri); 77931dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo 78031dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo long currentTime = System.currentTimeMillis(); 78131dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo long channelId = ContentUris.parseId(channelUri); 78231dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo 78331dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo // Close the open log entry first, if any. 78431dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo UserState userState = getUserStateLocked(resolvedUserId); 78531dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo SessionState sessionState = userState.sessionStateMap.get(sessionToken); 786d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim if (sessionState.mLogUri != null) { 78731dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo SomeArgs args = SomeArgs.obtain(); 788d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim args.arg1 = sessionState.mLogUri; 78931dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo args.arg2 = currentTime; 79031dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo mLogHandler.obtainMessage(LogHandler.MSG_CLOSE_ENTRY, args) 79131dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo .sendToTarget(); 79231dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo } 79331dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo 79431dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo // Create a log entry and fill it later. 79531dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo ContentValues values = new ContentValues(); 796f5cd0b388ac31104e014f9193d06080851a09e18Jae Seo values.put(TvContract.WatchedPrograms.COLUMN_WATCH_START_TIME_UTC_MILLIS, 79731dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo currentTime); 798f5cd0b388ac31104e014f9193d06080851a09e18Jae Seo values.put(TvContract.WatchedPrograms.COLUMN_WATCH_END_TIME_UTC_MILLIS, 0); 799f5cd0b388ac31104e014f9193d06080851a09e18Jae Seo values.put(TvContract.WatchedPrograms.COLUMN_CHANNEL_ID, channelId); 80031dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo 801d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim sessionState.mLogUri = mContentResolver.insert( 80231dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo TvContract.WatchedPrograms.CONTENT_URI, values); 80331dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo SomeArgs args = SomeArgs.obtain(); 804d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim args.arg1 = sessionState.mLogUri; 80531dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo args.arg2 = ContentUris.parseId(channelUri); 80631dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo args.arg3 = currentTime; 80731dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo mLogHandler.obtainMessage(LogHandler.MSG_OPEN_ENTRY, args).sendToTarget(); 8083957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } catch (RemoteException e) { 8099a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho Slog.e(TAG, "error in tune", e); 8103957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo return; 8113957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 8123957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 8133957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } finally { 8143957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo Binder.restoreCallingIdentity(identity); 8153957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 8163957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 8179a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho 8189a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho @Override 8199a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho public void createOverlayView(IBinder sessionToken, IBinder windowToken, Rect frame, 8209a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho int userId) { 8219a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho final int callingUid = Binder.getCallingUid(); 8229a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid, 8239a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho userId, "createOverlayView"); 8249a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho final long identity = Binder.clearCallingIdentity(); 8259a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho try { 8269a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho synchronized (mLock) { 8279a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho try { 8289a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho getSessionLocked(sessionToken, callingUid, resolvedUserId) 8299a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho .createOverlayView(windowToken, frame); 8309a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho } catch (RemoteException e) { 8319a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho Slog.e(TAG, "error in createOverlayView", e); 8329a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho } 8339a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho } 8349a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho } finally { 8359a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho Binder.restoreCallingIdentity(identity); 8369a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho } 8379a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho } 8389a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho 8399a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho @Override 8409a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho public void relayoutOverlayView(IBinder sessionToken, Rect frame, int userId) { 8419a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho final int callingUid = Binder.getCallingUid(); 8429a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid, 8439a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho userId, "relayoutOverlayView"); 8449a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho final long identity = Binder.clearCallingIdentity(); 8459a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho try { 8469a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho synchronized (mLock) { 8479a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho try { 8489a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho getSessionLocked(sessionToken, callingUid, resolvedUserId) 8499a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho .relayoutOverlayView(frame); 8509a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho } catch (RemoteException e) { 8519a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho Slog.e(TAG, "error in relayoutOverlayView", e); 8529a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho } 8539a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho } 8549a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho } finally { 8559a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho Binder.restoreCallingIdentity(identity); 8569a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho } 8579a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho } 8589a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho 8599a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho @Override 8609a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho public void removeOverlayView(IBinder sessionToken, int userId) { 8619a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho final int callingUid = Binder.getCallingUid(); 8629a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid, 8639a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho userId, "removeOverlayView"); 8649a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho final long identity = Binder.clearCallingIdentity(); 8659a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho try { 8669a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho synchronized (mLock) { 8679a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho try { 8689a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho getSessionLocked(sessionToken, callingUid, resolvedUserId) 8699a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho .removeOverlayView(); 8709a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho } catch (RemoteException e) { 8719a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho Slog.e(TAG, "error in removeOverlayView", e); 8729a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho } 8739a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho } 8749a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho } finally { 8759a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho Binder.restoreCallingIdentity(identity); 8769a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho } 8779a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho } 878c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim 879c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim @Override 880c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim public List<TvInputHardwareInfo> getHardwareList() throws RemoteException { 881c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim if (mContext.checkCallingPermission( 882c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim android.Manifest.permission.TV_INPUT_HARDWARE) 883c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim != PackageManager.PERMISSION_GRANTED) { 884c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim return null; 885c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 886c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim 887c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim final long identity = Binder.clearCallingIdentity(); 888c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim try { 889c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim return mTvInputHardwareManager.getHardwareList(); 890c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } finally { 891c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim Binder.restoreCallingIdentity(identity); 892c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 893c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 894c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim 895c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim @Override 896c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim public ITvInputHardware acquireTvInputHardware(int deviceId, 897c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim ITvInputHardwareCallback callback, int userId) throws RemoteException { 898c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim if (mContext.checkCallingPermission( 899c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim android.Manifest.permission.TV_INPUT_HARDWARE) 900c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim != PackageManager.PERMISSION_GRANTED) { 901c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim return null; 902c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 903c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim 904c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim final long identity = Binder.clearCallingIdentity(); 905c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim final int callingUid = Binder.getCallingUid(); 906c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid, 907c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim userId, "acquireTvInputHardware"); 908c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim try { 909c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim return mTvInputHardwareManager.acquireHardware( 910c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim deviceId, callback, callingUid, resolvedUserId); 911c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } finally { 912c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim Binder.restoreCallingIdentity(identity); 913c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 914c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 915c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim 916c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim @Override 917c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim public void releaseTvInputHardware(int deviceId, ITvInputHardware hardware, int userId) 918c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim throws RemoteException { 919c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim if (mContext.checkCallingPermission( 920c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim android.Manifest.permission.TV_INPUT_HARDWARE) 921c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim != PackageManager.PERMISSION_GRANTED) { 922c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim return; 923c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 924c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim 925c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim final long identity = Binder.clearCallingIdentity(); 926c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim final int callingUid = Binder.getCallingUid(); 927c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid, 928c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim userId, "releaseTvInputHardware"); 929c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim try { 930c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim mTvInputHardwareManager.releaseHardware( 931c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim deviceId, hardware, callingUid, resolvedUserId); 932c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } finally { 933c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim Binder.restoreCallingIdentity(identity); 934c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 935c22dbb69194c8e8fe2a32326d1f37a738cad0904Wonsik Kim } 9363957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 9373957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo 9383957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo private static final class UserState { 939d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim // A mapping from the TV input id to its TvInputInfo. 940d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim private final Map<String, TvInputInfo> inputMap = new HashMap<String,TvInputInfo>(); 9413957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo 94272ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim // A mapping from the token of a client to its state. 94372ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim private final Map<IBinder, ClientState> clientStateMap = 94472ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim new HashMap<IBinder, ClientState>(); 94572ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim 9463957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo // A mapping from the name of a TV input service to its state. 947d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim private final Map<String, ServiceState> serviceStateMap = 948d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim new HashMap<String, ServiceState>(); 9493957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo 9503957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo // A mapping from the token of a TV input session to its state. 9513957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo private final Map<IBinder, SessionState> sessionStateMap = 9523957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo new HashMap<IBinder, SessionState>(); 9533957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 9543957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo 95572ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim private final class ClientState implements IBinder.DeathRecipient { 95672ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim private final List<String> mInputIds = new ArrayList<String>(); 95772ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim private final List<IBinder> mSessionTokens = new ArrayList<IBinder>(); 95872ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim 95972ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim private IBinder mClientToken; 96072ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim private final int mUserId; 96172ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim 96272ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim ClientState(IBinder clientToken, int userId) { 96372ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim mClientToken = clientToken; 96472ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim mUserId = userId; 96572ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim } 96672ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim 96772ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim public boolean isEmpty() { 96872ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim return mInputIds.isEmpty() && mSessionTokens.isEmpty(); 96972ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim } 97072ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim 97172ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim @Override 97272ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim public void binderDied() { 97372ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim synchronized (mLock) { 97472ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim UserState userState = getUserStateLocked(mUserId); 97572ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim // DO NOT remove the client state of clientStateMap in this method. It will be 97672ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim // removed in releaseSessionLocked() or unregisterCallbackInternalLocked(). 97772ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim ClientState clientState = userState.clientStateMap.get(mClientToken); 97872ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim if (clientState != null) { 97972ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim while (clientState.mSessionTokens.size() > 0) { 98072ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim releaseSessionLocked( 98172ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim clientState.mSessionTokens.get(0), Process.SYSTEM_UID, mUserId); 98272ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim } 98372ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim while (clientState.mInputIds.size() > 0) { 98472ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim unregisterCallbackInternalLocked( 98572ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim mClientToken, clientState.mInputIds.get(0), mUserId); 98672ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim } 98772ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim } 98872ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim mClientToken = null; 98972ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim } 99072ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim } 99172ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim } 99272ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim 9933957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo private final class ServiceState { 99472ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim private final List<IBinder> mClientTokens = new ArrayList<IBinder>(); 995d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim private final List<IBinder> mSessionTokens = new ArrayList<IBinder>(); 996d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim private final ServiceConnection mConnection; 9972b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim private final TvInputInfo mTvInputInfo; 9983957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo 999d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim private ITvInputService mService; 1000d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim private ServiceCallback mCallback; 1001d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim private boolean mBound; 1002d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim private boolean mAvailable; 10032b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim private boolean mReconnecting; 10043957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo 1005d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim private ServiceState(TvInputInfo inputInfo, int userId) { 10062b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim mTvInputInfo = inputInfo; 10072b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim mConnection = new InputServiceConnection(inputInfo, userId); 10083957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 10093957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 10103957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo 10112b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim private final class SessionState implements IBinder.DeathRecipient { 1012d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim private final String mInputId; 1013d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim private final ITvInputClient mClient; 1014d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim private final int mSeq; 1015d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim private final int mCallingUid; 10162b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim private final int mUserId; 101772ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim private final IBinder mSessionToken; 1018d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim private ITvInputSession mSession; 1019d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim private Uri mLogUri; 10203957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo 102172ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim private SessionState(IBinder sessionToken, String inputId, ITvInputClient client, int seq, 10222b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim int callingUid, int userId) { 102372ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim mSessionToken = sessionToken; 10242b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim mInputId = inputId; 10252b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim mClient = client; 10262b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim mSeq = seq; 10272b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim mCallingUid = callingUid; 10282b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim mUserId = userId; 10292b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim } 10302b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim 10312b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim @Override 10322b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim public void binderDied() { 10332b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim synchronized (mLock) { 10342b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim mSession = null; 10352b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim if (mClient != null) { 10362b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim try { 10372b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim mClient.onSessionReleased(mSeq); 10382b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim } catch(RemoteException e) { 10392b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim Slog.e(TAG, "error in onSessionReleased", e); 10402b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim } 10412b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim } 104272ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim removeSessionStateLocked(mSessionToken, mUserId); 10432b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim } 10443957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 10453957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 10463957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo 10473957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo private final class InputServiceConnection implements ServiceConnection { 1048d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim private final TvInputInfo mTvInputInfo; 10493957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo private final int mUserId; 10503957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo 1051d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim private InputServiceConnection(TvInputInfo inputInfo, int userId) { 10523957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo mUserId = userId; 1053d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim mTvInputInfo = inputInfo; 10543957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 10553957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo 10563957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo @Override 10573957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo public void onServiceConnected(ComponentName name, IBinder service) { 10583957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo if (DEBUG) { 1059d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim Slog.d(TAG, "onServiceConnected(inputId=" + mTvInputInfo.getId() + ")"); 10603957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 10613957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo synchronized (mLock) { 1062d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim ServiceState serviceState = getServiceStateLocked(mTvInputInfo.getId(), mUserId); 1063d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim serviceState.mService = ITvInputService.Stub.asInterface(service); 10643957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo 10653957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo // Register a callback, if we need to. 106672ad7bf915ce40d8437a4ee2518ae07b73502e12Sungsoo Lim if (!serviceState.mClientTokens.isEmpty() && serviceState.mCallback == null) { 1067d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim serviceState.mCallback = new ServiceCallback(mUserId); 10683957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo try { 1069d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim serviceState.mService.registerCallback(serviceState.mCallback); 10703957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } catch (RemoteException e) { 10719a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho Slog.e(TAG, "error in registerCallback", e); 10723957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 10733957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 10743957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo 10753957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo // And create sessions, if any. 1076d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim for (IBinder sessionToken : serviceState.mSessionTokens) { 1077d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim createSessionInternalLocked(serviceState.mService, sessionToken, mUserId); 10783957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 10793957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 10803957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 10813957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo 10823957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo @Override 10833957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo public void onServiceDisconnected(ComponentName name) { 10843957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo if (DEBUG) { 1085d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim Slog.d(TAG, "onServiceDisconnected(inputId=" + mTvInputInfo.getId() + ")"); 10863957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 10872b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim if (!mTvInputInfo.getComponent().equals(name)) { 10882b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim throw new IllegalArgumentException("Mismatched ComponentName: " 10892b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim + mTvInputInfo.getComponent() + " (expected), " + name + " (actual)."); 10902b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim } 10912b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim synchronized (mLock) { 10922b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim UserState userState = getUserStateLocked(mUserId); 10932b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim ServiceState serviceState = userState.serviceStateMap.get(mTvInputInfo.getId()); 10942b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim if (serviceState != null) { 10952b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim serviceState.mReconnecting = true; 10962b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim serviceState.mBound = false; 10972b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim serviceState.mService = null; 10982b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim serviceState.mCallback = null; 10992b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim 11002b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim // Send null tokens for not finishing create session events. 11012b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim for (IBinder sessionToken : serviceState.mSessionTokens) { 11022b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim SessionState sessionState = userState.sessionStateMap.get(sessionToken); 11032b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim if (sessionState.mSession == null) { 11042b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim removeSessionStateLocked(sessionToken, sessionState.mUserId); 11052b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim sendSessionTokenToClientLocked(sessionState.mClient, 11062b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim sessionState.mInputId, null, null, sessionState.mSeq, 11072b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim sessionState.mUserId); 11082b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim } 11092b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim } 11102b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim 11112b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim if (serviceState.mAvailable) { 11122b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim serviceState.mAvailable = false; 11132b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim broadcastServiceAvailabilityChangedLocked(serviceState); 11142b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim } 11152b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim updateServiceConnectionLocked(mTvInputInfo.getId(), mUserId); 11162b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim } 11172b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim } 11183957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 11193957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 11203957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo 11213957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo private final class ServiceCallback extends ITvInputServiceCallback.Stub { 11223957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo private final int mUserId; 11233957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo 11243957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo ServiceCallback(int userId) { 11253957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo mUserId = userId; 11263957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 11273957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo 11283957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo @Override 11292b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim public void onAvailabilityChanged(String inputId, boolean isAvailable) { 11303957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo if (DEBUG) { 1131d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim Slog.d(TAG, "onAvailabilityChanged(inputId=" + inputId + ", isAvailable=" 11323957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo + isAvailable + ")"); 11333957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 11343957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo synchronized (mLock) { 1135d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim ServiceState serviceState = getServiceStateLocked(inputId, mUserId); 11362b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim if (serviceState.mAvailable != isAvailable) { 11372b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim serviceState.mAvailable = isAvailable; 11382b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim broadcastServiceAvailabilityChangedLocked(serviceState); 11393957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 11403957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 11413957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 11423957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 114331dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo 114431dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo private final class LogHandler extends Handler { 114531dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo private static final int MSG_OPEN_ENTRY = 1; 114631dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo private static final int MSG_UPDATE_ENTRY = 2; 114731dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo private static final int MSG_CLOSE_ENTRY = 3; 114831dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo 114931dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo public LogHandler(Looper looper) { 115031dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo super(looper); 115131dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo } 115231dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo 115331dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo @Override 115431dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo public void handleMessage(Message msg) { 115531dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo switch (msg.what) { 115631dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo case MSG_OPEN_ENTRY: { 115731dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo SomeArgs args = (SomeArgs) msg.obj; 115831dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo Uri uri = (Uri) args.arg1; 115931dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo long channelId = (long) args.arg2; 116031dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo long time = (long) args.arg3; 116131dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo onOpenEntry(uri, channelId, time); 116231dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo args.recycle(); 116331dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo return; 116431dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo } 116531dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo case MSG_UPDATE_ENTRY: { 116631dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo SomeArgs args = (SomeArgs) msg.obj; 116731dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo Uri uri = (Uri) args.arg1; 116831dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo long channelId = (long) args.arg2; 116931dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo long time = (long) args.arg3; 117031dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo onUpdateEntry(uri, channelId, time); 117131dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo args.recycle(); 117231dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo return; 117331dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo } 117431dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo case MSG_CLOSE_ENTRY: { 117531dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo SomeArgs args = (SomeArgs) msg.obj; 117631dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo Uri uri = (Uri) args.arg1; 117731dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo long time = (long) args.arg2; 117831dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo onCloseEntry(uri, time); 117931dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo args.recycle(); 118031dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo return; 118131dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo } 118231dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo default: { 11836a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo Slog.w(TAG, "Unhandled message code: " + msg.what); 118431dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo return; 118531dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo } 118631dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo } 118731dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo } 118831dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo 118931dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo private void onOpenEntry(Uri uri, long channelId, long watchStarttime) { 119031dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo String[] projection = { 1191f5cd0b388ac31104e014f9193d06080851a09e18Jae Seo TvContract.Programs.COLUMN_TITLE, 1192f5cd0b388ac31104e014f9193d06080851a09e18Jae Seo TvContract.Programs.COLUMN_START_TIME_UTC_MILLIS, 1193f5cd0b388ac31104e014f9193d06080851a09e18Jae Seo TvContract.Programs.COLUMN_END_TIME_UTC_MILLIS, 1194bd23fa0ba1460a8d5194fd7c700030bf9c3f6fcbJae Seo TvContract.Programs.COLUMN_SHORT_DESCRIPTION 119531dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo }; 1196f5cd0b388ac31104e014f9193d06080851a09e18Jae Seo String selection = TvContract.Programs.COLUMN_CHANNEL_ID + "=? AND " 1197f5cd0b388ac31104e014f9193d06080851a09e18Jae Seo + TvContract.Programs.COLUMN_START_TIME_UTC_MILLIS + "<=? AND " 1198f5cd0b388ac31104e014f9193d06080851a09e18Jae Seo + TvContract.Programs.COLUMN_END_TIME_UTC_MILLIS + ">?"; 119931dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo String[] selectionArgs = { 120031dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo String.valueOf(channelId), 120131dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo String.valueOf(watchStarttime), 120231dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo String.valueOf(watchStarttime) 120331dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo }; 1204f5cd0b388ac31104e014f9193d06080851a09e18Jae Seo String sortOrder = TvContract.Programs.COLUMN_START_TIME_UTC_MILLIS + " ASC"; 120531dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo Cursor cursor = null; 120631dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo try { 120731dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo cursor = mContentResolver.query(TvContract.Programs.CONTENT_URI, projection, 120831dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo selection, selectionArgs, sortOrder); 120931dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo if (cursor != null && cursor.moveToNext()) { 121031dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo ContentValues values = new ContentValues(); 1211f5cd0b388ac31104e014f9193d06080851a09e18Jae Seo values.put(TvContract.WatchedPrograms.COLUMN_TITLE, cursor.getString(0)); 1212f5cd0b388ac31104e014f9193d06080851a09e18Jae Seo values.put(TvContract.WatchedPrograms.COLUMN_START_TIME_UTC_MILLIS, 1213f5cd0b388ac31104e014f9193d06080851a09e18Jae Seo cursor.getLong(1)); 121431dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo long endTime = cursor.getLong(2); 1215f5cd0b388ac31104e014f9193d06080851a09e18Jae Seo values.put(TvContract.WatchedPrograms.COLUMN_END_TIME_UTC_MILLIS, endTime); 1216f5cd0b388ac31104e014f9193d06080851a09e18Jae Seo values.put(TvContract.WatchedPrograms.COLUMN_DESCRIPTION, cursor.getString(3)); 121731dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo mContentResolver.update(uri, values, null, null); 121831dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo 121931dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo // Schedule an update when the current program ends. 122031dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo SomeArgs args = SomeArgs.obtain(); 122131dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo args.arg1 = uri; 122231dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo args.arg2 = channelId; 122331dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo args.arg3 = endTime; 122431dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo Message msg = obtainMessage(LogHandler.MSG_UPDATE_ENTRY, args); 122531dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo sendMessageDelayed(msg, endTime - System.currentTimeMillis()); 122631dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo } 122731dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo } finally { 122831dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo if (cursor != null) { 122931dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo cursor.close(); 123031dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo } 123131dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo } 123231dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo } 123331dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo 123431dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo private void onUpdateEntry(Uri uri, long channelId, long time) { 123531dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo String[] projection = { 1236f5cd0b388ac31104e014f9193d06080851a09e18Jae Seo TvContract.WatchedPrograms.COLUMN_WATCH_START_TIME_UTC_MILLIS, 1237f5cd0b388ac31104e014f9193d06080851a09e18Jae Seo TvContract.WatchedPrograms.COLUMN_WATCH_END_TIME_UTC_MILLIS, 1238f5cd0b388ac31104e014f9193d06080851a09e18Jae Seo TvContract.WatchedPrograms.COLUMN_TITLE, 1239f5cd0b388ac31104e014f9193d06080851a09e18Jae Seo TvContract.WatchedPrograms.COLUMN_START_TIME_UTC_MILLIS, 1240f5cd0b388ac31104e014f9193d06080851a09e18Jae Seo TvContract.WatchedPrograms.COLUMN_END_TIME_UTC_MILLIS, 1241f5cd0b388ac31104e014f9193d06080851a09e18Jae Seo TvContract.WatchedPrograms.COLUMN_DESCRIPTION 124231dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo }; 124331dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo Cursor cursor = null; 124431dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo try { 124531dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo cursor = mContentResolver.query(uri, projection, null, null, null); 124631dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo if (cursor != null && cursor.moveToNext()) { 124731dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo long watchStartTime = cursor.getLong(0); 124831dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo long watchEndTime = cursor.getLong(1); 124931dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo String title = cursor.getString(2); 125031dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo long startTime = cursor.getLong(3); 125131dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo long endTime = cursor.getLong(4); 125231dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo String description = cursor.getString(5); 125331dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo 125431dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo // Do nothing if the current log entry is already closed. 125531dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo if (watchEndTime > 0) { 125631dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo return; 125731dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo } 125831dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo 125931dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo // The current program has just ended. Create a (complete) log entry off the 126031dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo // current entry. 126131dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo ContentValues values = new ContentValues(); 1262f5cd0b388ac31104e014f9193d06080851a09e18Jae Seo values.put(TvContract.WatchedPrograms.COLUMN_WATCH_START_TIME_UTC_MILLIS, 126331dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo watchStartTime); 1264f5cd0b388ac31104e014f9193d06080851a09e18Jae Seo values.put(TvContract.WatchedPrograms.COLUMN_WATCH_END_TIME_UTC_MILLIS, time); 1265f5cd0b388ac31104e014f9193d06080851a09e18Jae Seo values.put(TvContract.WatchedPrograms.COLUMN_CHANNEL_ID, channelId); 1266f5cd0b388ac31104e014f9193d06080851a09e18Jae Seo values.put(TvContract.WatchedPrograms.COLUMN_TITLE, title); 1267f5cd0b388ac31104e014f9193d06080851a09e18Jae Seo values.put(TvContract.WatchedPrograms.COLUMN_START_TIME_UTC_MILLIS, startTime); 1268f5cd0b388ac31104e014f9193d06080851a09e18Jae Seo values.put(TvContract.WatchedPrograms.COLUMN_END_TIME_UTC_MILLIS, endTime); 1269f5cd0b388ac31104e014f9193d06080851a09e18Jae Seo values.put(TvContract.WatchedPrograms.COLUMN_DESCRIPTION, description); 127031dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo mContentResolver.insert(TvContract.WatchedPrograms.CONTENT_URI, values); 127131dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo } 127231dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo } finally { 127331dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo if (cursor != null) { 127431dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo cursor.close(); 127531dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo } 127631dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo } 127731dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo // Re-open the current log entry with the next program information. 127831dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo onOpenEntry(uri, channelId, time); 127931dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo } 128031dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo 128131dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo private void onCloseEntry(Uri uri, long watchEndTime) { 128231dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo ContentValues values = new ContentValues(); 1283f5cd0b388ac31104e014f9193d06080851a09e18Jae Seo values.put(TvContract.WatchedPrograms.COLUMN_WATCH_END_TIME_UTC_MILLIS, watchEndTime); 128431dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo mContentResolver.update(uri, values, null, null); 128531dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo } 128631dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo } 12873957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo} 1288