First part of the Consent per API implementation. ConsentManager
getConsent / setConsent + refactor of BackgroundJobManager (could be a
different CL though, but wanted to keep it together as everyone gets the
context why it has to be changed - I can get better feedback on the
functionality)

Bug: 254351205
Bug: 254351131
Bug: 254350760
Fixes: 254352419
Test: atest
Change-Id: I1e07ec6687cd19b83d7d8ca4ac42fd8808c2a10f
diff --git a/adservices/apk/java/com/android/adservices/topics/TopicsService.java b/adservices/apk/java/com/android/adservices/topics/TopicsService.java
index 38e4854..014c3bb 100644
--- a/adservices/apk/java/com/android/adservices/topics/TopicsService.java
+++ b/adservices/apk/java/com/android/adservices/topics/TopicsService.java
@@ -31,6 +31,7 @@
 import com.android.adservices.service.common.AppImportanceFilter;
 import com.android.adservices.service.common.PackageChangedReceiver;
 import com.android.adservices.service.common.Throttler;
+import com.android.adservices.service.consent.AdServicesApiType;
 import com.android.adservices.service.consent.ConsentManager;
 import com.android.adservices.service.stats.AdServicesLoggerImpl;
 import com.android.adservices.service.stats.Clock;
@@ -92,7 +93,11 @@
     }
 
     private boolean hasUserConsent() {
-        return ConsentManager.getInstance(this).getConsent().isGiven();
+        if (FlagsFactory.getFlags().getGaUxFeatureEnabled()) {
+            return ConsentManager.getInstance(this).getConsent(AdServicesApiType.TOPICS).isGiven();
+        } else {
+            return ConsentManager.getInstance(this).getConsent().isGiven();
+        }
     }
 
     @Override
diff --git a/adservices/apk/unittest/src/com/android/adservices/topics/TopicsServiceTest.java b/adservices/apk/unittest/src/com/android/adservices/topics/TopicsServiceTest.java
index b43d1c9..260a041 100644
--- a/adservices/apk/unittest/src/com/android/adservices/topics/TopicsServiceTest.java
+++ b/adservices/apk/unittest/src/com/android/adservices/topics/TopicsServiceTest.java
@@ -38,6 +38,7 @@
 import com.android.adservices.service.common.AppImportanceFilter;
 import com.android.adservices.service.common.PackageChangedReceiver;
 import com.android.adservices.service.consent.AdServicesApiConsent;
+import com.android.adservices.service.consent.AdServicesApiType;
 import com.android.adservices.service.consent.ConsentManager;
 import com.android.adservices.service.stats.AdServicesLoggerImpl;
 import com.android.adservices.service.topics.EpochJobService;
