阻止来电

SHA*_*I86 4 android

我试图阻止来自特定号码的来电,我设法检测到来电及其号码。但是,我很难阻止呼叫。我浏览了我在这个网站和其他网站上找到的所有代码,我开始认为,由于新版本的android或每个设备的核心差异(我拥有LG4),这些代码可能无法工作。

再想一想,谁能解释一下在这个包中创建 ITelephony 的重要性:

package com.android.internal.telephony;
Run Code Online (Sandbox Code Playgroud)

这是我的代码:

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();
        }
    }

}
Run Code Online (Sandbox Code Playgroud)

这是我的电话:

package com.android.internal.telephony;

/**
 * Created by Shai on 19/12/2017.
 */

public interface ITelephony {
    boolean endCall();
    void answerRingingCall();
    void silenceRinger();
}
Run Code Online (Sandbox Code Playgroud)

谢谢!

Nik*_*ola 5

我遇到了和你一样的问题。我找到了解决方案,并在我的博客上一步步记录了它。

\n\n

这是我遗漏的最重要的部分:在运行时请求权限。这是阻碍我成功实现这一目标的一件事!

\n\n

也就是说,在Android 6.0+之后,即使您在文件中设置了权限AndroidManifest.xml,如果它们属于危险权限类别,您仍然必须明确向用户询问它们。

\n\n

