相关控件初始化方法:showSmscPref

private void showSmscPref() {

        int count = MSimTelephonyManager.getDefault().getPhoneCount();

        boolean airplaneModeOn = Settings.System.getInt(getContentResolver(),

                Settings.System.AIRPLANE_MODE_ON, 0) != 0;

        for (int i = 0; i < count; i++) {

            final Preference pref = new Preference(this);

            pref.setKey(String.valueOf(i));

            String title = (count <= 1) ?

getString(R.string.pref_one_smcs)

                    : getString(R.string.pref_more_smcs, i + 1);

            pref.setTitle(title);



            pref.setOnPreferenceClickListener(new OnPreferenceClickListener() {

                @Override

                public boolean onPreferenceClick(Preference preference) {

                    MyEditDialogFragment dialog = MyEditDialogFragment.newInstance(

                            MessagingPreferenceActivity.this,

                            preference.getTitle(),

                            preference.getSummary(),

                            Integer.valueOf(preference.getKey()));

                    dialog.show(getFragmentManager(), "dialog");

                    return true;

                }

            });




            mSmscPrefCate.addPreference(pref);

            mSmscPrefList.add(pref);

            updateSMSCPref(i, airplaneModeOn);

        }

        registerReceiver();

}

这里使用了一个内部类MyEditDialogFragment,该类继承了DialogFragment。

public static class MyEditDialogFragment extends DialogFragment {

        private MessagingPreferenceActivity mActivity;



        public static MyEditDialogFragment newInstance(MessagingPreferenceActivity activity,

                CharSequence title, CharSequence smsc, int sub) {

            MyEditDialogFragment dialog = new MyEditDialogFragment();

            dialog.mActivity = activity;



            Bundle args = new Bundle();

            args.putCharSequence(TITLE, title);

            args.putCharSequence(SMSC, smsc);

            args.putInt(SUB, sub);

            dialog.setArguments(args);

            return dialog;

        }



        @Override

        public Dialog onCreateDialog(Bundle savedInstanceState) {

            final int sub = getArguments().getInt(SUB);

            if (null == mActivity) {

                mActivity = (MessagingPreferenceActivity) getActivity();

                dismiss();

            }

            final EditText edit = new EditText(mActivity);

            edit.setPadding(15, 15, 15, 15);

            edit.setText(getArguments().getCharSequence(SMSC));



            Dialog alert = new AlertDialog.Builder(mActivity)

                    .setTitle(getArguments().getCharSequence(TITLE))

                    .setView(edit)

                    .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {

                        public void onClick(DialogInterface dialog, int whichButton) {

                            MyAlertDialogFragment newFragment = MyAlertDialogFragment.newInstance(

                                    mActivity, sub, edit.getText().toString());

                            newFragment.show(getFragmentManager(), "dialog");

                            dismiss();

                        }

                    })

                    .setNegativeButton(android.R.string.cancel, null)

                    .setCancelable(true)

                    .create();


            alert.getWindow().setSoftInputMode(

                    WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE);

            return alert;

        }

    }



上述代码调用了还有一个内部类:《TAG 1-2》

public static class MyAlertDialogFragment extends DialogFragment {

        private MessagingPreferenceActivity mActivity;



        public static MyAlertDialogFragment newInstance(MessagingPreferenceActivity activity,

                                                        int sub, String smsc) {

            MyAlertDialogFragment dialog = new MyAlertDialogFragment();

            dialog.mActivity = activity;



            Bundle args = new Bundle();

            args.putInt(SUB, sub);

            args.putString(SMSC, smsc);

            dialog.setArguments(args);

            return dialog;

        }



        @Override

