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 package com.android.permissioncontroller.privacysources 17 18 import android.content.ComponentName 19 import android.content.Context 20 import android.provider.Settings 21 import android.text.TextUtils 22 import android.util.Log 23 import kotlinx.coroutines.sync.Mutex 24 import kotlinx.coroutines.sync.withLock 25 26 /** 27 * Code reference from https://source.corp.google.com/android/frameworks/base/packages/SettingsLib/ 28 * src/com/android/settingslib/accessibility/AccessibilityUtils.java 29 */ 30 object AccessibilitySettingsUtil { 31 private const val ENABLED_ACCESSIBILITY_SERVICES_SEPARATOR = ':' 32 private val LOG_TAG = AccessibilitySettingsUtil::class.java.simpleName 33 private val lock = Mutex() 34 35 /** 36 * Changes an accessibility component's state. 37 */ disableAccessibilityServicenull38 suspend fun disableAccessibilityService(context: Context, serviceToBeDisabled: ComponentName) { 39 lock.withLock { 40 val settingsEnabledA11yServices = getEnabledServicesFromSettings(context) 41 if (settingsEnabledA11yServices.isEmpty() || 42 !settingsEnabledA11yServices.contains(serviceToBeDisabled) 43 ) { 44 Log.w(LOG_TAG, "${serviceToBeDisabled.toShortString()} is already disabled " + 45 "or not installed.") 46 return 47 } 48 49 settingsEnabledA11yServices.remove(serviceToBeDisabled) 50 51 val updatedEnabledServices = settingsEnabledA11yServices.map { it.flattenToString() } 52 .joinToString(separator = ENABLED_ACCESSIBILITY_SERVICES_SEPARATOR.toString()) 53 54 Settings.Secure.putString( 55 context.contentResolver, 56 Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES, 57 updatedEnabledServices 58 ) 59 } 60 } 61 62 /** 63 * @return the mutable set of enabled accessibility services. 64 */ getEnabledServicesFromSettingsnull65 fun getEnabledServicesFromSettings(context: Context): MutableSet<ComponentName> { 66 val enabledServicesSetting = Settings.Secure.getString( 67 context.contentResolver, Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES 68 ) 69 val enabledServices = mutableSetOf<ComponentName>() 70 if (TextUtils.isEmpty(enabledServicesSetting)) { 71 return enabledServices 72 } 73 74 val colonSplitter: TextUtils.StringSplitter = TextUtils.SimpleStringSplitter( 75 ENABLED_ACCESSIBILITY_SERVICES_SEPARATOR 76 ) 77 colonSplitter.setString(enabledServicesSetting) 78 79 for (componentNameString in colonSplitter) { 80 val enabledService = ComponentName.unflattenFromString( 81 componentNameString 82 ) 83 if (enabledService != null) { 84 enabledServices.add(enabledService) 85 } else { 86 Log.e(LOG_TAG, "unable to parse accessibility service $componentNameString") 87 } 88 } 89 90 return enabledServices 91 } 92 } 93