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

Commit 56fe34c8 authored by Alex Shabalin's avatar Alex Shabalin
Browse files

Convert SuggestedDeviceState to a Kotlin data class.

Move that structure out of InfoMediaManager to a separate Kotlin file.
This simplifies the code and allows to use Kotlin named parameters.

Bug: 431423375
Test: atest MediaDeviceManagerTest
Test: atest InfoMediaManagerTest
Test: atest LocalMediaManagerTest
Flag: EXEMPT refactor
Change-Id: I28e35f0b4d1d12ce287c34de2d6dbda76c35afb6
parent 43122a03
Loading
Loading
Loading
Loading
+4 −162
Original line number Diff line number Diff line
@@ -16,34 +16,6 @@
package com.android.settingslib.media;

import static android.media.MediaRoute2Info.CONNECTION_STATE_CONNECTING;
import static android.media.MediaRoute2Info.TYPE_AUX_LINE;
import static android.media.MediaRoute2Info.TYPE_BLE_HEADSET;
import static android.media.MediaRoute2Info.TYPE_BLUETOOTH_A2DP;
import static android.media.MediaRoute2Info.TYPE_BUILTIN_SPEAKER;
import static android.media.MediaRoute2Info.TYPE_DOCK;
import static android.media.MediaRoute2Info.TYPE_GROUP;
import static android.media.MediaRoute2Info.TYPE_HDMI;
import static android.media.MediaRoute2Info.TYPE_HDMI_ARC;
import static android.media.MediaRoute2Info.TYPE_HDMI_EARC;
import static android.media.MediaRoute2Info.TYPE_HEARING_AID;
import static android.media.MediaRoute2Info.TYPE_LINE_ANALOG;
import static android.media.MediaRoute2Info.TYPE_LINE_DIGITAL;
import static android.media.MediaRoute2Info.TYPE_REMOTE_AUDIO_VIDEO_RECEIVER;
import static android.media.MediaRoute2Info.TYPE_REMOTE_CAR;
import static android.media.MediaRoute2Info.TYPE_REMOTE_COMPUTER;
import static android.media.MediaRoute2Info.TYPE_REMOTE_GAME_CONSOLE;
import static android.media.MediaRoute2Info.TYPE_REMOTE_SMARTPHONE;
import static android.media.MediaRoute2Info.TYPE_REMOTE_SMARTWATCH;
import static android.media.MediaRoute2Info.TYPE_REMOTE_SPEAKER;
import static android.media.MediaRoute2Info.TYPE_REMOTE_TABLET;
import static android.media.MediaRoute2Info.TYPE_REMOTE_TABLET_DOCKED;
import static android.media.MediaRoute2Info.TYPE_REMOTE_TV;
import static android.media.MediaRoute2Info.TYPE_UNKNOWN;
import static android.media.MediaRoute2Info.TYPE_USB_ACCESSORY;
import static android.media.MediaRoute2Info.TYPE_USB_DEVICE;
import static android.media.MediaRoute2Info.TYPE_USB_HEADSET;
import static android.media.MediaRoute2Info.TYPE_WIRED_HEADPHONES;
import static android.media.MediaRoute2Info.TYPE_WIRED_HEADSET;
import static android.media.session.MediaController.PlaybackInfo;

import static com.android.settingslib.media.LocalMediaManager.MediaDeviceState.STATE_CONNECTED;
@@ -51,13 +23,16 @@ import static com.android.settingslib.media.LocalMediaManager.MediaDeviceState.S
import static com.android.settingslib.media.LocalMediaManager.MediaDeviceState.STATE_CONNECTING_FAILED;
import static com.android.settingslib.media.LocalMediaManager.MediaDeviceState.STATE_DISCONNECTED;
import static com.android.settingslib.media.LocalMediaManager.MediaDeviceState.STATE_SELECTED;
import static com.android.settingslib.media.MediaDeviceUtilKt.isBluetoothMediaDevice;
import static com.android.settingslib.media.MediaDeviceUtilKt.isComplexMediaDevice;
import static com.android.settingslib.media.MediaDeviceUtilKt.isInfoMediaDevice;
import static com.android.settingslib.media.MediaDeviceUtilKt.isPhoneMediaDevice;

import android.annotation.TargetApi;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.content.ComponentName;
import android.content.Context;
import android.graphics.drawable.Drawable;
import android.media.MediaRoute2Info;
import android.media.RouteListingPreference;
import android.media.RoutingChangeInfo;
@@ -77,7 +52,6 @@ import androidx.annotation.RequiresApi;

import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.settingslib.R;
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
import com.android.settingslib.bluetooth.LocalBluetoothManager;

