Mobile/Fennec/Android/CommonTips
Contents
General coding tips
Finding relevant code
Almost all of the Fennec-specific code is in the mozilla-central source tree under:
mobile/android/...
Of particular interest to most new contributors will be:
mobile/android/base/java/org/mozilla/gecko/BrowserApp.java # the main Android activity that starts when you open Fennec mobile/android/chrome/content/browser.js # the main JavaScript file that controls Gecko to make it do what we want
If you are looking for something specific, use the code-search tool at http://dxr.mozilla.org/ to search for relevant pieces of code.
Debugging
For the JavaScript parts of the code base, remote debugging with a desktop version of Firefox is the most effective way to see what is going on, add breakpoints, etc.
For Android Java code, if you have IntelliJ set up, the debugger works well and allows you to set breakpoints, inspect variables and objects, etc. See http://developer.android.com/tools/debugging/ddms.html
Debugging without an IDE is much more primitive, and you can try using Android Log statements and inspecting logcat.
logcat is a tool that is going to show you some logs prompted by the device. It might be a good help if you don't want to or can't run gdb. You can use it by running this command:
adb logcat -v time
You can make things appear in logcat using printf_stderr. With debug builds, NS_WARNING, NS_ERROR and NS_ASSERTIONS will show up in logcat. If you're trying to debug something, you may wish to pipe the logcat output through grep to filter out irrelevant things (most Fennec-related output will be viewable by
adb logcat -v time | grep Gecko
but remember that when attaching log output to a bug you should include unfiltered output as there may be relevant log entries under other tags.
If you want more debugging tools, Advanced Debugging is a good place to look.
Coding Style
The Java style follow the Mozilla Coding Style.
You can run `./mach gradle checkstyle` to automatically catch some style issues locally.
Common nits in Reviews
Check for these nits before asking for review for a patch:
- Remove trailing whitespace
- Spacing
- Four spaces for Java indent (for main Fennec code - android-sync github project has different spacing)
- Around operators (+, -, etc.) and :
- Between comment "//" and text
- Braces for Java if statements, even if they are one line
- Comments should be full sentences (capitalization, punctuation)
- Good comments are useful and clear even for someone reading a particular area of code for the first time
- Avoid using single-letter variables in almost all cases - it makes code harder to read
Strings
Add an Android string resource
- Add an XML string entity to mobile/android/base/locales/en-US/android_strings.dtd with the English string you want to add.
- Add a <string> element to mobile/android/base/strings.xml.in.
- Build using mach build mobile/android/base or your IDE.
Your new string should appear in org.mozilla.gecko.R.string. Here's an example patch that adds the single string pref_private_data_syncedTabs.
Why is this necessary? Mozilla's main localization process is based on XML entities. Localization teams localize the XML entity definitions using existing tools, but they do not see strings.xml itself. Building prepares the final strings.xml for use. You can be sure your changes are in place by finding your entity and string in $OBJDIR/mobile/android/base/res/values/strings.xml.
Modify an existing Android string resource
- Find the relevant <string> element in mobile/android/base/strings.xml.in.
- Find the underlying English string entity in mobile/android/base/locales/en-US/android_strings.dtd. Usually, you'll see <string>&string_entity;<string>; the string entity is string_entity.
- If your change is just fixing a typo (spelling error, capitalization, whitespace), just update the android_strings.dtd.
- If you are really changing the string, you also need to change the entity name. It's traditional to add or increment a trailing integer, like string_entity2.
- Build using mach build mobile/android/base or your IDE.
Your updated string should appear. Here's an example patch that changes several strings, including renaming tab_queue_notification_text_singular to tab_queue_notification_text_singular2.
Why is this necessary? Mozilla's localization process only recognizes new string entities, not modified string entities. (The old, unused entity is automatically ignored and eventually deleted.)
Testing
Add a new Robocop test
- Add a Java test file named like mobile/android/tests/browser/robocop/testMyThing.java. This will get your test compiled into the Robocop APK.
- Add your test file/name section like [testMyThing] to mobile/android/tests/browser/robocop/robocop.ini. Without this, the Robocop test harness will not know about your test!
- Optionally add HTML, JS, and CSS resources to folder mobile/android/tests/browser/robocop.
- Run mach build mobile/android to get them built/installed before running your test.
- Make sure you have host binaries downloaded and configured, following Host Builds (MOZ_HOST_BIN).
- Run mach robocop testMyThing to run your new test on your device.
- Iterate!
Here's an example patch that adds a fairly complicated new testSelectionCarets test.
See also some tips on writing UITests, or you can read about Testing on Firefox for Android.
Other
Copy a profile from your phone
E.g., to explore with sqlite3. Use Copy Profile.
Add new Android ids that identify resources that are only included in some builds
If you add a resource that you refer to by ID in code, your build will fail if that resource isn't present in a build that excludes that resource. You'll typically see this when adding a resource that's only used in v11+ builds, which aren't included in resource-constrained builds for Gingerbread.
For example, you'll see log output like:
14:15:27 INFO - /builds/slave/…/build/src/mobile/android/base/preferences/GeckoPreferenceFragment.java:122: error: cannot find symbol 14:15:27 INFO - return R.id.pref_header_general;
To fix this, you should should add a stub for the new id in mobile/android/base/resources/values/ids.xml.
You should also make sure that code that needs a valid resource id is behind a version check.
Add a new table to browser.db
To follow along with code, see Bug 1250707.
Prepare migration tests
- Capture a current version of the database (before your changes!) with some browsing data from your device using the Copy Profile add-on. Put this in mobile/android/tests/browser/robocop/assets/browser_db_upgrade/v<#>.db. It is used to test your upgrade changes in testBrowserDatabaseHelperUpgrades. The test should automatically pick up your new version.
Create the table and query & insert via BrowserProvider
- Add your table name & schema as a new static class in BrowserContract. It will likely need the @RobocopTarget annotation to be accessible for testing
- Increment the DATABASE_VERSION in BrowserDatabaseHelper and update the related bug # comment
- Implement a create method to create your table
- Add a call to it in BrowserDatabaseHelper.onCreate
- Add a method to upgrade the database from the old version to the new version (which likely calls your create table method) and add it to BrowserDatabaseHelper.onUpgrade
- Register your new table with BrowserProvider by adding your table to the URI_MATCHER in the BrowserProvider constructor (pattern match the other values). Note the TABLE_* constant, the constants assigned to ints, and the *_PROJECTION_MAP constant.
- Add to the BrowserProvider.query method (pattern match!) by setting the projection map and table in the SQLiteQueryBuilder object.
- Add to the BrowserProvider.insertInTransaction method (pattern match!) by calling out to your own method to insert into the DB
Test insertions via BrowserProvider
- Add a TestInsert* extends TestCase class with a test method. Insert a value, query, and make sure you receive what you think you should! TestInsertUrlAnnotations should provide a guide on how to write an extensible test that allows you to more easily test additions later on in this guide.
- Register your test to be run in TestBrowserProvider.setUp
Add a class to abstract querying your table from within Fennec
So instead of accessing the content provider directly, you can call, YourTable.insert(url, title);.
Alternatively, add these methods directly to LocalBrowserDB & friends if your queries overlap the queries there or share data (e.g. table join). This method won't be discussed here.
- Add a new interface for your class in omg.db. It should contain an insert* method with a ContentResolver arg and whatever else you want to insert. This method will likely need @RobocopTarget
- Add a class implementing this interface. The current pattern for the class name is Local* (like LocalBrowserDB). The insert method should use the ContentResolver to talk insert via the BrowserProvider methods you previously implemented.
- Add a getTableName method to the BrowserDB interface. It will like need @RobocopTarget.
- Construct your class in the constructor of LocalBrowserDB and store it in a member variable. Add the implementation of your getter from above (also @RobocopTarget).
- Add Stub* implements <your-interface> to StubBrowserDB and have the implementation do nothing. Construct your Stub* with your member variable declaration and add the getter.
- Don't forget to add your new files to moz.build
Test the class to query via the ContentResolver
- Add to the test method you previously wrote in testBrowserProvider. Follow TestInsertUrlAnnotations for an extensible pattern.
Next steps
You probably want an update and delete method too... get to it! :P
Updating search engine icons
Mobile/Fennec/Android/Updating search engine icons