1a6ff2c2b15018092af3a28697b521d1ca5e789f0Christian Williams & Phil Goodwinpackage com.xtremelabs.robolectric;
2a6ff2c2b15018092af3a28697b521d1ca5e789f0Christian Williams & Phil Goodwin
3fe7bed4efc83bcbdc6048405f3b579175e5277b8Lenny Turetsky & Rick Kawalaimport android.app.Application;
4fe7bed4efc83bcbdc6048405f3b579175e5277b8Lenny Turetsky & Rick Kawalaimport com.xtremelabs.robolectric.internal.ClassNameResolver;
5fe7bed4efc83bcbdc6048405f3b579175e5277b8Lenny Turetsky & Rick Kawalaimport org.w3c.dom.Document;
6fe7bed4efc83bcbdc6048405f3b579175e5277b8Lenny Turetsky & Rick Kawalaimport org.w3c.dom.Node;
7fe7bed4efc83bcbdc6048405f3b579175e5277b8Lenny Turetsky & Rick Kawalaimport org.w3c.dom.NodeList;
8a6ff2c2b15018092af3a28697b521d1ca5e789f0Christian Williams & Phil Goodwin
9fe7bed4efc83bcbdc6048405f3b579175e5277b8Lenny Turetsky & Rick Kawalaimport javax.xml.parsers.DocumentBuilder;
10fe7bed4efc83bcbdc6048405f3b579175e5277b8Lenny Turetsky & Rick Kawalaimport javax.xml.parsers.DocumentBuilderFactory;
11a6ff2c2b15018092af3a28697b521d1ca5e789f0Christian Williams & Phil Goodwinimport java.io.File;
12a6ff2c2b15018092af3a28697b521d1ca5e789f0Christian Williams & Phil Goodwinimport java.io.FileNotFoundException;
1372ca49dced475c55926dbad730c306184bb6a68eDavid Farber & Ryan Richardimport java.util.ArrayList;
1472ca49dced475c55926dbad730c306184bb6a68eDavid Farber & Ryan Richardimport java.util.List;
15a6ff2c2b15018092af3a28697b521d1ca5e789f0Christian Williams & Phil Goodwin
16fe7bed4efc83bcbdc6048405f3b579175e5277b8Lenny Turetsky & Rick Kawalaimport static android.content.pm.ApplicationInfo.*;
1708f79939304d82b7cfbb80d20b88fbe26eeab7a9Joe Moore and Tyler Schultz
18a6ff2c2b15018092af3a28697b521d1ca5e789f0Christian Williams & Phil Goodwinpublic class RobolectricConfig {
1964a6b8b69ff3076e1994899fa2de780d80bd57fcMartin Gontovnikas    private final File androidManifestFile;
2064a6b8b69ff3076e1994899fa2de780d80bd57fcMartin Gontovnikas    private final File resourceDirectory;
2164a6b8b69ff3076e1994899fa2de780d80bd57fcMartin Gontovnikas    private final File assetsDirectory;
22147cdda64f4a372a27599ae1f902bd7be90bee5cPhil Goodwin    private String rClassName;
23147cdda64f4a372a27599ae1f902bd7be90bee5cPhil Goodwin    private String packageName;
2408f79939304d82b7cfbb80d20b88fbe26eeab7a9Joe Moore and Tyler Schultz    private String processName;
25147cdda64f4a372a27599ae1f902bd7be90bee5cPhil Goodwin    private String applicationName;
26147cdda64f4a372a27599ae1f902bd7be90bee5cPhil Goodwin    private boolean manifestIsParsed = false;
273fab0d6b94c13c0ab7fc14b1d7f19dbe10991acbPhil Goodwin    private int sdkVersion;
2808f79939304d82b7cfbb80d20b88fbe26eeab7a9Joe Moore and Tyler Schultz    private int minSdkVersion;
2964a6b8b69ff3076e1994899fa2de780d80bd57fcMartin Gontovnikas    private boolean sdkVersionSpecified = true;
3064a6b8b69ff3076e1994899fa2de780d80bd57fcMartin Gontovnikas    private boolean minSdkVersionSpecified = true;
3108f79939304d82b7cfbb80d20b88fbe26eeab7a9Joe Moore and Tyler Schultz    private int applicationFlags;
3264a6b8b69ff3076e1994899fa2de780d80bd57fcMartin Gontovnikas    private final List<ReceiverAndIntentFilter> receivers = new ArrayList<ReceiverAndIntentFilter>();
3322e617961e21946fd47d3b96cc670181ccd3a2bdMichael Portuesi    private boolean strictI18n = false;
34dd40f718cf785a56e63c0685feeb73d266c13e3fWenhui Yao    private String locale = "";
35dd40f718cf785a56e63c0685feeb73d266c13e3fWenhui Yao    private String oldLocale = "";
3672ca49dced475c55926dbad730c306184bb6a68eDavid Farber & Ryan Richard
3772ca49dced475c55926dbad730c306184bb6a68eDavid Farber & Ryan Richard    /**
38a6ff2c2b15018092af3a28697b521d1ca5e789f0Christian Williams & Phil Goodwin     * Creates a Robolectric configuration using default Android files relative to the specified base directory.
3940c6251719cccc0a84ae99c976d2836b14374ce6Christian Williams     * <p/>
40a6ff2c2b15018092af3a28697b521d1ca5e789f0Christian Williams & Phil Goodwin     * The manifest will be baseDir/AndroidManifest.xml, res will be baseDir/res, and assets in baseDir/assets.
41a6ff2c2b15018092af3a28697b521d1ca5e789f0Christian Williams & Phil Goodwin     *
42a6ff2c2b15018092af3a28697b521d1ca5e789f0Christian Williams & Phil Goodwin     * @param baseDir the base directory of your Android project
43a6ff2c2b15018092af3a28697b521d1ca5e789f0Christian Williams & Phil Goodwin     */
4464a6b8b69ff3076e1994899fa2de780d80bd57fcMartin Gontovnikas    public RobolectricConfig(final File baseDir) {
45a6ff2c2b15018092af3a28697b521d1ca5e789f0Christian Williams & Phil Goodwin        this(new File(baseDir, "AndroidManifest.xml"), new File(baseDir, "res"), new File(baseDir, "assets"));
46a6ff2c2b15018092af3a28697b521d1ca5e789f0Christian Williams & Phil Goodwin    }
47a6ff2c2b15018092af3a28697b521d1ca5e789f0Christian Williams & Phil Goodwin
4864a6b8b69ff3076e1994899fa2de780d80bd57fcMartin Gontovnikas    public RobolectricConfig(final File androidManifestFile, final File resourceDirectory) {
49a6ff2c2b15018092af3a28697b521d1ca5e789f0Christian Williams & Phil Goodwin        this(androidManifestFile, resourceDirectory, new File(resourceDirectory.getParent(), "assets"));
50a6ff2c2b15018092af3a28697b521d1ca5e789f0Christian Williams & Phil Goodwin    }
51a6ff2c2b15018092af3a28697b521d1ca5e789f0Christian Williams & Phil Goodwin
52a6ff2c2b15018092af3a28697b521d1ca5e789f0Christian Williams & Phil Goodwin    /**
53a6ff2c2b15018092af3a28697b521d1ca5e789f0Christian Williams & Phil Goodwin     * Creates a Robolectric configuration using specified locations.
54a6ff2c2b15018092af3a28697b521d1ca5e789f0Christian Williams & Phil Goodwin     *
55a6ff2c2b15018092af3a28697b521d1ca5e789f0Christian Williams & Phil Goodwin     * @param androidManifestFile location of the AndroidManifest.xml file
56a6ff2c2b15018092af3a28697b521d1ca5e789f0Christian Williams & Phil Goodwin     * @param resourceDirectory   location of the res directory
57a6ff2c2b15018092af3a28697b521d1ca5e789f0Christian Williams & Phil Goodwin     * @param assetsDirectory     location of the assets directory
58a6ff2c2b15018092af3a28697b521d1ca5e789f0Christian Williams & Phil Goodwin     */
5964a6b8b69ff3076e1994899fa2de780d80bd57fcMartin Gontovnikas    public RobolectricConfig(final File androidManifestFile, final File resourceDirectory, final File assetsDirectory) {
60a6ff2c2b15018092af3a28697b521d1ca5e789f0Christian Williams & Phil Goodwin        this.androidManifestFile = androidManifestFile;
61a6ff2c2b15018092af3a28697b521d1ca5e789f0Christian Williams & Phil Goodwin        this.resourceDirectory = resourceDirectory;
62a6ff2c2b15018092af3a28697b521d1ca5e789f0Christian Williams & Phil Goodwin        this.assetsDirectory = assetsDirectory;
63a6ff2c2b15018092af3a28697b521d1ca5e789f0Christian Williams & Phil Goodwin    }
64a6ff2c2b15018092af3a28697b521d1ca5e789f0Christian Williams & Phil Goodwin
65147cdda64f4a372a27599ae1f902bd7be90bee5cPhil Goodwin    public String getRClassName() throws Exception {
66147cdda64f4a372a27599ae1f902bd7be90bee5cPhil Goodwin        parseAndroidManifest();
67147cdda64f4a372a27599ae1f902bd7be90bee5cPhil Goodwin        return rClassName;
686bdf10c660dd53023a3f889ca8d7b6da049e720dChristian Williams & Phil Goodwin    }
696bdf10c660dd53023a3f889ca8d7b6da049e720dChristian Williams & Phil Goodwin
706bdf10c660dd53023a3f889ca8d7b6da049e720dChristian Williams & Phil Goodwin    public void validate() throws FileNotFoundException {
71147cdda64f4a372a27599ae1f902bd7be90bee5cPhil Goodwin        if (!androidManifestFile.exists() || !androidManifestFile.isFile()) {
72147cdda64f4a372a27599ae1f902bd7be90bee5cPhil Goodwin            throw new FileNotFoundException(androidManifestFile.getAbsolutePath() + " not found or not a file; it should point to your project's AndroidManifest.xml");
73a6ff2c2b15018092af3a28697b521d1ca5e789f0Christian Williams & Phil Goodwin        }
74a6ff2c2b15018092af3a28697b521d1ca5e789f0Christian Williams & Phil Goodwin
75a6ff2c2b15018092af3a28697b521d1ca5e789f0Christian Williams & Phil Goodwin        if (!getResourceDirectory().exists() || !getResourceDirectory().isDirectory()) {
76a6ff2c2b15018092af3a28697b521d1ca5e789f0Christian Williams & Phil Goodwin            throw new FileNotFoundException(getResourceDirectory().getAbsolutePath() + " not found or not a directory; it should point to your project's res directory");
77a6ff2c2b15018092af3a28697b521d1ca5e789f0Christian Williams & Phil Goodwin        }
78a6ff2c2b15018092af3a28697b521d1ca5e789f0Christian Williams & Phil Goodwin    }
79a6ff2c2b15018092af3a28697b521d1ca5e789f0Christian Williams & Phil Goodwin
80147cdda64f4a372a27599ae1f902bd7be90bee5cPhil Goodwin    private void parseAndroidManifest() {
81147cdda64f4a372a27599ae1f902bd7be90bee5cPhil Goodwin        if (manifestIsParsed) {
82147cdda64f4a372a27599ae1f902bd7be90bee5cPhil Goodwin            return;
83147cdda64f4a372a27599ae1f902bd7be90bee5cPhil Goodwin        }
84a6ff2c2b15018092af3a28697b521d1ca5e789f0Christian Williams & Phil Goodwin        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
85147cdda64f4a372a27599ae1f902bd7be90bee5cPhil Goodwin        try {
86147cdda64f4a372a27599ae1f902bd7be90bee5cPhil Goodwin            DocumentBuilder db = dbf.newDocumentBuilder();
873fab0d6b94c13c0ab7fc14b1d7f19dbe10991acbPhil Goodwin            Document manifestDocument = db.parse(androidManifestFile);
88147cdda64f4a372a27599ae1f902bd7be90bee5cPhil Goodwin
89147cdda64f4a372a27599ae1f902bd7be90bee5cPhil Goodwin            packageName = getTagAttributeText(manifestDocument, "manifest", "package");
90147cdda64f4a372a27599ae1f902bd7be90bee5cPhil Goodwin            rClassName = packageName + ".R";
91147cdda64f4a372a27599ae1f902bd7be90bee5cPhil Goodwin            applicationName = getTagAttributeText(manifestDocument, "application", "android:name");
9264a6b8b69ff3076e1994899fa2de780d80bd57fcMartin Gontovnikas            Integer minSdkVer = getTagAttributeIntValue(manifestDocument, "uses-sdk", "android:minSdkVersion");
9364a6b8b69ff3076e1994899fa2de780d80bd57fcMartin Gontovnikas            Integer sdkVer = getTagAttributeIntValue(manifestDocument, "uses-sdk", "android:targetSdkVersion");
9464a6b8b69ff3076e1994899fa2de780d80bd57fcMartin Gontovnikas            if (minSdkVer == null) {
9564a6b8b69ff3076e1994899fa2de780d80bd57fcMartin Gontovnikas                minSdkVersion = 10;
9664a6b8b69ff3076e1994899fa2de780d80bd57fcMartin Gontovnikas                minSdkVersionSpecified = false;
9764a6b8b69ff3076e1994899fa2de780d80bd57fcMartin Gontovnikas            } else {
9864a6b8b69ff3076e1994899fa2de780d80bd57fcMartin Gontovnikas                minSdkVersion = minSdkVer;
9964a6b8b69ff3076e1994899fa2de780d80bd57fcMartin Gontovnikas            }
10064a6b8b69ff3076e1994899fa2de780d80bd57fcMartin Gontovnikas            if (sdkVer == null) {
10164a6b8b69ff3076e1994899fa2de780d80bd57fcMartin Gontovnikas                sdkVersion = 10;
10264a6b8b69ff3076e1994899fa2de780d80bd57fcMartin Gontovnikas                sdkVersionSpecified = false;
10364a6b8b69ff3076e1994899fa2de780d80bd57fcMartin Gontovnikas            } else {
10464a6b8b69ff3076e1994899fa2de780d80bd57fcMartin Gontovnikas                sdkVersion = sdkVer;
10564a6b8b69ff3076e1994899fa2de780d80bd57fcMartin Gontovnikas            }
10608f79939304d82b7cfbb80d20b88fbe26eeab7a9Joe Moore and Tyler Schultz
10708f79939304d82b7cfbb80d20b88fbe26eeab7a9Joe Moore and Tyler Schultz            processName = getTagAttributeText(manifestDocument, "application", "android:process");
10808f79939304d82b7cfbb80d20b88fbe26eeab7a9Joe Moore and Tyler Schultz            if (processName == null) {
10908f79939304d82b7cfbb80d20b88fbe26eeab7a9Joe Moore and Tyler Schultz            	processName = packageName;
11008f79939304d82b7cfbb80d20b88fbe26eeab7a9Joe Moore and Tyler Schultz            }
11108f79939304d82b7cfbb80d20b88fbe26eeab7a9Joe Moore and Tyler Schultz
11208f79939304d82b7cfbb80d20b88fbe26eeab7a9Joe Moore and Tyler Schultz            parseApplicationFlags(manifestDocument);
113fe7bed4efc83bcbdc6048405f3b579175e5277b8Lenny Turetsky & Rick Kawala            parseReceivers(manifestDocument, packageName);
114147cdda64f4a372a27599ae1f902bd7be90bee5cPhil Goodwin        } catch (Exception ignored) {
115147cdda64f4a372a27599ae1f902bd7be90bee5cPhil Goodwin        }
116147cdda64f4a372a27599ae1f902bd7be90bee5cPhil Goodwin        manifestIsParsed = true;
117147cdda64f4a372a27599ae1f902bd7be90bee5cPhil Goodwin    }
118a6ff2c2b15018092af3a28697b521d1ca5e789f0Christian Williams & Phil Goodwin
119fe7bed4efc83bcbdc6048405f3b579175e5277b8Lenny Turetsky & Rick Kawala    private void parseReceivers(final Document manifestDocument, String packageName) {
12072ca49dced475c55926dbad730c306184bb6a68eDavid Farber & Ryan Richard        Node application = manifestDocument.getElementsByTagName("application").item(0);
12172ca49dced475c55926dbad730c306184bb6a68eDavid Farber & Ryan Richard        if (application == null) {
12272ca49dced475c55926dbad730c306184bb6a68eDavid Farber & Ryan Richard            return;
12372ca49dced475c55926dbad730c306184bb6a68eDavid Farber & Ryan Richard        }
12472ca49dced475c55926dbad730c306184bb6a68eDavid Farber & Ryan Richard        for (Node receiverNode : getChildrenTags(application, "receiver")) {
12572ca49dced475c55926dbad730c306184bb6a68eDavid Farber & Ryan Richard            Node namedItem = receiverNode.getAttributes().getNamedItem("android:name");
12672ca49dced475c55926dbad730c306184bb6a68eDavid Farber & Ryan Richard            if (namedItem == null) {
12772ca49dced475c55926dbad730c306184bb6a68eDavid Farber & Ryan Richard                continue;
12872ca49dced475c55926dbad730c306184bb6a68eDavid Farber & Ryan Richard            }
12972ca49dced475c55926dbad730c306184bb6a68eDavid Farber & Ryan Richard            String receiverName = namedItem.getTextContent();
130fe7bed4efc83bcbdc6048405f3b579175e5277b8Lenny Turetsky & Rick Kawala            if (receiverName.startsWith(".")) {
131fe7bed4efc83bcbdc6048405f3b579175e5277b8Lenny Turetsky & Rick Kawala                receiverName = packageName + receiverName;
132fe7bed4efc83bcbdc6048405f3b579175e5277b8Lenny Turetsky & Rick Kawala            }
13372ca49dced475c55926dbad730c306184bb6a68eDavid Farber & Ryan Richard            for (Node intentFilterNode : getChildrenTags(receiverNode, "intent-filter")) {
13472ca49dced475c55926dbad730c306184bb6a68eDavid Farber & Ryan Richard                List<String> actions = new ArrayList<String>();
13572ca49dced475c55926dbad730c306184bb6a68eDavid Farber & Ryan Richard                for (Node actionNode : getChildrenTags(intentFilterNode, "action")) {
13672ca49dced475c55926dbad730c306184bb6a68eDavid Farber & Ryan Richard                    Node nameNode = actionNode.getAttributes().getNamedItem("android:name");
13772ca49dced475c55926dbad730c306184bb6a68eDavid Farber & Ryan Richard                    if (nameNode != null) {
13872ca49dced475c55926dbad730c306184bb6a68eDavid Farber & Ryan Richard                        actions.add(nameNode.getTextContent());
13972ca49dced475c55926dbad730c306184bb6a68eDavid Farber & Ryan Richard                    }
14072ca49dced475c55926dbad730c306184bb6a68eDavid Farber & Ryan Richard                }
14172ca49dced475c55926dbad730c306184bb6a68eDavid Farber & Ryan Richard                receivers.add(new ReceiverAndIntentFilter(receiverName, actions));
14272ca49dced475c55926dbad730c306184bb6a68eDavid Farber & Ryan Richard            }
14372ca49dced475c55926dbad730c306184bb6a68eDavid Farber & Ryan Richard        }
14472ca49dced475c55926dbad730c306184bb6a68eDavid Farber & Ryan Richard    }
14572ca49dced475c55926dbad730c306184bb6a68eDavid Farber & Ryan Richard
14664a6b8b69ff3076e1994899fa2de780d80bd57fcMartin Gontovnikas    private List<Node> getChildrenTags(final Node node, final String tagName) {
14772ca49dced475c55926dbad730c306184bb6a68eDavid Farber & Ryan Richard        List<Node> children = new ArrayList<Node>();
14872ca49dced475c55926dbad730c306184bb6a68eDavid Farber & Ryan Richard        for (int i = 0; i < node.getChildNodes().getLength(); i++) {
14972ca49dced475c55926dbad730c306184bb6a68eDavid Farber & Ryan Richard            Node childNode = node.getChildNodes().item(i);
15072ca49dced475c55926dbad730c306184bb6a68eDavid Farber & Ryan Richard            if (childNode.getNodeName().equalsIgnoreCase(tagName)) {
15172ca49dced475c55926dbad730c306184bb6a68eDavid Farber & Ryan Richard                children.add(childNode);
15272ca49dced475c55926dbad730c306184bb6a68eDavid Farber & Ryan Richard            }
15372ca49dced475c55926dbad730c306184bb6a68eDavid Farber & Ryan Richard        }
15472ca49dced475c55926dbad730c306184bb6a68eDavid Farber & Ryan Richard        return children;
15572ca49dced475c55926dbad730c306184bb6a68eDavid Farber & Ryan Richard    }
15672ca49dced475c55926dbad730c306184bb6a68eDavid Farber & Ryan Richard
15764a6b8b69ff3076e1994899fa2de780d80bd57fcMartin Gontovnikas    private void parseApplicationFlags(final Document manifestDocument) {
15808f79939304d82b7cfbb80d20b88fbe26eeab7a9Joe Moore and Tyler Schultz        applicationFlags = getApplicationFlag(manifestDocument, "android:allowBackup", FLAG_ALLOW_BACKUP);
15908f79939304d82b7cfbb80d20b88fbe26eeab7a9Joe Moore and Tyler Schultz        applicationFlags += getApplicationFlag(manifestDocument, "android:allowClearUserData", FLAG_ALLOW_CLEAR_USER_DATA);
16008f79939304d82b7cfbb80d20b88fbe26eeab7a9Joe Moore and Tyler Schultz        applicationFlags += getApplicationFlag(manifestDocument, "android:allowTaskReparenting", FLAG_ALLOW_TASK_REPARENTING);
16108f79939304d82b7cfbb80d20b88fbe26eeab7a9Joe Moore and Tyler Schultz        applicationFlags += getApplicationFlag(manifestDocument, "android:debuggable", FLAG_DEBUGGABLE);
16208f79939304d82b7cfbb80d20b88fbe26eeab7a9Joe Moore and Tyler Schultz        applicationFlags += getApplicationFlag(manifestDocument, "android:hasCode", FLAG_HAS_CODE);
16308f79939304d82b7cfbb80d20b88fbe26eeab7a9Joe Moore and Tyler Schultz        applicationFlags += getApplicationFlag(manifestDocument, "android:killAfterRestore", FLAG_KILL_AFTER_RESTORE);
16408f79939304d82b7cfbb80d20b88fbe26eeab7a9Joe Moore and Tyler Schultz        applicationFlags += getApplicationFlag(manifestDocument, "android:persistent", FLAG_PERSISTENT);
16508f79939304d82b7cfbb80d20b88fbe26eeab7a9Joe Moore and Tyler Schultz        applicationFlags += getApplicationFlag(manifestDocument, "android:resizeable", FLAG_RESIZEABLE_FOR_SCREENS);
16608f79939304d82b7cfbb80d20b88fbe26eeab7a9Joe Moore and Tyler Schultz        applicationFlags += getApplicationFlag(manifestDocument, "android:restoreAnyVersion", FLAG_RESTORE_ANY_VERSION);
16708f79939304d82b7cfbb80d20b88fbe26eeab7a9Joe Moore and Tyler Schultz        applicationFlags += getApplicationFlag(manifestDocument, "android:largeScreens", FLAG_SUPPORTS_LARGE_SCREENS);
16808f79939304d82b7cfbb80d20b88fbe26eeab7a9Joe Moore and Tyler Schultz        applicationFlags += getApplicationFlag(manifestDocument, "android:normalScreens", FLAG_SUPPORTS_NORMAL_SCREENS);
16908f79939304d82b7cfbb80d20b88fbe26eeab7a9Joe Moore and Tyler Schultz        applicationFlags += getApplicationFlag(manifestDocument, "android:anyDensity", FLAG_SUPPORTS_SCREEN_DENSITIES);
17008f79939304d82b7cfbb80d20b88fbe26eeab7a9Joe Moore and Tyler Schultz        applicationFlags += getApplicationFlag(manifestDocument, "android:smallScreens", FLAG_SUPPORTS_SMALL_SCREENS);
17108f79939304d82b7cfbb80d20b88fbe26eeab7a9Joe Moore and Tyler Schultz        applicationFlags += getApplicationFlag(manifestDocument, "android:testOnly", FLAG_TEST_ONLY);
17208f79939304d82b7cfbb80d20b88fbe26eeab7a9Joe Moore and Tyler Schultz        applicationFlags += getApplicationFlag(manifestDocument, "android:vmSafeMode", FLAG_VM_SAFE_MODE);
17308f79939304d82b7cfbb80d20b88fbe26eeab7a9Joe Moore and Tyler Schultz    }
17408f79939304d82b7cfbb80d20b88fbe26eeab7a9Joe Moore and Tyler Schultz
17564a6b8b69ff3076e1994899fa2de780d80bd57fcMartin Gontovnikas    private int getApplicationFlag(final Document doc, final String attribute, final int attributeValue) {
17608f79939304d82b7cfbb80d20b88fbe26eeab7a9Joe Moore and Tyler Schultz    	String flagString = getTagAttributeText(doc, "application", attribute);
17708f79939304d82b7cfbb80d20b88fbe26eeab7a9Joe Moore and Tyler Schultz    	return "true".equalsIgnoreCase(flagString) ? attributeValue : 0;
17808f79939304d82b7cfbb80d20b88fbe26eeab7a9Joe Moore and Tyler Schultz    }
17908f79939304d82b7cfbb80d20b88fbe26eeab7a9Joe Moore and Tyler Schultz
18064a6b8b69ff3076e1994899fa2de780d80bd57fcMartin Gontovnikas    private Integer getTagAttributeIntValue(final Document doc, final String tag, final String attribute) {
18164a6b8b69ff3076e1994899fa2de780d80bd57fcMartin Gontovnikas        return getTagAttributeIntValue(doc, tag, attribute, null);
18264a6b8b69ff3076e1994899fa2de780d80bd57fcMartin Gontovnikas    }
18364a6b8b69ff3076e1994899fa2de780d80bd57fcMartin Gontovnikas
18464a6b8b69ff3076e1994899fa2de780d80bd57fcMartin Gontovnikas    private Integer getTagAttributeIntValue(final Document doc, final String tag, final String attribute, final Integer defaultValue) {
18508f79939304d82b7cfbb80d20b88fbe26eeab7a9Joe Moore and Tyler Schultz        String valueString = getTagAttributeText(doc, tag, attribute);
18608f79939304d82b7cfbb80d20b88fbe26eeab7a9Joe Moore and Tyler Schultz        if (valueString != null) {
18708f79939304d82b7cfbb80d20b88fbe26eeab7a9Joe Moore and Tyler Schultz            return Integer.parseInt(valueString);
1883fab0d6b94c13c0ab7fc14b1d7f19dbe10991acbPhil Goodwin        }
1893fab0d6b94c13c0ab7fc14b1d7f19dbe10991acbPhil Goodwin        return defaultValue;
1903fab0d6b94c13c0ab7fc14b1d7f19dbe10991acbPhil Goodwin    }
1913fab0d6b94c13c0ab7fc14b1d7f19dbe10991acbPhil Goodwin
192147cdda64f4a372a27599ae1f902bd7be90bee5cPhil Goodwin    public String getApplicationName() {
193147cdda64f4a372a27599ae1f902bd7be90bee5cPhil Goodwin        parseAndroidManifest();
194147cdda64f4a372a27599ae1f902bd7be90bee5cPhil Goodwin        return applicationName;
195a6ff2c2b15018092af3a28697b521d1ca5e789f0Christian Williams & Phil Goodwin    }
196a6ff2c2b15018092af3a28697b521d1ca5e789f0Christian Williams & Phil Goodwin
197147cdda64f4a372a27599ae1f902bd7be90bee5cPhil Goodwin    public String getPackageName() {
198147cdda64f4a372a27599ae1f902bd7be90bee5cPhil Goodwin        parseAndroidManifest();
199147cdda64f4a372a27599ae1f902bd7be90bee5cPhil Goodwin        return packageName;
200a6ff2c2b15018092af3a28697b521d1ca5e789f0Christian Williams & Phil Goodwin    }
20108f79939304d82b7cfbb80d20b88fbe26eeab7a9Joe Moore and Tyler Schultz
20208f79939304d82b7cfbb80d20b88fbe26eeab7a9Joe Moore and Tyler Schultz    public int getMinSdkVersion() {
20308f79939304d82b7cfbb80d20b88fbe26eeab7a9Joe Moore and Tyler Schultz    	parseAndroidManifest();
20408f79939304d82b7cfbb80d20b88fbe26eeab7a9Joe Moore and Tyler Schultz		return minSdkVersion;
20508f79939304d82b7cfbb80d20b88fbe26eeab7a9Joe Moore and Tyler Schultz	}
206a6ff2c2b15018092af3a28697b521d1ca5e789f0Christian Williams & Phil Goodwin
2073fab0d6b94c13c0ab7fc14b1d7f19dbe10991acbPhil Goodwin    public int getSdkVersion() {
2083fab0d6b94c13c0ab7fc14b1d7f19dbe10991acbPhil Goodwin        parseAndroidManifest();
2093fab0d6b94c13c0ab7fc14b1d7f19dbe10991acbPhil Goodwin        return sdkVersion;
2103fab0d6b94c13c0ab7fc14b1d7f19dbe10991acbPhil Goodwin    }
2113fab0d6b94c13c0ab7fc14b1d7f19dbe10991acbPhil Goodwin
21208f79939304d82b7cfbb80d20b88fbe26eeab7a9Joe Moore and Tyler Schultz    public int getApplicationFlags() {
21308f79939304d82b7cfbb80d20b88fbe26eeab7a9Joe Moore and Tyler Schultz    	parseAndroidManifest();
21408f79939304d82b7cfbb80d20b88fbe26eeab7a9Joe Moore and Tyler Schultz    	return applicationFlags;
21508f79939304d82b7cfbb80d20b88fbe26eeab7a9Joe Moore and Tyler Schultz    }
21608f79939304d82b7cfbb80d20b88fbe26eeab7a9Joe Moore and Tyler Schultz
21708f79939304d82b7cfbb80d20b88fbe26eeab7a9Joe Moore and Tyler Schultz    public String getProcessName() {
21808f79939304d82b7cfbb80d20b88fbe26eeab7a9Joe Moore and Tyler Schultz		parseAndroidManifest();
21908f79939304d82b7cfbb80d20b88fbe26eeab7a9Joe Moore and Tyler Schultz		return processName;
22008f79939304d82b7cfbb80d20b88fbe26eeab7a9Joe Moore and Tyler Schultz	}
22108f79939304d82b7cfbb80d20b88fbe26eeab7a9Joe Moore and Tyler Schultz
222a6ff2c2b15018092af3a28697b521d1ca5e789f0Christian Williams & Phil Goodwin    public File getResourceDirectory() {
223a6ff2c2b15018092af3a28697b521d1ca5e789f0Christian Williams & Phil Goodwin        return resourceDirectory;
224a6ff2c2b15018092af3a28697b521d1ca5e789f0Christian Williams & Phil Goodwin    }
225a6ff2c2b15018092af3a28697b521d1ca5e789f0Christian Williams & Phil Goodwin
226a6ff2c2b15018092af3a28697b521d1ca5e789f0Christian Williams & Phil Goodwin    public File getAssetsDirectory() {
227a6ff2c2b15018092af3a28697b521d1ca5e789f0Christian Williams & Phil Goodwin        return assetsDirectory;
228a6ff2c2b15018092af3a28697b521d1ca5e789f0Christian Williams & Phil Goodwin    }
229a6ff2c2b15018092af3a28697b521d1ca5e789f0Christian Williams & Phil Goodwin
23072ca49dced475c55926dbad730c306184bb6a68eDavid Farber & Ryan Richard    public int getReceiverCount() {
23172ca49dced475c55926dbad730c306184bb6a68eDavid Farber & Ryan Richard        parseAndroidManifest();
23272ca49dced475c55926dbad730c306184bb6a68eDavid Farber & Ryan Richard        return receivers.size();
23372ca49dced475c55926dbad730c306184bb6a68eDavid Farber & Ryan Richard    }
23472ca49dced475c55926dbad730c306184bb6a68eDavid Farber & Ryan Richard
23564a6b8b69ff3076e1994899fa2de780d80bd57fcMartin Gontovnikas    public String getReceiverClassName(final int receiverIndex) {
23672ca49dced475c55926dbad730c306184bb6a68eDavid Farber & Ryan Richard        parseAndroidManifest();
23772ca49dced475c55926dbad730c306184bb6a68eDavid Farber & Ryan Richard        return receivers.get(receiverIndex).getBroadcastReceiverClassName();
23872ca49dced475c55926dbad730c306184bb6a68eDavid Farber & Ryan Richard    }
23972ca49dced475c55926dbad730c306184bb6a68eDavid Farber & Ryan Richard
24064a6b8b69ff3076e1994899fa2de780d80bd57fcMartin Gontovnikas    public List<String> getReceiverIntentFilterActions(final int receiverIndex) {
24172ca49dced475c55926dbad730c306184bb6a68eDavid Farber & Ryan Richard        parseAndroidManifest();
24272ca49dced475c55926dbad730c306184bb6a68eDavid Farber & Ryan Richard        return receivers.get(receiverIndex).getIntentFilterActions();
24372ca49dced475c55926dbad730c306184bb6a68eDavid Farber & Ryan Richard    }
24472ca49dced475c55926dbad730c306184bb6a68eDavid Farber & Ryan Richard
24522e617961e21946fd47d3b96cc670181ccd3a2bdMichael Portuesi    public boolean getStrictI18n() {
24622e617961e21946fd47d3b96cc670181ccd3a2bdMichael Portuesi    	return strictI18n;
24722e617961e21946fd47d3b96cc670181ccd3a2bdMichael Portuesi    }
24822e617961e21946fd47d3b96cc670181ccd3a2bdMichael Portuesi
24922e617961e21946fd47d3b96cc670181ccd3a2bdMichael Portuesi    public void setStrictI18n(boolean strict) {
25022e617961e21946fd47d3b96cc670181ccd3a2bdMichael Portuesi    	strictI18n = strict;
25122e617961e21946fd47d3b96cc670181ccd3a2bdMichael Portuesi    }
25222e617961e21946fd47d3b96cc670181ccd3a2bdMichael Portuesi
253dd40f718cf785a56e63c0685feeb73d266c13e3fWenhui Yao    public void setLocale( String locale ){
254dd40f718cf785a56e63c0685feeb73d266c13e3fWenhui Yao    	this.oldLocale = this.locale;
255dd40f718cf785a56e63c0685feeb73d266c13e3fWenhui Yao    	this.locale = locale;
256dd40f718cf785a56e63c0685feeb73d266c13e3fWenhui Yao    }
257dd40f718cf785a56e63c0685feeb73d266c13e3fWenhui Yao
258dd40f718cf785a56e63c0685feeb73d266c13e3fWenhui Yao    public String getLocale() {
259dd40f718cf785a56e63c0685feeb73d266c13e3fWenhui Yao    	return this.locale;
260dd40f718cf785a56e63c0685feeb73d266c13e3fWenhui Yao    }
261dd40f718cf785a56e63c0685feeb73d266c13e3fWenhui Yao
262ccc48a273af15b7513d5f5fc28110a0eebb82454Michael Portuesi    public boolean isLocaleChanged() {
263dd40f718cf785a56e63c0685feeb73d266c13e3fWenhui Yao    	return !locale.equals( oldLocale );
264dd40f718cf785a56e63c0685feeb73d266c13e3fWenhui Yao    }
265dd40f718cf785a56e63c0685feeb73d266c13e3fWenhui Yao
26664a6b8b69ff3076e1994899fa2de780d80bd57fcMartin Gontovnikas    private static String getTagAttributeText(final Document doc, final String tag, final String attribute) {
267147cdda64f4a372a27599ae1f902bd7be90bee5cPhil Goodwin        NodeList elementsByTagName = doc.getElementsByTagName(tag);
2683fab0d6b94c13c0ab7fc14b1d7f19dbe10991acbPhil Goodwin        for (int i = 0; i < elementsByTagName.getLength(); ++i) {
2693fab0d6b94c13c0ab7fc14b1d7f19dbe10991acbPhil Goodwin            Node item = elementsByTagName.item(i);
2703fab0d6b94c13c0ab7fc14b1d7f19dbe10991acbPhil Goodwin            Node namedItem = item.getAttributes().getNamedItem(attribute);
2713fab0d6b94c13c0ab7fc14b1d7f19dbe10991acbPhil Goodwin            if (namedItem != null) {
2723fab0d6b94c13c0ab7fc14b1d7f19dbe10991acbPhil Goodwin                return namedItem.getTextContent();
2733fab0d6b94c13c0ab7fc14b1d7f19dbe10991acbPhil Goodwin            }
2743fab0d6b94c13c0ab7fc14b1d7f19dbe10991acbPhil Goodwin        }
2753fab0d6b94c13c0ab7fc14b1d7f19dbe10991acbPhil Goodwin        return null;
276147cdda64f4a372a27599ae1f902bd7be90bee5cPhil Goodwin    }
27722e617961e21946fd47d3b96cc670181ccd3a2bdMichael Portuesi
27864a6b8b69ff3076e1994899fa2de780d80bd57fcMartin Gontovnikas    private static Application newApplicationInstance(final String packageName, final String applicationName) {
279147cdda64f4a372a27599ae1f902bd7be90bee5cPhil Goodwin        Application application;
280147cdda64f4a372a27599ae1f902bd7be90bee5cPhil Goodwin        try {
281147cdda64f4a372a27599ae1f902bd7be90bee5cPhil Goodwin            Class<? extends Application> applicationClass =
282147cdda64f4a372a27599ae1f902bd7be90bee5cPhil Goodwin                    new ClassNameResolver<Application>(packageName, applicationName).resolve();
283147cdda64f4a372a27599ae1f902bd7be90bee5cPhil Goodwin            application = applicationClass.newInstance();
284147cdda64f4a372a27599ae1f902bd7be90bee5cPhil Goodwin        } catch (Exception e) {
285147cdda64f4a372a27599ae1f902bd7be90bee5cPhil Goodwin            throw new RuntimeException(e);
286147cdda64f4a372a27599ae1f902bd7be90bee5cPhil Goodwin        }
287147cdda64f4a372a27599ae1f902bd7be90bee5cPhil Goodwin        return application;
288147cdda64f4a372a27599ae1f902bd7be90bee5cPhil Goodwin    }
289147cdda64f4a372a27599ae1f902bd7be90bee5cPhil Goodwin
290a6ff2c2b15018092af3a28697b521d1ca5e789f0Christian Williams & Phil Goodwin    @Override
29164a6b8b69ff3076e1994899fa2de780d80bd57fcMartin Gontovnikas    public boolean equals(final Object o) {
29264a6b8b69ff3076e1994899fa2de780d80bd57fcMartin Gontovnikas        if (this == o) {
29364a6b8b69ff3076e1994899fa2de780d80bd57fcMartin Gontovnikas            return true;
29464a6b8b69ff3076e1994899fa2de780d80bd57fcMartin Gontovnikas        }
29564a6b8b69ff3076e1994899fa2de780d80bd57fcMartin Gontovnikas        if (o == null || getClass() != o.getClass()) {
29664a6b8b69ff3076e1994899fa2de780d80bd57fcMartin Gontovnikas            return false;
29764a6b8b69ff3076e1994899fa2de780d80bd57fcMartin Gontovnikas        }
298a6ff2c2b15018092af3a28697b521d1ca5e789f0Christian Williams & Phil Goodwin
299a6ff2c2b15018092af3a28697b521d1ca5e789f0Christian Williams & Phil Goodwin        RobolectricConfig that = (RobolectricConfig) o;
300a6ff2c2b15018092af3a28697b521d1ca5e789f0Christian Williams & Phil Goodwin
30164a6b8b69ff3076e1994899fa2de780d80bd57fcMartin Gontovnikas        if (androidManifestFile != null ? !androidManifestFile.equals(that.androidManifestFile) : that.androidManifestFile != null) {
302a6ff2c2b15018092af3a28697b521d1ca5e789f0Christian Williams & Phil Goodwin            return false;
30364a6b8b69ff3076e1994899fa2de780d80bd57fcMartin Gontovnikas        }
30464a6b8b69ff3076e1994899fa2de780d80bd57fcMartin Gontovnikas        if (getAssetsDirectory() != null ? !getAssetsDirectory().equals(that.getAssetsDirectory()) : that.getAssetsDirectory() != null) {
305a6ff2c2b15018092af3a28697b521d1ca5e789f0Christian Williams & Phil Goodwin            return false;
30664a6b8b69ff3076e1994899fa2de780d80bd57fcMartin Gontovnikas        }
30764a6b8b69ff3076e1994899fa2de780d80bd57fcMartin Gontovnikas        if (getResourceDirectory() != null ? !getResourceDirectory().equals(that.getResourceDirectory()) : that.getResourceDirectory() != null) {
308a6ff2c2b15018092af3a28697b521d1ca5e789f0Christian Williams & Phil Goodwin            return false;
30964a6b8b69ff3076e1994899fa2de780d80bd57fcMartin Gontovnikas        }
310a6ff2c2b15018092af3a28697b521d1ca5e789f0Christian Williams & Phil Goodwin
311a6ff2c2b15018092af3a28697b521d1ca5e789f0Christian Williams & Phil Goodwin        return true;
312a6ff2c2b15018092af3a28697b521d1ca5e789f0Christian Williams & Phil Goodwin    }
313a6ff2c2b15018092af3a28697b521d1ca5e789f0Christian Williams & Phil Goodwin
314a6ff2c2b15018092af3a28697b521d1ca5e789f0Christian Williams & Phil Goodwin    @Override
315a6ff2c2b15018092af3a28697b521d1ca5e789f0Christian Williams & Phil Goodwin    public int hashCode() {
316147cdda64f4a372a27599ae1f902bd7be90bee5cPhil Goodwin        int result = androidManifestFile != null ? androidManifestFile.hashCode() : 0;
317a6ff2c2b15018092af3a28697b521d1ca5e789f0Christian Williams & Phil Goodwin        result = 31 * result + (getResourceDirectory() != null ? getResourceDirectory().hashCode() : 0);
318a6ff2c2b15018092af3a28697b521d1ca5e789f0Christian Williams & Phil Goodwin        result = 31 * result + (getAssetsDirectory() != null ? getAssetsDirectory().hashCode() : 0);
319a6ff2c2b15018092af3a28697b521d1ca5e789f0Christian Williams & Phil Goodwin        return result;
320a6ff2c2b15018092af3a28697b521d1ca5e789f0Christian Williams & Phil Goodwin    }
32164a6b8b69ff3076e1994899fa2de780d80bd57fcMartin Gontovnikas
32264a6b8b69ff3076e1994899fa2de780d80bd57fcMartin Gontovnikas    public int getRealSdkVersion() {
32364a6b8b69ff3076e1994899fa2de780d80bd57fcMartin Gontovnikas        parseAndroidManifest();
32464a6b8b69ff3076e1994899fa2de780d80bd57fcMartin Gontovnikas        if (sdkVersionSpecified) {
32564a6b8b69ff3076e1994899fa2de780d80bd57fcMartin Gontovnikas            return sdkVersion;
32664a6b8b69ff3076e1994899fa2de780d80bd57fcMartin Gontovnikas        }
32764a6b8b69ff3076e1994899fa2de780d80bd57fcMartin Gontovnikas        if (minSdkVersionSpecified) {
32864a6b8b69ff3076e1994899fa2de780d80bd57fcMartin Gontovnikas            return minSdkVersion;
32964a6b8b69ff3076e1994899fa2de780d80bd57fcMartin Gontovnikas        }
33064a6b8b69ff3076e1994899fa2de780d80bd57fcMartin Gontovnikas        return sdkVersion;
33164a6b8b69ff3076e1994899fa2de780d80bd57fcMartin Gontovnikas    }
33272ca49dced475c55926dbad730c306184bb6a68eDavid Farber & Ryan Richard
33372ca49dced475c55926dbad730c306184bb6a68eDavid Farber & Ryan Richard    private static class ReceiverAndIntentFilter {
33464a6b8b69ff3076e1994899fa2de780d80bd57fcMartin Gontovnikas        private final List<String> intentFilterActions;
33564a6b8b69ff3076e1994899fa2de780d80bd57fcMartin Gontovnikas        private final String broadcastReceiverClassName;
33672ca49dced475c55926dbad730c306184bb6a68eDavid Farber & Ryan Richard
33764a6b8b69ff3076e1994899fa2de780d80bd57fcMartin Gontovnikas        public ReceiverAndIntentFilter(final String broadcastReceiverClassName, final List<String> intentFilterActions) {
33872ca49dced475c55926dbad730c306184bb6a68eDavid Farber & Ryan Richard            this.broadcastReceiverClassName = broadcastReceiverClassName;
33972ca49dced475c55926dbad730c306184bb6a68eDavid Farber & Ryan Richard            this.intentFilterActions = intentFilterActions;
34072ca49dced475c55926dbad730c306184bb6a68eDavid Farber & Ryan Richard        }
34172ca49dced475c55926dbad730c306184bb6a68eDavid Farber & Ryan Richard
34272ca49dced475c55926dbad730c306184bb6a68eDavid Farber & Ryan Richard        public String getBroadcastReceiverClassName() {
34372ca49dced475c55926dbad730c306184bb6a68eDavid Farber & Ryan Richard            return broadcastReceiverClassName;
34472ca49dced475c55926dbad730c306184bb6a68eDavid Farber & Ryan Richard        }
34572ca49dced475c55926dbad730c306184bb6a68eDavid Farber & Ryan Richard
34672ca49dced475c55926dbad730c306184bb6a68eDavid Farber & Ryan Richard        public List<String> getIntentFilterActions() {
34772ca49dced475c55926dbad730c306184bb6a68eDavid Farber & Ryan Richard            return intentFilterActions;
34872ca49dced475c55926dbad730c306184bb6a68eDavid Farber & Ryan Richard        }
34972ca49dced475c55926dbad730c306184bb6a68eDavid Farber & Ryan Richard    }
350a6ff2c2b15018092af3a28697b521d1ca5e789f0Christian Williams & Phil Goodwin}
351