• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2022 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.settingslib.media;
18 
19 import static android.media.AudioDeviceInfo.AudioDeviceType;
20 import static android.media.AudioDeviceInfo.TYPE_BUILTIN_SPEAKER;
21 import static android.media.AudioDeviceInfo.TYPE_DOCK;
22 import static android.media.AudioDeviceInfo.TYPE_HDMI;
23 import static android.media.AudioDeviceInfo.TYPE_HDMI_ARC;
24 import static android.media.AudioDeviceInfo.TYPE_HDMI_EARC;
25 import static android.media.AudioDeviceInfo.TYPE_USB_ACCESSORY;
26 import static android.media.AudioDeviceInfo.TYPE_USB_DEVICE;
27 import static android.media.AudioDeviceInfo.TYPE_USB_HEADSET;
28 import static android.media.AudioDeviceInfo.TYPE_WIRED_HEADPHONES;
29 import static android.media.AudioDeviceInfo.TYPE_WIRED_HEADSET;
30 
31 import android.annotation.DrawableRes;
32 import android.annotation.SuppressLint;
33 import android.content.Context;
34 import android.content.pm.PackageManager;
35 import android.graphics.drawable.Drawable;
36 import android.media.AudioDeviceInfo;
37 import android.media.AudioManager;
38 import android.media.MediaRoute2Info;
39 import android.os.SystemProperties;
40 import android.util.SparseIntArray;
41 
42 import androidx.annotation.NonNull;
43 
44 import com.android.internal.annotations.VisibleForTesting;
45 import com.android.settingslib.R;
46 import com.android.settingslib.media.flags.Flags;
47 
48 import java.util.Arrays;
49 import java.util.Objects;
50 
51 /** A util class to get the appropriate icon for different device types. */
52 public class DeviceIconUtil {
53 
54     private static final SparseIntArray AUDIO_DEVICE_TO_MEDIA_ROUTE_TYPE = new SparseIntArray();
55 
56     private final boolean mIsTv;
57     private final boolean mIsTablet;
58     private final Context mContext;
DeviceIconUtil(@onNull Context context)59     public DeviceIconUtil(@NonNull Context context) {
60         mContext = Objects.requireNonNull(context);
61         mIsTv =
62                 mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_LEANBACK)
63                         && Flags.enableTvMediaOutputDialog();
64         mIsTablet =
65                 Arrays.asList(SystemProperties.get("ro.build.characteristics").split(","))
66                         .contains("tablet");
67     }
68 
69     @VisibleForTesting
DeviceIconUtil(boolean isTv)70     /* package */ DeviceIconUtil(boolean isTv) {
71         mContext = null;
72         mIsTv = isTv;
73         mIsTablet = false;
74     }
75 
76     /** Returns a drawable for an icon representing the given audioDeviceType. */
getIconFromAudioDeviceType(@udioDeviceType int audioDeviceType)77     public Drawable getIconFromAudioDeviceType(@AudioDeviceType int audioDeviceType) {
78         return mContext.getDrawable(getIconResIdFromAudioDeviceType(audioDeviceType));
79     }
80 
81     /** Returns a drawable res ID for an icon representing the given audioDeviceType. */
82     @DrawableRes
getIconResIdFromAudioDeviceType(@udioDeviceType int audioDeviceType)83     public int getIconResIdFromAudioDeviceType(@AudioDeviceType int audioDeviceType) {
84         int mediaRouteType =
85                 AUDIO_DEVICE_TO_MEDIA_ROUTE_TYPE.get(audioDeviceType, /* defaultValue */ -1);
86         return getIconResIdFromMediaRouteType(mediaRouteType);
87     }
88 
89     /** Returns a drawable res ID for an icon representing the given mediaRouteType. */
90     @DrawableRes
getIconResIdFromMediaRouteType(@ediaRoute2Info.Type int type)91     public int getIconResIdFromMediaRouteType(@MediaRoute2Info.Type int type) {
92         return mIsTv
93                 ? getIconResourceIdForTv(type)
94                 : getIconResourceIdForPhoneOrTablet(type, mIsTablet);
95     }
96 
97     @SuppressLint("SwitchIntDef")
98     @DrawableRes
getIconResourceIdForPhoneOrTablet( @ediaRoute2Info.Type int type, boolean isTablet)99     private static int getIconResourceIdForPhoneOrTablet(
100             @MediaRoute2Info.Type int type, boolean isTablet) {
101         int defaultResId = isTablet ? R.drawable.ic_media_tablet : R.drawable.ic_smartphone;
102 
103         return switch (type) {
104             case MediaRoute2Info.TYPE_USB_DEVICE,
105                             MediaRoute2Info.TYPE_USB_HEADSET,
106                             MediaRoute2Info.TYPE_USB_ACCESSORY,
107                             MediaRoute2Info.TYPE_WIRED_HEADSET,
108                             MediaRoute2Info.TYPE_WIRED_HEADPHONES ->
109                     R.drawable.ic_headphone;
110             case MediaRoute2Info.TYPE_DOCK -> R.drawable.ic_dock_device;
111             case MediaRoute2Info.TYPE_HDMI,
112                             MediaRoute2Info.TYPE_HDMI_ARC,
113                             MediaRoute2Info.TYPE_HDMI_EARC ->
114                     R.drawable.ic_external_display;
115             default -> defaultResId; // Includes TYPE_BUILTIN_SPEAKER.
116         };
117     }
118 
119     @SuppressLint("SwitchIntDef")
120     @DrawableRes
getIconResourceIdForTv(@ediaRoute2Info.Type int type)121     private int getIconResourceIdForTv(@MediaRoute2Info.Type int type) {
122         return switch (type) {
123             case MediaRoute2Info.TYPE_USB_DEVICE, MediaRoute2Info.TYPE_USB_HEADSET ->
124                     R.drawable.ic_headphone;
125             case MediaRoute2Info.TYPE_USB_ACCESSORY -> R.drawable.ic_usb;
126             case MediaRoute2Info.TYPE_DOCK -> R.drawable.ic_dock_device;
127             case MediaRoute2Info.TYPE_BUILTIN_SPEAKER ->
128                     isPanelTv() ? R.drawable.ic_tv : R.drawable.ic_tv_box_internal_speaker;
129             case MediaRoute2Info.TYPE_HDMI -> R.drawable.ic_tv;
130             case MediaRoute2Info.TYPE_HDMI_ARC, MediaRoute2Info.TYPE_HDMI_EARC ->
131                     R.drawable.ic_hdmi;
132             case MediaRoute2Info.TYPE_WIRED_HEADSET, MediaRoute2Info.TYPE_WIRED_HEADPHONES ->
133                     R.drawable.ic_wired_device;
134             default -> R.drawable.ic_media_speaker_device;
135         };
136     }
137 
138     private boolean isPanelTv() {
139         if (mContext == null) {
140             // This should only happen during testing.
141             return true;
142         }
143         AudioManager audioManager = mContext.getSystemService(AudioManager.class);
144         AudioDeviceInfo[] devices = audioManager.getDevices(
145                 AudioManager.GET_DEVICES_OUTPUTS);
146         // If we have an HDMI output (not ARC/eARC) we can assume it's a dongle / set top box.
147         for (AudioDeviceInfo device : devices) {
148             if (device.getType() == TYPE_HDMI) {
149                 return false;
150             }
151         }
152         return true;
153     }
154 
155     static {
156         AUDIO_DEVICE_TO_MEDIA_ROUTE_TYPE.put(TYPE_USB_DEVICE, MediaRoute2Info.TYPE_USB_DEVICE);
157         AUDIO_DEVICE_TO_MEDIA_ROUTE_TYPE.put(TYPE_USB_HEADSET, MediaRoute2Info.TYPE_USB_HEADSET);
158         AUDIO_DEVICE_TO_MEDIA_ROUTE_TYPE.put(
159                 TYPE_USB_ACCESSORY, MediaRoute2Info.TYPE_USB_ACCESSORY);
160         AUDIO_DEVICE_TO_MEDIA_ROUTE_TYPE.put(TYPE_DOCK, MediaRoute2Info.TYPE_DOCK);
161         AUDIO_DEVICE_TO_MEDIA_ROUTE_TYPE.put(TYPE_HDMI, MediaRoute2Info.TYPE_HDMI);
162         AUDIO_DEVICE_TO_MEDIA_ROUTE_TYPE.put(TYPE_HDMI_ARC, MediaRoute2Info.TYPE_HDMI_ARC);
163         AUDIO_DEVICE_TO_MEDIA_ROUTE_TYPE.put(TYPE_HDMI_EARC, MediaRoute2Info.TYPE_HDMI_EARC);
164         AUDIO_DEVICE_TO_MEDIA_ROUTE_TYPE.put(
165                 TYPE_WIRED_HEADSET, MediaRoute2Info.TYPE_WIRED_HEADSET);
166         AUDIO_DEVICE_TO_MEDIA_ROUTE_TYPE.put(
167                 TYPE_WIRED_HEADPHONES, MediaRoute2Info.TYPE_WIRED_HEADPHONES);
168         AUDIO_DEVICE_TO_MEDIA_ROUTE_TYPE.put(
169                 TYPE_BUILTIN_SPEAKER, MediaRoute2Info.TYPE_BUILTIN_SPEAKER);
170     }
171 }
172