android oreo 和 pie 中的广播接收器不在后台工作
Broadcast Receivers not working in background in android oreo and pie
在我的应用程序中,我使用广播接收器获取传入的 phone 号码并将其显示在对话框中,然后在单击按钮时将其保存在应用程序中。每次通话结束后都会得到号码。 Oreo 和 Pie 以下的所有 android 版本都运行良好。在 Oreo 和 Pie 中,当应用程序为 closed/killed 时,结束通话后不会出现对话框。但是当应用程序是 运行 时,对话框完美出现。我认为当我们终止应用程序时,广播接收器也会被终止。我一直在寻找几天,但没有任何帮助。
这里是我的代码的一些介绍:
Manifest.xml :
<receiver
android:name="com.softixtechnologies.phonemanager.callhelpers.CallReciever"
android:enabled="true">
<intent-filter>
<action android:name="android.intent.action.PHONE_STATE" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.NEW_OUTGOING_CALL" />
</intent-filter>
</receiver>
MainActivity.java :
public class MainActivity extends AppCompatActivity {
LinearLayout btncat, btnlog, btnIgnore, btnExit;
SwitchCompat checkBoxMissed, checkBoxUnknown ;
boolean isCheckedValue = true;
boolean isCheckedUnknown = true;
DatabaseHelper databaseHelper ;
public static final String SHARED_PREFS = "shared_prefs" ;
public final static int MY_PERMISSIONS_REQUEST_READ_PHONE_STATE = 11;
public static int ACTION_MANAGE_OVERLAY_PERMISSION_REQUEST_CODE = 5469;
public static final int CALL_LOG_PERMISSION = 1 ;
PhoneCallReceiver phoneCallReceiver ;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
databaseHelper = new DatabaseHelper(this) ;
btncat = findViewById(R.id.button_Categories);
btnlog = findViewById(R.id.button_logs) ;
btnIgnore = findViewById(R.id.button_Ignore_contacts) ;
checkBoxMissed= findViewById(R.id.checkbox_missed) ;
checkBoxUnknown= findViewById(R.id.checkbox_unknown);
btnExit = findViewById(R.id.button_exit);
phoneCallReceiver = new PhoneCallReceiver();
IntentFilter intentFilter = new IntentFilter();
// intentFilter.addAction("android.intent.action.PHONE_STATE");
// intentFilter.addAction("android.intent.action.NEW_OUTGOING_CALL");
IntentFilter intentFilter1 = new IntentFilter("android.intent.action.NEW_OUTGOING_CALL");
intentFilter.addCategory(Intent.CATEGORY_DEFAULT);
intentFilter1.addCategory(Intent.CATEGORY_DEFAULT);
registerReceiver(phoneCallReceiver, intentFilter);
registerReceiver(phoneCallReceiver, intentFilter1);
checkPermission();
requestCallLogPermission();
//permission check for pie 23-july-2019
if (ContextCompat.checkSelfPermission(this,Manifest.permission.READ_CALL_LOG) == PackageManager.PERMISSION_GRANTED){
}else {
requestCallLogPermission();
}
if (ContextCompat.checkSelfPermission(getApplicationContext(),
Manifest.permission.READ_PHONE_STATE)
!= PackageManager.PERMISSION_GRANTED)
if (ActivityCompat.shouldShowRequestPermissionRationale(this,
Manifest.permission.READ_CONTACTS)) {
} else {
ActivityCompat.requestPermissions(this,
new String[]{Manifest.permission.READ_PHONE_STATE, Manifest.permission.SYSTEM_ALERT_WINDOW},
MY_PERMISSIONS_REQUEST_READ_PHONE_STATE);
}
SharedPreferences sharedPreferenceCAT = getSharedPreferences(SHARED_PREFS, MODE_PRIVATE);
boolean isFirstTimeCAT =sharedPreferenceCAT.getBoolean("isFirstTimeCAT", true);
if (isFirstTimeCAT){
try{
databaseHelper.insertCAT("New Customer");
databaseHelper.insertCAT("Complaint");
databaseHelper.insertCAT("Reminder");
sharedPreferenceCAT.edit().putBoolean("isFirstTimeCAT",false).commit();}catch (Exception e){
Toast.makeText(this, ""+ e.getMessage(), Toast.LENGTH_SHORT).show();
}
}
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this);
final SharedPreferences.Editor editor = preferences.edit();
checkBoxMissed.setChecked(preferences.getBoolean("checked",false));
checkBoxMissed.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
isCheckedValue = isChecked;
editor.putBoolean("checked", isChecked);
editor.apply();
}
});
SharedPreferences preferencesUnknown = PreferenceManager.getDefaultSharedPreferences(this);
final SharedPreferences.Editor editorUnknown = preferencesUnknown.edit();
checkBoxUnknown.setChecked(preferencesUnknown.getBoolean("checkedunknown",false));
checkBoxUnknown.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
isCheckedUnknown = isChecked;
editorUnknown.putBoolean("checkedunknown", isChecked);
editorUnknown.apply();
}
});
private void requestCallLogPermission() {
if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.READ_CALL_LOG)){
new AlertDialog.Builder(this).setTitle("Permission Needed")
.setMessage("This permission is needed by App to work properly !")
.setPositiveButton("OK", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
ActivityCompat.requestPermissions(MainActivity.this, new String[] {Manifest.permission.READ_CALL_LOG},
CALL_LOG_PERMISSION);
}
}).setCancelable(false)
.create().show();
}else {
ActivityCompat.requestPermissions(this, new String[] {Manifest.permission.READ_CALL_LOG},
CALL_LOG_PERMISSION);
}
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
switch(requestCode){
case MY_PERMISSIONS_REQUEST_READ_PHONE_STATE:
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED){
}else {
return;
}
case CALL_LOG_PERMISSION:
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
Toast.makeText(this, "Call Log Permission Granted !", Toast.LENGTH_SHORT).show();
}
}
}
@TargetApi(Build.VERSION_CODES.M)
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == ACTION_MANAGE_OVERLAY_PERMISSION_REQUEST_CODE) {
if (!Settings.canDrawOverlays(this)) {
// You don't have permission
checkPermission();
} else {
// Do as per your logic
}
}
if (requestCode == CALL_LOG_PERMISSION) {
if (!Settings.canDrawOverlays(this)) {
// You don't have permission
requestCallLogPermission();
} else {
// Do as per your logic
}
}
}
public void checkPermission() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (!Settings.canDrawOverlays(this)) {
Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION,
Uri.parse("package:" + getPackageName()));
startActivityForResult(intent, ACTION_MANAGE_OVERLAY_PERMISSION_REQUEST_CODE);
}
}
}
@Override
protected void onStart() {
super.onStart();
IntentFilter intentFilter = new IntentFilter("android.intent.action.PHONE_STATE");
IntentFilter intentFilter1 = new IntentFilter("android.intent.action.NEW_OUTGOING_CALL");
intentFilter.addCategory(Intent.CATEGORY_DEFAULT);
intentFilter1.addCategory(Intent.CATEGORY_DEFAULT);
registerReceiver(phoneCallReceiver, intentFilter);
registerReceiver(phoneCallReceiver, intentFilter1);
}
@Override
protected void onStop() {
super.onStop();
// unregisterReceiver(phoneCallReceiver);
}
@Override
protected void onDestroy() {
super.onDestroy();
}
}
广播接收器:
public 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(final Context context, Intent intent) {
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.P){
TelephonyManager tm = (TelephonyManager)context.getSystemService(Service.TELEPHONY_SERVICE);
switch (tm.getCallState()) {
case TelephonyManager.CALL_STATE_IDLE:
Toast.makeText(context, "IDLE", Toast.LENGTH_SHORT).show();
final String phoneNr= intent.getStringExtra("incoming_number");
Toast.makeText(context, phoneNr,Toast.LENGTH_LONG).show();
SharedPreferences preferencesUnknown = PreferenceManager.getDefaultSharedPreferences(context);
final SharedPreferences.Editor editorUnknown = preferencesUnknown.edit();
boolean checkedUnknown = preferencesUnknown.getBoolean("checkedunknown", false);
if (checkedUnknown) {
boolean isUnknown = contactExists(context, phoneNr);
if (isUnknown == false) {
AlertDialog.Builder alerDialog = new AlertDialog.Builder(context);
alerDialog.setIcon(R.drawable.calllogo);
alerDialog.setTitle(phoneNr);
alerDialog.setMessage("Save this number ?");
alerDialog.setCancelable(false);
alerDialog.setPositiveButton("YES", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
Intent intent = new Intent(context, CategoryPhoneActivity.class);
intent.putExtra("Phone", phoneNr);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(intent);
}
});
alerDialog.setNegativeButton("NO", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.cancel();
}
});
AlertDialog aldialog = alerDialog.create();
aldialog.setCanceledOnTouchOutside(false);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
aldialog.getWindow().setType(WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY); } else {
aldialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
}
aldialog.show(); } else {
Toast.makeText(context, "Number is already saved", Toast.LENGTH_SHORT).show(); }
}else{
AlertDialog.Builder alerDialog = new AlertDialog.Builder(context);
alerDialog.setIcon(R.drawable.calllogo);
alerDialog.setTitle(phoneNr);
alerDialog.setCancelable(false);
alerDialog.setMessage("Save this number ?");
alerDialog.setPositiveButton("YES", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
Intent intent = new Intent(context, CategoryPhoneActivity.class);
intent.putExtra("Phone", phoneNr);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(intent);
}
});
alerDialog.setNegativeButton("NO", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.cancel();
}
});
AlertDialog aldialog = alerDialog.create();
aldialog.setCanceledOnTouchOutside(false);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
aldialog.getWindow().setType(WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY); } else {
aldialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
}
aldialog.show(); }
break;
}
}else {
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);
}
}
}
protected void onIncomingCallStarted(Context ctx, String number, Date start){}
protected void onOutgoingCallStarted(Context ctx, String number, Date start){}
protected void onIncomingCallEnded(Context ctx, String number, Date start, Date end){}
protected void onOutgoingCallEnded(Context ctx, String number, Date start, Date end){}
protected void onMissedCall(Context ctx, String number, Date start){}
public void onCallStateChanged(Context context, int state, String number) {
if(lastState == state){
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(lastState != TelephonyManager.CALL_STATE_RINGING){
isIncoming = false;
callStartTime = new Date();
onOutgoingCallStarted(context, savedNumber, callStartTime);
}
break;
case TelephonyManager.CALL_STATE_IDLE:
if(lastState == TelephonyManager.CALL_STATE_RINGING){
onMissedCall(context, savedNumber, callStartTime);
}
else if(isIncoming){
onIncomingCallEnded(context, savedNumber, callStartTime, new Date());
}
else{
onOutgoingCallEnded(context, savedNumber, callStartTime, new Date());
}
break;
}
lastState = state;
}
呼叫接收者:
public class CallReciever extends PhoneCallReceiver {
DatabaseHelper databaseHelper ;
@Override
protected void onIncomingCallStarted(final Context ctx, final String number, Date start) {
}
@Override
protected void onOutgoingCallStarted(Context ctx, String number, Date start) {
}
@Override
protected void onIncomingCallEnded(final Context ctx, final String number, Date start, Date end) {
SharedPreferences preferencesUnknown = PreferenceManager.getDefaultSharedPreferences(ctx);
final SharedPreferences.Editor editorUnknown = preferencesUnknown.edit();
boolean checkedUnknown = preferencesUnknown.getBoolean("checkedunknown", false);
if (checkedUnknown) {
boolean isUnknown = contactExists(ctx, number);
if (isUnknown == false) {
AlertDialog.Builder alerDialog = new AlertDialog.Builder(ctx);
alerDialog.setIcon(R.drawable.calllogo);
alerDialog.setTitle(number);
alerDialog.setMessage("Save this number ?");
alerDialog.setCancelable(false);
alerDialog.setPositiveButton("YES", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
Intent intent = new Intent(ctx, CategoryPhoneActivity.class);
intent.putExtra("Phone", number);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
ctx.startActivity(intent);
}
});
alerDialog.setNegativeButton("NO", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.cancel();
}
});
AlertDialog aldialog = alerDialog.create();
aldialog.setCanceledOnTouchOutside(false);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
aldialog.getWindow().setType(WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY); } else {
aldialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
}
aldialog.show(); } else {
Toast.makeText(ctx, "Number is already saved", Toast.LENGTH_SHORT).show(); }
}else{
AlertDialog.Builder alerDialog = new AlertDialog.Builder(ctx);
alerDialog.setIcon(R.drawable.calllogo);
alerDialog.setTitle(number);
alerDialog.setCancelable(false);
alerDialog.setMessage("Save this number ?");
alerDialog.setPositiveButton("YES", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
Intent intent = new Intent(ctx, CategoryPhoneActivity.class);
intent.putExtra("Phone", number);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
ctx.startActivity(intent);
}
});
alerDialog.setNegativeButton("NO", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.cancel();
}
});
AlertDialog aldialog = alerDialog.create();
aldialog.setCanceledOnTouchOutside(false);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
aldialog.getWindow().setType(WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY); } else {
aldialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
}
aldialog.show(); }
}
@Override
protected void onOutgoingCallEnded(Context ctx, String number, Date start, Date end) {
}
@Override
protected void onMissedCall(final Context ctx, final String number, Date start) {
Toast.makeText(ctx, "Missed call from " + number, Toast.LENGTH_SHORT).show();
databaseHelper = new DatabaseHelper(ctx);
if (databaseHelper.searchContact(number)){
return;
}
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(ctx);
final SharedPreferences.Editor editor = preferences.edit();
boolean checked = preferences.getBoolean("checked", false);
if (checked) {
SharedPreferences preferencesUnknown = PreferenceManager.getDefaultSharedPreferences(ctx);
final SharedPreferences.Editor editorUnknown = preferencesUnknown.edit();
boolean checkedUnknown = preferencesUnknown.getBoolean("checkedunknown", false);
if (checkedUnknown) {
boolean isUnknown = contactExists(ctx, number);
if (isUnknown == false) {
AlertDialog.Builder alerDialog = new AlertDialog.Builder(ctx);
alerDialog.setIcon(R.drawable.calllogo);
alerDialog.setTitle(number);
alerDialog.setMessage("Save this number ?");
alerDialog.setPositiveButton("YES", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
Intent intent = new Intent(ctx, CategoryPhoneActivity.class);
intent.putExtra("Phone", number);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
ctx.startActivity(intent);
}
});
alerDialog.setNegativeButton("NO", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.cancel();
}
});
AlertDialog aldialog = alerDialog.create();
aldialog.setCanceledOnTouchOutside(false);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
aldialog.getWindow().setType(WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY); } else {
aldialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
}
aldialog.show(); } else {
Toast.makeText(ctx, "Number is already saved", Toast.LENGTH_SHORT).show(); }
}else{
AlertDialog.Builder alerDialog = new AlertDialog.Builder(ctx);
alerDialog.setIcon(R.drawable.calllogo);
alerDialog.setTitle(number);
alerDialog.setMessage("Save this number ?");
alerDialog.setPositiveButton("YES", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
Intent intent = new Intent(ctx, CategoryPhoneActivity.class);
intent.putExtra("Phone", number);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
ctx.startActivity(intent);
}
});
alerDialog.setNegativeButton("NO", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.cancel();
}
});
AlertDialog aldialog = alerDialog.create();
aldialog.setCanceledOnTouchOutside(false);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
aldialog.getWindow().setType(WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY); } else {
aldialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
}
aldialog.show(); }
}else{
Toast.makeText(ctx, "", Toast.LENGTH_SHORT).show(); }
}
public boolean contactExists(Context context, String number) {
Uri lookupUri = Uri.withAppendedPath(
ContactsContract.PhoneLookup.CONTENT_FILTER_URI,
Uri.encode(number));
String[] mPhoneNumberProjection = { ContactsContract.PhoneLookup._ID, ContactsContract.PhoneLookup.NUMBER, ContactsContract.PhoneLookup.DISPLAY_NAME };
Cursor cur = context.getContentResolver().query(lookupUri,mPhoneNumberProjection, null, null, null);
try {
if (cur.moveToFirst()) {
return true;
}
} finally {
if (cur != null)
cur.close();
}
return false;
}
}
Beginning with Android 8.0 (API level 26), the system imposes
additional restrictions on manifest-declared receivers.
If your app targets Android 8.0 or higher, you cannot use the manifest
to declare a receiver for most implicit broadcasts (broadcasts that
don't target your app specifically). You can still use a
context-registered receiver when the user is actively using your app.
我猜系统会在您关闭应用程序时自动注销您的 broadcast receivers
。
解决方案: 创建粘性或前台服务并在服务中注册您的广播接收器。当您接收广播时,启动 activity 并显示来自广播接收器 onReceive
的对话框。
在我的应用程序中,我使用广播接收器获取传入的 phone 号码并将其显示在对话框中,然后在单击按钮时将其保存在应用程序中。每次通话结束后都会得到号码。 Oreo 和 Pie 以下的所有 android 版本都运行良好。在 Oreo 和 Pie 中,当应用程序为 closed/killed 时,结束通话后不会出现对话框。但是当应用程序是 运行 时,对话框完美出现。我认为当我们终止应用程序时,广播接收器也会被终止。我一直在寻找几天,但没有任何帮助。
这里是我的代码的一些介绍:
Manifest.xml :
<receiver
android:name="com.softixtechnologies.phonemanager.callhelpers.CallReciever"
android:enabled="true">
<intent-filter>
<action android:name="android.intent.action.PHONE_STATE" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.NEW_OUTGOING_CALL" />
</intent-filter>
</receiver>
MainActivity.java :
public class MainActivity extends AppCompatActivity {
LinearLayout btncat, btnlog, btnIgnore, btnExit;
SwitchCompat checkBoxMissed, checkBoxUnknown ;
boolean isCheckedValue = true;
boolean isCheckedUnknown = true;
DatabaseHelper databaseHelper ;
public static final String SHARED_PREFS = "shared_prefs" ;
public final static int MY_PERMISSIONS_REQUEST_READ_PHONE_STATE = 11;
public static int ACTION_MANAGE_OVERLAY_PERMISSION_REQUEST_CODE = 5469;
public static final int CALL_LOG_PERMISSION = 1 ;
PhoneCallReceiver phoneCallReceiver ;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
databaseHelper = new DatabaseHelper(this) ;
btncat = findViewById(R.id.button_Categories);
btnlog = findViewById(R.id.button_logs) ;
btnIgnore = findViewById(R.id.button_Ignore_contacts) ;
checkBoxMissed= findViewById(R.id.checkbox_missed) ;
checkBoxUnknown= findViewById(R.id.checkbox_unknown);
btnExit = findViewById(R.id.button_exit);
phoneCallReceiver = new PhoneCallReceiver();
IntentFilter intentFilter = new IntentFilter();
// intentFilter.addAction("android.intent.action.PHONE_STATE");
// intentFilter.addAction("android.intent.action.NEW_OUTGOING_CALL");
IntentFilter intentFilter1 = new IntentFilter("android.intent.action.NEW_OUTGOING_CALL");
intentFilter.addCategory(Intent.CATEGORY_DEFAULT);
intentFilter1.addCategory(Intent.CATEGORY_DEFAULT);
registerReceiver(phoneCallReceiver, intentFilter);
registerReceiver(phoneCallReceiver, intentFilter1);
checkPermission();
requestCallLogPermission();
//permission check for pie 23-july-2019
if (ContextCompat.checkSelfPermission(this,Manifest.permission.READ_CALL_LOG) == PackageManager.PERMISSION_GRANTED){
}else {
requestCallLogPermission();
}
if (ContextCompat.checkSelfPermission(getApplicationContext(),
Manifest.permission.READ_PHONE_STATE)
!= PackageManager.PERMISSION_GRANTED)
if (ActivityCompat.shouldShowRequestPermissionRationale(this,
Manifest.permission.READ_CONTACTS)) {
} else {
ActivityCompat.requestPermissions(this,
new String[]{Manifest.permission.READ_PHONE_STATE, Manifest.permission.SYSTEM_ALERT_WINDOW},
MY_PERMISSIONS_REQUEST_READ_PHONE_STATE);
}
SharedPreferences sharedPreferenceCAT = getSharedPreferences(SHARED_PREFS, MODE_PRIVATE);
boolean isFirstTimeCAT =sharedPreferenceCAT.getBoolean("isFirstTimeCAT", true);
if (isFirstTimeCAT){
try{
databaseHelper.insertCAT("New Customer");
databaseHelper.insertCAT("Complaint");
databaseHelper.insertCAT("Reminder");
sharedPreferenceCAT.edit().putBoolean("isFirstTimeCAT",false).commit();}catch (Exception e){
Toast.makeText(this, ""+ e.getMessage(), Toast.LENGTH_SHORT).show();
}
}
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this);
final SharedPreferences.Editor editor = preferences.edit();
checkBoxMissed.setChecked(preferences.getBoolean("checked",false));
checkBoxMissed.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
isCheckedValue = isChecked;
editor.putBoolean("checked", isChecked);
editor.apply();
}
});
SharedPreferences preferencesUnknown = PreferenceManager.getDefaultSharedPreferences(this);
final SharedPreferences.Editor editorUnknown = preferencesUnknown.edit();
checkBoxUnknown.setChecked(preferencesUnknown.getBoolean("checkedunknown",false));
checkBoxUnknown.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
isCheckedUnknown = isChecked;
editorUnknown.putBoolean("checkedunknown", isChecked);
editorUnknown.apply();
}
});
private void requestCallLogPermission() {
if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.READ_CALL_LOG)){
new AlertDialog.Builder(this).setTitle("Permission Needed")
.setMessage("This permission is needed by App to work properly !")
.setPositiveButton("OK", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
ActivityCompat.requestPermissions(MainActivity.this, new String[] {Manifest.permission.READ_CALL_LOG},
CALL_LOG_PERMISSION);
}
}).setCancelable(false)
.create().show();
}else {
ActivityCompat.requestPermissions(this, new String[] {Manifest.permission.READ_CALL_LOG},
CALL_LOG_PERMISSION);
}
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
switch(requestCode){
case MY_PERMISSIONS_REQUEST_READ_PHONE_STATE:
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED){
}else {
return;
}
case CALL_LOG_PERMISSION:
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
Toast.makeText(this, "Call Log Permission Granted !", Toast.LENGTH_SHORT).show();
}
}
}
@TargetApi(Build.VERSION_CODES.M)
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == ACTION_MANAGE_OVERLAY_PERMISSION_REQUEST_CODE) {
if (!Settings.canDrawOverlays(this)) {
// You don't have permission
checkPermission();
} else {
// Do as per your logic
}
}
if (requestCode == CALL_LOG_PERMISSION) {
if (!Settings.canDrawOverlays(this)) {
// You don't have permission
requestCallLogPermission();
} else {
// Do as per your logic
}
}
}
public void checkPermission() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (!Settings.canDrawOverlays(this)) {
Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION,
Uri.parse("package:" + getPackageName()));
startActivityForResult(intent, ACTION_MANAGE_OVERLAY_PERMISSION_REQUEST_CODE);
}
}
}
@Override
protected void onStart() {
super.onStart();
IntentFilter intentFilter = new IntentFilter("android.intent.action.PHONE_STATE");
IntentFilter intentFilter1 = new IntentFilter("android.intent.action.NEW_OUTGOING_CALL");
intentFilter.addCategory(Intent.CATEGORY_DEFAULT);
intentFilter1.addCategory(Intent.CATEGORY_DEFAULT);
registerReceiver(phoneCallReceiver, intentFilter);
registerReceiver(phoneCallReceiver, intentFilter1);
}
@Override
protected void onStop() {
super.onStop();
// unregisterReceiver(phoneCallReceiver);
}
@Override
protected void onDestroy() {
super.onDestroy();
}
}
广播接收器:
public 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(final Context context, Intent intent) {
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.P){
TelephonyManager tm = (TelephonyManager)context.getSystemService(Service.TELEPHONY_SERVICE);
switch (tm.getCallState()) {
case TelephonyManager.CALL_STATE_IDLE:
Toast.makeText(context, "IDLE", Toast.LENGTH_SHORT).show();
final String phoneNr= intent.getStringExtra("incoming_number");
Toast.makeText(context, phoneNr,Toast.LENGTH_LONG).show();
SharedPreferences preferencesUnknown = PreferenceManager.getDefaultSharedPreferences(context);
final SharedPreferences.Editor editorUnknown = preferencesUnknown.edit();
boolean checkedUnknown = preferencesUnknown.getBoolean("checkedunknown", false);
if (checkedUnknown) {
boolean isUnknown = contactExists(context, phoneNr);
if (isUnknown == false) {
AlertDialog.Builder alerDialog = new AlertDialog.Builder(context);
alerDialog.setIcon(R.drawable.calllogo);
alerDialog.setTitle(phoneNr);
alerDialog.setMessage("Save this number ?");
alerDialog.setCancelable(false);
alerDialog.setPositiveButton("YES", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
Intent intent = new Intent(context, CategoryPhoneActivity.class);
intent.putExtra("Phone", phoneNr);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(intent);
}
});
alerDialog.setNegativeButton("NO", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.cancel();
}
});
AlertDialog aldialog = alerDialog.create();
aldialog.setCanceledOnTouchOutside(false);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
aldialog.getWindow().setType(WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY); } else {
aldialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
}
aldialog.show(); } else {
Toast.makeText(context, "Number is already saved", Toast.LENGTH_SHORT).show(); }
}else{
AlertDialog.Builder alerDialog = new AlertDialog.Builder(context);
alerDialog.setIcon(R.drawable.calllogo);
alerDialog.setTitle(phoneNr);
alerDialog.setCancelable(false);
alerDialog.setMessage("Save this number ?");
alerDialog.setPositiveButton("YES", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
Intent intent = new Intent(context, CategoryPhoneActivity.class);
intent.putExtra("Phone", phoneNr);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(intent);
}
});
alerDialog.setNegativeButton("NO", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.cancel();
}
});
AlertDialog aldialog = alerDialog.create();
aldialog.setCanceledOnTouchOutside(false);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
aldialog.getWindow().setType(WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY); } else {
aldialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
}
aldialog.show(); }
break;
}
}else {
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);
}
}
}
protected void onIncomingCallStarted(Context ctx, String number, Date start){}
protected void onOutgoingCallStarted(Context ctx, String number, Date start){}
protected void onIncomingCallEnded(Context ctx, String number, Date start, Date end){}
protected void onOutgoingCallEnded(Context ctx, String number, Date start, Date end){}
protected void onMissedCall(Context ctx, String number, Date start){}
public void onCallStateChanged(Context context, int state, String number) {
if(lastState == state){
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(lastState != TelephonyManager.CALL_STATE_RINGING){
isIncoming = false;
callStartTime = new Date();
onOutgoingCallStarted(context, savedNumber, callStartTime);
}
break;
case TelephonyManager.CALL_STATE_IDLE:
if(lastState == TelephonyManager.CALL_STATE_RINGING){
onMissedCall(context, savedNumber, callStartTime);
}
else if(isIncoming){
onIncomingCallEnded(context, savedNumber, callStartTime, new Date());
}
else{
onOutgoingCallEnded(context, savedNumber, callStartTime, new Date());
}
break;
}
lastState = state;
}
呼叫接收者:
public class CallReciever extends PhoneCallReceiver {
DatabaseHelper databaseHelper ;
@Override
protected void onIncomingCallStarted(final Context ctx, final String number, Date start) {
}
@Override
protected void onOutgoingCallStarted(Context ctx, String number, Date start) {
}
@Override
protected void onIncomingCallEnded(final Context ctx, final String number, Date start, Date end) {
SharedPreferences preferencesUnknown = PreferenceManager.getDefaultSharedPreferences(ctx);
final SharedPreferences.Editor editorUnknown = preferencesUnknown.edit();
boolean checkedUnknown = preferencesUnknown.getBoolean("checkedunknown", false);
if (checkedUnknown) {
boolean isUnknown = contactExists(ctx, number);
if (isUnknown == false) {
AlertDialog.Builder alerDialog = new AlertDialog.Builder(ctx);
alerDialog.setIcon(R.drawable.calllogo);
alerDialog.setTitle(number);
alerDialog.setMessage("Save this number ?");
alerDialog.setCancelable(false);
alerDialog.setPositiveButton("YES", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
Intent intent = new Intent(ctx, CategoryPhoneActivity.class);
intent.putExtra("Phone", number);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
ctx.startActivity(intent);
}
});
alerDialog.setNegativeButton("NO", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.cancel();
}
});
AlertDialog aldialog = alerDialog.create();
aldialog.setCanceledOnTouchOutside(false);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
aldialog.getWindow().setType(WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY); } else {
aldialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
}
aldialog.show(); } else {
Toast.makeText(ctx, "Number is already saved", Toast.LENGTH_SHORT).show(); }
}else{
AlertDialog.Builder alerDialog = new AlertDialog.Builder(ctx);
alerDialog.setIcon(R.drawable.calllogo);
alerDialog.setTitle(number);
alerDialog.setCancelable(false);
alerDialog.setMessage("Save this number ?");
alerDialog.setPositiveButton("YES", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
Intent intent = new Intent(ctx, CategoryPhoneActivity.class);
intent.putExtra("Phone", number);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
ctx.startActivity(intent);
}
});
alerDialog.setNegativeButton("NO", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.cancel();
}
});
AlertDialog aldialog = alerDialog.create();
aldialog.setCanceledOnTouchOutside(false);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
aldialog.getWindow().setType(WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY); } else {
aldialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
}
aldialog.show(); }
}
@Override
protected void onOutgoingCallEnded(Context ctx, String number, Date start, Date end) {
}
@Override
protected void onMissedCall(final Context ctx, final String number, Date start) {
Toast.makeText(ctx, "Missed call from " + number, Toast.LENGTH_SHORT).show();
databaseHelper = new DatabaseHelper(ctx);
if (databaseHelper.searchContact(number)){
return;
}
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(ctx);
final SharedPreferences.Editor editor = preferences.edit();
boolean checked = preferences.getBoolean("checked", false);
if (checked) {
SharedPreferences preferencesUnknown = PreferenceManager.getDefaultSharedPreferences(ctx);
final SharedPreferences.Editor editorUnknown = preferencesUnknown.edit();
boolean checkedUnknown = preferencesUnknown.getBoolean("checkedunknown", false);
if (checkedUnknown) {
boolean isUnknown = contactExists(ctx, number);
if (isUnknown == false) {
AlertDialog.Builder alerDialog = new AlertDialog.Builder(ctx);
alerDialog.setIcon(R.drawable.calllogo);
alerDialog.setTitle(number);
alerDialog.setMessage("Save this number ?");
alerDialog.setPositiveButton("YES", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
Intent intent = new Intent(ctx, CategoryPhoneActivity.class);
intent.putExtra("Phone", number);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
ctx.startActivity(intent);
}
});
alerDialog.setNegativeButton("NO", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.cancel();
}
});
AlertDialog aldialog = alerDialog.create();
aldialog.setCanceledOnTouchOutside(false);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
aldialog.getWindow().setType(WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY); } else {
aldialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
}
aldialog.show(); } else {
Toast.makeText(ctx, "Number is already saved", Toast.LENGTH_SHORT).show(); }
}else{
AlertDialog.Builder alerDialog = new AlertDialog.Builder(ctx);
alerDialog.setIcon(R.drawable.calllogo);
alerDialog.setTitle(number);
alerDialog.setMessage("Save this number ?");
alerDialog.setPositiveButton("YES", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
Intent intent = new Intent(ctx, CategoryPhoneActivity.class);
intent.putExtra("Phone", number);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
ctx.startActivity(intent);
}
});
alerDialog.setNegativeButton("NO", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.cancel();
}
});
AlertDialog aldialog = alerDialog.create();
aldialog.setCanceledOnTouchOutside(false);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
aldialog.getWindow().setType(WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY); } else {
aldialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
}
aldialog.show(); }
}else{
Toast.makeText(ctx, "", Toast.LENGTH_SHORT).show(); }
}
public boolean contactExists(Context context, String number) {
Uri lookupUri = Uri.withAppendedPath(
ContactsContract.PhoneLookup.CONTENT_FILTER_URI,
Uri.encode(number));
String[] mPhoneNumberProjection = { ContactsContract.PhoneLookup._ID, ContactsContract.PhoneLookup.NUMBER, ContactsContract.PhoneLookup.DISPLAY_NAME };
Cursor cur = context.getContentResolver().query(lookupUri,mPhoneNumberProjection, null, null, null);
try {
if (cur.moveToFirst()) {
return true;
}
} finally {
if (cur != null)
cur.close();
}
return false;
}
}
Beginning with Android 8.0 (API level 26), the system imposes additional restrictions on manifest-declared receivers.
If your app targets Android 8.0 or higher, you cannot use the manifest to declare a receiver for most implicit broadcasts (broadcasts that don't target your app specifically). You can still use a context-registered receiver when the user is actively using your app.
我猜系统会在您关闭应用程序时自动注销您的 broadcast receivers
。
解决方案: 创建粘性或前台服务并在服务中注册您的广播接收器。当您接收广播时,启动 activity 并显示来自广播接收器 onReceive
的对话框。