Clicking Android Notification Actions does not close Notification drawer

AndroidAndroid IntentAndroid Notifications

Android Problem Overview


I am adding a Notification to System bar using the NotificationCompat library. This Notification has two action buttons. Also, AutoCancel() property on the Notification is set to true.

On Click of the action buttons, System is configured to launch an IntentService which calls NotificationManager.cancel(NOTIFICATION_ID) and then launches an Activity in a New Task.
Problem is that though this call removes the notification from the tray, it does not collapse the drawer. The called Activity is drawn behind the drawer.

Can someone please shed some light on what special code is need to close the draw apart from canceling the notification?

Android Solutions


Solution 1 - Android

If your action is in the form of a broadcast or a service but you intend for the notification drawer to collapse, you should broadcast android.intent.action.CLOSE_SYSTEM_DIALOGS from your onReceive. This will manually close the drawer.

Solution 2 - Android

I found that when you use the action buttons in expanded notifications, you have to write extra code and you are more constrained.

Prior to using expanded notifications, the default action in my file download notification was to start a VIEW activity on the file. The VIEW intent was wrapped by a Chooser intent. I couldn't use a pending intent for the Chooser intent directly from the notification because the Chooser would crash if there was no activity to view the file type. So I had a BroadcastReceiver that would start the Chooser intent.

With expanded notifications, I decided to change the file download notification so the default action is to show the file details activity, with action buttons for View and Send. As noted by user2536953, starting a broadcast receiver from the notification does not close the notification drawer. Based on his information that an activity would close the drawer, I changed my broadcast receiver to a NotificationActivity without any UI.

As indicated in this post How to dismiss Android notification after action has been clicked, another issue is that you have to manually cancel your notification when the user clicks an action button. The notification is only cancelled automatically for the default action. I also added code in NotificationActivity to handle this.

Building the expanded notification with view and send buttons:

    NotificationCompat.Builder builder = new NotificationCompat.Builder(m_context).setAutoCancel(true);

    final PendingIntent contentIntent = DownloadedFileIntentUtils.buildPendingItemDetailIntent(m_context, item);
        builder.setContentIntent(contentIntent);
        
    PendingIntent viewIntent = DownloadedFileIntentUtils.buildNotificationActionIntent(m_context, Intent.ACTION_VIEW,
                m_context.getString(R.string.action_open), uri, MimeTypeUtil.getMimeType(item), id);
    builder.addAction(R.drawable.actionbar_open_with, m_context.getString(R.string.action_open), viewIntent);

    PendingIntent sendIntent = DownloadedFileIntentUtils.buildNotificationActionIntent(m_context, Intent.ACTION_SEND,
                m_context.getString(R.string.action_send), uri, MimeTypeUtil.getMimeType(item), id);
    builder.addAction(R.drawable.actionbar_share, m_context.getString(R.string.action_send), sendIntent);

    builder.setTicker(title)
    .setContentTitle(title)
    .setContentText(text)
    .setSmallIcon(R.drawable.notification_download);
    .setStyle(new NotificationCompat.BigTextStyle().bigText(text));

    getNotificationManager().notify(id, builder.build());

Building the intent to start an activity from the notification action buttons:

    public static PendingIntent buildNotificationActionIntent(Context context, String action, String actionTitle, Uri uri,
        String mimeType, int notificationId) {
    // Build the file action intent (e.g. VIEW or SEND) that we eventually want to start.
    final Intent fileIntent = buildFileActionIntent(action, actionTitle, uri, mimeType);

    // Build the intent to start the NotificationActivity.
    final Intent notificationIntent = new Intent(context, NotificationActivity.class);
    // This flag must be set on activities started from a notification.
    notificationIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    // Pass the file action and notification id to the NotificationActivity.
    notificationIntent.putExtra(Intent.EXTRA_INTENT, fileIntent);
    notificationIntent.putExtra(IIntentCode.INTENT_EXTRA_NOTIFICATION_ID, notificationId);

    // Return a pending intent to pass to the notification manager.
    return PendingIntent.getActivity(context, s_intentCode.getAndIncrement(), notificationIntent, PendingIntent.FLAG_ONE_SHOT);
}

public static Intent buildFileActionIntent(String action, String actionTitle, 
        Uri uri, String mimeType) {
    Intent intent = new Intent(action);
    intent.addCategory(Intent.CATEGORY_DEFAULT);
    
    if (action.equals(Intent.ACTION_SEND)) {
        intent.putExtra(Intent.EXTRA_STREAM, uri);
        intent.setType(mimeType);
    } else {
        intent.setDataAndType(uri, mimeType);
    }

    intent.putExtra(Intent.EXTRA_TITLE, actionTitle);

    // Grant read permission on the file to other apps without declared permission.
    int flags = Intent.FLAG_GRANT_READ_URI_PERMISSION;
    intent.setFlags(flags);
    
    return intent;
}

Notification activity without any UI:

