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

Commit 5644a46b authored by Kyunglyul Hyun's avatar Kyunglyul Hyun Committed by Android (Google) Code Review
Browse files

Merge "Media: Add group id for media router to sync" into qt-dev

parents 013bc8ae cd18ace5
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -22,4 +22,5 @@ package android.media;
oneway interface IMediaRouterClient {
    void onStateChanged();
    void onRestoreRoute();
    void onSelectedRouteChanged(String routeId);
}
+2 −0
Original line number Diff line number Diff line
@@ -26,6 +26,8 @@ interface IMediaRouterService {
    void registerClientAsUser(IMediaRouterClient client, String packageName, int userId);
    void unregisterClient(IMediaRouterClient client);

    void registerClientGroupId(IMediaRouterClient client, String groupId);

    MediaRouterClientState getState(IMediaRouterClient client);
    boolean isPlaybackActive(IMediaRouterClient client);

+61 −0
Original line number Diff line number Diff line
@@ -20,6 +20,7 @@ import android.Manifest;
import android.annotation.DrawableRes;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemService;
import android.annotation.UnsupportedAppUsage;
import android.app.ActivityThread;
@@ -343,6 +344,16 @@ public class MediaRouter {
            updatePresentationDisplays(displayId);
        }

        public void setRouterGroupId(String groupId) {
            if (mClient != null) {
                try {
                    mMediaRouterService.registerClientGroupId(mClient, groupId);
                } catch (RemoteException ex) {
                    Log.e(TAG, "Unable to register group ID of the client.", ex);
                }
            }
        }

        public Display[] getAllPresentationDisplays() {
            return mDisplayService.getDisplays(DisplayManager.DISPLAY_CATEGORY_PRESENTATION);
        }
@@ -358,6 +369,21 @@ public class MediaRouter {
            }
        }

        void updateSelectedRouteForId(String routeId) {
            RouteInfo selectedRoute = isBluetoothA2dpOn()
                    ? mBluetoothA2dpRoute : mDefaultAudioVideo;
            final int count = mRoutes.size();
            for (int i = 0; i < count; i++) {
                final RouteInfo route = mRoutes.get(i);
                if (TextUtils.equals(route.mGlobalRouteId, routeId)) {
                    selectedRoute = route;
                }
            }
            if (selectedRoute != mSelectedRoute) {
                selectRouteStatic(selectedRoute.mSupportedTypes, selectedRoute, false);
            }
        }

        void setSelectedRoute(RouteInfo info, boolean explicit) {
            // Must be non-reentrant.
            mSelectedRoute = info;
@@ -619,6 +645,15 @@ public class MediaRouter {
                    }
                });
            }

            @Override
            public void onSelectedRouteChanged(String routeId) {
                mHandler.post(() -> {
                    if (Client.this == mClient) {
                        updateSelectedRouteForId(routeId);
                    }
                });
            }
        }
    }

