Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 1d364395 authored by Miranda Kephart's avatar Miranda Kephart
Browse files

[DO NOT MERGE] Update quickshare intent rather than recreating

Currently, we extract the quickshare intent and re-wrap it as a new
PendingIntent once we get the screenshot URI. This is insecure as
it leads to executing the original with SysUI's permissions, which
the app may not have. This change switches to using Intent.fillin
to add the URI, keeping the original PendingIntent and original
permission set.

Bug: 278720336
Fix: 278720336
Test: manual (to test successful quickshare), atest
SaveImageInBackgroundTaskTest (to verify original pending intent
unchanged)

Merged-In: Icad3d5f939fcfb894e2038948954bc2735dbe326
Change-Id: Icad3d5f939fcfb894e2038948954bc2735dbe326
parent f44f39cc
Loading
Loading
Loading
Loading
+66 −47
Original line number Diff line number Diff line
@@ -89,7 +89,8 @@ class SaveImageInBackgroundTask extends AsyncTask<Void, Void, Void> {
    SaveImageInBackgroundTask(Context context, ImageExporter exporter,
            ScreenshotSmartActions screenshotSmartActions,
            ScreenshotController.SaveImageInBackgroundData data,
            Supplier<ActionTransition> sharedElementTransition) {
            Supplier<ActionTransition> sharedElementTransition,
            boolean smartActionsEnabled) {
        mContext = context;
        mScreenshotSmartActions = screenshotSmartActions;
        mImageData = new ScreenshotController.SavedImageData();
@@ -101,8 +102,7 @@ class SaveImageInBackgroundTask extends AsyncTask<Void, Void, Void> {
        mParams = data;

        // Initialize screenshot notification smart actions provider.
        mSmartActionsEnabled = DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_SYSTEMUI,
                SystemUiDeviceConfigFlags.ENABLE_SCREENSHOT_NOTIFICATION_SMART_ACTIONS, true);
        mSmartActionsEnabled = smartActionsEnabled;
        if (mSmartActionsEnabled) {
            mSmartActionsProvider =
                    SystemUIFactory.getInstance()
@@ -135,7 +135,12 @@ class SaveImageInBackgroundTask extends AsyncTask<Void, Void, Void> {
                // Since Quick Share target recommendation does not rely on image URL, it is
                // queried and surfaced before image compress/export. Action intent would not be
                // used, because it does not contain image URL.
                queryQuickShareAction(image, user);
                Notification.Action quickShare =
                        queryQuickShareAction(mScreenshotId, image, user, null);
                if (quickShare != null) {
                    mQuickShareData.quickShareAction = quickShare;
                    mParams.mQuickShareActionsReadyListener.onActionsReady(mQuickShareData);
                }
            }

            // Call synchronously here since already on a background thread.
@@ -168,8 +173,9 @@ class SaveImageInBackgroundTask extends AsyncTask<Void, Void, Void> {
            mImageData.shareTransition = createShareAction(mContext, mContext.getResources(), uri);
            mImageData.editTransition = createEditAction(mContext, mContext.getResources(), uri);
            mImageData.deleteAction = createDeleteAction(mContext, mContext.getResources(), uri);
            mImageData.quickShareAction = createQuickShareAction(mContext,
                    mQuickShareData.quickShareAction, uri);
            mImageData.quickShareAction = createQuickShareAction(
                    mQuickShareData.quickShareAction, mScreenshotId, uri, mImageTime, image,
                    user);

            mParams.mActionsReadyListener.onActionsReady(mImageData);
            if (DEBUG_CALLBACK) {
@@ -407,60 +413,73 @@ class SaveImageInBackgroundTask extends AsyncTask<Void, Void, Void> {
    }

    /**
     * Populate image uri into intent of Quick Share action.
     * Wrap the quickshare intent and populate the fillin intent with the URI
     */
    @VisibleForTesting
    private Notification.Action createQuickShareAction(Context context, Notification.Action action,
            Uri uri) {
        if (action == null) {
    Notification.Action createQuickShareAction(
            Notification.Action quickShare, String screenshotId, Uri uri, long imageTime,
            Bitmap image, UserHandle user) {
        if (quickShare == null) {
            return null;
        } else if (quickShare.actionIntent.isImmutable()) {
            Notification.Action quickShareWithUri =
                    queryQuickShareAction(screenshotId, image, user, uri);
            if (quickShareWithUri == null
                    || !quickShareWithUri.title.toString().contentEquals(quickShare.title)) {
                return null;
            }
        // Populate image URI into Quick Share chip intent
        Intent sharingIntent = action.actionIntent.getIntent();
        sharingIntent.setType("image/png");
        sharingIntent.putExtra(Intent.EXTRA_STREAM, uri);
        String subjectDate = DateFormat.getDateTimeInstance().format(new Date(mImageTime));
        String subject = String.format(SCREENSHOT_SHARE_SUBJECT_TEMPLATE, subjectDate);
        sharingIntent.putExtra(Intent.EXTRA_SUBJECT, subject);
        // Include URI in ClipData also, so that grantPermission picks it up.
        // We don't use setData here because some apps interpret this as "to:".
        ClipData clipdata = new ClipData(new ClipDescription("content",
                new String[]{"image/png"}),
                new ClipData.Item(uri));
        sharingIntent.setClipData(clipdata);
        sharingIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
        PendingIntent updatedPendingIntent = PendingIntent.getActivity(
                context, 0, sharingIntent,
                PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_IMMUTABLE);
            quickShare = quickShareWithUri;
        }

        // Proxy smart actions through {@link GlobalScreenshot.SmartActionsReceiver}
        // for logging smart actions.
        Bundle extras = action.getExtras();
        Intent wrappedIntent = new Intent(mContext, SmartActionsReceiver.class)
                .putExtra(ScreenshotController.EXTRA_ACTION_INTENT, quickShare.actionIntent)
                .putExtra(ScreenshotController.EXTRA_ACTION_INTENT_FILLIN,
                        createFillInIntent(uri, imageTime))
                .addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
        Bundle extras = quickShare.getExtras();
        String actionType = extras.getString(
                ScreenshotNotificationSmartActionsProvider.ACTION_TYPE,
                ScreenshotNotificationSmartActionsProvider.DEFAULT_ACTION_TYPE);
        Intent intent = new Intent(context, SmartActionsReceiver.class)
                .putExtra(ScreenshotController.EXTRA_ACTION_INTENT, updatedPendingIntent)
                .addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
        addIntentExtras(mScreenshotId, intent, actionType, mSmartActionsEnabled);
        PendingIntent broadcastIntent = PendingIntent.getBroadcast(context,
                mRandom.nextInt(),
                intent,
        addIntentExtras(screenshotId, wrappedIntent, actionType, mSmartActionsEnabled);
        PendingIntent broadcastIntent =
                PendingIntent.getBroadcast(mContext, mRandom.nextInt(), wrappedIntent,
                        PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_IMMUTABLE);
        return new Notification.Action.Builder(action.getIcon(), action.title,
                broadcastIntent).setContextual(true).addExtras(extras).build();
        return new Notification.Action.Builder(quickShare.getIcon(), quickShare.title,
                broadcastIntent)
                .setContextual(true)
                .addExtras(extras)
                .build();
    }

    private Intent createFillInIntent(Uri uri, long imageTime) {
        Intent fillIn = new Intent();
        fillIn.setType("image/png");
        fillIn.putExtra(Intent.EXTRA_STREAM, uri);
        String subjectDate = DateFormat.getDateTimeInstance().format(new Date(imageTime));
        String subject = String.format(SCREENSHOT_SHARE_SUBJECT_TEMPLATE, subjectDate);
        fillIn.putExtra(Intent.EXTRA_SUBJECT, subject);
        // Include URI in ClipData also, so that grantPermission picks it up.
        // We don't use setData here because some apps interpret this as "to:".
        ClipData clipData = new ClipData(
                new ClipDescription("content", new String[]{"image/png"}),
                new ClipData.Item(uri));
        fillIn.setClipData(clipData);
        fillIn.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
        return fillIn;
    }

    /**
     * Query and surface Quick Share chip if it is available. Action intent would not be used,
     * because it does not contain image URL which would be populated in {@link
     * #createQuickShareAction(Context, Notification.Action, Uri)}
     * #createQuickShareAction(Notification.Action, String, Uri, long, Bitmap, UserHandle)}
     */
    private void queryQuickShareAction(Bitmap image, UserHandle user) {

    @VisibleForTesting
    Notification.Action queryQuickShareAction(
            String screenshotId, Bitmap image, UserHandle user, Uri uri) {
        CompletableFuture<List<Notification.Action>> quickShareActionsFuture =
                mScreenshotSmartActions.getSmartActionsFuture(
                        mScreenshotId, null, image, mSmartActionsProvider,
                        QUICK_SHARE_ACTION,
                        screenshotId, uri, image, mSmartActionsProvider, QUICK_SHARE_ACTION,
                        mSmartActionsEnabled, user);
        int timeoutMs = DeviceConfig.getInt(
                DeviceConfig.NAMESPACE_SYSTEMUI,
@@ -468,11 +487,11 @@ class SaveImageInBackgroundTask extends AsyncTask<Void, Void, Void> {
                500);
        List<Notification.Action> quickShareActions =
                mScreenshotSmartActions.getSmartActions(
                        mScreenshotId, quickShareActionsFuture, timeoutMs,
                        screenshotId, quickShareActionsFuture, timeoutMs,
                        mSmartActionsProvider, QUICK_SHARE_ACTION);
        if (!quickShareActions.isEmpty()) {
            mQuickShareData.quickShareAction = quickShareActions.get(0);
            mParams.mQuickShareActionsReadyListener.onActionsReady(mQuickShareData);
            return quickShareActions.get(0);
        }
        return null;
    }
}
+7 −1
Original line number Diff line number Diff line
@@ -57,6 +57,7 @@ import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
import android.os.RemoteException;
import android.provider.DeviceConfig;
import android.provider.Settings;
import android.util.DisplayMetrics;
import android.util.Log;
@@ -83,6 +84,7 @@ import android.widget.Toast;
import android.window.WindowContext;

import com.android.internal.app.ChooserActivity;
import com.android.internal.config.sysui.SystemUiDeviceConfigFlags;
import com.android.internal.logging.UiEventLogger;
import com.android.internal.policy.PhoneWindow;
import com.android.settingslib.applications.InterestingConfigChanges;
@@ -227,6 +229,7 @@ public class ScreenshotController {
    static final String EXTRA_SMART_ACTIONS_ENABLED = "android:smart_actions_enabled";
    static final String EXTRA_OVERRIDE_TRANSITION = "android:screenshot_override_transition";
    static final String EXTRA_ACTION_INTENT = "android:screenshot_action_intent";
    static final String EXTRA_ACTION_INTENT_FILLIN = "android:screenshot_action_intent_fillin";

    static final String SCREENSHOT_URI_ID = "android:screenshot_uri_id";
    static final String EXTRA_CANCEL_NOTIFICATION = "android:screenshot_cancel_notification";
@@ -867,8 +870,11 @@ public class ScreenshotController {
            mSaveInBgTask.setActionsReadyListener(this::logSuccessOnActionsReady);
        }

        boolean smartActionsEnabled = DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_SYSTEMUI,
                SystemUiDeviceConfigFlags.ENABLE_SCREENSHOT_NOTIFICATION_SMART_ACTIONS, true);

        mSaveInBgTask = new SaveImageInBackgroundTask(mContext, mImageExporter,
                mScreenshotSmartActions, data, getActionTransitionSupplier());
                mScreenshotSmartActions, data, getActionTransitionSupplier(), smartActionsEnabled);
        mSaveInBgTask.execute();
    }

+3 −1
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@ package com.android.systemui.screenshot;

import static com.android.systemui.screenshot.LogConfig.DEBUG_ACTIONS;
import static com.android.systemui.screenshot.ScreenshotController.EXTRA_ACTION_INTENT;
import static com.android.systemui.screenshot.ScreenshotController.EXTRA_ACTION_INTENT_FILLIN;
import static com.android.systemui.screenshot.ScreenshotController.EXTRA_ACTION_TYPE;
import static com.android.systemui.screenshot.ScreenshotController.EXTRA_ID;

@@ -47,6 +48,7 @@ public class SmartActionsReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        PendingIntent pendingIntent = intent.getParcelableExtra(EXTRA_ACTION_INTENT);
        Intent fillIn = intent.getParcelableExtra(EXTRA_ACTION_INTENT_FILLIN);
        String actionType = intent.getStringExtra(EXTRA_ACTION_TYPE);
        if (DEBUG_ACTIONS) {
            Log.d(TAG, "Executing smart action [" + actionType + "]:" + pendingIntent.getIntent());
@@ -54,7 +56,7 @@ public class SmartActionsReceiver extends BroadcastReceiver {
        ActivityOptions opts = ActivityOptions.makeBasic();

        try {
            pendingIntent.send(context, 0, null, null, null, null, opts.toBundle());
            pendingIntent.send(context, 0, fillIn, null, null, null, opts.toBundle());
        } catch (PendingIntent.CanceledException e) {
            Log.e(TAG, "Pending intent canceled", e);
        }
+274 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2023 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.systemui.screenshot

import android.app.Notification
import android.app.PendingIntent
import android.content.ComponentName
import android.content.Intent
import android.graphics.Bitmap
import android.graphics.drawable.Icon
import android.net.Uri
import android.os.UserHandle
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.screenshot.ScreenshotController.SaveImageInBackgroundData
import com.android.systemui.screenshot.ScreenshotNotificationSmartActionsProvider.ScreenshotSmartActionType
import java.util.concurrent.CompletableFuture
import java.util.function.Supplier
import org.junit.Assert.assertEquals
import org.junit.Assert.assertNull
import org.junit.Before
import org.junit.Test
import org.mockito.Mockito

@SmallTest
class SaveImageInBackgroundTaskTest : SysuiTestCase() {
    private val imageExporter = mock<ImageExporter>()
    private val smartActions = mock<ScreenshotSmartActions>()
    private val saveImageData = SaveImageInBackgroundData()
    private val sharedTransitionSupplier =
        mock<Supplier<ScreenshotController.SavedImageData.ActionTransition>>()
    private val testScreenshotId: String = "testScreenshotId"
    private val testBitmap = mock<Bitmap>()
    private val testUser = UserHandle.getUserHandleForUid(0)
    private val testIcon = mock<Icon>()
    private val testImageTime = 1234.toLong()

    private val smartActionsUriFuture = mock<CompletableFuture<List<Notification.Action>>>()
    private val smartActionsFuture = mock<CompletableFuture<List<Notification.Action>>>()

    private val testUri: Uri = Uri.parse("testUri")
    private val intent =
        Intent(Intent.ACTION_SEND)
            .setComponent(
                ComponentName.unflattenFromString(
                    "com.google.android.test/com.google.android.test.TestActivity"
                )
            )
    private val immutablePendingIntent =
        PendingIntent.getBroadcast(
            mContext,
            0,
            intent,
            PendingIntent.FLAG_CANCEL_CURRENT or PendingIntent.FLAG_IMMUTABLE
        )
    private val mutablePendingIntent =
        PendingIntent.getBroadcast(
            mContext,
            0,
            intent,
            PendingIntent.FLAG_CANCEL_CURRENT or PendingIntent.FLAG_MUTABLE
        )

    private val saveImageTask =
        SaveImageInBackgroundTask(
            mContext,
            imageExporter,
            smartActions,
            saveImageData,
            sharedTransitionSupplier,
            false, // forces a no-op implementation; we're mocking out the behavior anyway
        )

    @Before
    fun setup() {
        Mockito.`when`(
                smartActions.getSmartActionsFuture(
                    Mockito.eq(testScreenshotId),
                    Mockito.any(Uri::class.java),
                    Mockito.eq(testBitmap),
                    Mockito.any(ScreenshotNotificationSmartActionsProvider::class.java),
                    Mockito.any(ScreenshotSmartActionType::class.java),
                    Mockito.any(Boolean::class.java),
                    Mockito.eq(testUser)
                )
            )
            .thenReturn(smartActionsUriFuture)
        Mockito.`when`(
                smartActions.getSmartActionsFuture(
                    Mockito.eq(testScreenshotId),
                    Mockito.eq(null),
                    Mockito.eq(testBitmap),
                    Mockito.any(ScreenshotNotificationSmartActionsProvider::class.java),
                    Mockito.any(ScreenshotSmartActionType::class.java),
                    Mockito.any(Boolean::class.java),
                    Mockito.eq(testUser)
                )
            )
            .thenReturn(smartActionsFuture)
    }

    @Test
    fun testQueryQuickShare_noAction() {
        Mockito.`when`(
                smartActions.getSmartActions(
                    Mockito.eq(testScreenshotId),
                    Mockito.eq(smartActionsFuture),
                    Mockito.any(Int::class.java),
                    Mockito.any(ScreenshotNotificationSmartActionsProvider::class.java),
                    Mockito.eq(ScreenshotSmartActionType.QUICK_SHARE_ACTION)
                )
            )
            .thenReturn(ArrayList<Notification.Action>())

        val quickShareAction =
            saveImageTask.queryQuickShareAction(testScreenshotId, testBitmap, testUser, testUri)

        assertNull(quickShareAction)
    }

    @Test
    fun testQueryQuickShare_withActions() {
        val actions = ArrayList<Notification.Action>()
        actions.add(constructAction("Action One", mutablePendingIntent))
        actions.add(constructAction("Action Two", mutablePendingIntent))
        Mockito.`when`(
                smartActions.getSmartActions(
                    Mockito.eq(testScreenshotId),
                    Mockito.eq(smartActionsUriFuture),
                    Mockito.any(Int::class.java),
                    Mockito.any(ScreenshotNotificationSmartActionsProvider::class.java),
                    Mockito.eq(ScreenshotSmartActionType.QUICK_SHARE_ACTION)
                )
            )
            .thenReturn(actions)

        val quickShareAction =
            saveImageTask.queryQuickShareAction(testScreenshotId, testBitmap, testUser, testUri)!!

        assertEquals("Action One", quickShareAction.title)
        assertEquals(mutablePendingIntent, quickShareAction.actionIntent)
    }

    @Test
    fun testCreateQuickShareAction_originalWasNull_returnsNull() {
        val quickShareAction =
            saveImageTask.createQuickShareAction(
                null,
                testScreenshotId,
                testUri,
                testImageTime,
                testBitmap,
                testUser
            )

        assertNull(quickShareAction)
    }

    @Test
    fun testCreateQuickShareAction_immutableIntentDifferentAction_returnsNull() {
        val actions = ArrayList<Notification.Action>()
        actions.add(constructAction("New Test Action", immutablePendingIntent))
        Mockito.`when`(
                smartActions.getSmartActions(
                    Mockito.eq(testScreenshotId),
                    Mockito.eq(smartActionsUriFuture),
                    Mockito.any(Int::class.java),
                    Mockito.any(ScreenshotNotificationSmartActionsProvider::class.java),
                    Mockito.eq(ScreenshotSmartActionType.QUICK_SHARE_ACTION)
                )
            )
            .thenReturn(actions)
        val origAction = constructAction("Old Test Action", immutablePendingIntent)

        val quickShareAction =
            saveImageTask.createQuickShareAction(
                origAction,
                testScreenshotId,
                testUri,
                testImageTime,
                testBitmap,
                testUser,
            )

        assertNull(quickShareAction)
    }

    @Test
    fun testCreateQuickShareAction_mutableIntent_returnsSafeIntent() {
        val actions = ArrayList<Notification.Action>()
        val action = constructAction("Action One", mutablePendingIntent)
        actions.add(action)
        Mockito.`when`(
                smartActions.getSmartActions(
                    Mockito.eq(testScreenshotId),
                    Mockito.eq(smartActionsUriFuture),
                    Mockito.any(Int::class.java),
                    Mockito.any(ScreenshotNotificationSmartActionsProvider::class.java),
                    Mockito.eq(ScreenshotSmartActionType.QUICK_SHARE_ACTION)
                )
            )
            .thenReturn(actions)

        val quickShareAction =
            saveImageTask.createQuickShareAction(
                constructAction("Test Action", mutablePendingIntent),
                testScreenshotId,
                testUri,
                testImageTime,
                testBitmap,
                testUser
            )
        val quickSharePendingIntent : PendingIntent =
            quickShareAction.actionIntent.intent.extras!!.getParcelable(
                ScreenshotController.EXTRA_ACTION_INTENT)!!

        assertEquals("Test Action", quickShareAction.title)
        assertEquals(mutablePendingIntent, quickSharePendingIntent)
    }

    @Test
    fun testCreateQuickShareAction_immutableIntent_returnsSafeIntent() {
        val actions = ArrayList<Notification.Action>()
        val action = constructAction("Test Action", immutablePendingIntent)
        actions.add(action)
        Mockito.`when`(
                smartActions.getSmartActions(
                    Mockito.eq(testScreenshotId),
                    Mockito.eq(smartActionsUriFuture),
                    Mockito.any(Int::class.java),
                    Mockito.any(ScreenshotNotificationSmartActionsProvider::class.java),
                    Mockito.eq(ScreenshotSmartActionType.QUICK_SHARE_ACTION)
                )
            )
            .thenReturn(actions)

        val quickShareAction =
            saveImageTask.createQuickShareAction(
                constructAction("Test Action", immutablePendingIntent),
                testScreenshotId,
                testUri,
                testImageTime,
                testBitmap,
                testUser,
            )!!
        val quickSharePendingIntent : PendingIntent =
            quickShareAction.actionIntent.intent.extras!!.getParcelable(
                ScreenshotController.EXTRA_ACTION_INTENT)!!

        assertEquals("Test Action", quickShareAction.title)
        assertEquals(immutablePendingIntent, quickSharePendingIntent)
    }

    private fun constructAction(title: String, intent: PendingIntent): Notification.Action {
        return Notification.Action.Builder(testIcon, title, intent).build()
    }

    inline fun <reified T : Any> mock(apply: T.() -> Unit = {}): T =
        Mockito.mock(T::class.java).apply(apply)
}
+3 −3
Original line number Diff line number Diff line
@@ -183,7 +183,7 @@ public class ScreenshotNotificationSmartActionsTest extends SysuiTestCase {
        data.mActionsReadyListener = null;
        SaveImageInBackgroundTask task =
                new SaveImageInBackgroundTask(mContext, null, mScreenshotSmartActions, data,
                        ActionTransition::new);
                        ActionTransition::new, false);

        Notification.Action shareAction = task.createShareAction(mContext, mContext.getResources(),
                Uri.parse("Screenshot_123.png")).get().action;
@@ -211,7 +211,7 @@ public class ScreenshotNotificationSmartActionsTest extends SysuiTestCase {
        data.mActionsReadyListener = null;
        SaveImageInBackgroundTask task =
                new SaveImageInBackgroundTask(mContext, null, mScreenshotSmartActions, data,
                        ActionTransition::new);
                        ActionTransition::new, false);

        Notification.Action editAction = task.createEditAction(mContext, mContext.getResources(),
                Uri.parse("Screenshot_123.png")).get().action;
@@ -239,7 +239,7 @@ public class ScreenshotNotificationSmartActionsTest extends SysuiTestCase {
        data.mActionsReadyListener = null;
        SaveImageInBackgroundTask task =
                new SaveImageInBackgroundTask(mContext, null, mScreenshotSmartActions, data,
                        ActionTransition::new);
                        ActionTransition::new, false);

        Notification.Action deleteAction = task.createDeleteAction(mContext,
                mContext.getResources(),