Android 阻止USSD对话框并读取USSD响应?

Android 阻止USSD对话框并读取USSD响应?,android,ussd,Android,Ussd,我做了很多关于ussd的研究,但我无法阅读ussd respone以及如何防止像此应用程序这样的ussd对话框 我安装了这个重新启动我的手机(S2 android 4.0.3),发送ussd代码,但什么也没发生,有人告诉我我必须阅读日志,但我如何才能做到这一点 我尝试使用这些代码从日志中读取USSD USSD.java package com.example.ussd; import java.io.BufferedReader; import java.io.IOE

我做了很多关于ussd的研究,但我无法阅读ussd respone以及如何防止像此应用程序这样的ussd对话框

我安装了这个重新启动我的手机(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;

        }

    }
输出是这样的:

com.sec.android.app.callsetting.allcalls:com.sec.android.callsetting.allcalls.AllCallsProvider Terminated ALSA PLAYBACK device hifi

它可以在Android 2.3中使用,但我不完全确定它是否可以在高级版本中使用,请按照说明操作:

  • 将手机USB连接到计算机(调试模式)
  • 键入adb设备(您的手机必须在列表中)
  • 类型
    adb外壳
  • 键入
    logcat-v time-b main PhoneUtils:D>output.txt
  • 现在在手机中发送ussd代码示例:#123#稍等片刻,然后在控制台中按Ctrl+C
  • 阅读
    output.txt
    并找到这个单词
    displaymiplete

  • 可以使用辅助功能服务。 首先创建一个服务类:

    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);
        }
    }
    
    公共类USSDService扩展了AccessibilityService{
    公共静态字符串标记=USSDService.class.getSimpleName();
    @凌驾
    AccessibilityEvent上的公共无效(AccessibilityEvent事件){
    Log.d(标记“onAccessibilityEvent”);
    AccessibilityNodeInfo source=event.getSource();
    /*如果(event.getEventType()==AccessibilityEvent.TYPE\u WINDOW\u STATE\u CHANGED&!event.getClassName().equals(“android.app.AlertDialog”){//android.app.AlertDialog是标准配置,但并非适用于所有手机*/
    如果(event.getEventType()==AccessibilityEvent.TYPE\u WINDOW\u STATE\u已更改&&!String.valueOf(event.getClassName()).contains(“AlertDialog”)){
    返回;
    }
    如果(event.getEventType()==AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED&&(source==null | | |!source.getClassName().equals(“android.widget.TextView”)){
    返回;
    }
    if(event.getEventType()==AccessibilityEvent.TYPE\u WINDOW\u CONTENT\u CHANGED&&TextUtils.isEmpty(source.getText()){
    返回;
    }
    列出事件文本;
    if(event.getEventType()==AccessibilityEvent.TYPE\u窗口\u状态\u已更改){
    eventText=event.getText();
    }否则{
    eventText=Collections.singletonList(source.getText());
    }
    String text=processUSSDText(eventText);
    if(TextUtils.isEmpty(text))返回;
    //关闭对话框
    performGlobalAction(GLOBAL_ACTION_BACK);//这仅适用于4.1+版本
    Log.d(标签、文本);
    //在这里处理USSD响应
    }
    私有字符串processUSSDText(列表事件文本){
    for(字符序列:eventText){
    String text=String.valueOf(s);
    //如果文本是预期的ussd响应,则返回文本
    如果(真){
    返回文本;
    }
    }
    返回null;
    }
    @凌驾
    在中断时的公共无效(){
    }
    @凌驾
    ServiceConnected()上受保护的void{
    super.onServiceConnected();
    Log.d(标记“onServiceConnected”);
    AccessibilityServiceInfo=新的AccessibilityServiceInfo();
    info.flags=AccessibilityServiceInfo.DEFAULT;
    info.packageNames=新字符串[]{“com.android.phone”};
    info.eventTypes=AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED | AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED;
    info.feedbackType=可访问性服务info.FEEDBACK\u通用;
    设置服务信息(信息);
    }
    }
    
    在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" />
     </service>
    
    
    
    和。

    使用IExtendedNetworkService.aidl

    在路径com\android\internal\telephony中创建此文件

    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();
    }
    
    在manifast中添加com.android.ussd.IExtendedNetworkService筛选器:

    <?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>
    

    一旦设备必须重新启动才能运行

    你有解决方案吗?还没有,你对这个问题有什么想法吗?没有,我只是在尝试解决,但没有任何进展。每当你找到解决方案时,请在这个主题中回复:)你确定我会做杰克。这在棒棒糖上非常有效,但在4.2.2和4.0.3上没有成功。我想这个问题已经解决了副具体说明。上述代码适用于三星Duos(4.0.4)、一加一(5.1.1)、Xiomi mi(4.4),但不适用于Micromax A177(4.2.2)、Micromax A905(4.0.4)、联想(4.2.2)。如果您可以检查相同的问题并寻找解决方案,请检查。。是的,在某些设备上,它不起作用。在某些设备上,它是com.android.phone.UssdAlertActivity,而不是android.app.alertdialogy。请检查我的新答案。我是从我的角度让它起作用的。请检查!@hashemkaled,请查看此处的示例:在所有设备/android版本上,或者是否存在任何limitation?@Alex这只能在4.2.2之前的Android版本中实现。在4.2.2中,由于安全风险,IExtendedNetworkService似乎已被谷歌删除。请参阅谷歌发布的问题-
    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();
    }
    
    <?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>
    
    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;
        }
    }