• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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