@@ -89,6 +90,7 @@
         try {
             // Killswitch is off.
             doReturn(false).when(mMockFlags).getTopicsKillSwitch();
+            doReturn(false).when(mMockFlags).getGaUxFeatureEnabled();
 
             // Mock static method FlagsFactory.getFlags() to return Mock Flags.
             ExtendedMockito.doReturn(mMockFlags).when(FlagsFactory::getFlags);
@@ -125,6 +127,76 @@
             spyTopicsService.onCreate();
             IBinder binder = spyTopicsService.onBind(getIntentForTopicsService());
             assertNotNull(binder);
+            verifyMethodExecutionOnUserConsentGiven();
+        } finally {
+            session.finishMocking();
+        }
+    }
+
+    /**
+     * Test whether the {@link TopicsService} works properly with the GA UX feature flag on. It
+     * changes the behaviour of the consent - it's retrieved by a different method and it's per API.
+     */
+    @Test
+    public void testBindableTopicsService_killswitchOffGaUxFeatureFlagOn() {
+        // Start a mockitoSession to mock static method
+        MockitoSession session =
+                ExtendedMockito.mockitoSession()
+                        .spyStatic(FlagsFactory.class)
+                        .spyStatic(TopicsWorker.class)
+                        .spyStatic(ConsentManager.class)
+                        .spyStatic(AdServicesLoggerImpl.class)
+                        .spyStatic(MaintenanceJobService.class)
+                        .spyStatic(EpochJobService.class)
+                        .spyStatic(MddJobService.class)
+                        .spyStatic(EnrollmentDao.class)
+                        .spyStatic(AppImportanceFilter.class)
+                        .spyStatic(PackageChangedReceiver.class)
+                        .startMocking();
+
+        try {
+            // Killswitch is off.
+            doReturn(false).when(mMockFlags).getTopicsKillSwitch();
+            doReturn(true).when(mMockFlags).getGaUxFeatureEnabled();
+
+            // Mock static method FlagsFactory.getFlags() to return Mock Flags.
+            ExtendedMockito.doReturn(mMockFlags).when(FlagsFactory::getFlags);
+
+            ExtendedMockito.doReturn(mMockTopicsWorker)
+                    .when(() -> TopicsWorker.getInstance(any(Context.class)));
+
+            TopicsService spyTopicsService = spy(new TopicsService());
+            ExtendedMockito.doReturn(mMockConsentManager)
+                    .when(() -> ConsentManager.getInstance(any(Context.class)));
+            doReturn(true).when(mMockAdServicesApiConsent).isGiven();
+            doReturn(mMockAdServicesApiConsent)
+                    .when(mMockConsentManager)
+                    .getConsent(AdServicesApiType.TOPICS);
+
+            ExtendedMockito.doReturn(true)
+                    .when(() -> PackageChangedReceiver.enableReceiver(any(Context.class)));
+            ExtendedMockito.doReturn(true)
+                    .when(
+                            () ->
+                                    MaintenanceJobService.scheduleIfNeeded(
+                                            any(Context.class), eq(false)));
+            ExtendedMockito.doReturn(true)
+                    .when(() -> EpochJobService.scheduleIfNeeded(any(Context.class), eq(false)));
+            ExtendedMockito.doReturn(true)
+                    .when(() -> MddJobService.scheduleIfNeeded(any(Context.class), eq(false)));
+
+            ExtendedMockito.doReturn(mMockEnrollmentDao)
+                    .when(() -> EnrollmentDao.getInstance(any(Context.class)));
+            ExtendedMockito.doReturn(mMockAppImportanceFilter)
+                    .when(
+                            () ->
+                                    AppImportanceFilter.create(
+                                            any(Context.class), anyInt(), any(Supplier.class)));
+
+            spyTopicsService.onCreate();
+            IBinder binder = spyTopicsService.onBind(getIntentForTopicsService());
+            assertNotNull(binder);
+            verifyMethodExecutionOnUserConsentGiven();
         } finally {
             session.finishMocking();
         }
@@ -155,4 +227,13 @@
     private Intent getIntentForTopicsService() {
         return new Intent(ApplicationProvider.getApplicationContext(), TopicsService.class);
     }
+
+    private void verifyMethodExecutionOnUserConsentGiven() {
+        ExtendedMockito.verify(() -> PackageChangedReceiver.enableReceiver(any(Context.class)));
+        ExtendedMockito.verify(
+                () -> MaintenanceJobService.scheduleIfNeeded(any(Context.class), eq(false)));
+        ExtendedMockito.verify(
+                () -> EpochJobService.scheduleIfNeeded(any(Context.class), eq(false)));
+        ExtendedMockito.verify(() -> MddJobService.scheduleIfNeeded(any(Context.class), eq(false)));
+    }
 }
