blob: 6ecd82f50fdbf2f924c91ae3e33a866f308bb7e9 [file] [log] [blame]
Felipe Lemea5d5e2d2019-03-19 16:54:55 -07001/*
2 * Copyright (C) 2019 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
17package android.service.contentcapture;
18
19import android.Manifest;
20import android.annotation.NonNull;
21import android.annotation.Nullable;
22import android.annotation.UserIdInt;
23import android.app.AppGlobals;
24import android.content.ComponentName;
25import android.content.Context;
26import android.content.pm.PackageManager;
27import android.content.pm.PackageManager.NameNotFoundException;
28import android.content.pm.ServiceInfo;
29import android.content.res.Resources;
30import android.content.res.TypedArray;
31import android.content.res.XmlResourceParser;
32import android.os.RemoteException;
33import android.util.AttributeSet;
34import android.util.Log;
35import android.util.Slog;
36import android.util.Xml;
37
38import com.android.internal.R;
39
40import org.xmlpull.v1.XmlPullParser;
41import org.xmlpull.v1.XmlPullParserException;
42
43import java.io.IOException;
44import java.io.PrintWriter;
45
46/**
47 * {@link ServiceInfo} and meta-data about an {@link ContentCaptureService}.
48 *
49 * @hide
50 */
51public final class ContentCaptureServiceInfo {
52
53 private static final String TAG = ContentCaptureServiceInfo.class.getSimpleName();
54 private static final String XML_TAG_SERVICE = "content-capture-service";
55
56 private static ServiceInfo getServiceInfoOrThrow(ComponentName comp, boolean isTemp,
57 @UserIdInt int userId) throws PackageManager.NameNotFoundException {
58 int flags = PackageManager.GET_META_DATA;
59 if (!isTemp) {
60 flags |= PackageManager.MATCH_SYSTEM_ONLY;
61 }
62
63 ServiceInfo si = null;
64 try {
65 si = AppGlobals.getPackageManager().getServiceInfo(comp, flags, userId);
66 } catch (RemoteException e) {
67 }
68 if (si == null) {
69 throw new NameNotFoundException("Could not get serviceInfo for "
70 + (isTemp ? " (temp)" : "(default system)")
71 + " " + comp.flattenToShortString());
72 }
73 return si;
74 }
75
76 @NonNull
77 private final ServiceInfo mServiceInfo;
78
79 @Nullable
80 private final String mSettingsActivity;
81
82 public ContentCaptureServiceInfo(@NonNull Context context, @NonNull ComponentName comp,
83 boolean isTemporaryService, @UserIdInt int userId)
84 throws PackageManager.NameNotFoundException {
85 this(context, getServiceInfoOrThrow(comp, isTemporaryService, userId));
86 }
87
88 private ContentCaptureServiceInfo(@NonNull Context context, @NonNull ServiceInfo si) {
89 // Check for permissions.
90 if (!Manifest.permission.BIND_CONTENT_CAPTURE_SERVICE.equals(si.permission)) {
91 Slog.w(TAG, "ContentCaptureService from '" + si.packageName
92 + "' does not require permission "
93 + Manifest.permission.BIND_CONTENT_CAPTURE_SERVICE);
94 throw new SecurityException("Service does not require permission "
95 + Manifest.permission.BIND_CONTENT_CAPTURE_SERVICE);
96 }
97
98 mServiceInfo = si;
99
100 // Get the metadata, if declared.
101 final XmlResourceParser parser = si.loadXmlMetaData(context.getPackageManager(),
102 ContentCaptureService.SERVICE_META_DATA);
103 if (parser == null) {
104 mSettingsActivity = null;
105 return;
106 }
107
108 String settingsActivity = null;
109
110 try {
111 final Resources resources = context.getPackageManager().getResourcesForApplication(
112 si.applicationInfo);
113
114 int type = 0;
115 while (type != XmlPullParser.END_DOCUMENT && type != XmlPullParser.START_TAG) {
116 type = parser.next();
117 }
118
119 if (XML_TAG_SERVICE.equals(parser.getName())) {
120 final AttributeSet allAttributes = Xml.asAttributeSet(parser);
121 TypedArray afsAttributes = null;
122 try {
123 afsAttributes = resources.obtainAttributes(allAttributes,
124 com.android.internal.R.styleable.ContentCaptureService);
125 settingsActivity = afsAttributes.getString(
126 R.styleable.ContentCaptureService_settingsActivity);
127 } finally {
128 if (afsAttributes != null) {
129 afsAttributes.recycle();
130 }
131 }
132 } else {
133 Log.e(TAG, "Meta-data does not start with content-capture-service tag");
134 }
135 } catch (PackageManager.NameNotFoundException | IOException | XmlPullParserException e) {
136 Log.e(TAG, "Error parsing auto fill service meta-data", e);
137 }
138
139 mSettingsActivity = settingsActivity;
140 }
141
142 public ServiceInfo getServiceInfo() {
143 return mServiceInfo;
144 }
145
146 @Nullable
147 public String getSettingsActivity() {
148 return mSettingsActivity;
149 }
150
151 @Override
152 public String toString() {
153 final StringBuilder builder = new StringBuilder();
154 builder.append(getClass().getSimpleName());
155 builder.append("[").append(mServiceInfo);
156 builder.append(", settings:").append(mSettingsActivity);
157 return builder.toString();
158 }
159
160 /**
161 * Dumps it!
162 */
163 public void dump(@NonNull String prefix, @NonNull PrintWriter pw) {
164 pw.print(prefix);
165 pw.print("Component: ");
166 pw.println(getServiceInfo().getComponentName());
167 pw.print(prefix);
168 pw.print("Settings: ");
169 pw.println(mSettingsActivity);
170 }
171}