TvInputManagerService.java revision 2b35a72a69f6fc39d21f7de9e21044d64db1380d
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; 343957091ba8f08c02b5e781098cb955a5f697a1ffJae Seoimport android.net.Uri; 353957091ba8f08c02b5e781098cb955a5f697a1ffJae Seoimport android.os.Binder; 3631dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seoimport android.os.Handler; 373957091ba8f08c02b5e781098cb955a5f697a1ffJae Seoimport android.os.IBinder; 3831dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seoimport android.os.Looper; 3931dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seoimport android.os.Message; 403957091ba8f08c02b5e781098cb955a5f697a1ffJae Seoimport android.os.Process; 413957091ba8f08c02b5e781098cb955a5f697a1ffJae Seoimport android.os.RemoteException; 423957091ba8f08c02b5e781098cb955a5f697a1ffJae Seoimport android.os.UserHandle; 4331dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seoimport android.provider.TvContract; 443957091ba8f08c02b5e781098cb955a5f697a1ffJae Seoimport android.tv.ITvInputClient; 453957091ba8f08c02b5e781098cb955a5f697a1ffJae Seoimport android.tv.ITvInputManager; 463957091ba8f08c02b5e781098cb955a5f697a1ffJae Seoimport android.tv.ITvInputService; 473957091ba8f08c02b5e781098cb955a5f697a1ffJae Seoimport android.tv.ITvInputServiceCallback; 483957091ba8f08c02b5e781098cb955a5f697a1ffJae Seoimport android.tv.ITvInputSession; 493957091ba8f08c02b5e781098cb955a5f697a1ffJae Seoimport android.tv.ITvInputSessionCallback; 503957091ba8f08c02b5e781098cb955a5f697a1ffJae Seoimport android.tv.TvInputInfo; 513957091ba8f08c02b5e781098cb955a5f697a1ffJae Seoimport android.tv.TvInputService; 529a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Choimport android.util.Slog; 533957091ba8f08c02b5e781098cb955a5f697a1ffJae Seoimport android.util.SparseArray; 546a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seoimport android.view.InputChannel; 553957091ba8f08c02b5e781098cb955a5f697a1ffJae Seoimport android.view.Surface; 563957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo 573957091ba8f08c02b5e781098cb955a5f697a1ffJae Seoimport com.android.internal.content.PackageMonitor; 5831dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seoimport com.android.internal.os.SomeArgs; 5931dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seoimport com.android.server.IoThread; 603957091ba8f08c02b5e781098cb955a5f697a1ffJae Seoimport com.android.server.SystemService; 613957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo 623957091ba8f08c02b5e781098cb955a5f697a1ffJae Seoimport java.util.ArrayList; 633957091ba8f08c02b5e781098cb955a5f697a1ffJae Seoimport java.util.HashMap; 643957091ba8f08c02b5e781098cb955a5f697a1ffJae Seoimport java.util.List; 653957091ba8f08c02b5e781098cb955a5f697a1ffJae Seoimport java.util.Map; 663957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo 673957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo/** This class provides a system service that manages television inputs. */ 683957091ba8f08c02b5e781098cb955a5f697a1ffJae Seopublic final class TvInputManagerService extends SystemService { 693957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo // STOPSHIP: Turn debugging off. 703957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo private static final boolean DEBUG = true; 713957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo private static final String TAG = "TvInputManagerService"; 723957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo 733957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo private final Context mContext; 743957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo 7531dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo private final ContentResolver mContentResolver; 7631dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo 773957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo // A global lock. 783957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo private final Object mLock = new Object(); 793957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo 803957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo // ID of the current user. 813957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo private int mCurrentUserId = UserHandle.USER_OWNER; 823957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo 833957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo // A map from user id to UserState. 843957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo private final SparseArray<UserState> mUserStates = new SparseArray<UserState>(); 853957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo 8631dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo private final Handler mLogHandler; 8731dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo 883957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo public TvInputManagerService(Context context) { 893957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo super(context); 9031dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo 913957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo mContext = context; 9231dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo mContentResolver = context.getContentResolver(); 9331dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo mLogHandler = new LogHandler(IoThread.get().getLooper()); 9431dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo 953957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo registerBroadcastReceivers(); 9631dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo 973957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo synchronized (mLock) { 983957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo mUserStates.put(mCurrentUserId, new UserState()); 993957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo buildTvInputListLocked(mCurrentUserId); 1003957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 1013957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 1023957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo 1033957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo @Override 1043957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo public void onStart() { 1053957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo publishBinderService(Context.TV_INPUT_SERVICE, new BinderService()); 1063957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 1073957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo 1083957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo private void registerBroadcastReceivers() { 1093957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo PackageMonitor monitor = new PackageMonitor() { 1103957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo @Override 1113957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo public void onSomePackagesChanged() { 1123957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo synchronized (mLock) { 1133957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo buildTvInputListLocked(mCurrentUserId); 1143957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 1153957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 1163957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo }; 1173957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo monitor.register(mContext, null, UserHandle.ALL, true); 1183957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo 1193957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo IntentFilter intentFilter = new IntentFilter(); 1203957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo intentFilter.addAction(Intent.ACTION_USER_SWITCHED); 1213957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo intentFilter.addAction(Intent.ACTION_USER_REMOVED); 1223957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo mContext.registerReceiverAsUser(new BroadcastReceiver() { 1233957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo @Override 1243957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo public void onReceive(Context context, Intent intent) { 1253957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo String action = intent.getAction(); 1263957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo if (Intent.ACTION_USER_SWITCHED.equals(action)) { 1273957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo switchUser(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0)); 1283957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } else if (Intent.ACTION_USER_REMOVED.equals(action)) { 1293957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo removeUser(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0)); 1303957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 1313957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 1323957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo }, UserHandle.ALL, intentFilter, null, null); 1333957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 1343957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo 1353957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo private void buildTvInputListLocked(int userId) { 1363957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo UserState userState = getUserStateLocked(userId); 137d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim userState.inputMap.clear(); 1383957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo 1399a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho if (DEBUG) Slog.d(TAG, "buildTvInputList"); 1403957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo PackageManager pm = mContext.getPackageManager(); 1413957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo List<ResolveInfo> services = pm.queryIntentServices( 1423957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo new Intent(TvInputService.SERVICE_INTERFACE), PackageManager.GET_SERVICES); 1433957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo for (ResolveInfo ri : services) { 1443957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo ServiceInfo si = ri.serviceInfo; 1453957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo if (!android.Manifest.permission.BIND_TV_INPUT.equals(si.permission)) { 1469a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho Slog.w(TAG, "Skipping TV input " + si.name + ": it does not require the permission " 1473957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo + android.Manifest.permission.BIND_TV_INPUT); 1483957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo continue; 1493957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 1503957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo TvInputInfo info = new TvInputInfo(ri); 1519a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho if (DEBUG) Slog.d(TAG, "add " + info.getId()); 152d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim userState.inputMap.put(info.getId(), info); 1533957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 1543957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 1553957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo 1563957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo private void switchUser(int userId) { 1573957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo synchronized (mLock) { 1583957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo if (mCurrentUserId == userId) { 1593957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo return; 1603957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 1613957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo // final int oldUserId = mCurrentUserId; 1623957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo // TODO: Release services and sessions in the old user state, if needed. 1633957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo mCurrentUserId = userId; 1643957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo 1653957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo UserState userState = mUserStates.get(userId); 1663957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo if (userState == null) { 1673957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo userState = new UserState(); 1683957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 1693957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo mUserStates.put(userId, userState); 1703957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo buildTvInputListLocked(userId); 1713957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 1723957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 1733957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo 1743957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo private void removeUser(int userId) { 1753957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo synchronized (mLock) { 176b06cb8870f0407f18bb1225065a93aba2a5de2bfJae Seo UserState userState = mUserStates.get(userId); 177b06cb8870f0407f18bb1225065a93aba2a5de2bfJae Seo if (userState == null) { 178b06cb8870f0407f18bb1225065a93aba2a5de2bfJae Seo return; 179b06cb8870f0407f18bb1225065a93aba2a5de2bfJae Seo } 1803957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo // Release created sessions. 1813957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo for (SessionState state : userState.sessionStateMap.values()) { 182d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim if (state.mSession != null) { 1833957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo try { 184d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim state.mSession.release(); 1853957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } catch (RemoteException e) { 1869a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho Slog.e(TAG, "error in release", e); 1873957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 1883957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 1893957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 1903957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo userState.sessionStateMap.clear(); 1913957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo 1923957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo // Unregister all callbacks and unbind all services. 1933957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo for (ServiceState serviceState : userState.serviceStateMap.values()) { 194d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim if (serviceState.mCallback != null) { 1953957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo try { 196d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim serviceState.mService.unregisterCallback(serviceState.mCallback); 1973957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } catch (RemoteException e) { 1989a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho Slog.e(TAG, "error in unregisterCallback", e); 1993957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 2003957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 201d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim serviceState.mClients.clear(); 202d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim mContext.unbindService(serviceState.mConnection); 2033957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 2043957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo userState.serviceStateMap.clear(); 2053957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo 2063957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo mUserStates.remove(userId); 2073957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 2083957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 2093957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo 2103957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo private UserState getUserStateLocked(int userId) { 2113957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo UserState userState = mUserStates.get(userId); 2123957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo if (userState == null) { 2133957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo throw new IllegalStateException("User state not found for user ID " + userId); 2143957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 2153957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo return userState; 2163957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 2173957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo 218d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim private ServiceState getServiceStateLocked(String inputId, int userId) { 2193957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo UserState userState = getUserStateLocked(userId); 220d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim ServiceState serviceState = userState.serviceStateMap.get(inputId); 2213957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo if (serviceState == null) { 222d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim throw new IllegalStateException("Service state not found for " + inputId + " (userId=" 2237de5e234715a3baa8905afa3dd0c5009af64541fSungsoo Lim + userId + ")"); 2243957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 2253957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo return serviceState; 2263957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 2273957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo 2282b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim private SessionState getSessionStateLocked(IBinder sessionToken, int callingUid, int userId) { 2293957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo UserState userState = getUserStateLocked(userId); 2303957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo SessionState sessionState = userState.sessionStateMap.get(sessionToken); 2313957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo if (sessionState == null) { 2323957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo throw new IllegalArgumentException("Session state not found for token " + sessionToken); 2333957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 2343957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo // Only the application that requested this session or the system can access it. 235d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim if (callingUid != Process.SYSTEM_UID && callingUid != sessionState.mCallingUid) { 2363957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo throw new SecurityException("Illegal access to the session with token " + sessionToken 2373957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo + " from uid " + callingUid); 2383957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 2392b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim return sessionState; 2402b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim } 2412b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim 2422b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim private ITvInputSession getSessionLocked(IBinder sessionToken, int callingUid, int userId) { 2432b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim SessionState sessionState = getSessionStateLocked(sessionToken, callingUid, userId); 244d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim ITvInputSession session = sessionState.mSession; 2453957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo if (session == null) { 2463957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo throw new IllegalStateException("Session not yet created for token " + sessionToken); 2473957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 2483957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo return session; 2493957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 2503957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo 2513957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo private int resolveCallingUserId(int callingPid, int callingUid, int requestedUserId, 2523957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo String methodName) { 2533957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo return ActivityManager.handleIncomingUser(callingPid, callingUid, requestedUserId, false, 2543957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo false, methodName, null); 2553957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 2563957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo 257d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim private void updateServiceConnectionLocked(String inputId, int userId) { 2583957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo UserState userState = getUserStateLocked(userId); 259d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim ServiceState serviceState = userState.serviceStateMap.get(inputId); 2603957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo if (serviceState == null) { 2613957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo return; 2623957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 2632b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim if (serviceState.mReconnecting) { 2642b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim if (!serviceState.mSessionTokens.isEmpty()) { 2652b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim // wait until all the sessions are removed. 2662b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim return; 2672b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim } 2682b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim serviceState.mReconnecting = false; 2692b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim } 270d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim boolean isStateEmpty = serviceState.mClients.isEmpty() 271d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim && serviceState.mSessionTokens.isEmpty(); 272d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim if (serviceState.mService == null && !isStateEmpty && userId == mCurrentUserId) { 2733957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo // This means that the service is not yet connected but its state indicates that we 2743957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo // have pending requests. Then, connect the service. 275d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim if (serviceState.mBound) { 2763957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo // We have already bound to the service so we don't try to bind again until after we 2773957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo // unbind later on. 2783957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo return; 2793957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 2803957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo if (DEBUG) { 281d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim Slog.d(TAG, "bindServiceAsUser(inputId=" + inputId + ", userId=" + userId 2823957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo + ")"); 2833957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 284d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim 285d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim Intent i = new Intent(TvInputService.SERVICE_INTERFACE).setComponent( 286d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim userState.inputMap.get(inputId).getComponent()); 287d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim mContext.bindServiceAsUser(i, serviceState.mConnection, Context.BIND_AUTO_CREATE, 2883957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo new UserHandle(userId)); 289d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim serviceState.mBound = true; 290d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim } else if (serviceState.mService != null && isStateEmpty) { 2913957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo // This means that the service is already connected but its state indicates that we have 2923957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo // nothing to do with it. Then, disconnect the service. 2933957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo if (DEBUG) { 294d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim Slog.d(TAG, "unbindService(inputId=" + inputId + ")"); 2953957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 296d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim mContext.unbindService(serviceState.mConnection); 297d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim userState.serviceStateMap.remove(inputId); 2983957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 2993957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 3003957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo 3013957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo private void createSessionInternalLocked(ITvInputService service, final IBinder sessionToken, 3027de5e234715a3baa8905afa3dd0c5009af64541fSungsoo Lim final int userId) { 3037de5e234715a3baa8905afa3dd0c5009af64541fSungsoo Lim final SessionState sessionState = 3047de5e234715a3baa8905afa3dd0c5009af64541fSungsoo Lim getUserStateLocked(userId).sessionStateMap.get(sessionToken); 3053957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo if (DEBUG) { 306d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim Slog.d(TAG, "createSessionInternalLocked(inputId=" + sessionState.mInputId + ")"); 3073957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 3086a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo 3096a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo final InputChannel[] channels = InputChannel.openInputChannelPair(sessionToken.toString()); 3106a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo 3113957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo // Set up a callback to send the session token. 3123957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo ITvInputSessionCallback callback = new ITvInputSessionCallback.Stub() { 3133957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo @Override 3143957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo public void onSessionCreated(ITvInputSession session) { 3153957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo if (DEBUG) { 316d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim Slog.d(TAG, "onSessionCreated(inputId=" + sessionState.mInputId + ")"); 3173957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 3183957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo synchronized (mLock) { 319d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim sessionState.mSession = session; 320fd5b72f1ed2ee74a4204eef65f560fc82f0b62feDongwon Kang if (session == null) { 321fd5b72f1ed2ee74a4204eef65f560fc82f0b62feDongwon Kang removeSessionStateLocked(sessionToken, userId); 3222b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim sendSessionTokenToClientLocked(sessionState.mClient, sessionState.mInputId, 3232b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim null, null, sessionState.mSeq, userId); 324fd5b72f1ed2ee74a4204eef65f560fc82f0b62feDongwon Kang } else { 3252b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim try { 3262b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim session.asBinder().linkToDeath(sessionState, 0); 3272b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim } catch (RemoteException e) { 3282b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim Slog.e(TAG, "Session is already died."); 3292b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim } 330d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim sendSessionTokenToClientLocked(sessionState.mClient, sessionState.mInputId, 331d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim sessionToken, channels[0], sessionState.mSeq, userId); 332fd5b72f1ed2ee74a4204eef65f560fc82f0b62feDongwon Kang } 3336a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo channels[0].dispose(); 3343957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 3353957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 3363957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo }; 3373957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo 3383957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo // Create a session. When failed, send a null token immediately. 3393957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo try { 3406a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo service.createSession(channels[1], callback); 3413957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } catch (RemoteException e) { 3429a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho Slog.e(TAG, "error in createSession", e); 343fd5b72f1ed2ee74a4204eef65f560fc82f0b62feDongwon Kang removeSessionStateLocked(sessionToken, userId); 344d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim sendSessionTokenToClientLocked(sessionState.mClient, sessionState.mInputId, null, null, 345d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim sessionState.mSeq, userId); 3463957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 3476a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo channels[1].dispose(); 3483957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 3493957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo 350d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim private void sendSessionTokenToClientLocked(ITvInputClient client, String inputId, 3516a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo IBinder sessionToken, InputChannel channel, int seq, int userId) { 3523957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo try { 353d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim client.onSessionCreated(inputId, sessionToken, channel, seq); 3543957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } catch (RemoteException exception) { 3559a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho Slog.e(TAG, "error in onSessionCreated", exception); 3563957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 3572b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim } 3583957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo 3592b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim private void releaseSessionLocked(IBinder sessionToken, int callingUid, int userId) { 3602b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim SessionState sessionState = getSessionStateLocked(sessionToken, callingUid, userId); 3612b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim if (sessionState.mSession != null) { 3622b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim try { 3632b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim sessionState.mSession.release(); 3642b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim } catch (RemoteException e) { 3652b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim Slog.w(TAG, "session is already disapeared", e); 3662b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim } 3672b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim sessionState.mSession = null; 3683957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 3692b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim removeSessionStateLocked(sessionToken, userId); 3703957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 3713957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo 372fd5b72f1ed2ee74a4204eef65f560fc82f0b62feDongwon Kang private void removeSessionStateLocked(IBinder sessionToken, int userId) { 373fd5b72f1ed2ee74a4204eef65f560fc82f0b62feDongwon Kang // Remove the session state from the global session state map of the current user. 374fd5b72f1ed2ee74a4204eef65f560fc82f0b62feDongwon Kang UserState userState = getUserStateLocked(userId); 375fd5b72f1ed2ee74a4204eef65f560fc82f0b62feDongwon Kang SessionState sessionState = userState.sessionStateMap.remove(sessionToken); 376fd5b72f1ed2ee74a4204eef65f560fc82f0b62feDongwon Kang 37731dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo // Close the open log entry, if any. 378d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim if (sessionState.mLogUri != null) { 37931dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo SomeArgs args = SomeArgs.obtain(); 380d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim args.arg1 = sessionState.mLogUri; 38131dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo args.arg2 = System.currentTimeMillis(); 38231dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo mLogHandler.obtainMessage(LogHandler.MSG_CLOSE_ENTRY, args).sendToTarget(); 38331dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo } 38431dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo 3857de5e234715a3baa8905afa3dd0c5009af64541fSungsoo Lim // Also remove the session token from the session token list of the current service. 386d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim ServiceState serviceState = userState.serviceStateMap.get(sessionState.mInputId); 387fd5b72f1ed2ee74a4204eef65f560fc82f0b62feDongwon Kang if (serviceState != null) { 388d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim serviceState.mSessionTokens.remove(sessionToken); 389fd5b72f1ed2ee74a4204eef65f560fc82f0b62feDongwon Kang } 390d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim updateServiceConnectionLocked(sessionState.mInputId, userId); 391fd5b72f1ed2ee74a4204eef65f560fc82f0b62feDongwon Kang } 392fd5b72f1ed2ee74a4204eef65f560fc82f0b62feDongwon Kang 3932b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim private void broadcastServiceAvailabilityChangedLocked(ServiceState serviceState) { 3942b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim for (IBinder iBinder : serviceState.mClients) { 3952b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim ITvInputClient client = ITvInputClient.Stub.asInterface(iBinder); 3962b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim try { 3972b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim client.onAvailabilityChanged( 3982b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim serviceState.mTvInputInfo.getId(), serviceState.mAvailable); 3992b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim } catch (RemoteException e) { 4002b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim Slog.e(TAG, "error in onAvailabilityChanged", e); 4012b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim } 4022b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim } 4032b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim } 4042b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim 4053957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo private final class BinderService extends ITvInputManager.Stub { 4063957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo @Override 4073957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo public List<TvInputInfo> getTvInputList(int userId) { 4083957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), 4093957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo Binder.getCallingUid(), userId, "getTvInputList"); 4103957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo final long identity = Binder.clearCallingIdentity(); 4113957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo try { 4123957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo synchronized (mLock) { 4133957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo UserState userState = getUserStateLocked(resolvedUserId); 414d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim return new ArrayList<TvInputInfo>(userState.inputMap.values()); 4153957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 4163957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } finally { 4173957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo Binder.restoreCallingIdentity(identity); 4183957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 4193957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 4203957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo 4213957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo @Override 422d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim public boolean getAvailability(final ITvInputClient client, final String inputId, 4233957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo int userId) { 4243957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), 4253957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo Binder.getCallingUid(), userId, "getAvailability"); 4263957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo final long identity = Binder.clearCallingIdentity(); 4273957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo try { 4283957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo synchronized (mLock) { 4293957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo UserState userState = getUserStateLocked(resolvedUserId); 430d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim ServiceState serviceState = userState.serviceStateMap.get(inputId); 4313957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo if (serviceState != null) { 4323957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo // We already know the status of this input service. Return the cached 4333957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo // status. 434d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim return serviceState.mAvailable; 4353957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 4363957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 4373957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } finally { 4383957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo Binder.restoreCallingIdentity(identity); 4393957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 4403957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo return false; 4413957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 4423957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo 4433957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo @Override 444d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim public void registerCallback(final ITvInputClient client, final String inputId, 4453957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo int userId) { 4463957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), 4473957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo Binder.getCallingUid(), userId, "registerCallback"); 4483957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo final long identity = Binder.clearCallingIdentity(); 4493957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo try { 4503957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo synchronized (mLock) { 4513957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo // Create a new service callback and add it to the callback map of the current 4523957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo // service. 4533957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo UserState userState = getUserStateLocked(resolvedUserId); 454d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim ServiceState serviceState = userState.serviceStateMap.get(inputId); 4553957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo if (serviceState == null) { 456d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim serviceState = new ServiceState( 457d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim userState.inputMap.get(inputId), resolvedUserId); 458d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim userState.serviceStateMap.put(inputId, serviceState); 4593957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 4603957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo IBinder iBinder = client.asBinder(); 461d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim if (!serviceState.mClients.contains(iBinder)) { 462d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim serviceState.mClients.add(iBinder); 4633957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 464d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim if (serviceState.mService != null) { 465d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim if (serviceState.mCallback != null) { 4663957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo // We already handled. 4673957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo return; 4683957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 469d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim serviceState.mCallback = new ServiceCallback(resolvedUserId); 4703957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo try { 471d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim serviceState.mService.registerCallback(serviceState.mCallback); 4723957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } catch (RemoteException e) { 4739a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho Slog.e(TAG, "error in registerCallback", e); 4743957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 4753957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } else { 476d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim updateServiceConnectionLocked(inputId, resolvedUserId); 4773957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 4783957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 4793957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } finally { 4803957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo Binder.restoreCallingIdentity(identity); 4813957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 4823957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 4833957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo 4843957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo @Override 485d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim public void unregisterCallback(ITvInputClient client, String inputId, int userId) { 4863957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), 4873957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo Binder.getCallingUid(), userId, "unregisterCallback"); 4883957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo final long identity = Binder.clearCallingIdentity(); 4893957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo try { 4903957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo synchronized (mLock) { 4913957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo UserState userState = getUserStateLocked(resolvedUserId); 492d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim ServiceState serviceState = userState.serviceStateMap.get(inputId); 4933957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo if (serviceState == null) { 4943957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo return; 4953957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 4963957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo 4973957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo // Remove this client from the client list and unregister the callback. 498d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim serviceState.mClients.remove(client.asBinder()); 499d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim if (!serviceState.mClients.isEmpty()) { 5003957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo // We have other clients who want to keep the callback. Do this later. 5013957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo return; 5023957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 503d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim if (serviceState.mService == null || serviceState.mCallback == null) { 5043957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo return; 5053957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 5063957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo try { 507d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim serviceState.mService.unregisterCallback(serviceState.mCallback); 5083957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } catch (RemoteException e) { 5099a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho Slog.e(TAG, "error in unregisterCallback", e); 5103957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } finally { 511d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim serviceState.mCallback = null; 512d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim updateServiceConnectionLocked(inputId, resolvedUserId); 5133957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 5143957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 5153957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } finally { 5163957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo Binder.restoreCallingIdentity(identity); 5173957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 5183957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 5193957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo 5203957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo @Override 521d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim public void createSession(final ITvInputClient client, final String inputId, 5223957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo int seq, int userId) { 5233957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo final int callingUid = Binder.getCallingUid(); 5243957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid, 5253957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo userId, "createSession"); 5263957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo final long identity = Binder.clearCallingIdentity(); 5273957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo try { 5283957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo synchronized (mLock) { 5293957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo UserState userState = getUserStateLocked(resolvedUserId); 530d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim ServiceState serviceState = userState.serviceStateMap.get(inputId); 5313957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo if (serviceState == null) { 532d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim serviceState = new ServiceState( 533d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim userState.inputMap.get(inputId), resolvedUserId); 534d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim userState.serviceStateMap.put(inputId, serviceState); 5353957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 5362b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim // Send a null token immediately while reconnecting. 5372b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim if (serviceState.mReconnecting == true) { 5382b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim sendSessionTokenToClientLocked(client, inputId, null, null, seq, userId); 5392b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim return; 5402b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim } 5412b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim 5422b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim // Create a new session token and a session state. 5432b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim IBinder sessionToken = new Binder(); 5442b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim SessionState sessionState = new SessionState( 5452b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim sessionToken, inputId, client, seq, callingUid, resolvedUserId); 5462b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim 5472b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim // Add them to the global session state map of the current user. 5482b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim userState.sessionStateMap.put(sessionToken, sessionState); 5492b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim 5502b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim // Also, add them to the session state map of the current service. 551d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim serviceState.mSessionTokens.add(sessionToken); 5523957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo 553d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim if (serviceState.mService != null) { 554d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim createSessionInternalLocked(serviceState.mService, sessionToken, 5557de5e234715a3baa8905afa3dd0c5009af64541fSungsoo Lim resolvedUserId); 5563957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } else { 557d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim updateServiceConnectionLocked(inputId, resolvedUserId); 5583957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 5593957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 5603957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } finally { 5613957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo Binder.restoreCallingIdentity(identity); 5623957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 5633957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 5643957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo 5653957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo @Override 5663957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo public void releaseSession(IBinder sessionToken, int userId) { 5673957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo final int callingUid = Binder.getCallingUid(); 5683957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid, 5693957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo userId, "releaseSession"); 5703957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo final long identity = Binder.clearCallingIdentity(); 5713957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo try { 5723957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo synchronized (mLock) { 5732b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim releaseSessionLocked(sessionToken, callingUid, resolvedUserId); 5743957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 5753957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } finally { 5763957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo Binder.restoreCallingIdentity(identity); 5773957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 5783957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 5793957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo 5803957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo @Override 5813957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo public void setSurface(IBinder sessionToken, Surface surface, int userId) { 5823957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo final int callingUid = Binder.getCallingUid(); 5833957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid, 5843957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo userId, "setSurface"); 5853957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo final long identity = Binder.clearCallingIdentity(); 5863957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo try { 5873957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo synchronized (mLock) { 5883957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo try { 5893957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo getSessionLocked(sessionToken, callingUid, resolvedUserId).setSurface( 5903957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo surface); 5913957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } catch (RemoteException e) { 5929a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho Slog.e(TAG, "error in setSurface", e); 5933957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 5943957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 5953957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } finally { 596f836206818ce338db83a3c23c486fb8cab29cb6dYoungsang Cho if (surface != null) { 597f836206818ce338db83a3c23c486fb8cab29cb6dYoungsang Cho // surface is not used in TvInputManagerService. 598f836206818ce338db83a3c23c486fb8cab29cb6dYoungsang Cho surface.release(); 599f836206818ce338db83a3c23c486fb8cab29cb6dYoungsang Cho } 6003957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo Binder.restoreCallingIdentity(identity); 6013957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 6023957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 6033957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo 6043957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo @Override 6053957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo public void setVolume(IBinder sessionToken, float volume, int userId) { 6063957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo final int callingUid = Binder.getCallingUid(); 6073957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid, 6083957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo userId, "setVolume"); 6093957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo final long identity = Binder.clearCallingIdentity(); 6103957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo try { 6113957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo synchronized (mLock) { 6123957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo try { 6133957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo getSessionLocked(sessionToken, callingUid, resolvedUserId).setVolume( 6143957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo volume); 6153957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } catch (RemoteException e) { 6169a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho Slog.e(TAG, "error in setVolume", e); 6173957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 6183957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 6193957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } finally { 6203957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo Binder.restoreCallingIdentity(identity); 6213957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 6223957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 6233957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo 6243957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo @Override 6253957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo public void tune(IBinder sessionToken, final Uri channelUri, int userId) { 6263957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo final int callingUid = Binder.getCallingUid(); 6273957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid, 6283957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo userId, "tune"); 6293957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo final long identity = Binder.clearCallingIdentity(); 6303957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo try { 6313957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo synchronized (mLock) { 6323957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo try { 6333957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo getSessionLocked(sessionToken, callingUid, resolvedUserId).tune(channelUri); 63431dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo 63531dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo long currentTime = System.currentTimeMillis(); 63631dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo long channelId = ContentUris.parseId(channelUri); 63731dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo 63831dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo // Close the open log entry first, if any. 63931dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo UserState userState = getUserStateLocked(resolvedUserId); 64031dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo SessionState sessionState = userState.sessionStateMap.get(sessionToken); 641d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim if (sessionState.mLogUri != null) { 64231dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo SomeArgs args = SomeArgs.obtain(); 643d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim args.arg1 = sessionState.mLogUri; 64431dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo args.arg2 = currentTime; 64531dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo mLogHandler.obtainMessage(LogHandler.MSG_CLOSE_ENTRY, args) 64631dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo .sendToTarget(); 64731dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo } 64831dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo 64931dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo // Create a log entry and fill it later. 65031dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo ContentValues values = new ContentValues(); 65131dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo values.put(TvContract.WatchedPrograms.WATCH_START_TIME_UTC_MILLIS, 65231dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo currentTime); 65331dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo values.put(TvContract.WatchedPrograms.WATCH_END_TIME_UTC_MILLIS, 0); 65431dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo values.put(TvContract.WatchedPrograms.CHANNEL_ID, channelId); 65531dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo 656d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim sessionState.mLogUri = mContentResolver.insert( 65731dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo TvContract.WatchedPrograms.CONTENT_URI, values); 65831dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo SomeArgs args = SomeArgs.obtain(); 659d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim args.arg1 = sessionState.mLogUri; 66031dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo args.arg2 = ContentUris.parseId(channelUri); 66131dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo args.arg3 = currentTime; 66231dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo mLogHandler.obtainMessage(LogHandler.MSG_OPEN_ENTRY, args).sendToTarget(); 6633957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } catch (RemoteException e) { 6649a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho Slog.e(TAG, "error in tune", e); 6653957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo return; 6663957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 6673957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 6683957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } finally { 6693957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo Binder.restoreCallingIdentity(identity); 6703957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 6713957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 6729a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho 6739a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho @Override 6749a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho public void createOverlayView(IBinder sessionToken, IBinder windowToken, Rect frame, 6759a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho int userId) { 6769a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho final int callingUid = Binder.getCallingUid(); 6779a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid, 6789a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho userId, "createOverlayView"); 6799a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho final long identity = Binder.clearCallingIdentity(); 6809a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho try { 6819a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho synchronized (mLock) { 6829a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho try { 6839a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho getSessionLocked(sessionToken, callingUid, resolvedUserId) 6849a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho .createOverlayView(windowToken, frame); 6859a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho } catch (RemoteException e) { 6869a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho Slog.e(TAG, "error in createOverlayView", e); 6879a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho } 6889a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho } 6899a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho } finally { 6909a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho Binder.restoreCallingIdentity(identity); 6919a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho } 6929a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho } 6939a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho 6949a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho @Override 6959a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho public void relayoutOverlayView(IBinder sessionToken, Rect frame, int userId) { 6969a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho final int callingUid = Binder.getCallingUid(); 6979a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid, 6989a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho userId, "relayoutOverlayView"); 6999a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho final long identity = Binder.clearCallingIdentity(); 7009a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho try { 7019a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho synchronized (mLock) { 7029a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho try { 7039a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho getSessionLocked(sessionToken, callingUid, resolvedUserId) 7049a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho .relayoutOverlayView(frame); 7059a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho } catch (RemoteException e) { 7069a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho Slog.e(TAG, "error in relayoutOverlayView", e); 7079a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho } 7089a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho } 7099a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho } finally { 7109a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho Binder.restoreCallingIdentity(identity); 7119a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho } 7129a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho } 7139a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho 7149a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho @Override 7159a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho public void removeOverlayView(IBinder sessionToken, int userId) { 7169a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho final int callingUid = Binder.getCallingUid(); 7179a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid, 7189a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho userId, "removeOverlayView"); 7199a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho final long identity = Binder.clearCallingIdentity(); 7209a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho try { 7219a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho synchronized (mLock) { 7229a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho try { 7239a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho getSessionLocked(sessionToken, callingUid, resolvedUserId) 7249a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho .removeOverlayView(); 7259a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho } catch (RemoteException e) { 7269a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho Slog.e(TAG, "error in removeOverlayView", e); 7279a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho } 7289a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho } 7299a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho } finally { 7309a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho Binder.restoreCallingIdentity(identity); 7319a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho } 7329a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho } 7333957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 7343957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo 7353957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo private static final class UserState { 736d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim // A mapping from the TV input id to its TvInputInfo. 737d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim private final Map<String, TvInputInfo> inputMap = new HashMap<String,TvInputInfo>(); 7383957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo 7393957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo // A mapping from the name of a TV input service to its state. 740d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim private final Map<String, ServiceState> serviceStateMap = 741d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim new HashMap<String, ServiceState>(); 7423957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo 7433957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo // A mapping from the token of a TV input session to its state. 7443957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo private final Map<IBinder, SessionState> sessionStateMap = 7453957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo new HashMap<IBinder, SessionState>(); 7463957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 7473957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo 7483957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo private final class ServiceState { 7492b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim // TODO: need to implement DeathRecipient for clients. 750d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim private final List<IBinder> mClients = new ArrayList<IBinder>(); 751d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim private final List<IBinder> mSessionTokens = new ArrayList<IBinder>(); 752d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim private final ServiceConnection mConnection; 7532b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim private final TvInputInfo mTvInputInfo; 7543957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo 755d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim private ITvInputService mService; 756d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim private ServiceCallback mCallback; 757d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim private boolean mBound; 758d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim private boolean mAvailable; 7592b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim private boolean mReconnecting; 7603957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo 761d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim private ServiceState(TvInputInfo inputInfo, int userId) { 7622b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim mTvInputInfo = inputInfo; 7632b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim mConnection = new InputServiceConnection(inputInfo, userId); 7643957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 7653957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 7663957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo 7672b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim private final class SessionState implements IBinder.DeathRecipient { 768d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim private final String mInputId; 769d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim private final ITvInputClient mClient; 770d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim private final int mSeq; 771d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim private final int mCallingUid; 7722b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim private final int mUserId; 7732b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim private final IBinder mToken; 774d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim private ITvInputSession mSession; 775d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim private Uri mLogUri; 7763957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo 7772b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim private SessionState(IBinder token, String inputId, ITvInputClient client, int seq, 7782b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim int callingUid, int userId) { 7792b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim mToken = token; 7802b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim mInputId = inputId; 7812b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim mClient = client; 7822b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim mSeq = seq; 7832b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim mCallingUid = callingUid; 7842b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim mUserId = userId; 7852b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim } 7862b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim 7872b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim @Override 7882b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim public void binderDied() { 7892b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim synchronized (mLock) { 7902b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim mSession = null; 7912b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim if (mClient != null) { 7922b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim try { 7932b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim mClient.onSessionReleased(mSeq); 7942b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim } catch(RemoteException e) { 7952b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim Slog.e(TAG, "error in onSessionReleased", e); 7962b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim } 7972b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim } 7982b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim removeSessionStateLocked(mToken, mUserId); 7992b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim } 8003957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 8013957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 8023957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo 8033957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo private final class InputServiceConnection implements ServiceConnection { 804d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim private final TvInputInfo mTvInputInfo; 8053957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo private final int mUserId; 8063957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo 807d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim private InputServiceConnection(TvInputInfo inputInfo, int userId) { 8083957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo mUserId = userId; 809d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim mTvInputInfo = inputInfo; 8103957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 8113957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo 8123957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo @Override 8133957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo public void onServiceConnected(ComponentName name, IBinder service) { 8143957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo if (DEBUG) { 815d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim Slog.d(TAG, "onServiceConnected(inputId=" + mTvInputInfo.getId() + ")"); 8163957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 8173957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo synchronized (mLock) { 818d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim ServiceState serviceState = getServiceStateLocked(mTvInputInfo.getId(), mUserId); 819d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim serviceState.mService = ITvInputService.Stub.asInterface(service); 8203957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo 8213957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo // Register a callback, if we need to. 822d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim if (!serviceState.mClients.isEmpty() && serviceState.mCallback == null) { 823d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim serviceState.mCallback = new ServiceCallback(mUserId); 8243957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo try { 825d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim serviceState.mService.registerCallback(serviceState.mCallback); 8263957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } catch (RemoteException e) { 8279a22f0f0a631849d9c622c642d3ab0395f77584bYoungsang Cho Slog.e(TAG, "error in registerCallback", e); 8283957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 8293957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 8303957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo 8313957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo // And create sessions, if any. 832d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim for (IBinder sessionToken : serviceState.mSessionTokens) { 833d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim createSessionInternalLocked(serviceState.mService, sessionToken, mUserId); 8343957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 8353957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 8363957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 8373957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo 8383957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo @Override 8393957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo public void onServiceDisconnected(ComponentName name) { 8403957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo if (DEBUG) { 841d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim Slog.d(TAG, "onServiceDisconnected(inputId=" + mTvInputInfo.getId() + ")"); 8423957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 8432b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim if (!mTvInputInfo.getComponent().equals(name)) { 8442b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim throw new IllegalArgumentException("Mismatched ComponentName: " 8452b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim + mTvInputInfo.getComponent() + " (expected), " + name + " (actual)."); 8462b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim } 8472b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim synchronized (mLock) { 8482b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim UserState userState = getUserStateLocked(mUserId); 8492b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim ServiceState serviceState = userState.serviceStateMap.get(mTvInputInfo.getId()); 8502b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim if (serviceState != null) { 8512b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim serviceState.mReconnecting = true; 8522b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim serviceState.mBound = false; 8532b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim serviceState.mService = null; 8542b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim serviceState.mCallback = null; 8552b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim 8562b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim // Send null tokens for not finishing create session events. 8572b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim for (IBinder sessionToken : serviceState.mSessionTokens) { 8582b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim SessionState sessionState = userState.sessionStateMap.get(sessionToken); 8592b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim if (sessionState.mSession == null) { 8602b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim removeSessionStateLocked(sessionToken, sessionState.mUserId); 8612b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim sendSessionTokenToClientLocked(sessionState.mClient, 8622b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim sessionState.mInputId, null, null, sessionState.mSeq, 8632b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim sessionState.mUserId); 8642b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim } 8652b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim } 8662b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim 8672b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim if (serviceState.mAvailable) { 8682b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim serviceState.mAvailable = false; 8692b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim broadcastServiceAvailabilityChangedLocked(serviceState); 8702b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim } 8712b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim updateServiceConnectionLocked(mTvInputInfo.getId(), mUserId); 8722b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim } 8732b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim } 8743957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 8753957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 8763957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo 8773957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo private final class ServiceCallback extends ITvInputServiceCallback.Stub { 8783957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo private final int mUserId; 8793957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo 8803957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo ServiceCallback(int userId) { 8813957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo mUserId = userId; 8823957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 8833957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo 8843957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo @Override 8852b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim public void onAvailabilityChanged(String inputId, boolean isAvailable) { 8863957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo if (DEBUG) { 887d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim Slog.d(TAG, "onAvailabilityChanged(inputId=" + inputId + ", isAvailable=" 8883957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo + isAvailable + ")"); 8893957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 8903957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo synchronized (mLock) { 891d6672b51c5e07ec376a61057cfbb6bb7491a76b3Sungsoo Lim ServiceState serviceState = getServiceStateLocked(inputId, mUserId); 8922b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim if (serviceState.mAvailable != isAvailable) { 8932b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim serviceState.mAvailable = isAvailable; 8942b35a72a69f6fc39d21f7de9e21044d64db1380dSungsoo Lim broadcastServiceAvailabilityChangedLocked(serviceState); 8953957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 8963957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 8973957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 8983957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo } 89931dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo 90031dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo private final class LogHandler extends Handler { 90131dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo private static final int MSG_OPEN_ENTRY = 1; 90231dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo private static final int MSG_UPDATE_ENTRY = 2; 90331dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo private static final int MSG_CLOSE_ENTRY = 3; 90431dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo 90531dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo public LogHandler(Looper looper) { 90631dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo super(looper); 90731dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo } 90831dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo 90931dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo @Override 91031dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo public void handleMessage(Message msg) { 91131dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo switch (msg.what) { 91231dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo case MSG_OPEN_ENTRY: { 91331dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo SomeArgs args = (SomeArgs) msg.obj; 91431dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo Uri uri = (Uri) args.arg1; 91531dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo long channelId = (long) args.arg2; 91631dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo long time = (long) args.arg3; 91731dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo onOpenEntry(uri, channelId, time); 91831dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo args.recycle(); 91931dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo return; 92031dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo } 92131dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo case MSG_UPDATE_ENTRY: { 92231dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo SomeArgs args = (SomeArgs) msg.obj; 92331dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo Uri uri = (Uri) args.arg1; 92431dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo long channelId = (long) args.arg2; 92531dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo long time = (long) args.arg3; 92631dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo onUpdateEntry(uri, channelId, time); 92731dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo args.recycle(); 92831dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo return; 92931dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo } 93031dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo case MSG_CLOSE_ENTRY: { 93131dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo SomeArgs args = (SomeArgs) msg.obj; 93231dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo Uri uri = (Uri) args.arg1; 93331dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo long time = (long) args.arg2; 93431dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo onCloseEntry(uri, time); 93531dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo args.recycle(); 93631dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo return; 93731dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo } 93831dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo default: { 9396a6059a29edf31e65541b3d8927a46f5846fb0a2Jae Seo Slog.w(TAG, "Unhandled message code: " + msg.what); 94031dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo return; 94131dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo } 94231dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo } 94331dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo } 94431dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo 94531dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo private void onOpenEntry(Uri uri, long channelId, long watchStarttime) { 94631dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo String[] projection = { 94731dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo TvContract.Programs.TITLE, 94831dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo TvContract.Programs.START_TIME_UTC_MILLIS, 94931dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo TvContract.Programs.END_TIME_UTC_MILLIS, 95031dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo TvContract.Programs.DESCRIPTION 95131dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo }; 95231dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo String selection = TvContract.Programs.CHANNEL_ID + "=? AND " 95331dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo + TvContract.Programs.START_TIME_UTC_MILLIS + "<=? AND " 95431dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo + TvContract.Programs.END_TIME_UTC_MILLIS + ">?"; 95531dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo String[] selectionArgs = { 95631dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo String.valueOf(channelId), 95731dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo String.valueOf(watchStarttime), 95831dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo String.valueOf(watchStarttime) 95931dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo }; 96031dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo String sortOrder = TvContract.Programs.START_TIME_UTC_MILLIS + " ASC"; 96131dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo Cursor cursor = null; 96231dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo try { 96331dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo cursor = mContentResolver.query(TvContract.Programs.CONTENT_URI, projection, 96431dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo selection, selectionArgs, sortOrder); 96531dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo if (cursor != null && cursor.moveToNext()) { 96631dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo ContentValues values = new ContentValues(); 96731dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo values.put(TvContract.WatchedPrograms.TITLE, cursor.getString(0)); 96831dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo values.put(TvContract.WatchedPrograms.START_TIME_UTC_MILLIS, cursor.getLong(1)); 96931dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo long endTime = cursor.getLong(2); 97031dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo values.put(TvContract.WatchedPrograms.END_TIME_UTC_MILLIS, endTime); 97131dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo values.put(TvContract.WatchedPrograms.DESCRIPTION, cursor.getString(3)); 97231dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo mContentResolver.update(uri, values, null, null); 97331dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo 97431dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo // Schedule an update when the current program ends. 97531dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo SomeArgs args = SomeArgs.obtain(); 97631dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo args.arg1 = uri; 97731dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo args.arg2 = channelId; 97831dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo args.arg3 = endTime; 97931dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo Message msg = obtainMessage(LogHandler.MSG_UPDATE_ENTRY, args); 98031dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo sendMessageDelayed(msg, endTime - System.currentTimeMillis()); 98131dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo } 98231dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo } finally { 98331dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo if (cursor != null) { 98431dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo cursor.close(); 98531dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo } 98631dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo } 98731dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo } 98831dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo 98931dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo private void onUpdateEntry(Uri uri, long channelId, long time) { 99031dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo String[] projection = { 99131dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo TvContract.WatchedPrograms.WATCH_START_TIME_UTC_MILLIS, 99231dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo TvContract.WatchedPrograms.WATCH_END_TIME_UTC_MILLIS, 99331dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo TvContract.WatchedPrograms.TITLE, 99431dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo TvContract.WatchedPrograms.START_TIME_UTC_MILLIS, 99531dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo TvContract.WatchedPrograms.END_TIME_UTC_MILLIS, 99631dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo TvContract.WatchedPrograms.DESCRIPTION 99731dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo }; 99831dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo Cursor cursor = null; 99931dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo try { 100031dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo cursor = mContentResolver.query(uri, projection, null, null, null); 100131dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo if (cursor != null && cursor.moveToNext()) { 100231dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo long watchStartTime = cursor.getLong(0); 100331dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo long watchEndTime = cursor.getLong(1); 100431dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo String title = cursor.getString(2); 100531dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo long startTime = cursor.getLong(3); 100631dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo long endTime = cursor.getLong(4); 100731dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo String description = cursor.getString(5); 100831dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo 100931dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo // Do nothing if the current log entry is already closed. 101031dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo if (watchEndTime > 0) { 101131dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo return; 101231dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo } 101331dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo 101431dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo // The current program has just ended. Create a (complete) log entry off the 101531dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo // current entry. 101631dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo ContentValues values = new ContentValues(); 101731dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo values.put(TvContract.WatchedPrograms.WATCH_START_TIME_UTC_MILLIS, 101831dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo watchStartTime); 101931dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo values.put(TvContract.WatchedPrograms.WATCH_END_TIME_UTC_MILLIS, time); 102031dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo values.put(TvContract.WatchedPrograms.CHANNEL_ID, channelId); 102131dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo values.put(TvContract.WatchedPrograms.TITLE, title); 102231dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo values.put(TvContract.WatchedPrograms.START_TIME_UTC_MILLIS, startTime); 102331dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo values.put(TvContract.WatchedPrograms.END_TIME_UTC_MILLIS, endTime); 102431dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo values.put(TvContract.WatchedPrograms.DESCRIPTION, description); 102531dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo mContentResolver.insert(TvContract.WatchedPrograms.CONTENT_URI, values); 102631dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo } 102731dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo } finally { 102831dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo if (cursor != null) { 102931dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo cursor.close(); 103031dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo } 103131dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo } 103231dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo // Re-open the current log entry with the next program information. 103331dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo onOpenEntry(uri, channelId, time); 103431dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo } 103531dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo 103631dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo private void onCloseEntry(Uri uri, long watchEndTime) { 103731dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo ContentValues values = new ContentValues(); 103831dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo values.put(TvContract.WatchedPrograms.WATCH_END_TIME_UTC_MILLIS, watchEndTime); 103931dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo mContentResolver.update(uri, values, null, null); 104031dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo } 104131dc634be3610b062fbcc4afa02607ce8f4125f5Jae Seo } 10423957091ba8f08c02b5e781098cb955a5f697a1ffJae Seo} 1043