blob: 6e2b986142d020fab8af1788d8f2ad5f44606caa [file] [log] [blame]
/*
* 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 com.android.phone.slice;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.anyBoolean;
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.annotation.NonNull;
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;
import android.os.Message;
import android.os.PersistableBundle;
import android.telephony.CarrierConfigManager;
import android.telephony.ServiceState;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
import android.telephony.data.NetworkSliceInfo;
import android.telephony.data.NetworkSlicingConfig;
import android.telephony.data.RouteSelectionDescriptor;
import android.telephony.data.TrafficDescriptor;
import android.telephony.data.UrspRule;
import android.testing.TestableLooper;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import com.android.TelephonyTestBase;
import com.android.internal.telephony.CommandsInterface;
import com.android.internal.telephony.Phone;
import com.android.internal.telephony.data.DataSettingsManager;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.Mockito;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
@RunWith(AndroidJUnit4.class)
public class SlicePurchaseControllerTest extends TelephonyTestBase {
private static final String CARRIER = "Some Carrier";
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 CarrierConfigManager mCarrierConfigManager;
@Mock CommandsInterface mCommandsInterface;
@Mock ServiceState mServiceState;
@Mock DataSettingsManager mDataSettingsManager;
@Mock PremiumNetworkEntitlementApi mPremiumNetworkEntitlementApi;
@Mock SharedPreferences mSharedPreferences;
@Mock SharedPreferences.Editor mEditor;
private SlicePurchaseController mSlicePurchaseController;
private PersistableBundle mBundle;
private PremiumNetworkEntitlementResponse mEntitlementResponse;
private Handler mHandler;
private TestableLooper mTestableLooper;
@TelephonyManager.PurchasePremiumCapabilityResult private int mResult;
@Before
public void setUp() throws Exception {
super.setUp();
HandlerThread handlerThread = new HandlerThread("SlicePurchaseControllerTest");
handlerThread.start();
mHandler = new Handler(handlerThread.getLooper()) {
@Override
public void handleMessage(Message msg) {
AsyncResult ar = (AsyncResult) msg.obj;
mResult = (int) ar.result;
}
};
mTestableLooper = new TestableLooper(mHandler.getLooper());
doReturn(PHONE_ID).when(mPhone).getPhoneId();
doReturn(mContext).when(mPhone).getContext();
doReturn(mServiceState).when(mPhone).getServiceState();
doReturn(mDataSettingsManager).when(mPhone).getDataSettingsManager();
mPhone.mCi = mCommandsInterface;
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());
mSlicePurchaseController = spy(slicePurchaseController);
doReturn(null).when(mSlicePurchaseController).createPendingIntent(
anyString(), anyInt(), anyBoolean());
doReturn(CARRIER).when(mSlicePurchaseController).getSimOperator();
replaceInstance(SlicePurchaseController.class, "sInstances", mSlicePurchaseController,
Map.of(PHONE_ID, mSlicePurchaseController));
replaceInstance(SlicePurchaseController.class, "mIsSlicingUpsellEnabled",
mSlicePurchaseController, true);
mEntitlementResponse = new PremiumNetworkEntitlementResponse();
doReturn(mPremiumNetworkEntitlementApi).when(mSlicePurchaseController)
.getPremiumNetworkEntitlementApi();
doReturn(mEntitlementResponse).when(mPremiumNetworkEntitlementApi)
.checkEntitlementStatus(anyInt());
}
@Test
public void testCreatePendingIntent() {
doCallRealMethod().when(mSlicePurchaseController).createPendingIntent(
anyString(), anyInt(), anyBoolean());
try {
mSlicePurchaseController.createPendingIntent(
"com.android.phone.slice.action.SLICE_PURCHASE_APP_RESPONSE_CANCELED",
TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY,
true);
} catch (Exception expected) {
return;
}
fail("Expected createPendingIntent to throw an exception");
}
@Test
public void testIsPremiumCapabilityAvailableForPurchase() {
assertFalse(mSlicePurchaseController.isPremiumCapabilityAvailableForPurchase(
TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY));
// all conditions met
doReturn((int) TelephonyManager.NETWORK_TYPE_BITMASK_NR).when(mPhone)
.getCachedAllowedNetworkTypesBitmask();
mBundle.putIntArray(CarrierConfigManager.KEY_SUPPORTED_PREMIUM_CAPABILITIES_INT_ARRAY,
new int[]{TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY});
mBundle.putString(CarrierConfigManager.KEY_PREMIUM_CAPABILITY_PURCHASE_URL_STRING,
SlicePurchaseController.SLICE_PURCHASE_TEST_FILE);
doReturn(SubscriptionManager.getDefaultDataSubscriptionId()).when(mPhone).getSubId();
// retry to verify available
assertTrue(mSlicePurchaseController.isPremiumCapabilityAvailableForPurchase(
TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY));
}
@Test
public void testGetPurchaseURL() {
mEntitlementResponse.mServiceFlowURL = SlicePurchaseController.SLICE_PURCHASE_TEST_FILE;
String purchaseUrl = mSlicePurchaseController.getPurchaseUrl(mEntitlementResponse);
assertEquals(purchaseUrl, SlicePurchaseController.SLICE_PURCHASE_TEST_FILE);
mEntitlementResponse.mServiceFlowURL = null;
mBundle.putString(CarrierConfigManager.KEY_PREMIUM_CAPABILITY_PURCHASE_URL_STRING,
SlicePurchaseController.SLICE_PURCHASE_TEST_FILE);
purchaseUrl = mSlicePurchaseController.getPurchaseUrl(mEntitlementResponse);
assertEquals(purchaseUrl, SlicePurchaseController.SLICE_PURCHASE_TEST_FILE);
String[] invalidUrls = new String[] {
null,
"",
"www.google.com",
"htt://www.google.com",
"http//www.google.com",
"http:/www.google.com",
"file:///android_asset/",
"file:///android_asset/slice_store_test.html"
};
for (String url : invalidUrls) {
mBundle.putString(CarrierConfigManager.KEY_PREMIUM_CAPABILITY_PURCHASE_URL_STRING, url);
assertEquals("", mSlicePurchaseController.getPurchaseUrl(mEntitlementResponse));
}
}
@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, mHandler.obtainMessage());
mTestableLooper.processAllMessages();
assertEquals(TelephonyManager.PURCHASE_PREMIUM_CAPABILITY_RESULT_FEATURE_NOT_SUPPORTED,
mResult);
// retry after enabling feature
doReturn((int) TelephonyManager.NETWORK_TYPE_BITMASK_NR).when(mPhone)
.getCachedAllowedNetworkTypesBitmask();
mSlicePurchaseController.purchasePremiumCapability(
TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, mHandler.obtainMessage());
mTestableLooper.processAllMessages();
assertNotEquals(TelephonyManager.PURCHASE_PREMIUM_CAPABILITY_RESULT_FEATURE_NOT_SUPPORTED,
mResult);
}
@Test
public void testPurchasePremiumCapabilityResultCarrierDisabled() {
doReturn((int) TelephonyManager.NETWORK_TYPE_BITMASK_NR).when(mPhone)
.getCachedAllowedNetworkTypesBitmask();
mSlicePurchaseController.purchasePremiumCapability(
TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, mHandler.obtainMessage());
mTestableLooper.processAllMessages();
assertEquals(TelephonyManager.PURCHASE_PREMIUM_CAPABILITY_RESULT_CARRIER_DISABLED, mResult);
// retry after enabling carrier configs
mBundle.putIntArray(CarrierConfigManager.KEY_SUPPORTED_PREMIUM_CAPABILITIES_INT_ARRAY,
new int[]{TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY});
mBundle.putString(CarrierConfigManager.KEY_PREMIUM_CAPABILITY_PURCHASE_URL_STRING,
SlicePurchaseController.SLICE_PURCHASE_TEST_FILE);
mSlicePurchaseController.purchasePremiumCapability(
TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, mHandler.obtainMessage());
mTestableLooper.processAllMessages();
assertNotEquals(TelephonyManager.PURCHASE_PREMIUM_CAPABILITY_RESULT_CARRIER_DISABLED,
mResult);
}
@Test
public void testPurchasePremiumCapabilityResultNotDefaultDataSubscription() {
doReturn((int) TelephonyManager.NETWORK_TYPE_BITMASK_NR).when(mPhone)
.getCachedAllowedNetworkTypesBitmask();
mBundle.putIntArray(CarrierConfigManager.KEY_SUPPORTED_PREMIUM_CAPABILITIES_INT_ARRAY,
new int[]{TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY});
mBundle.putString(CarrierConfigManager.KEY_PREMIUM_CAPABILITY_PURCHASE_URL_STRING,
SlicePurchaseController.SLICE_PURCHASE_TEST_FILE);
mSlicePurchaseController.purchasePremiumCapability(
TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, mHandler.obtainMessage());
mTestableLooper.processAllMessages();
assertEquals(
TelephonyManager.PURCHASE_PREMIUM_CAPABILITY_RESULT_NOT_DEFAULT_DATA_SUBSCRIPTION,
mResult);
// retry on default data subscription
doReturn(SubscriptionManager.getDefaultDataSubscriptionId()).when(mPhone).getSubId();
mSlicePurchaseController.purchasePremiumCapability(
TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, mHandler.obtainMessage());
mTestableLooper.processAllMessages();
assertNotEquals(
TelephonyManager.PURCHASE_PREMIUM_CAPABILITY_RESULT_NOT_DEFAULT_DATA_SUBSCRIPTION,
mResult);
}
@Test
public void testPurchasePremiumCapabilityResultNetworkNotAvailable() {
doReturn((int) TelephonyManager.NETWORK_TYPE_BITMASK_NR).when(mPhone)
.getCachedAllowedNetworkTypesBitmask();
mBundle.putIntArray(CarrierConfigManager.KEY_SUPPORTED_PREMIUM_CAPABILITIES_INT_ARRAY,
new int[]{TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY});
mBundle.putString(CarrierConfigManager.KEY_PREMIUM_CAPABILITY_PURCHASE_URL_STRING,
SlicePurchaseController.SLICE_PURCHASE_TEST_FILE);
doReturn(SubscriptionManager.getDefaultDataSubscriptionId()).when(mPhone).getSubId();
mSlicePurchaseController.purchasePremiumCapability(
TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, mHandler.obtainMessage());
mTestableLooper.processAllMessages();
assertEquals(TelephonyManager.PURCHASE_PREMIUM_CAPABILITY_RESULT_NETWORK_NOT_AVAILABLE,
mResult);
// retry with valid network
doReturn(TelephonyManager.NETWORK_TYPE_NR).when(mServiceState).getDataNetworkType();
doReturn(true).when(mDataSettingsManager).isDataEnabledForReason(anyInt());
mSlicePurchaseController.purchasePremiumCapability(
TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, mHandler.obtainMessage());
mTestableLooper.processAllMessages();
assertNotEquals(TelephonyManager.PURCHASE_PREMIUM_CAPABILITY_RESULT_NETWORK_NOT_AVAILABLE,
mResult);
}
@Test
public void testPurchasePremiumCapabilityResultEntitlementCheckFailed() {
doReturn((int) TelephonyManager.NETWORK_TYPE_BITMASK_NR).when(mPhone)
.getCachedAllowedNetworkTypesBitmask();
mBundle.putIntArray(CarrierConfigManager.KEY_SUPPORTED_PREMIUM_CAPABILITIES_INT_ARRAY,
new int[]{TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY});
mBundle.putString(CarrierConfigManager.KEY_PREMIUM_CAPABILITY_PURCHASE_URL_STRING,
SlicePurchaseController.SLICE_PURCHASE_TEST_FILE);
doReturn(SubscriptionManager.getDefaultDataSubscriptionId()).when(mPhone).getSubId();
doReturn(TelephonyManager.NETWORK_TYPE_NR).when(mServiceState).getDataNetworkType();
doReturn(true).when(mDataSettingsManager).isDataEnabledForReason(anyInt());
doReturn(null).when(mPremiumNetworkEntitlementApi).checkEntitlementStatus(anyInt());
mSlicePurchaseController.purchasePremiumCapability(
TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, mHandler.obtainMessage());
mTestableLooper.processAllMessages();
assertEquals(TelephonyManager.PURCHASE_PREMIUM_CAPABILITY_RESULT_CARRIER_ERROR, mResult);
// retry with provisioned response
mEntitlementResponse.mEntitlementStatus =
PremiumNetworkEntitlementResponse.PREMIUM_NETWORK_ENTITLEMENT_STATUS_INCLUDED;
mEntitlementResponse.mProvisionStatus =
PremiumNetworkEntitlementResponse.PREMIUM_NETWORK_PROVISION_STATUS_PROVISIONED;
doReturn(mEntitlementResponse).when(mPremiumNetworkEntitlementApi)
.checkEntitlementStatus(anyInt());
mSlicePurchaseController.purchasePremiumCapability(
TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, mHandler.obtainMessage());
mTestableLooper.processAllMessages();
assertEquals(TelephonyManager.PURCHASE_PREMIUM_CAPABILITY_RESULT_ALREADY_PURCHASED,
mResult);
// retry with provisioning response
mEntitlementResponse.mEntitlementStatus =
PremiumNetworkEntitlementResponse.PREMIUM_NETWORK_ENTITLEMENT_STATUS_PROVISIONING;
mEntitlementResponse.mProvisionStatus =
PremiumNetworkEntitlementResponse.PREMIUM_NETWORK_PROVISION_STATUS_IN_PROGRESS;
mSlicePurchaseController.purchasePremiumCapability(
TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, mHandler.obtainMessage());
mTestableLooper.processAllMessages();
assertEquals(TelephonyManager.PURCHASE_PREMIUM_CAPABILITY_RESULT_ALREADY_IN_PROGRESS,
mResult);
// retry with disallowed response and throttling
mEntitlementResponse.mProvisionStatus =
PremiumNetworkEntitlementResponse.PREMIUM_NETWORK_PROVISION_STATUS_NOT_PROVISIONED;
mEntitlementResponse.mEntitlementStatus =
PremiumNetworkEntitlementResponse.PREMIUM_NETWORK_ENTITLEMENT_STATUS_INCOMPATIBLE;
mBundle.putLong(CarrierConfigManager
.KEY_PREMIUM_CAPABILITY_PURCHASE_CONDITION_BACKOFF_HYSTERESIS_TIME_MILLIS_LONG,
PURCHASE_CONDITION_TIMEOUT);
mSlicePurchaseController.purchasePremiumCapability(
TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, mHandler.obtainMessage());
mTestableLooper.processAllMessages();
assertEquals(TelephonyManager.PURCHASE_PREMIUM_CAPABILITY_RESULT_ENTITLEMENT_CHECK_FAILED,
mResult);
// retry to verify throttled
mSlicePurchaseController.purchasePremiumCapability(
TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, mHandler.obtainMessage());
mTestableLooper.processAllMessages();
assertEquals(TelephonyManager.PURCHASE_PREMIUM_CAPABILITY_RESULT_THROTTLED, mResult);
// retry with valid entitlement check to verify unthrottled
mTestableLooper.moveTimeForward(PURCHASE_CONDITION_TIMEOUT);
mTestableLooper.processAllMessages();
testPurchasePremiumCapabilityResultSuccess();
}
@Test
public void testPurchasePremiumCapabilityResultAlreadyInProgress() {
sendValidPurchaseRequest();
mSlicePurchaseController.purchasePremiumCapability(
TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, mHandler.obtainMessage());
mTestableLooper.processAllMessages();
assertEquals(TelephonyManager.PURCHASE_PREMIUM_CAPABILITY_RESULT_ALREADY_IN_PROGRESS,
mResult);
// retry to verify same result
mSlicePurchaseController.purchasePremiumCapability(
TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, mHandler.obtainMessage());
mTestableLooper.processAllMessages();
assertEquals(TelephonyManager.PURCHASE_PREMIUM_CAPABILITY_RESULT_ALREADY_IN_PROGRESS,
mResult);
}
@Test
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);
mContext.getBroadcastReceiver().onReceive(mContext, intent);
mTestableLooper.processAllMessages();
assertEquals(TelephonyManager.PURCHASE_PREMIUM_CAPABILITY_RESULT_SUCCESS, mResult);
// retry tested in testPurchasePremiumCapabilityResultPendingNetworkSetup
}
@Test
public void testPurchasePremiumCapabilityResultPendingNetworkSetup() {
testPurchasePremiumCapabilityResultSuccess();
mSlicePurchaseController.purchasePremiumCapability(
TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, mHandler.obtainMessage());
mTestableLooper.processAllMessages();
assertEquals(TelephonyManager.PURCHASE_PREMIUM_CAPABILITY_RESULT_PENDING_NETWORK_SETUP,
mResult);
// retry to verify unthrottled
mTestableLooper.moveTimeForward(NETWORK_SETUP_TIMEOUT);
mTestableLooper.processAllMessages();
testPurchasePremiumCapabilityResultSuccess();
}
@Test
public void testPurchasePremiumCapabilityResultAlreadyPurchased() {
testPurchasePremiumCapabilityResultSuccess();
sendNetworkSlicingConfig(TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, true);
mSlicePurchaseController.purchasePremiumCapability(
TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, mHandler.obtainMessage());
mTestableLooper.processAllMessages();
assertEquals(TelephonyManager.PURCHASE_PREMIUM_CAPABILITY_RESULT_ALREADY_PURCHASED,
mResult);
// retry to verify same result
mSlicePurchaseController.purchasePremiumCapability(
TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, mHandler.obtainMessage());
mTestableLooper.processAllMessages();
assertEquals(TelephonyManager.PURCHASE_PREMIUM_CAPABILITY_RESULT_ALREADY_PURCHASED,
mResult);
// retry to verify purchase expired
sendNetworkSlicingConfig(TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, false);
testPurchasePremiumCapabilityResultSuccess();
}
@Test
public void testPurchasePremiumCapabilityResultTimeout() {
sendValidPurchaseRequest();
mTestableLooper.moveTimeForward(NOTIFICATION_TIMEOUT);
mTestableLooper.processAllMessages();
assertEquals(TelephonyManager.PURCHASE_PREMIUM_CAPABILITY_RESULT_TIMEOUT, mResult);
// retry to verify throttled
mSlicePurchaseController.purchasePremiumCapability(
TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, mHandler.obtainMessage());
mTestableLooper.processAllMessages();
assertEquals(TelephonyManager.PURCHASE_PREMIUM_CAPABILITY_RESULT_THROTTLED, mResult);
// retry to verify unthrottled
mTestableLooper.moveTimeForward(THROTTLE_TIMEOUT);
mTestableLooper.processAllMessages();
testPurchasePremiumCapabilityResultSuccess();
}
@Test
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);
mContext.getBroadcastReceiver().onReceive(mContext, intent);
mTestableLooper.processAllMessages();
assertEquals(TelephonyManager.PURCHASE_PREMIUM_CAPABILITY_RESULT_USER_CANCELED, mResult);
// retry to verify throttled
mSlicePurchaseController.purchasePremiumCapability(
TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, mHandler.obtainMessage());
mTestableLooper.processAllMessages();
assertEquals(TelephonyManager.PURCHASE_PREMIUM_CAPABILITY_RESULT_THROTTLED, mResult);
// retry to verify unthrottled
mTestableLooper.moveTimeForward(THROTTLE_TIMEOUT);
mTestableLooper.processAllMessages();
testPurchasePremiumCapabilityResultSuccess();
}
@Test
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");
intent.putExtra(SlicePurchaseController.EXTRA_PHONE_ID, PHONE_ID);
intent.putExtra(SlicePurchaseController.EXTRA_PREMIUM_CAPABILITY,
TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY);
intent.putExtra(SlicePurchaseController.EXTRA_FAILURE_CODE,
SlicePurchaseController.FAILURE_CODE_CARRIER_URL_UNAVAILABLE);
mContext.getBroadcastReceiver().onReceive(mContext, intent);
mTestableLooper.processAllMessages();
assertEquals(TelephonyManager.PURCHASE_PREMIUM_CAPABILITY_RESULT_CARRIER_ERROR, mResult);
// retry to verify throttled
mSlicePurchaseController.purchasePremiumCapability(
TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, mHandler.obtainMessage());
mTestableLooper.processAllMessages();
assertEquals(TelephonyManager.PURCHASE_PREMIUM_CAPABILITY_RESULT_THROTTLED, mResult);
// retry to verify unthrottled
mTestableLooper.moveTimeForward(PURCHASE_CONDITION_TIMEOUT);
mTestableLooper.processAllMessages();
testPurchasePremiumCapabilityResultSuccess();
}
@Test
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);
mContext.getBroadcastReceiver().onReceive(mContext, intent);
mTestableLooper.processAllMessages();
assertEquals(TelephonyManager.PURCHASE_PREMIUM_CAPABILITY_RESULT_REQUEST_FAILED, mResult);
// retry to verify no throttling
testPurchasePremiumCapabilityResultSuccess();
}
@Test
public void testPurchasePremiumCapabilityResultNotDefaultDataSubscriptionResponse() {
sendValidPurchaseRequest();
Intent intent = new Intent();
intent.setAction("com.android.phone.slice.action."
+ "SLICE_PURCHASE_APP_RESPONSE_NOT_DEFAULT_DATA_SUBSCRIPTION");
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();
assertEquals(
TelephonyManager.PURCHASE_PREMIUM_CAPABILITY_RESULT_NOT_DEFAULT_DATA_SUBSCRIPTION,
mResult);
// retry to verify no throttling
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, 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, mHandler.obtainMessage());
mTestableLooper.processAllMessages();
assertEquals(TelephonyManager.PURCHASE_PREMIUM_CAPABILITY_RESULT_THROTTLED, mResult);
}
@Test
public void testIsSlicingConfigActive_emptyUrspRules() {
int capability = TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY;
NetworkSliceInfo sliceInfo = createNetworkSliceInfo(
getRandomSliceServiceType(capability), true);
NetworkSlicingConfig slicingConfig = new NetworkSlicingConfig(
Collections.emptyList(), Collections.singletonList(sliceInfo));
mSlicePurchaseController.setSlicingConfig(slicingConfig);
assertFalse(mSlicePurchaseController.isSlicingConfigActive(capability));
}
@Test
public void testIsSlicingConfigActive_noMatchingTrafficDescriptor() {
int capability = TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY;
NetworkSliceInfo sliceInfo = createNetworkSliceInfo(
getRandomSliceServiceType(capability), true);
TrafficDescriptor trafficDescriptor = createTrafficDescriptor("ENTERPRISE");
RouteSelectionDescriptor routeSelectionDescriptor = createRouteSelectionDescriptor(
Collections.singletonList(sliceInfo));
NetworkSlicingConfig slicingConfig = createNetworkSlicingConfig(
Collections.singletonList(sliceInfo),
Collections.singletonList(trafficDescriptor),
Collections.singletonList(routeSelectionDescriptor));
mSlicePurchaseController.setSlicingConfig(slicingConfig);
assertFalse(mSlicePurchaseController.isSlicingConfigActive(capability));
}
@Test
public void testIsSlicingConfigActive_multipleElements() {
int capability = TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY;
NetworkSliceInfo sliceInfo1 = createNetworkSliceInfo(
getRandomSliceServiceType(SlicePurchaseController.PREMIUM_CAPABILITY_INVALID),
false);
NetworkSliceInfo sliceInfo2 = createNetworkSliceInfo(
getRandomSliceServiceType(capability), true);
List<NetworkSliceInfo> sliceInfos = new ArrayList<>();
sliceInfos.add(sliceInfo1);
sliceInfos.add(sliceInfo2);
TrafficDescriptor trafficDescriptor1 = createTrafficDescriptor("ENTERPRISE");
TrafficDescriptor trafficDescriptor2 = createTrafficDescriptor(
SlicePurchaseController.getAppId(capability));
List<TrafficDescriptor> trafficDescriptors = new ArrayList<>();
trafficDescriptors.add(trafficDescriptor1);
trafficDescriptors.add(trafficDescriptor2);
RouteSelectionDescriptor routeSelectionDescriptor1 = createRouteSelectionDescriptor(
Collections.emptyList());
RouteSelectionDescriptor routeSelectionDescriptor2 = createRouteSelectionDescriptor(
sliceInfos);
List<RouteSelectionDescriptor> routeSelectionDescriptors = new ArrayList<>();
routeSelectionDescriptors.add(routeSelectionDescriptor1);
routeSelectionDescriptors.add(routeSelectionDescriptor2);
NetworkSlicingConfig slicingConfig = createNetworkSlicingConfig(
sliceInfos, trafficDescriptors, routeSelectionDescriptors);
mSlicePurchaseController.setSlicingConfig(slicingConfig);
assertTrue(mSlicePurchaseController.isSlicingConfigActive(capability));
}
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(TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, true);
// purchase expired
sendNetworkSlicingConfig(TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, false);
}
private void sendValidPurchaseRequest() {
clearInvocations(mContext);
// feature supported
doReturn((int) TelephonyManager.NETWORK_TYPE_BITMASK_NR).when(mPhone)
.getCachedAllowedNetworkTypesBitmask();
// carrier supported
mBundle.putIntArray(CarrierConfigManager.KEY_SUPPORTED_PREMIUM_CAPABILITIES_INT_ARRAY,
new int[]{TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY});
mBundle.putString(CarrierConfigManager.KEY_PREMIUM_CAPABILITY_PURCHASE_URL_STRING,
SlicePurchaseController.SLICE_PURCHASE_TEST_FILE);
mBundle.putLong(CarrierConfigManager
.KEY_PREMIUM_CAPABILITY_NOTIFICATION_DISPLAY_TIMEOUT_MILLIS_LONG,
NOTIFICATION_TIMEOUT);
mBundle.putLong(CarrierConfigManager.KEY_PREMIUM_CAPABILITY_NETWORK_SETUP_TIME_MILLIS_LONG,
NETWORK_SETUP_TIMEOUT);
mBundle.putLong(CarrierConfigManager
.KEY_PREMIUM_CAPABILITY_NOTIFICATION_BACKOFF_HYSTERESIS_TIME_MILLIS_LONG,
THROTTLE_TIMEOUT);
mBundle.putLong(CarrierConfigManager
.KEY_PREMIUM_CAPABILITY_PURCHASE_CONDITION_BACKOFF_HYSTERESIS_TIME_MILLIS_LONG,
PURCHASE_CONDITION_TIMEOUT);
// default data subscription
doReturn(SubscriptionManager.getDefaultDataSubscriptionId()).when(mPhone).getSubId();
// network available
doReturn(TelephonyManager.NETWORK_TYPE_NR).when(mServiceState).getDataNetworkType();
doReturn(true).when(mDataSettingsManager).isDataEnabledForReason(anyInt());
// entitlement check passed
mEntitlementResponse.mEntitlementStatus =
PremiumNetworkEntitlementResponse.PREMIUM_NETWORK_ENTITLEMENT_STATUS_ENABLED;
mEntitlementResponse.mProvisionStatus =
PremiumNetworkEntitlementResponse.PREMIUM_NETWORK_PROVISION_STATUS_NOT_PROVISIONED;
// send purchase request
mSlicePurchaseController.purchasePremiumCapability(
TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, mHandler.obtainMessage());
mTestableLooper.processAllMessages();
// verify that the purchase request was sent successfully
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),
eq(Context.RECEIVER_NOT_EXPORTED));
}
private void sendNetworkSlicingConfig(int capability, boolean configActive) {
NetworkSliceInfo sliceInfo = createNetworkSliceInfo(
getRandomSliceServiceType(capability), configActive);
TrafficDescriptor trafficDescriptor = createTrafficDescriptor(
SlicePurchaseController.getAppId(capability));
RouteSelectionDescriptor routeSelectionDescriptor = createRouteSelectionDescriptor(
Collections.singletonList(sliceInfo));
NetworkSlicingConfig slicingConfig = createNetworkSlicingConfig(
Collections.singletonList(sliceInfo),
Collections.singletonList(trafficDescriptor),
Collections.singletonList(routeSelectionDescriptor));
mSlicePurchaseController.obtainMessage(2 /* EVENT_SLICING_CONFIG_CHANGED */,
new AsyncResult(null, slicingConfig, null)).sendToTarget();
mTestableLooper.processAllMessages();
}
@NetworkSliceInfo.SliceServiceType private int getRandomSliceServiceType(
@TelephonyManager.PremiumCapability int capability) {
for (int sliceServiceType : SlicePurchaseController.getSliceServiceTypes(capability)) {
// Get a random valid sst from the set
return sliceServiceType;
}
return NetworkSliceInfo.SLICE_SERVICE_TYPE_NONE;
}
@NonNull private NetworkSliceInfo createNetworkSliceInfo(
@NetworkSliceInfo.SliceServiceType int sliceServiceType, boolean active) {
return new NetworkSliceInfo.Builder()
.setStatus(active ? NetworkSliceInfo.SLICE_STATUS_ALLOWED
: NetworkSliceInfo.SLICE_STATUS_UNKNOWN)
.setSliceServiceType(sliceServiceType)
.build();
}
@NonNull private TrafficDescriptor createTrafficDescriptor(@NonNull String appId) {
TrafficDescriptor.OsAppId osAppId = new TrafficDescriptor.OsAppId(
TrafficDescriptor.OsAppId.ANDROID_OS_ID, appId);
return new TrafficDescriptor.Builder()
.setOsAppId(osAppId.getBytes())
.build();
}
@NonNull private RouteSelectionDescriptor createRouteSelectionDescriptor(
@NonNull List<NetworkSliceInfo> sliceInfos) {
return new RouteSelectionDescriptor(
RouteSelectionDescriptor.MIN_ROUTE_PRECEDENCE,
RouteSelectionDescriptor.SESSION_TYPE_IPV4,
RouteSelectionDescriptor.ROUTE_SSC_MODE_1,
sliceInfos, Collections.emptyList());
}
@NonNull private NetworkSlicingConfig createNetworkSlicingConfig(
@NonNull List<NetworkSliceInfo> sliceInfos,
@NonNull List<TrafficDescriptor> trafficDescriptors,
@NonNull List<RouteSelectionDescriptor> routeSelectionDescriptors) {
UrspRule urspRule = new UrspRule(0, trafficDescriptors, routeSelectionDescriptors);
return new NetworkSlicingConfig(Collections.singletonList(urspRule), sliceInfos);
}
}