public final class

PendingIntentCompat

extends java.lang.Object

 java.lang.Object

↳androidx.core.app.PendingIntentCompat

Gradle dependencies

compile group: 'androidx.core', name: 'core', version: '1.15.0-alpha02'

  • groupId: androidx.core
  • artifactId: core
  • version: 1.15.0-alpha02

Artifact androidx.core:core:1.15.0-alpha02 it located at Google repository (https://maven.google.com/)

Androidx artifact mapping:

androidx.core:core com.android.support:support-compat

Overview

Helper for accessing features in PendingIntent.

Summary

Methods
public static PendingIntentgetActivities(Context context, int requestCode, Intent intents[], int flags, boolean isMutable)

Retrieves a PendingIntent with mandatory mutability flag set on supported platform versions.

public static PendingIntentgetActivities(Context context, int requestCode, Intent intents[], int flags, Bundle options, boolean isMutable)

Retrieves a PendingIntent with mandatory mutability flag set on supported platform versions.

public static PendingIntentgetActivity(Context context, int requestCode, Intent intent, int flags, boolean isMutable)

Retrieves a PendingIntent with mandatory mutability flag set on supported platform versions.

public static PendingIntentgetActivity(Context context, int requestCode, Intent intent, int flags, Bundle options, boolean isMutable)

Retrieves a PendingIntent with mandatory mutability flag set on supported platform versions.

public static PendingIntentgetBroadcast(Context context, int requestCode, Intent intent, int flags, boolean isMutable)

Retrieves a PendingIntent with mandatory mutability flag set on supported platform versions.

public static PendingIntentgetForegroundService(Context context, int requestCode, Intent intent, int flags, boolean isMutable)

Retrieves a PendingIntent with mandatory mutability flag set on supported platform versions.

public static PendingIntentgetService(Context context, int requestCode, Intent intent, int flags, boolean isMutable)

Retrieves a PendingIntent with mandatory mutability flag set on supported platform versions.

public static voidsend(PendingIntent pendingIntent, Context context, int code, Intent intent, PendingIntent.OnFinished onFinished, Handler handler)

PendingIntent variants that support callbacks have a bug on many API levels that the callback may be invoked even if the PendingIntent was never sent (ie, such as if the PendingIntent was canceled, and the send() invocation threw a ).

public static voidsend(PendingIntent pendingIntent, Context context, int code, Intent intent, PendingIntent.OnFinished onFinished, Handler handler, java.lang.String requiredPermissions, Bundle options)

PendingIntent variants that support callbacks have a bug on many API levels that the callback may be invoked even if the PendingIntent was never sent (ie, such as if the PendingIntent was canceled, and the send() invocation threw a ).

public static voidsend(PendingIntent pendingIntent, int code, PendingIntent.OnFinished onFinished, Handler handler)

PendingIntent variants that support callbacks have a bug on many API levels that the callback may be invoked even if the PendingIntent was never sent (ie, such as if the PendingIntent was canceled, and the send() invocation threw a ).

from java.lang.Objectclone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait

Methods

public static PendingIntent getActivities(Context context, int requestCode, Intent intents[], int flags, Bundle options, boolean isMutable)

Retrieves a PendingIntent with mandatory mutability flag set on supported platform versions. The caller provides the flag as combination of all the other values except mutability flag. This method combines mutability flag when necessary. See PendingIntent.

public static PendingIntent getActivities(Context context, int requestCode, Intent intents[], int flags, boolean isMutable)

Retrieves a PendingIntent with mandatory mutability flag set on supported platform versions. The caller provides the flag as combination of all the other values except mutability flag. This method combines mutability flag when necessary. See PendingIntent.

public static PendingIntent getActivity(Context context, int requestCode, Intent intent, int flags, boolean isMutable)

Retrieves a PendingIntent with mandatory mutability flag set on supported platform versions. The caller provides the flag as combination of all the other values except mutability flag. This method combines mutability flag when necessary.

Returns:

Returns an existing or new PendingIntent matching the given parameters. May return null only if PendingIntent has been supplied.

See also: PendingIntent

public static PendingIntent getActivity(Context context, int requestCode, Intent intent, int flags, Bundle options, boolean isMutable)

Retrieves a PendingIntent with mandatory mutability flag set on supported platform versions. The caller provides the flag as combination of all the other values except mutability flag. This method combines mutability flag when necessary.

Returns:

Returns an existing or new PendingIntent matching the given parameters. May return null only if PendingIntent has been supplied.

See also: PendingIntent

public static PendingIntent getBroadcast(Context context, int requestCode, Intent intent, int flags, boolean isMutable)

Retrieves a PendingIntent with mandatory mutability flag set on supported platform versions. The caller provides the flag as combination of all the other values except mutability flag. This method combines mutability flag when necessary.

Returns:

Returns an existing or new PendingIntent matching the given parameters. May return null only if PendingIntent has been supplied.

See also: PendingIntent

public static PendingIntent getForegroundService(Context context, int requestCode, Intent intent, int flags, boolean isMutable)

Retrieves a PendingIntent with mandatory mutability flag set on supported platform versions. The caller provides the flag as combination of all the other values except mutability flag. This method combines mutability flag when necessary. See PendingIntent .

public static PendingIntent getService(Context context, int requestCode, Intent intent, int flags, boolean isMutable)

Retrieves a PendingIntent with mandatory mutability flag set on supported platform versions. The caller provides the flag as combination of all the other values except mutability flag. This method combines mutability flag when necessary.

Returns:

Returns an existing or new PendingIntent matching the given parameters. May return null only if PendingIntent has been supplied.

See also: PendingIntent

public static void send(PendingIntent pendingIntent, int code, PendingIntent.OnFinished onFinished, Handler handler)

PendingIntent variants that support callbacks have a bug on many API levels that the callback may be invoked even if the PendingIntent was never sent (ie, such as if the PendingIntent was canceled, and the send() invocation threw a ). Using this compatibility method fixes that bug and guarantees that callbacks will only be invoked if send() completed successfully.

See PendingIntent.

public static void send(PendingIntent pendingIntent, Context context, int code, Intent intent, PendingIntent.OnFinished onFinished, Handler handler)

PendingIntent variants that support callbacks have a bug on many API levels that the callback may be invoked even if the PendingIntent was never sent (ie, such as if the PendingIntent was canceled, and the send() invocation threw a ). Using this compatibility method fixes that bug and guarantees that callbacks will only be invoked if send() completed successfully.

See PendingIntent.

public static void send(PendingIntent pendingIntent, Context context, int code, Intent intent, PendingIntent.OnFinished onFinished, Handler handler, java.lang.String requiredPermissions, Bundle options)

PendingIntent variants that support callbacks have a bug on many API levels that the callback may be invoked even if the PendingIntent was never sent (ie, such as if the PendingIntent was canceled, and the send() invocation threw a ). Using this compatibility method fixes that bug and guarantees that callbacks will only be invoked if send() completed successfully.

See PendingIntent

Source

/*
 * 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 androidx.core.app;

import static android.app.PendingIntent.FLAG_IMMUTABLE;
import static android.app.PendingIntent.FLAG_MUTABLE;

import android.annotation.SuppressLint;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.os.Build.VERSION;
import android.os.Build.VERSION_CODES;
import android.os.Bundle;
import android.os.Handler;

import androidx.annotation.IntDef;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;
import androidx.annotation.RestrictTo;

import java.io.Closeable;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.concurrent.CountDownLatch;

/** Helper for accessing features in {@link PendingIntent}. */
public final class PendingIntentCompat {

    @IntDef(
            flag = true,
            value = {
                PendingIntent.FLAG_ONE_SHOT,
                PendingIntent.FLAG_NO_CREATE,
                PendingIntent.FLAG_CANCEL_CURRENT,
                PendingIntent.FLAG_UPDATE_CURRENT,
                Intent.FILL_IN_ACTION,
                Intent.FILL_IN_DATA,
                Intent.FILL_IN_CATEGORIES,
                Intent.FILL_IN_COMPONENT,
                Intent.FILL_IN_PACKAGE,
                Intent.FILL_IN_SOURCE_BOUNDS,
                Intent.FILL_IN_SELECTOR,
                Intent.FILL_IN_CLIP_DATA
            })
    @Retention(RetentionPolicy.SOURCE)
    @RestrictTo(RestrictTo.Scope.LIBRARY)
    public @interface Flags {}

    /**
     * Retrieves a {@link PendingIntent} with mandatory mutability flag set on supported platform
     * versions. The caller provides the flag as combination of all the other values except
     * mutability flag. This method combines mutability flag when necessary. See {@link
     * PendingIntent#getActivities(Context, int, Intent[], int, Bundle)}.
     */
    public static @NonNull PendingIntent getActivities(
            @NonNull Context context,
            int requestCode,
            @NonNull @SuppressLint("ArrayReturn") Intent[] intents,
            @Flags int flags,
            @Nullable Bundle options,
            boolean isMutable) {
        return PendingIntent.getActivities(context, requestCode, intents,
                addMutabilityFlags(isMutable, flags), options);
    }

    /**
     * Retrieves a {@link PendingIntent} with mandatory mutability flag set on supported platform
     * versions. The caller provides the flag as combination of all the other values except
     * mutability flag. This method combines mutability flag when necessary. See {@link
     * PendingIntent#getActivities(Context, int, Intent[], int, Bundle)}.
     */
    public static @NonNull PendingIntent getActivities(
            @NonNull Context context,
            int requestCode,
            @NonNull @SuppressLint("ArrayReturn") Intent[] intents,
            @Flags int flags,
            boolean isMutable) {
        return PendingIntent.getActivities(
                context, requestCode, intents, addMutabilityFlags(isMutable, flags));
    }

    /**
     * Retrieves a {@link PendingIntent} with mandatory mutability flag set on supported platform
     * versions. The caller provides the flag as combination of all the other values except
     * mutability flag. This method combines mutability flag when necessary.
     *
     * @return Returns an existing or new PendingIntent matching the given parameters. May return
     *         {@code null} only if {@link PendingIntent#FLAG_NO_CREATE} has been supplied.
     * @see PendingIntent#getActivity(Context, int, Intent, int)
     */
    public static @Nullable PendingIntent getActivity(
            @NonNull Context context,
            int requestCode,
            @NonNull Intent intent,
            @Flags int flags,
            boolean isMutable) {
        return PendingIntent.getActivity(
                context, requestCode, intent, addMutabilityFlags(isMutable, flags));
    }

    /**
     * Retrieves a {@link PendingIntent} with mandatory mutability flag set on supported platform
     * versions. The caller provides the flag as combination of all the other values except
     * mutability flag. This method combines mutability flag when necessary.
     *
     * @return Returns an existing or new PendingIntent matching the given parameters. May return
     *         {@code null} only if {@link PendingIntent#FLAG_NO_CREATE} has been supplied.
     * @see PendingIntent#getActivity(Context, int, Intent, int, Bundle)
     */
    public static @Nullable PendingIntent getActivity(
            @NonNull Context context,
            int requestCode,
            @NonNull Intent intent,
            @Flags int flags,
            @Nullable Bundle options,
            boolean isMutable) {
        return PendingIntent.getActivity(context, requestCode, intent,
                addMutabilityFlags(isMutable, flags), options);
    }

    /**
     * Retrieves a {@link PendingIntent} with mandatory mutability flag set on supported platform
     * versions. The caller provides the flag as combination of all the other values except
     * mutability flag. This method combines mutability flag when necessary.
     *
     * @return Returns an existing or new PendingIntent matching the given parameters. May return
     *         {@code null} only if {@link PendingIntent#FLAG_NO_CREATE} has been supplied.
     * @see PendingIntent#getBroadcast(Context, int, Intent, int)
     */
    public static @Nullable PendingIntent getBroadcast(
            @NonNull Context context,
            int requestCode,
            @NonNull Intent intent,
            @Flags int flags,
            boolean isMutable) {
        return PendingIntent.getBroadcast(
                context, requestCode, intent, addMutabilityFlags(isMutable, flags));
    }

    /**
     * Retrieves a {@link PendingIntent} with mandatory mutability flag set on supported platform
     * versions. The caller provides the flag as combination of all the other values except
     * mutability flag. This method combines mutability flag when necessary. See {@link
     * PendingIntent#getForegroundService(Context, int, Intent, int)} .
     */
    @RequiresApi(26)
    public static @NonNull PendingIntent getForegroundService(
            @NonNull Context context,
            int requestCode,
            @NonNull Intent intent,
            @Flags int flags,
            boolean isMutable) {
        return Api26Impl.getForegroundService(
                context, requestCode, intent, addMutabilityFlags(isMutable, flags));
    }

    /**
     * Retrieves a {@link PendingIntent} with mandatory mutability flag set on supported platform
     * versions. The caller provides the flag as combination of all the other values except
     * mutability flag. This method combines mutability flag when necessary.
     *
     * @return Returns an existing or new PendingIntent matching the given parameters. May return
     *         {@code null} only if {@link PendingIntent#FLAG_NO_CREATE} has been supplied.
     * @see PendingIntent#getService(Context, int, Intent, int)
     */
    public static @Nullable PendingIntent getService(
            @NonNull Context context,
            int requestCode,
            @NonNull Intent intent,
            @Flags int flags,
            boolean isMutable) {
        return PendingIntent.getService(
                context, requestCode, intent, addMutabilityFlags(isMutable, flags));
    }

    /**
     * {@link PendingIntent#send()} variants that support {@link PendingIntent.OnFinished} callbacks
     * have a bug on many API levels that the callback may be invoked even if the PendingIntent was
     * never sent (ie, such as if the PendingIntent was canceled, and the send() invocation threw a
     * {@link PendingIntent.CanceledException}). Using this compatibility method fixes that bug and
     * guarantees that {@link PendingIntent.OnFinished} callbacks will only be invoked if send()
     * completed successfully.
     *
     * <p>See {@link PendingIntent#send(int, PendingIntent.OnFinished, Handler)}.
     */
    @SuppressLint("LambdaLast")  // compat shim so arguments should be in the same order
    public static void send(
            @NonNull PendingIntent pendingIntent,
            int code,
            @Nullable PendingIntent.OnFinished onFinished,
            @Nullable Handler handler) throws PendingIntent.CanceledException {
        try (GatedCallback gatedCallback = new GatedCallback(onFinished)) {
            pendingIntent.send(code, gatedCallback.getCallback(), handler);
            gatedCallback.complete();
        }
    }

    /**
     * {@link PendingIntent#send()} variants that support {@link PendingIntent.OnFinished} callbacks
     * have a bug on many API levels that the callback may be invoked even if the PendingIntent was
     * never sent (ie, such as if the PendingIntent was canceled, and the send() invocation threw a
     * {@link PendingIntent.CanceledException}). Using this compatibility method fixes that bug and
     * guarantees that {@link PendingIntent.OnFinished} callbacks will only be invoked if send()
     * completed successfully.
     *
     * <p>See {@link PendingIntent#send(Context, int, Intent, PendingIntent.OnFinished, Handler)}.
     */
    @SuppressLint("LambdaLast")  // compat shim so arguments must be in the same order
    public static void send(
            @NonNull PendingIntent pendingIntent,
            // compat shim so arguments must be in the same order
            @SuppressLint("ContextFirst") @NonNull Context context,
            int code,
            @NonNull Intent intent,
            @Nullable PendingIntent.OnFinished onFinished,
            @Nullable Handler handler) throws PendingIntent.CanceledException {
        send(pendingIntent, context, code, intent, onFinished, handler, null, null);
    }

    /**
     * {@link PendingIntent#send()} variants that support {@link PendingIntent.OnFinished} callbacks
     * have a bug on many API levels that the callback may be invoked even if the PendingIntent was
     * never sent (ie, such as if the PendingIntent was canceled, and the send() invocation threw a
     * {@link PendingIntent.CanceledException}). Using this compatibility method fixes that bug and
     * guarantees that {@link PendingIntent.OnFinished} callbacks will only be invoked if send()
     * completed successfully.
     *
     * <p>See {@link
     * PendingIntent#send(Context, int, Intent, PendingIntent.OnFinished, Handler, String, Bundle)}
     */
    @SuppressLint("LambdaLast")  // compat shim so arguments must be in the same order
    public static void send(
            @NonNull PendingIntent pendingIntent,
            // compat shim so arguments must be in the same order
            @SuppressLint("ContextFirst") @NonNull Context context,
            int code,
            @NonNull Intent intent,
            @Nullable PendingIntent.OnFinished onFinished,
            @Nullable Handler handler,
            @Nullable String requiredPermissions,
            @Nullable Bundle options) throws PendingIntent.CanceledException {
        try (GatedCallback gatedCallback = new GatedCallback(onFinished)) {
            if (VERSION.SDK_INT >= VERSION_CODES.M) {
                Api23Impl.send(
                        pendingIntent,
                        context,
                        code,
                        intent,
                        onFinished,
                        handler,
                        requiredPermissions,
                        options);
            } else {
                pendingIntent.send(context, code, intent, gatedCallback.getCallback(), handler,
                        requiredPermissions);
            }
            gatedCallback.complete();
        }
    }

    private static int addMutabilityFlags(boolean isMutable, int flags) {
        if (isMutable) {
            if (VERSION.SDK_INT >= 31) {
                flags |= FLAG_MUTABLE;
            }
        } else {
            if (VERSION.SDK_INT >= 23) {
                flags |= FLAG_IMMUTABLE;
            }
        }

        return flags;
    }

    private PendingIntentCompat() {}

    @RequiresApi(23)
    private static class Api23Impl {
        private Api23Impl() {}

        public static void send(
                @NonNull PendingIntent pendingIntent,
                @NonNull Context context,
                int code,
                @NonNull Intent intent,
                @Nullable PendingIntent.OnFinished onFinished,
                @Nullable Handler handler,
                @Nullable String requiredPermission,
                @Nullable Bundle options) throws PendingIntent.CanceledException {
            pendingIntent.send(
                    context,
                    code,
                    intent,
                    onFinished,
                    handler,
                    requiredPermission,
                    options);
        }
    }

    @RequiresApi(26)
    private static class Api26Impl {
        private Api26Impl() {}

        public static PendingIntent getForegroundService(
                Context context, int requestCode, Intent intent, int flags) {
            return PendingIntent.getForegroundService(context, requestCode, intent, flags);
        }
    }

    // see b/201299281 for more info and context
    private static class GatedCallback implements Closeable {

        private final CountDownLatch mComplete = new CountDownLatch(1);

        @Nullable
        private PendingIntent.OnFinished mCallback;
        private boolean mSuccess;

        GatedCallback(@Nullable PendingIntent.OnFinished callback) {
            this.mCallback = callback;
            mSuccess = false;
        }

        @Nullable
        public PendingIntent.OnFinished getCallback() {
            if (mCallback == null) {
                return null;
            } else {
                return this::onSendFinished;
            }
        }

        public void complete() {
            mSuccess = true;
        }

        @Override
        public void close() {
            if (!mSuccess) {
                mCallback = null;
            }
            mComplete.countDown();
        }

        private void onSendFinished(
                PendingIntent pendingIntent,
                Intent intent,
                int resultCode,
                String resultData,
                Bundle resultExtras) {
            boolean interrupted = false;
            try {
                while (true) {
                    try {
                        mComplete.await();
                        break;
                    } catch (InterruptedException e) {
                        interrupted = true;
                    }
                }
            } finally {
                if (interrupted) {
                    Thread.currentThread().interrupt();
                }
            }

            if (mCallback != null) {
                mCallback.onSendFinished(
                        pendingIntent,
                        intent,
                        resultCode,
                        resultData,
                        resultExtras);
                mCallback = null;
            }
        }
    }
}