我试图阻止来自特定号码的来电,我设法检测到来电及其号码。 但是,我无法阻止通话。我查看了我在本网站和其他网站上找到的所有代码,我开始认为,由于新版本的android或每个设备的核心差异(我拥有LG4),代码可能无法正常工作)。
还有一个人认为,任何人都可以向我解释在这个软件包中创建ITelephony的重要性:
package com.android.internal.telephony;
这是我的代码:
package com.darkmoonapps.telephony;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.telephony.TelephonyManager;
import android.widget.Toast;
import com.android.internal.telephony.ITelephony;
import java.lang.reflect.Method;
/**
* Created by Shai on 19/12/2017.
*/
public class incomingCalls extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
ITelephony telephonyService;
try {
String state = intent.getStringExtra(TelephonyManager.EXTRA_STATE);
String number = intent.getExtras().getString(TelephonyManager.EXTRA_INCOMING_NUMBER);
if(state.equalsIgnoreCase(TelephonyManager.EXTRA_STATE_RINGING)){
TelephonyManager tm = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
try {
Method m = tm.getClass().getDeclaredMethod("getITelephony");
m.setAccessible(true);
telephonyService = (ITelephony) m.invoke(tm);
if ((number != null)) {
telephonyService.endCall();
}
} catch (Exception e) {
e.printStackTrace();
}
Toast.makeText(context, "Ring " + number, Toast.LENGTH_SHORT).show();
}
if(state.equalsIgnoreCase(TelephonyManager.EXTRA_STATE_OFFHOOK)){
Toast.makeText(context, "Answered " + number, Toast.LENGTH_SHORT).show();
}
if(state.equalsIgnoreCase(TelephonyManager.EXTRA_STATE_IDLE)){
Toast.makeText(context, "Idle "+ number, Toast.LENGTH_SHORT).show();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
这是我的电话:
package com.android.internal.telephony;
/**
* Created by Shai on 19/12/2017.
*/
public interface ITelephony {
boolean endCall();
void answerRingingCall();
void silenceRinger();
}
谢谢!
答案 0 :(得分:1)
我遇到了和你一样的问题。我找到了解决方案并在my blog上逐步记录了它。
这是我所缺少的最重要的部分:在运行时请求权限。这是妨碍我成功实现这一目标的一件事!
即,在Android 6.0及之后,即使您在AndroidManifest.xml
文件中设置了权限,如果他们属于危险权限类别,您仍然必须明确询问用户。
要在此处申请此类权限,您可以使用的代码(我在MainActivity.java
方法的onCreate
中使用了该代码):
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) {
if (checkSelfPermission(Manifest.permission.READ_PHONE_STATE) == PackageManager.PERMISSION_DENIED || checkSelfPermission(Manifest.permission.CALL_PHONE) == PackageManager.PERMISSION_DENIED) {
String[] permissions = {Manifest.permission.READ_PHONE_STATE, Manifest.permission.CALL_PHONE};
requestPermissions(permissions, PERMISSION_REQUEST_READ_PHONE_STATE);
}
}
这里有完整内容的帖子:
在这篇文章中,我将逐步向您展示如何制作可以阻止某些号码呼叫您的原生Android应用。
源代码为on Github。
我希望我将在此向您展示的分步指南将帮助您,使您免于进行其他研究。
当然,由于我在日常工作中不是本地Android开发人员,所以我也这样做,因为它可以作为我提醒我的好时机。我需要再次处理类似的情况。向你们其他人大喊#jackOfAllTrades out
另外,鉴于上述声明;我将不胜感激有关此代码的任何反馈。
我花了很多时间浏览StackOverflow和博客文章以寻找此解决方案。在所有这些中,这些都很有帮助:
但遗憾的是,这些都不是直截了当的初学者教程。所以,经过大量的额外研究后,我才开始工作,这是我解释方法的最佳尝试。
作为旁注:在测试时,how to simulate an incoming call or SMS to an emulator in Android Studio的发现也非常有用。
在Android Studio中,转到File->New->New Project
,为其指定名称和位置,然后点击Next
:
保留最低API级别的默认选项:
选择Empty Activity
模板:
保留活动名称:
在uses-permission
文件中设置权限(两个receiver
代码)和AndroidManifest.xml
代码:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.nikola.callblockingtestdemo">
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.CALL_PHONE" />
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<receiver android:name=".IncomingCallReceiver" android:enabled="true" android:exported="true">
<intent-filter>
<action android:name="android.intent.action.PHONE_STATE" />
</intent-filter>
</receiver>
</application>
</manifest>
使用READ_PHONE_STATE
权限,我们可以获得此权限(如official docs中所定义):
允许对电话状态进行只读访问,包括设备的电话号码,当前的蜂窝网络信息,任何正在进行的呼叫的状态以及设备上注册的任何PhoneAccounts列表。
使用CALL_PHONE
权限,我们可以获得此权限(如official docs中所定义):
允许应用程序在不通过拨号器用户界面的情况下发起电话呼叫,以便用户确认呼叫。
⚠️我发现虽然这里没有说明,但我需要此权限才能以编程方式结束通话。
receiver
标记用于定义将处理android.intent.action.PHONE_STATE
的广播操作的类。当顾名思义,电话呼叫状态发生变化(我们接听电话,拒绝接听电话,正在通话等)时,Android操作系统将广播此操作。
创建一个新类(File->New->Java Class
),将其命名为IncomingCallReceiver
并粘贴此代码(注意:您的package
名称将与我的名称不同! ):
package com.example.nikola.callblockingtestdemo;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.telephony.TelephonyManager;
import android.widget.Toast;
import java.lang.reflect.Method;
import com.android.internal.telephony.ITelephony;
public class IncomingCallReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
ITelephony telephonyService;
try {
String state = intent.getStringExtra(TelephonyManager.EXTRA_STATE);
String number = intent.getExtras().getString(TelephonyManager.EXTRA_INCOMING_NUMBER);
if(state.equalsIgnoreCase(TelephonyManager.EXTRA_STATE_RINGING)){
TelephonyManager tm = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
try {
Method m = tm.getClass().getDeclaredMethod("getITelephony");
m.setAccessible(true);
telephonyService = (ITelephony) m.invoke(tm);
if ((number != null)) {
telephonyService.endCall();
Toast.makeText(context, "Ending the call from: " + number, Toast.LENGTH_SHORT).show();
}
} catch (Exception e) {
e.printStackTrace();
}
Toast.makeText(context, "Ring " + number, Toast.LENGTH_SHORT).show();
}
if(state.equalsIgnoreCase(TelephonyManager.EXTRA_STATE_OFFHOOK)){
Toast.makeText(context, "Answered " + number, Toast.LENGTH_SHORT).show();
}
if(state.equalsIgnoreCase(TelephonyManager.EXTRA_STATE_IDLE)){
Toast.makeText(context, "Idle "+ number, Toast.LENGTH_SHORT).show();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
在Android中,如果我们想要获得&#39;来自BroadcastReceiver
的数据,我们需要继承BroadcastReceiver
类,我们需要覆盖onReceive
方法。在此方法中,我们使用TelephonyManager
来获取通话状态,并且我们正在使用ITelephony
界面结束通话。
老实说,这是一个有点“奇怪”的地方,至于获取此ITelephony
界面,您需要创建ITelephony
界面。
为此,请创建一个新类(File->New->Java Class
),将其命名为ITelephony
并粘贴此代码(注意:使用以下内容覆盖所有内容;是的,即使是奇怪的包名称的):
package com.android.internal.telephony;
public interface ITelephony {
boolean endCall();
void answerRingingCall();
void silenceRinger();
}
Android Studio会抱怨package com.android.internal.telephony;
(此软件包名称下的红色波浪点),但是必须如何设置才能使其工作。我没有找到确切的解释,为什么必须包含它,所以如果你知道,请在评论中分享。
这是妨碍我成功实现这一目标的一件事!
即使在Android 6.0及更高版本之后,即使您在AndroidManifest.xml
文件中设置了权限,如果属于危险类别,您仍需要明确询问用户权限。这是此类权限的列表:
要在此处请求此类权限,您可以使用的代码(我在MainActivity.java
方法的onCreate
中使用了该代码):
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) {
if (checkSelfPermission(Manifest.permission.READ_PHONE_STATE) == PackageManager.PERMISSION_DENIED || checkSelfPermission(Manifest.permission.CALL_PHONE) == PackageManager.PERMISSION_DENIED) {
String[] permissions = {Manifest.permission.READ_PHONE_STATE, Manifest.permission.CALL_PHONE};
requestPermissions(permissions, PERMISSION_REQUEST_READ_PHONE_STATE);
}
}
PERMISSION_REQUEST_READ_PHONE_STATE
变量用于确定onRequestPermissionsResult
方法中要求的权限。当然,如果您不需要执行任何逻辑,具体取决于用户是否批准了该权限,您可以省略此方法:
@Override
public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {
switch (requestCode) {
case PERMISSION_REQUEST_READ_PHONE_STATE: {
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
Toast.makeText(this, "Permission granted: " + PERMISSION_REQUEST_READ_PHONE_STATE, Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(this, "Permission NOT granted: " + PERMISSION_REQUEST_READ_PHONE_STATE, Toast.LENGTH_SHORT).show();
}
return;
}
}
}
这就是应用在运行中的样子,在模拟器上测试以及在Android Studio中使用Android Device Monitor触发的调用:
在这篇文章中,我向您展示了如何制作可以阻止某些号码呼叫您的原生Android应用。我指出了我所面对的拦截器,我还在寻找一个解决方案来隐藏一个原生的来电弹出窗口,这个弹出窗口有时会在呼叫被拒绝之前显示一小段时间。
所以,如果您有任何想法,我可以接受建议