gpt4 book ai didi

java - 在拨号器应用程序顶部检测来电并在后台打开服务

转载 作者:行者123 更新时间:2023-11-29 02:28:39 24 4
gpt4 key购买 nike

检测到来电后,我在来电上打开聊天图标之类的 Messenger。但我面临两个问题:
1.当我的应用程序关闭时(即使在后台也不运行),未检测到来电。
2.当我的手机被锁定时,聊天图标没有出现。聊天图标隐藏在来电时的拨号器应用程序后面。

我正在使用 Broadcast Receiver 使用 PhoneCallReceiver 类接收来电,该类调用 CallReceiver 类下的方法 defined 等检测来电 我正在启动服务 ChatHeadService,它会打开一个聊天图标。我附上了聊天图标显示方式的屏幕截图。自过去 6 个月以来,我一直面临这个问题,但无法解决。如有任何帮助,我们将不胜感激。

编译SDK版本23
buildToolsVersion '27.0.3'
targetSdk版本 23

我在 API 级别 18 和 API 级别 26 的两台设备上测试了该应用程序。在 API 级别 18 中,我的应用程序运行良好,并且上述两个问题都已修复。但在 API 级别 26 中,我的应用程序无法运行,聊天图标隐藏在拨号器应用程序的后面。

我在 Oreo API 26 的传入调用中遇到以下错误。
06-13 16:22:23.969 1238-4375/? W/BroadcastQueue:权限拒绝:接收 Intent { act=android.intent.action.PHONE_STATE flg=0x1000010(有额外的)} 到 com.skype.m2/com.skype.nativephone.connector.NativePhoneCallReceiver 需要 android.permission.READ_PHONE_STATE 由于发件人 android (uid 1000)

API 级别 26
API level 26

API 级别 18
API level 18


AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.tarun.notifyme2">

<uses-sdk
android:minSdkVersion="16"
android:targetSdkVersion="23" />

<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.CALL_PHONE" />
<uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS" />
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
<uses-permission android:name="android.permission.Settings.ACTION_MANAGE_OVERLAY_PERMISSION" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission
android:name="android.permission.MODIFY_PHONE_STATE"
tools:ignore="ProtectedPermissions" />

<application
android:allowBackup="true"
android:enabled="true"
android:icon="@drawable/app_icon"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".SignUp">
<intent-filter>
<action android:name="android.intent.action.MAIN" />

<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name=".SendNoti" />

<receiver android:name=".CallReceiver"
android:enabled="true">
<intent-filter android:priority="1000">
<action android:name="android.intent.action.PHONE_STATE" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.NEW_OUTGOING_CALL" />
</intent-filter>
</receiver>


<service
android:name=".ChatHeadService"
android:exported="true"
android:enabled="true"/>

<service android:name=".FirebaseMessagingService">
<intent-filter>
<action android:name="com.google.firebase.MESSAGING_EVENT" />
</intent-filter>
</service>
<service android:name=".FirebaseInstanceIDService">
<intent-filter>
<action android:name="com.google.firebase.INSTANCE_ID_EVENT" />
</intent-filter>
</service>

<activity
android:name=".MainActivity"
android:label="@string/title_activity_main"
android:theme="@style/AppTheme.NoActionBar" />
<activity android:name=".MainChat" />
<activity android:name=".ChatRoom" />
<activity android:name=".Feedback" />
</application>

</manifest>

PhonecallReceiver.java

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.telephony.TelephonyManager;
import java.util.Date;

public abstract class PhonecallReceiver extends BroadcastReceiver
{
private static int lastState = TelephonyManager.CALL_STATE_IDLE;
private static Date callStartTime;
private static boolean isIncoming;
private static String savedNumber;

@Override
public void onReceive(Context context, Intent intent)
{
try
{
if (intent.getAction().equals("android.intent.action.NEW_OUTGOING_CALL"))
{
savedNumber = intent.getExtras().getString("android.intent.extra.PHONE_NUMBER");
}
else
{
String stateStr = intent.getExtras().getString(TelephonyManager.EXTRA_STATE);
String number = intent.getExtras().getString(TelephonyManager.EXTRA_INCOMING_NUMBER);
int state = 0;
if(stateStr.equals(TelephonyManager.EXTRA_STATE_IDLE))
{
state = TelephonyManager.CALL_STATE_IDLE;
}
else if(stateStr.equals(TelephonyManager.EXTRA_STATE_OFFHOOK))
{
state = TelephonyManager.CALL_STATE_OFFHOOK;
}
else if(stateStr.equals(TelephonyManager.EXTRA_STATE_RINGING))
{
state = TelephonyManager.CALL_STATE_RINGING;
}

onCallStateChanged(context, state, number);
}
}
catch (Exception e)
{
e.printStackTrace();
}
}

//Derived classes should override these to respond to specific events of interest
protected void onIncomingCallStarted(Context ctx, String number, Date start){}
protected void onIncomingCallEnded(Context ctx, String number, Date start, Date end){}

public void onCallStateChanged(Context context, int state, String number)
{
if(lastState == state)
{
//No change, debounce extras
return;
}
switch (state)
{
case TelephonyManager.CALL_STATE_RINGING:
isIncoming = true;
callStartTime = new Date();
savedNumber = number;
onIncomingCallStarted(context, number, callStartTime);
break;

case TelephonyManager.CALL_STATE_OFFHOOK:
if (isIncoming)
{
onIncomingCallEnded(context,savedNumber,callStartTime,new Date());
}

case TelephonyManager.CALL_STATE_IDLE:
if(isIncoming)
{
onIncomingCallEnded(context, savedNumber, callStartTime, new Date());
}
}
lastState = state;
}
}

