summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Sarah Chin <sarahchin@google.com> 2023-05-11 23:17:08 -0700
committer Sarah Chin <sarahchin@google.com> 2023-07-06 15:12:17 -0700
commit360c235ef631ab3c04dd68175d1336dbb4466da9 (patch)
tree7ea1144f23926e02b8cd3d1bbf7093a37643fcc0
parent7e1bfdf07b567277a336db1b0e2163c65fbb8549 (diff)
SlicePurchaseActivity handle user data based on contents type
If contents type is not present, we need to append user data to the url and send it as a GET request. If contents type is xml or json, we need to send the user data as a POST request. If user data is encoded, we need to decode it before sending it in the POST request. If the contents type is specified but user data does not exist, return an error. Test: atest CarrierDefaultAppUnitTests Test: manual test userdata is properly appended or posted Bug: 282905562 Change-Id: I59e1e28e7e1bd583307da55187886b8bb0798006
-rw-r--r--packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/SlicePurchaseActivity.java85
-rw-r--r--packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/SlicePurchaseBroadcastReceiver.java33
-rw-r--r--packages/CarrierDefaultApp/tests/unit/src/com/android/carrierdefaultapp/SlicePurchaseActivityTest.java24
-rw-r--r--packages/CarrierDefaultApp/tests/unit/src/com/android/carrierdefaultapp/SlicePurchaseBroadcastReceiverTest.java25
4 files changed, 152 insertions, 15 deletions
diff --git a/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/SlicePurchaseActivity.java b/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/SlicePurchaseActivity.java
index b1009808cccc..fcc4ec122839 100644
--- a/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/SlicePurchaseActivity.java
+++ b/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/SlicePurchaseActivity.java
@@ -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.
@@ -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
@@ -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="
@@ -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);
@@ -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);
@@ -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() {
@@ -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);
}
}
diff --git a/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/SlicePurchaseBroadcastReceiver.java b/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/SlicePurchaseBroadcastReceiver.java
index 23b976638eef..9b33704cc8e7 100644
--- a/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/SlicePurchaseBroadcastReceiver.java
+++ b/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/SlicePurchaseBroadcastReceiver.java
@@ -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;
}
@@ -195,12 +197,39 @@ public class SlicePurchaseBroadcastReceiver extends BroadcastReceiver{
}
/**
+ * 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;
}
diff --git a/packages/CarrierDefaultApp/tests/unit/src/com/android/carrierdefaultapp/SlicePurchaseActivityTest.java b/packages/CarrierDefaultApp/tests/unit/src/com/android/carrierdefaultapp/SlicePurchaseActivityTest.java
index cc103fa98e65..1ec180beea81 100644
--- a/packages/CarrierDefaultApp/tests/unit/src/com/android/carrierdefaultapp/SlicePurchaseActivityTest.java
+++ b/packages/CarrierDefaultApp/tests/unit/src/com/android/carrierdefaultapp/SlicePurchaseActivityTest.java
@@ -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;
@@ -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;
@@ -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";
@@ -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;
@@ -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));
+ }
}
diff --git a/packages/CarrierDefaultApp/tests/unit/src/com/android/carrierdefaultapp/SlicePurchaseBroadcastReceiverTest.java b/packages/CarrierDefaultApp/tests/unit/src/com/android/carrierdefaultapp/SlicePurchaseBroadcastReceiverTest.java
index 952789c56b2e..61847b517c8d 100644
--- a/packages/CarrierDefaultApp/tests/unit/src/com/android/carrierdefaultapp/SlicePurchaseBroadcastReceiverTest.java
+++ b/packages/CarrierDefaultApp/tests/unit/src/com/android/carrierdefaultapp/SlicePurchaseBroadcastReceiverTest.java
@@ -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