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

Commit c7224ea6 authored by Caitlin Cassidy's avatar Caitlin Cassidy Committed by Android (Google) Code Review
Browse files

Merge changes from topic "ccassidy-media-sass"

* changes:
  [Media SASS] Unregister the muteAwaitConnectionCallback when the Entry stops.
  [Media SASS] Choose the correct device icon based on the device attributes.
  [Media SASS] Display about-to-connect device names in the media player device chip.
parents 6d813744 b56e3138
Loading
Loading
Loading
Loading
+126 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2022 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.annotation.DrawableRes;
import android.content.Context;
import android.graphics.drawable.Drawable;
import android.media.AudioDeviceInfo;
import android.media.MediaRoute2Info;

import com.android.settingslib.R;

import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/** A util class to get the appropriate icon for different device types. */
public class DeviceIconUtil {
    // A map from a @AudioDeviceInfo.AudioDeviceType to full device information.
    private final Map<Integer, Device> mAudioDeviceTypeToIconMap = new HashMap<>();
    // A map from a @MediaRoute2Info.Type to full device information.
    private final Map<Integer, Device> mMediaRouteTypeToIconMap = new HashMap<>();
    // A default icon to use if the type is not present in the map.
    @DrawableRes private static final int DEFAULT_ICON = R.drawable.ic_smartphone;

    public DeviceIconUtil() {
        List<Device> deviceList = Arrays.asList(
                new Device(
                    AudioDeviceInfo.TYPE_USB_DEVICE,
                    MediaRoute2Info.TYPE_USB_DEVICE,
                    R.drawable.ic_headphone),
                new Device(
                    AudioDeviceInfo.TYPE_USB_HEADSET,
                    MediaRoute2Info.TYPE_USB_HEADSET,
                    R.drawable.ic_headphone),
                new Device(
                    AudioDeviceInfo.TYPE_USB_ACCESSORY,
                    MediaRoute2Info.TYPE_USB_ACCESSORY,
                    R.drawable.ic_headphone),
                new Device(
                    AudioDeviceInfo.TYPE_DOCK,
                    MediaRoute2Info.TYPE_DOCK,
                    R.drawable.ic_headphone),
                new Device(
                    AudioDeviceInfo.TYPE_HDMI,
                    MediaRoute2Info.TYPE_HDMI,
                    R.drawable.ic_headphone),
                new Device(
                    AudioDeviceInfo.TYPE_WIRED_HEADSET,
                    MediaRoute2Info.TYPE_WIRED_HEADSET,
                    R.drawable.ic_headphone),
                new Device(
                    AudioDeviceInfo.TYPE_WIRED_HEADPHONES,
                    MediaRoute2Info.TYPE_WIRED_HEADPHONES,
                    R.drawable.ic_headphone),
                new Device(
                    AudioDeviceInfo.TYPE_BUILTIN_SPEAKER,
                    MediaRoute2Info.TYPE_BUILTIN_SPEAKER,
                    R.drawable.ic_smartphone));
        for (int i = 0; i < deviceList.size(); i++) {
            Device device = deviceList.get(i);
            mAudioDeviceTypeToIconMap.put(device.mAudioDeviceType, device);
            mMediaRouteTypeToIconMap.put(device.mMediaRouteType, device);
        }
    }

    /** Returns a drawable for an icon representing the given audioDeviceType. */
    public Drawable getIconFromAudioDeviceType(
            @AudioDeviceInfo.AudioDeviceType int audioDeviceType, Context context) {
        return context.getDrawable(getIconResIdFromAudioDeviceType(audioDeviceType));
    }

    /** Returns a drawable res ID for an icon representing the given audioDeviceType. */
    @DrawableRes
    public int getIconResIdFromAudioDeviceType(
            @AudioDeviceInfo.AudioDeviceType int audioDeviceType) {
        if (mAudioDeviceTypeToIconMap.containsKey(audioDeviceType)) {
            return mAudioDeviceTypeToIconMap.get(audioDeviceType).mIconDrawableRes;
        }
        return DEFAULT_ICON;
    }

