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 |