Home | History | Annotate | Download | only in media
      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 
     48     MediaDevice(Context context, @MediaDeviceType int type) {
     49         mType = type;
     50         mContext = context;
     51     }
     52 
     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      */
     64     public abstract String getName();
     65 
     66     /**
     67      * Get summary from MediaDevice.
     68      *
     69      * @return summary of MediaDevice.
     70      */
     71     public abstract String getSummary();
     72 
     73     /**
     74      * Get icon of MediaDevice.
     75      *
     76      * @return drawable of icon.
     77      */
     78     public abstract Drawable getIcon();
     79 
     80     /**
     81      * Get unique ID that represent MediaDevice
     82      * @return unique id of MediaDevice
     83      */
     84     public abstract String getId();
     85 
     86     /**
     87      * Transfer MediaDevice for media
     88      *
     89      * @return result of transfer media
     90      */
     91     public abstract boolean connect();
     92 
     93     void setConnectedRecord() {
     94         mConnectedRecord++;
     95         ConnectionRecordManager.getInstance().setConnectionRecord(mContext, getId(),
     96                 mConnectedRecord);
     97     }
     98 
     99     /**
    100      * Stop transfer MediaDevice
    101      */
    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      */
    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 cant 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
    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      */
    181     protected boolean isCarKitDevice() {
    182         return false;
    183     }
    184 
    185     @Override
    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