source: trunk/autoquest-plugin-android/src/main/java/de/ugoe/cs/autoquest/plugin/android/guimodel/ANDROIDGUIElementSpec.java @ 2146

Last change on this file since 2146 was 2146, checked in by pharms, 7 years ago
  • refactored GUI model so that hierarchical event target structures can also be used and created by plugins not being strictly for GUIs
  • Property svn:mime-type set to text/plain
File size: 10.4 KB
Line 
1//   Copyright 2012 Georg-August-Universität Göttingen, Germany
2//
3//   Licensed under the Apache License, Version 2.0 (the "License");
4//   you may not use this file except in compliance with the License.
5//   You may obtain a copy of the License at
6//
7//       http://www.apache.org/licenses/LICENSE-2.0
8//
9//   Unless required by applicable law or agreed to in writing, software
10//   distributed under the License is distributed on an "AS IS" BASIS,
11//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12//   See the License for the specific language governing permissions and
13//   limitations under the License.
14
15package de.ugoe.cs.autoquest.plugin.android.guimodel;
16
17import java.util.List;
18
19import de.ugoe.cs.autoquest.eventcore.IEventTargetSpec;
20import de.ugoe.cs.autoquest.eventcore.guimodel.IGUIElementSpec;
21
22/**
23 * <p>
24 * Implements the specification of {@link IGUIElement} for {@link ANDROIDGUIElement}s.
25 * </p>
26 *
27 * @version 1.0
28 * @author Florian Unger
29 */
30public class ANDROIDGUIElementSpec implements IGUIElementSpec {
31
32    /**
33     * <p>
34     * Default serial version UID
35     * </p>
36     */
37    private static final long serialVersionUID = 1L;
38
39    /*
40     * (non-Javadoc)
41     *
42     * @see de.ugoe.cs.autoquest.androidmonitor.AndroidmonitorLogFile#logComponent()
43     */
44    /**
45     * <p>
46     * Hash code of the GUI element. Used as unique identifier during parsing a log file. Note that
47     * it is possible that the hash code of an element changes over several log files even if they
48     * come from the same target.
49     * </p>
50     */
51    private int elementHash;
52
53    /**
54     * <p>
55     * Path to an element in an activity. e.g. a path of a button could look like
56     * MainActivity/DecorView/ActionBarOverlayLayout/FrameLayout/RelativeLayout/Button
57     * </p>
58     */
59    private String path;
60
61    /*
62     * (non-Javadoc)
63     *
64     * @see http://developer.android.com/reference/android/view/View.html#getId()
65     */
66    /**
67     * <p>
68     * Id of the object as it is returned by view.getId().
69     * </p>
70     */
71    private int index;
72
73    /**
74     * <p>
75     * Current name of the GUI element
76     * </p>
77     */
78    private String name;
79
80    /**
81     * <p>
82     * The type of GUI element, i.e., the class of the android GUI element.
83     * </p>
84     */
85    private String type;
86
87    /**
88     * <p>
89     * The position of the element in the original GUI.
90     * </p>
91     */
92    private int elementPosition;
93
94    /**
95     * <p>
96     * Type hierarchy of the class itself.
97     * </p>
98     */
99    private List<String> typeHierarchy = null;
100
101    /*
102     * (non-Javadoc)
103     *
104     * @see
105     * de.ugoe.cs.autoquest.eventcore.guimodel.IGUIElementSpec#getSecificationSimilarity(IGUIElementSpec
106     * )
107     */
108    @Override
109    public boolean getSimilarity(IEventTargetSpec other) {
110        if (this == other) {
111            return true;
112        }
113
114        if (!(other instanceof ANDROIDGUIElementSpec)) {
115            return false;
116        }
117
118        ANDROIDGUIElementSpec otherSpec = (ANDROIDGUIElementSpec) other;
119
120        if (type == null ? otherSpec.type != null : !type.equals(otherSpec.type)) {
121            return false;
122        }
123
124        /*
125         * Up to now, we compared, if the basics match. Due to testing with different virtual
126         * devices it seems to be the case that the id of a view (named index here) keeps the same
127         * even on different devices even if the hashCode changes. Some of the GUI elements does not
128         * have an id (id is -1).
129         */
130
131        if (otherSpec.getIndex() > 1 && getIndex() == otherSpec.getIndex()) {
132            return true;
133        }
134
135        /*
136         * Path and label of the elements fits together. In this case it is most likely that this
137         * elements fits together. This only makes since in the case a label exists.
138         */
139        if (otherSpec.getName() != "NOT_SET" && getName() != "NOT_SET" &&
140            !otherSpec.getName().contains("image:") && getName().contains("image:") &&
141            otherSpec.getName() == getName() && otherSpec.getPath() == getPath())
142        {
143            return true;
144        }
145
146        /*
147         * Path and position fits together. In this case it is most likely that this elements fits
148         * together.
149         */
150        if (otherSpec.getPath() == getPath() &&
151            otherSpec.getElementPosition() == getElementPosition())
152        {
153            return true;
154        }
155
156        /*
157         * Two elements could also be similar if the path of the elements is equal and the name is
158         * set, equal and not equal to "image:" even if index <= 1. This comparison is not
159         * implemented up to know due to the reason that all recorded elements up to 2015/01 either
160         * have an index > 1 or no name to be compared.
161         *
162         * In all other cases up to know it is not clear if two elements are similar.
163         *
164         * Not working:
165         *
166         * - Position of the elements: Due to the reason that there are a lot of different displays
167         * on the android market and the in the most cases the layout depends on the display size
168         * (different resolutions) similar elements have different positions.
169         */
170
171        return false;
172    }
173
174    /*
175     * (non-Javadoc)
176     *
177     * @see de.ugoe.cs.autoquest.eventcore.guimodel.IGUIElementSpec#getType()
178     */
179    @Override
180    public String getType() {
181        return type;
182    }
183
184    /*
185     * (non-Javadoc)
186     *
187     * @see de.ugoe.cs.autoquest.eventcore.guimodel.IGUIElementSpec#getTypeHierarchy ()
188     */
189    @Override
190    public String[] getTypeHierarchy() {
191        if (typeHierarchy == null) {
192            return new String[]
193                { (getType()) };
194        }
195        else
196            return typeHierarchy.toArray(new String[typeHierarchy.size()]);
197    }
198
199    /**
200     * <p>
201     * Returns the object hash of the specified GUI element.
202     * </p>
203     *
204     * @return the elementHash
205     */
206    public int getElementHash() {
207        return elementHash;
208    }
209
210    /**
211     * <p>
212     * Returns the path associated with the specified GUI element.
213     * </p>
214     *
215     * @return the path to an element
216     */
217    public String getPath() {
218        return path;
219    }
220
221    /**
222     * <p>
223     * Returns the GUI element identifier.
224     * </p>
225     *
226     * @return identifier of the GUI element
227     */
228    public int getIndex() {
229        return index;
230    }
231
232    /**
233     * <p>
234     * Returns the name of the specified GUI element. Displayed text in the application or image
235     * name.
236     * </p>
237     *
238     * @return text or image of the GUI element.
239     */
240    public String getName() {
241        if (name == null || name.trim().length() == 0) {
242            return "NOT_SET";
243        }
244        return name;
245    }
246
247    /**
248     *
249     * <p>
250     * Return the position of the element in the original GUI.
251     * </p>
252     *
253     * @return position of the element in the original GUI.
254     */
255    public int getElementPosition() {
256        return elementPosition;
257    }
258
259    /**
260     *
261     * <p>
262     * Set the position of the element in the original GUI.
263     * </p>
264     *
265     * @param elementPosition
266     */
267    public void setElementPosition(int elementPosition) {
268        this.elementPosition = elementPosition;
269    }
270
271    /**
272     * <p>
273     * Sets the GUI element identifier.
274     * </p>
275     *
276     * @param indentifier
277     */
278    public void setIndex(int index) {
279        this.index = index;
280    }
281
282    /**
283     * Set the hash code associated with the GUI element.
284     *
285     * @param hash
286     *            the hash of an element object
287     */
288    public void setElementHash(int hash) {
289        this.elementHash = hash;
290    }
291
292    /**
293     * Set the path associated with the specified GUI element.
294     *
295     * @param path
296     *            the path to an element
297     */
298    public void setPath(String path) {
299        this.path = path;
300    }
301
302    /**
303     * <p>
304     * Sets the type of the specified GUI element.
305     * </p>
306     *
307     * @param type
308     *            the type
309     */
310    public void setType(String type) {
311        this.type = type;
312    }
313
314    /**
315     * <p>
316     * Sets the name of the specified GUI element. Displayed text in the application or image name.
317     * </p>
318     *
319     * @param name
320     *            the name
321     */
322    public void setName(String name) {
323        this.name = name;
324    }
325
326    /**
327     * <p>
328     * Sets the type hierarchy of the specified GUI element.
329     *
330     * @param typeHierarchy
331     *            </p>
332     */
333    public void setTypeHierarchy(List<String> typeHierarchy) {
334        this.typeHierarchy = typeHierarchy;
335    }
336
337    /*
338     * (non-Javadoc)
339     *
340     * @see de.ugoe.cs.autoquest.eventcore.guimodel.IGUIElementSpec#equals(IGUIElementSpec)
341     */
342    @Override
343    public boolean equals(Object other) {
344        if (this == other) {
345            return true;
346        }
347
348        if (!(other instanceof ANDROIDGUIElementSpec)) {
349            return false;
350        }
351
352        ANDROIDGUIElementSpec otherSpec = (ANDROIDGUIElementSpec) other;
353
354        return (elementHash == otherSpec.elementHash) &&
355            (path == null ? otherSpec.path == null : path.equals(otherSpec.path)) &&
356            (index == otherSpec.index) &&
357            (elementPosition == otherSpec.elementPosition) &&
358            (name == null ? otherSpec.name == null : name.equals(otherSpec.name)) &&
359            (type == null ? otherSpec.type == null : type.equals(otherSpec.type));
360    }
361
362    /*
363     * (non-Javadoc)
364     *
365     * @see java.lang.Object#hashCode()
366     */
367    @Override
368    public int hashCode() {
369        // 17 due to the reason that this is a prime number.
370        int result = 17;
371        /*
372         * 31 due to the reason that a lot of VM's could optimize this multiplication by a shift.
373         * Source: Effective Java, Joshua Bloch, 2008, p.48
374         */
375        result = 31 * result + elementHash;
376        result = 31 * result + path.hashCode();
377        result = 31 * result + index;
378        result = 31 * result + getName().hashCode();
379        result = 31 * result + type.hashCode();
380        result = 31 * result + elementPosition;
381        return result;
382    }
383
384}
Note: See TracBrowser for help on using the repository browser.