1 /****************************************************************************
2 **
3 ** Copyright (C) 2014 BogDan Vatra <bogdan@kde.org>
4 ** Contact: https://www.qt.io/licensing/
5 **
6 ** This file is part of the Android port of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see https://www.qt.io/terms-conditions. For further
15 ** information use the contact form at https://www.qt.io/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 3 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL3 included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 3 requirements
23 ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24 **
25 ** GNU General Public License Usage
26 ** Alternatively, this file may be used under the terms of the GNU
27 ** General Public License version 2.0 or (at your option) the GNU General
28 ** Public license version 3 or any later version approved by the KDE Free
29 ** Qt Foundation. The licenses are as published by the Free Software
30 ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31 ** included in the packaging of this file. Please review the following
32 ** information to ensure the GNU General Public License requirements will
33 ** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34 ** https://www.gnu.org/licenses/gpl-3.0.html.
35 **
36 ** $QT_END_LICENSE$
37 **
38 ****************************************************************************/
39 
40 package org.qtproject.qt5.android;
41 
42 import java.io.File;
43 import java.io.FileNotFoundException;
44 import java.io.FileOutputStream;
45 import java.io.IOException;
46 import java.io.OutputStreamWriter;
47 import java.lang.reflect.Field;
48 import java.util.ArrayList;
49 import java.util.HashMap;
50 import java.util.Map;
51 
52 import org.json.JSONArray;
53 import org.json.JSONException;
54 import org.json.JSONObject;
55 import org.xmlpull.v1.XmlPullParser;
56 
57 import android.content.Context;
58 import android.content.res.ColorStateList;
59 import android.content.res.Resources;
60 import android.content.res.TypedArray;
61 import android.content.res.XmlResourceParser;
62 import android.graphics.Bitmap;
63 import android.graphics.Bitmap.Config;
64 import android.graphics.Canvas;
65 import android.graphics.NinePatch;
66 import android.graphics.Paint;
67 import android.graphics.Rect;
68 import android.graphics.RectF;
69 import android.graphics.PorterDuff;
70 import android.graphics.drawable.AnimationDrawable;
71 import android.graphics.drawable.BitmapDrawable;
72 import android.graphics.drawable.ClipDrawable;
73 import android.graphics.drawable.ColorDrawable;
74 import android.graphics.drawable.Drawable;
75 import android.graphics.drawable.GradientDrawable;
76 import android.graphics.drawable.GradientDrawable.Orientation;
77 import android.graphics.drawable.InsetDrawable;
78 import android.graphics.drawable.LayerDrawable;
79 import android.graphics.drawable.NinePatchDrawable;
80 import android.graphics.drawable.RotateDrawable;
81 import android.graphics.drawable.ScaleDrawable;
82 import android.graphics.drawable.StateListDrawable;
83 import android.os.Build;
84 import android.util.AttributeSet;
85 import android.util.Log;
86 import android.util.Xml;
87 import android.view.inputmethod.EditorInfo;
88 
89 
90 public class ExtractStyle {
91 
extractChunkInfo20(byte[] chunkData)92     native static int[] extractChunkInfo20(byte[] chunkData);
extractNativeChunkInfo20(long nativeChunk)93     native static int[] extractNativeChunkInfo20(long nativeChunk);
94 
95     Class<?> styleableClass = getClass("android.R$styleable");
96     Class<?> rippleDrawableClass = getClass("android.graphics.drawable.RippleDrawable");
97     Class<?> animatedStateListDrawableClass = getClass("android.graphics.drawable.AnimatedStateListDrawable");
98     Class<?> vectorDrawableClass = getClass("android.graphics.drawable.VectorDrawable");
99 
100     final int[] EMPTY_STATE_SET = {};
101     final int[] ENABLED_STATE_SET = {android.R.attr.state_enabled};
102     final int[] FOCUSED_STATE_SET = {android.R.attr.state_focused};
103     final int[] SELECTED_STATE_SET = {android.R.attr.state_selected};
104     final int[] PRESSED_STATE_SET = {android.R.attr.state_pressed};
105     final int[] WINDOW_FOCUSED_STATE_SET = {android.R.attr.state_window_focused};
106     final int[] ENABLED_FOCUSED_STATE_SET = stateSetUnion(ENABLED_STATE_SET, FOCUSED_STATE_SET);
107     final int[] ENABLED_SELECTED_STATE_SET = stateSetUnion(ENABLED_STATE_SET, SELECTED_STATE_SET);
108     final int[] ENABLED_WINDOW_FOCUSED_STATE_SET = stateSetUnion(ENABLED_STATE_SET, WINDOW_FOCUSED_STATE_SET);
109     final int[] FOCUSED_SELECTED_STATE_SET = stateSetUnion(FOCUSED_STATE_SET, SELECTED_STATE_SET);
110     final int[] FOCUSED_WINDOW_FOCUSED_STATE_SET = stateSetUnion(FOCUSED_STATE_SET, WINDOW_FOCUSED_STATE_SET);
111     final int[] SELECTED_WINDOW_FOCUSED_STATE_SET = stateSetUnion(SELECTED_STATE_SET, WINDOW_FOCUSED_STATE_SET);
112     final int[] ENABLED_FOCUSED_SELECTED_STATE_SET =  stateSetUnion(ENABLED_FOCUSED_STATE_SET, SELECTED_STATE_SET);
113     final int[] ENABLED_FOCUSED_WINDOW_FOCUSED_STATE_SET = stateSetUnion(ENABLED_FOCUSED_STATE_SET, WINDOW_FOCUSED_STATE_SET);
114     final int[] ENABLED_SELECTED_WINDOW_FOCUSED_STATE_SET = stateSetUnion(ENABLED_SELECTED_STATE_SET, WINDOW_FOCUSED_STATE_SET);
115     final int[] FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET =  stateSetUnion(FOCUSED_SELECTED_STATE_SET, WINDOW_FOCUSED_STATE_SET);
116     final int[] ENABLED_FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET = stateSetUnion(ENABLED_FOCUSED_SELECTED_STATE_SET, WINDOW_FOCUSED_STATE_SET);
117     final int[] PRESSED_WINDOW_FOCUSED_STATE_SET = stateSetUnion(PRESSED_STATE_SET, WINDOW_FOCUSED_STATE_SET);
118     final int[] PRESSED_SELECTED_STATE_SET = stateSetUnion(PRESSED_STATE_SET, SELECTED_STATE_SET);
119     final int[] PRESSED_SELECTED_WINDOW_FOCUSED_STATE_SET = stateSetUnion(PRESSED_SELECTED_STATE_SET, WINDOW_FOCUSED_STATE_SET);
120     final int[] PRESSED_FOCUSED_STATE_SET = stateSetUnion(PRESSED_STATE_SET, FOCUSED_STATE_SET);
121     final int[] PRESSED_FOCUSED_WINDOW_FOCUSED_STATE_SET = stateSetUnion(PRESSED_FOCUSED_STATE_SET, WINDOW_FOCUSED_STATE_SET);
122     final int[] PRESSED_FOCUSED_SELECTED_STATE_SET = stateSetUnion(PRESSED_FOCUSED_STATE_SET, SELECTED_STATE_SET);
123     final int[] PRESSED_FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET = stateSetUnion(PRESSED_FOCUSED_SELECTED_STATE_SET, WINDOW_FOCUSED_STATE_SET);
124     final int[] PRESSED_ENABLED_STATE_SET = stateSetUnion(PRESSED_STATE_SET, ENABLED_STATE_SET);
125     final int[] PRESSED_ENABLED_WINDOW_FOCUSED_STATE_SET = stateSetUnion(PRESSED_ENABLED_STATE_SET, WINDOW_FOCUSED_STATE_SET);
126     final int[] PRESSED_ENABLED_SELECTED_STATE_SET = stateSetUnion(PRESSED_ENABLED_STATE_SET, SELECTED_STATE_SET);
127     final int[] PRESSED_ENABLED_SELECTED_WINDOW_FOCUSED_STATE_SET = stateSetUnion(PRESSED_ENABLED_SELECTED_STATE_SET, WINDOW_FOCUSED_STATE_SET);
128     final int[] PRESSED_ENABLED_FOCUSED_STATE_SET = stateSetUnion(PRESSED_ENABLED_STATE_SET, FOCUSED_STATE_SET);
129     final int[] PRESSED_ENABLED_FOCUSED_WINDOW_FOCUSED_STATE_SET = stateSetUnion(PRESSED_ENABLED_FOCUSED_STATE_SET, WINDOW_FOCUSED_STATE_SET);
130     final int[] PRESSED_ENABLED_FOCUSED_SELECTED_STATE_SET = stateSetUnion(PRESSED_ENABLED_FOCUSED_STATE_SET, SELECTED_STATE_SET);
131     final int[] PRESSED_ENABLED_FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET = stateSetUnion(PRESSED_ENABLED_FOCUSED_SELECTED_STATE_SET, WINDOW_FOCUSED_STATE_SET);
132 
133 
134     final int View_background = getField(styleableClass,"View_background");
135     final int View_padding = getField(styleableClass,"View_padding");
136     final int View_paddingLeft = getField(styleableClass,"View_paddingLeft");
137     final int View_paddingTop = getField(styleableClass,"View_paddingTop");
138     final int View_paddingRight = getField(styleableClass,"View_paddingRight");
139     final int View_paddingBottom = getField(styleableClass,"View_paddingBottom");
140     final int View_scrollX = getField(styleableClass,"View_scrollX");
141     final int View_scrollY = getField(styleableClass,"View_scrollY");
142     final int View_id = getField(styleableClass,"View_id");
143     final int View_tag = getField(styleableClass,"View_tag");
144     final int View_fitsSystemWindows = getField(styleableClass,"View_fitsSystemWindows");
145     final int View_focusable = getField(styleableClass,"View_focusable");
146     final int View_focusableInTouchMode = getField(styleableClass,"View_focusableInTouchMode");
147     final int View_clickable = getField(styleableClass,"View_clickable");
148     final int View_longClickable = getField(styleableClass,"View_longClickable");
149     final int View_saveEnabled = getField(styleableClass,"View_saveEnabled");
150     final int View_duplicateParentState = getField(styleableClass,"View_duplicateParentState");
151     final int View_visibility = getField(styleableClass,"View_visibility");
152     final int View_drawingCacheQuality = getField(styleableClass,"View_drawingCacheQuality");
153     final int View_contentDescription = getField(styleableClass,"View_contentDescription");
154     final int View_soundEffectsEnabled = getField(styleableClass,"View_soundEffectsEnabled");
155     final int View_hapticFeedbackEnabled = getField(styleableClass,"View_hapticFeedbackEnabled");
156     final int View_scrollbars = getField(styleableClass,"View_scrollbars");
157     final int View_fadingEdge = getField(styleableClass,"View_fadingEdge");
158     final int View_scrollbarStyle = getField(styleableClass,"View_scrollbarStyle");
159     final int View_scrollbarFadeDuration = getField(styleableClass,"View_scrollbarFadeDuration");
160     final int View_scrollbarDefaultDelayBeforeFade = getField(styleableClass,"View_scrollbarDefaultDelayBeforeFade");
161     final int View_scrollbarSize = getField(styleableClass,"View_scrollbarSize");
162     final int View_scrollbarThumbHorizontal = getField(styleableClass,"View_scrollbarThumbHorizontal");
163     final int View_scrollbarThumbVertical = getField(styleableClass,"View_scrollbarThumbVertical");
164     final int View_scrollbarTrackHorizontal = getField(styleableClass,"View_scrollbarTrackHorizontal");
165     final int View_scrollbarTrackVertical = getField(styleableClass,"View_scrollbarTrackVertical");
166     final int View_isScrollContainer = getField(styleableClass,"View_isScrollContainer");
167     final int View_keepScreenOn = getField(styleableClass,"View_keepScreenOn");
168     final int View_filterTouchesWhenObscured = getField(styleableClass,"View_filterTouchesWhenObscured");
169     final int View_nextFocusLeft = getField(styleableClass,"View_nextFocusLeft");
170     final int View_nextFocusRight = getField(styleableClass,"View_nextFocusRight");
171     final int View_nextFocusUp = getField(styleableClass,"View_nextFocusUp");
172     final int View_nextFocusDown = getField(styleableClass,"View_nextFocusDown");
173     final int View_minWidth = getField(styleableClass,"View_minWidth");
174     final int View_minHeight = getField(styleableClass,"View_minHeight");
175     final int View_onClick = getField(styleableClass,"View_onClick");
176     final int View_overScrollMode = getField(styleableClass,"View_overScrollMode");
177     final int View_paddingStart = getField(styleableClass,"View_paddingStart");
178     final int View_paddingEnd = getField(styleableClass,"View_paddingEnd");
179 
180     final int TextAppearance_textColorHighlight = getField(styleableClass,"TextAppearance_textColorHighlight");
181     final int TextAppearance_textColor = getField(styleableClass,"TextAppearance_textColor");
182     final int TextAppearance_textColorHint = getField(styleableClass,"TextAppearance_textColorHint");
183     final int TextAppearance_textColorLink = getField(styleableClass,"TextAppearance_textColorLink");
184     final int TextAppearance_textSize = getField(styleableClass,"TextAppearance_textSize");
185     final int TextAppearance_typeface = getField(styleableClass,"TextAppearance_typeface");
186     final int TextAppearance_textStyle = getField(styleableClass,"TextAppearance_textStyle");
187     final int TextAppearance_textAllCaps = getField(styleableClass,"TextAppearance_textAllCaps");
188     final int TextView_editable = getField(styleableClass,"TextView_editable");
189     final int TextView_inputMethod = getField(styleableClass,"TextView_inputMethod");
190     final int TextView_numeric = getField(styleableClass,"TextView_numeric");
191     final int TextView_digits = getField(styleableClass,"TextView_digits");
192     final int TextView_phoneNumber = getField(styleableClass,"TextView_phoneNumber");
193     final int TextView_autoText = getField(styleableClass,"TextView_autoText");
194     final int TextView_capitalize = getField(styleableClass,"TextView_capitalize");
195     final int TextView_bufferType = getField(styleableClass,"TextView_bufferType");
196     final int TextView_selectAllOnFocus = getField(styleableClass,"TextView_selectAllOnFocus");
197     final int TextView_autoLink = getField(styleableClass,"TextView_autoLink");
198     final int TextView_linksClickable = getField(styleableClass,"TextView_linksClickable");
199     final int TextView_drawableLeft = getField(styleableClass,"TextView_drawableLeft");
200     final int TextView_drawableTop = getField(styleableClass,"TextView_drawableTop");
201     final int TextView_drawableRight = getField(styleableClass,"TextView_drawableRight");
202     final int TextView_drawableBottom = getField(styleableClass,"TextView_drawableBottom");
203     final int TextView_drawableStart = getField(styleableClass,"TextView_drawableStart");
204     final int TextView_drawableEnd = getField(styleableClass,"TextView_drawableEnd");
205     final int TextView_drawablePadding = getField(styleableClass,"TextView_drawablePadding");
206     final int TextView_textCursorDrawable = getField(styleableClass,"TextView_textCursorDrawable");
207     final int TextView_maxLines = getField(styleableClass,"TextView_maxLines");
208     final int TextView_maxHeight = getField(styleableClass,"TextView_maxHeight");
209     final int TextView_lines = getField(styleableClass,"TextView_lines");
210     final int TextView_height = getField(styleableClass,"TextView_height");
211     final int TextView_minLines = getField(styleableClass,"TextView_minLines");
212     final int TextView_minHeight = getField(styleableClass,"TextView_minHeight");
213     final int TextView_maxEms = getField(styleableClass,"TextView_maxEms");
214     final int TextView_maxWidth = getField(styleableClass,"TextView_maxWidth");
215     final int TextView_ems = getField(styleableClass,"TextView_ems");
216     final int TextView_width = getField(styleableClass,"TextView_width");
217     final int TextView_minEms = getField(styleableClass,"TextView_minEms");
218     final int TextView_minWidth = getField(styleableClass,"TextView_minWidth");
219     final int TextView_gravity = getField(styleableClass,"TextView_gravity");
220     final int TextView_hint = getField(styleableClass,"TextView_hint");
221     final int TextView_text = getField(styleableClass,"TextView_text");
222     final int TextView_scrollHorizontally = getField(styleableClass,"TextView_scrollHorizontally");
223     final int TextView_singleLine = getField(styleableClass,"TextView_singleLine");
224     final int TextView_ellipsize = getField(styleableClass,"TextView_ellipsize");
225     final int TextView_marqueeRepeatLimit = getField(styleableClass,"TextView_marqueeRepeatLimit");
226     final int TextView_includeFontPadding = getField(styleableClass,"TextView_includeFontPadding");
227     final int TextView_cursorVisible = getField(styleableClass,"TextView_cursorVisible");
228     final int TextView_maxLength = getField(styleableClass,"TextView_maxLength");
229     final int TextView_textScaleX = getField(styleableClass,"TextView_textScaleX");
230     final int TextView_freezesText = getField(styleableClass,"TextView_freezesText");
231     final int TextView_shadowColor = getField(styleableClass,"TextView_shadowColor");
232     final int TextView_shadowDx = getField(styleableClass,"TextView_shadowDx");
233     final int TextView_shadowDy = getField(styleableClass,"TextView_shadowDy");
234     final int TextView_shadowRadius = getField(styleableClass,"TextView_shadowRadius");
235     final int TextView_enabled = getField(styleableClass,"TextView_enabled");
236     final int TextView_textColorHighlight = getField(styleableClass,"TextView_textColorHighlight");
237     final int TextView_textColor = getField(styleableClass,"TextView_textColor");
238     final int TextView_textColorHint = getField(styleableClass,"TextView_textColorHint");
239     final int TextView_textColorLink = getField(styleableClass,"TextView_textColorLink");
240     final int TextView_textSize = getField(styleableClass,"TextView_textSize");
241     final int TextView_typeface = getField(styleableClass,"TextView_typeface");
242     final int TextView_textStyle = getField(styleableClass,"TextView_textStyle");
243     final int TextView_password = getField(styleableClass,"TextView_password");
244     final int TextView_lineSpacingExtra = getField(styleableClass,"TextView_lineSpacingExtra");
245     final int TextView_lineSpacingMultiplier = getField(styleableClass,"TextView_lineSpacingMultiplier");
246     final int TextView_inputType = getField(styleableClass,"TextView_inputType");
247     final int TextView_imeOptions = getField(styleableClass,"TextView_imeOptions");
248     final int TextView_imeActionLabel = getField(styleableClass,"TextView_imeActionLabel");
249     final int TextView_imeActionId = getField(styleableClass,"TextView_imeActionId");
250     final int TextView_privateImeOptions = getField(styleableClass,"TextView_privateImeOptions");
251     final int TextView_textSelectHandleLeft = getField(styleableClass,"TextView_textSelectHandleLeft");
252     final int TextView_textSelectHandleRight = getField(styleableClass,"TextView_textSelectHandleRight");
253     final int TextView_textSelectHandle = getField(styleableClass,"TextView_textSelectHandle");
254     final int TextView_textIsSelectable = getField(styleableClass,"TextView_textIsSelectable");
255     final int TextView_textAllCaps = getField(styleableClass,"TextView_textAllCaps");
256 
257     final int ImageView_src = getField(styleableClass,"ImageView_src");
258     final int ImageView_baselineAlignBottom = getField(styleableClass,"ImageView_baselineAlignBottom");
259     final int ImageView_adjustViewBounds = getField(styleableClass,"ImageView_adjustViewBounds");
260     final int ImageView_maxWidth = getField(styleableClass,"ImageView_maxWidth");
261     final int ImageView_maxHeight = getField(styleableClass,"ImageView_maxHeight");
262     final int ImageView_scaleType = getField(styleableClass,"ImageView_scaleType");
263     final int ImageView_tint = getField(styleableClass,"ImageView_tint");
264     final int ImageView_cropToPadding = getField(styleableClass,"ImageView_cropToPadding");
265 
266     final Resources.Theme m_theme;
267     final String m_extractPath;
268     Context m_context;
269     final int defaultBackgroundColor;
270     final int defaultTextColor;
271     final boolean m_minimal;
272 
273     class SimpleJsonWriter
274     {
275         private OutputStreamWriter m_writer;
276         private boolean m_addComma = false;
277         private int m_indentLevel = 0;
SimpleJsonWriter(String filePath)278         public SimpleJsonWriter(String filePath) throws FileNotFoundException
279         {
280             m_writer = new OutputStreamWriter(new FileOutputStream(filePath));
281         }
282 
close()283         public void close() throws IOException
284         {
285             m_writer.close();
286         }
287 
writeIndent()288         private void writeIndent() throws IOException
289         {
290            m_writer.write(" ", 0, m_indentLevel);
291         }
292 
beginObject()293         SimpleJsonWriter beginObject() throws IOException
294         {
295             writeIndent();
296             m_writer.write("{\n");
297             ++m_indentLevel;
298             m_addComma = false;
299             return this;
300         }
301 
endObject()302         SimpleJsonWriter endObject() throws IOException
303         {
304             m_writer.write("\n");
305             writeIndent();
306             m_writer.write("}\n");
307             --m_indentLevel;
308             m_addComma = false;
309             return this;
310         }
311 
name(String name)312         SimpleJsonWriter name(String name) throws IOException
313         {
314             if (m_addComma) {
315                 m_writer.write(",\n");
316             }
317             writeIndent();
318             m_writer.write(JSONObject.quote(name) + ": ");
319             m_addComma = true;
320             return this;
321         }
322 
value(JSONObject value)323         SimpleJsonWriter value(JSONObject value) throws IOException
324         {
325             m_writer.write(value.toString());
326             return this;
327         }
328     }
329 
330     class FakeCanvas extends Canvas {
331         int[] chunkData = null;
332         class Size {
333             public int s,e;
Size(int start, int end)334             Size(int start, int end)
335             {
336                 s=start;
337                 e=end;
338             }
339         }
340 
isHardwareAccelerated()341         public boolean isHardwareAccelerated() {
342             return true;
343         }
344 
drawPatch(Bitmap bmp, byte[] chunks, RectF dst, Paint paint)345         public void drawPatch(Bitmap bmp, byte[] chunks, RectF dst, Paint paint) {
346             chunkData = extractChunkInfo20(chunks);
347         }
348     }
349 
350 
351 
stateSetUnion(final int[] stateSet1, final int[] stateSet2)352     private int[] stateSetUnion(final int[] stateSet1, final int[] stateSet2)
353     {
354         try
355         {
356             final int stateSet1Length = stateSet1.length;
357             final int stateSet2Length = stateSet2.length;
358             final int[] newSet = new int[stateSet1Length + stateSet2Length];
359             int k = 0;
360             int i = 0;
361             int j = 0;
362             // This is a merge of the two input state sets and assumes that the
363             // input sets are sorted by the order imposed by ViewDrawableStates.
364             int[] viewDrawableStatesState=(int[]) styleableClass.getDeclaredField("ViewDrawableStates").get(null);
365             for (int viewState : viewDrawableStatesState)
366             {
367                 if (i < stateSet1Length && stateSet1[i] == viewState)
368                 {
369                     newSet[k++] = viewState;
370                     i++;
371                 } else if (j < stateSet2Length && stateSet2[j] == viewState) {
372                     newSet[k++] = viewState;
373                     j++;
374                 }
375                 if (k > 1) {
376                     assert(newSet[k - 1] > newSet[k - 2]);
377                 }
378             }
379             return newSet;
380         }
381         catch(Exception e)
382         {
383             e.printStackTrace();
384         }
385         return null;
386     }
387 
getClass(String className)388     private Class<?> getClass(String className) {
389         try {
390             return Class.forName(className);
391         } catch (ClassNotFoundException e) {
392             e.printStackTrace();
393         }
394         return null;
395     }
396 
getAccessibleField(Class<?> clazz, String fieldName)397     Field getAccessibleField(Class<?> clazz, String fieldName) {
398         try {
399             Field f = clazz.getDeclaredField(fieldName);
400             f.setAccessible(true);
401             return f;
402         } catch (Exception e) {
403             e.printStackTrace();
404         }
405         return null;
406     }
407 
tryGetAccessibleField(Class<?> clazz, String fieldName)408     Field tryGetAccessibleField(Class<?> clazz, String fieldName) {
409         if (clazz == null)
410             return null;
411 
412         try {
413             Field f = clazz.getDeclaredField(fieldName);
414             f.setAccessible(true);
415             return f;
416         } catch (Exception e) {
417             for (Class<?> c : clazz.getInterfaces()) {
418                 Field f = tryGetAccessibleField(c, fieldName);
419                 if (f != null)
420                     return f;
421             }
422         }
423         return tryGetAccessibleField(clazz.getSuperclass(), fieldName);
424     }
425 
getField(Class<?> clazz, String fieldName)426     int getField(Class<?> clazz, String fieldName)
427     {
428         try {
429             return clazz.getDeclaredField(fieldName).getInt(null);
430         } catch (Exception e) {
431             e.printStackTrace();
432         }
433         return -1;
434     }
435 
getColorStateList(ColorStateList colorList)436     JSONObject getColorStateList(ColorStateList colorList)
437     {
438         JSONObject json = new JSONObject();
439         try
440         {
441             json.put("EMPTY_STATE_SET", colorList.getColorForState(EMPTY_STATE_SET, 0));
442             json.put("WINDOW_FOCUSED_STATE_SET", colorList.getColorForState(WINDOW_FOCUSED_STATE_SET, 0));
443             json.put("SELECTED_STATE_SET", colorList.getColorForState(SELECTED_STATE_SET, 0));
444             json.put("SELECTED_WINDOW_FOCUSED_STATE_SET", colorList.getColorForState(SELECTED_WINDOW_FOCUSED_STATE_SET, 0));
445             json.put("FOCUSED_STATE_SET", colorList.getColorForState(FOCUSED_STATE_SET, 0));
446             json.put("FOCUSED_WINDOW_FOCUSED_STATE_SET", colorList.getColorForState(FOCUSED_WINDOW_FOCUSED_STATE_SET, 0));
447             json.put("FOCUSED_SELECTED_STATE_SET", colorList.getColorForState(FOCUSED_SELECTED_STATE_SET, 0));
448             json.put("FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET", colorList.getColorForState(FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET, 0));
449             json.put("ENABLED_STATE_SET", colorList.getColorForState(ENABLED_STATE_SET, 0));
450             json.put("ENABLED_WINDOW_FOCUSED_STATE_SET", colorList.getColorForState(ENABLED_WINDOW_FOCUSED_STATE_SET, 0));
451             json.put("ENABLED_SELECTED_STATE_SET", colorList.getColorForState(ENABLED_SELECTED_STATE_SET, 0));
452             json.put("ENABLED_SELECTED_WINDOW_FOCUSED_STATE_SET", colorList.getColorForState(ENABLED_SELECTED_WINDOW_FOCUSED_STATE_SET, 0));
453             json.put("ENABLED_FOCUSED_STATE_SET", colorList.getColorForState(ENABLED_FOCUSED_STATE_SET, 0));
454             json.put("ENABLED_FOCUSED_WINDOW_FOCUSED_STATE_SET", colorList.getColorForState(ENABLED_FOCUSED_WINDOW_FOCUSED_STATE_SET, 0));
455             json.put("ENABLED_FOCUSED_SELECTED_STATE_SET", colorList.getColorForState(ENABLED_FOCUSED_SELECTED_STATE_SET, 0));
456             json.put("ENABLED_FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET", colorList.getColorForState(ENABLED_FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET, 0));
457             json.put("PRESSED_STATE_SET", colorList.getColorForState(PRESSED_STATE_SET, 0));
458             json.put("PRESSED_WINDOW_FOCUSED_STATE_SET", colorList.getColorForState(PRESSED_WINDOW_FOCUSED_STATE_SET, 0));
459             json.put("PRESSED_SELECTED_STATE_SET", colorList.getColorForState(PRESSED_SELECTED_STATE_SET, 0));
460             json.put("PRESSED_SELECTED_WINDOW_FOCUSED_STATE_SET", colorList.getColorForState(PRESSED_SELECTED_WINDOW_FOCUSED_STATE_SET, 0));
461             json.put("PRESSED_FOCUSED_STATE_SET", colorList.getColorForState(PRESSED_FOCUSED_STATE_SET, 0));
462             json.put("PRESSED_FOCUSED_WINDOW_FOCUSED_STATE_SET", colorList.getColorForState(PRESSED_FOCUSED_WINDOW_FOCUSED_STATE_SET, 0));
463             json.put("PRESSED_FOCUSED_SELECTED_STATE_SET", colorList.getColorForState(PRESSED_FOCUSED_SELECTED_STATE_SET, 0));
464             json.put("PRESSED_FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET", colorList.getColorForState(PRESSED_FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET, 0));
465             json.put("PRESSED_ENABLED_STATE_SET", colorList.getColorForState(PRESSED_ENABLED_STATE_SET, 0));
466             json.put("PRESSED_ENABLED_WINDOW_FOCUSED_STATE_SET", colorList.getColorForState(PRESSED_ENABLED_WINDOW_FOCUSED_STATE_SET, 0));
467             json.put("PRESSED_ENABLED_SELECTED_STATE_SET", colorList.getColorForState(PRESSED_ENABLED_SELECTED_STATE_SET, 0));
468             json.put("PRESSED_ENABLED_SELECTED_WINDOW_FOCUSED_STATE_SET", colorList.getColorForState(PRESSED_ENABLED_SELECTED_WINDOW_FOCUSED_STATE_SET, 0));
469             json.put("PRESSED_ENABLED_FOCUSED_STATE_SET", colorList.getColorForState(PRESSED_ENABLED_FOCUSED_STATE_SET, 0));
470             json.put("PRESSED_ENABLED_FOCUSED_WINDOW_FOCUSED_STATE_SET", colorList.getColorForState(PRESSED_ENABLED_FOCUSED_WINDOW_FOCUSED_STATE_SET, 0));
471             json.put("PRESSED_ENABLED_FOCUSED_SELECTED_STATE_SET", colorList.getColorForState(PRESSED_ENABLED_FOCUSED_SELECTED_STATE_SET, 0));
472             json.put("PRESSED_ENABLED_FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET", colorList.getColorForState(PRESSED_ENABLED_FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET, 0));
473         } catch (JSONException e) {
474             e.printStackTrace();
475         }
476 
477         return json;
478     }
479 
480     final int [] DrawableStates ={android.R.attr.state_active, android.R.attr.state_checked
481                                 , android.R.attr.state_enabled, android.R.attr.state_focused
482                                 , android.R.attr.state_pressed, android.R.attr.state_selected
483                                 , android.R.attr.state_window_focused, 16908288, 16843597, 16843518, 16843547};
484     final String[] DrawableStatesLabels = {"active", "checked", "enabled", "focused", "pressed", "selected", "window_focused", "background", "multiline", "activated", "accelerated"};
485     final String[] DisableDrawableStatesLabels = {"inactive", "unchecked", "disabled", "not_focused", "no_pressed", "unselected", "window_not_focused", "background", "multiline", "activated", "accelerated"};
486 
getFileName(String file, String[] states)487     String getFileName(String file, String[] states)
488     {
489         for (String state: states)
490             file+="__"+state;
491         return file;
492     }
493 
getStatesName(String[] states)494     String getStatesName(String[] states)
495     {
496         String statesName="";
497         for (String state: states)
498         {
499             if (statesName.length()>0)
500                 statesName+="__";
501             statesName += state;
502         }
503         return statesName;
504     }
505 
addDrawableItemIfNotExists(JSONObject json, ArrayList<Integer> list, Drawable item, String[] states, String filename)506     void addDrawableItemIfNotExists(JSONObject json, ArrayList<Integer> list, Drawable item, String[] states, String filename)
507     {
508         for (Integer it : list)
509         {
510             if (it.equals(item.hashCode()))
511                 return;
512         }
513         list.add(item.hashCode());
514         try {
515             json.put(getStatesName(states), getDrawable(item, getFileName(filename, states), null));
516         } catch (JSONException e) {
517             e.printStackTrace();
518         }
519     }
520 
addSolution(String filename, JSONObject json, int c, Drawable drawable, ArrayList<Integer> drawableList, int u)521     void addSolution(String filename, JSONObject json, int c, Drawable drawable, ArrayList<Integer> drawableList, int u)
522     {
523         int pos=0;
524         int states[] = new int[c];
525         String [] statesText = new String[c];
526 
527         for (int n= 0;u > 0;++n, u>>= 1)
528                 if ((u & 1) > 0)
529                 {
530                     statesText[pos]=DrawableStatesLabels[n];
531                     states[pos++]=DrawableStates[n];
532                 }
533         drawable.setState(states);
534         addDrawableItemIfNotExists(json, drawableList, drawable.getCurrent(), statesText, filename);
535     }
536 
bitCount(int u)537     int bitCount(int u)
538     {
539         int n;
540         for (n= 0;u > 0;++n, u&= (u - 1));
541             return n;
542     }
543 
getStatesList(int [] states)544     JSONObject getStatesList(int [] states) throws JSONException
545     {
546         JSONObject json = new JSONObject();
547         for (int s : states)
548         {
549             boolean found=false;
550             for (int d = 0;d<DrawableStates.length;d++)
551             {
552                 if (s==DrawableStates[d])
553                 {
554                     json.put(DrawableStatesLabels[d], true);
555                     found=true;
556                     break;
557                 }
558                 else if (s==-DrawableStates[d])
559                 {
560                     json.put(DrawableStatesLabels[d], false);
561 
562                     found=true;
563                     break;
564                 }
565             }
566             if (!found)
567             {
568                 json.put("unhandled_state_"+s,s>0);
569             }
570         }
571         return json;
572     }
573 
getStatesName(int [] states)574     String getStatesName(int [] states)
575     {
576         String statesName="";
577         for (int s : states)
578         {
579             boolean found=false;
580             for (int d = 0;d<DrawableStates.length;d++)
581             {
582                 if (s==DrawableStates[d])
583                 {
584                     if (statesName.length()>0)
585                         statesName+="__";
586                     statesName+=DrawableStatesLabels[d];
587                     found=true;
588                     break;
589                 }
590                 else if (s==-DrawableStates[d])
591                 {
592                     if (statesName.length()>0)
593                         statesName+="__";
594                     statesName+=DisableDrawableStatesLabels[d];
595                     found=true;
596                     break;
597                 }
598             }
599             if (!found)
600             {
601                 if (statesName.length()>0)
602                     statesName+=";";
603                 statesName+=s;
604             }
605         }
606         if (statesName.length()>0)
607             return statesName;
608         return "empty";
609     }
610 
getLayerDrawable(Object drawable, String filename)611     private JSONObject getLayerDrawable(Object drawable, String filename)
612     {
613         JSONObject json = new JSONObject();
614         LayerDrawable layers = (LayerDrawable) drawable;
615         final int nr=layers.getNumberOfLayers();
616         try {
617             JSONArray array =new JSONArray();
618             for (int i = 0; i < nr; i++)
619             {
620                 int id = layers.getId(i);
621                 if (id == -1)
622                     id = i;
623                 JSONObject layerJsonObject=getDrawable(layers.getDrawable(i), filename+"__"+id, null);
624                 layerJsonObject.put("id", id);
625                 array.put(layerJsonObject);
626             }
627             json.put("type", "layer");
628             Rect padding = new Rect();
629             if (layers.getPadding(padding))
630                 json.put("padding", getJsonRect(padding));
631             json.put("layers", array);
632         } catch (JSONException e) {
633             e.printStackTrace();
634         }
635         return json;
636     }
637 
getStateListDrawable(Object drawable, String filename)638     private JSONObject getStateListDrawable(Object drawable, String filename)
639     {
640         JSONObject json = new JSONObject();
641         try {
642             StateListDrawable stateList = (StateListDrawable) drawable;
643             final int numStates = (Integer) StateListDrawable.class.getMethod("getStateCount").invoke(stateList);
644             JSONArray array =new JSONArray();
645             for (int i = 0; i < numStates; i++)
646             {
647                 JSONObject stateJson = new JSONObject();
648                 final Drawable d =  (Drawable) StateListDrawable.class.getMethod("getStateDrawable", Integer.TYPE).invoke(stateList, i);
649                 final int [] states = (int[]) StateListDrawable.class.getMethod("getStateSet", Integer.TYPE).invoke(stateList, i);
650                 if (states != null)
651                     stateJson.put("states", getStatesList(states));
652                 stateJson.put("drawable", getDrawable(d, filename+"__" + (states != null ? getStatesName(states) : ("state_pos_" + i)), null));
653                 array.put(stateJson);
654             }
655             json.put("type", "stateslist");
656             Rect padding = new Rect();
657             if (stateList.getPadding(padding))
658                 json.put("padding", getJsonRect(padding));
659             json.put("stateslist", array);
660         } catch (Exception e) {
661             e.printStackTrace();
662         }
663         return json;
664     }
665 
getGradientDrawable(GradientDrawable drawable)666     private JSONObject getGradientDrawable(GradientDrawable drawable) {
667         JSONObject json = new JSONObject();
668         try {
669             json.put("type", "gradient");
670             Object obj=drawable.getConstantState();
671             Class<?> gradientStateClass=obj.getClass();
672             json.put("shape",gradientStateClass.getField("mShape").getInt(obj));
673             json.put("gradient",gradientStateClass.getField("mGradient").getInt(obj));
674             GradientDrawable.Orientation orientation=(Orientation) gradientStateClass.getField("mOrientation").get(obj);
675             json.put("orientation",orientation.name());
676             int [] intArray=(int[]) gradientStateClass.getField((Build.VERSION.SDK_INT < 23) ? "mColors" : "mGradientColors").get(obj);
677             if (intArray != null)
678                 json.put("colors",getJsonArray(intArray, 0, intArray.length));
679             json.put("positions",getJsonArray((float[]) gradientStateClass.getField("mPositions").get(obj)));
680             json.put("strokeWidth",gradientStateClass.getField("mStrokeWidth").getInt(obj));
681             json.put("strokeDashWidth",gradientStateClass.getField("mStrokeDashWidth").getFloat(obj));
682             json.put("strokeDashGap",gradientStateClass.getField("mStrokeDashGap").getFloat(obj));
683             json.put("radius",gradientStateClass.getField("mRadius").getFloat(obj));
684             float [] floatArray=(float[]) gradientStateClass.getField("mRadiusArray").get(obj);
685             if (floatArray!=null)
686                 json.put("radiusArray",getJsonArray(floatArray));
687             Rect rc= (Rect) gradientStateClass.getField("mPadding").get(obj);
688             if (rc!=null)
689                 json.put("padding",getJsonRect(rc));
690             json.put("width",gradientStateClass.getField("mWidth").getInt(obj));
691             json.put("height",gradientStateClass.getField("mHeight").getInt(obj));
692             json.put("innerRadiusRatio",gradientStateClass.getField("mInnerRadiusRatio").getFloat(obj));
693             json.put("thicknessRatio",gradientStateClass.getField("mThicknessRatio").getFloat(obj));
694             json.put("innerRadius",gradientStateClass.getField("mInnerRadius").getInt(obj));
695             json.put("thickness",gradientStateClass.getField("mThickness").getInt(obj));
696         } catch (Exception e) {
697             e.printStackTrace();
698         }
699         return json;
700     }
701 
getRotateDrawable(RotateDrawable drawable, String filename)702     private JSONObject getRotateDrawable(RotateDrawable drawable, String filename) {
703         JSONObject json = new JSONObject();
704         try {
705             json.put("type", "rotate");
706             Object obj = drawable.getConstantState();
707             Class<?> rotateStateClass = obj.getClass();
708             if (Build.VERSION.SDK_INT < 23)
709                 json.put("drawable", getDrawable(getAccessibleField(rotateStateClass, "mDrawable").get(obj), filename, null));
710             else
711                 json.put("drawable", getDrawable(drawable.getClass().getMethod("getDrawable").invoke(drawable), filename, null));
712             json.put("pivotX", getAccessibleField(rotateStateClass, "mPivotX").getFloat(obj));
713             json.put("pivotXRel", getAccessibleField(rotateStateClass, "mPivotXRel").getBoolean(obj));
714             json.put("pivotY", getAccessibleField(rotateStateClass, "mPivotY").getFloat(obj));
715             json.put("pivotYRel", getAccessibleField(rotateStateClass, "mPivotYRel").getBoolean(obj));
716             json.put("fromDegrees", getAccessibleField(rotateStateClass, "mFromDegrees").getFloat(obj));
717             json.put("toDegrees", getAccessibleField(rotateStateClass, "mToDegrees").getFloat(obj));
718         } catch (Exception e) {
719             e.printStackTrace();
720         }
721         return json;
722     }
723 
getAnimationDrawable(AnimationDrawable drawable, String filename)724     private JSONObject getAnimationDrawable(AnimationDrawable drawable, String filename) {
725         JSONObject json = new JSONObject();
726         try {
727             json.put("type", "animation");
728             json.put("oneshot", drawable.isOneShot());
729             final int count = drawable.getNumberOfFrames();
730             JSONArray frames = new JSONArray();
731             for (int i = 0; i < count; ++i)
732             {
733                 JSONObject frame = new JSONObject();
734                 frame.put("duration", drawable.getDuration(i));
735                 frame.put("drawable", getDrawable(drawable.getFrame(i), filename+"__"+i, null));
736                 frames.put(frame);
737             }
738             json.put("frames", frames);
739         } catch (Exception e) {
740             e.printStackTrace();
741         }
742         return json;
743     }
744 
getJsonRect(Rect rect)745     private JSONObject getJsonRect(Rect rect) throws JSONException
746     {
747         JSONObject jsonRect = new JSONObject();
748         jsonRect.put("left", rect.left);
749         jsonRect.put("top", rect.top);
750         jsonRect.put("right", rect.right);
751         jsonRect.put("bottom", rect.bottom);
752         return jsonRect;
753 
754     }
755 
getJsonArray(int[] array, int pos, int len)756     private JSONArray getJsonArray(int[] array, int pos, int len)
757     {
758         JSONArray a = new JSONArray();
759         final int l = pos+len;
760         for (int i=pos; i<l;i++)
761             a.put(array[i]);
762         return a;
763     }
764 
getJsonArray(float[] array)765     private JSONArray getJsonArray(float[] array) throws JSONException
766     {
767         JSONArray a = new JSONArray();
768         if (array != null)
769             for (float val: array)
770                 a.put(val);
771         return a;
772     }
773 
getJsonChunkInfo(int[] chunkData)774     private JSONObject getJsonChunkInfo(int[] chunkData) throws JSONException
775     {
776         JSONObject jsonRect = new JSONObject();
777         if (chunkData == null)
778             return jsonRect;
779 
780         jsonRect.put("xdivs", getJsonArray(chunkData, 3, chunkData[0]));
781         jsonRect.put("ydivs", getJsonArray(chunkData, 3 + chunkData[0], chunkData[1]));
782         jsonRect.put("colors", getJsonArray(chunkData, 3 + chunkData[0] + chunkData[1], chunkData[2]));
783         return jsonRect;
784     }
785 
findPatchesMarings(Drawable d)786     private JSONObject findPatchesMarings(Drawable d) throws JSONException, NoSuchFieldException, IllegalAccessException
787     {
788         NinePatch np;
789         Field f = tryGetAccessibleField(NinePatchDrawable.class, "mNinePatch");
790         if (f != null) {
791             np = (NinePatch) f.get(d);
792         } else {
793             Object state = getAccessibleField(NinePatchDrawable.class, "mNinePatchState").get(d);
794             np = (NinePatch) getAccessibleField(state.getClass(), "mNinePatch").get(state);
795         }
796         return getJsonChunkInfo(extractNativeChunkInfo20(getAccessibleField(np.getClass(), "mNativeChunk").getLong(np)));
797     }
798 
799     class DrawableCache
800     {
DrawableCache(JSONObject json, Object drawable)801         public DrawableCache(JSONObject json, Object drawable)
802         {
803             object = json;
804             this.drawable = drawable;
805         }
806         JSONObject object;
807         Object drawable;
808     }
809     private HashMap<String, DrawableCache> m_drawableCache = new HashMap<String, DrawableCache>();
810 
getRippleDrawable(Object drawable, String filename, Rect padding)811     private JSONObject getRippleDrawable(Object drawable, String filename, Rect padding)
812     {
813         JSONObject json = getLayerDrawable(drawable, filename);
814         JSONObject ripple =  new JSONObject();
815         try {
816             final Object mState = getAccessibleField(rippleDrawableClass, "mState").get(drawable);
817             ripple.put("mask", getDrawable((Drawable)getAccessibleField(rippleDrawableClass, "mMask").get(drawable), filename, padding));
818             ripple.put("maxRadius", getAccessibleField(mState.getClass(), "mMaxRadius").getInt(mState));
819             ripple.put("color", getColorStateList((ColorStateList)getAccessibleField(mState.getClass(), "mColor").get(mState)));
820             json.put("ripple", ripple);
821         } catch (Exception e) {
822             e.printStackTrace();
823         }
824         return json;
825     }
826 
getStateTransitions(Object sa)827     private HashMap<Long, Long> getStateTransitions(Object sa) throws Exception
828     {
829         HashMap<Long, Long> transitions = new HashMap<Long, Long>();
830         final int sz = getAccessibleField(sa.getClass(), "mSize").getInt(sa);
831         long[] keys = (long[]) getAccessibleField(sa.getClass(), "mKeys").get(sa);
832         long[] values = (long[]) getAccessibleField(sa.getClass(), "mValues").get(sa);
833         for (int i = 0; i < sz; i++) {
834             transitions.put(keys[i], values[i]);
835         }
836         return transitions;
837     }
838 
getStateIds(Object sa)839     private HashMap<Integer, Integer> getStateIds(Object sa) throws Exception
840     {
841         HashMap<Integer, Integer> states = new HashMap<Integer, Integer>();
842         final int sz = getAccessibleField(sa.getClass(), "mSize").getInt(sa);
843         int[] keys = (int[]) getAccessibleField(sa.getClass(), "mKeys").get(sa);
844         int[] values = (int[]) getAccessibleField(sa.getClass(), "mValues").get(sa);
845         for (int i = 0; i < sz; i++) {
846             states.put(keys[i], values[i]);
847         }
848         return states;
849     }
850 
findStateIndex(int id, HashMap<Integer, Integer> stateIds)851     private int findStateIndex(int id, HashMap<Integer, Integer> stateIds)
852     {
853         for (Map.Entry<Integer, Integer> s : stateIds.entrySet()) {
854             if (id == s.getValue())
855                 return s.getKey();
856         }
857         return -1;
858     }
859 
getAnimatedStateListDrawable(Object drawable, String filename)860     private JSONObject getAnimatedStateListDrawable(Object drawable, String filename)
861     {
862         JSONObject json = getStateListDrawable(drawable, filename);
863         try {
864             Object state = getAccessibleField(animatedStateListDrawableClass, "mState").get(drawable);
865 
866             HashMap<Integer, Integer> stateIds = getStateIds(getAccessibleField(state.getClass(), "mStateIds").get(state));
867             HashMap<Long, Long> transitions = getStateTransitions(getAccessibleField(state.getClass(), "mTransitions").get(state));
868 
869             for (Map.Entry<Long, Long> t : transitions.entrySet()) {
870                 final int toState = findStateIndex(t.getKey().intValue(), stateIds);
871                 final int fromState = findStateIndex((int) (t.getKey() >> 32), stateIds);
872 
873                 JSONObject transition = new JSONObject();
874                 transition.put("from", fromState);
875                 transition.put("to", toState);
876                 transition.put("reverse", (t.getValue() >> 32) != 0);
877 
878                 JSONArray stateslist = json.getJSONArray("stateslist");
879                 JSONObject stateobj = stateslist.getJSONObject(t.getValue().intValue());
880                 stateobj.put("transition", transition);
881             }
882         } catch (Exception e) {
883             e.printStackTrace();
884         }
885         return json;
886     }
887 
getVPath(Object path)888     private JSONObject getVPath(Object path) throws Exception
889     {
890         JSONObject json = new JSONObject();
891         final Class<?> pathClass = path.getClass();
892         json.put("type", "path");
893         json.put("name", tryGetAccessibleField(pathClass, "mPathName").get(path));
894         Object[] mNodes = (Object[]) tryGetAccessibleField(pathClass, "mNodes").get(path);
895         JSONArray nodes = new JSONArray();
896         for (Object n: mNodes) {
897             JSONObject node = new JSONObject();
898             node.put("type", String.valueOf(getAccessibleField(n.getClass(), "mType").getChar(n)));
899             node.put("params", getJsonArray((float[])getAccessibleField(n.getClass(), "mParams").get(n)));
900             nodes.put(node);
901         }
902         json.put("nodes", nodes);
903         json.put("isClip", (Boolean) pathClass.getMethod("isClipPath").invoke(path));
904 
905         if (tryGetAccessibleField(pathClass, "mStrokeColor") == null)
906             return json; // not VFullPath
907 
908         json.put("strokeColor", getAccessibleField(pathClass, "mStrokeColor").getInt(path));
909         json.put("strokeWidth", getAccessibleField(pathClass, "mStrokeWidth").getFloat(path));
910         json.put("fillColor", getAccessibleField(pathClass, "mFillColor").getInt(path));
911         json.put("strokeAlpha", getAccessibleField(pathClass, "mStrokeAlpha").getFloat(path));
912         json.put("fillRule", getAccessibleField(pathClass, "mFillRule").getInt(path));
913         json.put("fillAlpha", getAccessibleField(pathClass, "mFillAlpha").getFloat(path));
914         json.put("trimPathStart", getAccessibleField(pathClass, "mTrimPathStart").getFloat(path));
915         json.put("trimPathEnd", getAccessibleField(pathClass, "mTrimPathEnd").getFloat(path));
916         json.put("trimPathOffset", getAccessibleField(pathClass, "mTrimPathOffset").getFloat(path));
917         json.put("strokeLineCap", (Paint.Cap) getAccessibleField(pathClass, "mStrokeLineCap").get(path));
918         json.put("strokeLineJoin", (Paint.Join) getAccessibleField(pathClass, "mStrokeLineJoin").get(path));
919         json.put("strokeMiterlimit", getAccessibleField(pathClass, "mStrokeMiterlimit").getFloat(path));
920         return json;
921     }
922 
923     @SuppressWarnings("unchecked")
getVGroup(Object group)924     private JSONObject getVGroup(Object group) throws Exception
925     {
926         JSONObject json = new JSONObject();
927         json.put("type", "group");
928         final Class<?> groupClass = group.getClass();
929         json.put("name", getAccessibleField(groupClass, "mGroupName").get(group));
930         json.put("rotate", getAccessibleField(groupClass, "mRotate").getFloat(group));
931         json.put("pivotX", getAccessibleField(groupClass, "mPivotX").getFloat(group));
932         json.put("pivotY", getAccessibleField(groupClass, "mPivotY").getFloat(group));
933         json.put("scaleX", getAccessibleField(groupClass, "mScaleX").getFloat(group));
934         json.put("scaleY", getAccessibleField(groupClass, "mScaleY").getFloat(group));
935         json.put("translateX", getAccessibleField(groupClass, "mTranslateX").getFloat(group));
936         json.put("translateY", getAccessibleField(groupClass, "mTranslateY").getFloat(group));
937 
938         ArrayList<Object> mChildren = (ArrayList<Object>) getAccessibleField(groupClass, "mChildren").get(group);
939         JSONArray children = new JSONArray();
940         for (Object c: mChildren) {
941             if (groupClass.isInstance(c))
942                 children.put(getVGroup(c));
943             else
944                 children.put(getVPath(c));
945         }
946         json.put("children", children);
947         return json;
948     }
949 
getVectorDrawable(Object drawable, String filename, Rect padding)950     private JSONObject getVectorDrawable(Object drawable, String filename, Rect padding)
951     {
952         JSONObject json = new JSONObject();
953         try {
954             json.put("type", "vector");
955             final Object state = getAccessibleField(vectorDrawableClass, "mVectorState").get(drawable);
956             final Class<?> stateClass = state.getClass();
957             final ColorStateList mTint = (ColorStateList) getAccessibleField(stateClass, "mTint").get(state);
958             if (mTint != null) {
959                 json.put("tintList", getColorStateList(mTint));
960                 json.put("tintMode", (PorterDuff.Mode) getAccessibleField(stateClass, "mTintMode").get(state));
961             }
962             final Object mVPathRenderer = getAccessibleField(stateClass, "mVPathRenderer").get(state);
963             final Class<?> VPathRendererClass = mVPathRenderer.getClass();
964             json.put("baseWidth", getAccessibleField(VPathRendererClass, "mBaseWidth").getFloat(mVPathRenderer));
965             json.put("baseHeight", getAccessibleField(VPathRendererClass, "mBaseHeight").getFloat(mVPathRenderer));
966             json.put("viewportWidth", getAccessibleField(VPathRendererClass, "mViewportWidth").getFloat(mVPathRenderer));
967             json.put("viewportHeight", getAccessibleField(VPathRendererClass, "mViewportHeight").getFloat(mVPathRenderer));
968             json.put("rootAlpha", getAccessibleField(VPathRendererClass, "mRootAlpha").getInt(mVPathRenderer));
969             json.put("rootName", getAccessibleField(VPathRendererClass, "mRootName").get(mVPathRenderer));
970             json.put("rootGroup", getVGroup(getAccessibleField(mVPathRenderer.getClass(), "mRootGroup").get(mVPathRenderer)));
971         } catch(Exception e) {
972             e.printStackTrace();
973         }
974         return json;
975     }
976 
getDrawable(Object drawable, String filename, Rect padding)977     public JSONObject getDrawable(Object drawable, String filename, Rect padding)
978     {
979         if (drawable == null || m_minimal)
980             return null;
981 
982         DrawableCache dc = m_drawableCache.get(filename);
983         if (dc != null)
984         {
985             if (dc.drawable.equals(drawable))
986                 return dc.object;
987             else
988                 Log.e(QtNative.QtTAG, "Different drawable objects points to the same file name \"" + filename +"\"");
989         }
990         JSONObject json = new JSONObject();
991         Bitmap bmp = null;
992         if (drawable instanceof Bitmap)
993             bmp = (Bitmap) drawable;
994         else
995         {
996             if (drawable instanceof BitmapDrawable) {
997                 BitmapDrawable bitmapDrawable = (BitmapDrawable)drawable;
998                 bmp = bitmapDrawable.getBitmap();
999                 try {
1000                     json.put("gravity", bitmapDrawable.getGravity());
1001                     json.put("tileModeX", bitmapDrawable.getTileModeX());
1002                     json.put("tileModeY", bitmapDrawable.getTileModeY());
1003                     json.put("antialias", (Boolean) BitmapDrawable.class.getMethod("hasAntiAlias").invoke(bitmapDrawable));
1004                     json.put("mipMap", (Boolean) BitmapDrawable.class.getMethod("hasMipMap").invoke(bitmapDrawable));
1005                     json.put("tintMode", (PorterDuff.Mode) BitmapDrawable.class.getMethod("getTintMode").invoke(bitmapDrawable));
1006                     ColorStateList tintList = (ColorStateList) BitmapDrawable.class.getMethod("getTint").invoke(bitmapDrawable);
1007                     if (tintList != null)
1008                         json.put("tintList", getColorStateList(tintList));
1009                 } catch (Exception e) {
1010                     e.printStackTrace();
1011                 }
1012             }
1013             else
1014             {
1015 
1016                 if (rippleDrawableClass != null && rippleDrawableClass.isInstance(drawable))
1017                     return getRippleDrawable(drawable, filename, padding);
1018 
1019                 if (animatedStateListDrawableClass != null && animatedStateListDrawableClass.isInstance(drawable))
1020                     return getAnimatedStateListDrawable(drawable, filename);
1021 
1022                 if (vectorDrawableClass != null && vectorDrawableClass.isInstance(drawable))
1023                     return getVectorDrawable(drawable, filename, padding);
1024 
1025                 if (drawable instanceof ScaleDrawable)
1026                 {
1027                     return getDrawable(((ScaleDrawable)drawable).getDrawable(), filename, null);
1028                 }
1029                 if (drawable instanceof LayerDrawable)
1030                 {
1031                     return getLayerDrawable(drawable, filename);
1032                 }
1033                 if (drawable instanceof StateListDrawable)
1034                 {
1035                     return getStateListDrawable(drawable, filename);
1036                 }
1037                 if (drawable instanceof GradientDrawable)
1038                 {
1039                     return getGradientDrawable((GradientDrawable) drawable);
1040                 }
1041                 if (drawable instanceof RotateDrawable)
1042                 {
1043                     return getRotateDrawable((RotateDrawable) drawable, filename);
1044                 }
1045                 if (drawable instanceof AnimationDrawable)
1046                 {
1047                     return getAnimationDrawable((AnimationDrawable) drawable, filename);
1048                 }
1049                 if (drawable instanceof ClipDrawable)
1050                 {
1051                     try {
1052                         json.put("type", "clipDrawable");
1053                         Drawable.ConstantState dcs = ((ClipDrawable)drawable).getConstantState();
1054                         json.put("drawable", getDrawable(getAccessibleField(dcs.getClass(), "mDrawable").get(dcs), filename, null));
1055                         if (null != padding)
1056                             json.put("padding", getJsonRect(padding));
1057                         else {
1058                             Rect _padding = new Rect();
1059                             if (((Drawable) drawable).getPadding(_padding))
1060                                 json.put("padding", getJsonRect(_padding));
1061                         }
1062                     } catch (Exception e) {
1063                         e.printStackTrace();
1064                     }
1065                     return json;
1066                 }
1067                 if (drawable instanceof ColorDrawable)
1068                 {
1069                     bmp = Bitmap.createBitmap(1, 1, Config.ARGB_8888);
1070                     Drawable d = (Drawable) drawable;
1071                     d.setBounds(0, 0, 1, 1);
1072                     d.draw(new Canvas(bmp));
1073                     try {
1074                         json.put("type", "color");
1075                         json.put("color", bmp.getPixel(0, 0));
1076                         if (null != padding)
1077                             json.put("padding", getJsonRect(padding));
1078                         else {
1079                             Rect _padding = new Rect();
1080                             if (d.getPadding(_padding))
1081                                 json.put("padding", getJsonRect(_padding));
1082                         }
1083                     } catch (JSONException e) {
1084                         e.printStackTrace();
1085                     }
1086                     return json;
1087                 }
1088                 if (drawable instanceof InsetDrawable)
1089                 {
1090                     try {
1091                         InsetDrawable d = (InsetDrawable)drawable;
1092                         // mInsetState changed to mState in Android 5.1 (22)
1093                         Object mInsetStateObject = getAccessibleField(InsetDrawable.class, (Build.VERSION.SDK_INT > 21) ? "mState"
1094                                                                                                                         : "mInsetState").get(d);
1095                         Rect _padding = new Rect();
1096                         boolean hasPadding = d.getPadding(_padding);
1097                         return getDrawable(getAccessibleField(mInsetStateObject.getClass(), "mDrawable").get(mInsetStateObject), filename, hasPadding ? _padding : null);
1098                     } catch (Exception e) {
1099                         e.printStackTrace();
1100                     }
1101                 }
1102                 else
1103                 {
1104                     Drawable d = (Drawable) drawable;
1105                     int w=d.getIntrinsicWidth();
1106                     int h=d.getIntrinsicHeight();
1107                     d.setLevel(10000);
1108                     if (w<1 || h< 1)
1109                     {
1110                         w=100;
1111                         h=100;
1112                     }
1113                     bmp = Bitmap.createBitmap(w, h, Config.ARGB_8888);
1114                     d.setBounds(0, 0, w, h);
1115                     d.draw(new Canvas(bmp));
1116                     if (drawable instanceof NinePatchDrawable)
1117                     {
1118                         NinePatchDrawable npd = (NinePatchDrawable) drawable;
1119                         try {
1120                             json.put("type", "9patch");
1121                             json.put("drawable", getDrawable(bmp, filename, null));
1122                             if (padding != null)
1123                                 json.put("padding", getJsonRect(padding));
1124                             else {
1125                                 Rect _padding = new Rect();
1126                                 if (npd.getPadding(_padding))
1127                                     json.put("padding", getJsonRect(_padding));
1128                             }
1129 
1130                             json.put("chunkInfo", findPatchesMarings(d));
1131                             return json;
1132                         } catch (Exception e) {
1133                             e.printStackTrace();
1134                         }
1135                     }
1136                 }
1137             }
1138         }
1139         FileOutputStream out;
1140         try {
1141             filename = m_extractPath+filename+".png";
1142             out = new FileOutputStream(filename);
1143             bmp.compress(Bitmap.CompressFormat.PNG, 100, out);
1144             out.close();
1145         } catch (FileNotFoundException e) {
1146             e.printStackTrace();
1147         } catch (IOException e) {
1148             e.printStackTrace();
1149         }
1150         try {
1151             json.put("type", "image");
1152             json.put("path", filename);
1153             json.put("width", bmp.getWidth());
1154             json.put("height", bmp.getHeight());
1155             m_drawableCache.put(filename, new DrawableCache(json, drawable));
1156 //            MinistroActivity.nativeChmode(filename, 0644);
1157         } catch (JSONException e) {
1158             e.printStackTrace();
1159         }
1160         return json;
1161     }
1162 
extractViewInformations(String styleName, int styleId, JSONObject json, String qtClassName, AttributeSet attribSet)1163     public void extractViewInformations(String styleName, int styleId, JSONObject json, String qtClassName, AttributeSet attribSet)
1164     {
1165         try {
1166             int[] viewAttrs;
1167             viewAttrs = (int[]) styleableClass.getDeclaredField("View").get(null);
1168             TypedArray a =m_theme.obtainStyledAttributes(attribSet, viewAttrs, styleId, 0);
1169 
1170             if (null != qtClassName)
1171                 json.put("qtClass", qtClassName);
1172             json.put("defaultBackgroundColor", defaultBackgroundColor);
1173             json.put("defaultTextColorPrimary", defaultTextColor);
1174             final int N = a.getIndexCount();
1175             for (int i = 0; i < N; i++) {
1176                 int attr = a.getIndex(i);
1177                 if (attr == View_background)
1178                     json.put("View_background", getDrawable(a.getDrawable(attr), styleName + "_View_background", null));
1179                 else if (attr == View_padding)
1180                     json.put("View_padding", a.getDimensionPixelSize(attr, -1));
1181                 else if (attr == View_paddingLeft)
1182                     json.put("View_paddingLeft", a.getDimensionPixelSize(attr, -1));
1183                 else if (attr == View_paddingTop)
1184                     json.put("View_paddingTop", a.getDimensionPixelSize(attr, -1));
1185                 else if (attr == View_paddingRight)
1186                     json.put("View_paddingRight", a.getDimensionPixelSize(attr, -1));
1187                 else if (attr == View_paddingBottom)
1188                     json.put("View_paddingBottom", a.getDimensionPixelSize(attr, -1));
1189                 else if (attr == View_scrollX)
1190                     json.put("View_paddingBottom", a.getDimensionPixelOffset(attr, 0));
1191                 else if (attr == View_scrollY)
1192                     json.put("View_scrollY", a.getDimensionPixelOffset(attr, 0));
1193                 else if (attr == View_id)
1194                     json.put("View_id", a.getResourceId(attr, -1));
1195                 else if (attr == View_tag)
1196                     json.put("View_tag", a.getText(attr));
1197                 else if (attr == View_fitsSystemWindows)
1198                     json.put("View_fitsSystemWindows", a.getBoolean(attr, false));
1199                 else if (attr == View_focusable)
1200                     json.put("View_focusable", a.getBoolean(attr, false));
1201                 else if (attr == View_focusableInTouchMode)
1202                     json.put("View_focusableInTouchMode", a.getBoolean(attr, false));
1203                 else if (attr == View_clickable)
1204                     json.put("View_clickable", a.getBoolean(attr, false));
1205                 else if (attr == View_longClickable)
1206                     json.put("View_longClickable", a.getBoolean(attr, false));
1207                 else if (attr == View_saveEnabled)
1208                     json.put("View_saveEnabled", a.getBoolean(attr, true));
1209                 else if (attr == View_duplicateParentState)
1210                     json.put("View_duplicateParentState", a.getBoolean(attr, false));
1211                 else if (attr == View_visibility)
1212                     json.put("View_visibility", a.getInt(attr, 0));
1213                 else if (attr == View_drawingCacheQuality)
1214                     json.put("View_drawingCacheQuality", a.getInt(attr, 0));
1215                 else if (attr == View_drawingCacheQuality)
1216                     json.put("View_contentDescription", a.getString(attr));
1217                 else if (attr == View_soundEffectsEnabled)
1218                     json.put("View_soundEffectsEnabled", a.getBoolean(attr, true));
1219                 else if (attr == View_hapticFeedbackEnabled)
1220                     json.put("View_hapticFeedbackEnabled", a.getBoolean(attr, true));
1221                 else if (attr == View_scrollbars)
1222                     json.put("View_scrollbars", a.getInt(attr, 0));
1223                 else if (attr == View_fadingEdge)
1224                     json.put("View_fadingEdge", a.getInt(attr, 0));
1225                 else if (attr == View_scrollbarStyle)
1226                     json.put("View_scrollbarStyle", a.getInt(attr, 0));
1227                 else if (attr == View_scrollbarFadeDuration)
1228                     json.put("View_scrollbarFadeDuration", a.getInt(attr, 0));
1229                 else if (attr == View_scrollbarDefaultDelayBeforeFade)
1230                     json.put("View_scrollbarDefaultDelayBeforeFade", a.getInt(attr, 0));
1231                 else if (attr == View_scrollbarSize)
1232                     json.put("View_scrollbarSize", a.getDimensionPixelSize(attr, -1));
1233                 else if (attr == View_scrollbarThumbHorizontal)
1234                     json.put("View_scrollbarThumbHorizontal", getDrawable(a.getDrawable(attr), styleName + "_View_scrollbarThumbHorizontal", null));
1235                 else if (attr == View_scrollbarThumbVertical)
1236                     json.put("View_scrollbarThumbVertical", getDrawable(a.getDrawable(attr), styleName + "_View_scrollbarThumbVertical", null));
1237                 else if (attr == View_scrollbarTrackHorizontal)
1238                     json.put("View_scrollbarTrackHorizontal", getDrawable(a.getDrawable(attr), styleName + "_View_scrollbarTrackHorizontal", null));
1239                 else if (attr == View_scrollbarTrackVertical)
1240                     json.put("View_scrollbarTrackVertical", getDrawable(a.getDrawable(attr), styleName + "_View_scrollbarTrackVertical", null));
1241                 else if (attr == View_isScrollContainer)
1242                     json.put("View_isScrollContainer", a.getBoolean(attr, false));
1243                 else if (attr == View_keepScreenOn)
1244                     json.put("View_keepScreenOn", a.getBoolean(attr, false));
1245                 else if (attr == View_filterTouchesWhenObscured)
1246                     json.put("View_filterTouchesWhenObscured", a.getBoolean(attr, false));
1247                 else if (attr == View_nextFocusLeft)
1248                     json.put("View_nextFocusLeft", a.getResourceId(attr, -1));
1249                 else if (attr == View_nextFocusRight)
1250                     json.put("View_nextFocusRight", a.getResourceId(attr, -1));
1251                 else if (attr == View_nextFocusUp)
1252                     json.put("View_nextFocusUp", a.getResourceId(attr, -1));
1253                 else if (attr == View_nextFocusDown)
1254                     json.put("View_nextFocusDown", a.getResourceId(attr, -1));
1255                 else if (attr == View_minWidth)
1256                     json.put("View_minWidth", a.getDimensionPixelSize(attr, 0));
1257                 else if (attr == View_minHeight)
1258                     json.put("View_minHeight", a.getDimensionPixelSize(attr, 0));
1259                 else if (attr == View_onClick)
1260                     json.put("View_onClick", a.getString(attr));
1261                 else if (attr == View_overScrollMode)
1262                     json.put("View_overScrollMode", a.getInt(attr, 1));
1263                 else if (attr == View_paddingStart)
1264                     json.put("View_paddingStart", a.getDimensionPixelSize(attr, 0));
1265                 else if (attr == View_paddingEnd)
1266                     json.put("View_paddingEnd", a.getDimensionPixelSize(attr, 0));
1267             }
1268             a.recycle();
1269         } catch (Exception e) {
1270             e.printStackTrace();
1271         }
1272     }
1273 
extractTextAppearance(int styleId)1274     public JSONObject extractTextAppearance(int styleId)
1275     {
1276         JSONObject json = new JSONObject();
1277         try
1278         {
1279             TypedArray a = m_theme.obtainStyledAttributes(styleId, (int[]) styleableClass.getDeclaredField("TextAppearance").get(null));
1280             int n = a.getIndexCount();
1281             for (int i = 0; i < n; i++)
1282             {
1283                 int attr = a.getIndex(i);
1284                 if (attr == TextAppearance_textColorHighlight)
1285                     json.put("TextAppearance_textColorHighlight", a.getColor(attr, 0));
1286                 else if (attr == TextAppearance_textColor)
1287                     json.put("TextAppearance_textColor", getColorStateList(a.getColorStateList(attr)));
1288                 else if (attr == TextAppearance_textColorHint)
1289                     json.put("TextAppearance_textColorHint", getColorStateList(a.getColorStateList(attr)));
1290                 else if (attr == TextAppearance_textColorLink)
1291                     json.put("TextAppearance_textColorLink", getColorStateList(a.getColorStateList(attr)));
1292                 else if (attr == TextAppearance_textSize)
1293                     json.put("TextAppearance_textSize", a.getDimensionPixelSize(attr, 15));
1294                 else if (attr == TextAppearance_typeface)
1295                     json.put("TextAppearance_typeface", a.getInt(attr, -1));
1296                 else if (attr == TextAppearance_textStyle)
1297                     json.put("TextAppearance_textStyle", a.getInt(attr, -1));
1298                 else if (attr == TextAppearance_textAllCaps)
1299                     json.put("TextAppearance_textAllCaps", a.getBoolean(attr, false));
1300             }
1301             a.recycle();
1302         }
1303         catch (Exception e)
1304         {
1305             e.printStackTrace();
1306         }
1307         return json;
1308     }
1309 
extractTextAppearanceInformations(String styleName, String qtClass, AttributeSet attribSet, int textAppearance)1310     public JSONObject extractTextAppearanceInformations(String styleName, String qtClass, AttributeSet attribSet, int textAppearance)
1311     {
1312         JSONObject json = new JSONObject();
1313         try
1314         {
1315             int textColorHighlight = 0; //
1316             ColorStateList textColor = null; //
1317             ColorStateList textColorHint = null; //
1318             ColorStateList textColorLink = null; //
1319             int textSize = 15; //
1320             int typefaceIndex = -1; //
1321             int styleIndex = -1;
1322             boolean allCaps = false;
1323 
1324             Class<?> attrClass= Class.forName("android.R$attr");
1325             int styleId = attrClass.getDeclaredField(styleName).getInt(null);
1326 
1327             extractViewInformations(styleName, styleId, json, qtClass, attribSet);
1328 
1329             int[] textViewAttrs=(int[]) styleableClass.getDeclaredField("TextView").get(null);
1330             TypedArray a =m_theme.obtainStyledAttributes(null, textViewAttrs, styleId, 0);
1331 
1332             TypedArray appearance = null;
1333             if (-1==textAppearance)
1334                 textAppearance = a.getResourceId(styleableClass.getDeclaredField("TextView_textAppearance").getInt(null), -1);
1335 
1336             if (textAppearance != -1)
1337                 appearance = m_theme.obtainStyledAttributes(textAppearance, (int[]) styleableClass.getDeclaredField("TextAppearance").get(null));
1338 
1339             if (appearance != null)
1340             {
1341                 int n = appearance.getIndexCount();
1342                 for (int i = 0; i < n; i++)
1343                 {
1344                     int attr = appearance.getIndex(i);
1345                     if (attr == TextAppearance_textColorHighlight)
1346                         textColorHighlight = appearance.getColor(attr, textColorHighlight);
1347                     else if (attr == TextAppearance_textColor)
1348                         textColor = appearance.getColorStateList(attr);
1349                     else if (attr == TextAppearance_textColorHint)
1350                         textColorHint = appearance.getColorStateList(attr);
1351                     else if (attr == TextAppearance_textColorLink)
1352                         textColorLink = appearance.getColorStateList(attr);
1353                     else if (attr == TextAppearance_textSize)
1354                         textSize = appearance.getDimensionPixelSize(attr, textSize);
1355                     else if (attr == TextAppearance_typeface)
1356                         typefaceIndex = appearance.getInt(attr, -1);
1357                     else if (attr == TextAppearance_textStyle)
1358                         styleIndex = appearance.getInt(attr, -1);
1359                     else if (attr == TextAppearance_textAllCaps)
1360                         allCaps = appearance.getBoolean(attr, false);
1361                 }
1362                 appearance.recycle();
1363             }
1364 
1365             int n = a.getIndexCount();
1366 
1367             for (int i = 0; i < n; i++) {
1368                 int attr = a.getIndex(i);
1369 
1370                 if (attr == TextView_editable)
1371                     json.put("TextView_editable", a.getBoolean(attr, false));
1372                 else if (attr == TextView_inputMethod)
1373                     json.put("TextView_inputMethod", a.getText(attr));
1374                 else if (attr == TextView_numeric)
1375                     json.put("TextView_numeric", a.getInt(attr, 0));
1376                 else if (attr == TextView_digits)
1377                     json.put("TextView_digits", a.getText(attr));
1378                 else if (attr == TextView_phoneNumber)
1379                     json.put("TextView_phoneNumber", a.getBoolean(attr, false));
1380                 else if (attr == TextView_autoText)
1381                     json.put("TextView_autoText", a.getBoolean(attr, false));
1382                 else if (attr == TextView_capitalize)
1383                     json.put("TextView_capitalize", a.getInt(attr, -1));
1384                 else if (attr == TextView_bufferType)
1385                     json.put("TextView_bufferType", a.getInt(attr, 0));
1386                 else if (attr == TextView_selectAllOnFocus)
1387                     json.put("TextView_selectAllOnFocus", a.getBoolean(attr, false));
1388                 else if (attr == TextView_autoLink)
1389                     json.put("TextView_autoLink", a.getInt(attr, 0));
1390                 else if (attr == TextView_linksClickable)
1391                     json.put("TextView_linksClickable", a.getBoolean(attr, true));
1392                 else if (attr == TextView_linksClickable)
1393                     json.put("TextView_linksClickable", a.getBoolean(attr, true));
1394                 else if (attr == TextView_drawableLeft)
1395                     json.put("TextView_drawableLeft", getDrawable(a.getDrawable(attr), styleName + "_TextView_drawableLeft", null));
1396                 else if (attr == TextView_drawableTop)
1397                     json.put("TextView_drawableTop", getDrawable(a.getDrawable(attr), styleName + "_TextView_drawableTop", null));
1398                 else if (attr == TextView_drawableRight)
1399                     json.put("TextView_drawableRight", getDrawable(a.getDrawable(attr), styleName + "_TextView_drawableRight", null));
1400                 else if (attr == TextView_drawableBottom)
1401                     json.put("TextView_drawableBottom", getDrawable(a.getDrawable(attr), styleName + "_TextView_drawableBottom", null));
1402                 else if (attr == TextView_drawableStart)
1403                     json.put("TextView_drawableStart", getDrawable(a.getDrawable(attr), styleName + "_TextView_drawableStart", null));
1404                 else if (attr == TextView_drawableEnd)
1405                     json.put("TextView_drawableEnd", getDrawable(a.getDrawable(attr), styleName + "_TextView_drawableEnd", null));
1406                 else if (attr == TextView_drawablePadding)
1407                     json.put("TextView_drawablePadding", a.getDimensionPixelSize(attr, 0));
1408                 else if (attr == TextView_textCursorDrawable) {
1409                     try {
1410                         json.put("TextView_textCursorDrawable", getDrawable(a.getDrawable(attr), styleName + "_TextView_textCursorDrawable", null));
1411                     } catch (Exception e_) {
1412                         try {
1413                             json.put("TextView_textCursorDrawable", getDrawable(m_context.getResources().getDrawable(a.getResourceId(attr, 0)), styleName + "_TextView_textCursorDrawable", null));
1414                         } catch (Exception e) {
1415                             e.printStackTrace();
1416                         }
1417                     }
1418                 }else if (attr == TextView_maxLines)
1419                     json.put("TextView_maxLines", a.getInt(attr, -1));
1420                 else if (attr == TextView_maxHeight)
1421                     json.put("TextView_maxHeight", a.getDimensionPixelSize(attr, -1));
1422                 else if (attr == TextView_lines)
1423                     json.put("TextView_lines", a.getInt(attr, -1));
1424                 else if (attr == TextView_height)
1425                     json.put("TextView_height", a.getDimensionPixelSize(attr, -1));
1426                 else if (attr == TextView_minLines)
1427                     json.put("TextView_minLines", a.getInt(attr, -1));
1428                 else if (attr == TextView_minHeight)
1429                     json.put("TextView_minHeight", a.getDimensionPixelSize(attr, -1));
1430                 else if (attr == TextView_maxEms)
1431                     json.put("TextView_maxEms", a.getInt(attr, -1));
1432                 else if (attr == TextView_maxWidth)
1433                     json.put("TextView_maxWidth", a.getDimensionPixelSize(attr, -1));
1434                 else if (attr == TextView_ems)
1435                     json.put("TextView_ems", a.getInt(attr, -1));
1436                 else if (attr == TextView_width)
1437                     json.put("TextView_width", a.getDimensionPixelSize(attr, -1));
1438                 else if (attr == TextView_minEms)
1439                     json.put("TextView_minEms", a.getInt(attr, -1));
1440                 else if (attr == TextView_minWidth)
1441                     json.put("TextView_minWidth", a.getDimensionPixelSize(attr, -1));
1442                 else if (attr == TextView_gravity)
1443                     json.put("TextView_gravity", a.getInt(attr, -1));
1444                 else if (attr == TextView_hint)
1445                     json.put("TextView_hint", a.getText(attr));
1446                 else if (attr == TextView_text)
1447                     json.put("TextView_text", a.getText(attr));
1448                 else if (attr == TextView_scrollHorizontally)
1449                     json.put("TextView_scrollHorizontally", a.getBoolean(attr, false));
1450                 else if (attr == TextView_singleLine)
1451                     json.put("TextView_singleLine", a.getBoolean(attr, false));
1452                 else if (attr == TextView_ellipsize)
1453                     json.put("TextView_ellipsize", a.getInt(attr, -1));
1454                 else if (attr == TextView_marqueeRepeatLimit)
1455                     json.put("TextView_marqueeRepeatLimit", a.getInt(attr, 3));
1456                 else if (attr == TextView_includeFontPadding)
1457                     json.put("TextView_includeFontPadding", a.getBoolean(attr, true));
1458                 else if (attr == TextView_cursorVisible)
1459                     json.put("TextView_cursorVisible", a.getBoolean(attr, true));
1460                 else if (attr == TextView_maxLength)
1461                     json.put("TextView_maxLength", a.getInt(attr, -1));
1462                 else if (attr == TextView_textScaleX)
1463                     json.put("TextView_textScaleX", a.getFloat(attr, 1.0f));
1464                 else if (attr == TextView_freezesText)
1465                     json.put("TextView_freezesText", a.getBoolean(attr, false));
1466                 else if (attr == TextView_shadowColor)
1467                     json.put("TextView_shadowColor", a.getInt(attr, 0));
1468                 else if (attr == TextView_shadowDx)
1469                     json.put("TextView_shadowDx", a.getFloat(attr, 0));
1470                 else if (attr == TextView_shadowDy)
1471                     json.put("TextView_shadowDy", a.getFloat(attr, 0));
1472                 else if (attr == TextView_shadowRadius)
1473                     json.put("TextView_shadowRadius", a.getFloat(attr, 0));
1474                 else if (attr == TextView_enabled)
1475                     json.put("TextView_enabled", a.getBoolean(attr,true));
1476                 else if (attr == TextView_textColorHighlight)
1477                     textColorHighlight = a.getColor(attr, textColorHighlight);
1478                 else if (attr == TextView_textColor)
1479                     textColor = a.getColorStateList(attr);
1480                 else if (attr == TextView_textColorHint)
1481                     textColorHint = a.getColorStateList(attr);
1482                 else if (attr == TextView_textColorLink)
1483                     textColorLink = a.getColorStateList(attr);
1484                 else if (attr == TextView_textSize)
1485                     textSize = a.getDimensionPixelSize(attr, textSize);
1486                 else if (attr == TextView_typeface)
1487                     typefaceIndex = a.getInt(attr, typefaceIndex);
1488                 else if (attr == TextView_textStyle)
1489                     styleIndex = a.getInt(attr, styleIndex);
1490                 else if (attr == TextView_password)
1491                     json.put("TextView_password", a.getBoolean(attr,false));
1492                 else if (attr == TextView_lineSpacingExtra)
1493                     json.put("TextView_lineSpacingExtra", a.getDimensionPixelSize(attr, 0));
1494                 else if (attr == TextView_lineSpacingMultiplier)
1495                     json.put("TextView_lineSpacingMultiplier", a.getFloat(attr, 1.0f));
1496                 else if (attr == TextView_inputType)
1497                     json.put("TextView_inputType", a.getInt(attr, EditorInfo.TYPE_NULL));
1498                 else if (attr == TextView_imeOptions)
1499                     json.put("TextView_imeOptions", a.getInt(attr, EditorInfo.IME_NULL));
1500                 else if (attr == TextView_imeActionLabel)
1501                     json.put("TextView_imeActionLabel", a.getText(attr));
1502                 else if (attr == TextView_imeActionId)
1503                     json.put("TextView_imeActionId", a.getInt(attr,0));
1504                 else if (attr == TextView_privateImeOptions)
1505                     json.put("TextView_privateImeOptions", a.getString(attr));
1506                 else if (attr == TextView_textSelectHandleLeft && styleName.equals("textViewStyle")) {
1507                     try {
1508                         json.put("TextView_textSelectHandleLeft", getDrawable(a.getDrawable(attr), styleName + "_TextView_textSelectHandleLeft", null));
1509                     } catch (Exception _e) {
1510                         try {
1511                             json.put("TextView_textSelectHandleLeft", getDrawable(m_context.getResources().getDrawable(a.getResourceId(attr, 0)), styleName + "_TextView_textSelectHandleLeft", null));
1512                         } catch (Exception e) {
1513                             e.printStackTrace();
1514                         }
1515                     }
1516                 } else if (attr == TextView_textSelectHandleRight  && styleName.equals("textViewStyle")) {
1517                     try {
1518                         json.put("TextView_textSelectHandleRight", getDrawable(a.getDrawable(attr), styleName + "_TextView_textSelectHandleRight", null));
1519                     } catch (Exception _e) {
1520                         try {
1521                             json.put("TextView_textSelectHandleRight", getDrawable(m_context.getResources().getDrawable(a.getResourceId(attr, 0)), styleName + "_TextView_textSelectHandleRight", null));
1522                         } catch (Exception e) {
1523                             e.printStackTrace();
1524                         }
1525                     }
1526                 } else if (attr == TextView_textSelectHandle  && styleName.equals("textViewStyle")) {
1527                     try {
1528                         json.put("TextView_textSelectHandle", getDrawable(a.getDrawable(attr), styleName + "_TextView_textSelectHandle", null));
1529                     } catch (Exception _e) {
1530                         try {
1531                             json.put("TextView_textSelectHandle", getDrawable(m_context.getResources().getDrawable(a.getResourceId(attr, 0)), styleName + "_TextView_textSelectHandle", null));
1532                         } catch (Exception e) {
1533                             e.printStackTrace();
1534                         }
1535                     }
1536                 } else if (attr == TextView_textIsSelectable)
1537                     json.put("TextView_textIsSelectable", a.getBoolean(attr, false));
1538                 else if (attr == TextView_textAllCaps)
1539                     allCaps = a.getBoolean(attr, false);
1540             }
1541             a.recycle();
1542 
1543             json.put("TextAppearance_textColorHighlight",textColorHighlight);
1544             json.put("TextAppearance_textColor", getColorStateList(textColor));
1545             json.put("TextAppearance_textColorHint", getColorStateList(textColorHint));
1546             json.put("TextAppearance_textColorLink", getColorStateList(textColorLink));
1547             json.put("TextAppearance_textSize",textSize);
1548             json.put("TextAppearance_typeface",typefaceIndex);
1549             json.put("TextAppearance_textStyle",styleIndex);
1550             json.put("TextAppearance_textAllCaps",allCaps);
1551         }
1552         catch(Exception e)
1553         {
1554             e.printStackTrace();
1555         }
1556         return json;
1557     }
1558 
1559     final String[] sScaleTypeArray = {
1560         "MATRIX",
1561         "FIT_XY",
1562         "FIT_START",
1563         "FIT_CENTER",
1564         "FIT_END",
1565         "CENTER",
1566         "CENTER_CROP",
1567         "CENTER_INSIDE"
1568     };
1569 
extractImageViewInformations(String styleName, String qtClassName )1570     public JSONObject extractImageViewInformations(String styleName, String qtClassName )
1571     {
1572         JSONObject json = new JSONObject();
1573         try
1574         {
1575             Class<?> attrClass= Class.forName("android.R$attr");
1576             int styleId = attrClass.getDeclaredField(styleName).getInt(null);
1577 
1578             extractViewInformations(styleName, styleId, json, qtClassName, null);
1579 
1580             int[] imageViewAttrs=(int[]) styleableClass.getDeclaredField("ImageView").get(null);
1581             TypedArray a =m_theme.obtainStyledAttributes(null, imageViewAttrs, styleId, 0);
1582             Drawable d = a.getDrawable(ImageView_src);
1583             if (d != null)
1584                 json.put("ImageView_src", getDrawable(d, styleName + "_ImageView_src", null));
1585 
1586             json.put("ImageView_baselineAlignBottom", a.getBoolean(ImageView_baselineAlignBottom, false));
1587             json.put("ImageView_adjustViewBounds", a.getBoolean(ImageView_adjustViewBounds, false));
1588             json.put("ImageView_maxWidth", a.getDimensionPixelSize(ImageView_maxWidth, Integer.MAX_VALUE));
1589             json.put("ImageView_maxHeight", a.getDimensionPixelSize(ImageView_maxHeight, Integer.MAX_VALUE));
1590             int index = a.getInt(ImageView_scaleType, -1);
1591             if (index >= 0)
1592                 json.put("ImageView_scaleType", sScaleTypeArray[index]);
1593 
1594             int tint = a.getInt(ImageView_tint, 0);
1595             if (tint != 0)
1596                 json.put("ImageView_tint", tint);
1597 
1598 
1599             json.put("ImageView_cropToPadding",a.getBoolean(ImageView_cropToPadding, false));
1600             a.recycle();
1601         }
1602         catch(Exception e)
1603         {
1604             e.printStackTrace();
1605         }
1606         return json;
1607 
1608     }
1609 
extractCompoundButton(SimpleJsonWriter jsonWriter, String styleName, String qtClass)1610     void extractCompoundButton(SimpleJsonWriter jsonWriter, String styleName, String qtClass)
1611     {
1612         JSONObject json = extractTextAppearanceInformations(styleName, qtClass, null, -1);
1613         Class<?> attrClass;
1614         try {
1615             attrClass = Class.forName("android.R$attr");
1616             int styleId = attrClass.getDeclaredField(styleName).getInt(null);
1617             int[] compoundButtonAttrs=(int[]) styleableClass.getDeclaredField("CompoundButton").get(null);
1618 
1619             TypedArray a = m_theme.obtainStyledAttributes(
1620                         null, compoundButtonAttrs, styleId, 0);
1621 
1622             Drawable d = a.getDrawable(getField(styleableClass,"CompoundButton_button"));
1623             if (d != null)
1624                 json.put("CompoundButton_button", getDrawable(d, styleName + "_CompoundButton_button", null));
1625 
1626             a.recycle();
1627             jsonWriter.name(styleName).value(json);
1628         } catch (Exception e) {
1629             e.printStackTrace();
1630         }
1631     }
1632 
extractProgressBarInfo(JSONObject json, String styleName)1633     void extractProgressBarInfo(JSONObject json, String styleName)
1634     {
1635         Class<?> attrClass;
1636         try {
1637             attrClass = Class.forName("android.R$attr");
1638             int styleId = attrClass.getDeclaredField(styleName).getInt(null);
1639             int[] progressBarAttrs=(int[]) styleableClass.getDeclaredField("ProgressBar").get(null);
1640 
1641             TypedArray a = m_theme.obtainStyledAttributes(null, progressBarAttrs, styleId, 0);
1642             int mMinWidth = 24;
1643             int mMaxWidth = 48;
1644             int mMinHeight = 24;
1645             int mMaxHeight = 48;
1646             mMinWidth = a.getDimensionPixelSize(getField(styleableClass, "ProgressBar_minWidth"), mMinWidth);
1647             mMaxWidth = a.getDimensionPixelSize(getField(styleableClass, "ProgressBar_maxWidth"), mMaxWidth);
1648             mMinHeight = a.getDimensionPixelSize(getField(styleableClass, "ProgressBar_minHeight"), mMinHeight);
1649             mMaxHeight = a.getDimensionPixelSize(getField(styleableClass, "ProgressBar_maxHeight"), mMaxHeight);
1650 
1651             json.put("ProgressBar_indeterminateDuration", a.getInt(getField(styleableClass, "ProgressBar_indeterminateDuration"), 4000));
1652             json.put("ProgressBar_minWidth", mMinWidth);
1653             json.put("ProgressBar_maxWidth", mMaxWidth);
1654             json.put("ProgressBar_minHeight", mMinHeight);
1655             json.put("ProgressBar_maxHeight", mMaxHeight);
1656             json.put("ProgressBar_progress_id", android.R.id.progress);
1657             json.put("ProgressBar_secondaryProgress_id", android.R.id.secondaryProgress);
1658 
1659             Drawable d = a.getDrawable(getField(styleableClass,"ProgressBar_progressDrawable"));
1660             if (d != null)
1661                 json.put("ProgressBar_progressDrawable", getDrawable(d, styleName + "_ProgressBar_progressDrawable", null));
1662 
1663             d = a.getDrawable(getField(styleableClass,"ProgressBar_indeterminateDrawable"));
1664             if (d != null)
1665                 json.put("ProgressBar_indeterminateDrawable", getDrawable(d, styleName + "_ProgressBar_indeterminateDrawable", null));
1666 
1667             a.recycle();
1668         } catch (Exception e) {
1669             e.printStackTrace();
1670         }
1671     }
1672 
extractProgressBar(SimpleJsonWriter writer, String styleName, String qtClass)1673     void extractProgressBar(SimpleJsonWriter writer, String styleName, String qtClass)
1674     {
1675         JSONObject json = extractTextAppearanceInformations(styleName, qtClass, null, -1);
1676         try {
1677             extractProgressBarInfo(json, styleName);
1678             writer.name(styleName).value(json);
1679         } catch (Exception e) {
1680             e.printStackTrace();
1681         }
1682     }
1683 
extractAbsSeekBar(SimpleJsonWriter jsonWriter, String styleName, String qtClass)1684     void extractAbsSeekBar(SimpleJsonWriter jsonWriter, String styleName, String qtClass)
1685     {
1686         JSONObject json = extractTextAppearanceInformations(styleName, qtClass, null, -1);
1687         extractProgressBarInfo(json, styleName);
1688         Class<?> attrClass;
1689         try {
1690             attrClass = Class.forName("android.R$attr");
1691             int styleId = attrClass.getDeclaredField(styleName).getInt(null);
1692             int[] compoundButtonAttrs=(int[]) styleableClass.getDeclaredField("SeekBar").get(null);
1693 
1694             TypedArray a = m_theme.obtainStyledAttributes(
1695                         null, compoundButtonAttrs, styleId, 0);
1696 
1697             Drawable d = a.getDrawable(getField(styleableClass,"SeekBar_thumb"));
1698             if (d != null)
1699                 json.put("SeekBar_thumb", getDrawable(d, styleName + "_SeekBar_thumb", null));
1700 
1701             try {
1702                 json.put("SeekBar_thumbOffset", styleableClass.getDeclaredField("SeekBar_thumbOffset").getInt(null));
1703             } catch (Exception e) {
1704                 e.printStackTrace();
1705             }
1706 
1707             a.recycle();
1708             jsonWriter.name(styleName).value(json);
1709         } catch (Exception e) {
1710             e.printStackTrace();
1711         }
1712     }
1713 
extractSwitch(SimpleJsonWriter jsonWriter, String styleName, String qtClass)1714     void extractSwitch(SimpleJsonWriter jsonWriter, String styleName, String qtClass)
1715     {
1716         JSONObject json = new JSONObject();
1717         try {
1718             Class<?> attrClass = Class.forName("com.android.internal.R$attr");
1719             int styleId = attrClass.getDeclaredField(styleName).getInt(null);
1720 
1721             int[] switchAttrs = (int[]) styleableClass.getDeclaredField("Switch").get(null);
1722             TypedArray a = m_theme.obtainStyledAttributes(null, switchAttrs, styleId, 0);
1723 
1724             Drawable thumb = a.getDrawable(getField(styleableClass,"Switch_thumb"));
1725             if (thumb != null)
1726                 json.put("Switch_thumb", getDrawable(thumb, styleName + "_Switch_thumb", null));
1727 
1728             Drawable track = a.getDrawable(getField(styleableClass,"Switch_track"));
1729             if (track != null)
1730                 json.put("Switch_track", getDrawable(track, styleName + "_Switch_track", null));
1731 
1732             int textAppearance = a.getResourceId(styleableClass.getDeclaredField("Switch_switchTextAppearance").getInt(null), -1);
1733             json.put("Switch_switchTextAppearance", extractTextAppearance(textAppearance));
1734 
1735             json.put("Switch_textOn", a.getText(getField(styleableClass, "Switch_textOn")));
1736             json.put("Switch_textOff", a.getText(getField(styleableClass, "Switch_textOff")));
1737             json.put("Switch_switchMinWidth", a.getDimensionPixelSize(getField(styleableClass, "Switch_switchMinWidth"), 0));
1738             json.put("Switch_switchPadding", a.getDimensionPixelSize(getField(styleableClass, "Switch_switchPadding"), 0));
1739             json.put("Switch_thumbTextPadding", a.getDimensionPixelSize(getField(styleableClass, "Switch_thumbTextPadding"), 0));
1740 
1741             json.put("Switch_showText", a.getBoolean(getField(styleableClass, "Switch_showText"), true));
1742             json.put("Switch_splitTrack", a.getBoolean(getField(styleableClass, "Switch_splitTrack"), false));
1743 
1744             a.recycle();
1745             jsonWriter.name(styleName).value(json);
1746         } catch (Exception e) {
1747             e.printStackTrace();
1748         }
1749     }
1750 
extractCheckedTextView(AttributeSet attribSet, String itemName)1751     JSONObject extractCheckedTextView(AttributeSet attribSet, String itemName)
1752     {
1753         JSONObject json = extractTextAppearanceInformations("textViewStyle", itemName, attribSet, -1);
1754         try {
1755             Class<?> attrClass= Class.forName("android.R$attr");
1756             int styleId = attrClass.getDeclaredField("textViewStyle").getInt(null);
1757             int[] compoundButtonAttrs=(int[]) styleableClass.getDeclaredField("CheckedTextView").get(null);
1758 
1759             TypedArray a = m_theme.obtainStyledAttributes(attribSet, compoundButtonAttrs, styleId, 0);
1760 
1761             Drawable d = a.getDrawable(getField(styleableClass,"CheckedTextView_checkMark"));
1762             if (d != null)
1763                 json.put("CheckedTextView_checkMark", getDrawable(d, itemName+"_CheckedTextView_checkMark", null));
1764 
1765             a.recycle();
1766         } catch (Exception e) {
1767             e.printStackTrace();
1768         }
1769         return json;
1770     }
1771 
extractItemStyle(int resourceId, String itemName, int textAppearance)1772     private JSONObject extractItemStyle(int resourceId, String itemName, int textAppearance) {
1773         try
1774         {
1775             XmlResourceParser parser = m_context.getResources().getLayout(resourceId);
1776             int type;
1777             while ((type = parser.next()) != XmlPullParser.START_TAG &&
1778                     type != XmlPullParser.END_DOCUMENT) {
1779                 // Empty
1780             }
1781 
1782             if (type != XmlPullParser.START_TAG) {
1783                 return null;
1784             }
1785 
1786             AttributeSet attributes = Xml.asAttributeSet(parser);
1787             String name = parser.getName();
1788             if (name.equals("TextView"))
1789                 return extractTextAppearanceInformations("textViewStyle", itemName, attributes, textAppearance);
1790             if (name.equals("CheckedTextView"))
1791                 return extractCheckedTextView(attributes, itemName);
1792         } catch (Exception e) {
1793             e.printStackTrace();
1794         }
1795         return null;
1796     }
1797 
extractItemsStyle(SimpleJsonWriter jsonWriter)1798     private void extractItemsStyle(SimpleJsonWriter jsonWriter) {
1799         try
1800         {
1801             jsonWriter.name("simple_list_item").value(extractItemStyle(android.R.layout.simple_list_item_1, "simple_list_item", android.R.style.TextAppearance_Large));
1802             jsonWriter.name("simple_list_item_checked").value(extractItemStyle(android.R.layout.simple_list_item_checked, "simple_list_item_checked", android.R.style.TextAppearance_Large));
1803             jsonWriter.name("simple_list_item_multiple_choice").value(extractItemStyle(android.R.layout.simple_list_item_multiple_choice, "simple_list_item_multiple_choice", android.R.style.TextAppearance_Large));
1804             jsonWriter.name("simple_list_item_single_choice").value(extractItemStyle(android.R.layout.simple_list_item_single_choice, "simple_list_item_single_choice", android.R.style.TextAppearance_Large));
1805             jsonWriter.name("simple_spinner_item").value(extractItemStyle(android.R.layout.simple_spinner_item, "simple_spinner_item", -1));
1806             jsonWriter.name("simple_spinner_dropdown_item").value(extractItemStyle(android.R.layout.simple_spinner_dropdown_item, "simple_spinner_dropdown_item",android.R.style.TextAppearance_Large));
1807             jsonWriter.name("simple_dropdown_item_1line").value(extractItemStyle(android.R.layout.simple_dropdown_item_1line, "simple_dropdown_item_1line",android.R.style.TextAppearance_Large));
1808             jsonWriter.name("simple_selectable_list_item").value(extractItemStyle(android.R.layout.simple_selectable_list_item, "simple_selectable_list_item",android.R.style.TextAppearance_Large));
1809         } catch (Exception e) {
1810             e.printStackTrace();
1811         }
1812     }
1813 
extractListView(SimpleJsonWriter writer, String styleName, String qtClass)1814     void extractListView(SimpleJsonWriter writer, String styleName, String qtClass)
1815     {
1816         JSONObject json = extractTextAppearanceInformations(styleName, qtClass, null, -1);
1817         try {
1818             Class<?> attrClass = Class.forName("android.R$attr");
1819             int styleId = attrClass.getDeclaredField(styleName).getInt(null);
1820 
1821             int[] styleAttrs = (int[]) styleableClass.getDeclaredField("ListView").get(null);
1822             TypedArray a = m_theme.obtainStyledAttributes(null, styleAttrs, styleId, 0);
1823 
1824             Drawable divider = a.getDrawable(getField(styleableClass,"ListView_divider"));
1825             if (divider != null)
1826                 json.put("ListView_divider", getDrawable(divider, styleName + "_ListView_divider", null));
1827 
1828             json.put("ListView_dividerHeight", a.getDimensionPixelSize(getField(styleableClass, "ListView_dividerHeight"), 0));
1829 
1830             a.recycle();
1831             writer.name(styleName).value(json);
1832         } catch (Exception e) {
1833             e.printStackTrace();
1834         }
1835     }
1836 
extractCalendar(SimpleJsonWriter writer, String styleName, String qtClass)1837     void extractCalendar(SimpleJsonWriter writer, String styleName, String qtClass)
1838     {
1839         JSONObject json = extractTextAppearanceInformations(styleName, qtClass, null, -1);
1840         try {
1841             Class<?> attrClass = Class.forName("android.R$attr");
1842             int styleId = attrClass.getDeclaredField(styleName).getInt(null);
1843 
1844             int[] styleAttrs = (int[]) styleableClass.getDeclaredField("CalendarView").get(null);
1845             TypedArray a = m_theme.obtainStyledAttributes(null, styleAttrs, styleId, 0);
1846 
1847             Drawable d = a.getDrawable(getField(styleableClass,"CalendarView_selectedDateVerticalBar"));
1848             if (d != null)
1849                 json.put("CalendarView_selectedDateVerticalBar", getDrawable(d, styleName + "_CalendarView_selectedDateVerticalBar", null));
1850 
1851             int dateTextAppearance = a.getResourceId(styleableClass.getDeclaredField("CalendarView_dateTextAppearance").getInt(null), -1);
1852             json.put("CalendarView_dateTextAppearance", extractTextAppearance(dateTextAppearance));
1853 
1854             int weekDayTextAppearance = a.getResourceId(styleableClass.getDeclaredField("CalendarView_weekDayTextAppearance").getInt(null), -1);
1855             json.put("CalendarView_weekDayTextAppearance", extractTextAppearance(weekDayTextAppearance));
1856 
1857             json.put("CalendarView_firstDayOfWeek", a.getInt(getField(styleableClass, "CalendarView_firstDayOfWeek"), 0));
1858             json.put("CalendarView_focusedMonthDateColor", a.getColor(getField(styleableClass, "CalendarView_focusedMonthDateColor"), 0));
1859             json.put("CalendarView_selectedWeekBackgroundColor", a.getColor(getField(styleableClass, "CalendarView_selectedWeekBackgroundColor"), 0));
1860             json.put("CalendarView_showWeekNumber", a.getBoolean(getField(styleableClass, "CalendarView_showWeekNumber"), true));
1861             json.put("CalendarView_shownWeekCount", a.getInt(getField(styleableClass, "CalendarView_shownWeekCount"), 6));
1862             json.put("CalendarView_unfocusedMonthDateColor", a.getColor(getField(styleableClass, "CalendarView_unfocusedMonthDateColor"), 0));
1863             json.put("CalendarView_weekNumberColor", a.getColor(getField(styleableClass, "CalendarView_weekNumberColor"), 0));
1864             json.put("CalendarView_weekSeparatorLineColor", a.getColor(getField(styleableClass, "CalendarView_weekSeparatorLineColor"), 0));
1865 
1866             a.recycle();
1867             writer.name(styleName).value(json);
1868         } catch (Exception e) {
1869             e.printStackTrace();
1870         }
1871     }
1872 
extractToolBar(SimpleJsonWriter writer, String styleName, String qtClass)1873     void extractToolBar(SimpleJsonWriter writer, String styleName, String qtClass)
1874     {
1875         JSONObject json = extractTextAppearanceInformations(styleName, qtClass, null, -1);
1876         try {
1877             Class<?> attrClass = Class.forName("com.android.internal.R$attr");
1878             int styleId = attrClass.getDeclaredField(styleName).getInt(null);
1879 
1880             int[] styleAttrs = (int[]) styleableClass.getDeclaredField("ActionBar").get(null);
1881             TypedArray a = m_theme.obtainStyledAttributes(null, styleAttrs, styleId, 0);
1882 
1883             Drawable d = a.getDrawable(getField(styleableClass,"ActionBar_background"));
1884             if (d != null)
1885                 json.put("ActionBar_background", getDrawable(d, styleName + "_ActionBar_background", null));
1886 
1887             d = a.getDrawable(getField(styleableClass,"ActionBar_backgroundStacked"));
1888             if (d != null)
1889                 json.put("ActionBar_backgroundStacked", getDrawable(d, styleName + "_ActionBar_backgroundStacked", null));
1890 
1891             d = a.getDrawable(getField(styleableClass,"ActionBar_backgroundSplit"));
1892             if (d != null)
1893                 json.put("ActionBar_backgroundSplit", getDrawable(d, styleName + "_ActionBar_backgroundSplit", null));
1894 
1895             d = a.getDrawable(getField(styleableClass,"ActionBar_divider"));
1896             if (d != null)
1897                 json.put("ActionBar_divider", getDrawable(d, styleName + "_ActionBar_divider", null));
1898 
1899             json.put("ActionBar_itemPadding", a.getDimensionPixelSize(getField(styleableClass, "ActionBar_itemPadding"), 0));
1900 
1901             a.recycle();
1902             writer.name(styleName).value(json);
1903         } catch (Exception e) {
1904             e.printStackTrace();
1905         }
1906     }
1907 
extractTabBar(SimpleJsonWriter writer, String styleName, String qtClass)1908     void extractTabBar(SimpleJsonWriter writer, String styleName, String qtClass)
1909     {
1910         JSONObject json = extractTextAppearanceInformations(styleName, qtClass, null, -1);
1911         try {
1912             Class<?> attrClass = Class.forName("android.R$attr");
1913             int styleId = attrClass.getDeclaredField(styleName).getInt(null);
1914 
1915             int[] styleAttrs = (int[]) styleableClass.getDeclaredField("LinearLayout").get(null);
1916             TypedArray a = m_theme.obtainStyledAttributes(null, styleAttrs, styleId, 0);
1917 
1918             Drawable d = a.getDrawable(getField(styleableClass,"LinearLayout_divider"));
1919             if (d != null)
1920                 json.put("LinearLayout_divider", getDrawable(d, styleName + "_LinearLayout_divider", null));
1921             json.put("LinearLayout_showDividers", a.getInt(getField(styleableClass, "LinearLayout_showDividers"), 0));
1922             json.put("LinearLayout_dividerPadding", a.getDimensionPixelSize(getField(styleableClass, "LinearLayout_dividerPadding"), 0));
1923 
1924             a.recycle();
1925             writer.name(styleName).value(json);
1926         } catch (Exception e) {
1927             e.printStackTrace();
1928         }
1929     }
1930 
extractWindow(SimpleJsonWriter writer, String styleName)1931     private void extractWindow(SimpleJsonWriter writer, String styleName) {
1932         JSONObject json = new JSONObject();
1933         try
1934         {
1935             Class<?> attrClass = Class.forName("android.R$attr");
1936             int[] windowAttrs = (int[]) styleableClass.getDeclaredField("Window").get(null);
1937 
1938             int backgroundId = attrClass.getDeclaredField("windowBackground").getInt(null);
1939             TypedArray a = m_theme.obtainStyledAttributes(null, windowAttrs, backgroundId, 0);
1940             Drawable background = a.getDrawable(getField(styleableClass, "Window_windowBackground"));
1941             if (background != null)
1942                 json.put("Window_windowBackground", getDrawable(background, styleName + "_Window_windowBackground", null));
1943             a.recycle();
1944 
1945             int frameId = attrClass.getDeclaredField("windowFrame").getInt(null);
1946             a = m_theme.obtainStyledAttributes(null, windowAttrs, frameId, 0);
1947             Drawable frame = a.getDrawable(getField(styleableClass, "Window_windowFrame"));
1948             if (frame != null)
1949                 json.put("Window_windowFrame", getDrawable(frame, styleName + "_Window_windowFrame", null));
1950             a.recycle();
1951 
1952             writer.name(styleName).value(json);
1953         } catch (Exception e) {
1954             e.printStackTrace();
1955         }
1956     }
1957 
extractDefaultPalette()1958     private JSONObject extractDefaultPalette()
1959     {
1960         TypedArray array = m_theme.obtainStyledAttributes(new int[]{
1961                 android.R.attr.textAppearance
1962         });
1963         int pos = 0;
1964         JSONObject json = extractTextAppearance(array.getResourceId(pos++, -1));
1965         try {
1966             json.put("defaultBackgroundColor", defaultBackgroundColor);
1967             json.put("defaultTextColorPrimary", defaultTextColor);
1968         } catch (Exception e) {
1969             e.printStackTrace();
1970         }
1971         array.recycle();
1972         return json;
1973     }
1974 
ExtractStyle(Context context, String extractPath, boolean minimal)1975     public ExtractStyle(Context context, String extractPath, boolean minimal)
1976     {
1977 //        Log.i(MinistroService.TAG, "Extract " + extractPath);
1978         m_minimal = minimal;
1979         m_extractPath = extractPath + "/";
1980         new File(m_extractPath).mkdirs();
1981 //        MinistroActivity.nativeChmode(m_extractPath, 0755);
1982         m_context = context;
1983         m_theme = context.getTheme();
1984         TypedArray array = m_theme.obtainStyledAttributes(new int[]{
1985                 android.R.attr.colorBackground,
1986                 android.R.attr.textColorPrimary,
1987                 android.R.attr.textColor
1988         });
1989         defaultBackgroundColor = array.getColor(0, 0);
1990         int textColor = array.getColor(1, 0xFFFFFF);
1991         if (textColor == 0xFFFFFF)
1992             textColor = array.getColor(2, 0xFFFFFF);
1993         defaultTextColor = textColor;
1994         array.recycle();
1995 
1996         try
1997         {
1998           SimpleJsonWriter jsonWriter = new SimpleJsonWriter(m_extractPath+"style.json");
1999           jsonWriter.beginObject();
2000           try {
2001               jsonWriter.name("defaultStyle").value(extractDefaultPalette());
2002               extractWindow(jsonWriter, "windowStyle");
2003               jsonWriter.name("buttonStyle").value(extractTextAppearanceInformations("buttonStyle", "QPushButton", null, -1));
2004               jsonWriter.name("spinnerStyle").value(extractTextAppearanceInformations("spinnerStyle", "QComboBox", null, -1));
2005               extractProgressBar(jsonWriter, "progressBarStyleHorizontal", "QProgressBar");
2006               extractProgressBar(jsonWriter, "progressBarStyleLarge", null);
2007               extractProgressBar(jsonWriter, "progressBarStyleSmall", null);
2008               extractProgressBar(jsonWriter, "progressBarStyle", null);
2009               extractAbsSeekBar(jsonWriter, "seekBarStyle", "QSlider");
2010               extractSwitch(jsonWriter, "switchStyle", null);
2011               extractCompoundButton(jsonWriter, "checkboxStyle", "QCheckBox");
2012               jsonWriter.name("editTextStyle").value(extractTextAppearanceInformations("editTextStyle", "QLineEdit", null, -1));
2013               extractCompoundButton(jsonWriter, "radioButtonStyle", "QRadioButton");
2014               jsonWriter.name("textViewStyle").value(extractTextAppearanceInformations("textViewStyle", "QWidget", null, -1));
2015               jsonWriter.name("scrollViewStyle").value(extractTextAppearanceInformations("scrollViewStyle", "QAbstractScrollArea", null, -1));
2016               extractListView(jsonWriter, "listViewStyle", "QListView");
2017               jsonWriter.name("listSeparatorTextViewStyle").value(extractTextAppearanceInformations("listSeparatorTextViewStyle", null, null, -1));
2018               extractItemsStyle(jsonWriter);
2019               extractCompoundButton(jsonWriter, "buttonStyleToggle", null);
2020               extractCalendar(jsonWriter, "calendarViewStyle", "QCalendarWidget");
2021               extractToolBar(jsonWriter, "actionBarStyle", "QToolBar");
2022               jsonWriter.name("actionButtonStyle").value(extractTextAppearanceInformations("actionButtonStyle", "QToolButton", null, -1));
2023               jsonWriter.name("actionBarTabTextStyle").value(extractTextAppearanceInformations("actionBarTabTextStyle", null, null, -1));
2024               jsonWriter.name("actionBarTabStyle").value(extractTextAppearanceInformations("actionBarTabStyle", null, null, -1));
2025               jsonWriter.name("actionOverflowButtonStyle").value(extractImageViewInformations("actionOverflowButtonStyle", null));
2026               extractTabBar(jsonWriter, "actionBarTabBarStyle", "QTabBar");
2027           } catch (Exception e) {
2028               e.printStackTrace();
2029           }
2030           jsonWriter.endObject();
2031           jsonWriter.close();
2032 //          MinistroActivity.nativeChmode(m_extractPath+"style.json", 0644);
2033         }
2034         catch (Exception e) {
2035           e.printStackTrace();
2036         }
2037     }
2038 }
2039