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