diff --git a/adservices/service-core/java/com/android/adservices/service/common/BackgroundJobsManager.java b/adservices/service-core/java/com/android/adservices/service/common/BackgroundJobsManager.java
index 04e5907..f301cd5 100644
--- a/adservices/service-core/java/com/android/adservices/service/common/BackgroundJobsManager.java
+++ b/adservices/service-core/java/com/android/adservices/service/common/BackgroundJobsManager.java
@@ -44,20 +44,58 @@
      * @param context application context.
      */
     public static void scheduleAllBackgroundJobs(@NonNull Context context) {
-        // We will schedule MaintenanceJobService as long as either kill switch is off
-        if (!FlagsFactory.getFlags().getTopicsKillSwitch()
-                || !FlagsFactory.getFlags().getFledgeSelectAdsKillSwitch()) {
+        scheduleFledgeBackgroundJobs(context);
+
+        scheduleTopicsBackgroundJobs(context);
+
+        scheduleMddBackgroundJobs(context);
+
+        scheduleMeasurementBackgroundJobs(context);
+    }
+
+    /**
+     * Tries to schedule all the Fledge related background jobs if the FledgeSelectAdsKillSwitch is
+     * disabled.
+     *
+     * @param context application context.
+     */
+    public static void scheduleFledgeBackgroundJobs(@NonNull Context context) {
+        if (!FlagsFactory.getFlags().getFledgeSelectAdsKillSwitch()) {
             MaintenanceJobService.scheduleIfNeeded(context, false);
         }
+    }
 
+    /**
+     * Tries to schedule all the Topics related background jobs if the TopicsKillSwitch is disabled.
+     *
+     * @param context application context.
+     */
+    public static void scheduleTopicsBackgroundJobs(@NonNull Context context) {
         if (!FlagsFactory.getFlags().getTopicsKillSwitch()) {
             EpochJobService.scheduleIfNeeded(context, false);
+            MaintenanceJobService.scheduleIfNeeded(context, false);
         }
+    }
 
+    /**
+     * Tries to schedule all the Mdd related background jobs if the MddBackgroundTaskKillSwitch is
+     * disabled.
+     *
+     * @param context application context.
+     */
+    public static void scheduleMddBackgroundJobs(@NonNull Context context) {
         if (!FlagsFactory.getFlags().getMddBackgroundTaskKillSwitch()) {
             MddJobService.scheduleIfNeeded(context, /* forceSchedule */ false);
         }
+    }
 
+    /**
+     * Tries to schedule all the Measurement related background jobs if the MeasurementKillSwitch is
+     * disabled.
+     *
+     * @param context application context.
+     */
+    public static void scheduleMeasurementBackgroundJobs(@NonNull Context context) {
         if (!FlagsFactory.getFlags().getMeasurementKillSwitch()) {
             AggregateReportingJobService.scheduleIfNeeded(context, false);
             AggregateFallbackReportingJobService.scheduleIfNeeded(context, false);
@@ -78,8 +116,26 @@
     public static void unscheduleAllBackgroundJobs(@NonNull JobScheduler jobScheduler) {
         Objects.requireNonNull(jobScheduler);
 
-        jobScheduler.cancel(AdServicesConfig.MAINTENANCE_JOB_ID);
-        jobScheduler.cancel(AdServicesConfig.TOPICS_EPOCH_JOB_ID);
+        unscheduleTopicsBackgroundJobs(jobScheduler);
+
+        unscheduleMeasurementBackgroundJobs(jobScheduler);
+
+        unscheduleFledgeBackgroundJobs(jobScheduler);
+
+        unscheduleMaintenanceJobs(jobScheduler);
+
+        jobScheduler.cancel(AdServicesConfig.CONSENT_NOTIFICATION_JOB_ID);
+
+        MddJobService.unscheduleAllJobs(jobScheduler);
+    }
+
+    /**
+     * Tries to unschedule all the Measurement related background jobs.
+     *
+     * @param jobScheduler Job scheduler to cancel the jobs.
+     */
+    public static void unscheduleMeasurementBackgroundJobs(@NonNull JobScheduler jobScheduler) {
+        Objects.requireNonNull(jobScheduler);
 
         jobScheduler.cancel(AdServicesConfig.MEASUREMENT_EVENT_MAIN_REPORTING_JOB_ID);
         jobScheduler.cancel(AdServicesConfig.MEASUREMENT_DELETE_EXPIRED_JOB_ID);
@@ -89,11 +145,38 @@
         jobScheduler.cancel(AdServicesConfig.MEASUREMENT_AGGREGATE_MAIN_REPORTING_JOB_ID);
         jobScheduler.cancel(AdServicesConfig.MEASUREMENT_AGGREGATE_FALLBACK_REPORTING_JOB_ID);
         jobScheduler.cancel(AdServicesConfig.ASYNC_REGISTRATION_QUEUE_JOB_ID);
+    }
+
+    /**
+     * Tries to unschedule all the Topics related background jobs.
+     *
+     * @param jobScheduler Job scheduler to cancel the jobs.
+     */
+    public static void unscheduleTopicsBackgroundJobs(@NonNull JobScheduler jobScheduler) {
+        Objects.requireNonNull(jobScheduler);
+
+        jobScheduler.cancel(AdServicesConfig.TOPICS_EPOCH_JOB_ID);
+    }
+
+    /**
+     * Tries to unschedule all the Fledge related background jobs.
+     *
+     * @param jobScheduler Job scheduler to cancel the jobs.
+     */
+    public static void unscheduleFledgeBackgroundJobs(@NonNull JobScheduler jobScheduler) {
+        Objects.requireNonNull(jobScheduler);
 
         jobScheduler.cancel(AdServicesConfig.FLEDGE_BACKGROUND_FETCH_JOB_ID);
+    }
 
-        jobScheduler.cancel(AdServicesConfig.CONSENT_NOTIFICATION_JOB_ID);
+    /**
+     * Tries to unschedule all the maintenance background jobs.
+     *
+     * @param jobScheduler Job scheduler to cancel the jobs.
+     */
+    public static void unscheduleMaintenanceJobs(@NonNull JobScheduler jobScheduler) {
+        Objects.requireNonNull(jobScheduler);
 
-        MddJobService.unscheduleAllJobs(jobScheduler);
+        jobScheduler.cancel(AdServicesConfig.MAINTENANCE_JOB_ID);
     }
 }
diff --git a/adservices/service-core/java/com/android/adservices/service/consent/ConsentManager.java b/adservices/service-core/java/com/android/adservices/service/consent/ConsentManager.java
index c932e6c..bbbe7e6 100644
--- a/adservices/service-core/java/com/android/adservices/service/consent/ConsentManager.java
+++ b/adservices/service-core/java/com/android/adservices/service/consent/ConsentManager.java
@@ -63,6 +63,7 @@
     private static final String NOTIFICATION_DISPLAYED_ONCE = "NOTIFICATION-DISPLAYED-ONCE";
     private static final String CONSENT_ALREADY_INITIALIZED_KEY = "CONSENT-ALREADY-INITIALIZED";
     private static final String CONSENT_KEY = "CONSENT";
+    private static final String CONSENT_PER_API_FORMAT = "CONSENT-FOR-%s-API";
     private static final String ERROR_MESSAGE_DATASTORE_IO_EXCEPTION_WHILE_SET_CONTENT =
             "setConsent method failed due to IOException thrown by Datastore.";
     private static final int STORAGE_VERSION = 1;
@@ -213,6 +214,26 @@
     }
 
     /**
+     * Retrieves the consent per API.
+     *
+     * @param apiType apiType for which the consent should be provided
+     * @return {@link AdServicesApiConsent} providing information whether the consent was given or
+     *     revoked.
+     */
+    public AdServicesApiConsent getConsent(AdServicesApiType apiType) {
+        if (mFlags.getConsentManagerDebugMode()) {
+            return AdServicesApiConsent.GIVEN;
+        }
+        try {
+            init(apiType);
+            return AdServicesApiConsent.getConsent(mDatastore.get(getConsentKeyPerApi(apiType)));
+        } catch (NullPointerException | IllegalArgumentException | IOException e) {
+            LogUtil.e(e, ERROR_MESSAGE_DATASTORE_EXCEPTION_WHILE_GET_CONTENT);
+            return AdServicesApiConsent.REVOKED;
+        }
+    }
+
+    /**
      * Proxy call to {@link TopicsWorker} to get {@link ImmutableList} of {@link Topic}s which could
      * be returned to the {@link TopicsWorker} clients.
      *
@@ -451,6 +472,11 @@
         mDatastore.put(CONSENT_KEY, state.isGiven());
     }
 
+    private void setConsent(AdServicesApiConsent state, AdServicesApiType apiType)
+            throws IOException {
+        mDatastore.put(getConsentKeyPerApi(apiType), state.isGiven());
+    }
+
     void init() throws IOException {
         initializeStorage();
         if (mDatastore.get(CONSENT_ALREADY_INITIALIZED_KEY) == null
@@ -460,6 +486,33 @@
         }
     }
 
+    /*
+    Method to initialize the datastore and the ConsentManager itself, but also prepare the
+    consent-per-api if upgrade happens. If that's the case, there is a chance that the aggregated
+    consent was already initialized (set to GIVEN or REVOKED) and the consents-per-api weren't.
+    Init method detects such situations and update the consents accordingly.
+     */
+    void init(AdServicesApiType apiType) throws IOException {
+        init();
+        Boolean aggregatedConsent = mDatastore.get(CONSENT_KEY);
+        // if consent wasn't initialized at all, noop
+        if (aggregatedConsent == null) {
+            return;
+        }
+
+        String consentPerApiKey = getConsentKeyPerApi(apiType);
+        // if consent per api was already initialized, noop
+        if (mDatastore.get(consentPerApiKey) != null) {
+            return;
+        }
+
+        mDatastore.put(consentPerApiKey, aggregatedConsent);
+    }
+
+    private String getConsentKeyPerApi(AdServicesApiType apiType) {
+        return String.format(CONSENT_PER_API_FORMAT, apiType.name());
+    }
+
     private void initializeStorage() throws IOException {
         if (!mInitialized) {
             synchronized (ConsentManager.class) {
diff --git a/adservices/service-core/java/com/android/adservices/service/topics/TopicsServiceImpl.java b/adservices/service-core/java/com/android/adservices/service/topics/TopicsServiceImpl.java
index e66206f..f15585624 100644
--- a/adservices/service-core/java/com/android/adservices/service/topics/TopicsServiceImpl.java
+++ b/adservices/service-core/java/com/android/adservices/service/topics/TopicsServiceImpl.java
@@ -53,6 +53,7 @@
 import com.android.adservices.service.common.SdkRuntimeUtil;
 import com.android.adservices.service.common.Throttler;
 import com.android.adservices.service.consent.AdServicesApiConsent;
+import com.android.adservices.service.consent.AdServicesApiType;
 import com.android.adservices.service.consent.ConsentManager;
 import com.android.adservices.service.enrollment.EnrollmentData;
 import com.android.adservices.service.stats.AdServicesLogger;
@@ -269,7 +270,12 @@
             return false;
         }
 
-        AdServicesApiConsent userConsent = mConsentManager.getConsent();
+        AdServicesApiConsent userConsent;
+        if (mFlags.getGaUxFeatureEnabled()) {
+            userConsent = mConsentManager.getConsent(AdServicesApiType.TOPICS);
+        } else {
+            userConsent = mConsentManager.getConsent();
+        }
         if (!userConsent.isGiven()) {
             invokeCallbackWithStatus(
                     callback, STATUS_USER_CONSENT_REVOKED, "User consent revoked.");
diff --git a/adservices/tests/unittest/service-core/src/com/android/adservices/service/common/BackgroundJobsManagerTest.java b/adservices/tests/unittest/service-core/src/com/android/adservices/service/common/BackgroundJobsManagerTest.java
index 3cbe1ea..e17a811 100644
--- a/adservices/tests/unittest/service-core/src/com/android/adservices/service/common/BackgroundJobsManagerTest.java
+++ b/adservices/tests/unittest/service-core/src/com/android/adservices/service/common/BackgroundJobsManagerTest.java
@@ -89,7 +89,7 @@
 
                     assertMeasurementJobsScheduled(1);
                     assertTopicsJobsScheduled(1);
-                    assertMaintenanceJobScheduled(1);
+                    assertMaintenanceJobScheduled(2);
                     assertMddJobsScheduled(1);
                 });
     }
@@ -109,7 +109,7 @@
 
                     assertMeasurementJobsScheduled(0);
                     assertTopicsJobsScheduled(1);
-                    assertMaintenanceJobScheduled(1);
+                    assertMaintenanceJobScheduled(2);
                     assertMddJobsScheduled(1);
                 });
     }
