После обнаружения входящего звонка я открываю мессенджер, как значок чата при входящем звонке.Но я сталкиваюсь с двумя проблемами:
1. Входящий звонок не обнаруживается, когда мое приложение закрыто (не работает даже в фоновом режиме).
2. Когда мой телефон заблокирован, значок чата не появляется.Значок чата скрывается за приложением для набора номера при входящем звонке.
Я использую Broadcast Receiver
для приема входящего вызова с использованием класса PhoneCallReceiver
, который вызывает методы defined
в классе CallReceiver
, и при обнаружении входящего вызова я запускаю службу ChatHeadService
, которая открывает чаткак значок.Я приложил скриншот, как выглядит значок чата.Я сталкиваюсь с этой проблемой с последних 6 месяцев и не смог ее решить.Мы будем благодарны за любую помощь.
compileSdkVersion 23
buildToolsVersion '27 .0.3 '
targetSdkVersion 23
Я тестировал приложение на двух устройствах с уровнем API 18 и уровнем API 26.На уровне API 18 мое приложение работало нормально, и обе вышеуказанные проблемы были исправлены.Но на уровне API 26 мое приложение работало, не работало, а значок чата скрывался за приложением номеронабирателя.
Я сталкиваюсь со следующей ошибкой при входящем звонке в Oreo API 26.
06-13 16:22:23.969 1238-4375/? W/BroadcastQueue: Permission Denial: receiving Intent { act=android.intent.action.PHONE_STATE flg=0x1000010 (has extras) } to com.skype.m2/com.skype.nativephone.connector.NativePhoneCallReceiver requires android.permission.READ_PHONE_STATE due to sender android (uid 1000)
Уровень API 26
Уровень API 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;
}
}