AutofillServiceInfo.java revision 104b932b7b84e4d4dda51b187615d79e2559ebca
1/* 2 * Copyright (C) 2016 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 */ 16package android.service.autofill; 17 18import android.Manifest; 19import android.annotation.NonNull; 20import android.annotation.Nullable; 21import android.app.AppGlobals; 22import android.content.ComponentName; 23import android.content.pm.PackageManager; 24import android.content.pm.ServiceInfo; 25import android.content.res.Resources; 26import android.content.res.TypedArray; 27import android.content.res.XmlResourceParser; 28import android.os.RemoteException; 29import android.util.AttributeSet; 30import android.util.Log; 31import android.util.Xml; 32import org.xmlpull.v1.XmlPullParser; 33import org.xmlpull.v1.XmlPullParserException; 34 35import com.android.internal.R; 36 37import java.io.IOException; 38 39// TODO(b/33197203 , b/33802548): add CTS tests 40/** 41 * {@link ServiceInfo} and meta-data about an {@link AutofillService}. 42 * 43 * @hide 44 */ 45public final class AutofillServiceInfo { 46 private static final String TAG = "AutofillServiceInfo"; 47 48 private static ServiceInfo getServiceInfoOrThrow(ComponentName comp, int userHandle) 49 throws PackageManager.NameNotFoundException { 50 try { 51 ServiceInfo si = AppGlobals.getPackageManager().getServiceInfo( 52 comp, 53 PackageManager.GET_META_DATA, 54 userHandle); 55 if (si != null) { 56 return si; 57 } 58 } catch (RemoteException e) { 59 } 60 throw new PackageManager.NameNotFoundException(comp.toString()); 61 } 62 63 @NonNull 64 private final ServiceInfo mServiceInfo; 65 66 @Nullable 67 private final String mSettingsActivity; 68 69 public AutofillServiceInfo(PackageManager pm, ComponentName comp, int userHandle) 70 throws PackageManager.NameNotFoundException { 71 this(pm, getServiceInfoOrThrow(comp, userHandle)); 72 } 73 74 public AutofillServiceInfo(PackageManager pm, ServiceInfo si) { 75 mServiceInfo = si; 76 final TypedArray metaDataArray = getMetaDataArray(pm, si); 77 if (metaDataArray != null) { 78 // TODO(b/35956626): inline newSettingsActivity once clients migrate 79 final String newSettingsActivity = 80 metaDataArray.getString(R.styleable.AutofillService_settingsActivity); 81 if (newSettingsActivity != null) { 82 mSettingsActivity = newSettingsActivity; 83 } else { 84 mSettingsActivity = 85 metaDataArray.getString(R.styleable.AutoFillService_settingsActivity); 86 } 87 metaDataArray.recycle(); 88 } else { 89 mSettingsActivity = null; 90 } 91 } 92 93 /** 94 * Gets the meta-data as a TypedArray, or null if not provided, or throws if invalid. 95 */ 96 @Nullable 97 private static TypedArray getMetaDataArray(PackageManager pm, ServiceInfo si) { 98 // Check for permissions. 99 // TODO(b/35956626): remove check for BIND_AUTO_FILL once clients migrate 100 if (!Manifest.permission.BIND_AUTOFILL.equals(si.permission) 101 && !Manifest.permission.BIND_AUTO_FILL.equals(si.permission)) { 102 Log.e(TAG, "Service does not require permission " + Manifest.permission.BIND_AUTOFILL); 103 return null; 104 } 105 106 // TODO(b/35956626): remove once clients migrate 107 final boolean oldStyle = !Manifest.permission.BIND_AUTOFILL.equals(si.permission); 108 109 // Get the AutoFill metadata, if declared. 110 XmlResourceParser parser = si.loadXmlMetaData(pm, AutofillService.SERVICE_META_DATA); 111 if (parser == null) { 112 return null; 113 } 114 115 // Parse service info and get the <autofill-service> tag as an AttributeSet. 116 AttributeSet attrs; 117 try { 118 // Move the XML parser to the first tag. 119 try { 120 int type; 121 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT 122 && type != XmlPullParser.START_TAG) { 123 } 124 } catch (XmlPullParserException | IOException e) { 125 Log.e(TAG, "Error parsing auto fill service meta-data", e); 126 return null; 127 } 128 129 if (!"autofill-service".equals(parser.getName())) { 130 Log.e(TAG, "Meta-data does not start with autofill-service tag"); 131 return null; 132 } 133 attrs = Xml.asAttributeSet(parser); 134 135 // Get resources required to read the AttributeSet. 136 Resources res; 137 try { 138 res = pm.getResourcesForApplication(si.applicationInfo); 139 } catch (PackageManager.NameNotFoundException e) { 140 Log.e(TAG, "Error getting application resources", e); 141 return null; 142 } 143 144 return oldStyle ? res.obtainAttributes(attrs, R.styleable.AutoFillService) 145 : res.obtainAttributes(attrs, R.styleable.AutofillService); 146 } finally { 147 parser.close(); 148 } 149 } 150 151 public ServiceInfo getServiceInfo() { 152 return mServiceInfo; 153 } 154 155 @Nullable 156 public String getSettingsActivity() { 157 return mSettingsActivity; 158 } 159} 160