blob: 8e2e0cde273f47bea34bda0031e99ab96023f1a0 [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
Amith Yamasani09e9cdc2013-11-06 14:54:50 -080017package com.android.server.pm;
Dianne Hackbornf8b8a3f2011-03-04 00:05:31 -080018
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 {
Amith Yamasanie9ecc8b2013-08-22 11:16:27 -070036 private static final String TAG_SET = "set";
37 private static final String ATTR_ALWAYS = "always"; // boolean
38 private static final String ATTR_MATCH = "match"; // number
39 private static final String ATTR_NAME = "name"; // component name
40 private static final String ATTR_SET = "set"; // number
41
Dianne Hackbornf8b8a3f2011-03-04 00:05:31 -080042 public final int mMatch;
43 public final ComponentName mComponent;
Amith Yamasanie9ecc8b2013-08-22 11:16:27 -070044 // Whether this is to be the one that's always chosen. If false, it's the most recently chosen.
45 public boolean mAlways;
Dianne Hackbornf8b8a3f2011-03-04 00:05:31 -080046
Dianne Hackbornf2ac2762014-08-16 11:44:40 -070047 final String[] mSetPackages;
48 final String[] mSetClasses;
49 final String[] mSetComponents;
50 final String mShortComponent;
Dianne Hackbornf8b8a3f2011-03-04 00:05:31 -080051 private String mParseError;
52
53 private final Callbacks mCallbacks;
54
55 public interface Callbacks {
56 public boolean onReadTag(String tagName, XmlPullParser parser)
57 throws XmlPullParserException, IOException;
58 }
59
60 public PreferredComponent(Callbacks callbacks, int match, ComponentName[] set,
Amith Yamasanie9ecc8b2013-08-22 11:16:27 -070061 ComponentName component, boolean always) {
Dianne Hackbornf8b8a3f2011-03-04 00:05:31 -080062 mCallbacks = callbacks;
63 mMatch = match&IntentFilter.MATCH_CATEGORY_MASK;
64 mComponent = component;
Amith Yamasanie9ecc8b2013-08-22 11:16:27 -070065 mAlways = always;
Dianne Hackbornf8b8a3f2011-03-04 00:05:31 -080066 mShortComponent = component.flattenToShortString();
67 mParseError = null;
68 if (set != null) {
69 final int N = set.length;
70 String[] myPackages = new String[N];
71 String[] myClasses = new String[N];
72 String[] myComponents = new String[N];
73 for (int i=0; i<N; i++) {
74 ComponentName cn = set[i];
75 if (cn == null) {
76 mSetPackages = null;
77 mSetClasses = null;
78 mSetComponents = null;
79 return;
80 }
81 myPackages[i] = cn.getPackageName().intern();
82 myClasses[i] = cn.getClassName().intern();
Dianne Hackborn6d8dfbd2013-09-23 17:38:51 -070083 myComponents[i] = cn.flattenToShortString();
Dianne Hackbornf8b8a3f2011-03-04 00:05:31 -080084 }
85 mSetPackages = myPackages;
86 mSetClasses = myClasses;
87 mSetComponents = myComponents;
88 } else {
89 mSetPackages = null;
90 mSetClasses = null;
91 mSetComponents = null;
92 }
93 }
94
95 public PreferredComponent(Callbacks callbacks, XmlPullParser parser)
96 throws XmlPullParserException, IOException {
97 mCallbacks = callbacks;
Amith Yamasanie9ecc8b2013-08-22 11:16:27 -070098 mShortComponent = parser.getAttributeValue(null, ATTR_NAME);
Dianne Hackbornf8b8a3f2011-03-04 00:05:31 -080099 mComponent = ComponentName.unflattenFromString(mShortComponent);
100 if (mComponent == null) {
101 mParseError = "Bad activity name " + mShortComponent;
102 }
Amith Yamasanie9ecc8b2013-08-22 11:16:27 -0700103 String matchStr = parser.getAttributeValue(null, ATTR_MATCH);
Dianne Hackbornf8b8a3f2011-03-04 00:05:31 -0800104 mMatch = matchStr != null ? Integer.parseInt(matchStr, 16) : 0;
Amith Yamasanie9ecc8b2013-08-22 11:16:27 -0700105 String setCountStr = parser.getAttributeValue(null, ATTR_SET);
Dianne Hackbornf8b8a3f2011-03-04 00:05:31 -0800106 int setCount = setCountStr != null ? Integer.parseInt(setCountStr) : 0;
Amith Yamasanie9ecc8b2013-08-22 11:16:27 -0700107 String alwaysStr = parser.getAttributeValue(null, ATTR_ALWAYS);
108 mAlways = alwaysStr != null ? Boolean.parseBoolean(alwaysStr) : true;
Dianne Hackbornf8b8a3f2011-03-04 00:05:31 -0800109
110 String[] myPackages = setCount > 0 ? new String[setCount] : null;
111 String[] myClasses = setCount > 0 ? new String[setCount] : null;
112 String[] myComponents = setCount > 0 ? new String[setCount] : null;
113
114 int setPos = 0;
115
116 int outerDepth = parser.getDepth();
117 int type;
118 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
119 && (type != XmlPullParser.END_TAG
120 || parser.getDepth() > outerDepth)) {
121 if (type == XmlPullParser.END_TAG
122 || type == XmlPullParser.TEXT) {
123 continue;
124 }
125
126 String tagName = parser.getName();
127 //Log.i(TAG, "Parse outerDepth=" + outerDepth + " depth="
128 // + parser.getDepth() + " tag=" + tagName);
Amith Yamasanie9ecc8b2013-08-22 11:16:27 -0700129 if (tagName.equals(TAG_SET)) {
130 String name = parser.getAttributeValue(null, ATTR_NAME);
Dianne Hackbornf8b8a3f2011-03-04 00:05:31 -0800131 if (name == null) {
132 if (mParseError == null) {
133 mParseError = "No name in set tag in preferred activity "
134 + mShortComponent;
135 }
136 } else if (setPos >= setCount) {
137 if (mParseError == null) {
138 mParseError = "Too many set tags in preferred activity "
139 + mShortComponent;
140 }
141 } else {
142 ComponentName cn = ComponentName.unflattenFromString(name);
143 if (cn == null) {
144 if (mParseError == null) {
145 mParseError = "Bad set name " + name + " in preferred activity "
146 + mShortComponent;
147 }
148 } else {
149 myPackages[setPos] = cn.getPackageName();
150 myClasses[setPos] = cn.getClassName();
151 myComponents[setPos] = name;
152 setPos++;
153 }
154 }
155 XmlUtils.skipCurrentTag(parser);
156 } else if (!mCallbacks.onReadTag(tagName, parser)) {
157 Slog.w("PreferredComponent", "Unknown element: " + parser.getName());
158 XmlUtils.skipCurrentTag(parser);
159 }
160 }
161
162 if (setPos != setCount) {
163 if (mParseError == null) {
164 mParseError = "Not enough set tags (expected " + setCount
165 + " but found " + setPos + ") in " + mShortComponent;
166 }
167 }
168
169 mSetPackages = myPackages;
170 mSetClasses = myClasses;
171 mSetComponents = myComponents;
172 }
173
174 public String getParseError() {
175 return mParseError;
176 }
177
Dianne Hackborn8a2ed1d2013-01-29 15:18:29 -0800178 public void writeToXml(XmlSerializer serializer, boolean full) throws IOException {
Dianne Hackbornf8b8a3f2011-03-04 00:05:31 -0800179 final int NS = mSetClasses != null ? mSetClasses.length : 0;
Amith Yamasanie9ecc8b2013-08-22 11:16:27 -0700180 serializer.attribute(null, ATTR_NAME, mShortComponent);
Dianne Hackborn8a2ed1d2013-01-29 15:18:29 -0800181 if (full) {
182 if (mMatch != 0) {
Amith Yamasanie9ecc8b2013-08-22 11:16:27 -0700183 serializer.attribute(null, ATTR_MATCH, Integer.toHexString(mMatch));
Dianne Hackborn8a2ed1d2013-01-29 15:18:29 -0800184 }
Amith Yamasanie9ecc8b2013-08-22 11:16:27 -0700185 serializer.attribute(null, ATTR_ALWAYS, Boolean.toString(mAlways));
186 serializer.attribute(null, ATTR_SET, Integer.toString(NS));
Dianne Hackborn8a2ed1d2013-01-29 15:18:29 -0800187 for (int s=0; s<NS; s++) {
Amith Yamasanie9ecc8b2013-08-22 11:16:27 -0700188 serializer.startTag(null, TAG_SET);
189 serializer.attribute(null, ATTR_NAME, mSetComponents[s]);
190 serializer.endTag(null, TAG_SET);
Dianne Hackborn8a2ed1d2013-01-29 15:18:29 -0800191 }
Dianne Hackbornf8b8a3f2011-03-04 00:05:31 -0800192 }
193 }
194
Christopher Tate57792912015-01-27 13:47:51 -0800195 public boolean sameSet(List<ResolveInfo> query) {
Dianne Hackbornf2ac2762014-08-16 11:44:40 -0700196 if (mSetPackages == null) {
197 return query == null;
198 }
199 if (query == null) {
200 return false;
201 }
Dianne Hackbornf8b8a3f2011-03-04 00:05:31 -0800202 final int NQ = query.size();
203 final int NS = mSetPackages.length;
Christopher Tate57792912015-01-27 13:47:51 -0800204
Dianne Hackbornf8b8a3f2011-03-04 00:05:31 -0800205 int numMatch = 0;
206 for (int i=0; i<NQ; i++) {
207 ResolveInfo ri = query.get(i);
Dianne Hackbornf8b8a3f2011-03-04 00:05:31 -0800208 ActivityInfo ai = ri.activityInfo;
209 boolean good = false;
210 for (int j=0; j<NS; j++) {
211 if (mSetPackages[j].equals(ai.packageName)
212 && mSetClasses[j].equals(ai.name)) {
213 numMatch++;
214 good = true;
215 break;
216 }
217 }
218 if (!good) return false;
219 }
220 return numMatch == NS;
221 }
222
Dianne Hackbornf2ac2762014-08-16 11:44:40 -0700223 public boolean sameSet(ComponentName[] comps) {
224 if (mSetPackages == null) return false;
225 final int NQ = comps.length;
226 final int NS = mSetPackages.length;
227 int numMatch = 0;
228 for (int i=0; i<NQ; i++) {
229 ComponentName cn = comps[i];
230 boolean good = false;
231 for (int j=0; j<NS; j++) {
232 if (mSetPackages[j].equals(cn.getPackageName())
233 && mSetClasses[j].equals(cn.getClassName())) {
234 numMatch++;
235 good = true;
236 break;
237 }
238 }
239 if (!good) return false;
240 }
241 return numMatch == NS;
242 }
243
Dianne Hackbornf8b8a3f2011-03-04 00:05:31 -0800244 public void dump(PrintWriter out, String prefix, Object ident) {
245 out.print(prefix); out.print(
246 Integer.toHexString(System.identityHashCode(ident)));
247 out.print(' ');
Dianne Hackborn6d8dfbd2013-09-23 17:38:51 -0700248 out.println(mShortComponent);
249 out.print(prefix); out.print(" mMatch=0x");
250 out.print(Integer.toHexString(mMatch));
251 out.print(" mAlways="); out.println(mAlways);
Dianne Hackbornf8b8a3f2011-03-04 00:05:31 -0800252 if (mSetComponents != null) {
253 out.print(prefix); out.println(" Selected from:");
254 for (int i=0; i<mSetComponents.length; i++) {
255 out.print(prefix); out.print(" ");
256 out.println(mSetComponents[i]);
257 }
258 }
259 }
260}