Android、TelephonyManager、PhoneStateListener 和传入号码的乐趣
Android, TelephonyManager, the joys of PhoneStateListener and incoming numbers
我刚刚进入 Android
开发,并决定我在这个新领域的第一个征服将是掌握 phone 对来电的反应。
后来用谷歌搜索了一下 http://www.compiletimeerror.com/2013/08/android-call-state-listener-example.html#.Vi3Ren4vfwM(所以我的代码与 his/hers 非常相似)。
我的主要(也是唯一)activity 看起来像这样:
import android.app.Activity;
import android.content.Context;
import android.os.Bundle;
import android.telephony.PhoneStateListener;
import android.telephony.TelephonyManager;
import android.util.Log;
import android.view.Menu;
import android.widget.Toast;
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
TelephonyManager TelephonyMgr = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
TelephonyMgr.listen(new TeleListener(),
PhoneStateListener.LISTEN_CALL_STATE);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.activity_main, menu);
return true;
}
class TeleListener extends PhoneStateListener {
public void onCallStateChanged(int state, String incomingNumber) {
super.onCallStateChanged(state, incomingNumber);
switch (state) {
case TelephonyManager.CALL_STATE_IDLE:
// CALL_STATE_IDLE;
Log.d("MyLittleDebugger", "I'm in " + state + " and the number is " + incomingNumber);
Toast.makeText(getApplicationContext(), "CALL_STATE_IDLE",
Toast.LENGTH_LONG).show();
break;
case TelephonyManager.CALL_STATE_OFFHOOK:
// CALL_STATE_OFFHOOK;
Log.d("MyLittleDebugger", "I'm in " + state + " and the number is " + incomingNumber);
Toast.makeText(getApplicationContext(), "CALL_STATE_OFFHOOK",
Toast.LENGTH_LONG).show();
break;
case TelephonyManager.CALL_STATE_RINGING:
// CALL_STATE_RINGING
Log.d("MyLittleDebugger", "I'm in " + state + " and the number is " + incomingNumber);
Toast.makeText(getApplicationContext(), incomingNumber,
Toast.LENGTH_LONG).show();
Toast.makeText(getApplicationContext(), "CALL_STATE_RINGING",
Toast.LENGTH_LONG).show();
break;
default:
break;
}
}
}
}
现在,乐趣就到此为止了。我在模拟器上安装了应用程序 运行,并使用 DDMS
对我的模拟设备进行了几次 phone 调用,以查看碎片在哪里。
肯定有足够多的吐司弹出并且 MyLittleDebugger
在状态交换时爆发。侦听器正在工作,但是我的日志或 toast 中从未显示任何数字。
本来应该是数字的地方是空白!不为空或任何东西,不,但空白!
经过更多的谷歌搜索,我意识到我的 AndroidManifest.xml
可能是问题所在。如下:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.x.xy" >
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
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>
</application>
现在,问题来了:我错过了什么?
很明显,某处有一小部分出了问题,因为我可以让我的 TelephonyMgr
对象 .listen()
调用状态,但我无法获得要显示的号码.
新信息:
我也在我的 phone 上尝试过这个,但没有模拟到完全相同的结果。
我会建议您 运行 您的应用真正运行 phone!
phone 电话号码并非在所有通知中都可用的原因有多种,但如果呼叫来自真实的 phone 网络,则您更有可能获得电话号码提供号码。
您可能需要使用广播接收器,它可以帮助您实现您想要实现的目标。
创建 class 扩展广播接收器并尝试捕获传入的号码。
public class MyReceiver extends BroadcastReceiver {
@Override
public void onReceive(final Context context, Intent intent) {
TelephonyManager mtelephony = (TelephonyManager)context.getSystemService(Context.TELEPHONY_SERVICE);
mtelephony.listen(new PhoneStateListener(){
@Override
public void onCallStateChanged(int state, String incomingNumber) {
super.onCallStateChanged(state, incomingNumber);
switch (state) {
case TelephonyManager.CALL_STATE_RINGING:
// CALL_STATE_RINGING
Log.d("MyLittleDebugger", "I'm in " + state + " and the number is " + incomingNumber);
Toast.makeText(getApplicationContext(), incomingNumber,
Toast.LENGTH_LONG).show();
Toast.makeText(getApplicationContext(), "CALL_STATE_RINGING",
Toast.LENGTH_LONG).show();
break;
default:
break;
}
}
},PhoneStateListener.LISTEN_CALL_STATE);
}
并且在您的清单中也有这一行。
<receiver android:name=".MyReceiver" >
<intent-filter>
<action android:name="android.intent.action.PHONE_STATE" />
</intent-filter>
</receiver>
我没有使用 TelephonyManager
的 listen
函数,但我确实成功地使用了 BroadcastReceiver 来获取 phone 状态变化和 phone 数字。
在 Activity 或清单中注册您的接收器(如果您想在应用程序处于后台时接收更新):
Activity:
@Override
protected void onResume() {
super.onResume();
BroadcastReceiver receiver = new PhoneStateBroadcastReceiver();
IntentFilter filter= new IntentFilter();
filter.addAction("android.intent.action.PHONE_STATE");
filter.addAction("android.intent.action.NEW_OUTGOING_CALL");
registerReceiver(reciever, filter);
}
@Override
protected void onPause() {
super.onPause();
unregisterReceiver(reciever);
}
清单:
<receiver
android:name=".PhoneStateBroadcastReceiver"
android:permission="android.permission.READ_PHONE_STATE" >
<intent-filter>
<action android:name="android.intent.action.PHONE_STATE" />
<action android:name="android.intent.action.NEW_OUTGOING_CALL" />
</intent-filter>
</receiver>
和一个基本接收器:
public class PhoneStateBroadcastReceiver extends BroadcastReceiver {
private final String TAG = getClass().getName();
private static String number = null;
@Override
public void onReceive(final Context context, final Intent intent) {
if (intent.getAction().equals(TelephonyManager.ACTION_PHONE_STATE_CHANGED)) {
String state = intent.getStringExtra(TelephonyManager.EXTRA_STATE);
Log.d(TAG, intent.getAction() + ", EXTRA_STATE: " + state);
// on ringing get incoming number
if (state.equals(TelephonyManager.EXTRA_STATE_RINGING)) {
number = intent.getStringExtra(TelephonyManager.EXTRA_INCOMING_NUMBER);
Log.d(TAG, "EXTRA_INCOMING_NUMBER: " + number);
}
}
if (intent.getAction().equals(Intent.ACTION_NEW_OUTGOING_CALL)) {
number = intent.getStringExtra(Intent.EXTRA_PHONE_NUMBER);
Log.d(TAG, intent.getAction() + ", EXTRA_PHONE_NUMBER: " + number);
}
}
}
在这个 SO 答案中,您可以找到一个很好的实现,它也可以处理多个调用:
我刚刚进入 Android
开发,并决定我在这个新领域的第一个征服将是掌握 phone 对来电的反应。
后来用谷歌搜索了一下 http://www.compiletimeerror.com/2013/08/android-call-state-listener-example.html#.Vi3Ren4vfwM(所以我的代码与 his/hers 非常相似)。
我的主要(也是唯一)activity 看起来像这样:
import android.app.Activity;
import android.content.Context;
import android.os.Bundle;
import android.telephony.PhoneStateListener;
import android.telephony.TelephonyManager;
import android.util.Log;
import android.view.Menu;
import android.widget.Toast;
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
TelephonyManager TelephonyMgr = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
TelephonyMgr.listen(new TeleListener(),
PhoneStateListener.LISTEN_CALL_STATE);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.activity_main, menu);
return true;
}
class TeleListener extends PhoneStateListener {
public void onCallStateChanged(int state, String incomingNumber) {
super.onCallStateChanged(state, incomingNumber);
switch (state) {
case TelephonyManager.CALL_STATE_IDLE:
// CALL_STATE_IDLE;
Log.d("MyLittleDebugger", "I'm in " + state + " and the number is " + incomingNumber);
Toast.makeText(getApplicationContext(), "CALL_STATE_IDLE",
Toast.LENGTH_LONG).show();
break;
case TelephonyManager.CALL_STATE_OFFHOOK:
// CALL_STATE_OFFHOOK;
Log.d("MyLittleDebugger", "I'm in " + state + " and the number is " + incomingNumber);
Toast.makeText(getApplicationContext(), "CALL_STATE_OFFHOOK",
Toast.LENGTH_LONG).show();
break;
case TelephonyManager.CALL_STATE_RINGING:
// CALL_STATE_RINGING
Log.d("MyLittleDebugger", "I'm in " + state + " and the number is " + incomingNumber);
Toast.makeText(getApplicationContext(), incomingNumber,
Toast.LENGTH_LONG).show();
Toast.makeText(getApplicationContext(), "CALL_STATE_RINGING",
Toast.LENGTH_LONG).show();
break;
default:
break;
}
}
}
}
现在,乐趣就到此为止了。我在模拟器上安装了应用程序 运行,并使用 DDMS
对我的模拟设备进行了几次 phone 调用,以查看碎片在哪里。
肯定有足够多的吐司弹出并且 MyLittleDebugger
在状态交换时爆发。侦听器正在工作,但是我的日志或 toast 中从未显示任何数字。
本来应该是数字的地方是空白!不为空或任何东西,不,但空白!
经过更多的谷歌搜索,我意识到我的 AndroidManifest.xml
可能是问题所在。如下:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.x.xy" >
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
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>
</application>
现在,问题来了:我错过了什么?
很明显,某处有一小部分出了问题,因为我可以让我的 TelephonyMgr
对象 .listen()
调用状态,但我无法获得要显示的号码.
新信息:
我也在我的 phone 上尝试过这个,但没有模拟到完全相同的结果。
我会建议您 运行 您的应用真正运行 phone!
phone 电话号码并非在所有通知中都可用的原因有多种,但如果呼叫来自真实的 phone 网络,则您更有可能获得电话号码提供号码。
您可能需要使用广播接收器,它可以帮助您实现您想要实现的目标。 创建 class 扩展广播接收器并尝试捕获传入的号码。
public class MyReceiver extends BroadcastReceiver {
@Override
public void onReceive(final Context context, Intent intent) {
TelephonyManager mtelephony = (TelephonyManager)context.getSystemService(Context.TELEPHONY_SERVICE);
mtelephony.listen(new PhoneStateListener(){
@Override
public void onCallStateChanged(int state, String incomingNumber) {
super.onCallStateChanged(state, incomingNumber);
switch (state) {
case TelephonyManager.CALL_STATE_RINGING:
// CALL_STATE_RINGING
Log.d("MyLittleDebugger", "I'm in " + state + " and the number is " + incomingNumber);
Toast.makeText(getApplicationContext(), incomingNumber,
Toast.LENGTH_LONG).show();
Toast.makeText(getApplicationContext(), "CALL_STATE_RINGING",
Toast.LENGTH_LONG).show();
break;
default:
break;
}
}
},PhoneStateListener.LISTEN_CALL_STATE);
}
并且在您的清单中也有这一行。
<receiver android:name=".MyReceiver" >
<intent-filter>
<action android:name="android.intent.action.PHONE_STATE" />
</intent-filter>
</receiver>
我没有使用 TelephonyManager
的 listen
函数,但我确实成功地使用了 BroadcastReceiver 来获取 phone 状态变化和 phone 数字。
在 Activity 或清单中注册您的接收器(如果您想在应用程序处于后台时接收更新):
Activity:
@Override
protected void onResume() {
super.onResume();
BroadcastReceiver receiver = new PhoneStateBroadcastReceiver();
IntentFilter filter= new IntentFilter();
filter.addAction("android.intent.action.PHONE_STATE");
filter.addAction("android.intent.action.NEW_OUTGOING_CALL");
registerReceiver(reciever, filter);
}
@Override
protected void onPause() {
super.onPause();
unregisterReceiver(reciever);
}
清单:
<receiver
android:name=".PhoneStateBroadcastReceiver"
android:permission="android.permission.READ_PHONE_STATE" >
<intent-filter>
<action android:name="android.intent.action.PHONE_STATE" />
<action android:name="android.intent.action.NEW_OUTGOING_CALL" />
</intent-filter>
</receiver>
和一个基本接收器:
public class PhoneStateBroadcastReceiver extends BroadcastReceiver {
private final String TAG = getClass().getName();
private static String number = null;
@Override
public void onReceive(final Context context, final Intent intent) {
if (intent.getAction().equals(TelephonyManager.ACTION_PHONE_STATE_CHANGED)) {
String state = intent.getStringExtra(TelephonyManager.EXTRA_STATE);
Log.d(TAG, intent.getAction() + ", EXTRA_STATE: " + state);
// on ringing get incoming number
if (state.equals(TelephonyManager.EXTRA_STATE_RINGING)) {
number = intent.getStringExtra(TelephonyManager.EXTRA_INCOMING_NUMBER);
Log.d(TAG, "EXTRA_INCOMING_NUMBER: " + number);
}
}
if (intent.getAction().equals(Intent.ACTION_NEW_OUTGOING_CALL)) {
number = intent.getStringExtra(Intent.EXTRA_PHONE_NUMBER);
Log.d(TAG, intent.getAction() + ", EXTRA_PHONE_NUMBER: " + number);
}
}
}
在这个 SO 答案中,您可以找到一个很好的实现,它也可以处理多个调用: