如何在 Android 10 中打开活动(来电)

Posted

技术标签:

【中文标题】如何在 Android 10 中打开活动(来电)【英文标题】:How to open activity (incoming voip call) in Android 10 【发布时间】:2020-03-08 04:42:42 【问题描述】:

android 10 中,对应用应用了新的限制。 我们不能再从后台启动活动。虽然这对大多数应用程序来说可能没问题,但对于需要在推送通知到达后显示来电的 voip 应用程序来说,这是一个致命的打击。

根据这个https://developer.android.com/guide/components/activities/background-starts,有一个条件列表可以满足仍然允许打开活动,但我不完全理解(此处为非英语母语)。

我绝对知道的是:

我没有任何正在运行的activity、task、backstack之类的东西

应用甚至没有运行

我需要达到的目标:

应用程序的 FCM 服务从我们的服务器接收推送,并应显示来电屏幕(锁定屏幕和所有 - 就像它在 android 9 及更低版本中所做的那样)

如何在 android 10 中为传入的 voip 呼叫打开活动? 就像普通用户对 PHONE 应用程序所期望的一样,在锁屏界面上进行操作。

提前感谢任何提示。

【问题讨论】:

你可以给你这个代码link @Grisgram 你能解决这个问题吗? 【参考方案1】:

在锁定屏幕上打开 Activity。您可以使用具有“全屏意图”的高通知作为 CommonsWare 的答案。但要了解更多细节,您可以尝试我的解决方案,如下代码:

    创建一个前台服务,然后在onStartCommand方法中调用buildNotification,buildNotification方法会返回一个通知,放入startForeground方法参数中。

     public class IncomingCallService extends Service 
         public int onStartCommand(Intent intent, int flags, int startId) 
             Notification notification = buildNotification();
             startForeground(1, notification);
             return START_NOT_STICKY;
         
     
    

    在 buildNotification 方法中,我们将创建具有高优先级、调用类别和全屏意图的通知。

     private Notification buildNotification() 
         Intent fullScreenIntent = new Intent(this, IncomingCallActivity.class);
         PendingIntent fullScreenPendingIntent = PendingIntent.getActivity(this, 0, fullScreenIntent, PendingIntent.FLAG_UPDATE_CURRENT);
         NotificationManager notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
    
         NotificationCompat.Builder notificationBuilder =
             new NotificationCompat.Builder(this)
                     .setSmallIcon(R.drawable.ic_notification_icon)
                     .setContentTitle("Incoming call")
                     .setContentText("(919) 555-1234")
                     .setPriority(NotificationCompat.PRIORITY_HIGH)
                     .setCategory(NotificationCompat.CATEGORY_CALL)
                     // Use a full-screen intent only for the highest-priority alerts where you
                     // have an associated activity that you would like to launch after the user
                     // interacts with the notification. Also, if your app targets Android 10
                     // or higher, you need to request the USE_FULL_SCREEN_INTENT permission in
                     // order for the platform to invoke this notification.
                     .setFullScreenIntent(fullScreenPendingIntent, true);
         notificationBuilder.setAutoCancel(true);
         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) 
             notificationManager.createNotificationChannel(new NotificationChannel("123", "123", NotificationManager.IMPORTANCE_HIGH));
             notificationBuilder.setChannelId("123");
         
         Notification incomingCallNotification = notificationBuilder.build();
         return incomingCallNotification;
     
    

    在 onStartCommand 中,添加一行代码发送 ACTION_CLOSE_SYSTEM_DIALOGS 广播动作。此验证对于启动全屏挂起意图很重要。

     public int onStartCommand(Intent intent, int flags, int startId) 
         Notification notification = buildNotification();
         startForeground(1, notification);
         sendBroadcast(new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS));
         return START_NOT_STICKY;
     
    

    创建要在锁定屏幕上显示的全屏活动,然后您需要添加 setShowWhenLocked 和 setTurnScreenOn 以在锁定屏幕上显示。如果没有,您的活动将显示在锁定屏幕后面。以下是我的示例。

     public class IncomingCallActivity extends AppCompatActivity 
         protected void onCreate(@Nullable Bundle savedInstanceState) 
             super.onCreate(savedInstanceState);
             setContentView(R.layout.activity_explore);
             setShowWhenLocked(true);
             setTurnScreenOn(true);
             getWindow().addFlags(
             WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED
                     | WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD
                     | WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON
                     | WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON
                     | WindowManager.LayoutParams.FLAG_ALLOW_LOCK_WHILE_SCREEN_ON);
         
     
    

    现在,当您收到来自您的逻辑的呼叫时,您必须启动 IncomingCallService。

     public void startCallService() 
         Intent intent = new Intent(context, IncomingCallService.class);
         startForegroundService(intent);
     
    

    您必须在清单中声明活动、服务和一些权限,如下所示:

     <uses-permission android:name="android.permission.USE_FULL_SCREEN_INTENT" />
     <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
     <application
        ...>
         <activity android:name=".IncomingCallActivity" />
         <service
             android:name=".IncomingCallService"
             android:enabled="true"
             android:exported="true" />
     </application>
    

