1 /* 2 * Copyright (C) 2023 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.devicelockcontroller.storage; 18 19 import static com.android.devicelockcontroller.storage.ISetupParametersService.Stub.asInterface; 20 21 import android.annotation.SuppressLint; 22 import android.content.ComponentName; 23 import android.content.Context; 24 import android.os.Bundle; 25 26 import androidx.annotation.GuardedBy; 27 import androidx.annotation.NonNull; 28 import androidx.annotation.Nullable; 29 import androidx.annotation.VisibleForTesting; 30 31 import com.android.devicelockcontroller.DeviceLockControllerApplication; 32 import com.android.devicelockcontroller.common.DeviceLockConstants.ProvisioningType; 33 34 import com.google.common.util.concurrent.ListenableFuture; 35 import com.google.common.util.concurrent.ListeningExecutorService; 36 import com.google.common.util.concurrent.MoreExecutors; 37 38 import java.util.List; 39 import java.util.concurrent.Executors; 40 41 /** 42 * Class used to access Setup Parameters from any users. 43 * Storage is hosted by user 0 and is accessed indirectly using a service. 44 */ 45 public final class SetupParametersClient extends DlcClient 46 implements SetupParametersClientInterface { 47 private static final Object sInstanceLock = new Object(); 48 49 @SuppressLint("StaticFieldLeak") // Only holds application context. 50 @GuardedBy("sInstanceLock") 51 private static SetupParametersClient sClient; 52 SetupParametersClient(@onNull Context context, ListeningExecutorService executorService)53 private SetupParametersClient(@NonNull Context context, 54 ListeningExecutorService executorService) { 55 super(context, new ComponentName(context, SetupParametersService.class), executorService); 56 } 57 58 /** 59 * Get the SetupParametersClient singleton instance. 60 */ getInstance()61 public static SetupParametersClient getInstance() { 62 return getInstance(DeviceLockControllerApplication.getAppContext(), 63 /* executorService= */ null); 64 } 65 66 /** 67 * Get the SetupParametersClient singleton instance. 68 */ 69 @VisibleForTesting getInstance(Context appContext, @Nullable ListeningExecutorService executorService)70 public static SetupParametersClient getInstance(Context appContext, 71 @Nullable ListeningExecutorService executorService) { 72 synchronized (sInstanceLock) { 73 if (sClient == null) { 74 sClient = new SetupParametersClient( 75 appContext, 76 executorService == null 77 ? MoreExecutors.listeningDecorator(Executors.newCachedThreadPool()) 78 : executorService); 79 } 80 return sClient; 81 } 82 } 83 84 /** 85 * Reset the Client singleton instance 86 */ 87 @VisibleForTesting reset()88 public static void reset() { 89 synchronized (sInstanceLock) { 90 if (sClient != null) { 91 sClient.tearDown(); 92 sClient = null; 93 } 94 } 95 } 96 97 /** 98 * Override setup parameters if there exists any; otherwise create new parameters. 99 * Note that this API can only be called in debuggable build for debugging purpose. 100 */ 101 @SuppressWarnings("GuardedBy") // mLock already held in "call" (error prone). overridePrefs(Bundle bundle)102 public ListenableFuture<Void> overridePrefs(Bundle bundle) { 103 return call(() -> { 104 asInterface(getService()).overridePrefs(bundle); 105 return null; 106 }); 107 } 108 109 /** 110 * Clear any existing setup parameters. 111 * Note that this API can only be called in debuggable build for debugging purpose. 112 */ 113 @SuppressWarnings("GuardedBy") // mLock already held in "call" (error prone). clear()114 public ListenableFuture<Void> clear() { 115 return call(() -> { 116 asInterface(getService()).clear(); 117 return null; 118 }); 119 } 120 121 /** 122 * Parse setup parameters from the extras bundle. 123 * 124 * @param bundle Bundle with provisioning parameters. 125 */ 126 @SuppressWarnings("GuardedBy") // mLock already held in "call" (error prone). 127 public ListenableFuture<Void> createPrefs(Bundle bundle) { 128 return call(() -> { 129 asInterface(getService()).createPrefs(bundle); 130 return null; 131 }); 132 } 133 134 /** 135 * Get the name of the package implementing the kiosk app. 136 * 137 * @return kiosk app package name. 138 */ 139 @Override 140 @SuppressWarnings("GuardedBy") // mLock already held in "call" (error prone). 141 public ListenableFuture<String> getKioskPackage() { 142 return call(() -> asInterface(getService()).getKioskPackage()); 143 } 144 145 /** 146 * Get the setup activity for the kiosk app. 147 * 148 * @return Setup activity. 149 */ 150 @SuppressWarnings("GuardedBy") // mLock already held in "call" (error prone). 151 public ListenableFuture<String> getKioskSetupActivity() { 152 return call(() -> asInterface(getService()).getKioskSetupActivity()); 153 } 154 155 /** 156 * Check if the configuration disables outgoing calls. 157 * 158 * @return True if outgoign calls are disabled. 159 */ 160 @SuppressWarnings("GuardedBy") // mLock already held in "call" (error prone). 161 public ListenableFuture<Boolean> getOutgoingCallsDisabled() { 162 return call(() -> asInterface(getService()).getOutgoingCallsDisabled()); 163 } 164 165 /** 166 * Get package allowlist provisioned by the server. 167 * 168 * @return List of allowed packages. 169 */ 170 @SuppressWarnings("GuardedBy") // mLock already held in "call" (error prone). 171 public ListenableFuture<List<String>> getKioskAllowlist() { 172 return call(() -> asInterface(getService()).getKioskAllowlist()); 173 } 174 175 /** 176 * Check if notifications are enabled in lock task mode. 177 * 178 * @return True if notification are enabled. 179 */ 180 @SuppressWarnings("GuardedBy") // mLock already held in "call" (error prone). 181 public ListenableFuture<Boolean> isNotificationsInLockTaskModeEnabled() { 182 return call(() -> asInterface(getService()).isNotificationsInLockTaskModeEnabled()); 183 } 184 185 /** 186 * Get the provisioning type of this configuration. 187 * 188 * @return The type of provisioning which could be one of {@link ProvisioningType}. 189 */ 190 @SuppressWarnings("GuardedBy") // mLock already held in "call" (error prone). 191 public ListenableFuture<@ProvisioningType Integer> getProvisioningType() { 192 return call(() -> asInterface(getService()).getProvisioningType()); 193 } 194 195 /** 196 * Check if provision is mandatory. 197 * 198 * @return True if the provision should be mandatory. 199 */ 200 @SuppressWarnings("GuardedBy") // mLock already held in "call" (error prone). 201 public ListenableFuture<Boolean> isProvisionMandatory() { 202 return call(() -> asInterface(getService()).isProvisionMandatory()); 203 } 204 205 /** 206 * Get the name of the provider of the kiosk app. 207 * 208 * @return the name of the provider. 209 */ 210 @Nullable 211 @SuppressWarnings("GuardedBy") // mLock already held in "call" (error prone). 212 public ListenableFuture<String> getKioskAppProviderName() { 213 return call(() -> asInterface(getService()).getKioskAppProviderName()); 214 } 215 216 /** 217 * Check if installing from unknown sources should be disallowed on this device after 218 * provision 219 * 220 * @return True if installing from unknown sources is disallowed. 221 */ 222 @SuppressWarnings("GuardedBy") // mLock already held in "call" (error prone). 223 public ListenableFuture<Boolean> isInstallingFromUnknownSourcesDisallowed() { 224 return call(() -> asInterface(getService()).isInstallingFromUnknownSourcesDisallowed()); 225 } 226 227 /** 228 * Get the Terms and Conditions URL of the partner for enrolling in a Device Lock program. 229 * 230 * @return The URL to the terms and conditions. 231 */ 232 @SuppressWarnings("GuardedBy") // mLock already held in "call" (error prone). 233 public ListenableFuture<String> getTermsAndConditionsUrl() { 234 return call(() -> asInterface(getService()).getTermsAndConditionsUrl()); 235 } 236 237 /** 238 * The URL to the support page the user can use to get help. 239 * 240 * @return The URL to the support page. 241 */ 242 @SuppressWarnings("GuardedBy") // mLock already held in "call" (error prone). 243 public ListenableFuture<String> getSupportUrl() { 244 return call(() -> asInterface(getService()).getSupportUrl()); 245 } 246 } 247