@@ -149,7 +149,7 @@
 
                     assertMeasurementJobsScheduled(1);
                     assertTopicsJobsScheduled(1);
-                    assertMaintenanceJobScheduled(1);
+                    assertMaintenanceJobScheduled(2);
                     assertMddJobsScheduled(0);
                 });
     }
@@ -195,6 +195,98 @@
     }
 
     @Test
+    public void testScheduleMeasurementBackgroundJobs_measurementKillSwitchOn() throws Exception {
+        runWithMocks(
+                () -> {
+                    ExtendedMockito.doReturn(true).when(mMockFlags).getMeasurementKillSwitch();
+
+                    BackgroundJobsManager.scheduleMeasurementBackgroundJobs(
+                            Mockito.mock(Context.class));
+
+                    assertMeasurementJobsScheduled(0);
+                    assertTopicsJobsScheduled(0);
+                    assertMaintenanceJobScheduled(0);
+                    assertMddJobsScheduled(0);
+                });
+    }
+
+    @Test
+    public void testScheduleMeasurementBackgroundJobs_measurementKillSwitchOff() throws Exception {
+        runWithMocks(
+                () -> {
+                    ExtendedMockito.doReturn(false).when(mMockFlags).getMeasurementKillSwitch();
+
+                    BackgroundJobsManager.scheduleMeasurementBackgroundJobs(
+                            Mockito.mock(Context.class));
+
+                    assertMeasurementJobsScheduled(1);
+                    assertTopicsJobsScheduled(0);
+                    assertMaintenanceJobScheduled(0);
+                    assertMddJobsScheduled(0);
+                });
+    }
+
+    @Test
+    public void testScheduleTopicsBackgroundJobs_topicsKillSwitchOn() throws Exception {
+        runWithMocks(
+                () -> {
+                    ExtendedMockito.doReturn(true).when(mMockFlags).getTopicsKillSwitch();
+
+                    BackgroundJobsManager.scheduleTopicsBackgroundJobs(Mockito.mock(Context.class));
+
+                    assertMeasurementJobsScheduled(0);
+                    assertTopicsJobsScheduled(0);
+                    assertMaintenanceJobScheduled(0);
+                    assertMddJobsScheduled(0);
+                });
+    }
+
+    @Test
+    public void testScheduleTopicsBackgroundJobs_topicsKillSwitchOff() throws Exception {
+        runWithMocks(
+                () -> {
+                    ExtendedMockito.doReturn(false).when(mMockFlags).getTopicsKillSwitch();
+
+                    BackgroundJobsManager.scheduleTopicsBackgroundJobs(Mockito.mock(Context.class));
+
+                    assertMeasurementJobsScheduled(0);
+                    assertTopicsJobsScheduled(1);
+                    assertMaintenanceJobScheduled(1);
+                    assertMddJobsScheduled(0);
+                });
+    }
+
+    @Test
+    public void testScheduleFledgeBackgroundJobs_selectAdsKillSwitchOn() throws Exception {
+        runWithMocks(
+                () -> {
+                    ExtendedMockito.doReturn(true).when(mMockFlags).getFledgeSelectAdsKillSwitch();
+
+                    BackgroundJobsManager.scheduleFledgeBackgroundJobs(Mockito.mock(Context.class));
+
+                    assertMeasurementJobsScheduled(0);
+                    assertTopicsJobsScheduled(0);
+                    assertMaintenanceJobScheduled(0);
+                    assertMddJobsScheduled(0);
+                });
+    }
+
+    @Test
+    public void testScheduleFledgeBackgroundJobs_selectAdsKillSwitchOff() throws Exception {
+        runWithMocks(
+                () -> {
+                    ExtendedMockito.doReturn(false).when(mMockFlags).getFledgeSelectAdsKillSwitch();
+
+                    BackgroundJobsManager.scheduleFledgeBackgroundJobs(Mockito.mock(Context.class));
+
+                    assertMeasurementJobsScheduled(0);
+                    assertTopicsJobsScheduled(0);
+                    assertMaintenanceJobScheduled(1);
+                    assertMddJobsScheduled(0);
+                });
+    }
+
+    @Test
     public void testUnscheduleAllBackgroundJobs() {
         // Execute
         JobScheduler mockJobScheduler = mock(JobScheduler.class);
diff --git a/adservices/tests/unittest/service-core/src/com/android/adservices/service/consent/ConsentManagerTest.java b/adservices/tests/unittest/service-core/src/com/android/adservices/service/consent/ConsentManagerTest.java
index 7433da0..920cd7c 100644
--- a/adservices/tests/unittest/service-core/src/com/android/adservices/service/consent/ConsentManagerTest.java
+++ b/adservices/tests/unittest/service-core/src/com/android/adservices/service/consent/ConsentManagerTest.java
@@ -237,7 +237,8 @@
                 () -> EpochJobService.scheduleIfNeeded(any(Context.class), eq(false)));
         ExtendedMockito.verify(() -> MddJobService.scheduleIfNeeded(any(Context.class), eq(false)));
         ExtendedMockito.verify(
-                () -> MaintenanceJobService.scheduleIfNeeded(any(Context.class), eq(false)));
+                () -> MaintenanceJobService.scheduleIfNeeded(any(Context.class), eq(false)),
+                times(2));
         ExtendedMockito.verify(
                 () -> AggregateReportingJobService.scheduleIfNeeded(any(Context.class), eq(false)));
         ExtendedMockito.verify(
@@ -904,4 +905,29 @@
         verify(mAdServicesLoggerImpl, times(1)).logUIStats(any());
         verify(mAdServicesLoggerImpl, times(1)).logUIStats(expectedUIStats);
     }
