Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit a76f5149 authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Implement callback for current channel infos"

parents 1134c5ad 990957db
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -89,7 +89,7 @@ interface ITvInputManager {
    void timeShiftSetPlaybackParams(in IBinder sessionToken, in PlaybackParams params, int userId);
    void timeShiftEnablePositionTracking(in IBinder sessionToken, boolean enable, int userId);

    List<TvChannelInfo> getTvCurrentChannelInfos(int userId);
    List<TvChannelInfo> getCurrentTvChannelInfos(int userId);

    // For the recording session
    void startRecording(in IBinder sessionToken, in Uri programUri, in Bundle params, int userId);
+2 −0
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@

package android.media.tv;

import android.media.tv.TvChannelInfo;
import android.media.tv.TvInputInfo;

/**
@@ -28,4 +29,5 @@ oneway interface ITvInputManagerCallback {
    void onInputUpdated(in String inputId);
    void onInputStateChanged(in String inputId, int state);
    void onTvInputInfoUpdated(in TvInputInfo TvInputInfo);
    void onCurrentTvChannelInfosUpdated(in List<TvChannelInfo> currentTvChannelInfos);
}
+25 −4
Original line number Diff line number Diff line
@@ -899,6 +899,10 @@ public final class TvInputManager {
         */
        public void onTvInputInfoUpdated(TvInputInfo inputInfo) {
        }

        /** @hide */
        public void onCurrentTvChannelInfosUpdated(List<TvChannelInfo> tvChannelInfos) {
        }
    }

    private static final class TvInputCallbackRecord {
@@ -958,6 +962,16 @@ public final class TvInputManager {
                }
            });
        }

        public void postCurrentTvChannelInfosUpdated(
                final List<TvChannelInfo> currentTvChannelInfos) {
            mHandler.post(new Runnable() {
                @Override
                public void run() {
                    mCallback.onCurrentTvChannelInfosUpdated(currentTvChannelInfos);
                }
            });
        }
    }

    /**
@@ -1262,6 +1276,15 @@ public final class TvInputManager {
                    }
                }
            }

            @Override
            public void onCurrentTvChannelInfosUpdated(List<TvChannelInfo> currentTvChannelInfos) {
                synchronized (mLock) {
                    for (TvInputCallbackRecord record : mCallbackRecords) {
                        record.postCurrentTvChannelInfosUpdated(currentTvChannelInfos);
                    }
                }
            }
        };
        try {
            if (mService != null) {
@@ -1955,11 +1978,9 @@ public final class TvInputManager {
    /**
     * @hide
     */
    public List<TvChannelInfo> getTvCurrentChannelInfos() {
        // TODO: handle retuned() cases and add a method to TvInputCallback
        // TODO: unhide
    public List<TvChannelInfo> getCurrentTvChannelInfos() {
        try {
            return mService.getTvCurrentChannelInfos(mUserId);
            return mService.getCurrentTvChannelInfos(mUserId);
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
+91 −62
Original line number Diff line number Diff line
@@ -699,8 +699,8 @@ public final class TvInputManagerService extends SystemService {
        SessionState sessionState = null;
        try {
            sessionState = getSessionStateLocked(sessionToken, callingUid, userId);
            if (sessionState.session != null) {
            UserState userState = getOrCreateUserStateLocked(userId);
            if (sessionState.session != null) {
                if (sessionToken == userState.mainSessionToken) {
                    setMainLocked(sessionToken, false, callingUid, userId);
                }
@@ -709,6 +709,8 @@ public final class TvInputManagerService extends SystemService {
            }
            sessionState.isCurrent = false;
            sessionState.currentChannel = null;
            notifyCurrentChannelInfosUpdatedLocked(
                    userState, getCurrentTvChannelInfosInternalLocked(userState));
        } catch (RemoteException | SessionNotFoundException e) {
            Slog.e(TAG, "error in releaseSession", e);
        } finally {
@@ -849,6 +851,22 @@ public final class TvInputManagerService extends SystemService {
        }
    }

    private void notifyCurrentChannelInfosUpdatedLocked(
            UserState userState, List<TvChannelInfo> infos) {
        if (DEBUG) {
            Slog.d(TAG, "notifyCurrentChannelInfosUpdatedLocked");
        }
        int n = userState.mCallbacks.beginBroadcast();
        for (int i = 0; i < n; ++i) {
            try {
                userState.mCallbacks.getBroadcastItem(i).onCurrentTvChannelInfosUpdated(infos);
            } catch (RemoteException e) {
                Slog.e(TAG, "failed to report updated current channel infos to callback", e);
            }
        }
        userState.mCallbacks.finishBroadcast();
    }

    private void updateTvInputInfoLocked(UserState userState, TvInputInfo inputInfo) {
        if (DEBUG) {
            Slog.d(TAG, "updateTvInputInfoLocked(inputInfo=" + inputInfo + ")");
@@ -1414,6 +1432,8 @@ public final class TvInputManagerService extends SystemService {
                        if (sessionState != null) {
                            sessionState.isCurrent = true;
                            sessionState.currentChannel = channelUri;
                            notifyCurrentChannelInfosUpdatedLocked(
                                    userState, getCurrentTvChannelInfosInternalLocked(userState));
                        }
                        if (TvContract.isChannelUriForPassthroughInput(channelUri)) {
                            // Do not log the watch history for passthrough inputs.
@@ -2069,79 +2089,20 @@ public final class TvInputManagerService extends SystemService {
        }

        @Override
        public List<TvChannelInfo> getTvCurrentChannelInfos(@UserIdInt int userId) {
        public List<TvChannelInfo> getCurrentTvChannelInfos(@UserIdInt int userId) {
            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(),
                    Binder.getCallingUid(), userId, "getTvCurrentChannelInfos");
            final long identity = Binder.clearCallingIdentity();
            try {
                synchronized (mLock) {
                    UserState userState = getOrCreateUserStateLocked(resolvedUserId);
                    List<TvChannelInfo> channelInfos = new ArrayList<>();
                    boolean watchedProgramsAccess = hasAccessWatchedProgramsPermission();
                    for (SessionState state : userState.sessionStateMap.values()) {
                        if (state.isCurrent) {
                            Integer appTag;
                            int appType;
                            if (state.callingUid == Binder.getCallingUid()) {
                                appTag = APP_TAG_SELF;
                                appType = TvChannelInfo.APP_TYPE_SELF;
                            } else {
                                appTag = userState.mAppTagMap.get(state.callingUid);
                                if (appTag == null) {
                                    appTag = userState.mNextAppTag++;
                                    userState.mAppTagMap.put(state.callingUid, appTag);
                                }
                                appType = isSystemApp(state.componentName.getPackageName())
                                        ? TvChannelInfo.APP_TYPE_SYSTEM
                                        : TvChannelInfo.APP_TYPE_NON_SYSTEM;
                            }
                            channelInfos.add(new TvChannelInfo(
                                    state.inputId,
                                    watchedProgramsAccess ? state.currentChannel : null,
                                    state.isRecordingSession,
                                    isForeground(state.callingPid),
                                    appType,
                                    appTag));
                        }
                    }
                    return channelInfos;
                    return getCurrentTvChannelInfosInternalLocked(userState);
                }
            } finally {
                Binder.restoreCallingIdentity(identity);
            }
        }

        protected boolean isForeground(int pid) {
            if (mActivityManager == null) {
                return false;
            }
            List<RunningAppProcessInfo> appProcesses = mActivityManager.getRunningAppProcesses();
            if (appProcesses == null) {
                return false;
            }
            for (RunningAppProcessInfo appProcess : appProcesses) {
                if (appProcess.pid == pid
                        && appProcess.importance == RunningAppProcessInfo.IMPORTANCE_FOREGROUND) {
                    return true;
                }
            }
            return false;
        }

        private boolean hasAccessWatchedProgramsPermission() {
            return mContext.checkCallingPermission(PERMISSION_ACCESS_WATCHED_PROGRAMS)
                    == PackageManager.PERMISSION_GRANTED;
        }

        private boolean isSystemApp(String pkg) {
            try {
                return (mContext.getPackageManager().getApplicationInfo(pkg, 0).flags
                        & ApplicationInfo.FLAG_SYSTEM) != 0;
            } catch (NameNotFoundException e) {
                return false;
            }
        }

        /**
         * Add a hardware device in the TvInputHardwareManager for CTS testing
         * purpose.
@@ -2312,6 +2273,69 @@ public final class TvInputManagerService extends SystemService {
        }
    }

    private List<TvChannelInfo> getCurrentTvChannelInfosInternalLocked(UserState userState) {
        List<TvChannelInfo> channelInfos = new ArrayList<>();
        boolean watchedProgramsAccess = hasAccessWatchedProgramsPermission();
        for (SessionState state : userState.sessionStateMap.values()) {
            if (state.isCurrent) {
                Integer appTag;
                int appType;
                if (state.callingUid == Binder.getCallingUid()) {
                    appTag = APP_TAG_SELF;
                    appType = TvChannelInfo.APP_TYPE_SELF;
                } else {
                    appTag = userState.mAppTagMap.get(state.callingUid);
                    if (appTag == null) {
                        appTag = userState.mNextAppTag++;
                        userState.mAppTagMap.put(state.callingUid, appTag);
                    }
                    appType = isSystemApp(state.componentName.getPackageName())
                            ? TvChannelInfo.APP_TYPE_SYSTEM
                            : TvChannelInfo.APP_TYPE_NON_SYSTEM;
                }
                channelInfos.add(new TvChannelInfo(
                        state.inputId,
                        watchedProgramsAccess ? state.currentChannel : null,
                        state.isRecordingSession,
                        isForeground(state.callingPid),
                        appType,
                        appTag));
            }
        }
        return channelInfos;
    }

    private boolean isForeground(int pid) {
        if (mActivityManager == null) {
            return false;
        }
        List<RunningAppProcessInfo> appProcesses = mActivityManager.getRunningAppProcesses();
        if (appProcesses == null) {
            return false;
        }
        for (RunningAppProcessInfo appProcess : appProcesses) {
            if (appProcess.pid == pid
                    && appProcess.importance == RunningAppProcessInfo.IMPORTANCE_FOREGROUND) {
                return true;
            }
        }
        return false;
    }

    private boolean hasAccessWatchedProgramsPermission() {
        return mContext.checkCallingPermission(PERMISSION_ACCESS_WATCHED_PROGRAMS)
                == PackageManager.PERMISSION_GRANTED;
    }

    private boolean isSystemApp(String pkg) {
        try {
            return (mContext.getPackageManager().getApplicationInfo(pkg, 0).flags
                    & ApplicationInfo.FLAG_SYSTEM) != 0;
        } catch (NameNotFoundException e) {
            return false;
        }
    }

    private static final class UserState {
        // A mapping from the TV input id to its TvInputState.
        private Map<String, TvInputState> inputMap = new HashMap<>();
@@ -2685,6 +2709,11 @@ public final class TvInputManagerService extends SystemService {
                if (mSessionState.session == null || mSessionState.client == null) {
                    return;
                }
                mSessionState.isCurrent = true;
                mSessionState.currentChannel = channelUri;
                UserState userState = getOrCreateUserStateLocked(mSessionState.userId);
                notifyCurrentChannelInfosUpdatedLocked(
                        userState, getCurrentTvChannelInfosInternalLocked(userState));
                try {
                    // TODO: Consider adding this channel change in the watch log. When we do
                    // that, how we can protect the watch log from malicious tv inputs should