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 package com.android.ide.common.resources.deprecated;
17 
18 import com.android.ide.common.rendering.api.DensityBasedResourceValueImpl;
19 import com.android.ide.common.rendering.api.ResourceNamespace;
20 import com.android.ide.common.rendering.api.ResourceReference;
21 import com.android.ide.common.rendering.api.ResourceValue;
22 import com.android.ide.common.rendering.api.ResourceValueImpl;
23 import com.android.ide.common.resources.configuration.DensityQualifier;
24 import com.android.ide.common.resources.configuration.ResourceQualifier;
25 import com.android.io.IAbstractFile;
26 import com.android.resources.FolderTypeRelationship;
27 import com.android.resources.ResourceType;
28 import com.android.utils.SdkUtils;
29 
30 import java.util.List;
31 
32 
33 import static com.android.SdkConstants.DOT_XML;
34 
35 /**
36  * @deprecated This class is part of an obsolete resource repository system that is no longer used
37  *     in production code. The class is preserved temporarily for LayoutLib tests.
38  */
39 @Deprecated
40 public class SingleResourceFile extends ResourceFile {
41     private final String mResourceName;
42     private final ResourceType mType;
43     private final ResourceValue mValue;
44 
SingleResourceFile(TestFileWrapper file, ResourceFolder folder)45     public SingleResourceFile(TestFileWrapper file, ResourceFolder folder) {
46         super(file, folder);
47 
48         // we need to infer the type of the resource from the folder type.
49         // This is easy since this is a single Resource file.
50         List<ResourceType> types = FolderTypeRelationship.getRelatedResourceTypes(folder.getType());
51         mType = types.get(0);
52 
53         // compute the resource name
54         mResourceName = getResourceName();
55 
56         // test if there's a density qualifier associated with the resource
57         DensityQualifier qualifier = folder.getConfiguration().getDensityQualifier();
58 
59         if (!ResourceQualifier.isValid(qualifier)) {
60             mValue =
61                     new ResourceValueImpl(
62                             new ResourceReference(
63                                     ResourceNamespace.fromBoolean(isFramework()),
64                                     mType,
65                                     getResourceName()),
66                             file.getOsLocation());
67         } else {
68             mValue =
69                     new DensityBasedResourceValueImpl(
70                             new ResourceReference(
71                                     ResourceNamespace.fromBoolean(isFramework()),
72                                     mType,
73                                     getResourceName()),
74                             file.getOsLocation(),
75                             qualifier.getValue());
76         }
77     }
78 
79     @Override
load(ScanningContext context)80     protected void load(ScanningContext context) {
81         // get a resource item matching the given type and name
82         ResourceItem item = getRepository().getResourceItem(mType, mResourceName);
83 
84         // add this file to the list of files generating this resource item.
85         item.add(this);
86 
87         // Ask for an ID refresh since we're adding an item that will generate an ID
88         context.requestFullAapt();
89     }
90 
91     @Override
update(ScanningContext context)92     protected void update(ScanningContext context) {
93         // when this happens, nothing needs to be done since the file only generates
94         // a single resources that doesn't actually change (its content is the file path)
95 
96         // However, we should check for newly introduced errors
97         // Parse the file and look for @+id/ entries
98         validateAttributes(context);
99     }
100 
101     /*
102      * (non-Javadoc)
103      * @see com.android.ide.eclipse.editors.resources.manager.ResourceFile#getValue(com.android.ide.eclipse.common.resources.ResourceType, java.lang.String)
104      *
105      * This particular implementation does not care about the type or name since a
106      * SingleResourceFile represents a file generating only one resource.
107      * The value returned is the full absolute path of the file in OS form.
108      */
109     @Override
getValue(ResourceType type, String name)110     public ResourceValue getValue(ResourceType type, String name) {
111         return mValue;
112     }
113 
114     /**
115      * Returns the name of the resources.
116      */
getResourceName()117     private String getResourceName() {
118         // get the name from the filename.
119         String name = getFile().getName();
120 
121         int pos = name.indexOf('.');
122         if (pos != -1) {
123             name = name.substring(0, pos);
124         }
125 
126         return name;
127     }
128 
129     /**
130      * Validates the associated resource file to make sure the attribute references are valid
131      *
132      * @return true if parsing succeeds and false if it fails
133      */
validateAttributes(ScanningContext context)134     private boolean validateAttributes(ScanningContext context) {
135         // We only need to check if it's a non-framework file (and an XML file; skip .png's)
136         if (!isFramework() && SdkUtils.endsWith(getFile().getName(), DOT_XML)) {
137             ValidatingResourceParser parser = new ValidatingResourceParser(context, false);
138             try {
139                 IAbstractFile file = getFile();
140                 return parser.parse(file.getContents());
141             } catch (Exception e) {
142                 context.needsFullAapt();
143             }
144 
145             return false;
146         }
147 
148         return true;
149     }
150 }
151