CallReceiver.java

import android.app.Activity;
import android.app.Dialog;
import android.app.Notification;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.graphics.drawable.ColorDrawable;
import android.view.LayoutInflater;
import android.view.View;
import android.view.Window;
import android.widget.Button;
import android.widget.Toast;
import android.os.Handler;
import java.util.Date;

public class CallReceiver extends PhonecallReceiver
{
Context context;

@Override
protected void onIncomingCallStarted(final Context ctx, String number, Date start)
{
Toast.makeText(ctx,"New Incoming Call"+ number,Toast.LENGTH_LONG).show();
context = ctx;
final Intent intent = new Intent(context, ChatHeadService.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
intent.putExtra("phone_no",number);
SharedPreferences.Editor editor = ctx.getSharedPreferences("Notify", Context.MODE_PRIVATE).edit();
editor.putString("incomingNo",number);
editor.commit();
new Handler().postDelayed(new Runnable()
{
@Override
public void run()
{
//start service which opens a chat icon after 2 seconds wait
context.startService(intent);
}
},2000);

}

@Override
protected void onIncomingCallEnded(Context ctx, String number, Date start, Date end)
{
final Intent intent = new Intent(context, ChatHeadService.class);
ctx.stopService(intent);
Toast.makeText(ctx,"Bye Bye"+ number,Toast.LENGTH_LONG).show();
}
}

ChatHeadService.java

import android.app.Service;
import android.content.Intent;
import android.graphics.PixelFormat;
import android.os.IBinder;
import android.util.Log;
import android.view.Gravity;
import android.view.MotionEvent;
import android.view.View;
import android.view.WindowManager;
import android.widget.ImageView;
import android.widget.Toast;

public class ChatHeadService extends Service {

private WindowManager windowManager;
private ImageView chatHead;
WindowManager.LayoutParams params;
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
int res = super.onStartCommand(intent, flags, startId);
return res;
}
@Override
public void onCreate() {
super.onCreate();

windowManager = (WindowManager) getSystemService(WINDOW_SERVICE);
chatHead = new ImageView(this);
chatHead.setImageResource(R.drawable.bell2);
chatHead.setClickable(true);

params= new WindowManager.LayoutParams(
WindowManager.LayoutParams.WRAP_CONTENT,
WindowManager.LayoutParams.WRAP_CONTENT,
WindowManager.LayoutParams.TYPE_PHONE,
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
PixelFormat.TRANSLUCENT);
params.gravity = Gravity.TOP | Gravity.LEFT;
params.x = 0;
params.y = 400;

windowManager.addView(chatHead, params);

chatHead.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
startActivity(new Intent(ChatHeadService.this, SendNoti.class)
.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
stopSelf();
}
});

//this code is for dragging the chat head
chatHead.setOnTouchListener(new View.OnTouchListener() {
private int initialX;
private int initialY;
private float initialTouchX;
private float initialTouchY;
int flag=0;

@Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
initialX = params.x;
initialY = params.y;
initialTouchX = event.getRawX();
initialTouchY = event.getRawY();
if(flag==3){
flag=1;
return true;
}else{
flag=1;
return false;
}
case MotionEvent.ACTION_UP:
if(flag==3){
flag=2;
return true;
}else{
flag=2;
return false;
}
case MotionEvent.ACTION_MOVE:
flag=3;
params.x = initialX
+ (int) (event.getRawX() - initialTouchX);
params.y = initialY
+ (int) (event.getRawY() - initialTouchY);
windowManager.updateViewLayout(chatHead, params);
return true;
default:
Toast.makeText(getApplicationContext(),"You ckiced the imageview",Toast.LENGTH_LONG).show();
Log.i("tag","You clicked the imageview");
/*
Intent i = new Intent(view.getContext(),SendNoti.class);
startActivity(i);
stopSelf();*/
return true;
}
}
});
/*
Snackbar.make(chatHead, "Replace with your own action", Snackbar.LENGTH_LONG)
.setAction("Action", null).show();*/

}

