1 /*
<lambda>null2  * 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.settings.network.apn
18 
19 import android.content.ContentValues
20 import android.content.Context
21 import android.net.Uri
22 import android.provider.Telephony
23 import android.util.Log
24 import androidx.lifecycle.LifecycleOwner
25 import androidx.lifecycle.lifecycleScope
26 import com.android.settingslib.spa.framework.util.collectLatestWithLifecycle
27 import com.android.settingslib.spaprivileged.database.contentChangeFlow
28 import kotlinx.coroutines.Dispatchers
29 import kotlinx.coroutines.flow.Flow
30 import kotlinx.coroutines.flow.conflate
31 import kotlinx.coroutines.flow.flowOn
32 import kotlinx.coroutines.flow.map
33 import kotlinx.coroutines.launch
34 import kotlinx.coroutines.withContext
35 
36 class PreferredApnRepository(private val context: Context, private val subId: Int) {
37     private val contentResolver = context.contentResolver
38     private val preferredApnUri =
39         Uri.withAppendedPath(Telephony.Carriers.PREFERRED_APN_URI, "$subId")
40 
41     /** TODO: Move this to UI layer, when UI layer migrated to Kotlin. */
42     fun restorePreferredApn(lifecycleOwner: LifecycleOwner, onRestored: () -> Unit) {
43         lifecycleOwner.lifecycleScope.launch {
44             withContext(Dispatchers.Default) {
45                 restorePreferredApn()
46             }
47             onRestored()
48         }
49     }
50 
51     fun restorePreferredApn() {
52         contentResolver.delete(
53             Uri.withAppendedPath(RestorePreferredApnUri, "subId/$subId"), null, null
54         )
55     }
56 
57     fun setPreferredApn(apnId: String) {
58         val values = ContentValues().apply {
59             put(ApnSettings.APN_ID, apnId)
60         }
61         contentResolver.update(preferredApnUri, values, null, null)
62     }
63 
64     /** TODO: Move this to UI layer, when UI layer migrated to Kotlin. */
65     fun collectPreferredApn(lifecycleOwner: LifecycleOwner, action: (String?) -> Unit) {
66         preferredApnFlow().collectLatestWithLifecycle(lifecycleOwner, action = action)
67     }
68 
69     fun preferredApnFlow(): Flow<String?> = context.contentChangeFlow(preferredApnUri).map {
70         contentResolver.query(
71             preferredApnUri,
72             arrayOf(Telephony.Carriers._ID),
73             null,
74             null,
75             Telephony.Carriers.DEFAULT_SORT_ORDER,
76         ).use { cursor ->
77             if (cursor?.moveToNext() == true) {
78                 cursor.getString(cursor.getColumnIndex(Telephony.Carriers._ID))
79             } else {
80                 null
81             }.also { Log.d(TAG, "[$subId] preferred APN: $it") }
82         }
83     }.conflate().flowOn(Dispatchers.Default)
84 
85     companion object {
86         private const val TAG = "PreferredApnRepository"
87 
88         private const val RESTORE_PREFERRED_APN = "content://telephony/carriers/restore"
89 
90         @JvmStatic
91         val RestorePreferredApnUri: Uri = Uri.parse(RESTORE_PREFERRED_APN)
92     }
93 }
94