Add support for daily and monthly notification maximums

Create a slice purchase app response to indicate that the network boost
notification was shown and save the count to shared preferences.
Use LocalDate to clear the daily count every day and the monthly count
every month.
If the daily or monthly count was reached, return result throttled.

Test: atest TeleServiceTests, CarrierDefaultAppUnitTests
Test: manual verify throttled and reset
Bug: 248533515
Change-Id: If86debc3e7a3299ec5d83f04315df24673688678
diff --git a/tests/src/com/android/TestContext.java b/tests/src/com/android/TestContext.java
index 7c3a842..720d235 100644
--- a/tests/src/com/android/TestContext.java
+++ b/tests/src/com/android/TestContext.java
@@ -61,7 +61,11 @@
     @Mock ImsManager mMockImsManager;
     @Mock UserManager mMockUserManager;
 
-    private SparseArray<PersistableBundle> mCarrierConfigs = new SparseArray<>();
+    private final SparseArray<PersistableBundle> mCarrierConfigs = new SparseArray<>();
+
+    private Intent mIntent;
+
+    private BroadcastReceiver mReceiver;
 
     private final HashSet<String> mPermissionTable = new HashSet<>();
 
@@ -105,28 +109,42 @@
     }
 
     @Override
+    public void sendBroadcast(Intent intent) {
+        mIntent = intent;
+    }
+
+    @Override
     public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter) {
+        mReceiver = receiver;
         return null;
     }
 
     @Override
     public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter, int flags) {
+        mReceiver = receiver;
         return null;
     }
 
     @Override
     public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter,
             String broadcastPermission, Handler scheduler) {
+        mReceiver = receiver;
         return null;
     }
 
     @Override
     public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter,
             String broadcastPermission, Handler scheduler, int flags) {
+        mReceiver = receiver;
         return null;
     }
 
     @Override
+    public void unregisterReceiver(BroadcastReceiver receiver) {
+        mReceiver = null;
+    }
+
+    @Override
     public ContentResolver getContentResolver() {
         return null;
     }
