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