+
+    @Test
+    public void testGetInitializedConsentPerApi_aggregatedConsentInitializedAndGiven() {
+        mConsentManager.enable(mContextSpy);
+
+        assertTrue(mConsentManager.getConsent(AdServicesApiType.TOPICS).isGiven());
+        assertTrue(mConsentManager.getConsent(AdServicesApiType.MEASUREMENTS).isGiven());
+        assertTrue(mConsentManager.getConsent(AdServicesApiType.FLEDGE).isGiven());
+    }
+
+    @Test
+    public void testGetInitializedConsentPerApi_aggregatedConsentInitializedAndRevoked() {
+        mConsentManager.disable(mContextSpy);
+
+        assertFalse(mConsentManager.getConsent(AdServicesApiType.TOPICS).isGiven());
+        assertFalse(mConsentManager.getConsent(AdServicesApiType.MEASUREMENTS).isGiven());
+        assertFalse(mConsentManager.getConsent(AdServicesApiType.FLEDGE).isGiven());
+    }
+
+    @Test
+    public void testGetInitializedConsentPerApi_aggregatedConsentNotInitialized() {
+        assertFalse(mConsentManager.getConsent(AdServicesApiType.TOPICS).isGiven());
+        assertFalse(mConsentManager.getConsent(AdServicesApiType.MEASUREMENTS).isGiven());
+        assertFalse(mConsentManager.getConsent(AdServicesApiType.FLEDGE).isGiven());
+    }
 }
