• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2010 The Android Open Source Project
3  *
4  * Licensed under the Eclipse Public License, Version 1.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.eclipse.org/org/documents/epl-v10.php
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.eclipse.adt.internal.editors.layout.gle2;
18 
19 import com.android.annotations.NonNull;
20 import com.android.annotations.Nullable;
21 import com.android.ide.common.rendering.api.LayoutLog;
22 import com.android.ide.eclipse.adt.AdtPlugin;
23 
24 import org.eclipse.core.runtime.IStatus;
25 
26 import java.util.ArrayList;
27 import java.util.HashSet;
28 import java.util.List;
29 import java.util.Set;
30 
31 /**
32  * A {@link LayoutLog} which records the problems it encounters and offers them as a
33  * single summary at the end
34  */
35 public class RenderLogger extends LayoutLog {
36     static final String TAG_MISSING_DIMENSION = "missing.dimension";     //$NON-NLS-1$
37 
38     private final String mName;
39     private List<String> mFidelityWarnings;
40     private List<String> mWarnings;
41     private List<String> mErrors;
42     private boolean mHaveExceptions;
43     private List<String> mTags;
44     private List<Throwable> mTraces;
45     private static Set<String> sIgnoredFidelityWarnings;
46 
47     /** Construct a logger for the given named layout */
RenderLogger(String name)48     RenderLogger(String name) {
49         mName = name;
50     }
51 
52     /**
53      * Are there any logged errors or warnings during the render?
54      *
55      * @return true if there were problems during the render
56      */
hasProblems()57     public boolean hasProblems() {
58         return mFidelityWarnings != null || mErrors != null || mWarnings != null ||
59             mHaveExceptions;
60     }
61 
62     /**
63      * Returns a list of traces encountered during rendering, or null if none
64      *
65      * @return a list of traces encountered during rendering, or null if none
66      */
67     @Nullable
getFirstTrace()68     public List<Throwable> getFirstTrace() {
69         return mTraces;
70     }
71 
72     /**
73      * Returns a (possibly multi-line) description of all the problems
74      *
75      * @param includeFidelityWarnings if true, include fidelity warnings in the problem
76      *            summary
77      * @return a string describing the rendering problems
78      */
79     @NonNull
getProblems(boolean includeFidelityWarnings)80     public String getProblems(boolean includeFidelityWarnings) {
81         StringBuilder sb = new StringBuilder();
82 
83         if (mErrors != null) {
84             for (String error : mErrors) {
85                 sb.append(error).append('\n');
86             }
87         }
88 
89         if (mWarnings != null) {
90             for (String warning : mWarnings) {
91                 sb.append(warning).append('\n');
92             }
93         }
94 
95         if (includeFidelityWarnings && mFidelityWarnings != null) {
96             sb.append("The graphics preview in the layout editor may not be accurate:\n");
97             for (String warning : mFidelityWarnings) {
98                 sb.append("* ");
99                 sb.append(warning).append('\n');
100             }
101         }
102 
103         if (mHaveExceptions) {
104             sb.append("Exception details are logged in Window > Show View > Error Log");
105         }
106 
107         return sb.toString();
108     }
109 
110     /**
111      * Returns the fidelity warnings
112      *
113      * @return the fidelity warnings
114      */
115     @Nullable
getFidelityWarnings()116     public List<String> getFidelityWarnings() {
117         return mFidelityWarnings;
118     }
119 
120     // ---- extends LayoutLog ----
121 
122     @Override
error(String tag, String message, Object data)123     public void error(String tag, String message, Object data) {
124         String description = describe(message);
125 
126         AdtPlugin.log(IStatus.ERROR, "%1$s: %2$s", mName, description);
127 
128         // Workaround: older layout libraries don't provide a tag for this error
129         if (tag == null && message != null
130                 && message.startsWith("Failed to find style ")) { //$NON-NLS-1$
131             tag = LayoutLog.TAG_RESOURCES_RESOLVE_THEME_ATTR;
132         }
133 
134         addError(tag, description);
135     }
136 
137     @Override
error(String tag, String message, Throwable throwable, Object data)138     public void error(String tag, String message, Throwable throwable, Object data) {
139         String description = describe(message);
140         AdtPlugin.log(throwable, "%1$s: %2$s", mName, description);
141         if (throwable != null) {
142             if (throwable instanceof ClassNotFoundException) {
143                 // The project callback is given a chance to resolve classes,
144                 // and when it fails, it will record it in its own list which
145                 // is displayed in a special way (with action hyperlinks etc).
146                 // Therefore, include these messages in the visible render log,
147                 // especially since the user message from a ClassNotFoundException
148                 // is really not helpful (it just lists the class name without
149                 // even mentioning that it is a class-not-found exception.)
150                 return;
151             }
152 
153             if (description.equals(throwable.getLocalizedMessage()) ||
154                     description.equals(throwable.getMessage())) {
155                 description = "Exception raised during rendering: " + description;
156             }
157             recordThrowable(throwable);
158             mHaveExceptions = true;
159         }
160 
161         addError(tag, description);
162     }
163 
164     /**
165      * Record that the given exception was encountered during rendering
166      *
167      * @param throwable the exception that was raised
168      */
recordThrowable(@onNull Throwable throwable)169     public void recordThrowable(@NonNull Throwable throwable) {
170         if (mTraces == null) {
171             mTraces = new ArrayList<Throwable>();
172         }
173         mTraces.add(throwable);
174     }
175 
176     @Override
warning(String tag, String message, Object data)177     public void warning(String tag, String message, Object data) {
178         String description = describe(message);
179 
180         boolean log = true;
181         if (TAG_RESOURCES_FORMAT.equals(tag)) {
182             if (description.equals("You must supply a layout_width attribute.")       //$NON-NLS-1$
183                 || description.equals("You must supply a layout_height attribute.")) {//$NON-NLS-1$
184                 tag = TAG_MISSING_DIMENSION;
185                 log = false;
186             }
187         }
188 
189         if (log) {
190             AdtPlugin.log(IStatus.WARNING, "%1$s: %2$s", mName, description);
191         }
192 
193         addWarning(tag, description);
194     }
195 
196     @Override
fidelityWarning(String tag, String message, Throwable throwable, Object data)197     public void fidelityWarning(String tag, String message, Throwable throwable, Object data) {
198         if (sIgnoredFidelityWarnings != null && sIgnoredFidelityWarnings.contains(message)) {
199             return;
200         }
201 
202         String description = describe(message);
203         AdtPlugin.log(throwable, "%1$s: %2$s", mName, description);
204         if (throwable != null) {
205             mHaveExceptions = true;
206         }
207 
208         addFidelityWarning(tag, description);
209     }
210 
211     /**
212      * Ignore the given render fidelity warning for the current session
213      *
214      * @param message the message to be ignored for this session
215      */
ignoreFidelityWarning(String message)216     public static void ignoreFidelityWarning(String message) {
217         if (sIgnoredFidelityWarnings == null) {
218             sIgnoredFidelityWarnings = new HashSet<String>();
219         }
220         sIgnoredFidelityWarnings.add(message);
221     }
222 
223     @NonNull
describe(@ullable String message)224     private String describe(@Nullable String message) {
225         if (message == null) {
226             return "";
227         } else {
228             return message;
229         }
230     }
231 
addWarning(String tag, String description)232     private void addWarning(String tag, String description) {
233         if (mWarnings == null) {
234             mWarnings = new ArrayList<String>();
235         } else if (mWarnings.contains(description)) {
236             // Avoid duplicates
237             return;
238         }
239         mWarnings.add(description);
240         addTag(tag);
241     }
242 
addError(String tag, String description)243     private void addError(String tag, String description) {
244         if (mErrors == null) {
245             mErrors = new ArrayList<String>();
246         } else if (mErrors.contains(description)) {
247             // Avoid duplicates
248             return;
249         }
250         mErrors.add(description);
251         addTag(tag);
252     }
253 
addFidelityWarning(String tag, String description)254     private void addFidelityWarning(String tag, String description) {
255         if (mFidelityWarnings == null) {
256             mFidelityWarnings = new ArrayList<String>();
257         } else if (mFidelityWarnings.contains(description)) {
258             // Avoid duplicates
259             return;
260         }
261         mFidelityWarnings.add(description);
262         addTag(tag);
263     }
264 
265     // ---- Tags ----
266 
addTag(String tag)267     private void addTag(String tag) {
268         if (tag != null) {
269             if (mTags == null) {
270                 mTags = new ArrayList<String>();
271             }
272             mTags.add(tag);
273         }
274     }
275 
276     /**
277      * Returns true if the given tag prefix has been seen
278      *
279      * @param prefix the tag prefix to look for
280      * @return true iff any tags with the given prefix was seen during the render
281      */
seenTagPrefix(String prefix)282     public boolean seenTagPrefix(String prefix) {
283         if (mTags != null) {
284             for (String tag : mTags) {
285                 if (tag.startsWith(prefix)) {
286                     return true;
287                 }
288             }
289         }
290 
291         return false;
292     }
293 
294     /**
295      * Returns true if the given tag has been seen
296      *
297      * @param tag the tag to look for
298      * @return true iff the tag was seen during the render
299      */
seenTag(String tag)300     public boolean seenTag(String tag) {
301         if (mTags != null) {
302             return mTags.contains(tag);
303         } else {
304             return false;
305         }
306     }
307 }
308