@@ -142,67 +116,6 @@ public abstract class InfoMediaManager {
        ;
    }

    /**
     * Wrapper class around SuggestedDeviceInfo and the corresponding connection state of the
     * suggestion.
     */
    public static class SuggestedDeviceState {
        private final SuggestedDeviceInfo mSuggestedDeviceInfo;
        private final @LocalMediaManager.MediaDeviceState int mConnectionState;

        @VisibleForTesting
        SuggestedDeviceState(@NonNull SuggestedDeviceInfo suggestedDeviceInfo) {
            mSuggestedDeviceInfo = suggestedDeviceInfo;
            mConnectionState = STATE_DISCONNECTED;
        }

        @VisibleForTesting
        SuggestedDeviceState(
                @NonNull SuggestedDeviceInfo suggestedDeviceInfo,
                @LocalMediaManager.MediaDeviceState int state) {
            mSuggestedDeviceInfo = suggestedDeviceInfo;
            mConnectionState = state;
        }

        @NonNull
        public SuggestedDeviceInfo getSuggestedDeviceInfo() {
            return mSuggestedDeviceInfo;
        }

        public @LocalMediaManager.MediaDeviceState int getConnectionState() {
            return mConnectionState;
        }

        /** Gets the drawable associated with the suggested device type. */
        @NonNull
        public Drawable getIcon(Context context) {
            return getDrawableForSuggestion(context, this);
        }

        @Override
        public boolean equals(Object obj) {
            if (this == obj) {
                return true;
            }
            if (!(obj instanceof SuggestedDeviceState)) {
                return false;
            }
            return Objects.equals(
                            mSuggestedDeviceInfo, ((SuggestedDeviceState) obj).mSuggestedDeviceInfo)
                    && Objects.equals(
                            mConnectionState, ((SuggestedDeviceState) obj).mConnectionState);
        }

        @Override
        public int hashCode() {
            return Objects.hash(mSuggestedDeviceInfo, mConnectionState);
        }

        @Override
        public String toString() {
            return "info: " + mSuggestedDeviceInfo + " state " + mConnectionState;
        }
    }

    /** Checked exception that signals the specified package is not present in the system. */
    public static class PackageNotAvailableException extends Exception {
@@ -1019,77 +932,6 @@ public abstract class InfoMediaManager {
        }
    }

    private static boolean isInfoMediaDevice(int deviceType) {
        switch (deviceType) {
            case TYPE_UNKNOWN:
            case TYPE_REMOTE_TV:
            case TYPE_REMOTE_SPEAKER:
            case TYPE_GROUP:
            case TYPE_REMOTE_TABLET:
            case TYPE_REMOTE_TABLET_DOCKED:
            case TYPE_REMOTE_COMPUTER:
            case TYPE_REMOTE_GAME_CONSOLE:
            case TYPE_REMOTE_CAR:
            case TYPE_REMOTE_SMARTWATCH:
            case TYPE_REMOTE_SMARTPHONE:
                return true;
            default:
                return false;
        }
    }

    private static boolean isPhoneMediaDevice(int deviceType) {
        switch (deviceType) {
            case TYPE_BUILTIN_SPEAKER:
            case TYPE_USB_DEVICE:
            case TYPE_USB_HEADSET:
            case TYPE_USB_ACCESSORY:
            case TYPE_DOCK:
            case TYPE_HDMI:
            case TYPE_HDMI_ARC:
            case TYPE_HDMI_EARC:
            case TYPE_LINE_DIGITAL:
            case TYPE_LINE_ANALOG:
            case TYPE_AUX_LINE:
            case TYPE_WIRED_HEADSET:
            case TYPE_WIRED_HEADPHONES:
                return true;
            default:
                return false;
        }
    }

    private static boolean isBluetoothMediaDevice(int deviceType) {
        switch (deviceType) {
            case TYPE_HEARING_AID:
            case TYPE_BLUETOOTH_A2DP:
            case TYPE_BLE_HEADSET:
                return true;
            default:
                return false;
        }
    }

    private static boolean isComplexMediaDevice(int deviceType) {
        return deviceType == TYPE_REMOTE_AUDIO_VIDEO_RECEIVER;
    }

    private static Drawable getDrawableForSuggestion(
            Context context, SuggestedDeviceState suggestion) {
        if (suggestion.getConnectionState() == STATE_CONNECTING_FAILED) {
            return context.getDrawable(android.R.drawable.ic_info);
        }
        int deviceType = suggestion.getSuggestedDeviceInfo().getType();
        if (isInfoMediaDevice(deviceType)) {
            return context.getDrawable(InfoMediaDevice.getDrawableResIdByType(deviceType));
        }
        if (isPhoneMediaDevice(deviceType)) {
            return context.getDrawable(
                    new DeviceIconUtil(context).getIconResIdFromMediaRouteType(deviceType));
        }
        return context.getDrawable(R.drawable.ic_media_speaker_device);
    }

    @RequiresApi(34)
    static class Api34Impl {
        @DoNotInline
+0 −1
Original line number Diff line number Diff line
@@ -49,7 +49,6 @@ import com.android.settingslib.bluetooth.HearingAidProfile;
import com.android.settingslib.bluetooth.LeAudioProfile;
import com.android.settingslib.bluetooth.LocalBluetoothManager;
import com.android.settingslib.bluetooth.LocalBluetoothProfile;
import com.android.settingslib.media.InfoMediaManager.SuggestedDeviceState;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+71 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2025 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.settingslib.media

import android.media.MediaRoute2Info

fun isInfoMediaDevice(deviceType: Int): Boolean {
  return when (deviceType) {
    MediaRoute2Info.TYPE_UNKNOWN,
    MediaRoute2Info.TYPE_REMOTE_TV,
    MediaRoute2Info.TYPE_REMOTE_SPEAKER,
    MediaRoute2Info.TYPE_GROUP,
    MediaRoute2Info.TYPE_REMOTE_TABLET,
    MediaRoute2Info.TYPE_REMOTE_TABLET_DOCKED,
    MediaRoute2Info.TYPE_REMOTE_COMPUTER,
    MediaRoute2Info.TYPE_REMOTE_GAME_CONSOLE,
    MediaRoute2Info.TYPE_REMOTE_CAR,
    MediaRoute2Info.TYPE_REMOTE_SMARTWATCH,
    MediaRoute2Info.TYPE_REMOTE_SMARTPHONE,
      -> true
    else -> false
  }
}

fun isPhoneMediaDevice(deviceType: Int): Boolean {
  return when (deviceType) {
    MediaRoute2Info.TYPE_BUILTIN_SPEAKER,
    MediaRoute2Info.TYPE_USB_DEVICE,
    MediaRoute2Info.TYPE_USB_HEADSET,
    MediaRoute2Info.TYPE_USB_ACCESSORY,
    MediaRoute2Info.TYPE_DOCK,
    MediaRoute2Info.TYPE_HDMI,
    MediaRoute2Info.TYPE_HDMI_ARC,
    MediaRoute2Info.TYPE_HDMI_EARC,
    MediaRoute2Info.TYPE_LINE_DIGITAL,
    MediaRoute2Info.TYPE_LINE_ANALOG,
    MediaRoute2Info.TYPE_AUX_LINE,
    MediaRoute2Info.TYPE_WIRED_HEADSET,
    MediaRoute2Info.TYPE_WIRED_HEADPHONES,
      -> true
    else -> false
  }
}

fun isBluetoothMediaDevice(deviceType: Int): Boolean {
  return when (deviceType) {
    MediaRoute2Info.TYPE_HEARING_AID,
    MediaRoute2Info.TYPE_BLUETOOTH_A2DP,
    MediaRoute2Info.TYPE_BLE_HEADSET,
      -> true
    else -> false
  }
}

fun isComplexMediaDevice(deviceType: Int): Boolean {
  return deviceType == MediaRoute2Info.TYPE_REMOTE_AUDIO_VIDEO_RECEIVER
}
+49 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2025 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.settingslib.media

import android.content.Context
import android.graphics.drawable.Drawable
import android.media.SuggestedDeviceInfo
import com.android.settingslib.R
import com.android.settingslib.media.LocalMediaManager.MediaDeviceState
import com.android.settingslib.media.LocalMediaManager.MediaDeviceState.STATE_CONNECTING_FAILED
import com.android.settingslib.media.LocalMediaManager.MediaDeviceState.STATE_DISCONNECTED

/**
 * Wrapper class around [SuggestedDeviceInfo] and the corresponding connection state of the
 * suggestion.
 */
data class SuggestedDeviceState
@JvmOverloads
constructor(
    val suggestedDeviceInfo: SuggestedDeviceInfo,
    @MediaDeviceState val connectionState: Int = STATE_DISCONNECTED,
) {
  fun getIcon(context: Context): Drawable {
      val deviceType = suggestedDeviceInfo.type
      val resourceId = when {
          connectionState == STATE_CONNECTING_FAILED -> android.R.drawable.ic_info
          isInfoMediaDevice(deviceType) -> InfoMediaDevice.getDrawableResIdByType(deviceType)
          isPhoneMediaDevice(deviceType) ->
              DeviceIconUtil(context).getIconResIdFromMediaRouteType(deviceType)
          else -> R.drawable.ic_media_speaker_device
      }

      return context.getDrawable(resourceId)!!
  }
}
+1 −2
Original line number Diff line number Diff line
@@ -65,7 +65,6 @@ import com.android.settingslib.bluetooth.CachedBluetoothDevice;
import com.android.settingslib.bluetooth.CachedBluetoothDeviceManager;
import com.android.settingslib.bluetooth.LocalBluetoothManager;
import com.android.settingslib.media.InfoMediaManager.Api34Impl;
import com.android.settingslib.media.InfoMediaManager.SuggestedDeviceState;

import com.google.common.collect.ImmutableList;

@@ -158,7 +157,7 @@ public class InfoMediaManagerTest {
    private ArgumentCaptor<DeviceSuggestionsUpdatesCallback> mDeviceSuggestionsUpdatesCallback;

    @Captor
    private ArgumentCaptor<InfoMediaManager.SuggestedDeviceState> mSuggestedDeviceStateCaptor;
    private ArgumentCaptor<SuggestedDeviceState> mSuggestedDeviceStateCaptor;

    private RouterInfoMediaManager mInfoMediaManager;
    private Context mContext;
Loading