content: /*
   * Copyright (C) 2014 The Android Open Source Project
   *
   * Licensed under the Apache License, Version 2.0 (the "License");
   * you may not use this file except in compliance with the License.
   * You may obtain a copy of the License at
   *
   *      http://www.apache.org/licenses/LICENSE-2.0
   *
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS,
   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   * See the License for the specific language governing permissions and
   * limitations under the License.
   */
  
  package com.android.internal.telephony;
  
  import android.content.res.Resources;
  import com.android.internal.telephony.*;
  import android.telephony.TelephonyManager;
  
  import android.os.AsyncResult;
  import android.telephony.Rlog;
  import java.util.BitSet;
  import java.util.List;
  import java.util.ArrayList;
  import android.text.TextUtils;
  import android.os.Handler;
  import android.os.Message;
  import android.os.Registrant;
  import android.os.RegistrantList;
  import android.telephony.ServiceState;
  
  /**
   * TelephonyDevController - provides a unified view of the
   * telephony hardware resources on a device.
   *
   * manages the set of HardwareConfig for the framework.
   */
  public class TelephonyDevController extends Handler {
      private static final String LOG_TAG = "TDC";
      private static final boolean DBG = true;
      private static final Object mLock = new Object();
  
      private static final int EVENT_HARDWARE_CONFIG_CHANGED = 1;
  
      private static TelephonyDevController sTelephonyDevController;
      private static ArrayList<HardwareConfig> mModems = new ArrayList<HardwareConfig>();
      private static ArrayList<HardwareConfig> mSims = new ArrayList<HardwareConfig>();
  
      private static Message sRilHardwareConfig;
  
      private static void logd(String s) {
          Rlog.d(LOG_TAG, s);
      }
  
      private static void loge(String s) {
          Rlog.e(LOG_TAG, s);
      }
  
      public static TelephonyDevController create() {
          synchronized (mLock) {
              if (sTelephonyDevController != null) {
                  throw new RuntimeException("TelephonyDevController already created!?!");
              }
              sTelephonyDevController = new TelephonyDevController();
              return sTelephonyDevController;
          }
      }
  
      public static TelephonyDevController getInstance() {
          synchronized (mLock) {
              if (sTelephonyDevController == null) {
                  throw new RuntimeException("TelephonyDevController not yet created!?!");
              }
              return sTelephonyDevController;
          }
      }
  
      private void initFromResource() {
          Resources resource = Resources.getSystem();
          String[] hwStrings = resource.getStringArray(
              com.android.internal.R.array.config_telephonyHardware);
          if (hwStrings != null) {
              for (String hwString : hwStrings) {
                  HardwareConfig hw = new HardwareConfig(hwString);
                  if (hw != null) {
                      if (hw.type == HardwareConfig.DEV_HARDWARE_TYPE_MODEM) {
                          updateOrInsert(hw, mModems);
                      } else if (hw.type == HardwareConfig.DEV_HARDWARE_TYPE_SIM) {
                          updateOrInsert(hw, mSims);
                      }
                  }
              }
          }
      }
  
      private TelephonyDevController() {
          initFromResource();
  
          mModems.trimToSize();
          mSims.trimToSize();
      }
  
      /**
       * each RIL call this interface to register/unregister the unsolicited hardware
       * configuration callback data it can provide.
       */
      public static void registerRIL(CommandsInterface cmdsIf) {
          /* get the current configuration from this ril... */
          cmdsIf.getHardwareConfig(sRilHardwareConfig);
          /* ... process it ... */
          if (sRilHardwareConfig != null) {
              AsyncResult ar = (AsyncResult) sRilHardwareConfig.obj;
              if (ar.exception == null) {
                  handleGetHardwareConfigChanged(ar);
              }
          }
          /* and register for async device configuration change. */
          cmdsIf.registerForHardwareConfigChanged(sTelephonyDevController, EVENT_HARDWARE_CONFIG_CHANGED, null);
      }
  
      public static void unregisterRIL(CommandsInterface cmdsIf) {
          cmdsIf.unregisterForHardwareConfigChanged(sTelephonyDevController);
      }
  
      /**
       * handle callbacks from RIL.
       */
      public void handleMessage(Message msg) {
          AsyncResult ar;
          switch (msg.what) {
              case EVENT_HARDWARE_CONFIG_CHANGED:
                  if (DBG) logd("handleMessage: received EVENT_HARDWARE_CONFIG_CHANGED");
                  ar = (AsyncResult) msg.obj;
                  handleGetHardwareConfigChanged(ar);
              break;
              default:
                  loge("handleMessage: Unknown Event " + msg.what);
          }
      }
  
      /**
       * hardware configuration update or insert.
       */
      private static void updateOrInsert(HardwareConfig hw, ArrayList<HardwareConfig> list) {
          int size;
          HardwareConfig item;
          synchronized (mLock) {
              size = list.size();
              for (int i = 0 ; i < size ; i++) {
                  item = list.get(i);
                  if (item.uuid.compareTo(hw.uuid) == 0) {
                      if (DBG) logd("updateOrInsert: removing: " + item);
                      list.remove(i);
                      break;
                  }
              }
              if (DBG) logd("updateOrInsert: inserting: " + hw);
              list.add(hw);
          }
      }
  
      /**
       * hardware configuration changed.
       */
      private static void handleGetHardwareConfigChanged(AsyncResult ar) {
          if ((ar.exception == null) && (ar.result != null)) {
              List hwcfg = (List)ar.result;
              for (int i = 0 ; i < hwcfg.size() ; i++) {
                  HardwareConfig hw = null;
  
                  hw = (HardwareConfig) hwcfg.get(i);
                  if (hw != null) {
                      if (hw.type == HardwareConfig.DEV_HARDWARE_TYPE_MODEM) {
                          updateOrInsert(hw, mModems);
                      } else if (hw.type == HardwareConfig.DEV_HARDWARE_TYPE_SIM) {
                          updateOrInsert(hw, mSims);
                      }
                  }
              }
          } else {
              /* error detected, ignore.  are we missing some real time configutation
               * at this point?  what to do...
               */
              loge("handleGetHardwareConfigChanged - returned an error.");
          }
      }
  
      /**
       * get total number of registered modem.
       */
      public static int getModemCount() {
          synchronized (mLock) {
              int count = mModems.size();
              if (DBG) logd("getModemCount: " + count);
              return count;
          }
      }
  
      /**
       * get modem at index 'index'.
       */
      public HardwareConfig getModem(int index) {
          synchronized (mLock) {
              if (mModems.isEmpty()) {
                  loge("getModem: no registered modem device?!?");
                  return null;
              }
  
              if (index > getModemCount()) {
                  loge("getModem: out-of-bounds access for modem device " + index + " max: " + getModemCount());
                  return null;
              }
  
              if (DBG) logd("getModem: " + index);
              return mModems.get(index);
          }
      }
  
      /**
       * get total number of registered sims.
       */
      public int getSimCount() {
          synchronized (mLock) {
              int count = mSims.size();
              if (DBG) logd("getSimCount: " + count);
              return count;
          }
      }
  
      /**
       * get sim at index 'index'.
       */
      public HardwareConfig getSim(int index) {
          synchronized (mLock) {
              if (mSims.isEmpty()) {
                  loge("getSim: no registered sim device?!?");
                  return null;
              }
  
              if (index > getSimCount()) {
                  loge("getSim: out-of-bounds access for sim device " + index + " max: " + getSimCount());
                  return null;
              }
  
              if (DBG) logd("getSim: " + index);
              return mSims.get(index);
          }
      }
  
      /**
       * get modem associated with sim index 'simIndex'.
       */
      public HardwareConfig getModemForSim(int simIndex) {
          synchronized (mLock) {
              if (mModems.isEmpty() || mSims.isEmpty()) {
                  loge("getModemForSim: no registered modem/sim device?!?");
                  return null;
              }
  
              if (simIndex > getSimCount()) {
                  loge("getModemForSim: out-of-bounds access for sim device " + simIndex + " max: " + getSimCount());
                  return null;
              }
  
              if (DBG) logd("getModemForSim " + simIndex);
  
              HardwareConfig sim = getSim(simIndex);
              for (HardwareConfig modem: mModems) {
                  if (modem.uuid.equals(sim.modemUuid)) {
                      return modem;
                  }
              }
  
              return null;
          }
      }
  
      /**
       * get all sim's associated with modem at index 'modemIndex'.
       */
      public ArrayList<HardwareConfig> getAllSimsForModem(int modemIndex) {
          synchronized (mLock) {
              if (mSims.isEmpty()) {
                  loge("getAllSimsForModem: no registered sim device?!?");
                  return null;
              }
  
              if (modemIndex > getModemCount()) {
                  loge("getAllSimsForModem: out-of-bounds access for modem device " + modemIndex + " max: " + getModemCount());
                  return null;
              }
  
              if (DBG) logd("getAllSimsForModem " + modemIndex);
  
              ArrayList<HardwareConfig> result = new ArrayList<HardwareConfig>();
              HardwareConfig modem = getModem(modemIndex);
              for (HardwareConfig sim: mSims) {
                  if (sim.modemUuid.equals(modem.uuid)) {
                      result.add(sim);
                  }
              }
              return result;
          }
      }
  
      /**
       * get all modem's registered.
       */
      public ArrayList<HardwareConfig> getAllModems() {
          synchronized (mLock) {
              ArrayList<HardwareConfig> modems = new ArrayList<HardwareConfig>();
              if (mModems.isEmpty()) {
                  if (DBG) logd("getAllModems: empty list.");
              } else {
                  for (HardwareConfig modem: mModems) {
                      modems.add(modem);
                  }
              }
  
              return modems;
          }
      }
  
      /**
       * get all sim's registered.
       */
      public ArrayList<HardwareConfig> getAllSims() {
          synchronized (mLock) {
              ArrayList<HardwareConfig> sims = new ArrayList<HardwareConfig>();
              if (mSims.isEmpty()) {
                  if (DBG) logd("getAllSims: empty list.");
              } else {
                  for (HardwareConfig sim: mSims) {
                      sims.add(sim);
                  }
              }
  
              return sims;
          }
      }
  }
  