| 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.ResolveInfo; | 9 import android.content.pm.ResolveInfo; |
| 9 import android.net.Uri; | 10 import android.content.res.Resources; |
| 10 import android.text.TextUtils; | 11 import android.text.TextUtils; |
| 11 | 12 |
| 12 import org.chromium.base.Log; | 13 import org.chromium.base.Log; |
| 13 import org.chromium.chrome.browser.ChromeActivity; | 14 import org.chromium.chrome.browser.ChromeActivity; |
| 14 import org.chromium.chrome.browser.UrlConstants; | 15 import org.chromium.chrome.browser.UrlConstants; |
| 15 import org.chromium.chrome.browser.payments.PaymentAppFactory.PaymentAppCreatedC
allback; | 16 import org.chromium.chrome.browser.payments.PaymentAppFactory.PaymentAppCreatedC
allback; |
| 16 import org.chromium.chrome.browser.payments.PaymentManifestVerifier.ManifestVeri
fyCallback; | 17 import org.chromium.chrome.browser.payments.PaymentManifestVerifier.ManifestVeri
fyCallback; |
| 17 import org.chromium.components.payments.PaymentManifestDownloader; | 18 import org.chromium.components.payments.PaymentManifestDownloader; |
| 18 import org.chromium.components.payments.PaymentManifestParser; | 19 import org.chromium.components.payments.PaymentManifestParser; |
| 19 import org.chromium.content_public.browser.WebContents; | 20 import org.chromium.content_public.browser.WebContents; |
| 20 | 21 |
| 21 import java.net.URI; | 22 import java.net.URI; |
| 22 import java.net.URISyntaxException; | 23 import java.net.URISyntaxException; |
| 23 import java.util.ArrayList; | 24 import java.util.ArrayList; |
| 24 import java.util.HashMap; | 25 import java.util.HashMap; |
| 25 import java.util.HashSet; | 26 import java.util.HashSet; |
| 26 import java.util.List; | 27 import java.util.List; |
| 27 import java.util.Locale; | 28 import java.util.Locale; |
| 28 import java.util.Map; | 29 import java.util.Map; |
| 29 import java.util.Set; | 30 import java.util.Set; |
| 30 | 31 |
| 32 import javax.annotation.Nullable; |
| 33 |
| 31 /** | 34 /** |
| 32 * 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 |
| 33 * 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 |
| 34 * 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 |
| 35 * 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. |
| 36 */ | 39 */ |
| 37 public class AndroidPaymentAppFinder implements ManifestVerifyCallback { | 40 public class AndroidPaymentAppFinder implements ManifestVerifyCallback { |
| 38 private static final String TAG = "cr_PaymentAppFinder"; | 41 private static final String TAG = "cr_PaymentAppFinder"; |
| 39 | 42 |
| 40 /** The name of the intent for the service to check whether an app is ready
to pay. */ | 43 /** The name of the intent for the service to check whether an app is ready
to pay. */ |
| 41 /* package */ static final String ACTION_IS_READY_TO_PAY = | 44 /* package */ static final String ACTION_IS_READY_TO_PAY = |
| 42 "org.chromium.intent.action.IS_READY_TO_PAY"; | 45 "org.chromium.intent.action.IS_READY_TO_PAY"; |
| 43 | 46 |
| 44 /** The name of the intent for the action of paying using "basic-card" metho
d. */ | |
| 45 /* package */ static final String ACTION_PAY_BASIC_CARD = | |
| 46 "org.chromium.intent.action.PAY_BASIC_CARD"; | |
| 47 | |
| 48 /** | 47 /** |
| 49 * The basic-card payment method name used by merchant and defined by W3C: | 48 * The basic-card payment method name used by merchant and defined by W3C: |
| 50 * https://w3c.github.io/webpayments-methods-card/#method-id | 49 * https://w3c.github.io/webpayments-methods-card/#method-id |
| 51 */ | 50 */ |
| 52 /* package */ static final String BASIC_CARD_PAYMENT_METHOD = "basic-card"; | 51 /* package */ static final String BASIC_CARD_PAYMENT_METHOD = "basic-card"; |
| 53 | 52 |
| 53 /** |
| 54 * Meta data name of an app's supported payment method names. |
| 55 */ |
| 56 static final String META_DATA_NAME_OF_PAYMENT_METHOD_NAMES = |
| 57 "org.chromium.payment_method_names"; |
| 58 |
| 59 /** |
| 60 * Meta data name of an app's supported default payment method name. |
| 61 */ |
| 62 static final String META_DATA_NAME_OF_DEFAULT_PAYMENT_METHOD_NAME = |
| 63 "org.chromum.default_payment_method_name"; |
| 64 |
| 54 /** The maximum number of payment method manifests to download. */ | 65 /** The maximum number of payment method manifests to download. */ |
| 55 private static final int MAX_NUMBER_OF_MANIFESTS = 10; | 66 private static final int MAX_NUMBER_OF_MANIFESTS = 10; |
| 56 | 67 |
| 57 private final WebContents mWebContents; | 68 private final WebContents mWebContents; |
| 58 private final boolean mQueryBasicCard; | 69 private final boolean mQueryBasicCard; |
| 59 private final Set<URI> mPaymentMethods; | 70 private final Set<URI> mPaymentMethods; |
| 60 private final PaymentManifestDownloader mDownloader; | 71 private final PaymentManifestDownloader mDownloader; |
| 61 private final PaymentManifestParser mParser; | 72 private final PaymentManifestParser mParser; |
| 62 private final PackageManagerDelegate mPackageManagerDelegate; | 73 private final PackageManagerDelegate mPackageManagerDelegate; |
| 63 private final PaymentAppCreatedCallback mCallback; | 74 private final PaymentAppCreatedCallback mCallback; |
| (...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 144 mPendingApps = new HashMap<>(); | 155 mPendingApps = new HashMap<>(); |
| 145 mResult = new HashMap<>(); | 156 mResult = new HashMap<>(); |
| 146 ChromeActivity activity = ChromeActivity.fromWebContents(mWebContents); | 157 ChromeActivity activity = ChromeActivity.fromWebContents(mWebContents); |
| 147 mIsIncognito = activity != null && activity.getCurrentTabModel() != null | 158 mIsIncognito = activity != null && activity.getCurrentTabModel() != null |
| 148 && activity.getCurrentTabModel().isIncognito(); | 159 && activity.getCurrentTabModel().isIncognito(); |
| 149 mRequireShowInSettings = requireShowInSettings; | 160 mRequireShowInSettings = requireShowInSettings; |
| 150 mSettingsLookup = new Intent(AndroidPaymentApp.ACTION_PAY); | 161 mSettingsLookup = new Intent(AndroidPaymentApp.ACTION_PAY); |
| 151 } | 162 } |
| 152 | 163 |
| 153 private void findAndroidPaymentApps() { | 164 private void findAndroidPaymentApps() { |
| 165 Intent payIntent = new Intent(AndroidPaymentApp.ACTION_PAY); |
| 166 List<ResolveInfo> apps = |
| 167 mPackageManagerDelegate.getActivitiesThatCanRespondToIntentWithM
etaData(payIntent); |
| 168 if (apps.isEmpty()) { |
| 169 onSearchFinished(); |
| 170 return; |
| 171 } |
| 172 |
| 173 List<String[]> appSupportedMethods = new ArrayList<String[]>(); |
| 174 for (int i = 0; i < apps.size(); i++) { |
| 175 appSupportedMethods.add(getPaymentMethodNames(apps.get(i).activityIn
fo)); |
| 176 } |
| 177 |
| 178 List<String> appSupportedDefaultMethods = new ArrayList<String>(); |
| 179 for (int i = 0; i < apps.size(); i++) { |
| 180 appSupportedDefaultMethods.add(getDefaultPaymentMethodName(apps.get(
i).activityInfo)); |
| 181 } |
| 182 |
| 154 List<PaymentManifestVerifier> verifiers = new ArrayList<>(); | 183 List<PaymentManifestVerifier> verifiers = new ArrayList<>(); |
| 155 if (!mPaymentMethods.isEmpty()) { | 184 for (URI methodName : mPaymentMethods) { |
| 156 Intent payIntent = new Intent(AndroidPaymentApp.ACTION_PAY); | 185 List<ResolveInfo> supportedApps = filterAppsByMethodName( |
| 157 for (URI methodName : mPaymentMethods) { | 186 apps, appSupportedMethods, appSupportedDefaultMethods, metho
dName.toString()); |
| 158 payIntent.setData(Uri.parse(methodName.toString())); | 187 if (supportedApps.isEmpty()) continue; |
| 159 List<ResolveInfo> apps = | |
| 160 mPackageManagerDelegate.getActivitiesThatCanRespondToInt
ent(payIntent); | |
| 161 if (apps.isEmpty()) continue; | |
| 162 | 188 |
| 163 // Start the parser utility process as soon as possible, once we
know that a | 189 // Start the parser utility process as soon as possible, once we kno
w that a |
| 164 // manifest file needs to be parsed. The startup can take up to
2 seconds. | 190 // manifest file needs to be parsed. The startup can take up to 2 se
conds. |
| 165 if (!mParser.isUtilityProcessRunning()) mParser.startUtilityProc
ess(); | 191 if (!mParser.isUtilityProcessRunning()) mParser.startUtilityProcess(
); |
| 166 | 192 |
| 167 verifiers.add(new PaymentManifestVerifier(methodName, apps, mDow
nloader, mParser, | 193 verifiers.add(new PaymentManifestVerifier(methodName, supportedApps,
mDownloader, |
| 168 mPackageManagerDelegate, this /* callback */)); | 194 mParser, mPackageManagerDelegate, this /* callback */)); |
| 169 mPendingApps.put(methodName, new HashSet<>(apps)); | 195 mPendingApps.put(methodName, new HashSet<>(supportedApps)); |
| 170 if (verifiers.size() == MAX_NUMBER_OF_MANIFESTS) { | 196 |
| 171 Log.d(TAG, "Reached maximum number of allowed payment app ma
nifests."); | 197 if (verifiers.size() == MAX_NUMBER_OF_MANIFESTS) { |
| 172 break; | 198 Log.d(TAG, "Reached maximum number of allowed payment app manife
sts."); |
| 173 } | 199 break; |
| 174 } | 200 } |
| 175 } | 201 } |
| 176 | 202 |
| 177 if (mQueryBasicCard) { | 203 if (mQueryBasicCard) { |
| 178 Intent basicCardPayIntent = new Intent(ACTION_PAY_BASIC_CARD); | 204 List<ResolveInfo> supportedApps = filterAppsByMethodName(apps, appSu
pportedMethods, |
| 179 List<ResolveInfo> apps = | 205 appSupportedDefaultMethods, BASIC_CARD_PAYMENT_METHOD); |
| 180 mPackageManagerDelegate.getActivitiesThatCanRespondToIntent(
basicCardPayIntent); | 206 for (int i = 0; i < supportedApps.size(); i++) { |
| 181 for (int i = 0; i < apps.size(); i++) { | |
| 182 // Chrome does not verify app manifests for "basic-card" support
. | 207 // Chrome does not verify app manifests for "basic-card" support
. |
| 183 onValidPaymentApp(BASIC_CARD_PAYMENT_METHOD, apps.get(i)); | 208 onValidPaymentApp(BASIC_CARD_PAYMENT_METHOD, supportedApps.get(i
)); |
| 184 } | 209 } |
| 185 } | 210 } |
| 186 | 211 |
| 187 if (verifiers.isEmpty()) { | 212 if (verifiers.isEmpty()) { |
| 188 onSearchFinished(); | 213 onSearchFinished(); |
| 189 return; | 214 return; |
| 190 } | 215 } |
| 191 | 216 |
| 192 for (int i = 0; i < verifiers.size(); i++) { | 217 for (int i = 0; i < verifiers.size(); i++) { |
| 193 verifiers.get(i).verify(); | 218 verifiers.get(i).verify(); |
| 194 } | 219 } |
| 195 } | 220 } |
| 196 | 221 |
| 222 @Nullable |
| 223 private String[] getPaymentMethodNames(ActivityInfo activityInfo) { |
| 224 if (activityInfo.metaData == null) return null; |
| 225 |
| 226 int resId = activityInfo.metaData.getInt(META_DATA_NAME_OF_PAYMENT_METHO
D_NAMES); |
| 227 if (resId == 0) return null; |
| 228 |
| 229 Resources resources = |
| 230 mPackageManagerDelegate.getResourcesForApplication(activityInfo.
applicationInfo); |
| 231 if (resources == null) return null; |
| 232 return resources.getStringArray(resId); |
| 233 } |
| 234 |
| 235 @Nullable |
| 236 private String getDefaultPaymentMethodName(ActivityInfo activityInfo) { |
| 237 if (activityInfo.metaData == null) return null; |
| 238 |
| 239 return activityInfo.metaData.getString(META_DATA_NAME_OF_DEFAULT_PAYMENT
_METHOD_NAME); |
| 240 } |
| 241 |
| 242 private static List<ResolveInfo> filterAppsByMethodName(List<ResolveInfo> ap
ps, |
| 243 List<String[]> appsMethods, List<String> appsDefaultMethods, String
targetMethodName) { |
| 244 assert apps.size() == appsMethods.size(); |
| 245 assert apps.size() == appsDefaultMethods.size(); |
| 246 |
| 247 // Note that apps, appsMethods and appsDefaultMethods must have the same
size. And the |
| 248 // information at the same index must correspond to the same app. |
| 249 List<ResolveInfo> supportedApps = new ArrayList<ResolveInfo>(); |
| 250 for (int i = 0; i < apps.size(); i++) { |
| 251 if (targetMethodName.equals(appsDefaultMethods.get(i))) { |
| 252 supportedApps.add(apps.get(i)); |
| 253 continue; |
| 254 } |
| 255 |
| 256 String[] methods = appsMethods.get(i); |
| 257 if (methods == null) continue; |
| 258 for (int j = 0; j < methods.length; j++) { |
| 259 if (targetMethodName.equals(methods[j])) { |
| 260 supportedApps.add(apps.get(i)); |
| 261 break; |
| 262 } |
| 263 } |
| 264 } |
| 265 return supportedApps; |
| 266 } |
| 267 |
| 197 @Override | 268 @Override |
| 198 public void onValidPaymentApp(URI methodName, ResolveInfo resolveInfo) { | 269 public void onValidPaymentApp(URI methodName, ResolveInfo resolveInfo) { |
| 199 onValidPaymentApp(methodName.toString(), resolveInfo); | 270 onValidPaymentApp(methodName.toString(), resolveInfo); |
| 200 removePendingApp(methodName, resolveInfo); | 271 removePendingApp(methodName, resolveInfo); |
| 201 } | 272 } |
| 202 | 273 |
| 203 /** Same as above, but also works for non-URI method names, e.g., "basic-car
d". */ | 274 /** Same as above, but also works for non-URI method names, e.g., "basic-car
d". */ |
| 204 private void onValidPaymentApp(String methodName, ResolveInfo resolveInfo) { | 275 private void onValidPaymentApp(String methodName, ResolveInfo resolveInfo) { |
| 205 String packageName = resolveInfo.activityInfo.packageName; | 276 String packageName = resolveInfo.activityInfo.packageName; |
| 206 AndroidPaymentApp app = mResult.get(packageName); | 277 AndroidPaymentApp app = mResult.get(packageName); |
| (...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 263 } | 334 } |
| 264 } | 335 } |
| 265 | 336 |
| 266 for (Map.Entry<String, AndroidPaymentApp> entry : mResult.entrySet()) { | 337 for (Map.Entry<String, AndroidPaymentApp> entry : mResult.entrySet()) { |
| 267 mCallback.onPaymentAppCreated(entry.getValue()); | 338 mCallback.onPaymentAppCreated(entry.getValue()); |
| 268 } | 339 } |
| 269 | 340 |
| 270 mCallback.onAllPaymentAppsCreated(); | 341 mCallback.onAllPaymentAppsCreated(); |
| 271 } | 342 } |
| 272 } | 343 } |
| OLD | NEW |