30

有几个关于通过 Android SDK 访问双 SIM 卡功能的问题,所有这些问题都通过简短的声明来回答,即 Android 不支持此类功能。

尽管如此,双 SIM 卡手机确实存在,像MultiSim这样的应用程序似乎能够以某种独立于制造商的方式检测到这一点。

所以,从这个确认开始,让我试着问一些更尖锐的问题:

  • “Android SDK 不支持多个 SIM 功能”是否意味着这些功能不存在,或者尝试使用它们只是一个坏主意?
  • 是否有提供 SIM 卡信息的 Android 内容提供商或内部包(com.android...)?(据我在文档和代码中看到的 TelephonyManager 没有提到多个 SIM 卡)
  • 是否有任何制造商向开发人员公开多个 SIM 功能的报告?
  • 如果我要从制造商那里寻找未记录的功能,我会怎么做?

(顺便说一句,这一切的目的仅仅是实现这个算法:用 SIM 卡 1 发送短信;如果发送失败,则切换到 SIM 卡 2 并以这种方式重新发送消息。)

4

6 回答 6

11

您可以使用MultiSim库从多 sim 设备获取详细信息。

每张 SIM 卡的可用信息:IMEI、IMSI、SIM 序列号、SIM 状态、SIM 运营商代码、SIM 运营商名称、SIM 国家/地区 iso、网络运营商代码、网络运营商名称、网络运营商 iso、网络类型、漫游状态。

只需在您的应用级 Gradle 脚本中添加以下行:

dependencies {
    compile 'com.kirianov.multisim:multisim:2.0@aar'
}

不要忘记在 AndroidManifest.xml 中添加所需的权限:

<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.READ_PHONE_STATE"/>

在您的代码中使用类似的代码:

MultiSimTelephonyManager multiSimTelephonyManager = new MultiSimTelephonyManager(this);
// or
MultiSimTelephonyManager multiSimTelephonyManager = new MultiSimTelephonyManager(this, new BroadcastReceiver() {
  @Override
  public void onReceive(Context context, Intent intent) {
    updateInfo();
  }
});


public void updateInfo() {

  // for update UI
  runOnUiThread(new Runnable() {
    @Override
    public void run() {
      multiSimTelephonyManager.update();
      useInfo();
    }
  }

  // for update background information
  multiSimTelephonyManager.update();
  useInfo();
}

public void useInfo() {

  // get number of slots:
  if (multiSimTelephonyManager != null) {
     multiSimTelephonyManager.sizeSlots();
  }

  // get info from each slot:
  if (multiSimTelephonyManager != null) {
    for(int i = 0; i < multiSimTelephonyManager.sizeSlots(); i++) {
      multiSimTelephonyManager.getSlot(i).getImei();
      multiSimTelephonyManager.getSlot(i).getImsi();
      multiSimTelephonyManager.getSlot(i).getSimSerialNumber();
      multiSimTelephonyManager.getSlot(i).getSimState();
      multiSimTelephonyManager.getSlot(i).getSimOperator();
      multiSimTelephonyManager.getSlot(i).getSimOperatorName();
      multiSimTelephonyManager.getSlot(i).getSimCountryIso();
      multiSimTelephonyManager.getSlot(i).getNetworkOperator();
      multiSimTelephonyManager.getSlot(i).getNetworkOperatorName();
      multiSimTelephonyManager.getSlot(i).getNetworkCountryIso();
      multiSimTelephonyManager.getSlot(i).getNetworkType();
      multiSimTelephonyManager.getSlot(i).isNetworkRoaming();
    }
  }
}

// or for devices above android 6.0
MultiSimTelephonyManager multiSimTelephonyManager = new MultiSimTelephonyManager(MyActivity.this, broadcastReceiverChange);

用法:

// get info about slot 'i' by methods:
multiSimTelephonyManager.getSlot(i).

强制更新信息:

// force update phone info (needed on devices above android 6.0 after confirm permissions request)
multiSimTelephonyManager.update();

权限请求的句柄(6.0+):

// in YourActivity for update info after confirm permissions request on  devices above android 6.0
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    if (multiSimTelephonyManager != null) {
        multiSimTelephonyManager.update();
    }
}
于 2017-01-09T09:09:05.697 回答
8

