Home | History | Annotate | Download | only in pm
      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.pm;
     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     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 
     42     public final int mMatch;
     43     public final ComponentName mComponent;
     44     // Whether this is to be the one that's always chosen. If false, it's the most recently chosen.
     45     public boolean mAlways;
     46 
     47     final String[] mSetPackages;
     48     final String[] mSetClasses;
     49     final String[] mSetComponents;
     50     final String mShortComponent;
     51     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,
     61             ComponentName component, boolean always) {
     62         mCallbacks = callbacks;
     63         mMatch = match&IntentFilter.MATCH_CATEGORY_MASK;
     64         mComponent = component;
     65         mAlways = always;
     66         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();
     83                 myComponents[i] = cn.flattenToShortString();
     84             }
     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;
     98         mShortComponent = parser.getAttributeValue(null, ATTR_NAME);
     99         mComponent = ComponentName.unflattenFromString(mShortComponent);
    100         if (mComponent == null) {
    101             mParseError = "Bad activity name " + mShortComponent;
    102         }
    103         String matchStr = parser.getAttributeValue(null, ATTR_MATCH);
    104         mMatch = matchStr != null ? Integer.parseInt(matchStr, 16) : 0;
    105         String setCountStr = parser.getAttributeValue(null, ATTR_SET);
    106         int setCount = setCountStr != null ? Integer.parseInt(setCountStr) : 0;
    107         String alwaysStr = parser.getAttributeValue(null, ATTR_ALWAYS);
    108         mAlways = alwaysStr != null ? Boolean.parseBoolean(alwaysStr) : true;
    109 
    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);
    129             if (tagName.equals(TAG_SET)) {
    130                 String name = parser.getAttributeValue(null, ATTR_NAME);
    131                 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 
    178     public void writeToXml(XmlSerializer serializer, boolean full) throws IOException {
    179         final int NS = mSetClasses != null ? mSetClasses.length : 0;
    180         serializer.attribute(null, ATTR_NAME, mShortComponent);
    181         if (full) {
    182             if (mMatch != 0) {
    183                 serializer.attribute(null, ATTR_MATCH, Integer.toHexString(mMatch));
    184             }
    185             serializer.attribute(null, ATTR_ALWAYS, Boolean.toString(mAlways));
    186             serializer.attribute(null, ATTR_SET, Integer.toString(NS));
    187             for (int s=0; s<NS; s++) {
    188                 serializer.startTag(null, TAG_SET);
    189                 serializer.attribute(null, ATTR_NAME, mSetComponents[s]);
    190                 serializer.endTag(null, TAG_SET);
    191             }
    192         }
    193     }
    194 
    195     public boolean sameSet(List<ResolveInfo> query) {
    196         if (mSetPackages == null) {
    197             return query == null;
    198         }
    199         if (query == null) {
    200             return false;
    201         }
    202         final int NQ = query.size();
    203         final int NS = mSetPackages.length;
    204 
    205         int numMatch = 0;
    206         for (int i=0; i<NQ; i++) {
    207             ResolveInfo ri = query.get(i);
    208             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 
    223     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 
    244     public void dump(PrintWriter out, String prefix, Object ident) {
    245         out.print(prefix); out.print(
    246                 Integer.toHexString(System.identityHashCode(ident)));
    247                 out.print(' ');
    248                 out.println(mShortComponent);
    249         out.print(prefix); out.print(" mMatch=0x");
    250                 out.print(Integer.toHexString(mMatch));
    251                 out.print(" mAlways="); out.println(mAlways);
    252         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 }
    261