1 /* 2 * Copyright (C) 2025 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.car.tos 18 19 import android.car.settings.CarSettings.Secure.KEY_UNACCEPTED_TOS_DISABLED_APPS 20 import android.car.settings.CarSettings.Secure.KEY_USER_TOS_ACCEPTED 21 import android.content.Context 22 import android.content.Intent 23 import android.os.UserHandle 24 import android.provider.Settings 25 import android.util.Log 26 import java.net.URISyntaxException 27 import java.util.Objects 28 29 /** Helper methods for terms of services (tos) restrictions **/ 30 object TosHelper { 31 private const val TAG = "TosHelper" 32 33 // This value indicates if TOS is in uninitialized state 34 const val TOS_UNINITIALIZED = "0" 35 36 // This value indicates if TOS has not been accepted by the user 37 const val TOS_NOT_ACCEPTED = "1" 38 39 // This value indicates if TOS has been accepted by the user 40 const val TOS_ACCEPTED = "2" 41 private const val TOS_DISABLED_APPS_SEPARATOR = "," 42 43 /** 44 * Returns a set of packages that are disabled when terms of services are not accepted. 45 * 46 * @param context The application context 47 * @param uid A user id for a particular user 48 * 49 * @return Set of packages disabled by tos 50 */ 51 @JvmStatic 52 @JvmOverloads getTosDisabledPackagesnull53 fun getTosDisabledPackages(context: Context, uid: Int = UserHandle.myUserId()): Set<String> { 54 val settingsValue = Settings.Secure.getStringForUser( 55 context.contentResolver, 56 KEY_UNACCEPTED_TOS_DISABLED_APPS, 57 uid 58 ) 59 return settingsValue?.split(TOS_DISABLED_APPS_SEPARATOR)?.toSet() ?: emptySet() 60 } 61 62 /** 63 * Gets the intent for launching the terms of service acceptance flow. 64 * 65 * @param context The app context 66 * @param id The desired resource identifier 67 * 68 * @return TOS intent, or null 69 */ 70 @JvmStatic getIntentForTosAcceptanceFlownull71 fun getIntentForTosAcceptanceFlow(context: Context, id: Int): Intent? { 72 val tosIntentName = context.resources.getString(id) 73 return try { 74 Intent.parseUri(tosIntentName, Intent.URI_ANDROID_APP_SCHEME) 75 } catch (e: URISyntaxException) { 76 Log.e(TAG, "Invalid intent URI in user_tos_activity_intent", e) 77 null 78 } 79 } 80 81 /** 82 * Replaces the [mapIntent] with an intent defined in the resources with [id] if terms of 83 * services have not been accepted and the app defined by [mapIntent] is disabled. 84 */ 85 @JvmStatic 86 @JvmOverloads maybeReplaceWithTosMapIntentnull87 fun maybeReplaceWithTosMapIntent( 88 context: Context, 89 mapIntent: Intent, 90 id: Int, 91 uid: Int = UserHandle.myUserId() 92 ): Intent { 93 val packageName = mapIntent.component?.packageName 94 val tosDisabledPackages = getTosDisabledPackages(context, uid) 95 96 Log.i(TAG, "TOS disabled packages:$tosDisabledPackages") 97 Log.i(TAG, "TOS accepted:" + tosAccepted(context)) 98 99 // Launch tos map intent when the user has not accepted tos and when the 100 // default maps package is not available to package manager, or it's disabled by tos 101 if (!tosAccepted(context) && 102 (packageName == null || tosDisabledPackages.contains(packageName)) 103 ) { 104 Log.i(TAG, "Replacing default maps intent with tos map intent") 105 return getIntentForTosAcceptanceFlow(context, id) ?: mapIntent 106 } 107 return mapIntent 108 } 109 110 /** 111 * Returns true if tos is accepted or uninitialized, false otherwise. 112 */ 113 @JvmStatic 114 @JvmOverloads tosAcceptednull115 fun tosAccepted(context: Context, uid: Int = UserHandle.myUserId()): Boolean { 116 val settingsValue = Settings.Secure.getStringForUser( 117 context.contentResolver, 118 KEY_USER_TOS_ACCEPTED, 119 uid 120 ) 121 // We consider an uninitialized state to be TOS accepted. 122 return Objects.equals(settingsValue, TOS_ACCEPTED) || tosStatusUninitialized(context, uid) 123 } 124 125 /** 126 * Returns true if tos is uninitialized, false otherwise. 127 */ 128 @JvmStatic 129 @JvmOverloads tosStatusUninitializednull130 fun tosStatusUninitialized(context: Context, uid: Int = UserHandle.myUserId()): Boolean { 131 val settingsValue = Settings.Secure.getStringForUser( 132 context.contentResolver, 133 KEY_USER_TOS_ACCEPTED, 134 uid 135 ) 136 return settingsValue == null || Objects.equals(settingsValue, TOS_UNINITIALIZED) 137 } 138 } 139