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

Commit 38b97132 authored by Tanay Khemani's avatar Tanay Khemani Committed by Android (Google) Code Review
Browse files

Merge "Add fields in MediaDevice to enhance OSw metrics" into main

parents e8f446d7 38f5e11e
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) {