public class NotificationActivity extends Activity {
private final static Logger s_logger = LogUtil.getLogger(NotificationActivity.class);

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

    Intent intent = getIntent();

    // Cancel the notification that initiated this activity.
    // This is required when using the action buttons in expanded notifications.
    // While the default action automatically closes the notification, the
    // actions initiated by buttons do not.
    int notificationId = intent.getIntExtra(IIntentCode.INTENT_EXTRA_NOTIFICATION_ID, -1);
    if (notificationId != -1) {
        NotificationManager manager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
        manager.cancel(notificationId);
    }

    // If there is an activity to handle the action, start the file action.
    if (DownloadedFileIntentUtils.verifyActivityIsAvailable(this, fileActionIntent, false)) {
            fileActionIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            DownloadedFileIntentUtils.startFileActionActivity(this, fileActionIntent);
    }

    // Finish activity.
    finish();
}

public static void startFileActionActivity(Context context, Intent fileActionIntent) {
    // Start chooser intent.
    Intent chooser = Intent.createChooser(fileActionIntent, fileActionIntent.getStringExtra(Intent.EXTRA_TITLE));

    // Copy the flags from fileActionIntent to chooser intent.
    // FileActionExecutor must set FLAG_ACTIVITY_NEW_TASK on the intent passed to startActivity
    // because the flag is required when starting an activity from a context that is not an activity.
    chooser.addFlags(fileActionIntent.getFlags());

    context.startActivity(chooser);
}

Don't forget to add NotificationActivity to AndroidManifest.xml.

Solution 3 - Android

While I thoroughly appreciate that Soumyajyoti's answer should be correct... it is in fact not...

i am using

Intent CR = new Intent(CRCODE); 
PendingIntent.getBroadcast(getApplicationContext(), MY_ID, CR, 0);

in a remoteview layout for an ongoing notification...

i can assure you that it does not close the drawer but does fire the intent and draw the activity behind the opened drawer, as well as performing the other tasks that i have assigned to my receiver...

i have tested both getActivity, and getService (neither of which will work in my circumstance, i need to fire multiple intents onRecieve) and both of them close the drawer properly...

I know that this is not an answer, but when and if i find it i will report back to edit this...

crazy thought... perhaps an activity with no content view could be called as a broadcast receiver which would fire the appropriate intents to other classes or apps as required...

the crazy thought listed above works... start an activity with PendingIntent.getActivity and use it to relay broadcasts or other intents then finish itself... the effect is not direct but imperceptible to the end user

Solution 4 - Android

The android system collapses the notification drawer for you whenever you click on a notification and launch an activity or broadcast. I don't think there are any programmatic way to close the notification drawer by your code. I suggest that you check the intents that you pass to the notification builder and make sure that they are given correct reference intents. I think something inside the android notification manager is getting blocked due to the intent you provide. So far i have not seen the notification drawer staying open once the action is triggered from the notification. Just curious to know whether your target activity is having a semitransparent area where the previous activity is visible, if it is then i suggest you make the background completely opaque (having no transparent/semi transparent region). May be that is preventing the android home launcher to complete stop sequence and thus not letting launcher to close the notification drawer for you. Hope I was able to help you. All the best.

Solution 5 - Android

try this:

    NotificationManager notificationManager = (NotificationManager) getApplicationContext().getSystemService(getApplicationContext().NOTIFICATION_SERVICE);
    Intent notificationIntent = new Intent(this.getBaseContext(), MainActivity.class);
    notificationIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
    PendingIntent pendingIntent = PendingIntent.getActivity(getApplicationContext(), 0, notificationIntent, PendingIntent.FLAG_UPDATE_CURRENT);
    NotificationCompat.Builder mNotifyBuilder = (NotificationCompat.Builder) new NotificationCompat.Builder(
            getApplicationContext())
            .setTicker(getApplicationContext().getText(R.string.app_name))
            .setContentTitle(getApplicationContext().getText(R.string.app_name))
            .setContentText(getApplicationContext().getText(R.string.text))
            .setSmallIcon(R.drawable.smallicon)
            .setLargeIcon(BitmapFactory.decodeResource(getApplicationContext().getResources(), R.mipmap.ic_launcher))
            .setContentIntent(pendingIntent)
            .setAutoCancel(true)
            .setVibrate(new long[]{150, 300});
    mNotifyBuilder.build().flags |= Notification.FLAG_AUTO_CANCEL;
    notificationManager.notify(1, mNotifyBuilder.build());

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionAsterView Question on Stackoverflow
Solution 1 - AndroidAndro IdView Answer on Stackoverflow
Solution 2 - AndroidVickiView Answer on Stackoverflow
Solution 3 - Androidme_View Answer on Stackoverflow
Solution 4 - AndroidSoumyajyoti SahaView Answer on Stackoverflow
Solution 5 - AndroidRômulo Z. C. CunhaView Answer on Stackoverflow