有3个不同的类别...

  1. 支持和记录的功能
  2. 可用且未记录的功能
  3. 功能不可用

因此双 sim 卡功能可用但未记录在案,因此未得到官方支持。

话虽如此,这并不意味着它不能使用,它只是意味着 android(或就此而言 google 甚至制造商)不负责支持您的应用程序功能。

但它可能只是工作,例如联系人是一个类似的东西。

然后,您可能会问,如果没有记录,每个人都如何知道这些功能。嘿,android 是开源的 ..查看代码并自己找到它。这就是我猜多 sim 开发人员所做的。

于 2012-07-03T06:22:23.280 回答
5

在 API 22 之前,Android 不支持多 SIM 卡功能。但从 Android 5.1(API 级别 22)开始,Android 开始支持多 SIM 卡。有关Android 文档的更多详细信息

来自这个原始答案的参考

于 2015-12-08T08:08:00.493 回答
1

您可以使用SubscriptionInfo类来实现它,

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP_MR1) {
        val mSubscriptionManager = getSystemService(Context.TELEPHONY_SUBSCRIPTION_SERVICE) as SubscriptionManager
        // val mSubscriptionManager = SubscriptionManager.from(baseContext)
        if (ActivityCompat.checkSelfPermission(this, Manifest.permission.READ_PHONE_STATE) == PackageManager.PERMISSION_GRANTED) {
            val subscriptions = mSubscriptionManager.activeSubscriptionInfoList
        //loop through number of SIMS inserted
            for (subscriptionInfo in subscriptions) {
                //the number of this subscription if the calling app has been granted the READ_PHONE_NUMBERS permission, or an empty string otherwise
                Log.v("SIM", subscriptionInfo.number)
                //the ISO country code
                Log.v("SIM", subscriptionInfo.countryIso)
                //the name displayed to the user that identifies Subscription provider name
                Log.v("SIM", subscriptionInfo.carrierName.toString())
                //the name displayed to the user that identifies this subscription
                Log.v("SIM", subscriptionInfo.displayName.toString())
                //The MCC, as a string. This value may be null.
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
                    Log.v("SIM", subscriptionInfo.mccString.toString())
                } else {
                    Log.v("SIM", subscriptionInfo.mcc.toString())
                }
                //The MNC, as a string. This value may be null.
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
                    Log.v("SIM", subscriptionInfo.mncString.toString())
                } else {
                    Log.v("SIM", subscriptionInfo.mnc.toString())
                }
            }
        }
    }
于 2020-07-15T08:46:00.387 回答
0

MultiSim 库源现在在 VCS 上不可用
它的源仍然在这里可用https://mvnrepository.com/artifact/com.kirianov.multisim/multisim
我已经在 Kotlin 上重写了它以供个人使用

class Slot {

    var imei: String? = null

    var imsi: String? = null

    var simState = -1

    val simStates = hashSetOf<Int>()

    var simSerialNumber: String? = null

    var simOperator: String? = null

    var simCountryIso: String? = null

    fun setSimState(state: Int?) {
        if (state == null) {
            simState = -1
            return
        }
        simState = state
    }

    private fun compare(slot: Slot?): Boolean {
        return if (slot != null) {
            imei == slot.imei && imsi == slot.imsi && simSerialNumber == slot.simSerialNumber
        } else false
    }

    fun indexIn(slots: List<Slot>?): Int {
        if (slots == null) {
            return -1
        }
        for (i in slots.indices) {
            if (compare(slots[i])) {
                return i
            }
        }
        return -1
    }

    fun containsIn(slots: List<Slot>?): Boolean {
        if (slots == null) {
            return false
        }
        for (slot in slots) {
            if (compare(slot)) {
                return true
            }
        }
        return false
    }

    override fun toString(): String {
        return "Slot(" +
            "imei=$imei, " +
            "imsi=$imsi, " +
            "simState=$simState, " +
            "simStates=$simStates, " +
            "simSerialNumber=$simSerialNumber, " +
            "simOperator=$simOperator, " +
            "simCountryIso=$simCountryIso" +
            ")"
    }
}

我还删除了本机库依赖项