    /** Returns a drawable res ID for an icon representing the given mediaRouteType. */
    @DrawableRes
    public int getIconResIdFromMediaRouteType(
            @MediaRoute2Info.Type int mediaRouteType) {
        if (mMediaRouteTypeToIconMap.containsKey(mediaRouteType)) {
            return mMediaRouteTypeToIconMap.get(mediaRouteType).mIconDrawableRes;
        }
        return DEFAULT_ICON;
    }

    private static class Device {
        @AudioDeviceInfo.AudioDeviceType
        private final int mAudioDeviceType;

        @MediaRoute2Info.Type
        private final int mMediaRouteType;

        @DrawableRes
        private final int mIconDrawableRes;

        Device(@AudioDeviceInfo.AudioDeviceType int audioDeviceType,
                @MediaRoute2Info.Type int mediaRouteType,
                @DrawableRes int iconDrawableRes) {
            mAudioDeviceType = audioDeviceType;
            mMediaRouteType = mediaRouteType;
            mIconDrawableRes = iconDrawableRes;
        }
    }
}
+28 −0
Original line number Diff line number Diff line
@@ -21,6 +21,7 @@ import android.app.Notification;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.content.Context;
import android.graphics.drawable.Drawable;
import android.media.RoutingSessionInfo;
import android.os.Build;
import android.text.TextUtils;
@@ -226,6 +227,18 @@ public class LocalMediaManager implements BluetoothCallback {
        }
    }

    /**
     * Dispatch a change in the about-to-connect device. See
     * {@link DeviceCallback#onAboutToConnectDeviceChanged} for more information.
     */
    public void dispatchAboutToConnectDeviceChanged(
            @Nullable String deviceName,
            @Nullable Drawable deviceIcon) {
        for (DeviceCallback callback : getCallbacks()) {
            callback.onAboutToConnectDeviceChanged(deviceName, deviceIcon);
        }
    }

    /**
     * Stop scan MediaDevice
     */
