防止USSD对话框并读取USSD响应?
我做了许多关于ussd的研究,但我无法读取USSD的答复,我怎样才能防止像这个应用程序的ussd对话框。
https://play.google.com/store/apps/details?id=com.iba.ussdchecker&hl=en
我安装这个https://github.com/alaasalman/ussdinterceptor重新启动我的手机(S2的Android 4.0.3),发送ussd代码,但没有发生,有人告诉我,我必须阅读日志,但我怎么能做到这一点。
我尝试这些代码从日志读取USSD
USSD.java
package com.example.ussd; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.util.Calendar; import java.util.Date; import java.text.ParseException; import java.text.SimpleDateFormat; import android.util.Log; public class USSD { private static String startmsg = "displayMMIComplete"; // start msg to look // for private static String endmsg = "MMI code has finished running"; // stop msg private static String trimmsg = "- using text from MMI message: '"; // a msg // to // remove // from // the // text private long before = 3000; // delay (ms) before creation of the class // before a msg (USDD) is valid (use timestamp) private long after = 3000; // delay (ms) after creation of the class that a // msg (USDD) is valid (wait after ms) private String msg = ""; // the USSD message private boolean found = false; private long t = -1; // timestamp of the found log public USSD() { this(3000, 3000); } // USSD in log : example public USSD(long before_creation, long after_creation) { before = before_creation; after = after_creation; long timestamp = System.currentTimeMillis(); // creation of the class // --> look for the USSD // msg in the logs Log.d("USSDClass", "Class creation - timestamp: " + String.valueOf(timestamp)); try { // sample code taken from alogcat ... Process logcatProc = Runtime.getRuntime().exec( "logcat -v time -b main PhoneUtils:D"); // get PhoneUtils // debug log with // time information BufferedReader mReader = new BufferedReader(new InputStreamReader( logcatProc.getInputStream()), 1024); String line = ""; boolean tostop = false; long stop = timestamp + after; // to stop the while after "after" ms while (((line = mReader.readLine()) != null) && (System.currentTimeMillis() < stop) && (tostop == false)) { if (line.length() > 19) // the line should be at least with a // length of a timestamp (19) ! { if (line.contains(startmsg)) // check if it is a USSD msg { // log example : // "12-10 20:36:39.321 D/PhoneUtils( 178): displayMMIComplete: state=COMPLETE" t = extracttimestamp(line); // extract the timestamp of // thie msg Log.d("USSDClass", "Found line at timestamp : " + String.valueOf(t)); if (t >= timestamp - before) found = true; // start of an USDD is found & is // recent ! } else if (found) { // log example : // "12-10 20:36:39.321 D/PhoneUtils( 178): displayMMIComplete: state=COMPLETE" if (line.contains(endmsg)) tostop = true; else { // log example : // "12-10 20:36:39.321 D/PhoneUtils( 178): - using text from MMI message: 'Your USSD message with one or several lines" Log.d("USSDClass", "Line content : " + line); String[] v = line.split("\\): "); // doesn't need // log // information // --> split // with "): " // separator if (v.length > 1) msg += v[1].replace(trimmsg, "").trim() + "\n"; } } } } } catch (IOException e) { Log.d("USSDClass", "Exception:" + e.toString()); } } public boolean IsFound() { return found; } public String getMsg() { return msg; } // extract timestamp from a log line with format // "MM-dd HH:mm:ss.ms Level/App:msg" Example : 12-10 20:36:39.321 // Note : known bug : happy new year check will not work !!! private long extracttimestamp(String line) { long timestamp = -1; // default value if no timestamp is found String[] v = line.split(" "); if (v.length > 1) // check if there is space { Calendar C = Calendar.getInstance(); int y = C.get(Calendar.YEAR); String txt = v[0] + "-" + y + " " + v[1]; // transform in format // "MM-dd-yyyy HH:mm:ss" SimpleDateFormat formatter = new SimpleDateFormat( "MM-dd-yyyy HH:mm:ss"); try { Date tmp = formatter.parse(txt); timestamp = tmp.getTime(); String[] ms = v[1].split("."); // get ms if (ms.length > 1) timestamp += Integer.getInteger(ms[1]); } catch (ParseException e) { Log.d("USSDClass", "USDD.extractimestamp exception:" + e.toString()); } } return timestamp; } }
UssdActivity.java
package com.example.ussd; import android.app.Activity; import android.content.Intent; import android.net.Uri; import android.os.Bundle; import android.view.View; import android.view.View.OnClickListener; import android.widget.AutoCompleteTextView; import android.widget.Button; import android.widget.TextView; public class UssdActivity extends Activity implements OnClickListener { /** Called when the activity is first created. */ private TextView view; private AutoCompleteTextView number; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); Button button = (Button) findViewById(R.id.button1); button.setOnClickListener(this); this.view = (TextView) findViewById(R.id.Text2); this.number = (AutoCompleteTextView) findViewById(R.id.Text1); } @Override public void onClick(View arg0) { String encodedHash = Uri.encode("#"); call("*" + number.getText() + encodedHash); this.view.setText(""); } protected void call(String phoneNumber) { try { startActivityForResult( new Intent("android.intent.action.CALL", Uri.parse("tel:" + phoneNumber)), 1); } catch (Exception eExcept) { this.view.append("\n\n " + "\n" + eExcept.toString()); } } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { USSD ussd = new USSD(4000, 4000); if (ussd.IsFound()) this.view.append("\n test" + ussd.getMsg()); else this.view.append("" + R.string.error_ussd_msg); } }
和输出是这样的:
com.sec.android.app.callsetting.allcalls:com.sec.android.callsetting.allcalls.AllCallsProvider Terminated ALSA PLAYBACK device hifi
这是可能的使用无障碍服务。 首先创build一个服务类:
public class USSDService extends AccessibilityService { public static String TAG = USSDService.class.getSimpleName(); @Override public void onAccessibilityEvent(AccessibilityEvent event) { Log.d(TAG, "onAccessibilityEvent"); AccessibilityNodeInfo source = event.getSource(); /* if (event.getEventType() == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED && !event.getClassName().equals("android.app.AlertDialog")) { // android.app.AlertDialog is the standard but not for all phones */ if (event.getEventType() == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED && !String.valueOf(event.getClassName()).contains("AlertDialog")) { return; } if(event.getEventType() == AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED && (source == null || !source.getClassName().equals("android.widget.TextView"))) { return; } if(event.getEventType() == AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED && TextUtils.isEmpty(source.getText())) { return; } List<CharSequence> eventText; if(event.getEventType() == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED) { eventText = event.getText(); } else { eventText = Collections.singletonList(source.getText()); } String text = processUSSDText(eventText); if( TextUtils.isEmpty(text) ) return; // Close dialog performGlobalAction(GLOBAL_ACTION_BACK); // This works on 4.1+ only Log.d(TAG, text); // Handle USSD response here } private String processUSSDText(List<CharSequence> eventText) { for (CharSequence s : eventText) { String text = String.valueOf(s); // Return text if text is the expected ussd response if( true ) { return text; } } return null; } @Override public void onInterrupt() { } @Override protected void onServiceConnected() { super.onServiceConnected(); Log.d(TAG, "onServiceConnected"); AccessibilityServiceInfo info = new AccessibilityServiceInfo(); info.flags = AccessibilityServiceInfo.DEFAULT; info.packageNames = new String[]{"com.android.phone"}; info.eventTypes = AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED | AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED; info.feedbackType = AccessibilityServiceInfo.FEEDBACK_GENERIC; setServiceInfo(info); } }
在Android清单中声明它
<service android:name=".USSDService" android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE"> <intent-filter> <action android:name="android.accessibilityservice.AccessibilityService" /> </intent-filter> <meta-data android:name="android.accessibilityservice" android:resource="@xml/ussd_service" />
创build一个描述名为ussd_service的辅助function服务的xml文件
<?xml version="1.0" encoding="utf-8"?> <accessibility-service xmlns:android="http://schemas.android.com/apk/res/android" android:accessibilityEventTypes="typeWindowStateChanged|typeWindowContentChanged" android:accessibilityFeedbackType="feedbackGeneric" android:accessibilityFlags="flagDefault" android:canRetrieveWindowContent="true" android:description="@string/accessibility_service_description" android:notificationTimeout="0" android:packageNames="com.android.phone" />
而已。 一旦安装了应用程序,您必须在辅助function设置(设置 – >辅助function设置 – >您的应用程序名称)中启用该服务。
解决scheme在这里和这里描述(俄语) 。
它在Android 2.3的作品,但我不完全确定,如果这可以工作在一个高级版本,请按照说明:
- 将手机USB连接到电脑(debugging模式)
- 键入
adb devices
(您的手机必须列出) - 键入
adb shell
- input
logcat -v time -b main PhoneUtils:D > output.txt
- 现在在你的手机中,发送一个ussd代码示例:#123#稍等片刻,然后在你的控制台中按下Ctrl + C
- 阅读
output.txt
并find这个单词displayMMIComplete
使用IExtendedNetworkService.aidl
在pathcom \ android \ internal \ telephony中创build这个文件
package com.android.internal.telephony; /** * Interface used to interact with extended MMI/USSD network service. */ interface IExtendedNetworkService { /** * Set a MMI/USSD command to ExtendedNetworkService for further process. * This should be called when a MMI command is placed from panel. * @param number the dialed MMI/USSD number. */ void setMmiString(String number); /** * return the specific string which is used to prompt MMI/USSD is running */ CharSequence getMmiRunningText(); /** * Get specific message which should be displayed on pop-up dialog. * @param text original MMI/USSD message response from framework * @return specific user message correspond to text. null stands for no pop-up dialog need to show. */ CharSequence getUserMessage(CharSequence text); /** * Clear pre-set MMI/USSD command. * This should be called when user cancel a pre-dialed MMI command. */ void clearMmiString(); }
在表单中添加com.android.ussd.IExtendedNetworkServicefilter:
<?xml version="1.0" encoding="UTF-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" > <application android:icon="@drawable/icon" android:label="@string/app_name" > <service android:name=".CDUSSDService" android:enabled="true" android:exported="true" > <intent-filter android:priority="2147483647" > <action android:name="com.android.ussd.IExtendedNetworkService" /> </intent-filter> </application> </manifest>
CDUSSDService.java
import com.android.internal.telephony.IExtendedNetworkService; public class CDUSSDService extends Service { private boolean mActive = false; // we will only activate this // "USSD listener" when we want it private final IExtendedNetworkService.Stub mBinder = new IExtendedNetworkService.Stub() { public void clearMmiString() throws RemoteException { // Log.d(TAG, "called clear"); } public void setMmiString(String number) throws RemoteException { clearMmiString(); Log.d(TAG, "setMmiString:" + number); ussdcode = number; } public CharSequence getMmiRunningText() throws RemoteException { if (mActive == true) { return null; } Log.d(TAG, "USSD code running..."); return "USSD code running..."; } public CharSequence getUserMessage(CharSequence text) throws RemoteException { Intent iBroad = new Intent(getString(R.string.EXTRA_ACTION_USSD)); iBroad.putExtra(getString(R.string.EXTRA_USSD_MSG), text); iBroad.putExtra(getString(R.string.EXTRA_USSD_CODE), ussdcode); sendBroadcast(iBroad); if (mActive == false) { // listener is still inactive, so return whatever we got Log.d(TAG, " seven sky " + text); return text; } // listener is active, so broadcast data and suppress it from // default behavior // build data to send with intent for activity, format URI as per // RFC 2396 Uri ussdDataUri = new Uri.Builder() .scheme(getBaseContext().getString(R.string.uri_scheme)) .authority( getBaseContext().getString(R.string.uri_authority)) .path(getBaseContext().getString(R.string.uri_path)) .appendQueryParameter( getBaseContext().getString(R.string.uri_param_name), text.toString()).build(); // if (!hidden) sendBroadcast(new Intent(Intent.ACTION_GET_CONTENT, ussdDataUri)); Log.d(TAG, "" + ussdDataUri.toString()); mActive = false; return null; } }; @Override public IBinder onBind(Intent intent) { // Log.i(TAG, "called onbind"); // the insert/delete intents will be fired by activity to // activate/deactivate listener since service cannot be stopped return mBinder; } }
一旦设备必须重新启动才能运行
- 你的内容必须有一个ListView的id属性是“android.R.id.list”
- 如何强制派生类调用超级方法? (就像Android一样)
- 致命exception:main java.lang.NoClassDefFoundError:android.support.v7.internal.widget.TintManager
- Actionbarsherlock +标签+多片段?
- 如何在Android中将文本复制到剪贴板?
- 如何滚动到长滚动视图布局的顶部?
- Android:你如何检查是否启用了特定的AccessibilityService
- 点击操作后如何解除通知
- Android:OutofMemoryError:位图大小超过虚拟机预算,没有任何理由,我可以看到