/* * Copyright (C) 2022 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package android.adservices.customaudience; import static android.adservices.common.AdServicesPermissions.ACCESS_ADSERVICES_CUSTOM_AUDIENCE; import android.adservices.common.AdServicesStatusUtils; import android.adservices.common.FledgeErrorResponse; import android.annotation.CallbackExecutor; import android.annotation.NonNull; import android.annotation.RequiresPermission; import android.os.Build; import android.os.OutcomeReceiver; import android.os.RemoteException; import androidx.annotation.RequiresApi; import com.android.adservices.LoggerFactory; import java.util.Objects; import java.util.concurrent.Executor; /** TestCustomAudienceManager provides APIs for app and ad-SDKs to test custom audiences. */ @RequiresApi(Build.VERSION_CODES.S) public class TestCustomAudienceManager { private static final LoggerFactory.Logger sLogger = LoggerFactory.getFledgeLogger(); private final CustomAudienceManager mCustomAudienceManager; private final String mCallerPackageName; TestCustomAudienceManager( @NonNull CustomAudienceManager customAudienceManager, @NonNull String callerPackageName) { Objects.requireNonNull(customAudienceManager); Objects.requireNonNull(callerPackageName); mCustomAudienceManager = customAudienceManager; mCallerPackageName = callerPackageName; } /** * Overrides the Custom Audience API to avoid fetching data from remote servers and use the data * provided in {@link AddCustomAudienceOverrideRequest} instead. The {@link * AddCustomAudienceOverrideRequest} is provided by the Ads SDK. * *

This method is intended to be used for end-to-end testing. This API is enabled only for * apps in debug mode with developer options enabled. * *

This call will fail silently if the {@code owner} in the {@code request} is not the * calling app's package name. * * @throws IllegalStateException if this API is not enabled for the caller *

The receiver either returns a {@code void} for a successful run, or an {@link * Exception} indicates the error. */ @RequiresPermission(ACCESS_ADSERVICES_CUSTOM_AUDIENCE) public void overrideCustomAudienceRemoteInfo( @NonNull AddCustomAudienceOverrideRequest request, @NonNull @CallbackExecutor Executor executor, @NonNull OutcomeReceiver receiver) { Objects.requireNonNull(request); Objects.requireNonNull(executor); Objects.requireNonNull(receiver); try { final ICustomAudienceService service = mCustomAudienceManager.getService(); service.overrideCustomAudienceRemoteInfo( mCallerPackageName, request.getBuyer(), request.getName(), request.getBiddingLogicJs(), request.getBiddingLogicJsVersion(), request.getTrustedBiddingSignals(), new CustomAudienceOverrideCallback.Stub() { @Override public void onSuccess() { executor.execute(() -> receiver.onResult(new Object())); } @Override public void onFailure(FledgeErrorResponse failureParcel) { executor.execute( () -> receiver.onError( AdServicesStatusUtils.asException( failureParcel))); } }); } catch (RemoteException e) { sLogger.e(e, "Exception"); receiver.onError(new IllegalStateException("Internal Error!", e)); } } /** * Removes an override in th Custom Audience API with associated the data in {@link * RemoveCustomAudienceOverrideRequest}. * *

This method is intended to be used for end-to-end testing. This API is enabled only for * apps in debug mode with developer options enabled. * * @throws IllegalStateException if this API is not enabled for the caller *

The {@link RemoveCustomAudienceOverrideRequest} is provided by the Ads SDK. The * receiver either returns a {@code void} for a successful run, or an {@link Exception} * indicates the error. */ @RequiresPermission(ACCESS_ADSERVICES_CUSTOM_AUDIENCE) public void removeCustomAudienceRemoteInfoOverride( @NonNull RemoveCustomAudienceOverrideRequest request, @NonNull @CallbackExecutor Executor executor, @NonNull OutcomeReceiver receiver) { Objects.requireNonNull(request); Objects.requireNonNull(executor); Objects.requireNonNull(receiver); try { final ICustomAudienceService service = mCustomAudienceManager.getService(); service.removeCustomAudienceRemoteInfoOverride( mCallerPackageName, request.getBuyer(), request.getName(), new CustomAudienceOverrideCallback.Stub() { @Override public void onSuccess() { executor.execute(() -> receiver.onResult(new Object())); } @Override public void onFailure(FledgeErrorResponse failureParcel) { executor.execute( () -> receiver.onError( AdServicesStatusUtils.asException( failureParcel))); } }); } catch (RemoteException e) { sLogger.e(e, "Exception"); receiver.onError(new IllegalStateException("Internal Error!", e)); } } /** * Removes all override data in the Custom Audience API. * *

This method is intended to be used for end-to-end testing. This API is enabled only for * apps in debug mode with developer options enabled. * * @throws IllegalStateException if this API is not enabled for the caller *

The receiver either returns a {@code void} for a successful run, or an {@link * Exception} indicates the error. */ @RequiresPermission(ACCESS_ADSERVICES_CUSTOM_AUDIENCE) public void resetAllCustomAudienceOverrides( @NonNull @CallbackExecutor Executor executor, @NonNull OutcomeReceiver receiver) { Objects.requireNonNull(executor); Objects.requireNonNull(receiver); try { final ICustomAudienceService service = mCustomAudienceManager.getService(); service.resetAllCustomAudienceOverrides( new CustomAudienceOverrideCallback.Stub() { @Override public void onSuccess() { executor.execute(() -> receiver.onResult(new Object())); } @Override public void onFailure(FledgeErrorResponse failureParcel) { executor.execute( () -> receiver.onError( AdServicesStatusUtils.asException( failureParcel))); } }); } catch (RemoteException e) { sLogger.e(e, "Exception"); receiver.onError(new IllegalStateException("Internal Error!", e)); } } }