124dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton/*
224dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton * Copyright (C) 2009 The Android Open Source Project
324dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton *
424dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton * Licensed under the Apache License, Version 2.0 (the "License");
524dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton * you may not use this file except in compliance with the License.
624dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton * You may obtain a copy of the License at
724dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton *
824dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton *      http://www.apache.org/licenses/LICENSE-2.0
924dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton *
1024dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton * Unless required by applicable law or agreed to in writing, software
1124dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton * distributed under the License is distributed on an "AS IS" BASIS,
1224dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1324dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton * See the License for the specific language governing permissions and
1424dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton * limitations under the License.
1524dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton */
1624dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton
1724dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamiltonpackage com.android.nfc;
1824dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton
1924dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamiltonimport org.xmlpull.v1.XmlPullParser;
2024dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamiltonimport org.xmlpull.v1.XmlPullParserException;
2124dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton
22525c260303268a83da4c3413b953d13c9084e834The Android Open Source Projectimport android.app.ActivityManager;
2324dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamiltonimport android.content.BroadcastReceiver;
2424dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamiltonimport android.content.Context;
2524dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamiltonimport android.content.Intent;
2624dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamiltonimport android.content.IntentFilter;
2724dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamiltonimport android.content.pm.ActivityInfo;
2824dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamiltonimport android.content.pm.PackageManager;
2924dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamiltonimport android.content.pm.ResolveInfo;
3024dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamiltonimport android.content.pm.PackageManager.NameNotFoundException;
3124dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamiltonimport android.content.res.Resources;
3224dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamiltonimport android.content.res.XmlResourceParser;
33525c260303268a83da4c3413b953d13c9084e834The Android Open Source Projectimport android.os.UserHandle;
3424dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamiltonimport android.util.Log;
3524dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton
3624dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamiltonimport java.io.IOException;
3724dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamiltonimport java.util.ArrayList;
3824dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamiltonimport java.util.List;
3924dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamiltonimport java.util.concurrent.atomic.AtomicReference;
4024dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton
4124dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton/**
4224dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton * A cache of intent filters registered to receive the TECH_DISCOVERED dispatch.
4324dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton */
4424dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamiltonpublic class RegisteredComponentCache {
4524dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton    private static final String TAG = "RegisteredComponentCache";
46be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project    private static final boolean DEBUG = false;
4724dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton
4824dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton    final Context mContext;
4924dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton    final String mAction;
5024dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton    final String mMetaDataName;
5124dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton    final AtomicReference<BroadcastReceiver> mReceiver;
5224dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton
5324dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton    // synchronized on this
5424dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton    private ArrayList<ComponentInfo> mComponents;
5524dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton
5624dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton    public RegisteredComponentCache(Context context, String action, String metaDataName) {
5724dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton        mContext = context;
5824dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton        mAction = action;
5924dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton        mMetaDataName = metaDataName;
6024dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton
6124dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton        generateComponentsList();
6224dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton
6324dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton        final BroadcastReceiver receiver = new BroadcastReceiver() {
6424dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton            @Override
6524dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton            public void onReceive(Context context1, Intent intent) {
6624dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton                generateComponentsList();
6724dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton            }
6824dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton        };
6924dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton        mReceiver = new AtomicReference<BroadcastReceiver>(receiver);
7024dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton        IntentFilter intentFilter = new IntentFilter();
7124dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton        intentFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
7224dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton        intentFilter.addAction(Intent.ACTION_PACKAGE_CHANGED);
7324dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton        intentFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
7424dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton        intentFilter.addDataScheme("package");
75525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        mContext.registerReceiverAsUser(receiver, UserHandle.ALL, intentFilter, null, null);
7624dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton        // Register for events related to sdcard installation.
7724dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton        IntentFilter sdFilter = new IntentFilter();
7824dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton        sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE);
7924dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton        sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
80525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        mContext.registerReceiverAsUser(receiver, UserHandle.ALL, sdFilter, null, null);
81525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        // Generate a new list upon switching users as well
82525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        IntentFilter userFilter = new IntentFilter();
83525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        userFilter.addAction(Intent.ACTION_USER_SWITCHED);
84525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        mContext.registerReceiverAsUser(receiver, UserHandle.ALL, userFilter, null, null);
8524dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton    }
8624dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton
8724dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton    public static class ComponentInfo {
8824dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton        public final ResolveInfo resolveInfo;
8924dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton        public final String[] techs;
9024dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton
9124dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton        ComponentInfo(ResolveInfo resolveInfo, String[] techs) {
9224dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton            this.resolveInfo = resolveInfo;
9324dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton            this.techs = techs;
9424dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton        }
9524dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton
9624dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton        @Override
9724dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton        public String toString() {
9824dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton            StringBuilder out = new StringBuilder("ComponentInfo: ");
9924dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton            out.append(resolveInfo);
10024dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton            out.append(", techs: ");
10124dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton            for (String tech : techs) {
10224dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton                out.append(tech);
10324dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton                out.append(", ");
10424dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton            }
10524dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton            return out.toString();
10624dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton        }
10724dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton    }
10824dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton
10924dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton    /**
11024dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton     * @return a collection of {@link RegisteredComponentCache.ComponentInfo} objects for all
11124dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton     * registered authenticators.
11224dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton     */
11324dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton    public ArrayList<ComponentInfo> getComponents() {
11424dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton        synchronized (this) {
11524dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton            // It's safe to return a reference here since mComponents is always replaced and
11624dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton            // never updated when it changes.
11724dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton            return mComponents;
11824dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton        }
11924dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton    }
12024dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton
12124dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton    /**
12224dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton     * Stops the monitoring of package additions, removals and changes.
12324dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton     */
12424dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton    public void close() {
12524dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton        final BroadcastReceiver receiver = mReceiver.getAndSet(null);
12624dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton        if (receiver != null) {
12724dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton            mContext.unregisterReceiver(receiver);
12824dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton        }
12924dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton    }
13024dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton
13124dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton    @Override
13224dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton    protected void finalize() throws Throwable {
13324dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton        if (mReceiver.get() != null) {
13424dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton            Log.e(TAG, "RegisteredServicesCache finalized without being closed");
13524dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton        }
13624dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton        close();
13724dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton        super.finalize();
13824dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton    }
13924dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton
14024dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton    void dump(ArrayList<ComponentInfo> components) {
14124dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton        for (ComponentInfo component : components) {
14224dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton            Log.i(TAG, component.toString());
14324dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton        }
14424dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton    }
14524dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton
14624dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton    void generateComponentsList() {
147525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        PackageManager pm;
148525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        try {
149525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            UserHandle currentUser = new UserHandle(ActivityManager.getCurrentUser());
150525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            pm = mContext.createPackageContextAsUser("android", 0,
151525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                    currentUser).getPackageManager();
152525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        } catch (NameNotFoundException e) {
153525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            Log.e(TAG, "Could not create user package context");
154525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            return;
155525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        }
15624dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton        ArrayList<ComponentInfo> components = new ArrayList<ComponentInfo>();
157525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        List<ResolveInfo> resolveInfos = pm.queryIntentActivitiesAsUser(new Intent(mAction),
158525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                PackageManager.GET_META_DATA, ActivityManager.getCurrentUser());
15924dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton        for (ResolveInfo resolveInfo : resolveInfos) {
16024dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton            try {
161525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                parseComponentInfo(pm, resolveInfo, components);
16224dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton            } catch (XmlPullParserException e) {
16324dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton                Log.w(TAG, "Unable to load component info " + resolveInfo.toString(), e);
16424dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton            } catch (IOException e) {
16524dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton                Log.w(TAG, "Unable to load component info " + resolveInfo.toString(), e);
16624dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton            }
16724dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton        }
16824dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton
169be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project        if (DEBUG) {
170be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project            dump(components);
171be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project        }
17224dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton
17324dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton        synchronized (this) {
17424dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton            mComponents = components;
17524dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton        }
17624dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton    }
17724dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton
178525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project    void parseComponentInfo(PackageManager pm, ResolveInfo info,
179525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            ArrayList<ComponentInfo> components) throws XmlPullParserException, IOException {
18024dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton        ActivityInfo ai = info.activityInfo;
18124dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton
18224dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton        XmlResourceParser parser = null;
18324dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton        try {
18424dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton            parser = ai.loadXmlMetaData(pm, mMetaDataName);
18524dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton            if (parser == null) {
18624dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton                throw new XmlPullParserException("No " + mMetaDataName + " meta-data");
18724dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton            }
18824dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton
18924dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton            parseTechLists(pm.getResourcesForApplication(ai.applicationInfo), ai.packageName,
19024dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton                    parser, info, components);
19124dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton        } catch (NameNotFoundException e) {
19224dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton            throw new XmlPullParserException("Unable to load resources for " + ai.packageName);
19324dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton        } finally {
19424dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton            if (parser != null) parser.close();
19524dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton        }
19624dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton    }
19724dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton
19824dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton    void parseTechLists(Resources res, String packageName, XmlPullParser parser,
19924dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton            ResolveInfo resolveInfo, ArrayList<ComponentInfo> components)
20024dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton            throws XmlPullParserException, IOException {
20124dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton        int eventType = parser.getEventType();
20224dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton        while (eventType != XmlPullParser.START_TAG) {
20324dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton            eventType = parser.next();
20424dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton        }
20524dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton
206c9342fef947c49e247495b83f94f16d43cd3562cmike wakerly        ArrayList<String> items = new ArrayList<String>();
20724dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton        String tagName;
20824dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton        eventType = parser.next();
20924dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton        do {
21024dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton            tagName = parser.getName();
21124dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton            if (eventType == XmlPullParser.START_TAG && "tech".equals(tagName)) {
21224dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton                items.add(parser.nextText());
21324dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton            } else if (eventType == XmlPullParser.END_TAG && "tech-list".equals(tagName)) {
21424dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton                int size = items.size();
21524dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton                if (size > 0) {
21624dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton                    String[] techs = new String[size];
21724dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton                    techs = items.toArray(techs);
21824dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton                    items.clear();
21924dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton                    components.add(new ComponentInfo(resolveInfo, techs));
22024dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton                }
22124dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton            }
22224dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton            eventType = parser.next();
22324dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton        } while (eventType != XmlPullParser.END_DOCUMENT);
22424dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton    }
22524dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton}
226