• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
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 
17 package com.android.server;
18 
19 import com.android.internal.util.XmlUtils;
20 
21 import org.xmlpull.v1.XmlPullParser;
22 import org.xmlpull.v1.XmlPullParserException;
23 import org.xmlpull.v1.XmlSerializer;
24 
25 import android.content.ComponentName;
26 import android.content.IntentFilter;
27 import android.content.pm.ActivityInfo;
28 import android.content.pm.ResolveInfo;
29 import android.util.Slog;
30 
31 import java.io.IOException;
32 import java.io.PrintWriter;
33 import java.util.List;
34 
35 public 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 {
onReadTag(String tagName, XmlPullParser parser)48         public boolean onReadTag(String tagName, XmlPullParser parser)
49                 throws XmlPullParserException, IOException;
50     }
51 
PreferredComponent(Callbacks callbacks, int match, ComponentName[] set, ComponentName component)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 
PreferredComponent(Callbacks callbacks, XmlPullParser parser)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 
getParseError()163     public String getParseError() {
164         return mParseError;
165     }
166 
writeToXml(XmlSerializer serializer, boolean full)167     public void writeToXml(XmlSerializer serializer, boolean full) throws IOException {
168         final int NS = mSetClasses != null ? mSetClasses.length : 0;
169         serializer.attribute(null, "name", mShortComponent);
170         if (full) {
171             if (mMatch != 0) {
172                 serializer.attribute(null, "match", Integer.toHexString(mMatch));
173             }
174             serializer.attribute(null, "set", Integer.toString(NS));
175             for (int s=0; s<NS; s++) {
176                 serializer.startTag(null, "set");
177                 serializer.attribute(null, "name", mSetComponents[s]);
178                 serializer.endTag(null, "set");
179             }
180         }
181     }
182 
sameSet(List<ResolveInfo> query, int priority)183     public boolean sameSet(List<ResolveInfo> query, int priority) {
184         if (mSetPackages == null) return false;
185         final int NQ = query.size();
186         final int NS = mSetPackages.length;
187         int numMatch = 0;
188         for (int i=0; i<NQ; i++) {
189             ResolveInfo ri = query.get(i);
190             if (ri.priority != priority) continue;
191             ActivityInfo ai = ri.activityInfo;
192             boolean good = false;
193             for (int j=0; j<NS; j++) {
194                 if (mSetPackages[j].equals(ai.packageName)
195                         && mSetClasses[j].equals(ai.name)) {
196                     numMatch++;
197                     good = true;
198                     break;
199                 }
200             }
201             if (!good) return false;
202         }
203         return numMatch == NS;
204     }
205 
dump(PrintWriter out, String prefix, Object ident)206     public void dump(PrintWriter out, String prefix, Object ident) {
207         out.print(prefix); out.print(
208                 Integer.toHexString(System.identityHashCode(ident)));
209                 out.print(' ');
210                 out.print(mComponent.flattenToShortString());
211                 out.print(" match=0x");
212                 out.println( Integer.toHexString(mMatch));
213         if (mSetComponents != null) {
214             out.print(prefix); out.println("  Selected from:");
215             for (int i=0; i<mSetComponents.length; i++) {
216                 out.print(prefix); out.print("    ");
217                         out.println(mSetComponents[i]);
218             }
219         }
220     }
221 }
222