要在此处请求此类权限\xe2\x80\x99s,您可以使用代码(我在方法中使用了它MainActivity.javaonCreate

\n\n
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) {\n    if (checkSelfPermission(Manifest.permission.READ_PHONE_STATE) == PackageManager.PERMISSION_DENIED || checkSelfPermission(Manifest.permission.CALL_PHONE) == PackageManager.PERMISSION_DENIED) {\n        String[] permissions = {Manifest.permission.READ_PHONE_STATE, Manifest.permission.CALL_PHONE};\n        requestPermissions(permissions, PERMISSION_REQUEST_READ_PHONE_STATE);\n    }\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

这是帖子的完整内容:

\n\n

长话短说

\n\n

在这篇文章中,我将逐步向您展示如何制作一个可以阻止某些号码给您打电话的原生 Android 应用程序。

\n\n

源代码位于Github 上

\n\n

我希望我将在这里向您展示的分步指南能够帮助您并避免您进行额外的研究。

\n\n

当然,由于我在日常工作中不是一名原生 Android 开发人员,所以我这样做也是为了当我需要再次处理类似情况时,它可以很好地提醒我。向你们其他人大声喊叫#jackOfAllTrades

\n\n

另外,鉴于上述陈述;对于有关此代码的任何反馈,我将不胜感激。

\n\n

!TL;博士

\n\n

我花了很多时间浏览 StackOverflow 和博客文章来寻找这个解决方案。在所有这些中,这些很有帮助:

\n\n\n\n

但遗憾的是,它们都不是简单的初学者教程。因此,经过大量额外的研究,我使其发挥作用,这是我在解释如何进行的最佳尝试。

\n\n
\n

旁注:在测试时,发现如何在 Android Studio 中模拟来电或短信到模拟器也非常有帮助。

\n
\n\n

开始一个新项目

\n\n

在 Android Studio 中,转到File->New->New Project,为其指定名称和位置,然后单击Next

\n\n

\n\n

保留最低 API 级别的默认选项:

\n\n

\n\n

选择Empty Activity模板:

\n\n

\n\n

保留活动名称:

\n\n

\n\n

AndroidManifest.xml

\n\n

设置权限(两个uses-permission标签)和文件receiver中的标签AndroidManifest.xml

\n\n
<?xml version="1.0" encoding="utf-8"?>\n<manifest xmlns:android="http://schemas.android.com/apk/res/android"\n    package="com.example.nikola.callblockingtestdemo">\n\n    <uses-permission android:name="android.permission.READ_PHONE_STATE" />\n    <uses-permission android:name="android.permission.CALL_PHONE" />\n\n    <application\n        android:allowBackup="true"\n        android:icon="@mipmap/ic_launcher"\n        android:label="@string/app_name"\n        android:roundIcon="@mipmap/ic_launcher_round"\n        android:supportsRtl="true"\n        android:theme="@style/AppTheme">\n        <activity android:name=".MainActivity">\n            <intent-filter>\n                <action android:name="android.intent.action.MAIN" />\n\n                <category android:name="android.intent.category.LAUNCHER" />\n            </intent-filter>\n        </activity>\n\n        <receiver  android:name=".IncomingCallReceiver" android:enabled="true" android:exported="true">\n            <intent-filter>\n                <action android:name="android.intent.action.PHONE_STATE" />\n            </intent-filter>\n        </receiver>\n    </application>\n</manifest>\n
Run Code Online (Sandbox Code Playgroud)\n\n

READ_PHONE_STATE许可我们得到这个(如官方文档中定义的):

\n\n
\n

允许只读访问电话状态,包括设备的电话号码、当前的蜂窝网络信息、任何正在进行的通话的状态以及设备上注册的任何 PhoneAccounts 列表。

\n
\n\n

CALL_PHONE许可我们得到这个(如官方文档中定义的):

\n\n
\n

允许应用程序发起电话呼叫,而无需通过拨号器用户界面供用户确认呼叫。

\n
\n\n

\xe2\x9a\xa0\xef\xb8\x8f 我发现即使这里没有说明,我也需要此权限,以便我可以以编程方式结束调用。

\n\n

receiver标签用于定义一个将处理 的广播操作的类android.intent.action.PHONE_STATE。顾名思义,当电话状态发生变化(接到电话、拒绝接听电话、正在通话等)时,Android 操作系统将广播此操作。

\n\n

传入呼叫接收器.java

\n\n

创建一个新类 ( File->New->Java Class),调用它IncomingCallReceiver并将此代码粘贴到(注意:你的package名字将与我的不同!):

\n\n
package com.example.nikola.callblockingtestdemo;\n\nimport android.content.BroadcastReceiver;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.telephony.TelephonyManager;\nimport android.widget.Toast;\nimport java.lang.reflect.Method;\nimport com.android.internal.telephony.ITelephony;\n\npublic class IncomingCallReceiver extends BroadcastReceiver {\n    @Override\n    public void onReceive(Context context, Intent intent) {\n\n        ITelephony telephonyService;\n        try {\n            String state = intent.getStringExtra(TelephonyManager.EXTRA_STATE);\n            String number = intent.getExtras().getString(TelephonyManager.EXTRA_INCOMING_NUMBER);\n\n            if(state.equalsIgnoreCase(TelephonyManager.EXTRA_STATE_RINGING)){\n                TelephonyManager tm = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);\n                try {\n                    Method m = tm.getClass().getDeclaredMethod("getITelephony");\n\n                    m.setAccessible(true);\n                    telephonyService = (ITelephony) m.invoke(tm);\n\n                    if ((number != null)) {\n                        telephonyService.endCall();\n                        Toast.makeText(context, "Ending the call from: " + number, Toast.LENGTH_SHORT).show();\n                    }\n\n                } catch (Exception e) {\n                    e.printStackTrace();\n                }\n\n                Toast.makeText(context, "Ring " + number, Toast.LENGTH_SHORT).show();\n\n            }\n            if(state.equalsIgnoreCase(TelephonyManager.EXTRA_STATE_OFFHOOK)){\n                Toast.makeText(context, "Answered " + number, Toast.LENGTH_SHORT).show();\n            }\n            if(state.equalsIgnoreCase(TelephonyManager.EXTRA_STATE_IDLE)){\n                Toast.makeText(context, "Idle "+ number, Toast.LENGTH_SHORT).show();\n            }\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n    }\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

在Android中,如果我们想从 中“获取”数据BroadcastReceiver,我们需要继承该类BroadcastReceiver,并且需要重写该onReceive方法。在此方法中,我们使用 来TelephonyManager获取呼叫的状态,并使用该ITelephony接口来结束呼叫。

\n\n

说实话,这就是有点“奇怪”的地方,要获得这个ITelephony接口,你需要创建ITelephony接口。

\n\n

ITelephony.java

\n\n

为此,创建一个新类 ( File->New->Java Class),调用它ITelephony并将此代码粘贴到(注意:用以下内容覆盖所有内容;是的,甚至是奇怪的包名称):

\n\n
package com.android.internal.telephony;\n\npublic interface ITelephony {\n    boolean endCall();\n    void answerRingingCall();\n    void silenceRinger();\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

Android Studio 会抱怨package com.android.internal.telephony;(此包名称下的红色波浪点),但这就是它必须如何设置才能工作的方式。我没有找到为什么必须包含此内容的确切解释,所以如果您知道,请在评论中分享。

\n\n

运行时请求权限

\n\n

这是阻碍我成功实现这一目标的一件事!

\n\n

也就是说,在Android 6.0+之后,即使您在文件中设置了权限,如果它们属于危险AndroidManifest.xml权限类别,您仍然必须明确向用户询问它们。这是此类权限的列表:

\n\n
    \n
  • ACCESS_COARSE_LOCATION
  • \n
  • ACCESS_FINE_LOCATION
  • \n
  • ADD_VOICEMAIL
  • \n
  • BODY_SENSORS
  • \n
  • 呼叫电话
  • \n
  • 相机
  • \n
  • 获取帐户
  • \n
  • PROCESS_OUTGOING_CALLS
  • \n
  • READ_CALENDAR
  • \n
  • READ_CALL_LOG
  • \n
  • READ_CELL_BROADCASTS
  • \n
  • 读取联系人
  • \n
  • 读外部存储
  • \n
  • READ_PHONE_STATE
  • \n
  • 读短信
  • \n
  • 接收彩信
  • \n
  • 接收短信
  • \n
  • 接收_WAP_推送
  • \n
  • 录制音频
  • \n
  • 发简讯
  • \n
  • 使用SIP
  • \n
  • 写_日历
  • \n
  • 写调用日志
  • \n
  • 写联系人
  • \n
  • 写外部存储
  • \n
\n\n

要请求此类权限,您可以使用以下代码(我在方法中使用了它MainActivity.javaonCreate

\n\n
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) {\n    if (checkSelfPermission(Manifest.permission.READ_PHONE_STATE) == PackageManager.PERMISSION_DENIED || checkSelfPermission(Manifest.permission.CALL_PHONE) == PackageManager.PERMISSION_DENIED) {\n        String[] permissions = {Manifest.permission.READ_PHONE_STATE, Manifest.permission.CALL_PHONE};\n        requestPermissions(permissions, PERMISSION_REQUEST_READ_PHONE_STATE);\n    }\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

PERMISSION_REQUEST_READ_PHONE_STATE变量用于确定onRequestPermissionsResult方法中请求的权限。当然,如果您不需要根据用户是否批准权限执行任何逻辑,则可以省略此方法:

\n\n
@Override\npublic void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {\n    switch (requestCode) {\n        case PERMISSION_REQUEST_READ_PHONE_STATE: {\n            if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {\n                Toast.makeText(this, "Permission granted: " + PERMISSION_REQUEST_READ_PHONE_STATE, Toast.LENGTH_SHORT).show();\n            } else {\n                Toast.makeText(this, "Permission NOT granted: " + PERMISSION_REQUEST_READ_PHONE_STATE, Toast.LENGTH_SHORT).show();\n            }\n\n            return;\n        }\n    }\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

应用程序正在运行

\n\n

这是应用程序实际运行时的样子,在模拟器上进行了测试,并使用Android Studio 中的Android 设备监视器触发调用:

\n\n

\n\n

结论

\n\n

在这篇文章中,我向您展示了如何制作一个原生 Android 应用程序来阻止某些号码给您打电话。我指出了我面临的拦截器,并且我仍在寻找一种解决方案来隐藏本机来电弹出窗口,该弹出窗口有时在呼叫被拒绝之前仍会显示一小会儿。

\n\n

因此,如果您有任何想法,我愿意接受建议

\n