blob: 718b05d0227e59dafb83c4788dc6704d7aaed75e [file] [log] [blame]
Dianne Hackbornf8b8a3f2011-03-04 00:05:31 -08001/*
2 * Copyright (C) 2011 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.server;
18
19import com.android.internal.util.XmlUtils;
20
21import org.xmlpull.v1.XmlPullParser;
22import org.xmlpull.v1.XmlPullParserException;
23import org.xmlpull.v1.XmlSerializer;
24
25import android.content.ComponentName;
26import android.content.IntentFilter;
27import android.content.pm.ActivityInfo;
28import android.content.pm.ResolveInfo;
29import android.util.Slog;
30
31import java.io.IOException;
32import java.io.PrintWriter;
33import java.util.List;
34
35public class PreferredComponent {
36 public final int mMatch;
37 public final ComponentName mComponent;
38
39 private final String[] mSetPackages;
40 private final String[] mSetClasses;
41 private final String[] mSetComponents;
42 private final String mShortComponent;
43 private String mParseError;
44
45 private final Callbacks mCallbacks;
46
47 public interface Callbacks {
48 public boolean onReadTag(String tagName, XmlPullParser parser)
49 throws XmlPullParserException, IOException;
50 }
51
52 public PreferredComponent(Callbacks callbacks, int match, ComponentName[] set,
53 ComponentName component) {
54 mCallbacks = callbacks;
55 mMatch = match&IntentFilter.MATCH_CATEGORY_MASK;
56 mComponent = component;
57 mShortComponent = component.flattenToShortString();
58 mParseError = null;
59 if (set != null) {
60 final int N = set.length;
61 String[] myPackages = new String[N];
62 String[] myClasses = new String[N];
63 String[] myComponents = new String[N];
64 for (int i=0; i<N; i++) {
65 ComponentName cn = set[i];
66 if (cn == null) {
67 mSetPackages = null;
68 mSetClasses = null;
69 mSetComponents = null;
70 return;
71 }
72 myPackages[i] = cn.getPackageName().intern();
73 myClasses[i] = cn.getClassName().intern();
74 myComponents[i] = cn.flattenToShortString().intern();
75 }
76 mSetPackages = myPackages;
77 mSetClasses = myClasses;
78 mSetComponents = myComponents;
79 } else {
80 mSetPackages = null;
81 mSetClasses = null;
82 mSetComponents = null;
83 }
84 }
85
86 public PreferredComponent(Callbacks callbacks, XmlPullParser parser)
87 throws XmlPullParserException, IOException {
88 mCallbacks = callbacks;
89 mShortComponent = parser.getAttributeValue(null, "name");
90 mComponent = ComponentName.unflattenFromString(mShortComponent);
91 if (mComponent == null) {
92 mParseError = "Bad activity name " + mShortComponent;
93 }
94 String matchStr = parser.getAttributeValue(null, "match");
95 mMatch = matchStr != null ? Integer.parseInt(matchStr, 16) : 0;
96 String setCountStr = parser.getAttributeValue(null, "set");
97 int setCount = setCountStr != null ? Integer.parseInt(setCountStr) : 0;
98
99 String[] myPackages = setCount > 0 ? new String[setCount] : null;
100 String[] myClasses = setCount > 0 ? new String[setCount] : null;
101 String[] myComponents = setCount > 0 ? new String[setCount] : null;
102
103 int setPos = 0;
104
105 int outerDepth = parser.getDepth();
106 int type;
107 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
108 && (type != XmlPullParser.END_TAG
109 || parser.getDepth() > outerDepth)) {
110 if (type == XmlPullParser.END_TAG
111 || type == XmlPullParser.TEXT) {
112 continue;
113 }
114
115 String tagName = parser.getName();
116 //Log.i(TAG, "Parse outerDepth=" + outerDepth + " depth="
117 // + parser.getDepth() + " tag=" + tagName);
118 if (tagName.equals("set")) {
119 String name = parser.getAttributeValue(null, "name");
120 if (name == null) {
121 if (mParseError == null) {
122 mParseError = "No name in set tag in preferred activity "
123 + mShortComponent;
124 }
125 } else if (setPos >= setCount) {
126 if (mParseError == null) {
127 mParseError = "Too many set tags in preferred activity "
128 + mShortComponent;
129 }
130 } else {
131 ComponentName cn = ComponentName.unflattenFromString(name);
132 if (cn == null) {
133 if (mParseError == null) {
134 mParseError = "Bad set name " + name + " in preferred activity "
135 + mShortComponent;
136 }
137 } else {
138 myPackages[setPos] = cn.getPackageName();
139 myClasses[setPos] = cn.getClassName();
140 myComponents[setPos] = name;
141 setPos++;
142 }
143 }
144 XmlUtils.skipCurrentTag(parser);
145 } else if (!mCallbacks.onReadTag(tagName, parser)) {
146 Slog.w("PreferredComponent", "Unknown element: " + parser.getName());
147 XmlUtils.skipCurrentTag(parser);
148 }
149 }
150
151 if (setPos != setCount) {
152 if (mParseError == null) {
153 mParseError = "Not enough set tags (expected " + setCount
154 + " but found " + setPos + ") in " + mShortComponent;
155 }
156 }
157
158 mSetPackages = myPackages;
159 mSetClasses = myClasses;
160 mSetComponents = myComponents;
161 }
162
163 public String getParseError() {
164 return mParseError;
165 }
166
167 public void writeToXml(XmlSerializer serializer) throws IOException {
168 final int NS = mSetClasses != null ? mSetClasses.length : 0;
169 serializer.attribute(null, "name", mShortComponent);
170 if (mMatch != 0) {
171 serializer.attribute(null, "match", Integer.toHexString(mMatch));
172 }
173 serializer.attribute(null, "set", Integer.toString(NS));
174 for (int s=0; s<NS; s++) {
175 serializer.startTag(null, "set");
176 serializer.attribute(null, "name", mSetComponents[s]);
177 serializer.endTag(null, "set");
178 }
179 }
180
181 public boolean sameSet(List<ResolveInfo> query, int priority) {
182 if (mSetPackages == null) return false;
183 final int NQ = query.size();
184 final int NS = mSetPackages.length;
185 int numMatch = 0;
186 for (int i=0; i<NQ; i++) {
187 ResolveInfo ri = query.get(i);
188 if (ri.priority != priority) continue;
189 ActivityInfo ai = ri.activityInfo;
190 boolean good = false;
191 for (int j=0; j<NS; j++) {
192 if (mSetPackages[j].equals(ai.packageName)
193 && mSetClasses[j].equals(ai.name)) {
194 numMatch++;
195 good = true;
196 break;
197 }
198 }
199 if (!good) return false;
200 }
201 return numMatch == NS;
202 }
203
204 public void dump(PrintWriter out, String prefix, Object ident) {
205 out.print(prefix); out.print(
206 Integer.toHexString(System.identityHashCode(ident)));
207 out.print(' ');
208 out.print(mComponent.flattenToShortString());
209 out.print(" match=0x");
210 out.println( Integer.toHexString(mMatch));
211 if (mSetComponents != null) {
212 out.print(prefix); out.println(" Selected from:");
213 for (int i=0; i<mSetComponents.length; i++) {
214 out.print(prefix); out.print(" ");
215 out.println(mSetComponents[i]);
216 }
217 }
218 }
219}