Home | History | Annotate | Download | only in impl
      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 
     17 package com.android.voicemail.impl;
     18 
     19 import android.content.Context;
     20 import android.os.PersistableBundle;
     21 import android.support.annotation.Nullable;
     22 import android.support.annotation.VisibleForTesting;
     23 import android.util.ArrayMap;
     24 import com.android.dialer.configprovider.ConfigProviderBindings;
     25 import com.android.voicemail.impl.utils.XmlUtils;
     26 import java.io.IOException;
     27 import java.util.ArrayList;
     28 import java.util.Map;
     29 import java.util.Map.Entry;
     30 import org.xmlpull.v1.XmlPullParser;
     31 import org.xmlpull.v1.XmlPullParserException;
     32 
     33 /** Load and caches telephony vvm config from res/xml/vvm_config.xml */
     34 public class TelephonyVvmConfigManager {
     35 
     36   private static final String TAG = "TelephonyVvmCfgMgr";
     37 
     38   private static final boolean USE_DEBUG_CONFIG = false;
     39 
     40   private static final String TAG_PERSISTABLEMAP = "pbundle_as_map";
     41 
     42   @VisibleForTesting static final String KEY_MCCMNC = "mccmnc";
     43 
     44   private static final String KEY_FEATURE_FLAG_NAME = "feature_flag_name";
     45 
     46   private static Map<String, PersistableBundle> sCachedConfigs;
     47 
     48   private final Map<String, PersistableBundle> mConfigs;
     49 
     50   public TelephonyVvmConfigManager(Context context) {
     51     if (sCachedConfigs == null) {
     52       sCachedConfigs = loadConfigs(context, context.getResources().getXml(R.xml.vvm_config));
     53     }
     54     mConfigs = sCachedConfigs;
     55   }
     56 
     57   @VisibleForTesting
     58   TelephonyVvmConfigManager(Context context, XmlPullParser parser) {
     59     mConfigs = loadConfigs(context, parser);
     60   }
     61 
     62   @Nullable
     63   public PersistableBundle getConfig(String mccMnc) {
     64     if (USE_DEBUG_CONFIG) {
     65       return mConfigs.get("TEST");
     66     }
     67     return mConfigs.get(mccMnc);
     68   }
     69 
     70   private static Map<String, PersistableBundle> loadConfigs(Context context, XmlPullParser parser) {
     71     Map<String, PersistableBundle> configs = new ArrayMap<>();
     72     try {
     73       ArrayList list = readBundleList(parser);
     74       for (Object object : list) {
     75         if (!(object instanceof PersistableBundle)) {
     76           throw new IllegalArgumentException("PersistableBundle expected, got " + object);
     77         }
     78         PersistableBundle bundle = (PersistableBundle) object;
     79 
     80         if (bundle.containsKey(KEY_FEATURE_FLAG_NAME)
     81             && !ConfigProviderBindings.get(context)
     82                 .getBoolean(bundle.getString(KEY_FEATURE_FLAG_NAME), false)) {
     83           continue;
     84         }
     85 
     86         String[] mccMncs = bundle.getStringArray(KEY_MCCMNC);
     87         if (mccMncs == null) {
     88           throw new IllegalArgumentException("MCCMNC is null");
     89         }
     90         for (String mccMnc : mccMncs) {
     91           configs.put(mccMnc, bundle);
     92         }
     93       }
     94     } catch (IOException | XmlPullParserException e) {
     95       throw new RuntimeException(e);
     96     }
     97     return configs;
     98   }
     99 
    100   @Nullable
    101   public static ArrayList readBundleList(XmlPullParser in)
    102       throws IOException, XmlPullParserException {
    103     final int outerDepth = in.getDepth();
    104     int event;
    105     while (((event = in.next()) != XmlPullParser.END_DOCUMENT)
    106         && (event != XmlPullParser.END_TAG || in.getDepth() < outerDepth)) {
    107       if (event == XmlPullParser.START_TAG) {
    108         final String startTag = in.getName();
    109         final String[] tagName = new String[1];
    110         in.next();
    111         return XmlUtils.readThisListXml(in, startTag, tagName, new MyReadMapCallback(), false);
    112       }
    113     }
    114     return null;
    115   }
    116 
    117   public static PersistableBundle restoreFromXml(XmlPullParser in)
    118       throws IOException, XmlPullParserException {
    119     final int outerDepth = in.getDepth();
    120     final String startTag = in.getName();
    121     final String[] tagName = new String[1];
    122     int event;
    123     while (((event = in.next()) != XmlPullParser.END_DOCUMENT)
    124         && (event != XmlPullParser.END_TAG || in.getDepth() < outerDepth)) {
    125       if (event == XmlPullParser.START_TAG) {
    126         ArrayMap<String, ?> map =
    127             XmlUtils.readThisArrayMapXml(in, startTag, tagName, new MyReadMapCallback());
    128         PersistableBundle result = new PersistableBundle();
    129         for (Entry<String, ?> entry : map.entrySet()) {
    130           Object value = entry.getValue();
    131           if (value instanceof Integer) {
    132             result.putInt(entry.getKey(), (int) value);
    133           } else if (value instanceof Boolean) {
    134             result.putBoolean(entry.getKey(), (boolean) value);
    135           } else if (value instanceof String) {
    136             result.putString(entry.getKey(), (String) value);
    137           } else if (value instanceof String[]) {
    138             result.putStringArray(entry.getKey(), (String[]) value);
    139           } else if (value instanceof PersistableBundle) {
    140             result.putPersistableBundle(entry.getKey(), (PersistableBundle) value);
    141           }
    142         }
    143         return result;
    144       }
    145     }
    146     return PersistableBundle.EMPTY;
    147   }
    148 
    149   static class MyReadMapCallback implements XmlUtils.ReadMapCallback {
    150 
    151     @Override
    152     public Object readThisUnknownObjectXml(XmlPullParser in, String tag)
    153         throws XmlPullParserException, IOException {
    154       if (TAG_PERSISTABLEMAP.equals(tag)) {
    155         return restoreFromXml(in);
    156       }
    157       throw new XmlPullParserException("Unknown tag=" + tag);
    158     }
    159   }
    160 }
    161