• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2009 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.nfc;
18 
19 import org.xmlpull.v1.XmlPullParser;
20 import org.xmlpull.v1.XmlPullParserException;
21 
22 import android.content.BroadcastReceiver;
23 import android.content.ComponentName;
24 import android.content.Context;
25 import android.content.Intent;
26 import android.content.IntentFilter;
27 import android.content.pm.ActivityInfo;
28 import android.content.pm.PackageManager;
29 import android.content.pm.ResolveInfo;
30 import android.content.pm.PackageManager.NameNotFoundException;
31 import android.content.res.Resources;
32 import android.content.res.XmlResourceParser;
33 import android.util.Log;
34 
35 import java.io.IOException;
36 import java.util.ArrayList;
37 import java.util.List;
38 import java.util.concurrent.atomic.AtomicReference;
39 
40 /**
41  * A cache of intent filters registered to receive the TECH_DISCOVERED dispatch.
42  */
43 public class RegisteredComponentCache {
44     private static final String TAG = "RegisteredComponentCache";
45 
46     final Context mContext;
47     final String mAction;
48     final String mMetaDataName;
49     final AtomicReference<BroadcastReceiver> mReceiver;
50 
51     // synchronized on this
52     private ArrayList<ComponentInfo> mComponents;
53 
RegisteredComponentCache(Context context, String action, String metaDataName)54     public RegisteredComponentCache(Context context, String action, String metaDataName) {
55         mContext = context;
56         mAction = action;
57         mMetaDataName = metaDataName;
58 
59         generateComponentsList();
60 
61         final BroadcastReceiver receiver = new BroadcastReceiver() {
62             @Override
63             public void onReceive(Context context1, Intent intent) {
64                 generateComponentsList();
65             }
66         };
67         mReceiver = new AtomicReference<BroadcastReceiver>(receiver);
68         IntentFilter intentFilter = new IntentFilter();
69         intentFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
70         intentFilter.addAction(Intent.ACTION_PACKAGE_CHANGED);
71         intentFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
72         intentFilter.addDataScheme("package");
73         mContext.registerReceiver(receiver, intentFilter);
74         // Register for events related to sdcard installation.
75         IntentFilter sdFilter = new IntentFilter();
76         sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE);
77         sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
78         mContext.registerReceiver(receiver, sdFilter);
79     }
80 
81     public static class ComponentInfo {
82         public final ResolveInfo resolveInfo;
83         public final String[] techs;
84 
ComponentInfo(ResolveInfo resolveInfo, String[] techs)85         ComponentInfo(ResolveInfo resolveInfo, String[] techs) {
86             this.resolveInfo = resolveInfo;
87             this.techs = techs;
88         }
89 
90         @Override
toString()91         public String toString() {
92             StringBuilder out = new StringBuilder("ComponentInfo: ");
93             out.append(resolveInfo);
94             out.append(", techs: ");
95             for (String tech : techs) {
96                 out.append(tech);
97                 out.append(", ");
98             }
99             return out.toString();
100         }
101     }
102 
103     /**
104      * @return a collection of {@link RegisteredComponentCache.ComponentInfo} objects for all
105      * registered authenticators.
106      */
getComponents()107     public ArrayList<ComponentInfo> getComponents() {
108         synchronized (this) {
109             // It's safe to return a reference here since mComponents is always replaced and
110             // never updated when it changes.
111             return mComponents;
112         }
113     }
114 
115     /**
116      * Stops the monitoring of package additions, removals and changes.
117      */
close()118     public void close() {
119         final BroadcastReceiver receiver = mReceiver.getAndSet(null);
120         if (receiver != null) {
121             mContext.unregisterReceiver(receiver);
122         }
123     }
124 
125     @Override
finalize()126     protected void finalize() throws Throwable {
127         if (mReceiver.get() != null) {
128             Log.e(TAG, "RegisteredServicesCache finalized without being closed");
129         }
130         close();
131         super.finalize();
132     }
133 
dump(ArrayList<ComponentInfo> components)134     void dump(ArrayList<ComponentInfo> components) {
135         for (ComponentInfo component : components) {
136             Log.i(TAG, component.toString());
137         }
138     }
139 
generateComponentsList()140     void generateComponentsList() {
141         PackageManager pm = mContext.getPackageManager();
142         ArrayList<ComponentInfo> components = new ArrayList<ComponentInfo>();
143         List<ResolveInfo> resolveInfos = pm.queryIntentActivities(new Intent(mAction),
144                 PackageManager.GET_META_DATA);
145         for (ResolveInfo resolveInfo : resolveInfos) {
146             try {
147                 parseComponentInfo(resolveInfo, components);
148             } catch (XmlPullParserException e) {
149                 Log.w(TAG, "Unable to load component info " + resolveInfo.toString(), e);
150             } catch (IOException e) {
151                 Log.w(TAG, "Unable to load component info " + resolveInfo.toString(), e);
152             }
153         }
154 
155         dump(components);
156 
157         synchronized (this) {
158             mComponents = components;
159         }
160     }
161 
parseComponentInfo(ResolveInfo info, ArrayList<ComponentInfo> components)162     void parseComponentInfo(ResolveInfo info, ArrayList<ComponentInfo> components)
163             throws XmlPullParserException, IOException {
164         ActivityInfo ai = info.activityInfo;
165         PackageManager pm = mContext.getPackageManager();
166 
167         XmlResourceParser parser = null;
168         try {
169             parser = ai.loadXmlMetaData(pm, mMetaDataName);
170             if (parser == null) {
171                 throw new XmlPullParserException("No " + mMetaDataName + " meta-data");
172             }
173 
174             parseTechLists(pm.getResourcesForApplication(ai.applicationInfo), ai.packageName,
175                     parser, info, components);
176         } catch (NameNotFoundException e) {
177             throw new XmlPullParserException("Unable to load resources for " + ai.packageName);
178         } finally {
179             if (parser != null) parser.close();
180         }
181     }
182 
parseTechLists(Resources res, String packageName, XmlPullParser parser, ResolveInfo resolveInfo, ArrayList<ComponentInfo> components)183     void parseTechLists(Resources res, String packageName, XmlPullParser parser,
184             ResolveInfo resolveInfo, ArrayList<ComponentInfo> components)
185             throws XmlPullParserException, IOException {
186         int eventType = parser.getEventType();
187         while (eventType != XmlPullParser.START_TAG) {
188             eventType = parser.next();
189         }
190 
191         ArrayList<String> items = new ArrayList();
192         String tagName;
193         eventType = parser.next();
194         do {
195             tagName = parser.getName();
196             if (eventType == XmlPullParser.START_TAG && "tech".equals(tagName)) {
197                 items.add(parser.nextText());
198             } else if (eventType == XmlPullParser.END_TAG && "tech-list".equals(tagName)) {
199                 int size = items.size();
200                 if (size > 0) {
201                     String[] techs = new String[size];
202                     techs = items.toArray(techs);
203                     items.clear();
204                     components.add(new ComponentInfo(resolveInfo, techs));
205                 }
206             }
207             eventType = parser.next();
208         } while (eventType != XmlPullParser.END_DOCUMENT);
209     }
210 }
211