• Home
  • History
  • Annotate
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2009 The Android Open Source Project
3  *
4  * Licensed under the Eclipse Public License, Version 1.0 (the "License"); you
5  * may not use this file except in compliance with the License. You may obtain a
6  * 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, WITHOUT
12  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13  * License for the specific language governing permissions and limitations under
14  * the License.
15  */
16 
17 package com.android.ide.eclipse.tests.functests.layoutRendering;
18 
19 import com.android.SdkConstants;
20 import com.android.ide.common.rendering.LayoutLibrary;
21 import com.android.ide.common.rendering.api.ActionBarCallback;
22 import com.android.ide.common.rendering.api.AdapterBinding;
23 import com.android.ide.common.rendering.api.HardwareConfig;
24 import com.android.ide.common.rendering.api.ILayoutPullParser;
25 import com.android.ide.common.rendering.api.IProjectCallback;
26 import com.android.ide.common.rendering.api.RenderSession;
27 import com.android.ide.common.rendering.api.ResourceReference;
28 import com.android.ide.common.rendering.api.ResourceValue;
29 import com.android.ide.common.rendering.api.SessionParams;
30 import com.android.ide.common.rendering.api.SessionParams.RenderingMode;
31 import com.android.ide.common.resources.ResourceItem;
32 import com.android.ide.common.resources.ResourceRepository;
33 import com.android.ide.common.resources.ResourceResolver;
34 import com.android.ide.common.resources.configuration.DensityQualifier;
35 import com.android.ide.common.resources.configuration.FolderConfiguration;
36 import com.android.ide.common.resources.configuration.KeyboardStateQualifier;
37 import com.android.ide.common.resources.configuration.NavigationMethodQualifier;
38 import com.android.ide.common.resources.configuration.NavigationStateQualifier;
39 import com.android.ide.common.resources.configuration.ScreenDimensionQualifier;
40 import com.android.ide.common.resources.configuration.ScreenHeightQualifier;
41 import com.android.ide.common.resources.configuration.ScreenOrientationQualifier;
42 import com.android.ide.common.resources.configuration.ScreenRatioQualifier;
43 import com.android.ide.common.resources.configuration.ScreenSizeQualifier;
44 import com.android.ide.common.resources.configuration.ScreenWidthQualifier;
45 import com.android.ide.common.resources.configuration.SmallestScreenWidthQualifier;
46 import com.android.ide.common.resources.configuration.TextInputMethodQualifier;
47 import com.android.ide.common.resources.configuration.TouchScreenQualifier;
48 import com.android.ide.common.sdk.LoadStatus;
49 import com.android.ide.eclipse.adt.internal.resources.manager.ResourceManager;
50 import com.android.ide.eclipse.adt.internal.sdk.AndroidTargetData;
51 import com.android.ide.eclipse.tests.SdkLoadingTestCase;
52 import com.android.io.FolderWrapper;
53 import com.android.resources.Density;
54 import com.android.resources.Keyboard;
55 import com.android.resources.KeyboardState;
56 import com.android.resources.Navigation;
57 import com.android.resources.NavigationState;
58 import com.android.resources.ResourceType;
59 import com.android.resources.ScreenOrientation;
60 import com.android.resources.ScreenRatio;
61 import com.android.resources.ScreenSize;
62 import com.android.resources.TouchScreen;
63 import com.android.sdklib.IAndroidTarget;
64 import com.android.util.Pair;
65 
66 import org.kxml2.io.KXmlParser;
67 import org.xmlpull.v1.XmlPullParser;
68 import org.xmlpull.v1.XmlPullParserException;
69 
70 import java.io.File;
71 import java.io.FileReader;
72 import java.io.IOException;
73 import java.util.HashMap;
74 import java.util.Map;
75 
76 import javax.imageio.ImageIO;
77 
78 public class ApiDemosRenderingTest extends SdkLoadingTestCase {
79 
80     /**
81      * Custom parser that implements {@link ILayoutPullParser} (which itself extends
82      * {@link XmlPullParser}).
83      */
84     private final static class TestParser extends KXmlParser implements ILayoutPullParser {
85         /**
86          * Since we're not going to go through the result of the rendering/layout, we can return
87          * null for the View Key.
88          */
89         @Override
getViewCookie()90         public Object getViewCookie() {
91             return null;
92         }
93 
94         @Override
getParser(String layoutName)95         public ILayoutPullParser getParser(String layoutName) {
96             return null;
97         }
98     }
99 
100     private final static class ProjectCallBack implements IProjectCallback {
101         // resource id counter.
102         // We start at 0x7f000000 to avoid colliding with the framework id
103         // since we have no access to the project R.java and we need to generate them automatically.
104         private int mIdCounter = 0x7f000000;
105 
106         // in some cases, the id that getResourceValue(String type, String name) returns
107         // will be sent back to get the type/name. This map stores the id/type/name we generate
108         // to be able to do the reverse resolution.
109         private Map<Integer, Pair<ResourceType, String>> mResourceMap =
110             new HashMap<Integer, Pair<ResourceType, String>>();
111 
112         private boolean mCustomViewAttempt = false;
113 
114         @Override
getNamespace()115         public String getNamespace() {
116             // TODO: read from the ApiDemos manifest.
117             return "com.example.android.apis";
118         }
119 
120         @Override
121         @SuppressWarnings("unchecked")
loadView(String name, Class[] constructorSignature, Object[] constructorArgs)122         public Object loadView(String name, Class[] constructorSignature, Object[] constructorArgs)
123                 throws ClassNotFoundException, Exception {
124             mCustomViewAttempt = true;
125             return null;
126         }
127 
128         @Override
getResourceId(ResourceType type, String name)129         public Integer getResourceId(ResourceType type, String name) {
130             Integer result = ++mIdCounter;
131             mResourceMap.put(result, Pair.of(type, name));
132             return result;
133         }
134 
135         @Override
resolveResourceId(int id)136         public Pair<ResourceType, String> resolveResourceId(int id) {
137             return mResourceMap.get(id);
138         }
139 
140         @Override
resolveResourceId(int[] id)141         public String resolveResourceId(int[] id) {
142             return null;
143         }
144 
145         @Override
getParser(String layoutName)146         public ILayoutPullParser getParser(String layoutName) {
147             return null;
148         }
149 
150         @Override
getAdapterItemValue(ResourceReference adapterView, Object adapterCookie, ResourceReference itemRef, int fullPosition, int typePosition, int fullChildPosition, int typeChildPosition, ResourceReference viewRef, ViewAttribute viewAttribute, Object defaultValue)151         public Object getAdapterItemValue(ResourceReference adapterView, Object adapterCookie,
152                 ResourceReference itemRef, int fullPosition, int typePosition,
153                 int fullChildPosition, int typeChildPosition,
154                 ResourceReference viewRef, ViewAttribute viewAttribute, Object defaultValue) {
155             return null;
156         }
157 
158         @Override
getAdapterBinding(ResourceReference adapterView, Object adapterCookie, Object viewObject)159         public AdapterBinding getAdapterBinding(ResourceReference adapterView,
160                 Object adapterCookie, Object viewObject) {
161             return null;
162         }
163 
164         @Override
getParser(ResourceValue layoutResource)165         public ILayoutPullParser getParser(ResourceValue layoutResource) {
166             return null;
167         }
168 
169         @Override
getActionBarCallback()170         public ActionBarCallback getActionBarCallback() {
171             return new ActionBarCallback();
172         }
173     }
174 
testApiDemos()175     public void testApiDemos() throws IOException, XmlPullParserException {
176         findApiDemos();
177     }
178 
findApiDemos()179     private void findApiDemos() throws IOException, XmlPullParserException {
180         IAndroidTarget[] targets = getSdk().getTargets();
181 
182         for (IAndroidTarget target : targets) {
183             String path = target.getPath(IAndroidTarget.SAMPLES);
184             File samples = new File(path);
185             if (samples.isDirectory()) {
186                 File[] files = samples.listFiles();
187                 for (File file : files) {
188                     if ("apidemos".equalsIgnoreCase(file.getName())) {
189                         testSample(target, file);
190                         return;
191                     }
192                 }
193             }
194         }
195 
196         fail("Failed to find ApiDemos!");
197     }
198 
testSample(IAndroidTarget target, File sampleProject)199     private void testSample(IAndroidTarget target, File sampleProject) throws IOException, XmlPullParserException {
200         AndroidTargetData data = getSdk().getTargetData(target);
201         if (data == null) {
202             fail("No AndroidData!");
203         }
204 
205         LayoutLibrary layoutLib = data.getLayoutLibrary();
206         if (layoutLib.getStatus() != LoadStatus.LOADED) {
207             fail("Fail to load the bridge: " + layoutLib.getLoadMessage());
208         }
209 
210         FolderWrapper resFolder = new FolderWrapper(sampleProject, SdkConstants.FD_RES);
211         if (resFolder.exists() == false) {
212             fail("Sample project has no res folder!");
213         }
214 
215         // look for the layout folder
216         File layoutFolder = new File(resFolder, SdkConstants.FD_RES_LAYOUT);
217         if (layoutFolder.isDirectory() == false) {
218             fail("Sample project has no layout folder!");
219         }
220 
221         // first load the project's target framework resource
222         ResourceRepository framework = ResourceManager.getInstance().loadFrameworkResources(target);
223 
224         // now load the project resources
225         ResourceRepository project = new ResourceRepository(resFolder, false) {
226             @Override
227             protected ResourceItem createResourceItem(String name) {
228                 return new ResourceItem(name);
229             }
230 
231         };
232 
233         // Create a folder configuration that will be used for the rendering:
234         FolderConfiguration config = getConfiguration();
235 
236         // get the configured resources
237         Map<ResourceType, Map<String, ResourceValue>> configuredFramework =
238                 framework.getConfiguredResources(config);
239         Map<ResourceType, Map<String, ResourceValue>> configuredProject =
240                 project.getConfiguredResources(config);
241 
242         boolean saveFiles = System.getenv("save_file") != null;
243 
244         // loop on the layouts and render them
245         File[] layouts = layoutFolder.listFiles();
246         for (File layout : layouts) {
247             // create a parser for the layout file
248             TestParser parser = new TestParser();
249             parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, true);
250             parser.setInput(new FileReader(layout));
251 
252             System.out.println("Rendering " + layout.getName());
253 
254             ProjectCallBack projectCallBack = new ProjectCallBack();
255 
256             ResourceResolver resolver = ResourceResolver.create(
257                     configuredProject, configuredFramework,
258                     "Theme", false /*isProjectTheme*/);
259 
260             HardwareConfig hardwareConfig = new HardwareConfig(
261                     320,
262                     480,
263                     Density.MEDIUM,
264                     160, //xdpi
265                     160, // ydpi
266                     ScreenSize.NORMAL,
267                     ScreenOrientation.PORTRAIT,
268                     false /*software buttons */);
269 
270             RenderSession session = layoutLib.createSession(new SessionParams(
271                     parser,
272                     RenderingMode.NORMAL,
273                     null /*projectKey*/,
274                     hardwareConfig,
275                     resolver,
276                     projectCallBack,
277                     1, // minSdkVersion
278                     1, // targetSdkVersion
279                     null //logger
280                     ));
281 
282             if (session.getResult().isSuccess() == false) {
283                 if (projectCallBack.mCustomViewAttempt == false) {
284                     System.out.println("FAILED");
285                     fail(String.format("Rendering %1$s: %2$s", layout.getName(),
286                             session.getResult().getErrorMessage()));
287                 } else {
288                     System.out.println("Ignore custom views for now");
289                 }
290             } else {
291                 if (saveFiles) {
292                     File tmp = File.createTempFile(layout.getName(), ".png");
293                     ImageIO.write(session.getImage(), "png", tmp);
294                 }
295                 System.out.println("Success!");
296             }
297         }
298     }
299 
300     /**
301      * Returns a config. This must be a valid config like a device would return. This is to
302      * prevent issues where some resources don't exist in all cases and not in the default
303      * (for instance only available in hdpi and mdpi but not in default).
304      * @return
305      */
getConfiguration()306     private FolderConfiguration getConfiguration() {
307         FolderConfiguration config = new FolderConfiguration();
308 
309         // this matches an ADP1.
310         config.addQualifier(new SmallestScreenWidthQualifier(320));
311         config.addQualifier(new ScreenWidthQualifier(320));
312         config.addQualifier(new ScreenHeightQualifier(480));
313         config.addQualifier(new ScreenSizeQualifier(ScreenSize.NORMAL));
314         config.addQualifier(new ScreenRatioQualifier(ScreenRatio.NOTLONG));
315         config.addQualifier(new ScreenOrientationQualifier(ScreenOrientation.PORTRAIT));
316         config.addQualifier(new DensityQualifier(Density.MEDIUM));
317         config.addQualifier(new TouchScreenQualifier(TouchScreen.FINGER));
318         config.addQualifier(new KeyboardStateQualifier(KeyboardState.HIDDEN));
319         config.addQualifier(new TextInputMethodQualifier(Keyboard.QWERTY));
320         config.addQualifier(new NavigationStateQualifier(NavigationState.HIDDEN));
321         config.addQualifier(new NavigationMethodQualifier(Navigation.TRACKBALL));
322         config.addQualifier(new ScreenDimensionQualifier(480, 320));
323 
324         config.updateScreenWidthAndHeight();
325 
326         return config;
327     }
328 }
329