1 /*
2  * Copyright 2023 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 androidx.core.telecom
18 
19 import android.os.Build.VERSION_CODES
20 import android.os.ParcelUuid
21 import androidx.annotation.IntDef
22 import androidx.annotation.RequiresApi
23 import androidx.annotation.RestrictTo
24 import androidx.core.telecom.internal.CallEndpointUuidTracker
25 import androidx.core.telecom.internal.utils.EndpointUtils
26 import java.util.Objects
27 
28 /**
29  * Constructor for a [CallEndpointCompat] object.
30  *
31  * @param name Human-readable name associated with the endpoint
32  * @param type The type of endpoint through which call media being routed Allowed values:
33  *   [TYPE_EARPIECE] , [TYPE_BLUETOOTH] , [TYPE_WIRED_HEADSET] , [TYPE_SPEAKER] , [TYPE_STREAMING] ,
34  *   [TYPE_UNKNOWN]
35  * @param identifier A unique identifier for this endpoint on the device
36  */
37 @RequiresApi(VERSION_CODES.O)
38 public class CallEndpointCompat(
39     public val name: CharSequence,
40     public val type: Int,
41     public val identifier: ParcelUuid
42 ) : Comparable<CallEndpointCompat> {
43     internal var mMackAddress: String = UNKNOWN_MAC_ADDRESS
44 
toStringnull45     override fun toString(): String {
46         return "CallEndpoint(" +
47             "name=[$name]," +
48             "type=[${EndpointUtils.endpointTypeToString(type)}]," +
49             "identifier=[$identifier])"
50     }
51 
52     /**
53      * Compares this [CallEndpointCompat] to the other [CallEndpointCompat] for order. Returns a
54      * positive number if this type rank is greater than the other value. Returns a negative number
55      * if this type rank is less than the other value. Sort the CallEndpoint by type. Ranking them
56      * by:
57      * 1. TYPE_WIRED_HEADSET
58      * 2. TYPE_BLUETOOTH
59      * 3. TYPE_SPEAKER
60      * 4. TYPE_EARPIECE
61      * 5. TYPE_STREAMING
62      * 6. TYPE_UNKNOWN If two endpoints have the same type, the name is compared to determine the
63      *    value.
64      */
compareTonull65     override fun compareTo(other: CallEndpointCompat): Int {
66         // sort by type
67         val res = this.getTypeRank().compareTo(other.getTypeRank())
68         if (res != 0) {
69             return res
70         }
71         // break ties using alphabetic order
72         return this.name.toString().compareTo(other.name.toString())
73     }
74 
equalsnull75     override fun equals(other: Any?): Boolean {
76         return other is CallEndpointCompat &&
77             name == other.name &&
78             type == other.type &&
79             identifier == other.identifier
80     }
81 
hashCodenull82     override fun hashCode(): Int {
83         return Objects.hash(name, type, identifier)
84     }
85 
86     public companion object {
87         @RestrictTo(RestrictTo.Scope.LIBRARY)
88         @Retention(AnnotationRetention.SOURCE)
89         @IntDef(
90             TYPE_UNKNOWN,
91             TYPE_EARPIECE,
92             TYPE_BLUETOOTH,
93             TYPE_WIRED_HEADSET,
94             TYPE_SPEAKER,
95             TYPE_STREAMING
96         )
97         @Target(AnnotationTarget.TYPE, AnnotationTarget.PROPERTY, AnnotationTarget.VALUE_PARAMETER)
98         public annotation class EndpointType
99 
100         /** Indicates that the type of endpoint through which call media flows is unknown type. */
101         public const val TYPE_UNKNOWN: Int = -1
102 
103         /** Indicates that the type of endpoint through which call media flows is an earpiece. */
104         public const val TYPE_EARPIECE: Int = 1
105 
106         /** Indicates that the type of endpoint through which call media flows is a Bluetooth. */
107         public const val TYPE_BLUETOOTH: Int = 2
108 
109         /**
110          * Indicates that the type of endpoint through which call media flows is a wired headset.
111          */
112         public const val TYPE_WIRED_HEADSET: Int = 3
113 
114         /** Indicates that the type of endpoint through which call media flows is a speakerphone. */
115         public const val TYPE_SPEAKER: Int = 4
116 
117         /** Indicates that the type of endpoint through which call media flows is an external. */
118         public const val TYPE_STREAMING: Int = 5
119 
120         internal const val UNKNOWN_MAC_ADDRESS: String = "-1"
121     }
122 
123     internal constructor(
124         name: String,
125         @EndpointType type: Int,
126         sessionId: Int,
127         mackAddress: String = "-1"
128     ) : this(name, type, CallEndpointUuidTracker.getUuid(sessionId, type, name)) {
129         mMackAddress = mackAddress
130     }
131 
132     /** Internal helper to determine if this [CallEndpointCompat] is EndpointType#TYPE_BLUETOOTH */
isBluetoothTypenull133     internal fun isBluetoothType(): Boolean {
134         return type == TYPE_BLUETOOTH
135     }
136 
getTypeRanknull137     private fun getTypeRank(): Int {
138         return when (this.type) {
139             TYPE_WIRED_HEADSET -> return 0
140             TYPE_BLUETOOTH -> return 1
141             TYPE_SPEAKER -> return 2
142             TYPE_EARPIECE -> return 3
143             TYPE_STREAMING -> return 4
144             else -> 5
145         }
146     }
147 }
148