import android.Manifest
import android.annotation.SuppressLint
import android.annotation.TargetApi
import android.content.Context
import android.os.Build
import android.telephony.SubscriptionManager
import android.text.TextUtils
import domain.shadowss.extension.areGranted
import domain.shadowss.extension.isLollipopMR1Plus
import domain.shadowss.extension.isMarshmallowPlus
import domain.shadowss.extension.isOreoPlus
import domain.shadowss.model.Slot
import org.jetbrains.anko.telephonyManager
import timber.log.Timber
import java.lang.ref.WeakReference
import java.lang.reflect.Modifier
import java.util.*

/**
 * https://mvnrepository.com/artifact/com.kirianov.multisim/multisim
 */
@Suppress("MemberVisibilityCanBePrivate")
class MultiSimManager(context: Context) {

    private val reference = WeakReference(context)

    val slots = arrayListOf<Slot>()
        @Synchronized get

    @Suppress("unused")
    val dualMcc: Pair<String?, String?>
        @SuppressLint("MissingPermission")
        @TargetApi(Build.VERSION_CODES.LOLLIPOP_MR1)
        get() = reference.get()?.run {
            if (isLollipopMR1Plus()) {
                if (areGranted(Manifest.permission.READ_PHONE_STATE)) {
                    val subscriptionManager =
                        getSystemService(Context.TELEPHONY_SUBSCRIPTION_SERVICE) as SubscriptionManager
                    val list = subscriptionManager.activeSubscriptionInfoList
                    return list.getOrNull(0)?.mcc?.toString()
                        ?.padStart(3, '0') to list.getOrNull(1)?.mcc?.toString()
                        ?.padStart(3, '0')
                }
            }
            null to null
        } ?: null to null

    @Synchronized
    @SuppressLint("MissingPermission")
    fun updateData(): String? = reference.get()?.run {
        if (areGranted(Manifest.permission.READ_PHONE_STATE)) {
            val error = try {
                var slotNumber = 0
                while (true) {
                    val slot = touchSlot(slotNumber)
                    if (slot == null) {
                        for (i in slotNumber until slots.size) {
                            slots.removeAt(i)
                        }
                        break
                    }
                    if (slot.containsIn(slots) && slot.indexIn(slots) < slotNumber) {
                        // protect from Alcatel infinity bug
                        break
                    }
                    slots.apply {
                        when {
                            size > slotNumber -> {
                                removeAt(slotNumber)
                                add(slotNumber, slot)
                            }
                            size == slotNumber -> add(slot)
                        }
                    }
                    slotNumber++
                }
                null
            } catch (e: Throwable) {
                Timber.e(e)
                e.toString()
            }
            // below is my custom logic only which was found on practice
            slots.removeAll { it.imsi == null || it.simOperator?.trim()?.isEmpty() != false }
            val imsi = arrayListOf<String?>()
            slots.forEachReversedWithIndex { i, slot ->
                if (imsi.contains(slot.imsi)) {
                    slots.removeAt(i)
                } else {
                    imsi.add(slot.imsi)
                    slot.simStates.apply {
                        clear()
                        addAll(slots.filter { it.imsi == slot.imsi }.map { it.simState })
                    }
                }
            }
            error
        } else {
            slots.clear()
            null
        }
    }

