1 /* 2 * Copyright (C) 2015 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.statementservice.retriever; 18 19 import android.annotation.NonNull; 20 import android.net.Network; 21 22 import com.android.statementservice.network.retriever.StatementRetriever; 23 24 import kotlin.coroutines.Continuation; 25 26 import java.util.Collections; 27 import java.util.List; 28 29 30 /** 31 * An immutable value type representing a statement, consisting of a source, target, and relation. 32 * This reflects an assertion that the relation holds for the source, target pair. For example, if a 33 * web site has the following in its assetlinks.json file: 34 * 35 * <pre> 36 * { 37 * "relation": ["delegate_permission/common.handle_all_urls"], 38 * "target" : {"namespace": "android_app", "package_name": "com.example.app", 39 * "sha256_cert_fingerprints": ["00:11:22:33"] }, 40 * "relation_extensions": { 41 * "delegate_permission/common_handle_all_urls": { 42 * "dynamic_app_link_components": [ 43 * { 44 * "/": "/foo*", 45 * "exclude": true, 46 * "comments": "App should not handle paths that start with foo" 47 * }, 48 * { 49 * "/": "*", 50 * "comments": "Catch all other paths" 51 * } 52 * ] 53 * } 54 * } 55 * </pre> 56 * 57 * Then invoking {@link StatementRetriever#retrieve(AbstractAsset, Network, Continuation)} will 58 * return a {@link Statement} with {@link #getSource} equal to the input parameter, 59 * {@link #getRelation} equal to 60 * 61 * <pre>Relation.create("delegate_permission", "common.handle_all_urls");</pre> 62 * 63 * and with {@link #getTarget} equal to 64 * 65 * <pre>AbstractAsset.create("{\"namespace\" : \"android_app\"," 66 * + "\"package_name\": \"com.example.app\"}" 67 * + "\"sha256_cert_fingerprints\": \"[\"00:11:22:33\"]\"}"); 68 * </pre> 69 * 70 * If extensions exist for the handle_all_urls relation then {@link #getDynamicAppLinkComponents} 71 * will return a list of parsed {@link DynamicAppLinkComponent}s. 72 */ 73 public final class Statement { 74 75 private final AbstractAsset mTarget; 76 private final Relation mRelation; 77 private final AbstractAsset mSource; 78 private final List<DynamicAppLinkComponent> mDynamicAppLinkComponents; 79 Statement(AbstractAsset source, AbstractAsset target, Relation relation, List<DynamicAppLinkComponent> components)80 private Statement(AbstractAsset source, AbstractAsset target, Relation relation, 81 List<DynamicAppLinkComponent> components) { 82 mSource = source; 83 mTarget = target; 84 mRelation = relation; 85 mDynamicAppLinkComponents = Collections.unmodifiableList(components); 86 } 87 88 /** 89 * Returns the source asset of the statement. 90 */ 91 @NonNull getSource()92 public AbstractAsset getSource() { 93 return mSource; 94 } 95 96 /** 97 * Returns the target asset of the statement. 98 */ 99 @NonNull getTarget()100 public AbstractAsset getTarget() { 101 return mTarget; 102 } 103 104 /** 105 * Returns the relation of the statement. 106 */ 107 @NonNull getRelation()108 public Relation getRelation() { 109 return mRelation; 110 } 111 112 /** 113 * Returns the relation matching rules of the statement. 114 */ 115 @NonNull getDynamicAppLinkComponents()116 public List<DynamicAppLinkComponent> getDynamicAppLinkComponents() { 117 return mDynamicAppLinkComponents; 118 } 119 120 /** 121 * Creates a new Statement object for the specified target asset and relation. For example: 122 * <pre> 123 * Asset asset = Asset.Factory.create( 124 * "{\"namespace\" : \"web\",\"site\": \"https://www.test.com\"}"); 125 * Relation relation = Relation.create("delegate_permission", "common.get_login_creds"); 126 * Statement statement = Statement.create(asset, relation); 127 * </pre> 128 */ create(@onNull AbstractAsset source, @NonNull AbstractAsset target, @NonNull Relation relation, @NonNull List<DynamicAppLinkComponent> components)129 public static Statement create(@NonNull AbstractAsset source, @NonNull AbstractAsset target, 130 @NonNull Relation relation, 131 @NonNull List<DynamicAppLinkComponent> components) { 132 return new Statement(source, target, relation, components); 133 } 134 135 @Override equals(Object o)136 public boolean equals(Object o) { 137 if (this == o) { 138 return true; 139 } 140 if (o == null || getClass() != o.getClass()) { 141 return false; 142 } 143 144 Statement statement = (Statement) o; 145 146 if (!mRelation.equals(statement.mRelation)) { 147 return false; 148 } 149 if (!mTarget.equals(statement.mTarget)) { 150 return false; 151 } 152 if (!mSource.equals(statement.mSource)) { 153 return false; 154 } 155 if (!mDynamicAppLinkComponents.equals(statement.mDynamicAppLinkComponents)) { 156 return false; 157 } 158 159 return true; 160 } 161 162 @Override hashCode()163 public int hashCode() { 164 int result = mTarget.hashCode(); 165 result = 31 * result + mRelation.hashCode(); 166 result = 31 * result + mSource.hashCode(); 167 result = 31 * result + mDynamicAppLinkComponents.hashCode(); 168 return result; 169 } 170 171 @Override toString()172 public String toString() { 173 StringBuilder statement = new StringBuilder(); 174 statement.append("Statement: "); 175 statement.append(mSource); 176 statement.append(", "); 177 statement.append(mTarget); 178 statement.append(", "); 179 statement.append(mRelation); 180 if (!mDynamicAppLinkComponents.isEmpty()) { 181 statement.append(", "); 182 statement.append(mDynamicAppLinkComponents); 183 } 184 return statement.toString(); 185 } 186 } 187