1 /* 2 * Copyright 2018 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 package com.android.settingslib.media; 17 18 import android.content.Context; 19 import android.graphics.drawable.Drawable; 20 import android.text.TextUtils; 21 22 import androidx.annotation.IntDef; 23 24 import java.lang.annotation.Retention; 25 import java.lang.annotation.RetentionPolicy; 26 27 /** 28 * MediaDevice represents a media device(such like Bluetooth device, cast device and phone device). 29 */ 30 public abstract class MediaDevice implements Comparable<MediaDevice> { 31 private static final String TAG = "MediaDevice"; 32 33 @Retention(RetentionPolicy.SOURCE) 34 @IntDef({MediaDeviceType.TYPE_CAST_DEVICE, 35 MediaDeviceType.TYPE_BLUETOOTH_DEVICE, 36 MediaDeviceType.TYPE_PHONE_DEVICE}) 37 public @interface MediaDeviceType { 38 int TYPE_PHONE_DEVICE = 1; 39 int TYPE_CAST_DEVICE = 2; 40 int TYPE_BLUETOOTH_DEVICE = 3; 41 } 42 43 private int mConnectedRecord; 44 45 protected Context mContext; 46 protected int mType; 47 MediaDevice(Context context, @MediaDeviceType int type)48 MediaDevice(Context context, @MediaDeviceType int type) { 49 mType = type; 50 mContext = context; 51 } 52 initDeviceRecord()53 void initDeviceRecord() { 54 ConnectionRecordManager.getInstance().fetchLastSelectedDevice(mContext); 55 mConnectedRecord = ConnectionRecordManager.getInstance().fetchConnectionRecord(mContext, 56 getId()); 57 } 58 59 /** 60 * Get name from MediaDevice. 61 * 62 * @return name of MediaDevice. 63 */ getName()64 public abstract String getName(); 65 66 /** 67 * Get summary from MediaDevice. 68 * 69 * @return summary of MediaDevice. 70 */ getSummary()71 public abstract String getSummary(); 72 73 /** 74 * Get icon of MediaDevice. 75 * 76 * @return drawable of icon. 77 */ getIcon()78 public abstract Drawable getIcon(); 79 80 /** 81 * Get unique ID that represent MediaDevice 82 * @return unique id of MediaDevice 83 */ getId()84 public abstract String getId(); 85 86 /** 87 * Transfer MediaDevice for media 88 * 89 * @return result of transfer media 90 */ connect()91 public abstract boolean connect(); 92 setConnectedRecord()93 void setConnectedRecord() { 94 mConnectedRecord++; 95 ConnectionRecordManager.getInstance().setConnectionRecord(mContext, getId(), 96 mConnectedRecord); 97 } 98 99 /** 100 * Stop transfer MediaDevice 101 */ disconnect()102 public abstract void disconnect(); 103 104 /** 105 * According the MediaDevice type to check whether we are connected to this MediaDevice. 106 * 107 * @return Whether it is connected. 108 */ isConnected()109 public abstract boolean isConnected(); 110 111 /** 112 * Rules: 113 * 1. If there is one of the connected devices identified as a carkit, this carkit will 114 * be always on the top of the device list. Rule 2 and Rule 3 can’t overrule this rule. 115 * 2. For devices without any usage data yet 116 * WiFi device group sorted by alphabetical order + BT device group sorted by alphabetical 117 * order + phone speaker 118 * 3. For devices with usage record. 119 * The most recent used one + device group with usage info sorted by how many times the 120 * device has been used. 121 * 4. Phone device always in the top and the connected Bluetooth devices, cast devices and 122 * phone device will be always above on the disconnect Bluetooth devices. 123 * 124 * So the device list will look like 5 slots ranked as below. 125 * Rule 4 + Rule 1 + the most recently used device + Rule 3 + Rule 2 126 * Any slot could be empty. And available device will belong to one of the slots. 127 * 128 * @return a negative integer, zero, or a positive integer 129 * as this object is less than, equal to, or greater than the specified object. 130 */ 131 @Override compareTo(MediaDevice another)132 public int compareTo(MediaDevice another) { 133 // Check Bluetooth device is have same connection state 134 if (isConnected() ^ another.isConnected()) { 135 if (isConnected()) { 136 return -1; 137 } else { 138 return 1; 139 } 140 } 141 142 // Phone device always in the top. 143 if (mType == MediaDeviceType.TYPE_PHONE_DEVICE) { 144 return -1; 145 } else if (another.mType == MediaDeviceType.TYPE_PHONE_DEVICE) { 146 return 1; 147 } 148 // Check carkit 149 if (isCarKitDevice()) { 150 return -1; 151 } else if (another.isCarKitDevice()) { 152 return 1; 153 } 154 // Set last used device at the first item 155 String lastSelectedDevice = ConnectionRecordManager.getInstance().getLastSelectedDevice(); 156 if (TextUtils.equals(lastSelectedDevice, getId())) { 157 return -1; 158 } else if (TextUtils.equals(lastSelectedDevice, another.getId())) { 159 return 1; 160 } 161 // Sort by how many times the device has been used if there is usage record 162 if ((mConnectedRecord != another.mConnectedRecord) 163 && (another.mConnectedRecord > 0 || mConnectedRecord > 0)) { 164 return (another.mConnectedRecord - mConnectedRecord); 165 } 166 // Both devices have never been used 167 // To devices with the same type, sort by alphabetical order 168 if (mType == another.mType) { 169 final String s1 = getName(); 170 final String s2 = another.getName(); 171 return s1.compareToIgnoreCase(s2); 172 } 173 // Both devices have never been used, the priority is Phone > Cast > Bluetooth 174 return mType - another.mType; 175 } 176 177 /** 178 * Check if it is CarKit device 179 * @return true if it is CarKit device 180 */ isCarKitDevice()181 protected boolean isCarKitDevice() { 182 return false; 183 } 184 185 @Override equals(Object obj)186 public boolean equals(Object obj) { 187 if (!(obj instanceof MediaDevice)) { 188 return false; 189 } 190 final MediaDevice otherDevice = (MediaDevice) obj; 191 return otherDevice.getId().equals(getId()); 192 } 193 } 194