Loading packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/SlicePurchaseActivity.java +74 −11 Original line number Diff line number Diff line Loading @@ -31,9 +31,11 @@ import android.webkit.CookieManager; import android.webkit.WebView; import android.webkit.WebViewClient; import com.android.internal.annotations.VisibleForTesting; import com.android.phone.slice.SlicePurchaseController; import java.net.URL; import java.util.Base64; /** * Activity that launches when the user clicks on the performance boost notification. Loading @@ -56,11 +58,17 @@ import java.net.URL; public class SlicePurchaseActivity extends Activity { private static final String TAG = "SlicePurchaseActivity"; private static final int CONTENTS_TYPE_UNSPECIFIED = 0; private static final int CONTENTS_TYPE_JSON = 1; private static final int CONTENTS_TYPE_XML = 2; @NonNull private WebView mWebView; @NonNull private Context mApplicationContext; @NonNull private Intent mIntent; @NonNull private URL mUrl; @TelephonyManager.PremiumCapability protected int mCapability; @Nullable private String mUserData; private int mContentsType; private boolean mIsUserTriggeredFinish; @Override Loading @@ -72,6 +80,7 @@ public class SlicePurchaseActivity extends Activity { mCapability = mIntent.getIntExtra(SlicePurchaseController.EXTRA_PREMIUM_CAPABILITY, SlicePurchaseController.PREMIUM_CAPABILITY_INVALID); String url = mIntent.getStringExtra(SlicePurchaseController.EXTRA_PURCHASE_URL); mUserData = mIntent.getStringExtra(SlicePurchaseController.EXTRA_USER_DATA); mApplicationContext = getApplicationContext(); mIsUserTriggeredFinish = true; logd("onCreate: subId=" + subId + ", capability=" Loading @@ -81,7 +90,17 @@ public class SlicePurchaseActivity extends Activity { SlicePurchaseBroadcastReceiver.cancelNotification(mApplicationContext, mCapability); // Verify purchase URL is valid mUrl = SlicePurchaseBroadcastReceiver.getPurchaseUrl(url); String contentsType = mIntent.getStringExtra(SlicePurchaseController.EXTRA_CONTENTS_TYPE); mContentsType = CONTENTS_TYPE_UNSPECIFIED; if (!TextUtils.isEmpty(contentsType)) { if (contentsType.equals("json")) { mContentsType = CONTENTS_TYPE_JSON; } else if (contentsType.equals("xml")) { mContentsType = CONTENTS_TYPE_XML; } } mUrl = SlicePurchaseBroadcastReceiver.getPurchaseUrl(url, mUserData, mContentsType == CONTENTS_TYPE_UNSPECIFIED); if (mUrl == null) { String error = "Unable to create a purchase URL."; loge(error); Loading @@ -95,6 +114,20 @@ public class SlicePurchaseActivity extends Activity { return; } // Verify user data exists if contents type is specified if (mContentsType != CONTENTS_TYPE_UNSPECIFIED && TextUtils.isEmpty(mUserData)) { String error = "Contents type was specified but user data does not exist."; loge(error); Intent data = new Intent(); data.putExtra(SlicePurchaseController.EXTRA_FAILURE_CODE, SlicePurchaseController.FAILURE_CODE_NO_USER_DATA); data.putExtra(SlicePurchaseController.EXTRA_FAILURE_REASON, error); SlicePurchaseBroadcastReceiver.sendSlicePurchaseAppResponseWithData(mApplicationContext, mIntent, SlicePurchaseController.EXTRA_INTENT_CARRIER_ERROR, data); finishAndRemoveTask(); return; } // Verify intent is valid if (!SlicePurchaseBroadcastReceiver.isIntentValid(mIntent)) { loge("Not starting SlicePurchaseActivity with an invalid Intent: " + mIntent); Loading @@ -115,9 +148,7 @@ public class SlicePurchaseActivity extends Activity { } // Clear any cookies that might be persisted from previous sessions before loading WebView CookieManager.getInstance().removeAllCookies(value -> { setupWebView(); }); CookieManager.getInstance().removeAllCookies(value -> setupWebView()); } protected void onPurchaseSuccessful() { Loading Loading @@ -190,14 +221,46 @@ public class SlicePurchaseActivity extends Activity { // Display WebView setContentView(mWebView); // Load the URL String userData = mIntent.getStringExtra(SlicePurchaseController.EXTRA_USER_DATA); if (TextUtils.isEmpty(userData)) { logd("Starting WebView with url: " + mUrl.toString()); mWebView.loadUrl(mUrl.toString()); // Start the WebView startWebView(mWebView, mUrl.toString(), mContentsType, mUserData); } /** * Send the URL to the WebView as either a GET or POST request, based on the contents type: * <ul> * <li> * CONTENTS_TYPE_UNSPECIFIED: * If the user data exists, append it to the purchase URL and load it as a GET request. * If the user data does not exist, load just the purchase URL as a GET request. * </li> * <li> * CONTENTS_TYPE_JSON or CONTENTS_TYPE_XML: * The user data must exist. Send the JSON or XML formatted user data in a POST request. * If the user data is encoded, it must be prefaced by {@code encodedValue=} and will be * encoded in Base64. Decode the user data and send it in the POST request. * </li> * </ul> * @param webView The WebView to start. * @param url The URL to start the WebView with. * @param contentsType The contents type of the userData. * @param userData The user data to send with the GET or POST request, if it exists. */ @VisibleForTesting public static void startWebView(@NonNull WebView webView, @NonNull String url, int contentsType, @Nullable String userData) { if (contentsType == CONTENTS_TYPE_UNSPECIFIED) { logd("Starting WebView GET with url: " + url); webView.loadUrl(url); } else { logd("Starting WebView with url: " + mUrl.toString() + ", userData=" + userData); mWebView.postUrl(mUrl.toString(), userData.getBytes()); byte[] data = userData.getBytes(); String[] split = userData.split("encodedValue="); if (split.length > 1) { logd("Decoding encoded value: " + split[1]); data = Base64.getDecoder().decode(split[1]); } logd("Starting WebView POST with url: " + url + ", contentsType: " + contentsType + ", data: " + new String(data)); webView.postUrl(url, data); } } Loading packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/SlicePurchaseBroadcastReceiver.java +31 −2 Original line number Diff line number Diff line Loading @@ -173,7 +173,9 @@ public class SlicePurchaseBroadcastReceiver extends BroadcastReceiver{ } String purchaseUrl = intent.getStringExtra(SlicePurchaseController.EXTRA_PURCHASE_URL); if (getPurchaseUrl(purchaseUrl) == null) { String userData = intent.getStringExtra(SlicePurchaseController.EXTRA_USER_DATA); String contentsType = intent.getStringExtra(SlicePurchaseController.EXTRA_CONTENTS_TYPE); if (getPurchaseUrl(purchaseUrl, userData, TextUtils.isEmpty(contentsType)) == null) { loge("isIntentValid: invalid purchase URL: " + purchaseUrl); return false; } Loading @@ -194,13 +196,40 @@ public class SlicePurchaseBroadcastReceiver extends BroadcastReceiver{ SlicePurchaseController.EXTRA_INTENT_NOTIFICATION_SHOWN); } /** * Get the {@link URL} from the given purchase URL String and user data, if it is valid. * * @param purchaseUrl The purchase URL String to use to create the URL. * @param userData The user data parameter from the entitlement server. * @param shouldAppendUserData If this is {@code true} and the {@code userData} exists, * the {@code userData} should be appended to the {@code purchaseUrl} to create the URL. * If this is false, only the {@code purchaseUrl} should be used and the {@code userData} * will be sent as data to the POST request instead. * @return The URL from the given purchase URL and user data or {@code null} if it is invalid. */ @Nullable public static URL getPurchaseUrl(@Nullable String purchaseUrl, @Nullable String userData, boolean shouldAppendUserData) { if (purchaseUrl == null) { return null; } // Only append user data if it exists, otherwise just return the purchase URL if (!shouldAppendUserData || TextUtils.isEmpty(userData)) { return getPurchaseUrl(purchaseUrl); } URL url = getPurchaseUrl(purchaseUrl + "?" + userData); if (url == null) { url = getPurchaseUrl(purchaseUrl); } return url; } /** * Get the {@link URL} from the given purchase URL String, if it is valid. * * @param purchaseUrl The purchase URL String to use to create the URL. * @return The purchase URL from the given String or {@code null} if it is invalid. */ @Nullable public static URL getPurchaseUrl(@Nullable String purchaseUrl) { @Nullable private static URL getPurchaseUrl(@Nullable String purchaseUrl) { if (!URLUtil.isValidUrl(purchaseUrl)) { return null; } Loading packages/CarrierDefaultApp/tests/unit/src/com/android/carrierdefaultapp/SlicePurchaseActivityTest.java +24 −0 Original line number Diff line number Diff line Loading @@ -21,6 +21,7 @@ import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import android.app.NotificationManager; Loading @@ -33,6 +34,7 @@ import android.telephony.CarrierConfigManager; import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; import android.test.ActivityUnitTestCase; import android.webkit.WebView; import androidx.test.platform.app.InstrumentationRegistry; import androidx.test.runner.AndroidJUnit4; Loading @@ -46,6 +48,8 @@ import org.mockito.ArgumentCaptor; import org.mockito.Mock; import org.mockito.MockitoAnnotations; import java.util.Base64; @RunWith(AndroidJUnit4.class) public class SlicePurchaseActivityTest extends ActivityUnitTestCase<SlicePurchaseActivity> { private static final String CARRIER = "Some Carrier"; Loading @@ -59,6 +63,7 @@ public class SlicePurchaseActivityTest extends ActivityUnitTestCase<SlicePurchas @Mock CarrierConfigManager mCarrierConfigManager; @Mock NotificationManager mNotificationManager; @Mock PersistableBundle mPersistableBundle; @Mock WebView mWebView; private SlicePurchaseActivity mSlicePurchaseActivity; private Context mContext; Loading Loading @@ -153,4 +158,23 @@ public class SlicePurchaseActivityTest extends ActivityUnitTestCase<SlicePurchas mSlicePurchaseActivity.onDismissFlow(); verify(mRequestFailedIntent).send(); } @Test public void testStartWebView() { // unspecified contents type SlicePurchaseActivity.startWebView(mWebView, URL, 0 /* CONTENTS_TYPE_UNSPECIFIED */, null); verify(mWebView).loadUrl(eq(URL)); // specified contents type with user data String userData = "userData"; byte[] userDataBytes = userData.getBytes(); SlicePurchaseActivity.startWebView(mWebView, URL, 1 /* CONTENTS_TYPE_JSON */, userData); verify(mWebView).postUrl(eq(URL), eq(userDataBytes)); // specified contents type with encoded user data byte[] encodedUserData = Base64.getEncoder().encode(userDataBytes); userData = "encodedValue=" + new String(encodedUserData); SlicePurchaseActivity.startWebView(mWebView, URL, 1 /* CONTENTS_TYPE_JSON */, userData); verify(mWebView, times(2)).postUrl(eq(URL), eq(userDataBytes)); } } packages/CarrierDefaultApp/tests/unit/src/com/android/carrierdefaultapp/SlicePurchaseBroadcastReceiverTest.java +23 −2 Original line number Diff line number Diff line Loading @@ -160,14 +160,35 @@ public class SlicePurchaseBroadcastReceiverTest { "file:///android_asset/slice_store_test.html" }; // test invalid URLs for (String url : invalidUrls) { URL purchaseUrl = SlicePurchaseBroadcastReceiver.getPurchaseUrl(url); URL purchaseUrl = SlicePurchaseBroadcastReceiver.getPurchaseUrl(url, null, false); assertNull(purchaseUrl); } // test asset URL assertEquals(SlicePurchaseController.SLICE_PURCHASE_TEST_FILE, SlicePurchaseBroadcastReceiver.getPurchaseUrl( SlicePurchaseController.SLICE_PURCHASE_TEST_FILE).toString()); SlicePurchaseController.SLICE_PURCHASE_TEST_FILE, null, false).toString()); // test normal URL String validUrl = "http://www.google.com"; assertEquals(validUrl, SlicePurchaseBroadcastReceiver.getPurchaseUrl(validUrl, null, false).toString()); // test normal URL with user data but no append String userData = "encryptedUserData=data"; assertEquals(validUrl, SlicePurchaseBroadcastReceiver.getPurchaseUrl(validUrl, userData, false) .toString()); // test normal URL with user data and append assertEquals(validUrl + "?" + userData, SlicePurchaseBroadcastReceiver.getPurchaseUrl(validUrl, userData, true).toString()); // test normal URL without user data and append assertEquals(validUrl, SlicePurchaseBroadcastReceiver.getPurchaseUrl(validUrl, null, true).toString()); } @Test Loading Loading
packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/SlicePurchaseActivity.java +74 −11 Original line number Diff line number Diff line Loading @@ -31,9 +31,11 @@ import android.webkit.CookieManager; import android.webkit.WebView; import android.webkit.WebViewClient; import com.android.internal.annotations.VisibleForTesting; import com.android.phone.slice.SlicePurchaseController; import java.net.URL; import java.util.Base64; /** * Activity that launches when the user clicks on the performance boost notification. Loading @@ -56,11 +58,17 @@ import java.net.URL; public class SlicePurchaseActivity extends Activity { private static final String TAG = "SlicePurchaseActivity"; private static final int CONTENTS_TYPE_UNSPECIFIED = 0; private static final int CONTENTS_TYPE_JSON = 1; private static final int CONTENTS_TYPE_XML = 2; @NonNull private WebView mWebView; @NonNull private Context mApplicationContext; @NonNull private Intent mIntent; @NonNull private URL mUrl; @TelephonyManager.PremiumCapability protected int mCapability; @Nullable private String mUserData; private int mContentsType; private boolean mIsUserTriggeredFinish; @Override Loading @@ -72,6 +80,7 @@ public class SlicePurchaseActivity extends Activity { mCapability = mIntent.getIntExtra(SlicePurchaseController.EXTRA_PREMIUM_CAPABILITY, SlicePurchaseController.PREMIUM_CAPABILITY_INVALID); String url = mIntent.getStringExtra(SlicePurchaseController.EXTRA_PURCHASE_URL); mUserData = mIntent.getStringExtra(SlicePurchaseController.EXTRA_USER_DATA); mApplicationContext = getApplicationContext(); mIsUserTriggeredFinish = true; logd("onCreate: subId=" + subId + ", capability=" Loading @@ -81,7 +90,17 @@ public class SlicePurchaseActivity extends Activity { SlicePurchaseBroadcastReceiver.cancelNotification(mApplicationContext, mCapability); // Verify purchase URL is valid mUrl = SlicePurchaseBroadcastReceiver.getPurchaseUrl(url); String contentsType = mIntent.getStringExtra(SlicePurchaseController.EXTRA_CONTENTS_TYPE); mContentsType = CONTENTS_TYPE_UNSPECIFIED; if (!TextUtils.isEmpty(contentsType)) { if (contentsType.equals("json")) { mContentsType = CONTENTS_TYPE_JSON; } else if (contentsType.equals("xml")) { mContentsType = CONTENTS_TYPE_XML; } } mUrl = SlicePurchaseBroadcastReceiver.getPurchaseUrl(url, mUserData, mContentsType == CONTENTS_TYPE_UNSPECIFIED); if (mUrl == null) { String error = "Unable to create a purchase URL."; loge(error); Loading @@ -95,6 +114,20 @@ public class SlicePurchaseActivity extends Activity { return; } // Verify user data exists if contents type is specified if (mContentsType != CONTENTS_TYPE_UNSPECIFIED && TextUtils.isEmpty(mUserData)) { String error = "Contents type was specified but user data does not exist."; loge(error); Intent data = new Intent(); data.putExtra(SlicePurchaseController.EXTRA_FAILURE_CODE, SlicePurchaseController.FAILURE_CODE_NO_USER_DATA); data.putExtra(SlicePurchaseController.EXTRA_FAILURE_REASON, error); SlicePurchaseBroadcastReceiver.sendSlicePurchaseAppResponseWithData(mApplicationContext, mIntent, SlicePurchaseController.EXTRA_INTENT_CARRIER_ERROR, data); finishAndRemoveTask(); return; } // Verify intent is valid if (!SlicePurchaseBroadcastReceiver.isIntentValid(mIntent)) { loge("Not starting SlicePurchaseActivity with an invalid Intent: " + mIntent); Loading @@ -115,9 +148,7 @@ public class SlicePurchaseActivity extends Activity { } // Clear any cookies that might be persisted from previous sessions before loading WebView CookieManager.getInstance().removeAllCookies(value -> { setupWebView(); }); CookieManager.getInstance().removeAllCookies(value -> setupWebView()); } protected void onPurchaseSuccessful() { Loading Loading @@ -190,14 +221,46 @@ public class SlicePurchaseActivity extends Activity { // Display WebView setContentView(mWebView); // Load the URL String userData = mIntent.getStringExtra(SlicePurchaseController.EXTRA_USER_DATA); if (TextUtils.isEmpty(userData)) { logd("Starting WebView with url: " + mUrl.toString()); mWebView.loadUrl(mUrl.toString()); // Start the WebView startWebView(mWebView, mUrl.toString(), mContentsType, mUserData); } /** * Send the URL to the WebView as either a GET or POST request, based on the contents type: * <ul> * <li> * CONTENTS_TYPE_UNSPECIFIED: * If the user data exists, append it to the purchase URL and load it as a GET request. * If the user data does not exist, load just the purchase URL as a GET request. * </li> * <li> * CONTENTS_TYPE_JSON or CONTENTS_TYPE_XML: * The user data must exist. Send the JSON or XML formatted user data in a POST request. * If the user data is encoded, it must be prefaced by {@code encodedValue=} and will be * encoded in Base64. Decode the user data and send it in the POST request. * </li> * </ul> * @param webView The WebView to start. * @param url The URL to start the WebView with. * @param contentsType The contents type of the userData. * @param userData The user data to send with the GET or POST request, if it exists. */ @VisibleForTesting public static void startWebView(@NonNull WebView webView, @NonNull String url, int contentsType, @Nullable String userData) { if (contentsType == CONTENTS_TYPE_UNSPECIFIED) { logd("Starting WebView GET with url: " + url); webView.loadUrl(url); } else { logd("Starting WebView with url: " + mUrl.toString() + ", userData=" + userData); mWebView.postUrl(mUrl.toString(), userData.getBytes()); byte[] data = userData.getBytes(); String[] split = userData.split("encodedValue="); if (split.length > 1) { logd("Decoding encoded value: " + split[1]); data = Base64.getDecoder().decode(split[1]); } logd("Starting WebView POST with url: " + url + ", contentsType: " + contentsType + ", data: " + new String(data)); webView.postUrl(url, data); } } Loading
packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/SlicePurchaseBroadcastReceiver.java +31 −2 Original line number Diff line number Diff line Loading @@ -173,7 +173,9 @@ public class SlicePurchaseBroadcastReceiver extends BroadcastReceiver{ } String purchaseUrl = intent.getStringExtra(SlicePurchaseController.EXTRA_PURCHASE_URL); if (getPurchaseUrl(purchaseUrl) == null) { String userData = intent.getStringExtra(SlicePurchaseController.EXTRA_USER_DATA); String contentsType = intent.getStringExtra(SlicePurchaseController.EXTRA_CONTENTS_TYPE); if (getPurchaseUrl(purchaseUrl, userData, TextUtils.isEmpty(contentsType)) == null) { loge("isIntentValid: invalid purchase URL: " + purchaseUrl); return false; } Loading @@ -194,13 +196,40 @@ public class SlicePurchaseBroadcastReceiver extends BroadcastReceiver{ SlicePurchaseController.EXTRA_INTENT_NOTIFICATION_SHOWN); } /** * Get the {@link URL} from the given purchase URL String and user data, if it is valid. * * @param purchaseUrl The purchase URL String to use to create the URL. * @param userData The user data parameter from the entitlement server. * @param shouldAppendUserData If this is {@code true} and the {@code userData} exists, * the {@code userData} should be appended to the {@code purchaseUrl} to create the URL. * If this is false, only the {@code purchaseUrl} should be used and the {@code userData} * will be sent as data to the POST request instead. * @return The URL from the given purchase URL and user data or {@code null} if it is invalid. */ @Nullable public static URL getPurchaseUrl(@Nullable String purchaseUrl, @Nullable String userData, boolean shouldAppendUserData) { if (purchaseUrl == null) { return null; } // Only append user data if it exists, otherwise just return the purchase URL if (!shouldAppendUserData || TextUtils.isEmpty(userData)) { return getPurchaseUrl(purchaseUrl); } URL url = getPurchaseUrl(purchaseUrl + "?" + userData); if (url == null) { url = getPurchaseUrl(purchaseUrl); } return url; } /** * Get the {@link URL} from the given purchase URL String, if it is valid. * * @param purchaseUrl The purchase URL String to use to create the URL. * @return The purchase URL from the given String or {@code null} if it is invalid. */ @Nullable public static URL getPurchaseUrl(@Nullable String purchaseUrl) { @Nullable private static URL getPurchaseUrl(@Nullable String purchaseUrl) { if (!URLUtil.isValidUrl(purchaseUrl)) { return null; } Loading
packages/CarrierDefaultApp/tests/unit/src/com/android/carrierdefaultapp/SlicePurchaseActivityTest.java +24 −0 Original line number Diff line number Diff line Loading @@ -21,6 +21,7 @@ import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import android.app.NotificationManager; Loading @@ -33,6 +34,7 @@ import android.telephony.CarrierConfigManager; import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; import android.test.ActivityUnitTestCase; import android.webkit.WebView; import androidx.test.platform.app.InstrumentationRegistry; import androidx.test.runner.AndroidJUnit4; Loading @@ -46,6 +48,8 @@ import org.mockito.ArgumentCaptor; import org.mockito.Mock; import org.mockito.MockitoAnnotations; import java.util.Base64; @RunWith(AndroidJUnit4.class) public class SlicePurchaseActivityTest extends ActivityUnitTestCase<SlicePurchaseActivity> { private static final String CARRIER = "Some Carrier"; Loading @@ -59,6 +63,7 @@ public class SlicePurchaseActivityTest extends ActivityUnitTestCase<SlicePurchas @Mock CarrierConfigManager mCarrierConfigManager; @Mock NotificationManager mNotificationManager; @Mock PersistableBundle mPersistableBundle; @Mock WebView mWebView; private SlicePurchaseActivity mSlicePurchaseActivity; private Context mContext; Loading Loading @@ -153,4 +158,23 @@ public class SlicePurchaseActivityTest extends ActivityUnitTestCase<SlicePurchas mSlicePurchaseActivity.onDismissFlow(); verify(mRequestFailedIntent).send(); } @Test public void testStartWebView() { // unspecified contents type SlicePurchaseActivity.startWebView(mWebView, URL, 0 /* CONTENTS_TYPE_UNSPECIFIED */, null); verify(mWebView).loadUrl(eq(URL)); // specified contents type with user data String userData = "userData"; byte[] userDataBytes = userData.getBytes(); SlicePurchaseActivity.startWebView(mWebView, URL, 1 /* CONTENTS_TYPE_JSON */, userData); verify(mWebView).postUrl(eq(URL), eq(userDataBytes)); // specified contents type with encoded user data byte[] encodedUserData = Base64.getEncoder().encode(userDataBytes); userData = "encodedValue=" + new String(encodedUserData); SlicePurchaseActivity.startWebView(mWebView, URL, 1 /* CONTENTS_TYPE_JSON */, userData); verify(mWebView, times(2)).postUrl(eq(URL), eq(userDataBytes)); } }
packages/CarrierDefaultApp/tests/unit/src/com/android/carrierdefaultapp/SlicePurchaseBroadcastReceiverTest.java +23 −2 Original line number Diff line number Diff line Loading @@ -160,14 +160,35 @@ public class SlicePurchaseBroadcastReceiverTest { "file:///android_asset/slice_store_test.html" }; // test invalid URLs for (String url : invalidUrls) { URL purchaseUrl = SlicePurchaseBroadcastReceiver.getPurchaseUrl(url); URL purchaseUrl = SlicePurchaseBroadcastReceiver.getPurchaseUrl(url, null, false); assertNull(purchaseUrl); } // test asset URL assertEquals(SlicePurchaseController.SLICE_PURCHASE_TEST_FILE, SlicePurchaseBroadcastReceiver.getPurchaseUrl( SlicePurchaseController.SLICE_PURCHASE_TEST_FILE).toString()); SlicePurchaseController.SLICE_PURCHASE_TEST_FILE, null, false).toString()); // test normal URL String validUrl = "http://www.google.com"; assertEquals(validUrl, SlicePurchaseBroadcastReceiver.getPurchaseUrl(validUrl, null, false).toString()); // test normal URL with user data but no append String userData = "encryptedUserData=data"; assertEquals(validUrl, SlicePurchaseBroadcastReceiver.getPurchaseUrl(validUrl, userData, false) .toString()); // test normal URL with user data and append assertEquals(validUrl + "?" + userData, SlicePurchaseBroadcastReceiver.getPurchaseUrl(validUrl, userData, true).toString()); // test normal URL without user data and append assertEquals(validUrl, SlicePurchaseBroadcastReceiver.getPurchaseUrl(validUrl, null, true).toString()); } @Test Loading