Android N:如何在分屏模式下点击通知时启动当前活动窗口而不是第二个窗口?

20

在使用分屏功能时,当用户通过点击通知来启动activity时,我希望能够在当前活动窗口中启动activity,但是Android N总是在第二个窗口中启动activity

NotificationCompat.Builder mBuilder =
                new NotificationCompat.Builder(this)
                        .setSmallIcon(R.drawable.notification)
                        .setAutoCancel(false)
                        .setContentTitle("Demo Title")
                        .setContentText("Demo");

Intent intent = new Intent(this, MainActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);
intent.putExtra("myIntent", "test");

PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
mBuilder.setContentIntent(pendingIntent);

NotificationManager mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);

Notification notification = mBuilder.build();

notification.flags = Notification.FLAG_NO_CLEAR;

mNotificationManager.notify(156, notification);

当获取到 intent 后,启动 activity

 Intent in = new Intent(MainActivity.this, SecondActivity.class);
 startActivity(in);

例如-我有两个应用程序在前景中,如第一个窗口的Chrome浏览器第二个窗口的Facebook,现在我正在Chrome浏览器中搜索某些内容,在这一刻,我收到了Gmail的通知。现在当我点击Gmail通知时,Gmail应用程序会在第二个窗口中打开,替换Facebook,但我希望我的应用程序通知可以替换用户交互的Chrome第一个窗口中。


就这段代码而言,不应该发生这种情况。您确定没有在“AndroidManifest.xml”中设置任何内容吗?除非使用像“FLAG_ACTIVITY_NEW_TASK”和“FLAG_ACTIVITY_LAUNCH_ADJACENT”这样的标志或在“<activity>”定义中使用“AndroidManifest.xml”等效项明确告知Android在单独的任务中启动活动(而单独的窗口是单独的任务),否则Android不会启动活动。 - Nohus
@Nohus 是的,我确定我没有在 AndroidManifest.xml 中设置任何影响此问题的内容。这不仅发生在我的应用程序上,任何类似 Gmail、Whatsapp 等应用程序中,当我单击这些应用程序的通知时,它们也会在 Android N 的分屏第二个窗口中打开,而不是当前活动窗口(当我正在与第一个活动窗口交互时)。 - Nikhil
无论是水平还是垂直多窗口,我的通知都会在活动窗口中打开,也就是我最近与之交互的窗口。如果你在 Chrome 中滚动然后点击通知,它仍然会在另一个窗口中打开吗? - Nohus
是的,我正在Nexus 7和Nexus 6P上检查它。它总是在第二个窗口中打开。无论我是在第一个窗口还是第二个窗口工作。 - Nikhil
你在<activity>标签的<layout>属性中使用android:gravity="top"了吗? - Pravin Divraniya
显示剩余10条评论
3个回答

5

你不能

在一个应用程序不属于的任务中(包括其他应用程序的多窗口窗口),无法通过Intent指定启动Activity,下面是几种可能的情况:

  1. 从另一个活动开始一个活动,它将在前一个活动的任务(和窗口)中启动。
  2. 您可以在意图中包含Intent.FLAG_ACTIVITY_LAUNCH_ADJACENT标志和Intent.FLAG_ACTIVITY_NEW_TASK标志,以在另一个窗口中启动Activity。这仅在系统已处于多窗口模式且不保证时才有效。如果系统处于自由形式模式(而不是分屏),则请求在另一个自由浮动窗口中启动Activity,然后您还可以使用.setLaunchBounds()来指定其大小。
  3. 从服务中启动活动,因为服务无法在任务中,您必须指定Intent.FLAG_ACTIVITY_NEW_TASK标志,系统会为活动启动新的任务。
  4. 从通知(PendingIntent)中启动活动,如下所示:
    • 您可以让Intent转到已经启动并在其中执行任何操作的活动。例如,使用Intent.FLAG_ACTIVITY_LAUNCH_ADJACENT在另一个窗口中启动活动。
    • 如果没有使用您的活动的任务/窗口,则系统将选择在哪里启动它,您无法控制。您可以使用.setLaunchBounds()控制在自由形式模式下启动活动的位置,但无法像您想要的那样劫持另一个应用程序的窗口。

    简而言之:您可以创建新窗口或更改已有的窗口,但无法使用其他应用程序的窗口。

    但是,如果您坚持

    控制您的新Activity在分屏多窗口中所占的屏幕的一侧,则创建一个新的虚拟活动。而不是启动您的SecondActivity,请启动虚拟活动。在其中,检查其启动的屏幕的哪一侧。我现在能想到的一种方法是在View上调用.getGlobalVisibleRect()并查看值与整个屏幕大小的比较情况。您可以通过以下方式获取屏幕大小:

    Display display = getWindowManager().getDefaultDisplay();
    Point size = new Point();
    display.getSize(size);
    int width = size.x;
    int height = size.y;
    

    您可以使用此解决方案来检测键盘大小以检测您窗口的位置。但这种方法更加hacky。

    如果您在所需屏幕侧面,请正常启动SecondActivity,并结束虚拟的Activity。如果您在错误的屏幕上,还要使用Intent.FLAG_ACTIVITY_LAUNCH_ADJACENT标志,您的Activity将在您想要的一侧启动,而虚拟的Activity会消失。

    这是一个肮脏的hack。我建议让系统自己选择启动Activity的位置。

    如果您总是想要替换已打开的浏览器

    那么让浏览器打开您的应用程序并占用其任务(和窗口)。您可以通过使用Intent打开链接来实现,浏览器将处理该链接,然后重定向到打开您的应用程序的链接,有关如何执行此操作的更多信息,请参见处理App Links启用深度链接。它应该能够正常工作。