@@ -674,6 +687,21 @@ public class LocalMediaManager implements BluetoothCallback {
         * {@link android.media.MediaRoute2ProviderService#REASON_INVALID_COMMAND},
         */
        default void onRequestFailed(int reason){};

        /**
         * Callback for notifying that we have a new about-to-connect device.
         *
         * An about-to-connect device is a device that is not yet connected but is expected to
         * connect imminently and should be displayed as the current device in the media player.
         * See [AudioManager.muteAwaitConnection] for more details.
         *
         * @param deviceName the name of the device (displayed to the user).
         * @param deviceIcon the icon that should be used with the device.
         */
        default void onAboutToConnectDeviceChanged(
                @Nullable String deviceName,
                @Nullable Drawable deviceIcon
        ) {}
    }

    /**
+4 −18
Original line number Diff line number Diff line
@@ -47,10 +47,12 @@ public class PhoneMediaDevice extends MediaDevice {

    private String mSummary = "";

    private final DeviceIconUtil mDeviceIconUtil;

    PhoneMediaDevice(Context context, MediaRouter2Manager routerManager, MediaRoute2Info info,
            String packageName) {
        super(context, routerManager, info, packageName);

        mDeviceIconUtil = new DeviceIconUtil();
        initDeviceRecord();
    }

@@ -94,23 +96,7 @@ public class PhoneMediaDevice extends MediaDevice {

    @VisibleForTesting
    int getDrawableResId() {
        int resId;
        switch (mRouteInfo.getType()) {
            case TYPE_USB_DEVICE:
            case TYPE_USB_HEADSET:
            case TYPE_USB_ACCESSORY:
            case TYPE_DOCK:
            case TYPE_HDMI:
            case TYPE_WIRED_HEADSET:
            case TYPE_WIRED_HEADPHONES:
                resId = R.drawable.ic_headphone;
                break;
            case TYPE_BUILTIN_SPEAKER:
            default:
                resId = R.drawable.ic_smartphone;
                break;
        }
        return resId;
        return mDeviceIconUtil.getIconResIdFromMediaRouteType(mRouteInfo.getType());
    }

    @Override
+150 −0
Original line number Diff line number Diff line
/*
 * Copyright 2022 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 static com.google.common.truth.Truth.assertThat;

import android.media.AudioDeviceInfo;
import android.media.MediaRoute2Info;

import com.android.settingslib.R;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.RobolectricTestRunner;

@RunWith(RobolectricTestRunner.class)
public class DeviceIconUtilTest {
    private final DeviceIconUtil mDeviceIconUtil = new DeviceIconUtil();

    @Test
    public void getIconResIdFromMediaRouteType_usbDevice_isHeadphone() {
        assertThat(mDeviceIconUtil.getIconResIdFromMediaRouteType(MediaRoute2Info.TYPE_USB_DEVICE))
            .isEqualTo(R.drawable.ic_headphone);
    }

    @Test
    public void getIconResIdFromMediaRouteType_usbHeadset_isHeadphone() {
        assertThat(mDeviceIconUtil.getIconResIdFromMediaRouteType(MediaRoute2Info.TYPE_USB_HEADSET))
            .isEqualTo(R.drawable.ic_headphone);
    }

    @Test
    public void getIconResIdFromMediaRouteType_usbAccessory_isHeadphone() {
        assertThat(
            mDeviceIconUtil.getIconResIdFromMediaRouteType(MediaRoute2Info.TYPE_USB_ACCESSORY))
            .isEqualTo(R.drawable.ic_headphone);
    }

    @Test
    public void getIconResIdFromMediaRouteType_dock_isHeadphone() {
        assertThat(mDeviceIconUtil.getIconResIdFromMediaRouteType(MediaRoute2Info.TYPE_DOCK))
            .isEqualTo(R.drawable.ic_headphone);
    }

    @Test
    public void getIconResIdFromMediaRouteType_hdmi_isHeadphone() {
        assertThat(mDeviceIconUtil.getIconResIdFromMediaRouteType(MediaRoute2Info.TYPE_HDMI))
            .isEqualTo(R.drawable.ic_headphone);
    }

    @Test
    public void getIconResIdFromMediaRouteType_wiredHeadset_isHeadphone() {
        assertThat(
            mDeviceIconUtil.getIconResIdFromMediaRouteType(MediaRoute2Info.TYPE_WIRED_HEADSET))
            .isEqualTo(R.drawable.ic_headphone);
    }

    @Test
    public void getIconResIdFromMediaRouteType_wiredHeadphones_isHeadphone() {
        assertThat(
            mDeviceIconUtil.getIconResIdFromMediaRouteType(MediaRoute2Info.TYPE_WIRED_HEADPHONES))
            .isEqualTo(R.drawable.ic_headphone);
    }

    @Test
    public void getIconResIdFromMediaRouteType_builtinSpeaker_isSmartphone() {
        assertThat(
            mDeviceIconUtil.getIconResIdFromMediaRouteType(MediaRoute2Info.TYPE_BUILTIN_SPEAKER))
            .isEqualTo(R.drawable.ic_smartphone);
    }

    @Test
    public void getIconResIdFromMediaRouteType_unsupportedType_isSmartphone() {
        assertThat(mDeviceIconUtil.getIconResIdFromMediaRouteType(MediaRoute2Info.TYPE_UNKNOWN))
            .isEqualTo(R.drawable.ic_smartphone);
    }

    @Test
    public void getIconResIdFromAudioDeviceType_usbDevice_isHeadphone() {
        assertThat(mDeviceIconUtil.getIconResIdFromAudioDeviceType(AudioDeviceInfo.TYPE_USB_DEVICE))
            .isEqualTo(R.drawable.ic_headphone);
    }

    @Test
    public void getIconResIdFromAudioDeviceType_usbHeadset_isHeadphone() {
        assertThat(
            mDeviceIconUtil.getIconResIdFromAudioDeviceType(AudioDeviceInfo.TYPE_USB_HEADSET))
            .isEqualTo(R.drawable.ic_headphone);
    }

    @Test
    public void getIconResIdFromAudioDeviceType_usbAccessory_isHeadphone() {
        assertThat(
            mDeviceIconUtil.getIconResIdFromAudioDeviceType(AudioDeviceInfo.TYPE_USB_ACCESSORY))
            .isEqualTo(R.drawable.ic_headphone);
    }

    @Test
    public void getIconResIdFromAudioDeviceType_dock_isHeadphone() {
        assertThat(mDeviceIconUtil.getIconResIdFromAudioDeviceType(AudioDeviceInfo.TYPE_DOCK))
            .isEqualTo(R.drawable.ic_headphone);
    }

    @Test
    public void getIconResIdFromAudioDeviceType_hdmi_isHeadphone() {
        assertThat(mDeviceIconUtil.getIconResIdFromAudioDeviceType(AudioDeviceInfo.TYPE_HDMI))
            .isEqualTo(R.drawable.ic_headphone);
    }

    @Test
    public void getIconResIdFromAudioDeviceType_wiredHeadset_isHeadphone() {
        assertThat(
            mDeviceIconUtil.getIconResIdFromAudioDeviceType(AudioDeviceInfo.TYPE_WIRED_HEADSET))
            .isEqualTo(R.drawable.ic_headphone);
    }

    @Test
    public void getIconResIdFromAudioDeviceType_wiredHeadphones_isHeadphone() {
        assertThat(
            mDeviceIconUtil.getIconResIdFromAudioDeviceType(AudioDeviceInfo.TYPE_WIRED_HEADPHONES))
            .isEqualTo(R.drawable.ic_headphone);
    }

    @Test
    public void getIconResIdFromAudioDeviceType_builtinSpeaker_isSmartphone() {
        assertThat(
            mDeviceIconUtil.getIconResIdFromAudioDeviceType(AudioDeviceInfo.TYPE_BUILTIN_SPEAKER))
            .isEqualTo(R.drawable.ic_smartphone);
    }

    @Test
    public void getIconResIdFromAudioDeviceType_unsupportedType_isSmartphone() {
        assertThat(mDeviceIconUtil.getIconResIdFromAudioDeviceType(AudioDeviceInfo.TYPE_UNKNOWN))
            .isEqualTo(R.drawable.ic_smartphone);
    }
}
+5 −0
Original line number Diff line number Diff line
@@ -25,6 +25,7 @@ import com.android.systemui.SystemUIAppComponentFactory;
import com.android.systemui.dagger.qualifiers.PerUser;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.keyguard.KeyguardSliceProvider;
import com.android.systemui.media.muteawait.MediaMuteAwaitConnectionCli;
import com.android.systemui.media.taptotransfer.MediaTttCommandLineHelper;
import com.android.systemui.media.taptotransfer.receiver.MediaTttChipControllerReceiver;
import com.android.systemui.media.taptotransfer.sender.MediaTttChipControllerSender;
@@ -150,6 +151,7 @@ public interface SysUIComponent {
        getMediaTttChipControllerSender();
        getMediaTttChipControllerReceiver();
        getMediaTttCommandLineHelper();
        getMediaMuteAwaitConnectionCli();
        getUnfoldLatencyTracker().init();
        getFoldStateLoggingProvider().ifPresent(FoldStateLoggingProvider::init);
        getFoldStateLogger().ifPresent(FoldStateLogger::init);
@@ -226,6 +228,9 @@ public interface SysUIComponent {
    /** */
    Optional<MediaTttCommandLineHelper> getMediaTttCommandLineHelper();

    /** */
    Optional<MediaMuteAwaitConnectionCli> getMediaMuteAwaitConnectionCli();

    /**
     * Returns {@link CoreStartable}s that should be started with the application.
     */
Loading