Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(19)

Side by Side Diff: chrome/android/java/src/org/chromium/chrome/browser/payments/AndroidPaymentAppFinder.java

Issue 2838403002: Enable supporting arbitrary short string payment method names. (Closed)
Patch Set: Limit to basic-card for now Created 3 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2017 The Chromium Authors. All rights reserved. 1 // Copyright 2017 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 package org.chromium.chrome.browser.payments; 5 package org.chromium.chrome.browser.payments;
6 6
7 import android.content.Intent; 7 import android.content.Intent;
8 import android.content.pm.ActivityInfo; 8 import android.content.pm.ActivityInfo;
9 import android.content.pm.ResolveInfo; 9 import android.content.pm.ResolveInfo;
10 import android.content.res.Resources; 10 import android.content.res.Resources;
(...skipping 16 matching lines...) Expand all
27 import java.util.List; 27 import java.util.List;
28 import java.util.Locale; 28 import java.util.Locale;
29 import java.util.Map; 29 import java.util.Map;
30 import java.util.Set; 30 import java.util.Set;
31 31
32 import javax.annotation.Nullable; 32 import javax.annotation.Nullable;
33 33
34 /** 34 /**
35 * Finds installed native Android payment apps and verifies their signatures acc ording to the 35 * Finds installed native Android payment apps and verifies their signatures acc ording to the
36 * payment method manifests. The manifests are located based on the payment meth od name, which 36 * payment method manifests. The manifests are located based on the payment meth od name, which
37 * is a URI that starts with "https://". The "basic-card" payment method is an e xception: it's a 37 * is a URI that starts with "https://". The "basic-card" payment method is an e xception: it's a
gogerald1 2017/04/26 20:38:10 not only basic-card?
please use gerrit instead 2017/04/26 21:52:07 Done.
38 * common payment method that does not have a manifest and can be used by any pa yment app. 38 * common payment method that does not have a manifest and can be used by any pa yment app.
39 */ 39 */
40 public class AndroidPaymentAppFinder implements ManifestVerifyCallback { 40 public class AndroidPaymentAppFinder implements ManifestVerifyCallback {
41 private static final String TAG = "cr_PaymentAppFinder"; 41 private static final String TAG = "cr_PaymentAppFinder";
42 42
43 /** The maximum number of payment method manifests to download. */
44 private static final int MAX_NUMBER_OF_MANIFESTS = 10;
45
43 /** The name of the intent for the service to check whether an app is ready to pay. */ 46 /** The name of the intent for the service to check whether an app is ready to pay. */
44 /* package */ static final String ACTION_IS_READY_TO_PAY = 47 /* package */ static final String ACTION_IS_READY_TO_PAY =
45 "org.chromium.intent.action.IS_READY_TO_PAY"; 48 "org.chromium.intent.action.IS_READY_TO_PAY";
46 49
47 /** 50 /**
48 * The basic-card payment method name used by merchant and defined by W3C: 51 * The basic-card payment method name used by merchant and defined by W3C:
49 * https://w3c.github.io/webpayments-methods-card/#method-id 52 * https://w3c.github.io/webpayments-methods-card/#method-id
50 */ 53 */
51 /* package */ static final String BASIC_CARD_PAYMENT_METHOD = "basic-card"; 54 /* package */ static final String BASIC_CARD_PAYMENT_METHOD = "basic-card";
52 55
53 /** 56 /**
54 * Meta data name of an app's supported payment method names. 57 * Meta data name of an app's supported payment method names.
55 */ 58 */
56 static final String META_DATA_NAME_OF_PAYMENT_METHOD_NAMES = 59 /* package */ static final String META_DATA_NAME_OF_PAYMENT_METHOD_NAMES =
57 "org.chromium.payment_method_names"; 60 "org.chromium.payment_method_names";
58 61
59 /** 62 /**
60 * Meta data name of an app's supported default payment method name. 63 * Meta data name of an app's supported default payment method name.
61 */ 64 */
62 static final String META_DATA_NAME_OF_DEFAULT_PAYMENT_METHOD_NAME = 65 /* package */ static final String META_DATA_NAME_OF_DEFAULT_PAYMENT_METHOD_N AME =
63 "org.chromium.default_payment_method_name"; 66 "org.chromium.default_payment_method_name";
64 67
65 /** The maximum number of payment method manifests to download. */
66 private static final int MAX_NUMBER_OF_MANIFESTS = 10;
67
68 private final WebContents mWebContents; 68 private final WebContents mWebContents;
69 private final boolean mQueryBasicCard; 69 private final Set<String> mShortStringPaymentMethods;
70 private final Set<URI> mPaymentMethods; 70 private final Set<URI> mUriPaymentMethods;
71 private final PaymentManifestDownloader mDownloader; 71 private final PaymentManifestDownloader mDownloader;
72 private final PaymentManifestParser mParser; 72 private final PaymentManifestParser mParser;
73 private final PackageManagerDelegate mPackageManagerDelegate; 73 private final PackageManagerDelegate mPackageManagerDelegate;
74 private final PaymentAppCreatedCallback mCallback; 74 private final PaymentAppCreatedCallback mCallback;
75 private final boolean mIsIncognito; 75 private final boolean mIsIncognito;
76 76
77 /** 77 /**
78 * A map of payment method names to the list of (yet) unverified Android app s that claim to 78 * A map of payment method names to the list of (yet) unverified Android app s that claim to
79 * handle these methods. Example payment method names in this data structure : 79 * handle these methods. Example payment method names in this data structure :
80 * "https://bobpay.com", "https://android.com/pay". Basic card is excluded. 80 * "https://bobpay.com", "https://android.com/pay". Basic card is excluded.
gogerald1 2017/04/26 20:38:10 not only basic card is excluded anymore?
please use gerrit instead 2017/04/26 21:52:07 Done.
81 */ 81 */
82 private final Map<URI, Set<ResolveInfo>> mPendingApps; 82 private final Map<URI, Set<ResolveInfo>> mPendingApps;
83 83
84 /** A map of Android package name to the payment app. */ 84 /** A map of Android package name to the payment app. */
85 private final Map<String, AndroidPaymentApp> mResult; 85 private final Map<String, AndroidPaymentApp> mResult;
86 86
87 /** 87 /**
88 * Finds native Android payment apps. 88 * Finds native Android payment apps.
89 * 89 *
90 * @param webContents The web contents that invoked the web payme nts API. 90 * @param webContents The web contents that invoked the web payme nts API.
(...skipping 11 matching lines...) Expand all
102 PackageManagerDelegate packageManagerDelegate, PaymentAppCreatedCall back callback) { 102 PackageManagerDelegate packageManagerDelegate, PaymentAppCreatedCall back callback) {
103 new AndroidPaymentAppFinder( 103 new AndroidPaymentAppFinder(
104 webContents, methods, downloader, parser, packageManagerDelegate , callback) 104 webContents, methods, downloader, parser, packageManagerDelegate , callback)
105 .findAndroidPaymentApps(); 105 .findAndroidPaymentApps();
106 } 106 }
107 107
108 private AndroidPaymentAppFinder(WebContents webContents, Set<String> methods , 108 private AndroidPaymentAppFinder(WebContents webContents, Set<String> methods ,
109 PaymentManifestDownloader downloader, PaymentManifestParser parser, 109 PaymentManifestDownloader downloader, PaymentManifestParser parser,
110 PackageManagerDelegate packageManagerDelegate, PaymentAppCreatedCall back callback) { 110 PackageManagerDelegate packageManagerDelegate, PaymentAppCreatedCall back callback) {
111 mWebContents = webContents; 111 mWebContents = webContents;
112 mQueryBasicCard = methods.contains(BASIC_CARD_PAYMENT_METHOD); 112
113 mPaymentMethods = new HashSet<>(); 113 // For short string payment method names, only names published by W3C sh ould be supported.
gogerald1 2017/04/26 20:38:10 'short string payment method' looks not a precise
please use gerrit instead 2017/04/26 21:52:07 Done.
114 Set<String> supportedShortStringPaymentMethods = new HashSet<>();
115 supportedShortStringPaymentMethods.add(BASIC_CARD_PAYMENT_METHOD);
116
117 mShortStringPaymentMethods = new HashSet<>();
118 mUriPaymentMethods = new HashSet<>();
114 for (String method : methods) { 119 for (String method : methods) {
115 assert !TextUtils.isEmpty(method); 120 assert !TextUtils.isEmpty(method);
121 if (supportedShortStringPaymentMethods.contains(method)) {
122 mShortStringPaymentMethods.add(method);
123 } else if (method.startsWith(UrlConstants.HTTPS_URL_PREFIX)) {
124 URI uri;
125 try {
126 // Don't use java.net.URL, because it performs a synchronous DNS lookup in
127 // the constructor.
128 uri = new URI(method);
129 } catch (URISyntaxException e) {
130 continue;
131 }
116 132
117 if (!method.startsWith(UrlConstants.HTTPS_URL_PREFIX)) continue; 133 if (uri.isAbsolute()) {
118 134 assert UrlConstants.HTTPS_SCHEME.equals(uri.getScheme());
119 URI uri; 135 mUriPaymentMethods.add(uri);
120 try { 136 }
121 // Don't use java.net.URL, because it performs a synchronous DNS lookup in
122 // the constructor.
123 uri = new URI(method);
124 } catch (URISyntaxException e) {
125 continue;
126 }
127
128 if (uri.isAbsolute()) {
129 assert UrlConstants.HTTPS_SCHEME.equals(uri.getScheme());
130 mPaymentMethods.add(uri);
131 } 137 }
132 } 138 }
133 139
134 mDownloader = downloader; 140 mDownloader = downloader;
135 mParser = parser; 141 mParser = parser;
136 mPackageManagerDelegate = packageManagerDelegate; 142 mPackageManagerDelegate = packageManagerDelegate;
137 mCallback = callback; 143 mCallback = callback;
138 mPendingApps = new HashMap<>(); 144 mPendingApps = new HashMap<>();
139 mResult = new HashMap<>(); 145 mResult = new HashMap<>();
140 ChromeActivity activity = ChromeActivity.fromWebContents(mWebContents); 146 ChromeActivity activity = ChromeActivity.fromWebContents(mWebContents);
141 mIsIncognito = activity != null && activity.getCurrentTabModel() != null 147 mIsIncognito = activity != null && activity.getCurrentTabModel() != null
142 && activity.getCurrentTabModel().isIncognito(); 148 && activity.getCurrentTabModel().isIncognito();
143 } 149 }
144 150
145 private void findAndroidPaymentApps() { 151 private void findAndroidPaymentApps() {
146 Intent payIntent = new Intent(AndroidPaymentApp.ACTION_PAY); 152 Intent payIntent = new Intent(AndroidPaymentApp.ACTION_PAY);
147 List<ResolveInfo> apps = 153 List<ResolveInfo> apps =
148 mPackageManagerDelegate.getActivitiesThatCanRespondToIntentWithM etaData(payIntent); 154 mPackageManagerDelegate.getActivitiesThatCanRespondToIntentWithM etaData(payIntent);
149 if (apps.isEmpty()) { 155 if (apps.isEmpty()) {
150 onSearchFinished(); 156 onSearchFinished();
151 return; 157 return;
152 } 158 }
153 159
154 List<String[]> appSupportedMethods = new ArrayList<String[]>(); 160 List<Set<String>> appSupportedMethods = new ArrayList<>();
155 for (int i = 0; i < apps.size(); i++) { 161 for (int i = 0; i < apps.size(); i++) {
156 appSupportedMethods.add(getPaymentMethodNames(apps.get(i).activityIn fo)); 162 appSupportedMethods.add(getPaymentMethodNames(apps.get(i).activityIn fo));
157 } 163 }
158 164
159 List<String> appSupportedDefaultMethods = new ArrayList<String>();
160 for (int i = 0; i < apps.size(); i++) {
161 appSupportedDefaultMethods.add(getDefaultPaymentMethodName(apps.get( i).activityInfo));
162 }
163
164 List<PaymentManifestVerifier> verifiers = new ArrayList<>(); 165 List<PaymentManifestVerifier> verifiers = new ArrayList<>();
165 for (URI methodName : mPaymentMethods) { 166 for (URI uriMethodName : mUriPaymentMethods) {
166 List<ResolveInfo> supportedApps = filterAppsByMethodName( 167 List<ResolveInfo> supportedApps =
167 apps, appSupportedMethods, appSupportedDefaultMethods, metho dName.toString()); 168 filterAppsByMethodName(apps, appSupportedMethods, uriMethodN ame.toString());
168 if (supportedApps.isEmpty()) continue; 169 if (supportedApps.isEmpty()) continue;
169 170
170 // Start the parser utility process as soon as possible, once we kno w that a 171 // Start the parser utility process as soon as possible, once we kno w that a
171 // manifest file needs to be parsed. The startup can take up to 2 se conds. 172 // manifest file needs to be parsed. The startup can take up to 2 se conds.
172 if (!mParser.isUtilityProcessRunning()) mParser.startUtilityProcess( ); 173 if (!mParser.isUtilityProcessRunning()) mParser.startUtilityProcess( );
173 174
174 verifiers.add(new PaymentManifestVerifier(methodName, supportedApps, mDownloader, 175 verifiers.add(new PaymentManifestVerifier(uriMethodName, supportedAp ps, mDownloader,
175 mParser, mPackageManagerDelegate, this /* callback */)); 176 mParser, mPackageManagerDelegate, this /* callback */));
176 mPendingApps.put(methodName, new HashSet<>(supportedApps)); 177 mPendingApps.put(uriMethodName, new HashSet<>(supportedApps));
177 178
178 if (verifiers.size() == MAX_NUMBER_OF_MANIFESTS) { 179 if (verifiers.size() == MAX_NUMBER_OF_MANIFESTS) {
179 Log.d(TAG, "Reached maximum number of allowed payment app manife sts."); 180 Log.d(TAG, "Reached maximum number of allowed payment app manife sts.");
180 break; 181 break;
181 } 182 }
182 } 183 }
183 184
184 if (mQueryBasicCard) { 185 for (String shortMethodName : mShortStringPaymentMethods) {
185 List<ResolveInfo> supportedApps = filterAppsByMethodName(apps, appSu pportedMethods, 186 List<ResolveInfo> supportedApps =
186 appSupportedDefaultMethods, BASIC_CARD_PAYMENT_METHOD); 187 filterAppsByMethodName(apps, appSupportedMethods, shortMetho dName);
187 for (int i = 0; i < supportedApps.size(); i++) { 188 for (int i = 0; i < supportedApps.size(); i++) {
188 // Chrome does not verify app manifests for "basic-card" support . 189 // Chrome does not verify app manifests for short string payment method support.
189 onValidPaymentApp(BASIC_CARD_PAYMENT_METHOD, supportedApps.get(i )); 190 onValidPaymentApp(shortMethodName, supportedApps.get(i));
190 } 191 }
191 } 192 }
192 193
193 if (verifiers.isEmpty()) { 194 if (verifiers.isEmpty()) {
194 onSearchFinished(); 195 onSearchFinished();
195 return; 196 return;
196 } 197 }
197 198
198 for (int i = 0; i < verifiers.size(); i++) { 199 for (int i = 0; i < verifiers.size(); i++) {
199 verifiers.get(i).verify(); 200 verifiers.get(i).verify();
200 } 201 }
201 } 202 }
202 203
203 @Nullable 204 @Nullable
204 private String[] getPaymentMethodNames(ActivityInfo activityInfo) { 205 private Set<String> getPaymentMethodNames(ActivityInfo activityInfo) {
205 if (activityInfo.metaData == null) return null; 206 Set<String> result = new HashSet<>();
207 if (activityInfo.metaData == null) return result;
208
209 String defaultMethodName =
210 activityInfo.metaData.getString(META_DATA_NAME_OF_DEFAULT_PAYMEN T_METHOD_NAME);
211 if (!TextUtils.isEmpty(defaultMethodName)) result.add(defaultMethodName) ;
206 212
207 int resId = activityInfo.metaData.getInt(META_DATA_NAME_OF_PAYMENT_METHO D_NAMES); 213 int resId = activityInfo.metaData.getInt(META_DATA_NAME_OF_PAYMENT_METHO D_NAMES);
208 if (resId == 0) return null; 214 if (resId == 0) return result;
209 215
210 Resources resources = 216 Resources resources =
211 mPackageManagerDelegate.getResourcesForApplication(activityInfo. applicationInfo); 217 mPackageManagerDelegate.getResourcesForApplication(activityInfo. applicationInfo);
212 if (resources == null) return null; 218 if (resources == null) return result;
213 return resources.getStringArray(resId); 219
220 String[] methodNames = resources.getStringArray(resId);
221 if (methodNames == null) return result;
222
223 for (int i = 0; i < methodNames.length; i++) {
224 result.add(methodNames[i]);
225 }
226
227 return result;
214 } 228 }
215 229
216 @Nullable 230 private static List<ResolveInfo> filterAppsByMethodName(
217 private String getDefaultPaymentMethodName(ActivityInfo activityInfo) { 231 List<ResolveInfo> apps, List<Set<String>> methodNames, String target MethodName) {
218 if (activityInfo.metaData == null) return null; 232 assert apps.size() == methodNames.size();
219 233
220 return activityInfo.metaData.getString(META_DATA_NAME_OF_DEFAULT_PAYMENT _METHOD_NAME); 234 // Note that apps and methodNames must have the same size. The informat ion at the same
221 } 235 // index must correspond to the same app.
222 236 List<ResolveInfo> supportedApps = new ArrayList<>();
223 private static List<ResolveInfo> filterAppsByMethodName(List<ResolveInfo> ap ps,
224 List<String[]> appsMethods, List<String> appsDefaultMethods, String targetMethodName) {
225 assert apps.size() == appsMethods.size();
226 assert apps.size() == appsDefaultMethods.size();
227
228 // Note that apps, appsMethods and appsDefaultMethods must have the same size. And the
229 // information at the same index must correspond to the same app.
230 List<ResolveInfo> supportedApps = new ArrayList<ResolveInfo>();
231 for (int i = 0; i < apps.size(); i++) { 237 for (int i = 0; i < apps.size(); i++) {
232 if (targetMethodName.equals(appsDefaultMethods.get(i))) { 238 if (methodNames.get(i).contains(targetMethodName)) {
233 supportedApps.add(apps.get(i)); 239 supportedApps.add(apps.get(i));
234 continue; 240 continue;
235 } 241 }
236
237 String[] methods = appsMethods.get(i);
238 if (methods == null) continue;
239 for (int j = 0; j < methods.length; j++) {
240 if (targetMethodName.equals(methods[j])) {
241 supportedApps.add(apps.get(i));
242 break;
243 }
244 }
245 } 242 }
246 return supportedApps; 243 return supportedApps;
247 } 244 }
248 245
249 @Override 246 @Override
250 public void onValidPaymentApp(URI methodName, ResolveInfo resolveInfo) { 247 public void onValidPaymentApp(URI methodName, ResolveInfo resolveInfo) {
251 onValidPaymentApp(methodName.toString(), resolveInfo); 248 onValidPaymentApp(methodName.toString(), resolveInfo);
252 removePendingApp(methodName, resolveInfo); 249 removePendingApp(methodName, resolveInfo);
253 } 250 }
254 251
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after
311 } 308 }
312 } 309 }
313 310
314 for (Map.Entry<String, AndroidPaymentApp> entry : mResult.entrySet()) { 311 for (Map.Entry<String, AndroidPaymentApp> entry : mResult.entrySet()) {
315 mCallback.onPaymentAppCreated(entry.getValue()); 312 mCallback.onPaymentAppCreated(entry.getValue());
316 } 313 }
317 314
318 mCallback.onAllPaymentAppsCreated(); 315 mCallback.onAllPaymentAppsCreated();
319 } 316 }
320 } 317 }
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698