Chromium Code Reviews| OLD | NEW |
|---|---|
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 } |
| OLD | NEW |