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

Commit bfbdf101 authored by Shenqiu Zhang's avatar Shenqiu Zhang Committed by Android (Google) Code Review
Browse files

Merge "Cleanup the flag fix_output_media_item_list_index_out_of_bounds_exception" into main

parents 0897f1f0 fad8fa40
Loading
Loading
Loading
Loading
+0 −10
Original line number Diff line number Diff line
@@ -270,16 +270,6 @@ flag {
    bug: "293743975"
}

flag {
    name: "fix_output_media_item_list_index_out_of_bounds_exception"
    namespace: "media_better_together"
    description: "Fixes a bug of causing IndexOutOfBoundsException when building media item list."
    bug: "398246089"
    metadata {
        purpose: PURPOSE_BUGFIX
    }
}

flag {
    name: "avoid_binder_calls_during_render"
    namespace: "media_better_together"
+9 −155
Original line number Diff line number Diff line
@@ -68,7 +68,6 @@ import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
import androidx.core.graphics.drawable.IconCompat;

import com.android.internal.annotations.GuardedBy;
import com.android.media.flags.Flags;
import com.android.settingslib.RestrictedLockUtilsInternal;
import com.android.settingslib.Utils;
@@ -89,7 +88,6 @@ import com.android.systemui.broadcast.BroadcastSender;
import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.media.dialog.MediaItem.MediaItemType;
import com.android.systemui.media.nearby.NearbyMediaDevicesManager;
import com.android.systemui.monet.ColorScheme;
import com.android.systemui.plugins.ActivityStarter;
@@ -108,14 +106,12 @@ import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.Executor;
import java.util.function.Function;
import java.util.stream.Collectors;

import javax.inject.Inject;
@@ -626,12 +622,13 @@ public class MediaSwitchingController
                    Collections.sort(devices, Comparator.naturalOrder());
                }
            }
            if (Flags.fixOutputMediaItemListIndexOutOfBoundsException()) {

            // For the first time building list, to make sure the top device is the connected
            // device.
            boolean hasMutingExpectedDevice =
                        avoidBinderCallsForMutingExpectedDevice() ? containsMutingExpectedDevice(
                                devices) : hasMutingExpectedDevice();
                    avoidBinderCallsForMutingExpectedDevice()
                            ? containsMutingExpectedDevice(devices)
                            : hasMutingExpectedDevice();
            boolean needToHandleMutingExpectedDevice =
                    hasMutingExpectedDevice && !isCurrentConnectedDeviceRemote();
            final MediaDevice connectedMediaDevice =
@@ -641,100 +638,6 @@ public class MediaSwitchingController
                    getSelectedMediaDevice(),
                    connectedMediaDevice,
                    needToHandleMutingExpectedDevice);
            } else {
                List<MediaItem> updatedMediaItems =
                        buildMediaItems(
                                mOutputMediaItemListProxy.getOutputMediaItemList(), devices);
                mOutputMediaItemListProxy.clearAndAddAll(updatedMediaItems);
            }
        }
    }

    protected List<MediaItem> buildMediaItems(
            List<MediaItem> oldMediaItems, List<MediaDevice> devices) {
        synchronized (mMediaDevicesLock) {
            // For the first time building list, to make sure the top device is the connected
            // device.
            boolean hasMutingExpectedDevice =
                    avoidBinderCallsForMutingExpectedDevice() ? containsMutingExpectedDevice(
                            devices) : hasMutingExpectedDevice();
            boolean needToHandleMutingExpectedDevice =
                    hasMutingExpectedDevice && !isCurrentConnectedDeviceRemote();
            final MediaDevice connectedMediaDevice =
                    needToHandleMutingExpectedDevice ? null
                            : getCurrentConnectedMediaDevice();
            if (oldMediaItems.isEmpty()) {
                if (connectedMediaDevice == null) {
                    if (DEBUG) {
                        Log.d(TAG, "No connected media device or muting expected device exist.");
                    }
                    return categorizeMediaItemsLocked(
                            /* connectedMediaDevice */ null,
                            devices,
                            needToHandleMutingExpectedDevice);
                } else {
                    // selected device exist
                    return categorizeMediaItemsLocked(
                            connectedMediaDevice,
                            devices,
                            /* needToHandleMutingExpectedDevice */ false);
                }
            }
            // To keep the same list order
            final List<MediaDevice> targetMediaDevices = new ArrayList<>();
            final Map<Integer, MediaItem> dividerItems = new HashMap<>();

            Map<String, MediaDevice> idToMediaDeviceMap =
                    devices.stream()
                            .collect(Collectors.toMap(MediaDevice::getId, Function.identity()));

            for (MediaItem originalMediaItem : oldMediaItems) {
                switch (originalMediaItem.getMediaItemType()) {
                    case MediaItemType.TYPE_GROUP_DIVIDER -> {
                        dividerItems.put(
                                oldMediaItems.indexOf(originalMediaItem), originalMediaItem);
                    }
                    case MediaItemType.TYPE_DEVICE -> {
                        String originalMediaItemId =
                                originalMediaItem.getMediaDevice().orElseThrow().getId();
                        if (idToMediaDeviceMap.containsKey(originalMediaItemId)) {
                            targetMediaDevices.add(idToMediaDeviceMap.get(originalMediaItemId));
                        }
                    }
                    case MediaItemType.TYPE_PAIR_NEW_DEVICE -> {
                        // Do nothing.
                    }
                }
            }
            if (targetMediaDevices.size() != devices.size()) {
                devices.removeAll(targetMediaDevices);
                targetMediaDevices.addAll(devices);
            }
            List<MediaItem> finalMediaItems = targetMediaDevices.stream()
                    .map(MediaItem::createDeviceMediaItem)
                    .collect(Collectors.toList());

            boolean shouldAddFirstSeenSelectedDevice = Flags.enableOutputSwitcherDeviceGrouping();

            if (shouldAddFirstSeenSelectedDevice) {
                finalMediaItems.clear();
                Set<String> selectedDevicesIds = getSelectedMediaDevice().stream()
                        .map(MediaDevice::getId)
                        .collect(Collectors.toSet());
                for (MediaDevice targetMediaDevice : targetMediaDevices) {
                    if (shouldAddFirstSeenSelectedDevice
                            && selectedDevicesIds.contains(targetMediaDevice.getId())) {
                        finalMediaItems.add(MediaItem.createDeviceMediaItem(
                                targetMediaDevice, /* isFirstDeviceInGroup */ true));
                        shouldAddFirstSeenSelectedDevice = false;
                    } else {
                        finalMediaItems.add(MediaItem.createDeviceMediaItem(
                                targetMediaDevice, /* isFirstDeviceInGroup */ false));
                    }
                }
            }
            dividerItems.forEach(finalMediaItems::add);
            return finalMediaItems;
        }
    }

