Sim 卡

274 阅读2分钟
  • 有关Sim卡状态

    •   public static final int SIM_STATE_UNKNOWN = 0;//未知
        public static final int SIM_STATE_ABSENT = 1;//拨卡、没有可用sim卡
        public static final int SIM_STATE_PIN_REQUIRED = 2;//需要pin码解锁
        public static final int SIM_STATE_PUK_REQUIRED = 3;//需要puk码解锁
        public static final int SIM_STATE_NETWORK_LOCKED = 4;
        public static final int SIM_STATE_READY = 5;//验证成功
        public static final int SIM_STATE_NOT_READY = 6;//SIM 卡未就绪
      
  • 关于Sim卡数据,有几个比较重要属性

    •   slotidphoneid:是指卡槽,双卡机器的卡槽1值为0,卡槽2值为1,依次类推
    •   subid:数据库中的一个主键,从1开始,每插入一个新卡,subId的值就会加1
    •   simstate:表示卡状态
  • Sim卡底层和锁屏主要通过广播的方式进行数据通讯 Intent.ACTION_SIM_STATE_CHANGED

    • protected final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
      
          @Override
          public void onReceive(Context context, Intent intent) {
              final String action = intent.getAction();
              if (Intent.ACTION_SIM_STATE_CHANGED.equals(action)) {
                  mSimLockManagerInner = getSimLockManager();
                  mIccLockViewCtrl = getIccLockViewController();
                  SimData args = SimData.fromIntent(intent);
                  if (intent.getBooleanExtra(Intent.EXTRA_REBROADCAST_ON_UNLOCK, false)) {
                      // Guarantee mTelephonyCapable state after SysUI crash and restart
                      if (args.simState == TelephonyManager.SIM_STATE_ABSENT) {
                          mHandler.obtainMessage(MSG_TELEPHONY_CAPABLE, true).sendToTarget();
                      }
                      return;
                  }
                  mHandler.obtainMessage(MSG_SIM_STATE_CHANGE, args.subId, args.slotId, args.simState)
                          .sendToTarget();
              }
          }
      };
      

广播一般配合Handler进行处理,因为广播无法处理耗时操作

mHandler.obtainMessage(MSG_SIM_STATE_CHANGE, args.subId, args.slotId, args.simState)
                    .sendToTarget();

然后再通过观察者的方式,回调通知到各个地方

void handleSimStateChange(int subId, int slotId, int state) {
    if ((changed || becameAbsent || becameNotReady)) {
        for (int i = 0; i < mCallbacks.size(); i++) {
            KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
            if (cb != null) {
                cb.onSimStateChanged(subId, slotId, state);
            }
        }
    }
}
  • 插卡还没准备好TelephonyManager.SIM_STATE_NOT_READY

  • 拨卡TelephonyManager.*SIM_STATE_ABSENT*的时候,修改缓存数据状态

    • if (state == TelephonyManager.SIM_STATE_ABSENT) {
          updateTelephonyCapable(true);
          // Even though the subscription is not valid anymore, we need to notify that the
          // SIM card was removed so we can update the UI.
          becameAbsent = true;
          for (SimData data : mSimDatas.values()) {
              // Set the SIM state of all SimData associated with that slot to ABSENT se we
              // do not move back into PIN/PUK locked and not detect the change below.
              if (data.slotId == slotId) {
                  data.simState = TelephonyManager.SIM_STATE_ABSENT;
              }
          }
      }
      
  • Pin 码验证成功 TelephonyManager.SIM_STATE_READY

    • @MainThread
      public void reportSimUnlocked(int subId) {
          mLogger.logSimUnlocked(subId);
          handleSimStateChange(subId, getSlotId(subId), TelephonyManager.SIM_STATE_READY);
      }
      
  • Pin 码验证,由于IPC可能会堵塞线程,所以需要放在独立线程执行

    • private abstract class CheckSimPin extends Thread {
          @Override
          public void run() {
              TelephonyManager telephonyManager = mTelephonyManager.createForSubscriptionId(mSubId);
              final PinResult result = telephonyManager.supplyIccLockPin(mPin);
              mView.post(() -> onSimCheckResponse(result,mSubId));
          }
      }
      
  • 验证卡槽是否有效

SubscriptionManager.isValidSlotIndex(slotId)

public static boolean isValidSlotIndex(int slotIndex) {
    return slotIndex >= 0 && slotIndex < TelephonyManager.getDefault().getActiveModemCount();
}
  • 验证subId是否有效

SubscriptionManager.isValidSubscriptionId(subId)

public static boolean isValidSubscriptionId(int subscriptionId) {
    return subscriptionId > INVALID_SUBSCRIPTION_ID;
}
  • 根据subId获取对应卡槽

int slotId = SubscriptionManager.getSlotIndex(subId);

  • 根据卡状态查找下一个有效的sim卡,比如还有哪些sim pin码待验证

    •   bestSlotId > slotId 该逻辑主要是为了从小到大验证,比如0,1,2,3 这样的顺序验证
    • public int getNextSubIdForState(int state) {
          List<SubscriptionInfo> list = getSubscriptionInfo(false /* forceReload */);
          int resultId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
          int bestSlotId = Integer.MAX_VALUE; // Favor lowest slot first
          for (int i = 0; i < list.size(); i++) {
              final SubscriptionInfo info = list.get(i);
              final int id = info.getSubscriptionId();
              int slotId = getSlotId(id);
              if (state == getSimState(id) && bestSlotId > slotId
                      /* Unisoc: Add for Bug1153151 @{ */
                      && SubscriptionManager.isValidSlotIndex(slotId)/* @} */) {
                  resultId = id;
                  bestSlotId = slotId;
              }
          }
          return resultId;
      }