1 /* 2 * Copyright (C) 2022 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.ide.common.resources.deprecated; 18 19 import com.android.ide.common.rendering.api.DensityBasedResourceValueImpl; 20 import com.android.ide.common.rendering.api.ResourceNamespace; 21 import com.android.ide.common.rendering.api.ResourceReference; 22 import com.android.ide.common.rendering.api.ResourceValue; 23 import com.android.ide.common.rendering.api.ResourceValueImpl; 24 import com.android.ide.common.resources.ResourceValueMap; 25 import com.android.ide.common.resources.configuration.DensityQualifier; 26 import com.android.ide.common.resources.configuration.ResourceQualifier; 27 import com.android.ide.common.resources.deprecated.ValueResourceParser.IValueResourceRepository; 28 import com.android.io.IAbstractFile; 29 import com.android.io.StreamException; 30 import com.android.resources.ResourceType; 31 32 import java.io.IOException; 33 import java.util.Collection; 34 import java.util.EnumSet; 35 import java.util.HashSet; 36 import java.util.Set; 37 38 /** 39 * @deprecated This class is part of an obsolete resource repository system that is no longer used 40 * in production code. The class is preserved temporarily for LayoutLib tests. 41 */ 42 @Deprecated 43 public final class IdGeneratingResourceFile extends ResourceFile 44 implements IValueResourceRepository { 45 46 private final ResourceValueMap mIdResources = ResourceValueMap.create(); 47 48 private final Collection<ResourceType> mResourceTypeList; 49 50 private final String mFileName; 51 52 private final ResourceType mFileType; 53 54 private final ResourceValue mFileValue; 55 IdGeneratingResourceFile(TestFileWrapper file, ResourceFolder folder, ResourceType type)56 public IdGeneratingResourceFile(TestFileWrapper file, ResourceFolder folder, ResourceType type) { 57 super(file, folder); 58 59 mFileType = type; 60 61 // Set up our resource types 62 mResourceTypeList = EnumSet.of(mFileType, ResourceType.ID); 63 64 // compute the resource name 65 mFileName = getFileName(); 66 67 // Get the resource value of this file as a whole layout 68 mFileValue = getFileValue(file, folder); 69 } 70 71 @Override load(ScanningContext context)72 protected void load(ScanningContext context) { 73 // Parse the file and look for @+id/ entries 74 parseFileForIds(); 75 76 // create the resource items in the repository 77 updateResourceItems(context); 78 } 79 80 @Override update(ScanningContext context)81 protected void update(ScanningContext context) { 82 // Copy the previous list of ID names 83 Set<String> oldIdNames = new HashSet<>(mIdResources.keySet()); 84 85 // reset current content. 86 mIdResources.clear(); 87 88 // need to parse the file and find the IDs. 89 if (!parseFileForIds()) { 90 context.requestFullAapt(); 91 // Continue through to updating the resource item here since it 92 // will make for example layout rendering more accurate until 93 // aapt is re-run 94 } 95 96 // We only need to update the repository if our IDs have changed 97 Set<String> keySet = mIdResources.keySet(); 98 assert keySet != oldIdNames; 99 if (!oldIdNames.equals(keySet)) { 100 updateResourceItems(context); 101 } 102 } 103 104 @Override getValue(ResourceType type, String name)105 public ResourceValue getValue(ResourceType type, String name) { 106 // Check to see if they're asking for one of the right types: 107 if (type != mFileType && type != ResourceType.ID) { 108 return null; 109 } 110 111 // If they're looking for a resource of this type with this name give them the whole file 112 if (type == mFileType && name.equals(mFileName)) { 113 return mFileValue; 114 } else { 115 // Otherwise try to return them an ID 116 // the map will return null if it's not found 117 return mIdResources.get(name); 118 } 119 } 120 121 /** 122 * Looks through the file represented for Ids and adds them to 123 * our id repository 124 * 125 * @return true if parsing succeeds and false if it fails 126 */ parseFileForIds()127 private boolean parseFileForIds() { 128 IdResourceParser parser = new IdResourceParser(this, isFramework()); 129 try { 130 IAbstractFile file = getFile(); 131 return parser.parse(file.getContents()); 132 } catch (IOException | StreamException ignore) {} 133 134 return false; 135 } 136 137 /** 138 * Add the resources represented by this file to the repository 139 */ updateResourceItems(ScanningContext context)140 private void updateResourceItems(ScanningContext context) { 141 ResourceRepository repository = getRepository(); 142 143 // remove this file from all existing ResourceItem. 144 repository.removeFile(mResourceTypeList, this); 145 146 // First add this as a layout file 147 ResourceItem item = repository.getResourceItem(mFileType, mFileName); 148 item.add(this); 149 150 // Now iterate through our IDs and add 151 for (String idName : mIdResources.keySet()) { 152 item = repository.getResourceItem(ResourceType.ID, idName); 153 // add this file to the list of files generating ID resources. 154 item.add(this); 155 } 156 157 // Ask the repository for an ID refresh 158 context.requestFullAapt(); 159 } 160 161 /** 162 * Returns the resource value associated with this whole file as a layout resource 163 * @param file the file handler that represents this file 164 * @param folder the folder this file is under 165 * @return a resource value associated with this layout 166 */ getFileValue(IAbstractFile file, ResourceFolder folder)167 private ResourceValue getFileValue(IAbstractFile file, ResourceFolder folder) { 168 // test if there's a density qualifier associated with the resource 169 DensityQualifier qualifier = folder.getConfiguration().getDensityQualifier(); 170 171 ResourceValue value; 172 if (!ResourceQualifier.isValid(qualifier)) { 173 value = 174 new ResourceValueImpl( 175 new ResourceReference( 176 ResourceNamespace.fromBoolean(isFramework()), 177 mFileType, 178 mFileName), 179 file.getOsLocation()); 180 } else { 181 value = 182 new DensityBasedResourceValueImpl( 183 new ResourceReference( 184 ResourceNamespace.fromBoolean(isFramework()), 185 mFileType, 186 mFileName), 187 file.getOsLocation(), 188 qualifier.getValue()); 189 } 190 return value; 191 } 192 193 194 /** 195 * Returns the name of this resource. 196 */ getFileName()197 private String getFileName() { 198 // get the name from the filename. 199 String name = getFile().getName(); 200 201 int pos = name.indexOf('.'); 202 if (pos != -1) { 203 name = name.substring(0, pos); 204 } 205 206 return name; 207 } 208 209 @Override addResourceValue(ResourceValue value)210 public void addResourceValue(ResourceValue value) { 211 // Just overwrite collisions. We're only interested in the unique 212 // IDs declared 213 mIdResources.put(value.getName(), value); 214 } 215 } 216