@@ -134,22 +152,22 @@
     @Override
     public Object getSystemService(String name) {
         switch (name) {
-            case (Context.CARRIER_CONFIG_SERVICE) : {
+            case Context.CARRIER_CONFIG_SERVICE: {
                 return mMockCarrierConfigManager;
             }
-            case (Context.TELECOM_SERVICE) : {
+            case Context.TELECOM_SERVICE: {
                 return mMockTelecomManager;
             }
-            case (Context.TELEPHONY_SERVICE) : {
+            case Context.TELEPHONY_SERVICE: {
                 return mMockTelephonyManager;
             }
-            case (Context.TELEPHONY_SUBSCRIPTION_SERVICE) : {
+            case Context.TELEPHONY_SUBSCRIPTION_SERVICE: {
                 return mMockSubscriptionManager;
             }
-            case(Context.TELEPHONY_IMS_SERVICE) : {
+            case Context.TELEPHONY_IMS_SERVICE: {
                 return mMockImsManager;
             }
-            case(Context.USER_SERVICE) : {
+            case Context.USER_SERVICE: {
                 return mMockUserManager;
             }
         }
@@ -170,6 +188,9 @@
         if (serviceClass == SubscriptionManager.class) {
             return Context.TELEPHONY_SUBSCRIPTION_SERVICE;
         }
+        if (serviceClass == ImsManager.class) {
+            return Context.TELEPHONY_IMS_SERVICE;
+        }
         if (serviceClass == UserManager.class) {
             return Context.USER_SERVICE;
         }
@@ -252,6 +273,14 @@
         }
     }
 
+    public Intent getBroadcast() {
+        return mIntent;
+    }
+
+    public BroadcastReceiver getBroadcastReceiver() {
+        return mReceiver;
+    }
+
     private static void logd(String s) {
         Log.d(TAG, s);
     }
diff --git a/tests/src/com/android/phone/SlicePurchaseControllerTest.java b/tests/src/com/android/phone/slice/SlicePurchaseControllerTest.java
similarity index 75%
rename from tests/src/com/android/phone/SlicePurchaseControllerTest.java
rename to tests/src/com/android/phone/slice/SlicePurchaseControllerTest.java
index ebcf15d..e9e23f3 100644
--- a/tests/src/com/android/phone/SlicePurchaseControllerTest.java
+++ b/tests/src/com/android/phone/slice/SlicePurchaseControllerTest.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.phone;
+package com.android.phone.slice;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
@@ -26,15 +26,19 @@
 import static org.mockito.Mockito.anyInt;
 import static org.mockito.Mockito.anyString;
 import static org.mockito.Mockito.clearInvocations;
+import static org.mockito.Mockito.doAnswer;
 import static org.mockito.Mockito.doCallRealMethod;
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.eq;
+import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.verify;
 
+import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
+import android.content.SharedPreferences;
 import android.os.AsyncResult;
 import android.os.Handler;
 import android.os.HandlerThread;
@@ -53,38 +57,42 @@
 import com.android.TelephonyTestBase;
 import com.android.internal.telephony.CommandsInterface;
 import com.android.internal.telephony.Phone;
-import com.android.phone.slice.PremiumNetworkEntitlementApi;
-import com.android.phone.slice.PremiumNetworkEntitlementResponse;
-import com.android.phone.slice.SlicePurchaseController;
-import com.android.phone.slice.SlicePurchaseController.SlicePurchaseControllerBroadcastReceiver;
 
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
-import org.mockito.ArgumentCaptor;
 import org.mockito.Mock;
+import org.mockito.Mockito;
 
+import java.time.LocalDate;
 import java.util.Collections;
 import java.util.Map;
 
 @RunWith(AndroidJUnit4.class)
 public class SlicePurchaseControllerTest extends TelephonyTestBase {
     private static final String TAG = "SlicePurchaseControllerTest";
+    private static final String DAILY_NOTIFICATION_COUNT_KEY = "daily_notification_count0";
+    private static final String MONTHLY_NOTIFICATION_COUNT_KEY = "monthly_notification_count0";
+    private static final int YEAR = 2000;
+    private static final int MONTH = 6;
+    private static final int DATE = 1;
     private static final int PHONE_ID = 0;
+    private static final int DAILY_NOTIFICATION_MAX = 3;
+    private static final int MONTHLY_NOTIFICATION_MAX = 5;
     private static final long NOTIFICATION_TIMEOUT = 1000;
     private static final long PURCHASE_CONDITION_TIMEOUT = 2000;
     private static final long NETWORK_SETUP_TIMEOUT = 3000;
     private static final long THROTTLE_TIMEOUT = 4000;
 
     @Mock Phone mPhone;
-    @Mock Context mMockedContext;
     @Mock CarrierConfigManager mCarrierConfigManager;
     @Mock CommandsInterface mCommandsInterface;
     @Mock ServiceState mServiceState;
     @Mock PremiumNetworkEntitlementApi mPremiumNetworkEntitlementApi;
+    @Mock SharedPreferences mSharedPreferences;
+    @Mock SharedPreferences.Editor mEditor;
 
     private SlicePurchaseController mSlicePurchaseController;
-    private SlicePurchaseControllerBroadcastReceiver mBroadcastReceiver;
     private PersistableBundle mBundle;
     private PremiumNetworkEntitlementResponse mEntitlementResponse;
     private Handler mHandler;
@@ -106,17 +114,34 @@
         mTestableLooper = new TestableLooper(mHandler.getLooper());
 
         doReturn(PHONE_ID).when(mPhone).getPhoneId();
-        doReturn(mMockedContext).when(mPhone).getContext();
+        doReturn(mContext).when(mPhone).getContext();
         doReturn(mServiceState).when(mPhone).getServiceState();
         mPhone.mCi = mCommandsInterface;
 
-        doReturn(Context.CARRIER_CONFIG_SERVICE).when(mMockedContext)
-                .getSystemServiceName(eq(CarrierConfigManager.class));
-        doReturn(mCarrierConfigManager).when(mMockedContext)
-                .getSystemService(eq(Context.CARRIER_CONFIG_SERVICE));
+        doReturn(mCarrierConfigManager).when(mContext)
+                .getSystemService(Context.CARRIER_CONFIG_SERVICE);
         mBundle = new PersistableBundle();
+        mBundle.putInt(
+                CarrierConfigManager.KEY_PREMIUM_CAPABILITY_MAXIMUM_DAILY_NOTIFICATION_COUNT_INT,
+                DAILY_NOTIFICATION_MAX);
+        mBundle.putInt(
+                CarrierConfigManager.KEY_PREMIUM_CAPABILITY_MAXIMUM_MONTHLY_NOTIFICATION_COUNT_INT,
+                MONTHLY_NOTIFICATION_MAX);
         doReturn(mBundle).when(mCarrierConfigManager).getConfigForSubId(anyInt());
 
+        doReturn(mSharedPreferences).when(mContext).getSharedPreferences(anyString(), anyInt());
+        doReturn(mEditor).when(mSharedPreferences).edit();
+        doAnswer(invocation -> {
+            doReturn(invocation.getArgument(1)).when(mSharedPreferences)
+                    .getInt(eq(invocation.getArgument(0)), anyInt());
+            return null;
+        }).when(mEditor).putInt(anyString(), anyInt());
+        doAnswer(invocation -> {
+            doReturn(invocation.getArgument(1)).when(mSharedPreferences)
+                    .getString(eq(invocation.getArgument(0)), anyString());
+            return null;
+        }).when(mEditor).putString(anyString(), anyString());
+
         // create a spy to mock final PendingIntent methods
         SlicePurchaseController slicePurchaseController =
                 new SlicePurchaseController(mPhone, mHandler.getLooper());
@@ -159,7 +184,6 @@
                 new int[]{TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY});
         mBundle.putString(CarrierConfigManager.KEY_PREMIUM_CAPABILITY_PURCHASE_URL_STRING,
                 SlicePurchaseController.SLICE_PURCHASE_TEST_FILE);
-        doReturn(mBundle).when(mCarrierConfigManager).getConfigForSubId(anyInt());
         doReturn(SubscriptionManager.getDefaultDataSubscriptionId()).when(mPhone).getSubId();
 
         // retry to verify available
@@ -188,19 +212,65 @@
         };
         for (String url : invalidUrls) {
             mBundle.putString(CarrierConfigManager.KEY_PREMIUM_CAPABILITY_PURCHASE_URL_STRING, url);
-            doReturn(mBundle).when(mCarrierConfigManager).getConfigForSubId(anyInt());
             assertFalse(mSlicePurchaseController.isPremiumCapabilityAvailableForPurchase(
                     TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY));
         }
 
         mBundle.putString(CarrierConfigManager.KEY_PREMIUM_CAPABILITY_PURCHASE_URL_STRING,
                 SlicePurchaseController.SLICE_PURCHASE_TEST_FILE);
-        doReturn(mBundle).when(mCarrierConfigManager).getConfigForSubId(anyInt());
         assertTrue(mSlicePurchaseController.isPremiumCapabilityAvailableForPurchase(
                 TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY));
     }
 
     @Test
+    public void testUpdateNotificationCounts() {
+        mSlicePurchaseController.setLocalDate(LocalDate.of(YEAR, MONTH, DATE));
+        mSlicePurchaseController.updateNotificationCounts();
+
+        // change only date, month and year remain the same
+        Mockito.clearInvocations(mEditor);
+        mSlicePurchaseController.setLocalDate(LocalDate.of(YEAR, MONTH, DATE + 1));
+        mSlicePurchaseController.updateNotificationCounts();
+        verify(mEditor).putInt(eq(DAILY_NOTIFICATION_COUNT_KEY), eq(0));
+        verify(mEditor, never()).putInt(eq(MONTHLY_NOTIFICATION_COUNT_KEY), eq(0));
+
+        // change only month, date and year remain the same
+        Mockito.clearInvocations(mEditor);
+        mSlicePurchaseController.setLocalDate(LocalDate.of(YEAR, MONTH + 1, DATE + 1));
+        mSlicePurchaseController.updateNotificationCounts();
+        verify(mEditor).putInt(eq(DAILY_NOTIFICATION_COUNT_KEY), eq(0));
+        verify(mEditor).putInt(eq(MONTHLY_NOTIFICATION_COUNT_KEY), eq(0));
+
+        // change only year, date and month remain the same
+        Mockito.clearInvocations(mEditor);
+        mSlicePurchaseController.setLocalDate(LocalDate.of(YEAR + 1, MONTH + 1, DATE + 1));
+        mSlicePurchaseController.updateNotificationCounts();
+        verify(mEditor).putInt(eq(DAILY_NOTIFICATION_COUNT_KEY), eq(0));
+        verify(mEditor).putInt(eq(MONTHLY_NOTIFICATION_COUNT_KEY), eq(0));
+
+        // change only month and year, date remains the same
+        Mockito.clearInvocations(mEditor);
+        mSlicePurchaseController.setLocalDate(LocalDate.of(YEAR + 2, MONTH + 2, DATE + 1));
+        mSlicePurchaseController.updateNotificationCounts();
+        verify(mEditor).putInt(eq(DAILY_NOTIFICATION_COUNT_KEY), eq(0));
+        verify(mEditor).putInt(eq(MONTHLY_NOTIFICATION_COUNT_KEY), eq(0));
+
+        // change only date and year, month remains the same
+        Mockito.clearInvocations(mEditor);
+        mSlicePurchaseController.setLocalDate(LocalDate.of(YEAR + 3, MONTH + 2, DATE + 2));
+        mSlicePurchaseController.updateNotificationCounts();
+        verify(mEditor).putInt(eq(DAILY_NOTIFICATION_COUNT_KEY), eq(0));
+        verify(mEditor).putInt(eq(MONTHLY_NOTIFICATION_COUNT_KEY), eq(0));
+
+        // change only date and month, year remains the same
+        Mockito.clearInvocations(mEditor);
+        mSlicePurchaseController.setLocalDate(LocalDate.of(YEAR + 3, MONTH + 3, DATE + 3));
+        mSlicePurchaseController.updateNotificationCounts();
+        verify(mEditor).putInt(eq(DAILY_NOTIFICATION_COUNT_KEY), eq(0));
+        verify(mEditor).putInt(eq(MONTHLY_NOTIFICATION_COUNT_KEY), eq(0));
+    }
+
+    @Test
     public void testPurchasePremiumCapabilityResultFeatureNotSupported() {
         mSlicePurchaseController.purchasePremiumCapability(
                 TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, TAG,
@@ -237,7 +307,6 @@
                 new int[]{TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY});
         mBundle.putString(CarrierConfigManager.KEY_PREMIUM_CAPABILITY_PURCHASE_URL_STRING,
                 SlicePurchaseController.SLICE_PURCHASE_TEST_FILE);
-        doReturn(mBundle).when(mCarrierConfigManager).getConfigForSubId(anyInt());
 
         mSlicePurchaseController.purchasePremiumCapability(
                 TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, TAG,
@@ -255,7 +324,6 @@
                 new int[]{TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY});
         mBundle.putString(CarrierConfigManager.KEY_PREMIUM_CAPABILITY_PURCHASE_URL_STRING,
                 SlicePurchaseController.SLICE_PURCHASE_TEST_FILE);
-        doReturn(mBundle).when(mCarrierConfigManager).getConfigForSubId(anyInt());
 
         mSlicePurchaseController.purchasePremiumCapability(
                 TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, TAG,
@@ -285,7 +353,6 @@
                 new int[]{TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY});
         mBundle.putString(CarrierConfigManager.KEY_PREMIUM_CAPABILITY_PURCHASE_URL_STRING,
                 SlicePurchaseController.SLICE_PURCHASE_TEST_FILE);
-        doReturn(mBundle).when(mCarrierConfigManager).getConfigForSubId(anyInt());
         doReturn(SubscriptionManager.getDefaultDataSubscriptionId()).when(mPhone).getSubId();
 
         mSlicePurchaseController.purchasePremiumCapability(
@@ -314,7 +381,6 @@
                 new int[]{TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY});
         mBundle.putString(CarrierConfigManager.KEY_PREMIUM_CAPABILITY_PURCHASE_URL_STRING,
                 SlicePurchaseController.SLICE_PURCHASE_TEST_FILE);
-        doReturn(mBundle).when(mCarrierConfigManager).getConfigForSubId(anyInt());
         doReturn(SubscriptionManager.getDefaultDataSubscriptionId()).when(mPhone).getSubId();
         doReturn(TelephonyManager.NETWORK_TYPE_NR).when(mServiceState).getDataNetworkType();
         doReturn(null).when(mPremiumNetworkEntitlementApi).checkEntitlementStatus(anyInt());
@@ -342,8 +408,6 @@
         // retry with provisioning response
         mEntitlementResponse.mProvisionStatus =
                 PremiumNetworkEntitlementResponse.PREMIUM_NETWORK_PROVISION_STATUS_IN_PROGRESS;
-        doReturn(mEntitlementResponse).when(mPremiumNetworkEntitlementApi)
-                .checkEntitlementStatus(anyInt());
 
         mSlicePurchaseController.purchasePremiumCapability(
                 TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, TAG,
@@ -357,12 +421,9 @@
                 PremiumNetworkEntitlementResponse.PREMIUM_NETWORK_PROVISION_STATUS_NOT_PROVISIONED;
         mEntitlementResponse.mEntitlementStatus =
                 PremiumNetworkEntitlementResponse.PREMIUM_NETWORK_ENTITLEMENT_STATUS_INCOMPATIBLE;
-        doReturn(mEntitlementResponse).when(mPremiumNetworkEntitlementApi)
-                .checkEntitlementStatus(anyInt());
         mBundle.putLong(CarrierConfigManager
                 .KEY_PREMIUM_CAPABILITY_PURCHASE_CONDITION_BACKOFF_HYSTERESIS_TIME_MILLIS_LONG,
                 PURCHASE_CONDITION_TIMEOUT);
-        doReturn(mBundle).when(mCarrierConfigManager).getConfigForSubId(anyInt());
 
         mSlicePurchaseController.purchasePremiumCapability(
                 TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, TAG,
@@ -409,12 +470,13 @@
     public void testPurchasePremiumCapabilityResultSuccess() {
         sendValidPurchaseRequest();
 
+        // broadcast SUCCESS response from slice purchase application
         Intent intent = new Intent();
         intent.setAction("com.android.phone.slice.action.SLICE_PURCHASE_APP_RESPONSE_SUCCESS");
         intent.putExtra(SlicePurchaseController.EXTRA_PHONE_ID, PHONE_ID);
         intent.putExtra(SlicePurchaseController.EXTRA_PREMIUM_CAPABILITY,
                 TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY);
-        mBroadcastReceiver.onReceive(mMockedContext, intent);
+        mContext.getBroadcastReceiver().onReceive(mContext, intent);
         mTestableLooper.processAllMessages();
         assertEquals(TelephonyManager.PURCHASE_PREMIUM_CAPABILITY_RESULT_SUCCESS, mResult);
 
@@ -443,13 +505,7 @@
     public void testPurchasePremiumCapabilityResultAlreadyPurchased() {
         testPurchasePremiumCapabilityResultSuccess();
 
-        // TODO: implement slicing config logic properly
-        NetworkSlicingConfig slicingConfig = new NetworkSlicingConfig(Collections.emptyList(),
-                Collections.singletonList(new NetworkSliceInfo.Builder()
-                        .setStatus(NetworkSliceInfo.SLICE_STATUS_ALLOWED).build()));
-        mSlicePurchaseController.obtainMessage(2 /* EVENT_SLICING_CONFIG_CHANGED */,
-                new AsyncResult(null, slicingConfig, null)).sendToTarget();
-        mTestableLooper.processAllMessages();
+        sendNetworkSlicingConfig(true);
 
         mSlicePurchaseController.purchasePremiumCapability(
                 TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, TAG,
@@ -467,10 +523,7 @@
                 mResult);
 
         // retry to verify purchase expired
-        slicingConfig = new NetworkSlicingConfig(Collections.emptyList(), Collections.emptyList());
-        mSlicePurchaseController.obtainMessage(2 /* EVENT_SLICING_CONFIG_CHANGED */,
-                new AsyncResult(null, slicingConfig, null)).sendToTarget();
-        mTestableLooper.processAllMessages();
+        sendNetworkSlicingConfig(false);
 
         testPurchasePremiumCapabilityResultSuccess();
     }
@@ -501,12 +554,13 @@
     public void testPurchasePremiumCapabilityResultUserCanceled() {
         sendValidPurchaseRequest();
 
+        // broadcast CANCELED response from slice purchase application
         Intent intent = new Intent();
         intent.setAction("com.android.phone.slice.action.SLICE_PURCHASE_APP_RESPONSE_CANCELED");
         intent.putExtra(SlicePurchaseController.EXTRA_PHONE_ID, PHONE_ID);
         intent.putExtra(SlicePurchaseController.EXTRA_PREMIUM_CAPABILITY,
                 TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY);
-        mBroadcastReceiver.onReceive(mMockedContext, intent);
+        mContext.getBroadcastReceiver().onReceive(mContext, intent);
         mTestableLooper.processAllMessages();
         assertEquals(TelephonyManager.PURCHASE_PREMIUM_CAPABILITY_RESULT_USER_CANCELED, mResult);
 
@@ -528,6 +582,7 @@
     public void testPurchasePremiumCapabilityResultCarrierError() {
         sendValidPurchaseRequest();
 
+        // broadcast CARRIER_ERROR response from slice purchase application
         Intent intent = new Intent();
         intent.setAction(
                 "com.android.phone.slice.action.SLICE_PURCHASE_APP_RESPONSE_CARRIER_ERROR");
@@ -536,7 +591,7 @@
                 TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY);
         intent.putExtra(SlicePurchaseController.EXTRA_FAILURE_CODE,
                 SlicePurchaseController.FAILURE_CODE_SERVER_UNREACHABLE);
-        mBroadcastReceiver.onReceive(mMockedContext, intent);
+        mContext.getBroadcastReceiver().onReceive(mContext, intent);
         mTestableLooper.processAllMessages();
         assertEquals(TelephonyManager.PURCHASE_PREMIUM_CAPABILITY_RESULT_CARRIER_ERROR, mResult);
 
@@ -558,13 +613,14 @@
     public void testPurchasePremiumCapabilityResultRequestFailed() {
         sendValidPurchaseRequest();
 
+        // broadcast REQUEST_FAILED response from slice purchase application
         Intent intent = new Intent();
         intent.setAction(
                 "com.android.phone.slice.action.SLICE_PURCHASE_APP_RESPONSE_REQUEST_FAILED");
         intent.putExtra(SlicePurchaseController.EXTRA_PHONE_ID, PHONE_ID);
         intent.putExtra(SlicePurchaseController.EXTRA_PREMIUM_CAPABILITY,
                 TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY);
-        mBroadcastReceiver.onReceive(mMockedContext, intent);
+        mContext.getBroadcastReceiver().onReceive(mContext, intent);
         mTestableLooper.processAllMessages();
         assertEquals(TelephonyManager.PURCHASE_PREMIUM_CAPABILITY_RESULT_REQUEST_FAILED, mResult);
 
@@ -582,7 +638,7 @@
         intent.putExtra(SlicePurchaseController.EXTRA_PHONE_ID, PHONE_ID);
         intent.putExtra(SlicePurchaseController.EXTRA_PREMIUM_CAPABILITY,
                 TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY);
-        mBroadcastReceiver.onReceive(mMockedContext, intent);
+        mContext.getBroadcastReceiver().onReceive(mContext, intent);
         mTestableLooper.processAllMessages();
         assertEquals(
                 TelephonyManager.PURCHASE_PREMIUM_CAPABILITY_RESULT_NOT_DEFAULT_DATA_SUBSCRIPTION,
@@ -592,8 +648,70 @@
         testPurchasePremiumCapabilityResultSuccess();
     }
 
+    @Test
+    public void testPurchasePremiumCapabilityResultNotificationThrottled() {
+        mSlicePurchaseController.setLocalDate(LocalDate.of(YEAR, MONTH, DATE));
+        mSlicePurchaseController.updateNotificationCounts();
+
+        for (int count = 1; count <= DAILY_NOTIFICATION_MAX; count++) {
+            completeSuccessfulPurchase();
+            verify(mEditor).putInt(eq(DAILY_NOTIFICATION_COUNT_KEY), eq(count));
+            verify(mEditor).putInt(eq(MONTHLY_NOTIFICATION_COUNT_KEY), eq(count));
+        }
+
+        // retry to verify throttled
+        mSlicePurchaseController.purchasePremiumCapability(
+                TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, TAG,
+                mHandler.obtainMessage());
+        mTestableLooper.processAllMessages();
+        assertEquals(TelephonyManager.PURCHASE_PREMIUM_CAPABILITY_RESULT_THROTTLED, mResult);
+
+        // change the date to trigger daily reset
+        mSlicePurchaseController.setLocalDate(LocalDate.of(YEAR, MONTH, DATE + 1));
+        Mockito.clearInvocations(mEditor);
+
+        for (int count = 1; count <= (MONTHLY_NOTIFICATION_MAX - DAILY_NOTIFICATION_MAX); count++) {
+            completeSuccessfulPurchase();
+            verify(mEditor).putInt(eq(DAILY_NOTIFICATION_COUNT_KEY), eq(count));
+            verify(mEditor).putInt(eq(MONTHLY_NOTIFICATION_COUNT_KEY),
+                    eq(count + DAILY_NOTIFICATION_MAX));
+        }
+
+        // retry to verify throttled
+        mSlicePurchaseController.purchasePremiumCapability(
+                TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, TAG,
+                mHandler.obtainMessage());
+        mTestableLooper.processAllMessages();
+        assertEquals(TelephonyManager.PURCHASE_PREMIUM_CAPABILITY_RESULT_THROTTLED, mResult);
+    }
+
+    private void completeSuccessfulPurchase() {
+        sendValidPurchaseRequest();
+
+        // broadcast NOTIFICATION_SHOWN response from slice purchase application
+        Intent intent = new Intent();
+        intent.setAction(
+                "com.android.phone.slice.action.SLICE_PURCHASE_APP_RESPONSE_NOTIFICATION_SHOWN");
+        intent.putExtra(SlicePurchaseController.EXTRA_PHONE_ID, PHONE_ID);
+        intent.putExtra(SlicePurchaseController.EXTRA_PREMIUM_CAPABILITY,
+                TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY);
+        mContext.getBroadcastReceiver().onReceive(mContext, intent);
+        mTestableLooper.processAllMessages();
+
+        // broadcast SUCCESS response from slice purchase application
+        intent.setAction("com.android.phone.slice.action.SLICE_PURCHASE_APP_RESPONSE_SUCCESS");
+        mContext.getBroadcastReceiver().onReceive(mContext, intent);
+        mTestableLooper.processAllMessages();
+        assertEquals(TelephonyManager.PURCHASE_PREMIUM_CAPABILITY_RESULT_SUCCESS, mResult);
+
+        // complete network setup
+        sendNetworkSlicingConfig(true);
+        // purchase expired
+        sendNetworkSlicingConfig(false);
+    }
+
     private void sendValidPurchaseRequest() {
-        clearInvocations(mMockedContext);
+        clearInvocations(mContext);
 
         // feature supported
         doReturn((int) TelephonyManager.NETWORK_TYPE_BITMASK_NR).when(mPhone)
@@ -614,7 +732,6 @@
         mBundle.putLong(CarrierConfigManager
                 .KEY_PREMIUM_CAPABILITY_PURCHASE_CONDITION_BACKOFF_HYSTERESIS_TIME_MILLIS_LONG,
                 PURCHASE_CONDITION_TIMEOUT);
-        doReturn(mBundle).when(mCarrierConfigManager).getConfigForSubId(anyInt());
         // default data subscription
         doReturn(SubscriptionManager.getDefaultDataSubscriptionId()).when(mPhone).getSubId();
         // network available
@@ -622,8 +739,6 @@
         // entitlement check passed
         mEntitlementResponse.mEntitlementStatus =
                 PremiumNetworkEntitlementResponse.PREMIUM_NETWORK_ENTITLEMENT_STATUS_ENABLED;
-        doReturn(mEntitlementResponse).when(mPremiumNetworkEntitlementApi)
-                .checkEntitlementStatus(anyInt());
 
         // send purchase request
         mSlicePurchaseController.purchasePremiumCapability(
@@ -632,18 +747,23 @@
         mTestableLooper.processAllMessages();
 
         // verify that the purchase request was sent successfully
-        ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class);
-        verify(mMockedContext).sendBroadcast(intentCaptor.capture());
-        Intent intent = intentCaptor.getValue();
-        assertEquals(SlicePurchaseController.ACTION_START_SLICE_PURCHASE_APP, intent.getAction());
+        verify(mContext).sendBroadcast(any(Intent.class));
+        assertEquals(SlicePurchaseController.ACTION_START_SLICE_PURCHASE_APP,
+                mContext.getBroadcast().getAction());
         assertTrue(mSlicePurchaseController.hasMessages(4 /* EVENT_PURCHASE_TIMEOUT */,
                 TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY));
+        verify(mContext).registerReceiver(any(BroadcastReceiver.class), any(IntentFilter.class));
+    }
 
-        // capture the broadcast receiver to fake responses from the slice purchase application
-        ArgumentCaptor<SlicePurchaseControllerBroadcastReceiver> broadcastReceiverCaptor =
-                ArgumentCaptor.forClass(SlicePurchaseControllerBroadcastReceiver.class);
-        verify(mMockedContext).registerReceiver(
-                broadcastReceiverCaptor.capture(), any(IntentFilter.class));
-        mBroadcastReceiver = broadcastReceiverCaptor.getValue();
+    private void sendNetworkSlicingConfig(boolean configExists) {
+        // TODO: implement slicing config logic properly
+        NetworkSlicingConfig slicingConfig = new NetworkSlicingConfig(Collections.emptyList(),
+                configExists
+                        ? Collections.singletonList(new NetworkSliceInfo.Builder()
+                                .setStatus(NetworkSliceInfo.SLICE_STATUS_ALLOWED).build())
+                        : Collections.emptyList());
+        mSlicePurchaseController.obtainMessage(2 /* EVENT_SLICING_CONFIG_CHANGED */,
+                new AsyncResult(null, slicingConfig, null)).sendToTarget();
+        mTestableLooper.processAllMessages();
     }
 }