1 /* 2 * Copyright (C) 2024 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.systemui.volume.panel.component.anc.data.repository 18 19 import android.bluetooth.BluetoothDevice 20 import android.net.Uri 21 import androidx.slice.Slice 22 import androidx.slice.SliceViewManager 23 import com.android.settingslib.bluetooth.BluetoothUtils 24 import com.android.systemui.dagger.qualifiers.Main 25 import com.android.systemui.slice.sliceForUri 26 import dagger.assisted.Assisted 27 import dagger.assisted.AssistedFactory 28 import dagger.assisted.AssistedInject 29 import kotlin.coroutines.CoroutineContext 30 import kotlinx.coroutines.flow.Flow 31 import kotlinx.coroutines.flow.flowOf 32 import kotlinx.coroutines.flow.flowOn 33 34 /** Provides ANC slice data */ 35 interface AncSliceRepository { 36 37 /** 38 * ANC slice with a given width. [isCollapsed] slice shows a single button, and expanded shows a 39 * row buttons. 40 * 41 * Emits null when there is no ANC slice available. This can mean that: 42 * - there is no supported device connected; 43 * - there is no slice provider for the uri; 44 */ ancSlicenull45 fun ancSlice( 46 device: BluetoothDevice, 47 width: Int, 48 isCollapsed: Boolean, 49 hideLabel: Boolean 50 ): Flow<Slice?> 51 } 52 53 class AncSliceRepositoryImpl 54 @AssistedInject 55 constructor( 56 @Main private val mainCoroutineContext: CoroutineContext, 57 @Assisted private val sliceViewManager: SliceViewManager, 58 ) : AncSliceRepository { 59 60 override fun ancSlice( 61 device: BluetoothDevice, 62 width: Int, 63 isCollapsed: Boolean, 64 hideLabel: Boolean 65 ): Flow<Slice?> { 66 val sliceUri = 67 device.getExtraControlUri(width, isCollapsed, hideLabel) ?: return flowOf(null) 68 return sliceViewManager.sliceForUri(sliceUri).flowOn(mainCoroutineContext) 69 } 70 71 private fun BluetoothDevice.getExtraControlUri( 72 width: Int, 73 isCollapsed: Boolean, 74 hideLabel: Boolean 75 ): Uri? { 76 val uri: String? = BluetoothUtils.getControlUriMetaData(this) 77 uri ?: return null 78 79 return if (uri.isEmpty()) { 80 null 81 } else { 82 Uri.parse( 83 "$uri$width" + 84 "&version=${SliceParameters.VERSION}" + 85 "&is_collapsed=$isCollapsed" + 86 "&hide_label=$hideLabel" 87 ) 88 } 89 } 90 91 @AssistedFactory 92 interface Factory { 93 fun create(sliceViewManager: SliceViewManager): AncSliceRepositoryImpl 94 } 95 96 private object SliceParameters { 97 /** 98 * Slice version 99 * 1) legacy slice 100 * 2) new slice 101 */ 102 const val VERSION = 2 103 } 104 } 105