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