@Override
public void onDestroy() {
super.onDestroy();
if (chatHead != null)
windowManager.removeView(chatHead);
stopSelf();
}

@Override
public IBinder onBind(Intent intent) {
// TODO Auto-generated method stub
return null;
}
}

最佳答案

前段时间我发现了这个例子。我只添加了,调用是传入或传出。按 Intent 将您的数据传递给服务,并使用它来执行服务。应该在 api 23 中工作。在最新版本中我不能确保这一点。

public class CallReceiver extends BroadcastReceiver {

private final static String TAG = "CallReceiver";
private static PhoneCallStartEndDetector listener;
private String outgoingSavedNumber;
protected Context savedContext;

@Override
public void onReceive(Context context, Intent intent) {

this.savedContext = context;
if (listener == null) {

listener = new PhoneCallStartEndDetector();
}

String phoneState = intent.getStringExtra(TelephonyManager.EXTRA_STATE);

if (phoneState == null) {

listener.setOutgoingNumber(intent.getStringExtra(Intent.EXTRA_PHONE_NUMBER));

} else if (phoneState.equals(TelephonyManager.EXTRA_STATE_RINGING)) {

listener.setOutgoingNumber(intent.getStringExtra(TelephonyManager.EXTRA_INCOMING_NUMBER));
}

TelephonyManager telephony = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
telephony.listen(listener, PhoneStateListener.LISTEN_CALL_STATE);

}

//Deals with actual events
private class PhoneCallStartEndDetector extends PhoneStateListener {
int lastState = TelephonyManager.CALL_STATE_IDLE;
boolean isIncoming;
boolean isOutgoing;
String savedNumber; //because the passed incoming is only valid in ringing

private PhoneCallStartEndDetector() {

}

//The outgoing number is only sent via a separate intent, so we need to store it out of band
private void setOutgoingNumber(String number) {

savedNumber = number;
}

Intent serviceIntent = new Intent(savedContext, YourService.class);

//Incoming call- goes from IDLE to RINGING when it rings, to OFFHOOK when it's answered, to IDLE when its hung up
//Outgoing call- goes from IDLE to OFFHOOK when it dials out, to IDLE when hung up
@Override
public void onCallStateChanged(int state, String incomingNumber) {
super.onCallStateChanged(state, incomingNumber);

if (lastState == state) {
//No change, debounce extras
return;
}

switch (state) {

case TelephonyManager.CALL_STATE_RINGING:

isIncoming = true;
savedNumber = incomingNumber;

serviceIntent.putExtra("label", value);
savedContext.startService(serviceIntent);

break;

case TelephonyManager.CALL_STATE_OFFHOOK:
//Transition of ringing->offhook are pickups of incoming calls. Nothing donw on them
if (lastState != TelephonyManager.CALL_STATE_RINGING) {

if (!isOutgoing) {

isOutgoing = true;

}

if (!savedNumber.equals("")) {

serviceIntent.putExtra("label", value);
savedContext.startService(serviceIntent);
}
}
break;

case TelephonyManager.CALL_STATE_IDLE:
//Went to idle- this is the end of a call. What type depends on previous state(s)
if (lastState == TelephonyManager.CALL_STATE_RINGING) {
//Ring but no pickup- a miss

savedContext.stopService(serviceIntent);

} else if (isIncoming) {

savedContext.stopService(serviceIntent);

} else {

if (isOutgoing) {

savedContext.stopService(serviceIntent);

isOutgoing = false;
}
}

break;
}

lastState = state;
}
}

在 list 中注册这个接收器,这应该在 api 25 中工作:

<receiver
android:name=".calls.CallReceiver"
android:enabled="true">
<intent-filter android:priority="-1">
<action android:name="android.intent.action.PHONE_STATE" />
<action android:name="android.intent.action.NEW_OUTGOING_CALL"/>
</intent-filter>
</receiver>

或者在代码中注册 BroadcastReceiver,这应该可以在 api 26 中工作:

IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction("android.intent.action.PHONE_STATE");
CallReceiver receiver = new CallReceiver();
registerReceiver(receiver, intentFilter);

当然,要使用此代码,您需要授予权限。在 api 级别低于 23 的 list 中:

<uses-permission android:name="android.permission.READ_PHONE_STATE"/>

对于 api 23 和最新版本,询问用户权限:

Manifest.permission.READ_PHONE_STATE

关于java - 在拨号器应用程序顶部检测来电并在后台打开服务,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50810552/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com