1/*
2 * Copyright (C) 2014 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
17package com.android.layoutlib.bridge.intensive.setup;
18
19import com.android.ide.common.rendering.api.HardwareConfig;
20import com.android.ide.common.resources.configuration.CountryCodeQualifier;
21import com.android.ide.common.resources.configuration.DensityQualifier;
22import com.android.ide.common.resources.configuration.FolderConfiguration;
23import com.android.ide.common.resources.configuration.KeyboardStateQualifier;
24import com.android.ide.common.resources.configuration.LayoutDirectionQualifier;
25import com.android.ide.common.resources.configuration.LocaleQualifier;
26import com.android.ide.common.resources.configuration.NavigationMethodQualifier;
27import com.android.ide.common.resources.configuration.NetworkCodeQualifier;
28import com.android.ide.common.resources.configuration.NightModeQualifier;
29import com.android.ide.common.resources.configuration.ScreenDimensionQualifier;
30import com.android.ide.common.resources.configuration.ScreenOrientationQualifier;
31import com.android.ide.common.resources.configuration.ScreenRatioQualifier;
32import com.android.ide.common.resources.configuration.ScreenSizeQualifier;
33import com.android.ide.common.resources.configuration.TextInputMethodQualifier;
34import com.android.ide.common.resources.configuration.TouchScreenQualifier;
35import com.android.ide.common.resources.configuration.UiModeQualifier;
36import com.android.ide.common.resources.configuration.VersionQualifier;
37import com.android.resources.Density;
38import com.android.resources.Keyboard;
39import com.android.resources.KeyboardState;
40import com.android.resources.Navigation;
41import com.android.resources.NightMode;
42import com.android.resources.ScreenOrientation;
43import com.android.resources.ScreenRatio;
44import com.android.resources.ScreenSize;
45import com.android.resources.TouchScreen;
46import com.android.resources.UiMode;
47
48import org.xmlpull.v1.XmlPullParser;
49import org.xmlpull.v1.XmlPullParserException;
50import org.xmlpull.v1.XmlPullParserFactory;
51
52import java.io.File;
53import java.io.FileInputStream;
54import java.io.IOException;
55import java.util.Map;
56import java.util.Properties;
57
58import com.google.android.collect.Maps;
59
60/**
61 * Provides {@link FolderConfiguration} and {@link HardwareConfig} for various devices. Also
62 * provides utility methods to parse build.prop and attrs.xml to generate the appropriate maps.
63 */
64@SuppressWarnings("UnusedDeclaration") // For the pre-configured nexus generators.
65public class ConfigGenerator {
66
67    public static final ConfigGenerator NEXUS_4 = new ConfigGenerator();
68
69    public static final ConfigGenerator NEXUS_5 = new ConfigGenerator()
70                                                        .setScreenHeight(1920)
71                                                        .setScreenWidth(1080)
72                                                        .setXdpi(445)
73                                                        .setYdpi(445)
74                                                        .setOrientation(ScreenOrientation.PORTRAIT)
75                                                        .setDensity(Density.XXHIGH)
76                                                        .setRatio(ScreenRatio.NOTLONG)
77                                                        .setSize(ScreenSize.NORMAL)
78                                                        .setKeyboard(Keyboard.NOKEY)
79                                                        .setTouchScreen(TouchScreen.FINGER)
80                                                        .setKeyboardState(KeyboardState.SOFT)
81                                                        .setSoftButtons(true)
82                                                        .setNavigation(Navigation.NONAV);
83
84    public static final ConfigGenerator NEXUS_7 = new ConfigGenerator()
85                                                        .setScreenHeight(1920)
86                                                        .setScreenWidth(1200)
87                                                        .setXdpi(323)
88                                                        .setYdpi(323)
89                                                        .setOrientation(ScreenOrientation.PORTRAIT)
90                                                        .setDensity(Density.XHIGH)
91                                                        .setRatio(ScreenRatio.NOTLONG)
92                                                        .setSize(ScreenSize.LARGE)
93                                                        .setKeyboard(Keyboard.NOKEY)
94                                                        .setTouchScreen(TouchScreen.FINGER)
95                                                        .setKeyboardState(KeyboardState.SOFT)
96                                                        .setSoftButtons(true)
97                                                        .setNavigation(Navigation.NONAV);
98
99    public static final ConfigGenerator NEXUS_10 = new ConfigGenerator()
100                                                        .setScreenHeight(1600)
101                                                        .setScreenWidth(2560)
102                                                        .setXdpi(300)
103                                                        .setYdpi(300)
104                                                        .setOrientation(ScreenOrientation.LANDSCAPE)
105                                                        .setDensity(Density.XHIGH)
106                                                        .setRatio(ScreenRatio.NOTLONG)
107                                                        .setSize(ScreenSize.XLARGE)
108                                                        .setKeyboard(Keyboard.NOKEY)
109                                                        .setTouchScreen(TouchScreen.FINGER)
110                                                        .setKeyboardState(KeyboardState.SOFT)
111                                                        .setSoftButtons(true)
112                                                        .setNavigation(Navigation.NONAV);
113
114    public static final ConfigGenerator NEXUS_5_LAND = new ConfigGenerator()
115                                                        .setScreenHeight(1080)
116                                                        .setScreenWidth(1920)
117                                                        .setXdpi(445)
118                                                        .setYdpi(445)
119                                                        .setOrientation(ScreenOrientation.LANDSCAPE)
120                                                        .setDensity(Density.XXHIGH)
121                                                        .setRatio(ScreenRatio.NOTLONG)
122                                                        .setSize(ScreenSize.NORMAL)
123                                                        .setKeyboard(Keyboard.NOKEY)
124                                                        .setTouchScreen(TouchScreen.FINGER)
125                                                        .setKeyboardState(KeyboardState.SOFT)
126                                                        .setSoftButtons(true)
127                                                        .setNavigation(Navigation.NONAV);
128
129    public static final ConfigGenerator NEXUS_7_2012 = new ConfigGenerator()
130                                                        .setScreenHeight(1280)
131                                                        .setScreenWidth(800)
132                                                        .setXdpi(195)
133                                                        .setYdpi(200)
134                                                        .setOrientation(ScreenOrientation.PORTRAIT)
135                                                        .setDensity(Density.TV)
136                                                        .setRatio(ScreenRatio.NOTLONG)
137                                                        .setSize(ScreenSize.LARGE)
138                                                        .setKeyboard(Keyboard.NOKEY)
139                                                        .setTouchScreen(TouchScreen.FINGER)
140                                                        .setKeyboardState(KeyboardState.SOFT)
141                                                        .setSoftButtons(true)
142                                                        .setNavigation(Navigation.NONAV);
143
144    private static final String TAG_ATTR = "attr";
145    private static final String TAG_ENUM = "enum";
146    private static final String TAG_FLAG = "flag";
147    private static final String ATTR_NAME = "name";
148    private static final String ATTR_VALUE = "value";
149
150    // Device Configuration. Defaults are for a Nexus 4 device.
151    private int mScreenHeight = 1280;
152    private int mScreenWidth = 768;
153    private int mXdpi = 320;
154    private int mYdpi = 320;
155    private ScreenOrientation mOrientation = ScreenOrientation.PORTRAIT;
156    private Density mDensity = Density.XHIGH;
157    private ScreenRatio mRatio = ScreenRatio.NOTLONG;
158    private ScreenSize mSize = ScreenSize.NORMAL;
159    private Keyboard mKeyboard = Keyboard.NOKEY;
160    private TouchScreen mTouchScreen = TouchScreen.FINGER;
161    private KeyboardState mKeyboardState = KeyboardState.SOFT;
162    private boolean mSoftButtons = true;
163    private Navigation mNavigation = Navigation.NONAV;
164
165    public FolderConfiguration getFolderConfig() {
166        FolderConfiguration config = new FolderConfiguration();
167        config.createDefault();
168        config.setDensityQualifier(new DensityQualifier(mDensity));
169        config.setNavigationMethodQualifier(new NavigationMethodQualifier(mNavigation));
170        if (mScreenWidth > mScreenHeight) {
171            config.setScreenDimensionQualifier(new ScreenDimensionQualifier(mScreenWidth,
172                    mScreenHeight));
173        } else {
174            config.setScreenDimensionQualifier(new ScreenDimensionQualifier(mScreenHeight,
175                    mScreenWidth));
176        }
177        config.setScreenRatioQualifier(new ScreenRatioQualifier(mRatio));
178        config.setScreenSizeQualifier(new ScreenSizeQualifier(mSize));
179        config.setTextInputMethodQualifier(new TextInputMethodQualifier(mKeyboard));
180        config.setTouchTypeQualifier(new TouchScreenQualifier(mTouchScreen));
181        config.setKeyboardStateQualifier(new KeyboardStateQualifier(mKeyboardState));
182        config.setScreenOrientationQualifier(new ScreenOrientationQualifier(mOrientation));
183
184        config.updateScreenWidthAndHeight();
185
186        // some default qualifiers.
187        config.setUiModeQualifier(new UiModeQualifier(UiMode.NORMAL));
188        config.setNightModeQualifier(new NightModeQualifier(NightMode.NOTNIGHT));
189        config.setCountryCodeQualifier(new CountryCodeQualifier());
190        config.setLayoutDirectionQualifier(new LayoutDirectionQualifier());
191        config.setNetworkCodeQualifier(new NetworkCodeQualifier());
192        config.setLocaleQualifier(new LocaleQualifier());
193        config.setVersionQualifier(new VersionQualifier());
194        return config;
195    }
196
197    public HardwareConfig getHardwareConfig() {
198        return new HardwareConfig(mScreenWidth, mScreenHeight, mDensity, mXdpi, mYdpi, mSize,
199                mOrientation, null, mSoftButtons);
200    }
201
202    public static Map<String, String> loadProperties(File path) {
203        Properties p = new Properties();
204        Map<String, String> map = Maps.newHashMap();
205        try {
206            p.load(new FileInputStream(path));
207            for (String key : p.stringPropertyNames()) {
208                map.put(key, p.getProperty(key));
209            }
210        } catch (IOException e) {
211            e.printStackTrace();
212        }
213        return map;
214    }
215
216    public static Map<String, Map<String, Integer>> getEnumMap(File path) {
217        Map<String, Map<String, Integer>> map = Maps.newHashMap();
218        try {
219            XmlPullParser xmlPullParser = XmlPullParserFactory.newInstance().newPullParser();
220            xmlPullParser.setInput(new FileInputStream(path), null);
221            int eventType = xmlPullParser.getEventType();
222            String attr = null;
223            while (eventType != XmlPullParser.END_DOCUMENT) {
224                if (eventType == XmlPullParser.START_TAG) {
225                    if (TAG_ATTR.equals(xmlPullParser.getName())) {
226                        attr = xmlPullParser.getAttributeValue(null, ATTR_NAME);
227                    } else if (TAG_ENUM.equals(xmlPullParser.getName())
228                            || TAG_FLAG.equals(xmlPullParser.getName())) {
229                        String name = xmlPullParser.getAttributeValue(null, ATTR_NAME);
230                        String value = xmlPullParser.getAttributeValue(null, ATTR_VALUE);
231                        // Integer.decode cannot handle "ffffffff", see JDK issue 6624867
232                        int i = (int) (long) Long.decode(value);
233                        assert attr != null;
234                        Map<String, Integer> attributeMap = map.get(attr);
235                        if (attributeMap == null) {
236                            attributeMap = Maps.newHashMap();
237                            map.put(attr, attributeMap);
238                        }
239                        attributeMap.put(name, i);
240                    }
241                } else if (eventType == XmlPullParser.END_TAG) {
242                    if (TAG_ATTR.equals(xmlPullParser.getName())) {
243                        attr = null;
244                    }
245                }
246                eventType = xmlPullParser.next();
247            }
248        } catch (XmlPullParserException e) {
249            e.printStackTrace();
250        } catch (IOException e) {
251            e.printStackTrace();
252        }
253        return map;
254    }
255
256    // Methods to set the configuration values.
257
258    public ConfigGenerator setScreenHeight(int height) {
259        mScreenHeight = height;
260        return this;
261    }
262
263    public ConfigGenerator setScreenWidth(int width) {
264        mScreenWidth = width;
265        return this;
266    }
267
268    public ConfigGenerator setXdpi(int xdpi) {
269        mXdpi = xdpi;
270        return this;
271    }
272
273    public ConfigGenerator setYdpi(int ydpi) {
274        mYdpi = ydpi;
275        return this;
276    }
277
278    public ConfigGenerator setOrientation(ScreenOrientation orientation) {
279        mOrientation = orientation;
280        return this;
281    }
282
283    public ConfigGenerator setDensity(Density density) {
284        mDensity = density;
285        return this;
286    }
287
288    public ConfigGenerator setRatio(ScreenRatio ratio) {
289        mRatio = ratio;
290        return this;
291    }
292
293    public ConfigGenerator setSize(ScreenSize size) {
294        mSize = size;
295        return this;
296    }
297
298    public ConfigGenerator setKeyboard(Keyboard keyboard) {
299        mKeyboard = keyboard;
300        return this;
301    }
302
303    public ConfigGenerator setTouchScreen(TouchScreen touchScreen) {
304        mTouchScreen = touchScreen;
305        return this;
306    }
307
308    public ConfigGenerator setKeyboardState(KeyboardState state) {
309        mKeyboardState = state;
310        return this;
311    }
312
313    public ConfigGenerator setSoftButtons(boolean softButtons) {
314        mSoftButtons = softButtons;
315        return this;
316    }
317
318    public ConfigGenerator setNavigation(Navigation navigation) {
319        mNavigation = navigation;
320        return this;
321    }
322}
323