Home | History | Annotate | Download | only in telephony
      1 /*
      2  * Copyright (C) 2016 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 package com.android.internal.telephony;
     17 
     18 import android.content.BroadcastReceiver;
     19 import android.content.Context;
     20 import android.content.Intent;
     21 import android.content.IntentFilter;
     22 import android.os.PersistableBundle;
     23 import android.os.UserHandle;
     24 import android.telephony.CarrierConfigManager;
     25 import android.telephony.ServiceState;
     26 import android.telephony.Rlog;
     27 import android.util.SparseArray;
     28 import android.util.SparseIntArray;
     29 
     30 import java.util.ArrayList;
     31 
     32 /**
     33  * This class loads configuration from CarrierConfig and uses it to determine
     34  * what RATs are within a ratcheting family.  For example all the HSPA/HSDPA/HSUPA RATs.
     35  * Then, until reset the class will only ratchet upwards within the family (order
     36  * determined by the CarrierConfig data).  The ServiceStateTracker will reset this
     37  * on cell-change.
     38  */
     39 public class RatRatcheter {
     40     private final static String LOG_TAG = "RilRatcheter";
     41 
     42     /**
     43      * This is a map of RAT types -> RAT families for rapid lookup.
     44      * The RAT families are defined by RAT type -> RAT Rank SparseIntArrays, so
     45      * we can compare the priorities of two RAT types by comparing the values
     46      * stored in the SparseIntArrays, higher values are higher priority.
     47      */
     48     private final SparseArray<SparseIntArray> mRatFamilyMap = new SparseArray<>();
     49 
     50     private final Phone mPhone;
     51 
     52     /** Constructor */
     53     public RatRatcheter(Phone phone) {
     54         mPhone = phone;
     55 
     56         IntentFilter intentFilter = new IntentFilter();
     57         intentFilter.addAction(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED);
     58         phone.getContext().registerReceiverAsUser(mConfigChangedReceiver, UserHandle.ALL,
     59                 intentFilter, null, null);
     60         resetRatFamilyMap();
     61     }
     62 
     63     public int ratchetRat(int oldRat, int newRat) {
     64         synchronized (mRatFamilyMap) {
     65             final SparseIntArray oldFamily = mRatFamilyMap.get(oldRat);
     66             if (oldFamily == null) return newRat;
     67 
     68             final SparseIntArray newFamily = mRatFamilyMap.get(newRat);
     69             if (newFamily != oldFamily) return newRat;
     70 
     71             // now go with the higher of the two
     72             final int oldRatRank = newFamily.get(oldRat, -1);
     73             final int newRatRank = newFamily.get(newRat, -1);
     74             return (oldRatRank > newRatRank ? oldRat : newRat);
     75         }
     76     }
     77 
     78     public void ratchetRat(ServiceState oldSS, ServiceState newSS) {
     79         int newVoiceRat = ratchetRat(oldSS.getRilVoiceRadioTechnology(),
     80                 newSS.getRilVoiceRadioTechnology());
     81         int newDataRat = ratchetRat(oldSS.getRilDataRadioTechnology(),
     82                 newSS.getRilDataRadioTechnology());
     83         boolean newUsingCA = oldSS.isUsingCarrierAggregation() ||
     84                 newSS.isUsingCarrierAggregation();
     85 
     86         newSS.setRilVoiceRadioTechnology(newVoiceRat);
     87         newSS.setRilDataRadioTechnology(newDataRat);
     88         newSS.setIsUsingCarrierAggregation(newUsingCA);
     89     }
     90 
     91     private BroadcastReceiver mConfigChangedReceiver = new BroadcastReceiver() {
     92         @Override
     93         public void onReceive(Context context, Intent intent) {
     94             final String action = intent.getAction();
     95             if (CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED.equals(action)) {
     96                 resetRatFamilyMap();
     97             }
     98         }
     99     };
    100 
    101     private void resetRatFamilyMap() {
    102         synchronized(mRatFamilyMap) {
    103             mRatFamilyMap.clear();
    104 
    105             final CarrierConfigManager configManager = (CarrierConfigManager)
    106                     mPhone.getContext().getSystemService(Context.CARRIER_CONFIG_SERVICE);
    107             if (configManager == null) return;
    108             PersistableBundle b = configManager.getConfig();
    109             if (b == null) return;
    110 
    111             // Reads an array of strings, eg:
    112             // ["GPRS, EDGE", "EVDO, EVDO_A, EVDO_B", "HSPA, HSDPA, HSUPA, HSPAP"]
    113             // Each string defines a family and the order of rats within the string express
    114             // the priority of the RAT within the family (ie, we'd move up to later-listed RATs, but
    115             // not down).
    116             String[] ratFamilies = b.getStringArray(CarrierConfigManager.KEY_RATCHET_RAT_FAMILIES);
    117             if (ratFamilies == null) return;
    118             for (String ratFamily : ratFamilies) {
    119                 String[] rats = ratFamily.split(",");
    120                 if (rats.length < 2) continue;
    121                 SparseIntArray currentFamily = new SparseIntArray(rats.length);
    122                 int pos = 0;
    123                 for (String ratString : rats) {
    124                     int ratInt;
    125                     try {
    126                         ratInt = Integer.parseInt(ratString.trim());
    127                     } catch (NumberFormatException e) {
    128                         Rlog.e(LOG_TAG, "NumberFormatException on " + ratString);
    129                         break;
    130                     }
    131                     if (mRatFamilyMap.get(ratInt) != null) {
    132                         Rlog.e(LOG_TAG, "RAT listed twice: " + ratString);
    133                         break;
    134                     }
    135                     currentFamily.put(ratInt, pos++);
    136                     mRatFamilyMap.put(ratInt, currentFamily);
    137                 }
    138             }
    139         }
    140     }
    141 }
    142