1 /*
2  * Copyright (C) 2022 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.statusbar.pipeline.mobile.data.repository.demo
18 
19 import android.os.Bundle
20 import android.telephony.Annotation.DataActivityType
21 import android.telephony.TelephonyManager.DATA_ACTIVITY_IN
22 import android.telephony.TelephonyManager.DATA_ACTIVITY_INOUT
23 import android.telephony.TelephonyManager.DATA_ACTIVITY_NONE
24 import android.telephony.TelephonyManager.DATA_ACTIVITY_OUT
25 import com.android.settingslib.SignalIcon.MobileIconGroup
26 import com.android.settingslib.mobile.TelephonyIcons
27 import com.android.systemui.dagger.SysUISingleton
28 import com.android.systemui.dagger.qualifiers.Application
29 import com.android.systemui.demomode.DemoMode.COMMAND_NETWORK
30 import com.android.systemui.demomode.DemoModeController
31 import com.android.systemui.statusbar.pipeline.mobile.data.repository.demo.model.FakeNetworkEventModel
32 import com.android.systemui.statusbar.pipeline.mobile.data.repository.demo.model.FakeNetworkEventModel.Mobile
33 import com.android.systemui.statusbar.pipeline.mobile.data.repository.demo.model.FakeNetworkEventModel.MobileDisabled
34 import javax.inject.Inject
35 import kotlinx.coroutines.CoroutineScope
36 import kotlinx.coroutines.flow.SharingStarted
37 import kotlinx.coroutines.flow.map
38 import kotlinx.coroutines.flow.shareIn
39 
40 /**
41  * Data source that can map from demo mode commands to inputs into the
42  * [DemoMobileConnectionsRepository]'s flows
43  */
44 @SysUISingleton
45 class DemoModeMobileConnectionDataSource
46 @Inject
47 constructor(
48     demoModeController: DemoModeController,
49     @Application scope: CoroutineScope,
50 ) {
51     private val demoCommandStream = demoModeController.demoFlowForCommand(COMMAND_NETWORK)
52 
53     // If the args contains "mobile", then all of the args are relevant. It's just the way demo mode
54     // commands work and it's a little silly
55     private val _mobileCommands = demoCommandStream.map { args -> args.toMobileEvent() }
56     val mobileEvents = _mobileCommands.shareIn(scope, SharingStarted.WhileSubscribed())
57 
58     private fun Bundle.toMobileEvent(): FakeNetworkEventModel? {
59         val mobile = getString("mobile") ?: return null
60         return if (mobile == "show") {
61             activeMobileEvent()
62         } else {
63             MobileDisabled(subId = getString("slot")?.toInt())
64         }
65     }
66 
67     /** Parse a valid mobile command string into a network event */
68     private fun Bundle.activeMobileEvent(): Mobile {
69         // There are many key/value pairs supported by mobile demo mode. Bear with me here
70         val level = getString("level")?.toInt()
71         val dataType = getString("datatype")?.toDataType()
72         val slot = getString("slot")?.toInt()
73         val carrierId = getString("carrierid")?.toInt()
74         val inflateStrength = getString("inflate").toBoolean()
75         val activity = getString("activity")?.toActivity()
76         val carrierNetworkChange = getString("carriernetworkchange") == "show"
77         val roaming = getString("roam") == "show"
78         val name = getString("networkname") ?: "demo mode"
79 
80         return Mobile(
81             level = level,
82             dataType = dataType,
83             subId = slot,
84             carrierId = carrierId,
85             inflateStrength = inflateStrength,
86             activity = activity,
87             carrierNetworkChange = carrierNetworkChange,
88             roaming = roaming,
89             name = name,
90         )
91     }
92 }
93 
94 private fun String.toDataType(): MobileIconGroup =
95     when (this) {
96         "1x" -> TelephonyIcons.ONE_X
97         "3g" -> TelephonyIcons.THREE_G
98         "4g" -> TelephonyIcons.FOUR_G
99         "4g+" -> TelephonyIcons.FOUR_G_PLUS
100         "5g" -> TelephonyIcons.NR_5G
101         "5ge" -> TelephonyIcons.LTE_CA_5G_E
102         "5g+" -> TelephonyIcons.NR_5G_PLUS
103         "e" -> TelephonyIcons.E
104         "g" -> TelephonyIcons.G
105         "h" -> TelephonyIcons.H
106         "h+" -> TelephonyIcons.H_PLUS
107         "lte" -> TelephonyIcons.LTE
108         "lte+" -> TelephonyIcons.LTE_PLUS
109         "dis" -> TelephonyIcons.DATA_DISABLED
110         "not" -> TelephonyIcons.NOT_DEFAULT_DATA
111         else -> TelephonyIcons.UNKNOWN
112     }
113 
114 @DataActivityType
115 private fun String.toActivity(): Int =
116     when (this) {
117         "inout" -> DATA_ACTIVITY_INOUT
118         "in" -> DATA_ACTIVITY_IN
119         "out" -> DATA_ACTIVITY_OUT
120         else -> DATA_ACTIVITY_NONE
121     }
122