chromium/chrome/android/webapk/shell_apk/src/org/chromium/webapk/shell_apk/NotificationPermissionRequestActivity.java

// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

package org.chromium.webapk.shell_apk;

import android.Manifest;
import android.app.Activity;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.os.Build;
import android.os.Bundle;
import android.os.Message;
import android.os.Messenger;
import android.os.RemoteException;
import android.util.Log;

/**
 * A simple transparent activity for requesting the notification permission. On either approve or
 * disapprove, this will send the result via the {@link Messenger} provided with the intent, and
 * then finish.
 */
public class NotificationPermissionRequestActivity extends Activity {
    private static final String TAG = "PermissionRequestActivity";

    // An intent extra for a notification channel name string.
    private static final String EXTRA_NOTIFICATION_CHANNEL_NAME = "notificationChannelName";

    // An intent extra for a notification channel id string.
    private static final String EXTRA_NOTIFICATION_CHANNEL_ID = "notificationChannelId";

    // An intent extra for a {@link Messenger}.
    private static final String EXTRA_MESSENGER = "messenger";

    // A bundle key for a {@link PermissionStatus}.
    private static final String KEY_PERMISSION_STATUS = "permissionStatus";

    private String mChannelName;
    private String mChannelId;
    private Messenger mMessenger;

    /**
     * Creates a {@link PendingIntent} for launching this activity to request the notification
     * permission. It is mutable so that a messenger extra can be added for returning the permission
     * request result.
     */
    public static PendingIntent createPermissionRequestPendingIntent(
            Context context, String channelName, String channelId) {
        Intent intent =
                new Intent(
                        context.getApplicationContext(),
                        NotificationPermissionRequestActivity.class);
        intent.putExtra(EXTRA_NOTIFICATION_CHANNEL_NAME, channelName);
        intent.putExtra(EXTRA_NOTIFICATION_CHANNEL_ID, channelId);
        // Starting with Build.VERSION_CODES.S it is required to explicitly specify the mutability
        // of PendingIntents.
        int flags = Build.VERSION.SDK_INT >= Build.VERSION_CODES.S ? PendingIntent.FLAG_MUTABLE : 0;
        return PendingIntent.getActivity(context.getApplicationContext(), 0, intent, flags);
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) {
            Log.w(TAG, "Cannot request notification permission before Android T.");
            finish();
            return;
        }

        mChannelName = getIntent().getStringExtra(EXTRA_NOTIFICATION_CHANNEL_NAME);
        mChannelId = getIntent().getStringExtra(EXTRA_NOTIFICATION_CHANNEL_ID);
        mMessenger = getIntent().getParcelableExtra(EXTRA_MESSENGER);
        if (mChannelName == null || mChannelId == null || mMessenger == null) {
            Log.w(TAG, "Finishing because not all required extras were provided.");
            finish();
            return;
        }

        // When running on T or greater, with the app targeting less than T, creating a channel for
        // the first time will trigger the permission dialog.
        if (getApplicationContext().getApplicationInfo().targetSdkVersion
                < Build.VERSION_CODES.TIRAMISU) {
            NotificationChannel channel =
                    new NotificationChannel(
                            mChannelId, mChannelName, NotificationManager.IMPORTANCE_DEFAULT);
            getNotificationManager().createNotificationChannel(channel);
        }

        requestPermissions(new String[] {Manifest.permission.POST_NOTIFICATIONS}, 0);
    }

    @Override
    public void onRequestPermissionsResult(
            int requestCode, String[] permissions, int[] grantResults) {
        boolean enabled = false;
        for (int i = 0; i < permissions.length; i++) {
            if (!permissions[i].equals(Manifest.permission.POST_NOTIFICATIONS)) continue;

            PrefUtils.setHasRequestedNotificationPermission(this);
            enabled = grantResults[i] == PackageManager.PERMISSION_GRANTED;
            break;
        }

        // This method will only receive the notification permission and its grant result when
        // running on and targeting >= T. Check whether notifications are actually enabled, perhaps
        // because the system displayed a permission dialog after the first notification channel was
        // created and the user approved it.
        if (!enabled) {
            enabled = getNotificationManager().areNotificationsEnabled();
        }

        sendPermissionMessage(mMessenger, enabled);
        finish();
    }

    /** Sends a message to the messenger containing the permission status. */
    private static void sendPermissionMessage(Messenger messenger, boolean enabled) {
        Bundle data = new Bundle();
        @PermissionStatus int status = enabled ? PermissionStatus.ALLOW : PermissionStatus.BLOCK;
        data.putInt(KEY_PERMISSION_STATUS, status);
        Message message = Message.obtain();
        message.setData(data);

        try {
            messenger.send(message);
        } catch (RemoteException e) {
            e.printStackTrace();
        }
    }

    private NotificationManager getNotificationManager() {
        return (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
    }
}