@@ -751,55 +654,6 @@ public class MediaSwitchingController
        }
    }

    /**
     * Initial categorization of current devices, will not be called for updates to the devices
     * list.
     */
    @GuardedBy("mMediaDevicesLock")
    private List<MediaItem> categorizeMediaItemsLocked(
            MediaDevice connectedMediaDevice,
            List<MediaDevice> devices,
            boolean needToHandleMutingExpectedDevice) {
        List<MediaItem> finalMediaItems = new ArrayList<>();
        Set<String> selectedDevicesIds = getSelectedMediaDevice().stream()
                .map(MediaDevice::getId)
                .collect(Collectors.toSet());
        if (connectedMediaDevice != null) {
            selectedDevicesIds.add(connectedMediaDevice.getId());
        }
        boolean groupSelectedDevices = Flags.enableOutputSwitcherDeviceGrouping();
        int nextSelectedItemIndex = 0;
        boolean suggestedDeviceAdded = false;
        boolean displayGroupAdded = false;
        boolean selectedDeviceAdded = false;
        for (MediaDevice device : devices) {
            if (needToHandleMutingExpectedDevice && device.isMutingExpectedDevice()) {
                finalMediaItems.add(0, MediaItem.createDeviceMediaItem(device));
                nextSelectedItemIndex++;
            } else if (!needToHandleMutingExpectedDevice && selectedDevicesIds.contains(
                    device.getId())) {
                if (groupSelectedDevices) {
                    finalMediaItems.add(
                            nextSelectedItemIndex++,
                            MediaItem.createDeviceMediaItem(device, !selectedDeviceAdded));
                    selectedDeviceAdded = true;
                } else {
                    finalMediaItems.add(0, MediaItem.createDeviceMediaItem(device));
                }
            } else {
                if (device.isSuggestedDevice() && !suggestedDeviceAdded) {
                    addSuggestedDeviceGroupDivider(finalMediaItems);
                    suggestedDeviceAdded = true;
                } else if (!device.isSuggestedDevice() && !displayGroupAdded) {
                    addSpeakersAndDisplaysGroupDivider(finalMediaItems);
                    displayGroupAdded = true;
                }
                finalMediaItems.add(MediaItem.createDeviceMediaItem(device));
            }
        }
        return finalMediaItems;
    }

    private void addSuggestedDeviceGroupDivider(List<MediaItem> mediaItems) {
        mediaItems.add(
                MediaItem.createGroupDividerMediaItem(
+18 −34
Original line number Diff line number Diff line
@@ -57,18 +57,16 @@ public class OutputMediaItemListProxy {

    /** Returns the list of output media items. */
    public List<MediaItem> getOutputMediaItemList() {
        if (Flags.fixOutputMediaItemListIndexOutOfBoundsException()) {
        if (isEmpty() && !mOutputMediaItemList.isEmpty()) {
                // Ensures mOutputMediaItemList is empty when all individual media item lists are
                // empty, preventing unexpected state issues.
            // Ensures mOutputMediaItemList is empty when all individual media item lists are empty,
            // preventing unexpected state issues.
            mOutputMediaItemList.clear();
        } else if (!isEmpty() && mOutputMediaItemList.isEmpty()) {
                // When any individual media item list is modified, the cached mOutputMediaItemList
                // is emptied. On the next request for the output media item list, a fresh list is
                // created and stored in the cache.
            // When any individual media item list is modified, the cached mOutputMediaItemList is
            // emptied. On the next request for the output media item list, a fresh list is created
            // and stored in the cache.
            mOutputMediaItemList.addAll(createOutputMediaItemList());
        }
        }
        return mOutputMediaItemList;
    }

@@ -180,41 +178,27 @@ public class OutputMediaItemListProxy {
        mOutputMediaItemList.clear();
    }

    /** Updates the list of output media items with the given list. */
    public void clearAndAddAll(List<MediaItem> updatedMediaItems) {
        mOutputMediaItemList.clear();
        mOutputMediaItemList.addAll(updatedMediaItems);
    }

    /** Removes the media items with muting expected devices. */
    public void removeMutingExpectedDevices() {
        if (Flags.fixOutputMediaItemListIndexOutOfBoundsException()) {
        mSelectedMediaItems.removeIf((MediaItem::isMutingExpectedDevice));
        mSuggestedMediaItems.removeIf((MediaItem::isMutingExpectedDevice));
        mSpeakersAndDisplaysMediaItems.removeIf((MediaItem::isMutingExpectedDevice));
        }
        mOutputMediaItemList.removeIf((MediaItem::isMutingExpectedDevice));
    }

    /** Clears the output media item list. */
    public void clear() {
        if (Flags.fixOutputMediaItemListIndexOutOfBoundsException()) {
        mSelectedMediaItems.clear();
        mSuggestedMediaItems.clear();
        mSpeakersAndDisplaysMediaItems.clear();
        }
        mOutputMediaItemList.clear();
    }

    /** Returns whether the output media item list is empty. */
    public boolean isEmpty() {
        if (Flags.fixOutputMediaItemListIndexOutOfBoundsException()) {
        return mSelectedMediaItems.isEmpty()
                && mSuggestedMediaItems.isEmpty()
                && mSpeakersAndDisplaysMediaItems.isEmpty();
        } else {
            return mOutputMediaItemList.isEmpty();
        }
    }

    private void buildMediaItems(
+0 −1
Original line number Diff line number Diff line
@@ -211,7 +211,6 @@ public class MediaSwitchingControllerTest extends SysuiTestCase {
    @Parameters(name = "{0}")
    public static List<FlagsParameterization> getParams() {
        return FlagsParameterization.allCombinationsOf(
                Flags.FLAG_FIX_OUTPUT_MEDIA_ITEM_LIST_INDEX_OUT_OF_BOUNDS_EXCEPTION,
                Flags.FLAG_ENABLE_OUTPUT_SWITCHER_DEVICE_GROUPING);
    }

+99 −121

File changed.

Preview size limit exceeded, changes collapsed.