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

Commit 38f5e11e authored by tanaykhemani's avatar tanaykhemani
Browse files

Add fields in MediaDevice to enhance OSw metrics

Test: mp droid
Test: atest InfoMediaManagerTest
Test: atest MediaSwitchingControllerTest
Bug: 428951557
Flag: EXEMPT adding a new method to get value for logging
Change-Id: I1a27d9735691884ffaf844b595c37745c51350bf
parent d914b146
Loading
Loading
Loading
Loading
+31 −37
Original line number Diff line number Diff line
@@ -54,6 +54,7 @@ import com.android.internal.annotations.VisibleForTesting;
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
import com.android.settingslib.bluetooth.LocalBluetoothManager;

import java.util.AbstractMap;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
@@ -118,7 +119,6 @@ public abstract class InfoMediaManager {
        }
    }


    /** Checked exception that signals the specified package is not present in the system. */
    public static class PackageNotAvailableException extends Exception {
        public PackageNotAvailableException(String message) {
@@ -641,8 +641,18 @@ public abstract class InfoMediaManager {
        }
    }

    /**
     * Gets the list of suggested devices.
     *
     * @return the list of suggested devices.
     */
    @NonNull
    List<SuggestedDeviceInfo> getSuggestions() {
    /* package */ List<SuggestedDeviceInfo> getSuggestions() {
        return getSuggestionsWithPackage().getValue();
    }

    @NonNull
    private Map.Entry<String, List<SuggestedDeviceInfo>> getSuggestionsWithPackage() {
        // Give suggestions in the following order
        // 1. Suggestions from the local router
        // 2. Suggestions from the proxy router if only one proxy router is providing suggestions
@@ -650,17 +660,16 @@ public abstract class InfoMediaManager {
        synchronized (mLock) {
            List<SuggestedDeviceInfo> suggestions = mSuggestedDeviceMap.get(mPackageName);
            if (suggestions != null) {
                return suggestions;
            }
            if (mSuggestedDeviceMap.size() == 1) {
                for (List<SuggestedDeviceInfo> packageSuggestions : mSuggestedDeviceMap.values()) {
                    if (packageSuggestions != null) {
                        return packageSuggestions;
                    }
                return new AbstractMap.SimpleEntry<>(mPackageName, suggestions);
            } else if (mSuggestedDeviceMap.size() == 1) {
                Map.Entry<String, List<SuggestedDeviceInfo>> singleEntry =
                        mSuggestedDeviceMap.entrySet().iterator().next();
                if (singleEntry.getValue() != null) {
                    return singleEntry;
                }
            }
        }
        return List.of();
        return new AbstractMap.SimpleEntry<>("", Collections.emptyList());
    }

    // Go through all current MediaDevices, and update the ones that are suggested.
@@ -670,42 +679,27 @@ public abstract class InfoMediaManager {
        }
        Set<String> suggestedDevices = new HashSet<>();
        // Prioritize suggestions from the package, otherwise pick any.
        for (SuggestedDeviceInfo suggestion : getSuggestions()) {
        Map.Entry<String, List<SuggestedDeviceInfo>> deviceSuggestionsByPackage =
                getSuggestionsWithPackage();
        for (SuggestedDeviceInfo suggestion : deviceSuggestionsByPackage.getValue()) {
            suggestedDevices.add(suggestion.getRouteId());
        }
        boolean didUpdate = false;
        String suggestingPackage = deviceSuggestionsByPackage.getKey();
        boolean isSuggestedByApp = mPackageName.equals(suggestingPackage);
        synchronized (mLock) {
            for (MediaDevice device : mMediaDevices) {
                if (device.isSuggestedDevice()) {
                    if (!suggestedDevices.contains(device.getId())) {
                        device.setIsSuggested(false);
                        // Case 1: Device was suggested only by setDeviceSuggestions(), and has been
                        // updated to no longer be suggested.
                        if (!device.isSuggestedByRouteListingPreferences()) {
                            didUpdate = true;
                        }
                        // Case 2: Device was suggested by both setDeviceSuggestions() and RLP.
                        // Since it's still suggested by RLP, no update.
                    } else {
                        // Case 3: Device was suggested (either by RLP or by
                        // setDeviceSuggestions()), and should still be suggested.
                        device.setIsSuggested(true);
                    }
                } else {
                boolean wasSuggested = device.isSuggestedDevice();
                if (suggestedDevices.contains(device.getId())) {
                        // Case 4: Device was not suggested by either RLP or setDeviceSuggestions()
                        // but is now suggested.
                        device.setIsSuggested(true);
                        didUpdate = true;
                    device.setIsSuggested(/* suggested= */ true, isSuggestedByApp);
                } else {
                        // Case 5: Device was not suggested by either RLP or setDeviceSuggestions()
                        // and is still not suggested.
                        device.setIsSuggested(false);
                    device.setIsSuggested(/* suggested= */ false, /* suggestedByApp= */ false);
                }
                if (wasSuggested != device.isSuggestedDevice()) {
                    didUpdate = true;
                }
            }
        }

        return didUpdate;
    }

+38 −2
Original line number Diff line number Diff line
@@ -58,6 +58,7 @@ import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.drawable.Drawable;
import android.media.MediaRoute2Info;
import android.media.MediaRouter2;
import android.media.NearbyDevice;
import android.media.RouteListingPreference;
import android.os.Build;
@@ -116,6 +117,21 @@ public abstract class MediaDevice implements Comparable<MediaDevice> {
        int SELECTION_BEHAVIOR_GO_TO_APP = 2;
    }

    public static final int SUGGESTION_PROVIDER_UNSPECIFIED = 0;
    public static final int SUGGESTION_PROVIDER_RLP = 1;
    public static final int SUGGESTION_PROVIDER_DEVICE_SUGGESTION_APP = 2;
    public static final int SUGGESTION_PROVIDER_DEVICE_SUGGESTION_OTHER = 3;

    @Retention(RetentionPolicy.SOURCE)
    @IntDef(
            value = {
                SUGGESTION_PROVIDER_UNSPECIFIED,
                SUGGESTION_PROVIDER_RLP,
                SUGGESTION_PROVIDER_DEVICE_SUGGESTION_APP,
                SUGGESTION_PROVIDER_DEVICE_SUGGESTION_OTHER
            })
    public @interface SuggestionProvider {}

    @VisibleForTesting
    int mType;

@@ -129,6 +145,7 @@ public abstract class MediaDevice implements Comparable<MediaDevice> {
    @Nullable private final DynamicRouteAttributes mDynamicRouteAttributes;
    protected final RouteListingPreference.Item mRlpItem;
    private boolean mIsSuggested;
    private boolean mIsSuggestedByApp;

    MediaDevice(
            @NonNull Context context,
@@ -328,7 +345,7 @@ public abstract class MediaDevice implements Comparable<MediaDevice> {

    /**
     * Checks if device is suggested device from application. A device can be suggested through
     * either RouteListingPreferences or through MediaRouter2#setDeviceSuggestions.
     * either {@link RouteListingPreference} or through {@link MediaRouter2#setDeviceSuggestions}.
     *
     * <p>Prioritization and conflict resolution between the two APIs is as follows: - Suggestions
     * from both RLP and the new API will be visible in OSw - Only suggestions from the new API will
@@ -351,6 +368,24 @@ public abstract class MediaDevice implements Comparable<MediaDevice> {
                && Api34Impl.isSuggestedDevice(mRlpItem);
    }

    /**
     * Returns the provider influencing the route ordering in the Output Switcher. See {@link
     * SuggestionProvider}
     *
     * @return the provider influencing the route ordering.
     */
    public @SuggestionProvider int getSuggestionProvider() {
        if (!isSuggestedDevice()) {
            return SUGGESTION_PROVIDER_UNSPECIFIED;
        }
        if (isSuggestedByRouteListingPreferences()) {
            return SUGGESTION_PROVIDER_RLP;
        }
        return mIsSuggestedByApp
                ? SUGGESTION_PROVIDER_DEVICE_SUGGESTION_APP
                : SUGGESTION_PROVIDER_DEVICE_SUGGESTION_OTHER;
    }

    void setConnectedRecord() {
        mConnectedRecord++;
        ConnectionRecordManager.getInstance().setConnectionRecord(mContext, getId(),
@@ -466,8 +501,9 @@ public abstract class MediaDevice implements Comparable<MediaDevice> {
    }

    /** Sets whether the current device is suggested. */
    public void setIsSuggested(boolean suggested) {
    public void setIsSuggested(boolean suggested, boolean suggestedByApp) {
        mIsSuggested = suggested;
        mIsSuggestedByApp = suggestedByApp;
    }

    /**
+83 −3
Original line number Diff line number Diff line
@@ -19,9 +19,14 @@ import static android.media.MediaRoute2Info.TYPE_BLUETOOTH_A2DP;
import static android.media.MediaRoute2Info.TYPE_BUILTIN_SPEAKER;
import static android.media.MediaRoute2Info.TYPE_REMOTE_SPEAKER;
import static android.media.MediaRoute2Info.TYPE_WIRED_HEADPHONES;
import static android.media.RouteListingPreference.Item.FLAG_SUGGESTED;
import static android.media.RouteListingPreference.Item.SELECTION_BEHAVIOR_GO_TO_APP;

import static com.android.settingslib.media.LocalMediaManager.MediaDeviceState.STATE_SELECTED;
import static com.android.settingslib.media.MediaDevice.SUGGESTION_PROVIDER_DEVICE_SUGGESTION_APP;
import static com.android.settingslib.media.MediaDevice.SUGGESTION_PROVIDER_DEVICE_SUGGESTION_OTHER;
import static com.android.settingslib.media.MediaDevice.SUGGESTION_PROVIDER_RLP;
import static com.android.settingslib.media.MediaDevice.SUGGESTION_PROVIDER_UNSPECIFIED;
import static com.android.settingslib.media.MediaDevice.SelectionBehavior.SELECTION_BEHAVIOR_TRANSFER;

import static com.google.common.truth.Truth.assertThat;
@@ -387,8 +392,8 @@ public class MediaDeviceTest {

    @Test
    public void compareTo_suggestedDevice_comesBeforeNonSuggested() {
        mInfoMediaDevice2.setIsSuggested(true);
        mInfoMediaDevice1.setIsSuggested(false);
        mInfoMediaDevice2.setIsSuggested(/* suggested= */ true, /* suggestedByApp= */ true);
        mInfoMediaDevice1.setIsSuggested(/* suggested= */ false, /* suggestedByApp= */ true);

        mMediaDevices.add(mInfoMediaDevice1);
        mMediaDevices.add(mInfoMediaDevice2);
@@ -402,7 +407,7 @@ public class MediaDeviceTest {

    @Test
    public void compareTo_selectedAndSuggested_selectedIsFirst() {
        mInfoMediaDevice1.setIsSuggested(true);
        mInfoMediaDevice1.setIsSuggested(/* suggested= */ true, /* suggestedByApp= */ true);
        mInfoMediaDevice2.setState(STATE_SELECTED);

        mMediaDevices.add(mInfoMediaDevice1);
@@ -608,4 +613,79 @@ public class MediaDeviceTest {
        assertThat(mediaDevice.isSelectable()).isFalse();
        assertThat(mediaDevice.isDeselectable()).isFalse();
    }

    @Test
    public void getSuggestionProvider_notSuggestedDevice_returnsSuggestionProviderUnspecified() {
        MediaDevice device =
                new PhoneMediaDevice(
                        mContext,
                        mRouteInfo1,
                        /* dynamicRouteAttributes= */ null,
                        /* item= */ null);
        assertThat(device.getSuggestionProvider()).isEqualTo(SUGGESTION_PROVIDER_UNSPECIFIED);
    }

    @Test
    public void getSuggestionProvider_rlpSuggestedDevice_returnsSuggestionProviderRlp() {
        RouteListingPreference.Item item =
                new RouteListingPreference.Item.Builder(DEVICE_ADDRESS_1)
                        .setSelectionBehavior(SELECTION_BEHAVIOR_TRANSFER)
                        .setFlags(FLAG_SUGGESTED)
                        .build();
        MediaDevice device =
                new PhoneMediaDevice(
                        mContext,
                        mRouteInfo1,
                        /* dynamicRouteAttributes= */ null,
                        /* item= */ item);

        assertThat(device.getSuggestionProvider()).isEqualTo(SUGGESTION_PROVIDER_RLP);
    }

    @Test
    public void getSuggestionProvider_rlpAndDeviceSuggestion_returnsSuggestionProviderRlp() {
        RouteListingPreference.Item item =
                new RouteListingPreference.Item.Builder(DEVICE_ADDRESS_1)
                        .setSelectionBehavior(SELECTION_BEHAVIOR_TRANSFER)
                        .setFlags(FLAG_SUGGESTED)
                        .build();

        MediaDevice device =
                new PhoneMediaDevice(
                        mContext,
                        mRouteInfo1,
                        /* dynamicRouteAttributes= */ null,
                        /* item= */ item);
        device.setIsSuggested(/* suggested= */ true, /* suggestedByApp= */ true);

        assertThat(device.getSuggestionProvider()).isEqualTo(SUGGESTION_PROVIDER_RLP);
    }

    @Test
    public void getSuggestionProvider_suggestedDeviceNotByApp_returnsSuggestionProviderOther() {
        MediaDevice device =
                new PhoneMediaDevice(
                        mContext,
                        mRouteInfo1,
                        /* dynamicRouteAttributes= */ null,
                        /* item= */ null);
        device.setIsSuggested(/* suggested= */ true, /* suggestedByApp= */ false);

        assertThat(device.getSuggestionProvider())
                .isEqualTo(SUGGESTION_PROVIDER_DEVICE_SUGGESTION_OTHER);
    }

    @Test
    public void getSuggestionProvider_suggestedDeviceByApp_returnsSuggestionProviderApp() {
        MediaDevice device =
                new PhoneMediaDevice(
                        mContext,
                        mRouteInfo1,
                        /* dynamicRouteAttributes= */ null,
                        /* item= */ null);
        device.setIsSuggested(/* suggested= */ true, /* suggestedByApp= */ true);

        assertThat(device.getSuggestionProvider())
                .isEqualTo(SUGGESTION_PROVIDER_DEVICE_SUGGESTION_APP);
    }
}
+20 −9
Original line number Diff line number Diff line
@@ -100,7 +100,8 @@ public class MediaOutputMetricLogger {
                mRemoteDeviceCount,
                mAppliedDeviceCountWithinRemoteGroup,
                mTargetDevice.isSuggestedDevice(),
                mTargetDevice.hasOngoingSession());
                mTargetDevice.hasOngoingSession(),
                mTargetDevice.getSuggestionProvider());
    }

    /**
@@ -118,7 +119,8 @@ public class MediaOutputMetricLogger {
                SysUiStatsLog.MEDIA_OUTPUT_OP_INTERACTION_REPORTED__INTERACTION_TYPE__ADJUST_VOLUME,
                getInteractionDeviceType(source),
                getLoggingPackageName(),
                source.isSuggestedDevice());
                source.isSuggestedDevice(),
                source.getSuggestionProvider());
    }

    /**
@@ -134,7 +136,9 @@ public class MediaOutputMetricLogger {
                SysUiStatsLog.MEDIA_OUTPUT_OP_INTERACTION_REPORTED__INTERACTION_TYPE__STOP_SHARING,
                SysUiStatsLog.MEDIA_OUTPUT_OP_INTERACTION_REPORTED__TARGET__UNKNOWN_TYPE,
                getLoggingPackageName(),
                /*isSuggestedDevice = */false);
                /* isSuggestedDevice= */ false,
                SysUiStatsLog
                        .MEDIA_OUTPUT_OP_INTERACTION_REPORTED__SUGGESTION_PROVIDER__UNSPECIFIED);
    }

    /**
@@ -150,7 +154,9 @@ public class MediaOutputMetricLogger {
                SysUiStatsLog.MEDIA_OUTPUT_OP_INTERACTION_REPORTED__INTERACTION_TYPE__STOP_CASTING,
                SysUiStatsLog.MEDIA_OUTPUT_OP_INTERACTION_REPORTED__TARGET__UNKNOWN_TYPE,
                getLoggingPackageName(),
                /*isSuggestedDevice = */false);
                /* isSuggestedDevice= */ false,
                SysUiStatsLog
                        .MEDIA_OUTPUT_OP_INTERACTION_REPORTED__SUGGESTION_PROVIDER__UNSPECIFIED);
    }

    /**
@@ -166,7 +172,8 @@ public class MediaOutputMetricLogger {
                SysUiStatsLog.MEDIA_OUTPUT_OP_INTERACTION_REPORTED__INTERACTION_TYPE__EXPANSION,
                getInteractionDeviceType(source),
                getLoggingPackageName(),
                source.isSuggestedDevice());
                source.isSuggestedDevice(),
                source.getSuggestionProvider());
    }

    /**
@@ -182,7 +189,8 @@ public class MediaOutputMetricLogger {
                SysUiStatsLog.MEDIA_OUTPUT_OP_INTERACTION_REPORTED__INTERACTION_TYPE__CONTRACTION,
                getInteractionDeviceType(source),
                getLoggingPackageName(),
                source.isSuggestedDevice());
                source.isSuggestedDevice(),
                source.getSuggestionProvider());
    }

    /**
@@ -198,7 +206,8 @@ public class MediaOutputMetricLogger {
                SysUiStatsLog.MEDIA_OUTPUT_OP_INTERACTION_REPORTED__INTERACTION_TYPE__MUTE,
                getInteractionDeviceType(source),
                getLoggingPackageName(),
                source.isSuggestedDevice());
                source.isSuggestedDevice(),
                source.getSuggestionProvider());
    }

    /**
@@ -214,7 +223,8 @@ public class MediaOutputMetricLogger {
                SysUiStatsLog.MEDIA_OUTPUT_OP_INTERACTION_REPORTED__INTERACTION_TYPE__UNMUTE,
                getInteractionDeviceType(source),
                getLoggingPackageName(),
                source.isSuggestedDevice());
                source.isSuggestedDevice(),
                source.getSuggestionProvider());
    }

    /**
@@ -246,7 +256,8 @@ public class MediaOutputMetricLogger {
                mRemoteDeviceCount,
                mAppliedDeviceCountWithinRemoteGroup,
                mTargetDevice.isSuggestedDevice(),
                mTargetDevice.hasOngoingSession());
                mTargetDevice.hasOngoingSession(),
                mTargetDevice.getSuggestionProvider());
    }

    private void updateLoggingDeviceCount(List<MediaDevice> deviceList) {