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

Commit eda918a0 authored by tanaykhemani's avatar tanaykhemani Committed by Santiago Seifert
Browse files

Add suggestion provider to route transfer metrics

Bug: 440346859
Test: atest MediaRouterMetricLoggerTest
Test: atest MediaDeviceTest
Test: Tested with media routing demo app
Flag: EXEMPT METRICS
Change-Id: I4cb02b1d36be53448edf7e800d9e9b20ea2dadc9
parent 97fef960
Loading
Loading
Loading
Loading
+72 −3
Original line number Diff line number Diff line
@@ -38,6 +38,9 @@ public final class RoutingChangeInfo implements Parcelable {
    // Indicates that the route was a suggested route.
    private final boolean mIsSuggested;

    // Indicates the suggestion providers for a route.
    private final @SuggestionProviderFlags int mSuggestionProviderFlags;

    /**
     * Indicates that a routing session started as the result of selecting a route from the output
     * switcher.
@@ -97,6 +100,40 @@ public final class RoutingChangeInfo implements Parcelable {
    @Retention(RetentionPolicy.SOURCE)
    public @interface EntryPoint {}

    /**
     * Flag indicating that the route was suggested by {@link RouteListingPreference}.
     *
     * @hide
     */
    public static final int SUGGESTION_PROVIDER_RLP = 1;

    /**
     * Flag indicating that the route was suggested by the app as a device suggestion.
     *
     * @hide
     */
    public static final int SUGGESTION_PROVIDER_DEVICE_SUGGESTION_APP = 1 << 1;

    /**
     * Flag indicating that the route was suggested as a device suggestion by an app not playing the
     * media.
     *
     * @hide
     */
    public static final int SUGGESTION_PROVIDER_DEVICE_SUGGESTION_OTHER = 1 << 2;

    /** @hide */
    @Retention(RetentionPolicy.SOURCE)
    @IntDef(
            prefix = "SUGGESTION_PROVIDER",
            flag = true,
            value = {
                SUGGESTION_PROVIDER_RLP,
                SUGGESTION_PROVIDER_DEVICE_SUGGESTION_APP,
                SUGGESTION_PROVIDER_DEVICE_SUGGESTION_OTHER
            })
    public @interface SuggestionProviderFlags {}

    @NonNull
    public static final Creator<RoutingChangeInfo> CREATOR =
            new Creator<>() {
@@ -112,13 +149,22 @@ public final class RoutingChangeInfo implements Parcelable {
            };

    public RoutingChangeInfo(@EntryPoint int entryPoint, boolean isSuggested) {
        this(entryPoint, isSuggested, /* suggestionProviderFlags= */ 0);
    }

    public RoutingChangeInfo(
            @EntryPoint int entryPoint,
            boolean isSuggested,
            @SuggestionProviderFlags int suggestionProviderFlags) {
        mEntryPoint = entryPoint;
        mIsSuggested = isSuggested;
        mSuggestionProviderFlags = suggestionProviderFlags;
    }

    private RoutingChangeInfo(Parcel in) {
        mEntryPoint = in.readInt();
        mIsSuggested = in.readBoolean();
        mSuggestionProviderFlags = in.readInt();
    }

    @Override
@@ -130,6 +176,7 @@ public final class RoutingChangeInfo implements Parcelable {
    public void writeToParcel(@androidx.annotation.NonNull Parcel dest, int flags) {
        dest.writeInt(mEntryPoint);
        dest.writeBoolean(mIsSuggested);
        dest.writeInt(mSuggestionProviderFlags);
    }

    @Override
@@ -146,13 +193,14 @@ public final class RoutingChangeInfo implements Parcelable {
            return true;
        }

        return other.getEntryPoint() == this.getEntryPoint()
                && other.isSuggested() == this.mIsSuggested;
        return other.getEntryPoint() == this.mEntryPoint
                && other.isSuggested() == this.mIsSuggested
                && other.mSuggestionProviderFlags == this.mSuggestionProviderFlags;
    }

    @Override
    public int hashCode() {
        return Objects.hash(mEntryPoint, mIsSuggested);
        return Objects.hash(mEntryPoint, mIsSuggested, mSuggestionProviderFlags);
    }

    public @EntryPoint int getEntryPoint() {
@@ -162,4 +210,25 @@ public final class RoutingChangeInfo implements Parcelable {
    public boolean isSuggested() {
        return mIsSuggested;
    }

    public @SuggestionProviderFlags int getSuggestionProviderFlags() {
        return mSuggestionProviderFlags;
    }

    /**
     * Returns whether the route had an active suggestion from the active route listing preference.
     */
    public boolean isSuggestedByRlp() {
        return (mSuggestionProviderFlags & SUGGESTION_PROVIDER_RLP) != 0;
    }

    /** Returns whether the route had an active device suggestion from the media app. */
    public boolean isSuggestedByMediaApp() {
        return (mSuggestionProviderFlags & SUGGESTION_PROVIDER_DEVICE_SUGGESTION_APP) != 0;
    }

    /** Whether the route had an active device suggestion from an app other than the media app. */
    public boolean isSuggestedByAnotherApp() {
        return (mSuggestionProviderFlags & SUGGESTION_PROVIDER_DEVICE_SUGGESTION_OTHER) != 0;
    }
}
+53 −2
Original line number Diff line number Diff line
@@ -25,6 +25,11 @@ import static android.media.MediaRouter2.SCANNING_STATE_SCANNING_FULL;
import static android.media.MediaRouter2.SCANNING_STATE_WHILE_INTERACTIVE;
import static android.media.MediaRouter2Utils.getOriginalId;
import static android.media.MediaRouter2Utils.getProviderId;
import static android.media.RouteListingPreference.Item.FLAG_SUGGESTED;
import static android.media.RoutingChangeInfo.SUGGESTION_PROVIDER_DEVICE_SUGGESTION_APP;
import static android.media.RoutingChangeInfo.SUGGESTION_PROVIDER_DEVICE_SUGGESTION_OTHER;
import static android.media.RoutingChangeInfo.SUGGESTION_PROVIDER_RLP;
import static android.media.RoutingChangeInfo.SuggestionProviderFlags;

import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage;
import static com.android.server.media.MediaRouterMetricLogger.EVENT_TYPE_CREATE_SESSION;
@@ -1629,9 +1634,16 @@ class MediaRouter2ServiceImpl {
        }

        long uniqueRequestId = toUniqueRequestId(routerRecord.mRouterId, requestId);
        @SuggestionProviderFlags
        int suggestionProviderFlags = getSuggestionProviderFlags(routerRecord, route);
        RoutingChangeInfo updatedInfo =
                new RoutingChangeInfo(
                        routingChangeInfo.getEntryPoint(),
                        routingChangeInfo.isSuggested(),
                        suggestionProviderFlags);
        mMediaRouterMetricLogger.addRequestInfo(
                uniqueRequestId, EVENT_TYPE_CREATE_SESSION, routingChangeInfo);
        mMediaRouterMetricLogger.notifyRoutingChangeRequested(uniqueRequestId, routingChangeInfo);
                uniqueRequestId, EVENT_TYPE_CREATE_SESSION, updatedInfo);
        mMediaRouterMetricLogger.notifyRoutingChangeRequested(uniqueRequestId, updatedInfo);
        userHandler.sendMessage(
                obtainMessage(
                        UserHandler::requestCreateSessionWithRouter2OnHandler,
@@ -2465,6 +2477,45 @@ class MediaRouter2ServiceImpl {
        }
    }

    private static @SuggestionProviderFlags int getSuggestionProviderFlags(
            RouterRecord routerRecord, MediaRoute2Info mediaRoute2Info) {
        String routeId = mediaRoute2Info.getId();
        int result = 0;
        if (routerRecord.mRouteListingPreference != null) {
            List<RouteListingPreference.Item> routeListingPreferenceItems =
                    routerRecord.mRouteListingPreference.getItems();
            if (routeListingPreferenceItems.stream()
                    .anyMatch(
                            item ->
                                    (item.getRouteId().equals(routeId))
                                            && (item.getFlags() & FLAG_SUGGESTED) != 0)) {
                result |= SUGGESTION_PROVIDER_RLP;
            }
        }
        Map<String, List<SuggestedDeviceInfo>> suggestionsMap = routerRecord.mDeviceSuggestions;
        List<SuggestedDeviceInfo> suggestionsByApp = suggestionsMap.get(routerRecord.mPackageName);
        if (suggestionsByApp != null
                && suggestionsByApp.stream()
                        .anyMatch(
                                suggestedDeviceInfo ->
                                        suggestedDeviceInfo.getRouteId().equals(routeId))) {
            result |= SUGGESTION_PROVIDER_DEVICE_SUGGESTION_APP;
        }
        if (suggestionsMap.entrySet().stream()
                .filter(entry -> !entry.getKey().equals(routerRecord.mPackageName))
                .anyMatch(
                        entry ->
                                entry.getValue().stream()
                                        .anyMatch(
                                                suggestedDeviceInfo ->
                                                        suggestedDeviceInfo
                                                                .getRouteId()
                                                                .equals(routeId)))) {
            result |= SUGGESTION_PROVIDER_DEVICE_SUGGESTION_OTHER;
        }
        return result;
    }

    /** Invoked when {@link MediaRouterService#systemRunning()} is invoked. */
    /* package */ void systemRunning() {
        sInstance.set(this);
+36 −3
Original line number Diff line number Diff line
@@ -75,6 +75,7 @@ import com.android.internal.annotations.VisibleForTesting;
import java.io.PrintWriter;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.Map;

/**
@@ -314,6 +315,9 @@ final class MediaRouterMetricLogger {
                        routingSessionInfo.isSystemSession(),
                        routingSessionInfo.getTransferReason(),
                        routingChangeInfo.isSuggested(),
                        routingChangeInfo.isSuggestedByRlp(),
                        routingChangeInfo.isSuggestedByMediaApp(),
                        routingChangeInfo.isSuggestedByAnotherApp(),
                        getElapsedRealTime());
        mOngoingRoutingChangeCache.put(routingSessionInfo.getOriginalId(), ongoingRoutingChange);
        mRoutingChangeInfoCache.remove(uniqueRequestId);
@@ -338,12 +342,13 @@ final class MediaRouterMetricLogger {
                    TextUtils.formatSimple(
                            "notifySessionEnd | EntryPoint: %d, ClientPackageUid: %d,"
                                    + " IsSystemSession: %b, TransferReason: %d, IsSuggested: %b,"
                                    + " SessionLengthInMillis: %d",
                                    + " SuggestionProviders: %s, SessionLengthInMillis: %d",
                            ongoingRoutingChange.entryPoint,
                            ongoingRoutingChange.clientPackageUid,
                            ongoingRoutingChange.isSystemSession,
                            ongoingRoutingChange.transferReason,
                            ongoingRoutingChange.isSuggested,
                            ongoingRoutingChange.getSuggestionProvidersDebugString(),
                            sessionLengthInMillis));
        }

@@ -354,7 +359,10 @@ final class MediaRouterMetricLogger {
                ongoingRoutingChange.isSystemSession,
                convertTransferReasonForLogging(ongoingRoutingChange.transferReason),
                ongoingRoutingChange.isSuggested,
                sessionLengthInMillis);
                sessionLengthInMillis,
                ongoingRoutingChange.isSuggestedByRlp,
                ongoingRoutingChange.isSuggestedByMediaApp,
                ongoingRoutingChange.isSuggestedByAnotherApp);

        mOngoingRoutingChangeCache.remove(sessionId);
    }
@@ -745,7 +753,32 @@ final class MediaRouterMetricLogger {
            boolean isSystemSession,
            @TransferReason int transferReason,
            boolean isSuggested,
            long startTimeInMillis) {}
            boolean isSuggestedByRlp,
            boolean isSuggestedByMediaApp,
            boolean isSuggestedByAnotherApp,
            long startTimeInMillis) {

        /**
         * Returns a human-readable representation of the suggestion provider for logging purposes.
         */
        public String getSuggestionProvidersDebugString() {
            var providerStrings = new ArrayList<String>();
            if (isSuggestedByRlp) {
                providerStrings.add("RLP");
            }
            if (isSuggestedByMediaApp) {
                providerStrings.add("MEDIA_APP");
            }
            if (isSuggestedByAnotherApp) {
                providerStrings.add("ANOTHER_APP");
            }
            if (providerStrings.isEmpty()) {
                return "NONE";
            } else {
                return String.join("|", providerStrings);
            }
        }
    }

    /** Tracks the count of changes in route listing preference */
    private record RlpCount(long rlpTotalCount, long rlpWithSuggestionCount) {}
+8 −2
Original line number Diff line number Diff line
@@ -402,7 +402,10 @@ public class MediaRouterMetricLoggerTest {
                                anyBoolean(),
                                anyInt(),
                                anyBoolean(),
                                anyLong()),
                                anyLong(),
                                anyBoolean(),
                                anyBoolean(),
                                anyBoolean()),
                never());
    }

@@ -449,7 +452,10 @@ public class MediaRouterMetricLoggerTest {
                                eq(
                                        ROUTING_CHANGE_REPORTED__TRANSFER_REASON__TRANSFER_REASON_SYSTEM_REQUEST),
                                eq(/* isSuggested= */ false),
                                sessionLengthCaptor.capture()));
                                sessionLengthCaptor.capture(),
                                eq(/* isSuggestedByRlp= */ false),
                                eq(/* isSuggestedByMediaApp= */ false),
                                eq(/* isSuggestedByOtherApp= */ false)));
        assertThat(sessionLengthCaptor.getValue()).isEqualTo(sessionTimeInMillis);
    }