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

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

Merge "Revert "Revert "Complete [add|remove]OnSessionTokensChangedListener"""

parents 6f5ed04a 375efa1e
Loading
Loading
Loading
Loading
+119 −7
Original line number Diff line number Diff line
@@ -92,6 +92,7 @@ import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.NoSuchElementException;

/**
 * System implementation of MediaSessionManager
@@ -139,6 +140,8 @@ public class MediaSessionService extends SystemService implements Monitor {
    // TODO(jaewan): Make it priority list for handling volume/media key.
    private final Map<SessionToken2, MediaController2> mSessionRecords = new ArrayMap<>();

    private final List<SessionTokensListenerRecord> mSessionTokensListeners = new ArrayList<>();

    public MediaSessionService(Context context) {
        super(context);
        mSessionManagerImpl = new SessionManagerImpl();
@@ -521,6 +524,7 @@ public class MediaSessionService extends SystemService implements Monitor {
        synchronized (mLock) {
            // List to keep the session services that need be removed because they don't exist
            // in the 'services' above.
            boolean notifySessionTokensUpdated = false;
            Set<SessionToken2> sessionTokensToRemove = new HashSet<>();
            for (SessionToken2 token : mSessionRecords.keySet()) {
                if (token.getType() != TYPE_SESSION) {
@@ -553,11 +557,17 @@ public class MediaSessionService extends SystemService implements Monitor {
                // sessionTokensToRemove.
                if (!sessionTokensToRemove.remove(token)) {
                    // New session service is found.
                    mSessionRecords.put(token, null);
                    notifySessionTokensUpdated |= addSessionRecordLocked(token);
                }
            }
            for (SessionToken2 token : sessionTokensToRemove) {
                mSessionRecords.remove(token);
                notifySessionTokensUpdated |= removeSessionRecordLocked(token);
            }

            if (notifySessionTokensUpdated) {
                // TODO(jaewan): Pass proper user id to postSessionTokensUpdated(...)
                postSessionTokensUpdated(UserHandle.USER_ALL);
            }
        }
        if (DEBUG) {
@@ -780,10 +790,14 @@ public class MediaSessionService extends SystemService implements Monitor {

    void destroySession2Internal(SessionToken2 token) {
        synchronized (mLock) {
            boolean notifySessionTokensUpdated = false;
            if (token.getType() == SessionToken2.TYPE_SESSION) {
                mSessionRecords.remove(token);
                notifySessionTokensUpdated |= removeSessionRecordLocked(token);
            } else {
                mSessionRecords.put(token, null);
                notifySessionTokensUpdated |= addSessionRecordLocked(token);
            }
            if (notifySessionTokensUpdated) {
                postSessionTokensUpdated(UserHandle.getUserId(token.getUid()));
            }
        }
    }
@@ -1517,8 +1531,11 @@ public class MediaSessionService extends SystemService implements Monitor {
                    return false;
                }
                Context context = getContext();
                mSessionRecords.put(token, new MediaController2(context, token,
                        context.getMainExecutor(), new ControllerCallback(token)));
                controller = new MediaController2(context, token, context.getMainExecutor(),
                        new ControllerCallback(token));
                if (addSessionRecordLocked(token, controller)) {
                    postSessionTokensUpdated(UserHandle.getUserId(token.getUid()));
                }
                return true;
            }
        }
@@ -1571,16 +1588,37 @@ public class MediaSessionService extends SystemService implements Monitor {
        }

        // TODO(jaewan): Protect this API with permission
        // TODO(jaewan): "userId != calling user" needs extra protection
        @Override
        public void addSessionTokensListener(ISessionTokensListener listener, int userId,
                String packageName) {
            // TODO(jaewan): Implement.
            synchronized (mLock) {
                final SessionTokensListenerRecord record =
                        new SessionTokensListenerRecord(listener, userId);
                try {
                    listener.asBinder().linkToDeath(record, 0);
                } catch (RemoteException e) {
                }
                mSessionTokensListeners.add(record);
            }
        }

        // TODO(jaewan): Protect this API with permission
        @Override
        public void removeSessionTokensListener(ISessionTokensListener listener) {
            // TODO(jaewan): Implement
            synchronized (mLock) {
                IBinder listenerBinder = listener.asBinder();
                for (SessionTokensListenerRecord record : mSessionTokensListeners) {
                    if (listenerBinder.equals(record.mListener.asBinder())) {
                        try {
                            listenerBinder.unlinkToDeath(record, 0);
                        } catch (NoSuchElementException e) {
                        }
                        mSessionTokensListeners.remove(record);
                        break;
                    }
                }
            }
        }

        private int verifySessionsRequest(ComponentName componentName, int userId, final int pid,
@@ -1944,6 +1982,7 @@ public class MediaSessionService extends SystemService implements Monitor {
    final class MessageHandler extends Handler {
        private static final int MSG_SESSIONS_CHANGED = 1;
        private static final int MSG_VOLUME_INITIAL_DOWN = 2;
        private static final int MSG_SESSIONS_TOKENS_CHANGED = 3;
        private final SparseArray<Integer> mIntegerCache = new SparseArray<>();

        @Override
@@ -1962,6 +2001,9 @@ public class MediaSessionService extends SystemService implements Monitor {
                        }
                    }
                    break;
                case MSG_SESSIONS_TOKENS_CHANGED:
                    pushSessionTokensChanged((int) msg.obj);
                    break;
            }
        }

@@ -1990,4 +2032,74 @@ public class MediaSessionService extends SystemService implements Monitor {
            destroySession2Internal(mToken);
        }
    };

    private final class SessionTokensListenerRecord implements IBinder.DeathRecipient {
        private final ISessionTokensListener mListener;
        private final int mUserId;

        public SessionTokensListenerRecord(ISessionTokensListener listener, int userId) {
            mListener = listener;
            mUserId = userId; // TODO should userId be mapped through mFullUserIds?
        }

        @Override
        public void binderDied() {
            synchronized (mLock) {
                mSessionTokensListeners.remove(this);
            }
        }
    }

    private void postSessionTokensUpdated(int userId) {
        mHandler.obtainMessage(MessageHandler.MSG_SESSIONS_TOKENS_CHANGED, userId).sendToTarget();
    }

    private void pushSessionTokensChanged(int userId) {
        synchronized (mLock) {
            List<Bundle> tokens = new ArrayList<>();
            for (SessionToken2 token : mSessionRecords.keySet()) {
                // TODO(jaewan): Remove the check for UserHandle.USER_ALL (shouldn't happen).
                //               This happens when called form buildMediaSessionService2List(...).
                if (UserHandle.getUserId(token.getUid()) == userId
                        || UserHandle.USER_ALL == userId) {
                    tokens.add(token.toBundle());
                }
            }

            for (SessionTokensListenerRecord record : mSessionTokensListeners) {
                // TODO should userId be mapped through mFullUserIds?
                if (record.mUserId == userId || record.mUserId == UserHandle.USER_ALL) {
                    try {
                        record.mListener.onSessionTokensChanged(tokens);
                    } catch (RemoteException e) {
                        Log.w(TAG, "Failed to notify session tokens changed", e);
                    }
                }
            }
        }
    }

    private boolean addSessionRecordLocked(SessionToken2 token) {
        return addSessionRecordLocked(token, null);
    }

    private boolean addSessionRecordLocked(SessionToken2 token, MediaController2 controller) {
        if (mSessionRecords.containsKey(token) && mSessionRecords.get(token) == controller) {
            // The key/value pair already exists, no need to update.
            return false;
        }

        mSessionRecords.put(token, controller);
        return true;
    }

    private boolean removeSessionRecordLocked(SessionToken2 token) {
        if (!mSessionRecords.containsKey(token)) {
            // The key is already removed, no need to remove.
            return false;
        }

        mSessionRecords.remove(token);
        return true;
    }
}