        public Dialog onCreateDialog(Bundle savedInstanceState) {

            final int sub = getArguments().getInt(SUB);

            final String displayedSMSC = getArguments().getString(SMSC);



            // When framework re-instantiate this fragment by public empty

            // constructor and call onCreateDialog(Bundle savedInstanceState) ,

            // we should make sure mActivity not null.

            if (null == mActivity) {

                mActivity = (MessagingPreferenceActivity) getActivity();

            }



            return new AlertDialog.Builder(mActivity)

                    .setIcon(android.R.drawable.ic_dialog_alert).setMessage(

                            R.string.set_smsc_confirm_message)

                    .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {

                        public void onClick(DialogInterface dialog, int whichButton) {

                            Intent intent = new Intent();

                            intent.setComponent(new ComponentName("com.android.phonefeature",

                                    "com.android.phonefeature.smsc.SmscService"));

                            intent.setAction(COMMAND_SET_SMSC);

                            intent.putExtra(SUB, sub);

                            intent.putExtra(SMSC, displayedSMSC);

                            mActivity.startService(intent);

                        }


                    })

                    .setNegativeButton(android.R.string.cancel, null)

                    .setCancelable(true)

                    .create();

        }

    }

当用户点击确认(OK)后,会启动一个SmscService服务,而且把改动后的smsc number封装到intent中去,在SmscService服务中的onStartCommand将Intent中的数加入到消息队列中进行处理。

    public int onStartCommand(Intent intent, int flags, int startId) {

        int sub = intent.getIntExtra(SUB, 0);

        int count = MSimTelephonyManager.getDefault().getPhoneCount();

        Phone phone = count > 1 ? MSimPhoneFactory.getPhone(sub)

                : PhoneFactory.getDefaultPhone();

        if (phone == null) return START_STICKY;



        boolean enable = phone.getIccCard().hasIccCard();

        Intent i = new Intent();

        i.setAction(NOTIFY_PHONE_STATE);

        i.putExtra(SUB, sub);

        i.putExtra(ENABLE, enable);

        sendBroadcast(i);



        String action = intent.getAction();

        Message msg;



        if (COMMAND_GET_SMSC.equals(action)) {

            msg = mHandler.obtainMessage(MSG_GET_SMSC);

            msg.arg1 = sub;

            phone.getSmscAddress(msg);

        } else if (COMMAND_SET_SMSC.equals(action)) {

            msg = mHandler.obtainMessage(MSG_SET_SMSC);

            msg.arg1 = sub;



            String displayedSMSC = intent.getStringExtra(SMSC);

            Bundle bundle = new Bundle();

            bundle.putString(SMSC, displayedSMSC);

            msg.setData(bundle);



            String actualSMSC = adjustSMSC(displayedSMSC);

            phone.setSmscAddress(actualSMSC, msg);


        }

        return START_STICKY;

    }