我在 google、samsung、vsmart 手机上测试过。它运作良好。但是对于小米设备。您需要通过以下步骤启用一些权限:

    长按您的应用图标 打开应用信息 点击“其他权限”项 允许在锁定屏幕上显示

现在您的应用可以在 xaomi 设备上运行。如果您对我的解决方案有任何问题,请在此处发表评论。如果可以的话,我会帮助你。

【讨论】:

感谢您抽出宝贵时间提供如此详细的答案 - 我会调查一下 我的解决方案已上传到github。你可以看看github.com/doanpt/PhoneActivity 进行测试。安装应用程序后。打开 cmd 或终端然后运行命令: adb shell am start-foreground-service com.ddona.call/.IncomingCallService 小心 - getWindow().addFlags() 应该在 SetContentView 之前调用。在 API >= 27 上设置这些标志可能不太好 - 但不确定 @MichalDobrodenka, 1) 实际上,我的示例可能在不添加标志的情况下工作。但我将它添加到 27 以下的 API 上工作。2)对于 addFlags 方法,Google 说它应该在 setContentView 之前设置一些标志,而不是所有标志,然后最好,我同意我们应该在调用 setContentView 【参考方案2】:

查看此链接,这将对您有所帮助 here

您需要请求“绘制其他应用程序”的权限,然后您才能将其设为以前的版本

  if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) 
            if (!Settings.canDrawOverlays(this)) 
                RequestPermission();

        
        

    private void RequestPermission() 
        // Check if Android P or higher
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) 
            // Show alert dialog to the user saying a separate permission is needed
            // Launch the settings activity if the user prefers
            Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION,
                    Uri.parse("package:" + BuildConfig.APPLICATION_ID));
            startActivityForResult(intent, 
            ACTION_MANAGE_OVERLAY_PERMISSION_REQUEST_CODE);
        
     

或者你可以使用我的这个answer

https://***.com/a/63699960/7108113

【讨论】:

【参考方案3】:

请浏览我的博客,了解如何为 OS 10 打开活动,以及如何显示抬头通知和处理对操作按钮的点击。

https://medium.com/@dcostalloyd90/show-incoming-voip-call-notification-and-open-activity-for-android-os-10-5aada2d4c1e4

【讨论】:

我完全按照您的示例进行操作,但没有像您显示的那样工作。通知仍然是正常的通知 - 没有大的弹出窗口,也没有全屏意图。 @YazidEF 创建通知通道时将优先级设置为高。 @LloydDcosta 我也查看了您的示例,但是单击按钮后,没有调用 HeadsUpNotificationActionReceiver。知道为什么吗?【参考方案4】:

使用具有“全屏意图”的高优先级通知。那将:

如果设备被锁定,调用您的“全屏意图” 否则,显示“提醒”通知

【讨论】:

谢谢。它为我指明了正确的方向。我认为这将与带有自定义布局的扩展通知一起工作,以防应用程序当前处于前台(使用前台服务)。 一个很好的教程可以在这里找到:developer.android.com/training/notify-user/time-sensitive 用于记录。包含解决此问题所需的一切。 使用这种方法是否可以只显示全屏意图而不显示通知?我实现了这个解决方案,但是当我的全屏意图出现时它会发出通知声音。 setFullScreenIntent 的描述说:“意图启动而不是将通知发布到状态栏。”。我不认为这是真的。它为全屏意图加注星标并创建通知。 @Mitulátbáti:“是否可以只显示全屏意图而不显示通知?” - 不。 “它为全屏意图加注星标并创建通知”——这就是报价所说的。引用说它用于“而不是将通知发布到状态栏”(强调添加)。据推测,其他效果,如铃声和振动,仍然是合格的。如果用户不想要这些效果,用户应该能够在“设置”应用中为您的频道禁用它们。 @CommonsWare 你能不能提一下我们如何为通知操作设置不同的颜色(比如红色表示拒绝,绿色表示回答)

以上是关于如何在 Android 10 中打开活动(来电)的主要内容,如果未能解决你的问题,请参考以下文章

在 Android 原生来电屏幕上弹出窗口,如真正的来电者 Android 应用程序

在 Android Q-Municate 中未收到后台来电和消息通知

如何使用phonegap检测android中的来电号码

如何在Android中清除以前打开的活动

如何在android应用程序活动和非活动状态下处理推送通知

Android:quickblox 来电视频通话收不到