@@ -728,6 +763,13 @@ public class MediaRouter {
     */
    public static final int AVAILABILITY_FLAG_IGNORE_DEFAULT_ROUTE = 1 << 0;

    /**
     * The route group id used for sharing the selected mirroring device.
     * System UI and Settings use this to synchronize their mirroring status.
     * @hide
     */
    public static final String MIRRORING_GROUP_ID = "android.media.mirroring_group";

    // Maps application contexts
    static final HashMap<Context, MediaRouter> sRouters = new HashMap<Context, MediaRouter>();

@@ -847,6 +889,25 @@ public class MediaRouter {
        return false;
    }

    /**
     * Sets the group ID of the router.
     * Media routers with the same ID acts as if they were a single media router.
     * For example, if a media router selects a route, the selected route of routers
     * with the same group ID will be changed automatically.
     *
     * Two routers in a group are supposed to use the same route types.
     *
     * System UI and Settings use this to synchronize their mirroring status.
     * Do not set the router group id unless it's necessary.
     *
     * {@link android.Manifest.permission#CONFIGURE_WIFI_DISPLAY} permission is required to
     * call this method.
     * @hide
     */
    public void setRouterGroupId(@Nullable String groupId) {
        sStatic.setRouterGroupId(groupId);
    }

    /**
     * Add a callback to listen to events about specific kinds of media routes.
     * If the specified callback is already registered, its registration will be updated for any
+122 −1
Original line number Diff line number Diff line
@@ -246,6 +246,29 @@ public final class MediaRouterService extends IMediaRouterService.Stub
        }
    }

    // Binder call
    @Override
    public void registerClientGroupId(IMediaRouterClient client, String groupId) {
        if (client == null) {
            throw new NullPointerException("client must not be null");
        }
        if (mContext.checkCallingOrSelfPermission(
                android.Manifest.permission.CONFIGURE_WIFI_DISPLAY)
                != PackageManager.PERMISSION_GRANTED) {
            Log.w(TAG, "Ignoring client group request because "
                    + "the client doesn't have the CONFIGURE_WIFI_DISPLAY permission.");
            return;
        }
        final long token = Binder.clearCallingIdentity();
        try {
            synchronized (mLock) {
                registerClientGroupIdLocked(client, groupId);
            }
        } finally {
            Binder.restoreCallingIdentity(token);
        }
    }

    // Binder call
    @Override
    public void unregisterClient(IMediaRouterClient client) {
@@ -502,11 +525,37 @@ public final class MediaRouterService extends IMediaRouterService.Stub
        }
    }

    private void registerClientGroupIdLocked(IMediaRouterClient client, String groupId) {
        final IBinder binder = client.asBinder();
        ClientRecord clientRecord = mAllClientRecords.get(binder);
        if (clientRecord == null) {
            Log.w(TAG, "Ignoring group id register request of a unregistered client.");
            return;
        }
        if (TextUtils.equals(clientRecord.mGroupId, groupId)) {
            return;
        }
        UserRecord userRecord = clientRecord.mUserRecord;
        if (clientRecord.mGroupId != null) {
            userRecord.removeFromGroup(clientRecord.mGroupId, clientRecord);
        }
        clientRecord.mGroupId = groupId;
        if (groupId != null) {
            userRecord.addToGroup(groupId, clientRecord);
            userRecord.mHandler.obtainMessage(UserHandler.MSG_UPDATE_SELECTED_ROUTE, groupId)
                .sendToTarget();
        }
    }

    private void unregisterClientLocked(IMediaRouterClient client, boolean died) {
        ClientRecord clientRecord = mAllClientRecords.remove(client.asBinder());
        if (clientRecord != null) {
            UserRecord userRecord = clientRecord.mUserRecord;
            userRecord.mClientRecords.remove(clientRecord);
            if (clientRecord.mGroupId != null) {
                userRecord.removeFromGroup(clientRecord.mGroupId, clientRecord);
                clientRecord.mGroupId = null;
            }
            disposeClientLocked(clientRecord, died);
            disposeUserIfNeededLocked(userRecord); // since client removed from user
        }
@@ -568,6 +617,16 @@ public final class MediaRouterService extends IMediaRouterService.Stub
                        clientRecord.mUserRecord.mHandler.obtainMessage(
                                UserHandler.MSG_SELECT_ROUTE, routeId).sendToTarget();
                    }
                    if (clientRecord.mGroupId != null) {
                        ClientGroup group =
                                clientRecord.mUserRecord.mClientGroupMap.get(clientRecord.mGroupId);
                        if (group != null) {
                            group.mSelectedRouteId = routeId;
                            clientRecord.mUserRecord.mHandler.obtainMessage(
                                UserHandler.MSG_UPDATE_SELECTED_ROUTE, clientRecord.mGroupId)
                                .sendToTarget();
                        }
                    }
                }
            }
        }
@@ -680,6 +739,7 @@ public final class MediaRouterService extends IMediaRouterService.Stub
        public int mRouteTypes;
        public boolean mActiveScan;
        public String mSelectedRouteId;
        public String mGroupId;

        public ClientRecord(UserRecord userRecord, IMediaRouterClient client,
                int uid, int pid, String packageName, boolean trusted) {
@@ -720,6 +780,11 @@ public final class MediaRouterService extends IMediaRouterService.Stub
        }
    }

    final class ClientGroup {
        public String mSelectedRouteId;
        public final List<ClientRecord> mClientRecords = new ArrayList<>();
    }

    /**
     * Information about a particular user.
     * The contents of this object is guarded by mLock.
@@ -729,6 +794,7 @@ public final class MediaRouterService extends IMediaRouterService.Stub
        public final ArrayList<ClientRecord> mClientRecords = new ArrayList<ClientRecord>();
        public final UserHandler mHandler;
        public MediaRouterClientState mRouterState;
        private final ArrayMap<String, ClientGroup> mClientGroupMap = new ArrayMap<>();

        public UserRecord(int userId) {
            mUserId = userId;
@@ -761,6 +827,25 @@ public final class MediaRouterService extends IMediaRouterService.Stub
            }
        }

        public void addToGroup(String groupId, ClientRecord clientRecord) {
            ClientGroup group = mClientGroupMap.get(groupId);
            if (group == null) {
                group = new ClientGroup();
                mClientGroupMap.put(groupId, group);
            }
            group.mClientRecords.add(clientRecord);
        }

        public void removeFromGroup(String groupId, ClientRecord clientRecord) {
            ClientGroup group = mClientGroupMap.get(groupId);
            if (group != null) {
                group.mClientRecords.remove(clientRecord);
                if (group.mClientRecords.size() == 0) {
                    mClientGroupMap.remove(groupId);
                }
            }
        }

        @Override
        public String toString() {
            return "User " + mUserId;
@@ -791,6 +876,7 @@ public final class MediaRouterService extends IMediaRouterService.Stub
        public static final int MSG_REQUEST_UPDATE_VOLUME = 7;
        private static final int MSG_UPDATE_CLIENT_STATE = 8;
        private static final int MSG_CONNECTION_TIMED_OUT = 9;
        private static final int MSG_UPDATE_SELECTED_ROUTE = 10;

        private static final int TIMEOUT_REASON_NOT_AVAILABLE = 1;
        private static final int TIMEOUT_REASON_CONNECTION_LOST = 2;
@@ -867,6 +953,10 @@ public final class MediaRouterService extends IMediaRouterService.Stub
                    connectionTimedOut();
                    break;
                }
                case MSG_UPDATE_SELECTED_ROUTE: {
                    updateSelectedRoute((String) msg.obj);
                    break;
                }
            }
        }

@@ -1191,6 +1281,37 @@ public final class MediaRouterService extends IMediaRouterService.Stub
            }
        }

        private void updateSelectedRoute(String groupId) {
            try {
                String selectedRouteId = null;
                synchronized (mService.mLock) {
                    ClientGroup group = mUserRecord.mClientGroupMap.get(groupId);
                    if (group == null) {
                        return;
                    }
                    selectedRouteId = group.mSelectedRouteId;
                    final int count = group.mClientRecords.size();
                    for (int i = 0; i < count; i++) {
                        ClientRecord clientRecord = group.mClientRecords.get(i);
                        if (!TextUtils.equals(selectedRouteId, clientRecord.mSelectedRouteId)) {
                            mTempClients.add(clientRecord.mClient);
                        }
                    }
                }

                final int count = mTempClients.size();
                for (int i = 0; i < count; i++) {
                    try {
                        mTempClients.get(i).onSelectedRouteChanged(selectedRouteId);
                    } catch (RemoteException ex) {
                        Slog.w(TAG, "Failed to call onSelectedRouteChanged. Client probably died.");
                    }
                }
            } finally {
                mTempClients.clear();
            }
        }

        private int findProviderRecord(RemoteDisplayProviderProxy provider) {
            final int count = mProviderRecords.size();
            for (int i = 0; i < count; i++) {