上述代码中的phone。通过验证分析,得到phone为GSMPhone的实例,验证的代码为PhoneFactory类中的makeDefaultPhone方法进行验证得到(我这里验证的结果为GSM:

public static void makeDefaultPhone(Context context) {<TAG 1-1>

        synchronized(Phone.class) {

            if (!sMadeDefaults) {

                sLooper = Looper.myLooper();

                sContext = context;



                if (sLooper == null) {

                    throw new RuntimeException(

                        "PhoneFactory.makeDefaultPhone must be called from Looper thread");

                }



                int retryCount = 0;

                for(;;) {

                    boolean hasException = false;

                    retryCount ++;



                    try {

                        // use UNIX domain socket to

                        // prevent subsequent initialization

                        new LocalServerSocket("com.android.internal.telephony");

                    } catch (java.io.IOException ex) {

                        hasException = true;

                    }



                    if ( !hasException ) {

                        break;

                    } else if (retryCount > SOCKET_OPEN_MAX_RETRY) {

                        throw new RuntimeException("PhoneFactory probably already running");

                    } else {

                        try {

                            Thread.sleep(SOCKET_OPEN_RETRY_MILLIS);

                        } catch (InterruptedException er) {

                        }

                    }

                }



                sPhoneNotifier = new DefaultPhoneNotifier();



                // Get preferred network mode

                int preferredNetworkMode = RILConstants.PREFERRED_NETWORK_MODE;

                if (TelephonyManager.getLteOnCdmaModeStatic() == PhoneConstants.LTE_ON_CDMA_TRUE) {

                    preferredNetworkMode = Phone.NT_MODE_GLOBAL;

                }

                int networkMode = Settings.Global.getInt(context.getContentResolver(),

                        Settings.Global.PREFERRED_NETWORK_MODE, preferredNetworkMode);

                Rlog.i(LOG_TAG, "Network Mode set to " + Integer.toString(networkMode));



                // As per certain operator requirement, the device is expected to be in global《TAG 1-2》

                // mode from boot up, by enabling the property persist.env.phone.global the

                // network mode is set to global during boot up.

                if (SystemProperties.getBoolean("persist.env.phone.global", false)) {

                    networkMode = Phone.NT_MODE_LTE_CMDA_EVDO_GSM_WCDMA;

                    Settings.Global.putInt(context.getContentResolver(),

                            Settings.Global.PREFERRED_NETWORK_MODE, networkMode);

                }



                // Get cdmaSubscription mode from Settings.Global

                int cdmaSubscription;

                cdmaSubscription = Settings.Global.getInt(context.getContentResolver(),

                                Settings.Global.CDMA_SUBSCRIPTION_MODE,

                                sPreferredCdmaSubscription);

                Rlog.i(LOG_TAG, "Cdma Subscription set to " + cdmaSubscription);



                //reads the system properties and makes commandsinterface

                sCommandsInterface = new RIL(context, networkMode, cdmaSubscription);



                // Instantiate UiccController so that all other classes can just call getInstance()

                UiccController.make(context, sCommandsInterface);



                int phoneType = TelephonyManager.getPhoneType(networkMode);

                if (phoneType == PhoneConstants.PHONE_TYPE_GSM) {

                    Rlog.i(LOG_TAG, "Creating GSMPhone");

                    sProxyPhone = new PhoneProxy(new GSMPhone(context,

                            sCommandsInterface, sPhoneNotifier));

                            android.util.Log.d("bill","GSM");


                } else if (phoneType == PhoneConstants.PHONE_TYPE_CDMA) {

                    switch (TelephonyManager.getLteOnCdmaModeStatic()) {

                        case PhoneConstants.LTE_ON_CDMA_TRUE:

                            Rlog.i(LOG_TAG, "Creating CDMALTEPhone");

                            sProxyPhone = new PhoneProxy(new CDMALTEPhone(context,

                                sCommandsInterface, sPhoneNotifier));

                                android.util.Log.d("bill","CDMALTE");

                            break;

                        case PhoneConstants.LTE_ON_CDMA_FALSE:

                        default:

                            Rlog.i(LOG_TAG, "Creating CDMAPhone");

                            sProxyPhone = new PhoneProxy(new CDMAPhone(context,

                                    sCommandsInterface, sPhoneNotifier));

                                    android.util.Log.d("bill","CDMA");

                            break;

                    }

                }



                sMadeDefaults = true;

            }

        }

    }

可是GSMPhone中并没有setSmscAddress()方法,可是GSMPhone继承了BasePhone类,因此我们在BasePhone中找到了setSmscAddress()方法。




    @Override

    public void setSmscAddress(String address, Message result) {

        mCi.setSmscAddress(address, result);

    }

上述代码中的mCi为接口CommandsInterface的实例。mCi的所引用的实例为BasePhone构造函数中传递过来的,因此我们代码<TAG1-1>中找到了该实例为RIL的实例。因此我们在RIL类中找到了setSmscAddress方法;

@Override

    public void setSmscAddress(String address, Message result) {

        RILRequest rr = RILRequest.obtain(RIL_REQUEST_SET_SMSC_ADDRESS, result);



        rr.mParcel.writeString(address);



        if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)

                + " : " + address);



        send(rr);


    }

private void

    send(RILRequest rr) {


        Message msg;



        if (mSocket == null) {

            rr.onError(RADIO_NOT_AVAILABLE, null);

            rr.release();

            return;

        }



        msg = mSender.obtainMessage(EVENT_SEND, rr);



        acquireWakeLock();



        msg.sendToTarget();

    }

