Merge "Slice upsell fail if notifications are disabled" into udc-qpr-dev

This commit is contained in:
Sarah Kim
2023-07-18 02:35:37 +00:00
committed by Android (Google) Code Review
4 changed files with 82 additions and 21 deletions

View File

@@ -191,6 +191,8 @@ public class SlicePurchaseBroadcastReceiver extends BroadcastReceiver{
&& isPendingIntentValid(intent, SlicePurchaseController.EXTRA_INTENT_REQUEST_FAILED) && isPendingIntentValid(intent, SlicePurchaseController.EXTRA_INTENT_REQUEST_FAILED)
&& isPendingIntentValid(intent, && isPendingIntentValid(intent,
SlicePurchaseController.EXTRA_INTENT_NOT_DEFAULT_DATA_SUBSCRIPTION) SlicePurchaseController.EXTRA_INTENT_NOT_DEFAULT_DATA_SUBSCRIPTION)
&& isPendingIntentValid(intent,
SlicePurchaseController.EXTRA_INTENT_NOTIFICATIONS_DISABLED)
&& isPendingIntentValid(intent, SlicePurchaseController.EXTRA_INTENT_SUCCESS) && isPendingIntentValid(intent, SlicePurchaseController.EXTRA_INTENT_SUCCESS)
&& isPendingIntentValid(intent, && isPendingIntentValid(intent,
SlicePurchaseController.EXTRA_INTENT_NOTIFICATION_SHOWN); SlicePurchaseController.EXTRA_INTENT_NOTIFICATION_SHOWN);
@@ -276,6 +278,8 @@ public class SlicePurchaseBroadcastReceiver extends BroadcastReceiver{
case SlicePurchaseController.EXTRA_INTENT_REQUEST_FAILED: return "request failed"; case SlicePurchaseController.EXTRA_INTENT_REQUEST_FAILED: return "request failed";
case SlicePurchaseController.EXTRA_INTENT_NOT_DEFAULT_DATA_SUBSCRIPTION: case SlicePurchaseController.EXTRA_INTENT_NOT_DEFAULT_DATA_SUBSCRIPTION:
return "not default data subscription"; return "not default data subscription";
case SlicePurchaseController.EXTRA_INTENT_NOTIFICATIONS_DISABLED:
return "notifications disabled";
case SlicePurchaseController.EXTRA_INTENT_SUCCESS: return "success"; case SlicePurchaseController.EXTRA_INTENT_SUCCESS: return "success";
case SlicePurchaseController.EXTRA_INTENT_NOTIFICATION_SHOWN: case SlicePurchaseController.EXTRA_INTENT_NOTIFICATION_SHOWN:
return "notification shown"; return "notification shown";
@@ -321,26 +325,45 @@ public class SlicePurchaseBroadcastReceiver extends BroadcastReceiver{
} }
private void onDisplayPerformanceBoostNotification(@NonNull Context context, private void onDisplayPerformanceBoostNotification(@NonNull Context context,
@NonNull Intent intent, boolean repeat) { @NonNull Intent intent, boolean localeChanged) {
if (!repeat && !isIntentValid(intent)) { if (!localeChanged && !isIntentValid(intent)) {
sendSlicePurchaseAppResponse(intent, sendSlicePurchaseAppResponse(intent,
SlicePurchaseController.EXTRA_INTENT_REQUEST_FAILED); SlicePurchaseController.EXTRA_INTENT_REQUEST_FAILED);
return; return;
} }
Resources res = getResources(context); Resources res = getResources(context);
NotificationChannel channel = new NotificationChannel( NotificationManager notificationManager =
context.getSystemService(NotificationManager.class);
NotificationChannel channel = notificationManager.getNotificationChannel(
PERFORMANCE_BOOST_NOTIFICATION_CHANNEL_ID);
if (channel == null) {
channel = new NotificationChannel(
PERFORMANCE_BOOST_NOTIFICATION_CHANNEL_ID, PERFORMANCE_BOOST_NOTIFICATION_CHANNEL_ID,
res.getString(R.string.performance_boost_notification_channel), res.getString(R.string.performance_boost_notification_channel),
NotificationManager.IMPORTANCE_DEFAULT); NotificationManager.IMPORTANCE_DEFAULT);
// CarrierDefaultApp notifications are unblockable by default. Make this channel blockable // CarrierDefaultApp notifications are unblockable by default.
// to allow users to disable notifications posted to this channel without affecting other // Make this channel blockable to allow users to disable notifications posted to this
// notifications in this application. // channel without affecting other notifications in this application.
channel.setBlockable(true); channel.setBlockable(true);
context.getSystemService(NotificationManager.class).createNotificationChannel(channel); context.getSystemService(NotificationManager.class).createNotificationChannel(channel);
} else if (localeChanged) {
// If the channel already exists but the locale has changed, update the channel name.
channel.setName(res.getString(R.string.performance_boost_notification_channel));
}
boolean channelNotificationsDisabled =
channel.getImportance() == NotificationManager.IMPORTANCE_NONE;
if (channelNotificationsDisabled || !notificationManager.areNotificationsEnabled()) {
// If notifications are disabled for the app or channel, fail the purchase request.
logd("Purchase request failed because notifications are disabled for the "
+ (channelNotificationsDisabled ? "channel." : "application."));
sendSlicePurchaseAppResponse(intent,
SlicePurchaseController.EXTRA_INTENT_NOTIFICATIONS_DISABLED);
return;
}
String carrier = intent.getStringExtra(SlicePurchaseController.EXTRA_CARRIER); String carrier = intent.getStringExtra(SlicePurchaseController.EXTRA_CARRIER);
Notification notification = Notification notification =
new Notification.Builder(context, PERFORMANCE_BOOST_NOTIFICATION_CHANNEL_ID) new Notification.Builder(context, PERFORMANCE_BOOST_NOTIFICATION_CHANNEL_ID)
.setContentTitle(res.getString( .setContentTitle(res.getString(
@@ -369,11 +392,12 @@ public class SlicePurchaseBroadcastReceiver extends BroadcastReceiver{
int capability = intent.getIntExtra(SlicePurchaseController.EXTRA_PREMIUM_CAPABILITY, int capability = intent.getIntExtra(SlicePurchaseController.EXTRA_PREMIUM_CAPABILITY,
SlicePurchaseController.PREMIUM_CAPABILITY_INVALID); SlicePurchaseController.PREMIUM_CAPABILITY_INVALID);
logd((repeat ? "Update" : "Display") + " the performance boost notification for capability " logd((localeChanged ? "Update" : "Display")
+ " the performance boost notification for capability "
+ TelephonyManager.convertPremiumCapabilityToString(capability)); + TelephonyManager.convertPremiumCapabilityToString(capability));
context.getSystemService(NotificationManager.class).notifyAsUser( context.getSystemService(NotificationManager.class).notifyAsUser(
PERFORMANCE_BOOST_NOTIFICATION_TAG, capability, notification, UserHandle.ALL); PERFORMANCE_BOOST_NOTIFICATION_TAG, capability, notification, UserHandle.ALL);
if (!repeat) { if (!localeChanged) {
sIntents.put(capability, intent); sIntents.put(capability, intent);
sendSlicePurchaseAppResponse(intent, sendSlicePurchaseAppResponse(intent,
SlicePurchaseController.EXTRA_INTENT_NOTIFICATION_SHOWN); SlicePurchaseController.EXTRA_INTENT_NOTIFICATION_SHOWN);

View File

@@ -32,6 +32,7 @@ import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy; import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verify;
import android.annotation.NonNull;
import android.app.Notification; import android.app.Notification;
import android.app.NotificationManager; import android.app.NotificationManager;
import android.app.PendingIntent; import android.app.PendingIntent;
@@ -72,6 +73,7 @@ public class SlicePurchaseBroadcastReceiverTest {
@Mock PendingIntent mContentIntent1; @Mock PendingIntent mContentIntent1;
@Mock PendingIntent mContentIntent2; @Mock PendingIntent mContentIntent2;
@Mock PendingIntent mNotificationShownIntent; @Mock PendingIntent mNotificationShownIntent;
@Mock PendingIntent mNotificationsDisabledIntent;
@Mock Context mContext; @Mock Context mContext;
@Mock Resources mResources; @Mock Resources mResources;
@Mock Configuration mConfiguration; @Mock Configuration mConfiguration;
@@ -90,6 +92,7 @@ public class SlicePurchaseBroadcastReceiverTest {
doReturn("").when(mResources).getString(anyInt()); doReturn("").when(mResources).getString(anyInt());
doReturn(mNotificationManager).when(mContext) doReturn(mNotificationManager).when(mContext)
.getSystemService(eq(NotificationManager.class)); .getSystemService(eq(NotificationManager.class));
doReturn(true).when(mNotificationManager).areNotificationsEnabled();
doReturn(mApplicationInfo).when(mContext).getApplicationInfo(); doReturn(mApplicationInfo).when(mContext).getApplicationInfo();
doReturn(mPackageManager).when(mContext).getPackageManager(); doReturn(mPackageManager).when(mContext).getPackageManager();
doReturn(mSpiedResources).when(mContext).getResources(); doReturn(mSpiedResources).when(mContext).getResources();
@@ -221,12 +224,10 @@ public class SlicePurchaseBroadcastReceiverTest {
doReturn(true).when(mPendingIntent).isBroadcast(); doReturn(true).when(mPendingIntent).isBroadcast();
doReturn(mPendingIntent).when(mIntent).getParcelableExtra( doReturn(mPendingIntent).when(mIntent).getParcelableExtra(
anyString(), eq(PendingIntent.class)); anyString(), eq(PendingIntent.class));
doReturn(TelephonyManager.PHONE_PROCESS_NAME).when(mNotificationShownIntent) createValidPendingIntent(mNotificationShownIntent,
.getCreatorPackage(); SlicePurchaseController.EXTRA_INTENT_NOTIFICATION_SHOWN);
doReturn(true).when(mNotificationShownIntent).isBroadcast(); createValidPendingIntent(mNotificationsDisabledIntent,
doReturn(mNotificationShownIntent).when(mIntent).getParcelableExtra( SlicePurchaseController.EXTRA_INTENT_NOTIFICATIONS_DISABLED);
eq(SlicePurchaseController.EXTRA_INTENT_NOTIFICATION_SHOWN),
eq(PendingIntent.class));
// spy notification intents to prevent PendingIntent issues // spy notification intents to prevent PendingIntent issues
doReturn(mContentIntent1).when(mSlicePurchaseBroadcastReceiver).createContentIntent( doReturn(mContentIntent1).when(mSlicePurchaseBroadcastReceiver).createContentIntent(
@@ -253,6 +254,12 @@ public class SlicePurchaseBroadcastReceiverTest {
mSlicePurchaseBroadcastReceiver.onReceive(mContext, mIntent); mSlicePurchaseBroadcastReceiver.onReceive(mContext, mIntent);
} }
private void createValidPendingIntent(@NonNull PendingIntent intent, @NonNull String extra) {
doReturn(TelephonyManager.PHONE_PROCESS_NAME).when(intent).getCreatorPackage();
doReturn(true).when(intent).isBroadcast();
doReturn(intent).when(mIntent).getParcelableExtra(eq(extra), eq(PendingIntent.class));
}
@Test @Test
public void testNotificationCanceled() { public void testNotificationCanceled() {
// send ACTION_NOTIFICATION_CANCELED // send ACTION_NOTIFICATION_CANCELED
@@ -335,4 +342,22 @@ public class SlicePurchaseBroadcastReceiverTest {
clearInvocations(mConfiguration); clearInvocations(mConfiguration);
return captor.getValue(); return captor.getValue();
} }
@Test
public void testNotificationsDisabled() throws Exception {
doReturn(false).when(mNotificationManager).areNotificationsEnabled();
displayPerformanceBoostNotification();
// verify notification was not shown
verify(mNotificationManager, never()).notifyAsUser(
eq(SlicePurchaseBroadcastReceiver.PERFORMANCE_BOOST_NOTIFICATION_TAG),
eq(TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY),
any(),
eq(UserHandle.ALL));
verify(mNotificationShownIntent, never()).send();
// verify SlicePurchaseController was notified that notifications are disabled
verify(mNotificationsDisabledIntent).send();
}
} }

View File

@@ -9621,6 +9621,7 @@ public class CarrierConfigManager {
* *
* @see TelephonyManager#PURCHASE_PREMIUM_CAPABILITY_RESULT_USER_CANCELED * @see TelephonyManager#PURCHASE_PREMIUM_CAPABILITY_RESULT_USER_CANCELED
* @see TelephonyManager#PURCHASE_PREMIUM_CAPABILITY_RESULT_TIMEOUT * @see TelephonyManager#PURCHASE_PREMIUM_CAPABILITY_RESULT_TIMEOUT
* @see TelephonyManager#PURCHASE_PREMIUM_CAPABILITY_RESULT_USER_DISABLED
*/ */
public static final String public static final String
KEY_PREMIUM_CAPABILITY_NOTIFICATION_BACKOFF_HYSTERESIS_TIME_MILLIS_LONG = KEY_PREMIUM_CAPABILITY_NOTIFICATION_BACKOFF_HYSTERESIS_TIME_MILLIS_LONG =

View File

@@ -17607,6 +17607,16 @@ public class TelephonyManager {
*/ */
public static final int PURCHASE_PREMIUM_CAPABILITY_RESULT_PENDING_NETWORK_SETUP = 15; public static final int PURCHASE_PREMIUM_CAPABILITY_RESULT_PENDING_NETWORK_SETUP = 15;
/**
* Purchase premium capability failed because the user disabled the feature.
* Subsequent attempts will be throttled for the amount of time specified by
* {@link CarrierConfigManager
* #KEY_PREMIUM_CAPABILITY_NOTIFICATION_BACKOFF_HYSTERESIS_TIME_MILLIS_LONG}
* and return {@link #PURCHASE_PREMIUM_CAPABILITY_RESULT_THROTTLED}.
* @hide
*/
public static final int PURCHASE_PREMIUM_CAPABILITY_RESULT_USER_DISABLED = 16;
/** /**
* Results of the purchase premium capability request. * Results of the purchase premium capability request.
* @hide * @hide
@@ -17626,7 +17636,8 @@ public class TelephonyManager {
PURCHASE_PREMIUM_CAPABILITY_RESULT_NETWORK_NOT_AVAILABLE, PURCHASE_PREMIUM_CAPABILITY_RESULT_NETWORK_NOT_AVAILABLE,
PURCHASE_PREMIUM_CAPABILITY_RESULT_ENTITLEMENT_CHECK_FAILED, PURCHASE_PREMIUM_CAPABILITY_RESULT_ENTITLEMENT_CHECK_FAILED,
PURCHASE_PREMIUM_CAPABILITY_RESULT_NOT_DEFAULT_DATA_SUBSCRIPTION, PURCHASE_PREMIUM_CAPABILITY_RESULT_NOT_DEFAULT_DATA_SUBSCRIPTION,
PURCHASE_PREMIUM_CAPABILITY_RESULT_PENDING_NETWORK_SETUP}) PURCHASE_PREMIUM_CAPABILITY_RESULT_PENDING_NETWORK_SETUP,
PURCHASE_PREMIUM_CAPABILITY_RESULT_USER_DISABLED})
public @interface PurchasePremiumCapabilityResult {} public @interface PurchasePremiumCapabilityResult {}
/** /**