    @Suppress("SpellCheckingInspection", "DEPRECATION")
    @SuppressLint("MissingPermission", "HardwareIds")
    private fun touchSlot(slotNumber: Int): Slot? = reference.get()?.run {
        val slot = Slot()
        val telephonyManager = telephonyManager
        Timber.v("telephonyManager [$telephonyManager] ${telephonyManager.deviceId}")
        val subscriberIdIntValue = ArrayList<String>()
        val subscriberIdIntIndex = ArrayList<Int>()
        for (i in 0..99) {
            val subscriber = runMethodReflect(
                telephonyManager,
                "android.telephony.TelephonyManager",
                "getSubscriberId",
                arrayOf(i),
                null
            ) as? String
            if (subscriber != null && !subscriberIdIntValue.contains(subscriber)) {
                subscriberIdIntValue.add(subscriber)
                subscriberIdIntIndex.add(i)
            }
        }
        var subIdInt =
            if (subscriberIdIntIndex.size > slotNumber) subscriberIdIntIndex[slotNumber] else null
        if (subIdInt == null) {
            try {
                subIdInt = runMethodReflect(
                    telephonyManager,
                    "android.telephony.TelephonyManager",
                    "getSubId",
                    arrayOf(slotNumber),
                    null
                ).toString().toInt()
            } catch (ignored: Throwable) {
            }
        }
        Timber.v("subIdInt $subIdInt")
        val subscriberIdLongValue = ArrayList<String>()
        val subscriberIdLongIndex = ArrayList<Long>()
        for (i in 0L until 100L) {
            val subscriber = runMethodReflect(
                telephonyManager,
                "android.telephony.TelephonyManager",
                "getSubscriberId",
                arrayOf(i),
                null
            ) as? String
            runMethodReflect(
                telephonyManager,
                "android.telephony.TelephonyManagerSprd",
                "getSubInfoForSubscriber",
                arrayOf(i),
                null
            ) ?: continue
            if (subscriber != null && !subscriberIdLongValue.contains(subscriber)) {
                subscriberIdLongValue.add(subscriber)
                subscriberIdLongIndex.add(i)
            }
        }
        if (subscriberIdLongIndex.size <= 0) {
            for (i in 0L until 100L) {
                val subscriber = runMethodReflect(
                    telephonyManager,
                    "android.telephony.TelephonyManager",
                    "getSubscriberId",
                    arrayOf(i),
                    null
                ) as? String
                if (subscriber != null && !subscriberIdLongValue.contains(subscriber)) {
                    subscriberIdLongValue.add(subscriber)
                    subscriberIdLongIndex.add(i)
                }
            }
        }
        var subIdLong =
            if (subscriberIdLongIndex.size > slotNumber) subscriberIdLongIndex[slotNumber] else null
        if (subIdLong == null) {
            subIdLong = runMethodReflect(
                telephonyManager,
                "android.telephony.TelephonyManager",
                "getSubId",
                arrayOf(slotNumber),
                null
            ) as? Long
        }
        Timber.v("subIdLong $subIdLong")
        val listParamsSubs = ArrayList<Any?>()
        if (subIdInt != null && !listParamsSubs.contains(subIdInt)) {
            listParamsSubs.add(subIdInt)
        }
        if (subIdLong != null && !listParamsSubs.contains(subIdLong)) {
            listParamsSubs.add(subIdLong)
        }
        if (!listParamsSubs.contains(slotNumber)) {
            listParamsSubs.add(slotNumber)
        }
        val objectParamsSubs = listParamsSubs.toTypedArray()
        for (i in objectParamsSubs.indices) {
            Timber.v("SPAM PARAMS_SUBS [$i]=[${objectParamsSubs[i]}]")
        }
        val listParamsSlot = ArrayList<Any?>()
        if (!listParamsSlot.contains(slotNumber)) {
            listParamsSlot.add(slotNumber)
        }
        if (subIdInt != null && !listParamsSlot.contains(subIdInt)) {
            listParamsSlot.add(subIdInt)
        }
        if (subIdLong != null && !listParamsSlot.contains(subIdLong)) {
            listParamsSlot.add(subIdLong)
        }
        val objectParamsSlot = listParamsSlot.toTypedArray()
        for (i in objectParamsSlot.indices) {
            Timber.v("SPAM PARAMS_SLOT [$i]=[${objectParamsSlot[i]}]")
        }
        // firstly all Int params, then all Long params
        Timber.v("------------------------------------------")
        Timber.v("SLOT [$slotNumber]")
        if (isMarshmallowPlus()) {
            slot.imei = telephonyManager.getDeviceId(slotNumber)
        }
        if (slot.imei == null) {
            slot.imei = iterateMethods("getDeviceId", objectParamsSlot) as? String
        }
        if (slot.imei == null) {
            slot.imei = runMethodReflect(
                null,
                "com.android.internal.telephony.Phone",
                null,
                null,
                "GEMINI_SIM_" + (slotNumber + 1)
            ) as? String
        }
        if (slot.imei == null) {
            slot.imei = runMethodReflect(
                getSystemService("phone" + (slotNumber + 1)),
                null,
                "getDeviceId",
                null,
                null
            ) as? String
        }
        Timber.v("IMEI [${slot.imei}]")
        if (slot.imei == null) {
            when (slotNumber) {
                0 -> {
                    slot.imei = if (isOreoPlus()) {
                        telephonyManager.imei
                    } else {
                        telephonyManager.deviceId
                    }
                    slot.imsi = telephonyManager.subscriberId
                    slot.simState = telephonyManager.simState
                    slot.simOperator = telephonyManager.simOperator
                    slot.simSerialNumber = telephonyManager.simSerialNumber
                    slot.simCountryIso = telephonyManager.simCountryIso
                    return slot
                }
            }
        }
        if (slot.imei == null) {
            return null
        }
        slot.setSimState(iterateMethods("getSimState", objectParamsSlot) as? Int)
        Timber.v("SIMSTATE [${slot.simState}]")
        slot.imsi = iterateMethods("getSubscriberId", objectParamsSubs) as? String
        Timber.v("IMSI [${slot.imsi}]")
        slot.simSerialNumber = iterateMethods("getSimSerialNumber", objectParamsSubs) as? String
        Timber.v("SIMSERIALNUMBER [${slot.simSerialNumber}]")
        slot.simOperator = iterateMethods("getSimOperator", objectParamsSubs) as? String
        Timber.v("SIMOPERATOR [${slot.simOperator}]")
        slot.simCountryIso = iterateMethods("getSimCountryIso", objectParamsSubs) as? String
        Timber.v("SIMCOUNTRYISO [${slot.simCountryIso}]")
        Timber.v("------------------------------------------")
        return slot
    }

