blob: 8793f28bc7085eb29fba268b32f1fc909fbb0fe0 [file] [log] [blame]
Sean Pontd00aefb2020-01-07 12:05:09 -08001/*
2 * Copyright (C) 2020 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.quickaccesswallet;
18
19import android.Manifest;
20import android.annotation.NonNull;
21import android.annotation.Nullable;
22import android.content.ComponentName;
23import android.content.ContentResolver;
24import android.content.Context;
25import android.content.Intent;
26import android.content.pm.PackageManager;
27import android.content.pm.ResolveInfo;
28import android.content.pm.ServiceInfo;
29import android.content.res.Resources;
30import android.content.res.TypedArray;
31import android.content.res.XmlResourceParser;
32import android.provider.Settings;
33import android.util.AttributeSet;
34import android.util.Log;
35import android.util.Xml;
36
37import com.android.internal.R;
38
39import org.xmlpull.v1.XmlPullParser;
40import org.xmlpull.v1.XmlPullParserException;
41
42import java.io.IOException;
43import java.util.List;
44
45/**
46 * {@link ServiceInfo} and meta-data about a {@link QuickAccessWalletService}.
47 *
48 * @hide
49 */
50class QuickAccessWalletServiceInfo {
51
52 private static final String TAG = "QAWalletSInfo";
53 private static final String TAG_WALLET_SERVICE = "quickaccesswallet-service";
54
55 private final ServiceInfo mServiceInfo;
56 private final ServiceMetadata mServiceMetadata;
57
58 private QuickAccessWalletServiceInfo(
59 @NonNull ServiceInfo serviceInfo,
60 @NonNull ServiceMetadata metadata) {
61 mServiceInfo = serviceInfo;
62 mServiceMetadata = metadata;
63 }
64
65 @Nullable
66 static QuickAccessWalletServiceInfo tryCreate(@NonNull Context context) {
67 ComponentName defaultPaymentApp = getDefaultPaymentApp(context);
68 if (defaultPaymentApp == null) {
69 Log.d(TAG, "create: default payment app not set");
70 return null;
71 }
72
73 ServiceInfo serviceInfo = getWalletServiceInfo(context, defaultPaymentApp.getPackageName());
74 if (serviceInfo == null) {
75 Log.d(TAG, "create: unable to resolve service intent");
76 return null;
77 }
78
79 if (!Manifest.permission.BIND_QUICK_ACCESS_WALLET_SERVICE.equals(serviceInfo.permission)) {
80 Log.w(TAG, String.format("QuickAccessWalletService from %s does not have permission %s",
81 serviceInfo.packageName, Manifest.permission.BIND_QUICK_ACCESS_WALLET_SERVICE));
82 return null;
83 }
84
85 ServiceMetadata metadata = parseServiceMetadata(context, serviceInfo);
86 return new QuickAccessWalletServiceInfo(serviceInfo, metadata);
87 }
88
89 private static ComponentName getDefaultPaymentApp(Context context) {
90 ContentResolver cr = context.getContentResolver();
91 String comp = Settings.Secure.getString(cr, Settings.Secure.NFC_PAYMENT_DEFAULT_COMPONENT);
92 return comp == null ? null : ComponentName.unflattenFromString(comp);
93 }
94
95 private static ServiceInfo getWalletServiceInfo(Context context, String packageName) {
96 Intent intent = new Intent(QuickAccessWalletService.SERVICE_INTERFACE);
97 intent.setPackage(packageName);
98 List<ResolveInfo> resolveInfos =
99 context.getPackageManager().queryIntentServices(intent,
100 PackageManager.MATCH_DEFAULT_ONLY);
101 return resolveInfos.isEmpty() ? null : resolveInfos.get(0).serviceInfo;
102 }
103
104 private static class ServiceMetadata {
105 @Nullable
106 private final String mSettingsActivity;
107 @Nullable
108 private final String mWalletActivity;
109
110 private ServiceMetadata(String settingsActivity, String walletActivity) {
111 this.mSettingsActivity = settingsActivity;
112 this.mWalletActivity = walletActivity;
113 }
114 }
115
116 private static ServiceMetadata parseServiceMetadata(Context context, ServiceInfo serviceInfo) {
117 PackageManager pm = context.getPackageManager();
118 final XmlResourceParser parser =
119 serviceInfo.loadXmlMetaData(pm, QuickAccessWalletService.SERVICE_META_DATA);
120
121 if (parser == null) {
122 return new ServiceMetadata(null, null);
123 }
124
125 try {
126 Resources resources = pm.getResourcesForApplication(serviceInfo.applicationInfo);
127 int type = 0;
128 while (type != XmlPullParser.END_DOCUMENT && type != XmlPullParser.START_TAG) {
129 type = parser.next();
130 }
131
132 if (TAG_WALLET_SERVICE.equals(parser.getName())) {
133 final AttributeSet allAttributes = Xml.asAttributeSet(parser);
134 TypedArray afsAttributes = null;
135 try {
136 afsAttributes = resources.obtainAttributes(allAttributes,
137 R.styleable.QuickAccessWalletService);
138 String settingsActivity = afsAttributes.getString(
139 R.styleable.QuickAccessWalletService_settingsActivity);
140 String walletActivity = afsAttributes.getString(
141 R.styleable.QuickAccessWalletService_targetActivity);
142 return new ServiceMetadata(settingsActivity, walletActivity);
143 } finally {
144 if (afsAttributes != null) {
145 afsAttributes.recycle();
146 }
147 }
148 } else {
149 Log.e(TAG, "Meta-data does not start with quickaccesswallet-service tag");
150 }
151
152 } catch (PackageManager.NameNotFoundException
153 | IOException
154 | XmlPullParserException e) {
155 Log.e(TAG, "Error parsing quickaccesswallet service meta-data", e);
156 }
157 return new ServiceMetadata(null, null);
158 }
159
160 /**
161 * @return the component name of the {@link QuickAccessWalletService}
162 */
163 @NonNull
164 ComponentName getComponentName() {
165 return mServiceInfo.getComponentName();
166 }
167
168 /**
169 * @return the fully qualified name of the activity that hosts the full wallet. If available,
170 * this intent should be started with the action
171 * {@link QuickAccessWalletService#ACTION_VIEW_WALLET}
172 */
173 @Nullable
174 String getWalletActivity() {
175 return mServiceMetadata.mWalletActivity;
176 }
177
178 /**
179 * @return the fully qualified name of the activity that allows the user to change quick access
180 * wallet settings. If available, this intent should be started with the action {@link
181 * QuickAccessWalletService#ACTION_VIEW_WALLET_SETTINGS}
182 */
183 @Nullable
184 String getSettingsActivity() {
185 return mServiceMetadata.mSettingsActivity;
186 }
187}