OLD | NEW |
(Empty) | |
| 1 // Copyright 2016 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. |
| 4 |
| 5 package org.chromium.content.browser.installedapp; |
| 6 |
| 7 import android.content.Context; |
| 8 import android.content.pm.PackageManager; |
| 9 import android.content.pm.PackageManager.NameNotFoundException; |
| 10 import android.content.res.Resources; |
| 11 |
| 12 import org.chromium.mojo.system.MojoException; |
| 13 import org.chromium.mojom.content.InstalledAppProvider; |
| 14 import org.chromium.mojom.content.RelatedApplication; |
| 15 |
| 16 import org.json.JSONException; |
| 17 import org.json.JSONObject; |
| 18 |
| 19 import java.net.MalformedURLException; |
| 20 import java.net.URL; |
| 21 import java.util.ArrayList; |
| 22 import java.util.Arrays; |
| 23 import java.util.Collections; |
| 24 import java.util.List; |
| 25 |
| 26 /** |
| 27 * Android implementation of the InstalledAppProvider service defined in |
| 28 * content/common/installedapp/installed_app_provider.mojom. |
| 29 */ |
| 30 public class InstalledAppProviderImpl implements InstalledAppProvider { |
| 31 private Context mContext; |
| 32 private static final String ASSET_DESCRIPTOR_FIELD_TARGET = "target"; |
| 33 private static final String ASSET_DESCRIPTOR_WEB = "web"; |
| 34 private static final String ASSET_DESCRIPTOR_FIELD_SITE = "site"; |
| 35 private static final String ASSET_DESCRIPTOR_FIELD_NAMESPACE = "namespace"; |
| 36 private static final String ASSOCIATED_ASSETS_KEY = "associated_assets"; |
| 37 private static final String RELATED_APP_ANDROID_PLATFORM = "play"; |
| 38 |
| 39 public InstalledAppProviderImpl(Context context) { |
| 40 mContext = context; |
| 41 } |
| 42 |
| 43 @Override |
| 44 public void filterInstalledApps( |
| 45 RelatedApplication[] apps, String origin, FilterInstalledAppsRespons
e callback) { |
| 46 callback.call(filterAndroidInstalledApps(apps, origin)); |
| 47 } |
| 48 |
| 49 public RelatedApplication[] filterAndroidInstalledApps( |
| 50 RelatedApplication[] apps, String origin) { |
| 51 ArrayList<RelatedApplication> installedApps = new ArrayList<RelatedAppli
cation>(); |
| 52 PackageManager pm = mContext.getPackageManager(); |
| 53 for (RelatedApplication app : apps) { |
| 54 // If the package is of type "play" and origin is associated with pa
ckage, |
| 55 // add the package to the list of valid packages. |
| 56 if (app.platform.equals(RELATED_APP_ANDROID_PLATFORM) |
| 57 && isOriginAssociatedWithPackage(app.id, origin, pm)) { |
| 58 installedApps.add(app); |
| 59 } |
| 60 } |
| 61 RelatedApplication installedAppsArray[] = new RelatedApplication[install
edApps.size()]; |
| 62 installedAppsArray = installedApps.toArray(installedAppsArray); |
| 63 return installedAppsArray; |
| 64 } |
| 65 |
| 66 @Override |
| 67 public void close() {} |
| 68 |
| 69 @Override |
| 70 public void onConnectionError(MojoException e) {} |
| 71 |
| 72 private static List<String> getAssociations(String packageName, PackageManag
er pm) { |
| 73 Resources resources; |
| 74 |
| 75 try { |
| 76 resources = pm.getResourcesForApplication(packageName); |
| 77 } catch (NameNotFoundException e) { |
| 78 return Collections.<String>emptyList(); |
| 79 } |
| 80 |
| 81 if (resources == null) { |
| 82 return Collections.<String>emptyList(); |
| 83 } |
| 84 |
| 85 int identifier = resources.getIdentifier(ASSOCIATED_ASSETS_KEY, "array",
packageName); |
| 86 if (identifier == 0) { |
| 87 return Collections.<String>emptyList(); |
| 88 } |
| 89 return Arrays.asList(resources.getStringArray(identifier)); |
| 90 } |
| 91 |
| 92 private static boolean isOriginAssociatedWithPackage( |
| 93 String packageName, String origin, PackageManager pm) { |
| 94 List<String> associations = getAssociations(packageName, pm); |
| 95 URL originURL; |
| 96 try { |
| 97 originURL = new URL(origin); |
| 98 } catch (MalformedURLException e) { |
| 99 return false; |
| 100 } |
| 101 |
| 102 for (String statementString : associations) { |
| 103 try { |
| 104 JSONObject statement = new JSONObject(statementString); |
| 105 String assetDescriptorJson = statement.getString(ASSET_DESCRIPTO
R_FIELD_TARGET); |
| 106 JSONObject assetJson = new JSONObject(assetDescriptorJson); |
| 107 |
| 108 // If it is not a web appet, skip it. |
| 109 if (!isAssetIsWeb(assetJson)) { |
| 110 continue; |
| 111 } |
| 112 |
| 113 URL assetURL; |
| 114 try { |
| 115 assetURL = new URL(assetJson.getString(ASSET_DESCRIPTOR_FIEL
D_SITE)); |
| 116 } catch (MalformedURLException e) { |
| 117 continue; |
| 118 } |
| 119 |
| 120 // The URL is considered equivalent if the scheme, host, and por
t match, according |
| 121 // to the DigitalAssetLinks v1 spec. |
| 122 if (statementTargetMatches(originURL, assetURL)) { |
| 123 return true; |
| 124 } |
| 125 } catch (JSONException e) { |
| 126 continue; |
| 127 } |
| 128 } |
| 129 |
| 130 return false; |
| 131 } |
| 132 |
| 133 private static boolean isAssetIsWeb(JSONObject asset) { |
| 134 try { |
| 135 return asset.getString(ASSET_DESCRIPTOR_FIELD_NAMESPACE).equals(ASSE
T_DESCRIPTOR_WEB); |
| 136 } catch (JSONException e) { |
| 137 return false; |
| 138 } |
| 139 } |
| 140 |
| 141 private static boolean statementTargetMatches(URL originURL, URL assetURL) { |
| 142 return (assetURL.getProtocol().equals(originURL.getProtocol()) |
| 143 && assetURL.getHost().equals(originURL.getHost()) |
| 144 && assetURL.getPort() == originURL.getPort()); |
| 145 } |
| 146 } |
OLD | NEW |