    @SuppressLint("WrongConstant")
    private fun iterateMethods(methodName: String?, methodParams: Array<Any?>): Any? =
        reference.get()?.run {
            if (methodName == null || methodName.isEmpty()) {
                return null
            }
            val telephonyManager = telephonyManager
            val instanceMethods = ArrayList<Any?>()
            val multiSimTelephonyManagerExists = telephonyManager.toString()
                .startsWith("android.telephony.MultiSimTelephonyManager")
            for (methodParam in methodParams) {
                if (methodParam == null) {
                    continue
                }
                val objectMulti = if (multiSimTelephonyManagerExists) {
                    runMethodReflect(
                        null,
                        "android.telephony.MultiSimTelephonyManager",
                        "getDefault",
                        arrayOf(methodParam),
                        null
                    )
                } else {
                    telephonyManager
                }
                if (!instanceMethods.contains(objectMulti)) {
                    instanceMethods.add(objectMulti)
                }
            }
            if (!instanceMethods.contains(telephonyManager)) {
                instanceMethods.add(telephonyManager)
            }
            val telephonyManagerEx = runMethodReflect(
                null,
                "com.mediatek.telephony.TelephonyManagerEx",
                "getDefault",
                null,
                null
            )
            if (!instanceMethods.contains(telephonyManagerEx)) {
                instanceMethods.add(telephonyManagerEx)
            }
            val phoneMsim = getSystemService("phone_msim")
            if (!instanceMethods.contains(phoneMsim)) {
                instanceMethods.add(phoneMsim)
            }
            if (!instanceMethods.contains(null)) {
                instanceMethods.add(null)
            }
            var result: Any?
            for (methodSuffix in suffixes) {
                for (className in classNames) {
                    for (instanceMethod in instanceMethods) {
                        for (methodParam in methodParams) {
                            if (methodParam == null) {
                                continue
                            }
                            result = runMethodReflect(
                                instanceMethod,
                                className,
                                methodName + methodSuffix,
                                if (multiSimTelephonyManagerExists) null else arrayOf(methodParam),
                                null
                            )
                            if (result != null) {
                                return result
                            }
                        }
                    }
                }
            }
            return null
        }