diff --git a/adservices/tests/unittest/service-core/src/com/android/adservices/service/topics/TopicsServiceImplTest.java b/adservices/tests/unittest/service-core/src/com/android/adservices/service/topics/TopicsServiceImplTest.java
index d679017..fc3429b 100644
--- a/adservices/tests/unittest/service-core/src/com/android/adservices/service/topics/TopicsServiceImplTest.java
+++ b/adservices/tests/unittest/service-core/src/com/android/adservices/service/topics/TopicsServiceImplTest.java
@@ -67,6 +67,7 @@
 import com.android.adservices.service.common.AppManifestConfigHelper;
 import com.android.adservices.service.common.Throttler;
 import com.android.adservices.service.consent.AdServicesApiConsent;
+import com.android.adservices.service.consent.AdServicesApiType;
 import com.android.adservices.service.consent.ConsentManager;
 import com.android.adservices.service.enrollment.EnrollmentData;
 import com.android.adservices.service.stats.AdServicesLogger;
@@ -182,6 +183,8 @@
 
         DbTestUtil.deleteTable(TopicsTables.BlockedTopicsContract.TABLE);
         when(mConsentManager.getConsent()).thenReturn(AdServicesApiConsent.GIVEN);
+        when(mConsentManager.getConsent(AdServicesApiType.TOPICS))
+                .thenReturn(AdServicesApiConsent.GIVEN);
         when(mMockSdkContext.getPackageManager()).thenReturn(mPackageManager);
         when(mPackageManager.getPackageUid(TEST_APP_PACKAGE_NAME, 0)).thenReturn(Process.myUid());
 
