USSD 杂记
Android Oreo允许应用程序读取来自运营商的USSD消息。
利用emoney执行话费充值,需要执行USSD代码,尝试编写apk执行ussd代码进行充值。
尝试在Android8的系统上进行USSD session交互,发现暂时没有解决方案。。。。
尝试一次性发送所有USSD,*123*1*5*1256#,发现如果到了需要输入类似密码之类的自定义字符串时,会失败。
只能发送第一个USSD代码,无法进行后续的菜单交互。如果只需要调用USSD获取话费余额、套餐情况的请拿走。
代码如下:
package com.zongh.dbussd; import android.annotation.TargetApi;
import android.app.Activity;
import android.content.Context;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.ResultReceiver;
import android.telecom.TelecomManager;
import android.telephony.PhoneStateListener;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.EditText;
import android.widget.Switch;
import android.widget.Toast; import android.support.design.widget.Snackbar;
import android.support.annotation.RequiresApi; import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method; import static android.content.ContentValues.TAG; interface UssdResultNotifiable {
void notifyUssdResult(String request, String returnMessage, int resultCode);
} public class HomeActivity extends Activity implements UssdResultNotifiable { USSDSessionHandler hdl;
private TelephonyManager telephonyManager;
private PhoneCallListener listener;
private TelecomManager telecomManager; @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_home);
} public void onUssdSend(View view) {
//USSDHandler callback = new USSDHandler(view);
/* if (checkSelfPermission(Manifest.permission.CALL_PHONE) != PackageManager.PERMISSION_GRANTED) {
*//*if(ActivityCompat.shouldShowRequestPermissionRationale(HomeActivity.this, Manifest.permission.CALL_PHONE))
{ }
else
{*//*
//ActivityCompat.requestPermissions(HomeActivity.this, new String[]{Manifest.permission.CALL_PHONE}, 0);
// }
Snackbar.make(view, "permissions were missing", Snackbar.LENGTH_LONG)
.setAction("Response", null).show();
return;
}*/
//HomeActivity.this.telephonyManager.sendUssdRequest("*#123*99#", callback, new Handler()); hdl = new USSDSessionHandler(HomeActivity.this, HomeActivity.this); hdl.doSession(((EditText)this.findViewById(R.id.ussdText)).getText().toString()); } @Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
// getMenuInflater().inflate(R.menu.menu_home, menu);
return true;
} @Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId(); //noinspection SimplifiableIfStatement
// if (id == R.id.action_settings) {
// return true;
// } return super.onOptionsItemSelected(item);
} public void toggleListener(View v) {
if (((Switch) v).isChecked()) {
this.listenForTelephony();
Toast.makeText(this, "Listening for calls", Toast.LENGTH_LONG).show();
} else {
this.stopListeningForTelephony();
}
} private void listenForTelephony() {
this.telephonyManager = (TelephonyManager) this.getSystemService(this.TELEPHONY_SERVICE);
this.telecomManager = (TelecomManager) this.getSystemService(this.TELECOM_SERVICE);
this.listener = new PhoneCallListener();
telephonyManager.listen(listener, PhoneStateListener.LISTEN_CALL_STATE);
} private void stopListeningForTelephony() {
this.telephonyManager = null;
this.telecomManager = null;
} @Override
public void notifyUssdResult(final String request, final String returnMessage, final int resultCode) {
this.runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(HomeActivity.this, "Request was " + request + "\n response is " + returnMessage + "\n result code is " + resultCode, Toast.LENGTH_LONG).show(); }
}); } class PhoneCallListener extends PhoneStateListener {
@RequiresApi(api = Build.VERSION_CODES.M)
@Override
public void onCallStateChanged(int state, String incomingNumber) { switch (state) {
case TelephonyManager.CALL_STATE_RINGING:
HomeActivity.this.telecomManager.acceptRingingCall();
break;
case TelephonyManager.CALL_STATE_IDLE:
Toast.makeText(HomeActivity.this, "Call is no longer active...", Toast.LENGTH_LONG);
break;
}
}
} @TargetApi(Build.VERSION_CODES.O)
class USSDHandler extends TelephonyManager.UssdResponseCallback { View parent; USSDHandler(View v) {
this.parent = v;
} @Override
public void onReceiveUssdResponse(TelephonyManager telephonyManager, String request, CharSequence response) {
super.onReceiveUssdResponse(telephonyManager, request, response);
Snackbar.make(this.parent, response, Snackbar.LENGTH_LONG)
.setAction("Response", null).show();
} @Override
public void onReceiveUssdResponseFailed(TelephonyManager telephonyManager, String request, int failureCode) {
super.onReceiveUssdResponseFailed(telephonyManager, request, failureCode);
Snackbar.make(this.parent, "error is " + failureCode + " for req " + request, Snackbar.LENGTH_LONG)
.setAction("Response", null).show();
}
} } class USSDSessionHandler { TelephonyManager tm;
private UssdResultNotifiable client;
private Method handleUssdRequest;
private Object iTelephony; USSDSessionHandler(Context parent, UssdResultNotifiable client) {
this.client = client;
this.tm = (TelephonyManager) parent.getSystemService(Context.TELEPHONY_SERVICE);
try {
this.getUssdRequestMethod();
} catch (Exception ex) {
//log
} } private void getUssdRequestMethod() throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException {
if (tm != null) {
Class telephonyManagerClass = Class.forName(tm.getClass().getName());
if (telephonyManagerClass != null) {
Method getITelephony = telephonyManagerClass.getDeclaredMethod("getITelephony");
getITelephony.setAccessible(true);
this.iTelephony = getITelephony.invoke(tm); // Get the internal ITelephony object
Method[] methodList = iTelephony.getClass().getMethods();
this.handleUssdRequest = null;
/*
* Somehow, the method wouldn't come up if I simply used:
* iTelephony.getClass().getMethod('handleUssdRequest')
*/ for (Method _m : methodList)
if (_m.getName().equals("handleUssdRequest")) {
handleUssdRequest = _m;
break;
}
}
}
} public void doSession(String ussdRequest) {
try { if (handleUssdRequest != null) {
handleUssdRequest.setAccessible(true);
handleUssdRequest.invoke(iTelephony, SubscriptionManager.getDefaultSubscriptionId(), ussdRequest, new ResultReceiver(new Handler()) { @Override
protected void onReceiveResult(int resultCode, Bundle ussdResponse) {
/*
* Usually you should the getParcelable() response to some Parcel
* child class but that's not possible here, since the "UssdResponse"
* class isn't in the SDK so we need to
* reflect again to get the result of getReturnMessage() and
* finally return that!
*/ Object p = ussdResponse.getParcelable("USSD_RESPONSE"); if (p != null) { Method[] methodList = p.getClass().getMethods();
for(Method m : methodList)
{
Log.i(TAG, "onReceiveResult: " + m.getName());
}
try {
CharSequence returnMessage = (CharSequence) p.getClass().getMethod("getReturnMessage").invoke(p);
CharSequence request = (CharSequence) p.getClass().getMethod("getUssdRequest").invoke(p);
USSDSessionHandler.this.client.notifyUssdResult("" + request, "" + returnMessage, resultCode); //they could be null
} catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
e.printStackTrace();
}
}
} });
}
} catch (IllegalAccessException | InvocationTargetException e1) {
e1.printStackTrace();
}
}
}
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".HomeActivity"> <LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"> <TextView
android:id="@+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="USSD Input"
android:textSize="18sp" /> <EditText
android:id="@+id/ussdText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:ems="10"
android:inputType="textPersonName" />
</LinearLayout> <Button
android:id="@+id/button"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:onClick="onUssdSend"
android:text="send" />
</LinearLayout>
USSD 杂记的更多相关文章
- [Erlang 0118] Erlang 杂记 V
我在知乎回答问题不多,这个问题: "对你职业生涯帮助最大的习惯是什么?它是如何帮助你的?",我还是主动回答了一下. 做笔记 一开始笔记软件做的不好的时候就发邮件给自己, ...
- Ubuntu杂记——Ubuntu下用虚拟机共享上网
由于最近把自己电脑环境换成了Ubuntu,但学校的网络是电信的闪讯,大学里用过的人都知道这货有多坑,而且没有Linux客户端,上网都是问题,怪不得国内用Linux的人那么少,特别是高校的学生(让我瞎逼 ...
- 一个ubuntu phper的自我修养(杂记)
ubuntu使用杂记 1.flatabulous安装使用. flatabulous是一个ubuntu图标主题. 使用它,必须得安装tweak插件. sudo add-apt-repository pp ...
- 有关Java的日期处理的一些杂记
在企业应用开发中,经常会遇到日期的相关处理,说实话JDK自带的日期方法很难用.就我个人而言我一般都会采用joda-time来替代JDK自身的日期. 这篇文章是杂记,所以写的比较零散,希望大家不要见怪. ...
- 分布式系统之CAP理论杂记[转]
分布式系统之CAP理论杂记 http://www.cnblogs.com/highriver/archive/2011/09/15/2176833.html 分布式系统的CAP理论: 理论首先把分布式 ...
- Redis杂记
参考资料: Redis 教程 | 菜鸟教程 : http://www.runoob.com/redis/redis-tutorial.html Redis快速入门 :http://www.yiibai ...
- MySQL杂记
参考资料: w3school SQL 教程 : http://www.w3school.com.cn/sql/index.asp 21分钟 MySQL 入门教程 : http://www.cnblo ...
- Android之开发杂记(一)
1.cygwin环境变量设置 可在Cygwin.bat 中设置 set NDK_ROOT=P:/android/android-ndk-r8e 或者在home\Administrator\.bash_ ...
- ios程序开发杂记
ios程序开发杂记 一.程序构建 与一般的程序构建无太大区别,都是源文件编译链接这一套,通常是在mac上做交叉编译,也就是利用xcode里带的ios编译工具集去生成arm架构的ios程序(或是x86的 ...
随机推荐
- 解决TCPDF中文乱码,PHP
/* **主要是这个单词控制 stsongstdlight **/ $this->SetFont('stsongstdlight', 'B', 10);
- python从入门到实践-10章文件和异常(括号问题)
#!/user/bin/env python# -*- coding:utf-8 -*- # 1.从文件中读取数据with open('pi_digits.txt') as file_object: ...
- [安卓] 20、基于蓝牙BLE的广播包高频快速搜索
前言: 之前介绍过很多蓝牙beacon.搜索.连接.通讯的文章.不过最近我发现:之前写的蓝牙广播包搜索的工程,搜索频率太慢,而且不能一直保持搜索状态.因此,这里探讨下高频蓝牙广播包扫描 -- 蓝牙BL ...
- 算法与数据结构(十二) 散列(哈希)表的创建与查找(Swift版)
散列表又称为哈希表(Hash Table), 是为了方便查找而生的数据结构.关于散列的表的解释,我想引用维基百科上的解释,如下所示: 散列表(Hash table,也叫哈希表),是根据键(Key)而直 ...
- emWin监护仪界面设计,含uCOS-III和FreeRTOS两个版本
第5期:监护仪界面设计 配套例子:V6-908_STemWin提高篇实验_监护仪界面设计(uCOS-III)V6-909_STemWin提高篇实验_监护仪界面设计(FreeRTOS) 例程下载地址:h ...
- Java面试中笔试题——Java代码真题,这些题会做,笔试完全可拿下!
大家好,我是上海尚学堂Java培训老师,以下这些Java笔试真题是上海尚学堂Java学员在找工作中笔试遇到的真题.现在分享出来,也写了参考答案,供大家学习借鉴.想要更多学习资料和视频请留言联系或者上海 ...
- 爱奇艺技术分享:爱奇艺Android客户端启动速度优化实践总结
本文由爱奇艺技术团队原创分享,原题<爱奇艺Android客户端启动优化与分析>. 1.引言 互联网领域里有个八秒定律,如果网页打开时间超过8秒,便会有超过70%的用户放弃等待,对Andro ...
- CSS3禁止用户选中文字——user-select: none;
需求:现在有一个需求是在移动端让你禁止用户选中文字,你会怎么做呢?如下图 解决方法:使用CSS3新增属性 user-select: none; -webkit-user-select:non ...
- 12.Flask-Restful
定义Restful的视图 安装:pip install flask-restful 如果使用Flask-restful,那么定义视图函数的时候,就要继承flask_restful.Resourse类, ...
- Jquery.ajax dataType参数
dataType 类型:String 预期服务器返回的数据类型.如果不指定,jQuery 将自动根据 HTTP 包 MIME 信息来智能判断,比如 XML MIME 类型就被识别为 XML.在 1.4 ...