在上述代码中send()方法会发消息给RIL中RILSender进行处理,同一时候msg中封装了MSG_SET_SMSC,在RIL的RILSender中运行写卡操作,同一时候发消息给SmscService。

//***** Handler implementation

        @Override public void

        handleMessage(Message msg) {

            RILRequest rr = (RILRequest)(msg.obj);

            RILRequest req = null;



            switch (msg.what) {

                case EVENT_SEND:

                    /**

                     * mRequestMessagePending++ already happened for every

                     * EVENT_SEND, thus we must make sure

                     * mRequestMessagePending-- happens once and only once

                     */

                    boolean alreadySubtracted = false;

                    try {

                        LocalSocket s;



                        s = mSocket;



                        if (s == null) {

                            rr.onError(RADIO_NOT_AVAILABLE, null);

                            rr.release();

                            if (mRequestMessagesPending > 0)

                                mRequestMessagesPending--;

                            alreadySubtracted = true;

                            return;

                        }



                        synchronized (mRequestList) {

                            mRequestList.add(rr);

                            mRequestMessagesWaiting++;

                        }



                        if (mRequestMessagesPending > 0)

                            mRequestMessagesPending--;

                        alreadySubtracted = true;



                        byte[] data;



                        data = rr.mParcel.marshall();

                        rr.mParcel.recycle();

                        rr.mParcel = null;



                        if (data.length > RIL_MAX_COMMAND_BYTES) {

                            throw new RuntimeException(

                                    "Parcel larger than max bytes allowed! "

                                                          + data.length);

                        }



                        // parcel length in big endian

                        dataLength[0] = dataLength[1] = 0;

                        dataLength[2] = (byte)((data.length >> 8) & 0xff);

                        dataLength[3] = (byte)((data.length) & 0xff);



                        //Rlog.v(RILJ_LOG_TAG, "writing packet: " + data.length + " bytes");



                        s.getOutputStream().write(dataLength);

                        s.getOutputStream().write(data);

                    } catch (IOException ex) {

                        Rlog.e(RILJ_LOG_TAG, "IOException", ex);

                        req = findAndRemoveRequestFromList(rr.mSerial);

                        // make sure this request has not already been handled,

                        // eg, if RILReceiver cleared the list.

                        if (req != null || !alreadySubtracted) {

                            rr.onError(RADIO_NOT_AVAILABLE, null);

                            rr.release();

                        }

                    } catch (RuntimeException exc) {

                        Rlog.e(RILJ_LOG_TAG, "Uncaught exception ", exc);

                        req = findAndRemoveRequestFromList(rr.mSerial);

                        // make sure this request has not already been handled,

                        // eg, if RILReceiver cleared the list.

                        if (req != null || !alreadySubtracted) {

                            rr.onError(GENERIC_FAILURE, null);

                            rr.release();

                        }

                    } finally {

                        // Note: We are "Done" only if there are no outstanding

                        // requests or replies. Thus this code path will only release

                        // the wake lock on errors.

                        releaseWakeLockIfDone();

                    }



                    if (!alreadySubtracted && mRequestMessagesPending > 0) {

                        mRequestMessagesPending--;

                    }



                    break;

这里进行推断写卡操作是否成功,并发送广播。

private Handler mHandler = new Handler() {

        @Override

        public void handleMessage(Message msg) {

            AsyncResult ar = (AsyncResult) msg.obj;

            String smsc = null;

            switch (msg.what) {

                case MSG_SET_SMSC:

                    if (ar.exception != null) {

                        notifyChange(NOTIFY_SMSC_ERROR, null, 0);

                        return;

                    } else {

                        Bundle bundle = msg.getData();

                        smsc = bundle.getString(SMSC);

                        notifyChange(NOTIFY_SMSC_SUCCESS, null, 0);

                    }


                    break;

  private void notifyChange(String notify, String smsc, int sub) {

        Intent intent = new Intent(notify);

        intent.putExtra(SMSC, smsc);

        intent.putExtra(SUB, sub);

        sendBroadcast(intent);

    }

我们在MessagingPreferenceActivity的registerReceiver()方法中注冊广播接收器进行监听。

private void registerReceiver() {

        if (mReceiver != null) return;

        mReceiver = new BroadcastReceiver() {

            @Override

            public void onReceive(Context context, Intent intent) {

                String action = intent.getAction();

                if (Intent.ACTION_AIRPLANE_MODE_CHANGED.equals(action)) {

                    /*AddBy:yabin.huang BugID:SWBUG00029352 Date:20140521*/

                    updateSMSCPref(ALL_SUB, isAirplaneModeOn());

                    Message msg = new Message();

                    msg.what = AIR_PLANE_MODE_CHANGED;

                    msg.arg1 = (isAirplaneModeOn() ?

AIR_PLANE_MODE_ENABLE : AIR_PLANE_MODE_DISABLE);

                    mAirPlaneModeHandler.sendMessage(msg);

                } else if(TelephonyIntents.ACTION_SIM_STATE_CHANGED.equals(action)){

                    if(isSimReady())

                    updateSMSCPref(ALL_SUB, isAirplaneModeOn());

                } else if (NOTIFY_SMSC_ERROR.equals(action)) {

                    showToast(R.string.set_smsc_error);

                } else if (NOTIFY_SMSC_SUCCESS.equals(action)) {

                    showToast(R.string.set_smsc_success);

                    int sub = intent.getIntExtra(SUB, 0);

                    String summary = intent.getStringExtra(SMSC);

                    Log.d("bill","summary--"+summary);

                    mSmscPrefList.get(sub).setSummary(summary);


                } else if (NOTIFY_SMSC_UPDATE.equals(action)) {

                    int sub = intent.getIntExtra(SUB, 0);

                    if(TextUtils.isEmpty(mSmscPrefList.get(sub).getSummary())){

                        String summary = intent.getStringExtra(SMSC);

                        if(summary==null||summary.length()==0){

                            updateSMSCPref(ALL_SUB, isAirplaneModeOn());

                            mSmscPrefList.get(sub).setEnabled(false);

                            mSmscPrefList.get(sub).setSummary(null);

                        }else{

                            mSmscPrefList.get(sub).setEnabled(true);

                            mSmscPrefList.get(sub).setSummary(summary);

                        }

                    }else{

                        mSmscPrefList.get(sub).setEnabled(true);

                    }

                }

            }

        };



        IntentFilter filter = new IntentFilter();

        filter.addAction(TelephonyIntents.ACTION_SIM_STATE_CHANGED);

        filter.addAction(Intent.ACTION_AIRPLANE_MODE_CHANGED);

        filter.addAction(NOTIFY_SMSC_ERROR);

        filter.addAction(NOTIFY_SMSC_SUCCESS);

        filter.addAction(NOTIFY_SMSC_UPDATE);

        registerReceiver(mReceiver, filter);

    }

至今。改变整个过程的短信中心号码被整理完毕。

版权声明:本文博客原创文章,博客,未经同意,不得转载。

深度解析:Android在Mms设置页面更改短信中心号码流程的更多相关文章

  1. 深度分析:Android中Mms设置页面更改短信中心号码流程

    相关控件初始化方法:showSmscPref private void showSmscPref() {         int count = MSimTelephonyManager.getDef ...

  2. 【转载】深度解析Android中字体设置

    原文:http://mobile.51cto.com/android-265238.htm 1.在Android XML文件中设置字体 可以采用Android:typeface,例如android:t ...

  3. Android系统自带APP分析——短信app

    Android操作系统本身就是一个巨大的开源软件仓库,熟悉它既可以了解到Android系统的设计框架,也可以获得高效的应用程序编写方式.本文所分析的源码来自于Google官方的AOSP源码4.0.1_ ...

  4. android安全问题(八)伪造短信(利用原生android4.0漏洞)

    导读:本文利用android4.0的一个原生漏洞来伪造短信.无须声明任何权限即可伪造发送方为任何号码的短信给用户. android4.0发布已经是很久很久很久很久以前的事情了,这个漏洞早就报了出来,之 ...

  5. Android设为系统默认的短信应用

    要设为系统默认的短信应用首先要配置一下AndroidManifest.xml文件,添加下列: <!-- BroadcastReceiver that listens for incoming S ...

  6. android接收短信——framework处理流程(android 5.1)

    modem层不懂,所以直接从RIL.java开始.以电信卡接收短信为例 modem通知RIL.java中的 RILReceiver处理接收信息 class RILReceiver implements ...

  7. Android黑科技,读取用户短信+修改系统短信数据库

    安卓系统比起ios系统最大的缺点,相信大家都知道,就是系统安全问题.这篇博客就秀一波“黑科技”. 读取用户短信 Android应用能读取用户手机上的短信,相信已经不是什么新鲜事,比如我们收到的短信验证 ...

  8. 脚本控制向Android模拟拨打电话,发送短信,定位设置功能

    做行为触发的时候要向模拟器实现拨打电话,发送短信,定位设置的的功能,可以很方便通过telnet localhost  5554实现. 写个脚本很快的搞定了.网上资料很多,脚本的很少,也所积点德啦. 写 ...

  9. Android面试收集录 电话、短信和联系人、多媒体技术

    1.请写出调用系统拨号界面? Intent intent=new Intent(Intent.ACTION_DIAL,Uri.pase("tel:12345678910")); s ...

随机推荐

  1. 广域网佰腾玩O2O笑话——它看起来很漂亮,注定不低于

    据说 2014.8.29:中国最大的商业运营商万达在一起的互联网服务供应商百度.腾讯在深圳(属性)战略合作签约仪式举行. 从功能表面上.万达代表实体,百度代表数据.腾讯代表社区:按三个合伙人理解,是要 ...

  2. Oracle数据库的锁类型

    Oracle数据库的锁类型 博客分类: oracle   Oracle数据库的锁类型 根据保护的对象不同,Oracle数据库锁可以分为以下几大类:DML锁(data   locks,数据锁),用于保护 ...

  3. jenkins配置.net mvc网站

    jenkins配置.net mvc网站 上一篇使用jenkins配置.net mvc网站进行持续集成一只是简单介绍了jenkins构建站点到本地服务器,这一篇,就来讲解如何部署站点到指定的服务器上面. ...

  4. 解决alaert.builder二次调用报错的bug

    报错的代码是: The specified child already has a parent. You must call removeView() on the child's parent f ...

  5. cocos2d-x3.0数据结构

    1.cocos2d::Vector 1.头报价"CCVector.h"头文件. 2.保存的数据类型必须是cocos2d::Ref的子类. 3.实现是动态加入数据集合即链表.主要的使 ...

  6. android手机SD卡中的android_secure目录

    .android_secure 是官方app2sd的产物,删了之后装到sd卡中的软件就无法使用了.里面有非常多.asec的文件,都是装到SD卡上的软件,可是一般装到sd卡中的程序被卸载了.androi ...

  7. 制作简易计算器处理过程Servlet

    CalculationServlet.java: package com.you.servlet; import java.io.IOException; import java.io.PrintWr ...

  8. 白板编程浅谈——Why, What, How(转)

    原文链接:http://lucida.me/blog/whiteboard-coding-demystified/ 这篇文章节选自我正在撰写的一本关于应届生面试求职的书籍,欢迎在评论或微博(@peng ...

  9. NAT( 网络地址转换) 实现

    NAT基本介绍: 网络地址转换(NAT,Network Address Translation)属接入广域网(WAN)技术.是一种将私有(保留)地址转化为合法IP地址的转换技术,它被广泛应用于各种类型 ...

  10. 在C#主线程和子线程将数据传递给对方如何实现

    在C#中主线程和子线程怎样实现互相传递数据 老帅 在C#中创建线程Thread时,能够有多种方法,而主线程和子线程之间又怎样实现互相传递数据,每种创建方法传递參数的效果是不同的,逐一看一下:  一.不 ...