zoukankan      html  css  js  c++  java
  • 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 + "
     response is " + returnMessage + "
     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>
  • 相关阅读:
    appium之adb常用命令
    测试基础之等价类
    selenium之CSS定位
    括号序列的最小代价
    Spark相对于MapReduce的优势
    Cache系统设计
    [京东2017实习生笔试] 终结者C
    [京东2017实习生笔试] 通过考试
    [hihoCoder] 1078. 线段树的区间修改
    [转载] 一步一步理解线段树
  • 原文地址:https://www.cnblogs.com/dbxiaobai/p/10586849.html
Copyright © 2011-2022 走看看