blob: 31e51bb945d65d6920e428fb9df7c998e1532511 [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) {
Sean Pontd00aefb2020-01-07 12:05:09 -080069 return null;
70 }
71
72 ServiceInfo serviceInfo = getWalletServiceInfo(context, defaultPaymentApp.getPackageName());
73 if (serviceInfo == null) {
Sean Pontd00aefb2020-01-07 12:05:09 -080074 return null;
75 }
76
77 if (!Manifest.permission.BIND_QUICK_ACCESS_WALLET_SERVICE.equals(serviceInfo.permission)) {
Sean Pont72fc25f2020-02-11 19:02:44 -080078 Log.w(TAG, String.format("%s.%s does not require permission %s",
79 serviceInfo.packageName, serviceInfo.name,
80 Manifest.permission.BIND_QUICK_ACCESS_WALLET_SERVICE));
Sean Pontd00aefb2020-01-07 12:05:09 -080081 return null;
82 }
83
84 ServiceMetadata metadata = parseServiceMetadata(context, serviceInfo);
85 return new QuickAccessWalletServiceInfo(serviceInfo, metadata);
86 }
87
88 private static ComponentName getDefaultPaymentApp(Context context) {
89 ContentResolver cr = context.getContentResolver();
90 String comp = Settings.Secure.getString(cr, Settings.Secure.NFC_PAYMENT_DEFAULT_COMPONENT);
91 return comp == null ? null : ComponentName.unflattenFromString(comp);
92 }
93
94 private static ServiceInfo getWalletServiceInfo(Context context, String packageName) {
95 Intent intent = new Intent(QuickAccessWalletService.SERVICE_INTERFACE);
96 intent.setPackage(packageName);
97 List<ResolveInfo> resolveInfos =
98 context.getPackageManager().queryIntentServices(intent,
99 PackageManager.MATCH_DEFAULT_ONLY);
100 return resolveInfos.isEmpty() ? null : resolveInfos.get(0).serviceInfo;
101 }
102
103 private static class ServiceMetadata {
104 @Nullable
105 private final String mSettingsActivity;
106 @Nullable
107 private final String mWalletActivity;
108
109 private ServiceMetadata(String settingsActivity, String walletActivity) {
110 this.mSettingsActivity = settingsActivity;
111 this.mWalletActivity = walletActivity;
112 }
113 }
114
115 private static ServiceMetadata parseServiceMetadata(Context context, ServiceInfo serviceInfo) {
116 PackageManager pm = context.getPackageManager();
117 final XmlResourceParser parser =
118 serviceInfo.loadXmlMetaData(pm, QuickAccessWalletService.SERVICE_META_DATA);
119
120 if (parser == null) {
121 return new ServiceMetadata(null, null);
122 }
123
124 try {
125 Resources resources = pm.getResourcesForApplication(serviceInfo.applicationInfo);
126 int type = 0;
127 while (type != XmlPullParser.END_DOCUMENT && type != XmlPullParser.START_TAG) {
128 type = parser.next();
129 }
130
131 if (TAG_WALLET_SERVICE.equals(parser.getName())) {
132 final AttributeSet allAttributes = Xml.asAttributeSet(parser);
133 TypedArray afsAttributes = null;
134 try {
135 afsAttributes = resources.obtainAttributes(allAttributes,
136 R.styleable.QuickAccessWalletService);
137 String settingsActivity = afsAttributes.getString(
138 R.styleable.QuickAccessWalletService_settingsActivity);
139 String walletActivity = afsAttributes.getString(
140 R.styleable.QuickAccessWalletService_targetActivity);
141 return new ServiceMetadata(settingsActivity, walletActivity);
142 } finally {
143 if (afsAttributes != null) {
144 afsAttributes.recycle();
145 }
146 }
147 } else {
148 Log.e(TAG, "Meta-data does not start with quickaccesswallet-service tag");
149 }
150
151 } catch (PackageManager.NameNotFoundException
152 | IOException
153 | XmlPullParserException e) {
154 Log.e(TAG, "Error parsing quickaccesswallet service meta-data", e);
155 }
156 return new ServiceMetadata(null, null);
157 }
158
159 /**
160 * @return the component name of the {@link QuickAccessWalletService}
161 */
162 @NonNull
163 ComponentName getComponentName() {
164 return mServiceInfo.getComponentName();
165 }
166
167 /**
168 * @return the fully qualified name of the activity that hosts the full wallet. If available,
169 * this intent should be started with the action
170 * {@link QuickAccessWalletService#ACTION_VIEW_WALLET}
171 */
172 @Nullable
173 String getWalletActivity() {
174 return mServiceMetadata.mWalletActivity;
175 }
176
177 /**
178 * @return the fully qualified name of the activity that allows the user to change quick access
179 * wallet settings. If available, this intent should be started with the action {@link
180 * QuickAccessWalletService#ACTION_VIEW_WALLET_SETTINGS}
181 */
182 @Nullable
183 String getSettingsActivity() {
184 return mServiceMetadata.mSettingsActivity;
185 }
186}