As part of my last release i have i decided to work on a more complicated case. This time around i did not fix relatively easy issue, but rather picked up a complicated task that requires more time and knowledge to be invested. I have pushed code that resets Mozilla Focus browser settings to default. It is essentially a new feature that has not been implemented into the browser yet.
First of all lets define what Mozilla Focus is and what it is used for. Mozilla Focus is a mobile application that provides the user with secure browsing environment as if no one’s watching. The new Firefox Focus automatically blocks a wide range of online trackers — from the moment you launch it to the second you leave it. Easily erase your history, passwords and cookies, so you won’t get followed by things like unwanted ads. It is a very nice browser i regularly use myself. It is getting more and more popular lately, especially after all the security issues major companies have had and the news that have been leaked. The public gets more concerned with what happens to their private data and how it is can be used against them. Thus people start investing into secure and seemingly harmless applications (as of right now). Mozilla Focus is an open source project that provides support for two major mobile platforms Android and IOS. I will contribute to the the Android version of Focus open source project that is hosted on GitHub. The project is a very active and has around 400 open bugs. So i believe it is a good place to contribute to and gain some valuable Android experience.
The feature (#1848) i worked on is related to adding a functionality that would reset the the current browser settings to default. Meaning all the preferences like language, block social trackers, block JavaScript should be cleared and the all the default preferences have to be reused. The Setting tab of the Firefox Focus has a lot of preferences thus is is handy to add a button/preference that would simply remove all the settings with a single click. Here is how the Settings view looks like with all the main preferences:
As you can see there are a lot of things the user can set, so to make the UI more friendly we need to make sure the user can rollback to default any time and with ease. Lets begin coding.
First of all i added the preference XML code to the settings.xml that would represent a button the user can click.
<Preference android:key="@string/pref_key_reset_default_browser" android:title="@string/preference_browser_default_settings" android:summary="@string/preference_browser_default_settings_summary" android:defaultValue="false" />
Note how differently the above XML code is written. Usually the XML class has an Id attribute to identify the class and text attribute to set the class label text. However that strategy would require two classes to represent one button since the XML would link two labels to represent single Button title and summary. On the other hand, Mozilla Focus developers use Preference XML class that has key instead of Id, title to represent button header and summary to represent button description. To be honest i have newer seen this type of advanced XML before and it is truly amazing to get to know new trick. So Preference is not just a button, but rather a very smart button that allows the developer to customize the looks and the functionality of the Preference. This seemingly simple XML code made me question my Android skills for a second or two:)
Note that title and summary string resources have been added to the strings.xml to represent the following text in English:
<!-- Action header to reset the browser settings to default. --> <string name="preference_browser_default_settings">Reset</string> <!-- Action summary for reset the browser settings. --> <string name="preference_browser_default_settings_summary">Reset browser settings to default</string>
Ok so once the button is added we can finally take a look at the UI and check out if the newly added preference fits the design.
Looks stunning, mostly because the UI looks awesome already!
Now is time to add the largest code snippet that would link the preference with a listener that would respond to the event in SettingsFragment.java. Here is the code that responds to the button click and resets the browser settings to default:
} else if (preference.getKey().equals(resources.getString(R.string.pref_key_reset_default_browser))) { // Reset browser settings to default PreferenceManager.getDefaultSharedPreferences(getActivity().getApplicationContext()) .edit() .clear() .apply(); // Reset locale to default - US final LocaleManager localeManager = LocaleManager.getInstance(); localeManager.setSelectedLocale(getActivity(), String.valueOf(Locale.US)); localeManager.updateConfiguration(getActivity(), Locale.US); // Update the language selection (in dialog) final ListPreference languagePreference = (ListPreference) findPreference(getString(R.string.pref_key_locale)); languagePreference.setValue(String.valueOf(Locale.US)); // Scroll to selected item in ListView. final ListView mListView = getActivity().findViewById(android.R.id.list); mListView.smoothScrollToPosition(0); if (mListView != null) { mListView.setVerticalScrollBarEnabled(false); } // Half a second delay for better animation new CountDownTimer(500, 1000) { public void onTick(long millisUntilFinished) {} public void onFinish() { // Manually notify SettingsActivity of browser settings reset if (mListView != null) { mListView.setVerticalScrollBarEnabled(true); } if (getActivity() != null) { addPreferencesFromResource(R.xml.settings); } } }.start(); }
Let me walk you through the feature implementation logic. The first/parent if statement is located within am event listener function that watches the settings preference list using XML key attribute. If any preference changes the listener isolates the preference by its key and executes the logic for the corresponding preference that triggered an event.
Then the logic within the if statement clears the Preference Manager shared preferences. Meaning all the preference states are back to it original state. For example if the current state for the “Block analytic trackers” is on:
After the shared preferences are removed the preference will be back to its original state – off:
However shared preferences are not the only thing we need to reset. The locale and language have to be set to its original value. The default Firefox locale is US and language is English. The locale is reset (line 9-11) and the language gets updated in the language custom dialog and settings view during the refresh (line 14-15).
Once the preferences are reset to default we need to refresh the view. And this is where the major issue comes in. The refresh has to be well animated and smooth to correspond to the apps quality and UI integration rules. I browsed through the Focus files to find the logic that would help me easily refresh the view. I found out how to refresh the view but the animation was not proper and caused some jiggling effect. So i had to come up with own logic to refresh setting activity with nice animation.
So here is what i did (line 18-36 of the above code). I decided to set a timer for half a second to complete the animation. Then while the timer is ticking i tell the preferences list view to scroll up to the fist item in the list. Once the scroll is complete i refresh the settings view (recreate the view). The reason why i implemented this logic is because the refresh will cause the view to shake since the “Reset” button is in the bottom of the view. If you create the settings view it will always drop you to the first couple preferences, thus the refresh will cause discontinuity in animation because you momentarily go from last preference to first preference. That is why i decided to scroll up first and then recreate the view so that no jumping occurs.
Now lets run a quick test to prove that the functionality works:
As you can see i have changes a couple of preferences: changed language, turned off block dd trackers preference, turned on block other content trackers preference, etc. Once i clicked the reset button everything reset to default.
As you might notice the reset preference title and summary are always in English, since i have not localized these two strings. I originally planned to, but i decided it would be wise to get feedback on my code first before attempting to translate to more then 30 languages that Firefox Focus supports.
To conclude this release gave me unforgettable experience and enjoyment with Android. I have learned new tricks and advanced my knowledge with mobile development. First thing i learned is the advanced XML and styling Technics used to develop the views. XML is very responsive markup language and it is easy to work with most of the time. Also i liked the styling and code documentation. No unnecessary comments and if code is commented it should be concise and to the point. Another thing that i liked is the fact that you work on Mozilla code, that more experienced and established developers contributed. It exited me a lot and gave extra enthusiasm to keep grinding and get the job done.
On the other hand working on Mozilla code is very stressful since it is a huge project that has thousands lines of code. Most of time i bumped into problems that were causes by me simply not being familiar with something. Thus i had to do a lot of reading, review and research before i could add a single line of code. overall it has been amazing experience. I am pretty sure that my solution will get criticized and i will have to modify the code, but in the end of the day that is something i expect.