    private fun runMethodReflect(
        instanceInvoke: Any?,
        classInvokeName: String?,
        methodName: String?,
        methodParams: Array<Any>?,
        field: String?
    ): Any? {
        var result: Any? = null
        try {
            val classInvoke = when {
                classInvokeName != null -> Class.forName(classInvokeName)
                instanceInvoke != null -> instanceInvoke.javaClass
                else -> return null
            }
            if (field != null) {
                val fieldReflect = classInvoke.getField(field)
                val accessible = fieldReflect.isAccessible
                fieldReflect.isAccessible = true
                result = fieldReflect.get(null).toString()
                fieldReflect.isAccessible = accessible
            } else {
                var classesParams: Array<Class<*>?>? = null
                if (methodParams != null) {
                    classesParams = arrayOfNulls(methodParams.size)
                    for (i in methodParams.indices) {
                        classesParams[i] = when {
                            methodParams[i] is Int -> Int::class.javaPrimitiveType
                            methodParams[i] is Long -> Long::class.javaPrimitiveType
                            methodParams[i] is Boolean -> Boolean::class.javaPrimitiveType
                            else -> methodParams[i].javaClass
                        }
                    }
                }
                val method = if (classesParams != null) {
                    classInvoke.getDeclaredMethod(methodName.toString(), *classesParams)
                } else {
                    classInvoke.getDeclaredMethod(methodName.toString())
                }
                val accessible = method.isAccessible
                method.isAccessible = true
                result = if (methodParams != null) {
                    method.invoke(instanceInvoke ?: classInvoke, *methodParams)
                } else {
                    method.invoke(instanceInvoke ?: classInvoke)
                }
                method.isAccessible = accessible
            }
        } catch (ignored: Throwable) {
        }
        return result
    }

    @Suppress("unused")
    val allMethodsAndFields: String
        get() = """
            Default: ${reference.get()?.telephonyManager}${'\n'}
            ${printAllMethodsAndFields("android.telephony.TelephonyManager")}
            ${printAllMethodsAndFields("android.telephony.MultiSimTelephonyManager")}
            ${printAllMethodsAndFields("android.telephony.MSimTelephonyManager")}
            ${printAllMethodsAndFields("com.mediatek.telephony.TelephonyManager")}
            ${printAllMethodsAndFields("com.mediatek.telephony.TelephonyManagerEx")}
            ${printAllMethodsAndFields("com.android.internal.telephony.ITelephony")}
        """.trimIndent()

    private fun printAllMethodsAndFields(className: String): String {
        val builder = StringBuilder()
        builder.append("========== $className\n")
        try {
            val cls = Class.forName(className)
            for (method in cls.methods) {
                val params = method.parameterTypes.map { it.name }
                builder.append(
                    "M: ${method.name} [${params.size}](${TextUtils.join(
                        ",",
                        params
                    )}) -> ${method.returnType} ${if (Modifier.isStatic(method.modifiers)) "(static)" else ""}\n"
                )
            }
            for (field in cls.fields) {
                builder.append("F: ${field.name} ${field.type}\n")
            }
        } catch (e: Throwable) {
            builder.append("E: $e\n")
        }
        return builder.toString()
    }

    companion object {

        private val classNames = arrayOf(
            null,
            "android.telephony.TelephonyManager",
            "android.telephony.MSimTelephonyManager",
            "android.telephony.MultiSimTelephonyManager",
            "com.mediatek.telephony.TelephonyManagerEx",
            "com.android.internal.telephony.Phone",
            "com.android.internal.telephony.PhoneFactory"
        )

        private val suffixes = arrayOf(
            "",
            "Gemini",
            "Ext",
            "Ds",
            "ForSubscription",
            "ForPhone"
        )
    }
}

可能对某人有帮助

于 2019-11-15T15:41:41.767 回答
-2
 <receiver
     android:name=".SimChangedReceiver"
    android:enabled="true"
    android:process=":remote" >
    <intent-filter>
        <action android:name="android.intent.action.SIM_STATE_CHANGED" />
    </intent-filter>
    <intent-filter>
        <action android:name="android.intent.action.BOOT_COMPLETED" />
    </intent-filter>
 </receiver>

SimChangedReceiver class

public class SimChangedReceiver extends BroadcastReceiver {

public void onReceive(Context context, Intent intent) {
    String action = intent.getAction();
    if (action.equalsIgnoreCase("android.intent.action.SIM_STATE_CHANGED")) {
        Log.d("SimChangedReceiver", "--> SIM state changed <--");   

      //            do code  whatever u want to apply action                //

    }
   }
}

这也适用于双卡,你不需要打电话给这个接收器,因为它会远程运行

于 2014-07-15T06:19:17.507 回答