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    private static final String TAG_ATTR = "attr";
130    private static final String TAG_ENUM = "enum";
131    private static final String TAG_FLAG = "flag";
132    private static final String ATTR_NAME = "name";
133    private static final String ATTR_VALUE = "value";
134
135    // Device Configuration. Defaults are for a Nexus 4 device.
136    private int mScreenHeight = 1280;
137    private int mScreenWidth = 768;
138    private int mXdpi = 320;
139    private int mYdpi = 320;
140    private ScreenOrientation mOrientation = ScreenOrientation.PORTRAIT;
141    private Density mDensity = Density.XHIGH;
142    private ScreenRatio mRatio = ScreenRatio.NOTLONG;
143    private ScreenSize mSize = ScreenSize.NORMAL;
144    private Keyboard mKeyboard = Keyboard.NOKEY;
145    private TouchScreen mTouchScreen = TouchScreen.FINGER;
146    private KeyboardState mKeyboardState = KeyboardState.SOFT;
147    private boolean mSoftButtons = true;
148    private Navigation mNavigation = Navigation.NONAV;
149
150    public FolderConfiguration getFolderConfig() {
151        FolderConfiguration config = new FolderConfiguration();
152        config.createDefault();
153        config.setDensityQualifier(new DensityQualifier(mDensity));
154        config.setNavigationMethodQualifier(new NavigationMethodQualifier(mNavigation));
155        if (mScreenWidth > mScreenHeight) {
156            config.setScreenDimensionQualifier(new ScreenDimensionQualifier(mScreenWidth,
157                    mScreenHeight));
158        } else {
159            config.setScreenDimensionQualifier(new ScreenDimensionQualifier(mScreenHeight,
160                    mScreenWidth));
161        }
162        config.setScreenRatioQualifier(new ScreenRatioQualifier(mRatio));
163        config.setScreenSizeQualifier(new ScreenSizeQualifier(mSize));
164        config.setTextInputMethodQualifier(new TextInputMethodQualifier(mKeyboard));
165        config.setTouchTypeQualifier(new TouchScreenQualifier(mTouchScreen));
166        config.setKeyboardStateQualifier(new KeyboardStateQualifier(mKeyboardState));
167        config.setScreenOrientationQualifier(new ScreenOrientationQualifier(mOrientation));
168
169        config.updateScreenWidthAndHeight();
170
171        // some default qualifiers.
172        config.setUiModeQualifier(new UiModeQualifier(UiMode.NORMAL));
173        config.setNightModeQualifier(new NightModeQualifier(NightMode.NOTNIGHT));
174        config.setCountryCodeQualifier(new CountryCodeQualifier());
175        config.setLayoutDirectionQualifier(new LayoutDirectionQualifier());
176        config.setNetworkCodeQualifier(new NetworkCodeQualifier());
177        config.setLocaleQualifier(new LocaleQualifier());
178        config.setVersionQualifier(new VersionQualifier());
179        return config;
180    }
181
182    public HardwareConfig getHardwareConfig() {
183        return new HardwareConfig(mScreenWidth, mScreenHeight, mDensity, mXdpi, mYdpi, mSize,
184                mOrientation, null, mSoftButtons);
185    }
186
187    public static Map<String, String> loadProperties(File path) {
188        Properties p = new Properties();
189        Map<String, String> map = Maps.newHashMap();
190        try {
191            p.load(new FileInputStream(path));
192            for (String key : p.stringPropertyNames()) {
193                map.put(key, p.getProperty(key));
194            }
195        } catch (IOException e) {
196            e.printStackTrace();
197        }
198        return map;
199    }
200
201    public static Map<String, Map<String, Integer>> getEnumMap(File path) {
202        Map<String, Map<String, Integer>> map = Maps.newHashMap();
203        try {
204            XmlPullParser xmlPullParser = XmlPullParserFactory.newInstance().newPullParser();
205            xmlPullParser.setInput(new FileInputStream(path), null);
206            int eventType = xmlPullParser.getEventType();
207            String attr = null;
208            while (eventType != XmlPullParser.END_DOCUMENT) {
209                if (eventType == XmlPullParser.START_TAG) {
210                    if (TAG_ATTR.equals(xmlPullParser.getName())) {
211                        attr = xmlPullParser.getAttributeValue(null, ATTR_NAME);
212                    } else if (TAG_ENUM.equals(xmlPullParser.getName())
213                            || TAG_FLAG.equals(xmlPullParser.getName())) {
214                        String name = xmlPullParser.getAttributeValue(null, ATTR_NAME);
215                        String value = xmlPullParser.getAttributeValue(null, ATTR_VALUE);
216                        // Integer.decode cannot handle "ffffffff", see JDK issue 6624867
217                        int i = (int) (long) Long.decode(value);
218                        assert attr != null;
219                        Map<String, Integer> attributeMap = map.get(attr);
220                        if (attributeMap == null) {
221                            attributeMap = Maps.newHashMap();
222                            map.put(attr, attributeMap);
223                        }
224                        attributeMap.put(name, i);
225                    }
226                } else if (eventType == XmlPullParser.END_TAG) {
227                    if (TAG_ATTR.equals(xmlPullParser.getName())) {
228                        attr = null;
229                    }
230                }
231                eventType = xmlPullParser.next();
232            }
233        } catch (XmlPullParserException e) {
234            e.printStackTrace();
235        } catch (IOException e) {
236            e.printStackTrace();
237        }
238        return map;
239    }
240
241    // Methods to set the configuration values.
242
243    public ConfigGenerator setScreenHeight(int height) {
244        mScreenHeight = height;
245        return this;
246    }
247
248    public ConfigGenerator setScreenWidth(int width) {
249        mScreenWidth = width;
250        return this;
251    }
252
253    public ConfigGenerator setXdpi(int xdpi) {
254        mXdpi = xdpi;
255        return this;
256    }
257
258    public ConfigGenerator setYdpi(int ydpi) {
259        mYdpi = ydpi;
260        return this;
261    }
262
263    public ConfigGenerator setOrientation(ScreenOrientation orientation) {
264        mOrientation = orientation;
265        return this;
266    }
267
268    public ConfigGenerator setDensity(Density density) {
269        mDensity = density;
270        return this;
271    }
272
273    public ConfigGenerator setRatio(ScreenRatio ratio) {
274        mRatio = ratio;
275        return this;
276    }
277
278    public ConfigGenerator setSize(ScreenSize size) {
279        mSize = size;
280        return this;
281    }
282
283    public ConfigGenerator setKeyboard(Keyboard keyboard) {
284        mKeyboard = keyboard;
285        return this;
286    }
287
288    public ConfigGenerator setTouchScreen(TouchScreen touchScreen) {
289        mTouchScreen = touchScreen;
290        return this;
291    }
292
293    public ConfigGenerator setKeyboardState(KeyboardState state) {
294        mKeyboardState = state;
295        return this;
296    }
297
298    public ConfigGenerator setSoftButtons(boolean softButtons) {
299        mSoftButtons = softButtons;
300        return this;
301    }
302
303    public ConfigGenerator setNavigation(Navigation navigation) {
304        mNavigation = navigation;
305        return this;
306    }
307}
308