1
我找到了一个符合我的需求的应用程序,https://play.google.com/store/apps/details?id=com.safeincloud&hl=en 当自动填充开启并且Chrome浏览器始终在第一窗口或第二窗口时,该应用程序会在Chrome浏览器上显示通知。我也想实现这个功能,但不知道如何做? - Nikhil
根据您所说的“现在,如果您在期望的屏幕侧面”,但是我无法理解如何知道哪个窗口是当前活动窗口,因为我的期望屏幕是当前活动屏幕。 - Nikhil
当您检查视图的全局坐标并且它们小于屏幕大小的一半时,您的 Activity 在左侧,否则在右侧。这适用于横屏模式,当纵向模式时,上下方向同理。 - Nohus
我认为你无法检测当前活动窗口,也许可以使用一些辅助功能API,就像我说的那样,系统已经在屏幕的活动侧开始新窗口。如果这对你不起作用,那么这是不寻常的。 - Nohus
用户应该完全控制是否要在第一个窗口或第二个窗口中打开活动。这取决于他们的逻辑。用户决定场景。不应该需要任何黑客手段。 - M. Usman Khan

2

您能检查以下代码吗:

private void Notify(String notificationMessage, String pushFullMessage) {

    Intent intent = new Intent(this, GCMNotificationActivity.class);
    intent.putExtra("pushNotification", pushFullMessage);
    intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
    final int not_nu = generateRandom();
    PendingIntent pendingIntent = PendingIntent.getActivity(this,
            not_nu, intent, PendingIntent.FLAG_ONE_SHOT);


    android.support.v4.app.NotificationCompat.Builder notificationBuilder = new android.support.v4.app.NotificationCompat.Builder(
            this)
            .setSmallIcon(R.drawable.app_logo) //Small Icon from drawable
            .setContentTitle(this.getString(R.string.app_name))
            .setContentText(notificationMessage)
            .setAutoCancel(true)
            .setLocalOnly(true)
            .setColor(this.getResources().getColor(R.color.green))
            .setStyle(
                    new android.support.v4.app.NotificationCompat.BigTextStyle().bigText(notificationMessage))
//       .setLargeIcon(BitmapFactory.decodeResource(this.getResources(), R.drawable.ic_launcher)) //Big Icon from drawable
            .setContentIntent(pendingIntent);


    notificationBuilder.setPriority(Notification.PRIORITY_HIGH);
    notificationBuilder.setDefaults(Notification.DEFAULT_SOUND);
    notificationBuilder.setVibrate(new long[]{0, 100, 200, 300});

    NotificationManager notificationManager = (NotificationManager) this
            .getSystemService(Context.NOTIFICATION_SERVICE);

    notificationManager.notify(not_nu, notificationBuilder.build());
}

public static int generateRandom() {
    Random random = new Random();
    return random.nextInt(9999 - 1000) + 1000;
}

1

您不能使用活动来实现此功能...

解决方案是 使用片段代替活动...

只需在需要时替换片段即可


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接