Home | History | Annotate | Download | only in server
      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 {
     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, 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 
    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 
    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