/* * 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 mModems = new ArrayList(); private static ArrayList mSims = new ArrayList(); 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 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); } } 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 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 result = new ArrayList(); 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 getAllModems() { synchronized (mLock) { ArrayList modems = new ArrayList(); 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 getAllSims() { synchronized (mLock) { ArrayList sims = new ArrayList(); if (mSims.isEmpty()) { if (DBG) logd("getAllSims: empty list."); } else { for (HardwareConfig sim: mSims) { sims.add(sim); } } return sims; } } }