@@ -219,12 +222,22 @@
 
     @Test
     public void checkNoUserConsent() throws InterruptedException {
+        when(mMockFlags.getGaUxFeatureEnabled()).thenReturn(false);
         when(Binder.getCallingUidOrThrow()).thenReturn(Process.myUid());
         when(mConsentManager.getConsent()).thenReturn(AdServicesApiConsent.REVOKED);
         invokeGetTopicsAndVerifyError(mContext, STATUS_USER_CONSENT_REVOKED);
     }
 
     @Test
+    public void checkNoUserConsent_gaUxFeatureEnabled() throws InterruptedException {
+        when(mMockFlags.getGaUxFeatureEnabled()).thenReturn(true);
+        when(Binder.getCallingUidOrThrow()).thenReturn(Process.myUid());
+        when(mConsentManager.getConsent(AdServicesApiType.TOPICS))
+                .thenReturn(AdServicesApiConsent.REVOKED);
+        invokeGetTopicsAndVerifyError(mContext, STATUS_USER_CONSENT_REVOKED);
+    }
+
+    @Test
     public void checkSignatureAllowList_successAllowList() throws Exception {
         when(Binder.getCallingUidOrThrow()).thenReturn(Process.myUid());
         mTopicsServiceImpl = createTestTopicsServiceImplInstance();