Titanium is a Chromium-based browser that provides a locked and secure experience for Android 8+ devices. Managed configurations are used to customize the browsing experience.
Reach out to your Esper representative for Titanium access.
In this article:
- Default Behavior
- Customizing Titanium’s Managed Configurations
- Managed Configurations
- Managed Configuration Copy/Paste File
Default Behavior
Out of the box, Titanium displays an about:blank page without a URL bar.
Most behavior can be customized with managed configurations.
Some behaviors are available by default and not configurable.
Non-persistable tabs on restart
Requires Titanium v105.0.5195.126+
Memory is cleared upon each new browser session.
Do not track and network isolation
Requires Titanium v90.0.4430.83+
Features such as Do Not Track (which opts out of tracking by websites) and Network Isolations are available by default.
Blank new tab and page
Requires Titanium v90.0.4430.83+
The browser launches with a blank new tab and page which reduces Google branding.
Customizing Titanium’s Managed Configurations
You can customize the Titanium browser through the config file in a blueprint. In a blueprint’s Apps & Configuration section, add Titanium to the app list, and click on the Actions ellipsis (...).
Select Managed Configurations, and edit the config file.
Press Apply Changes. Then, save and publish the blueprint and converge the device. You can update the configs at any time by updating the blueprint.
Managed Configurations
Customize the browser experience with the following managed configurations. In addition, Titanium supports all Chrome managed configurations.
Allow and block list
Requires: Titanium v108.0.5359.130+
Out of the box, the browser does not allow access to any websites unless specified in the managed configuration file.
Both the allowlist and blocklist are configurable, enabling admins to specify the sites available for browsing.
Example to allow all sites and block example website:
{
"URLAllowlist":[
"*"
],
"URLBlocklist":[
"example.com"
]
}
Homepage
Requires: Titanium v108.0.5359.130+
The browser’s homepage defaults to a blank page (about:blank), which reduces Google branding. Any site may be set as the homepage with HomepageLocation.
Example to set the homepage:
{
“HomepageLocation”: "https://esper.io"
}
URL bar
Requires Titanium v108.0.5359.130+
The URL bar is hidden by default.
Example to show the URL bar:
{
"URLBarVisible": true
}
Main menu
Requires Titanium v90.0.4430.83+
The main menu is hidden by default and its keyboard shortcuts are disabled by default.
Example to show the main menu and enable the keyboard shortcut:
{
"HideMainMenu":false
}
Long press menu
Requires Titanium v90.0.4430.83+
The menu that pops up when the user presses and holds on a website can be disabled through a config file.
Example to disable long press menu:
{
"DisableLongPressMenu": true
}
Silent permissions for audio and video capture
Requires Titanium v105.0.5195.127+
Automatic audio and video capture permissions are enabled by default for sites added to AudioCaptureAllowedUrls and VideoCaptureAllowedUrls.
Example auto-enable audio and video:
{
"AudioCaptureAllowedUrls":[
"https://example.com"
],
"VideoCaptureAllowedUrls":[
"https://example.com"
]
}
Text select menu
Version 117.0.5938.155+
The text select menu is restricted by default. Options such as “Web Search” and “Open” are disabled by default. “Copy” and “Select All” are available. To customize, use values with the configuration “EnableFullTextSelectMenu”. The default value is false.
Example to enable the full-text select menu:
{
"EnableFullTextSelectMenu": true
}
Access to tab management
Version 124.0.6367.85+
Access to the tab management page is disabled by default. This disables the tab stack button and gestures that launch the tab management page.
Example to enable tab management:
{
“DisableTabManagement”: false
}
Titanium history store
Version: 131.0.6778.106+
By default, this setting is set to 0, effectively disabling it.
When this setting is enabled, it specifies the maximum number of stored entries for URL browsing history. For example, setting the value as 100 will make the maximum number of entries 100. After reaching the maximum number of entries, older entries will be replaced.
Note: Browsing history is not cleared when data is deleted with “Delete browsing data.” To clear this data, go to Android Settings > Apps and Storage > Titanium > Storage & cache > Clear storage. You may enable Android Settings through a blueprint.
Reading history store data from an Android application
History store data is read-only. It can be exposed to other Android applications via a ContentProvider.
In order to read the history store, the contract must be stored in the HistoryStoreContract.java file in the io/esper/titanium/browser/history_store/ path source.
package io.esper.titanium.browser.history_store;
import android.net.Uri;
/**
* Content provider corresponding to this contract supports only the below method.
* public Cursor query(@NonNull Uri uri, @Nullable String[] projection, @Nullable Bundle queryArgs, @Nullable CancellationSignal cancellationSignal)
*
* Below mentioned are only the supported keys in queryArgs.
* ContentResolver.QUERY_ARG_OFFSET - specifies the timestamp of type long; timestamp is measured in milliseconds, between the current time and
* midnight, January 1, 1970 UTC
* ContentResolver.QUERY_ARG_LIMIT - specifies the number of rows of type int
* ContentResolver.QUERY_ARG_SORT_DIRECTION - Value is either ContentResolver.QUERY_SORT_DIRECTION_ASCENDING or ContentResolver.QUERY_SORT_DIRECTION_DESCENDING
* specifies whether to query recent / older entries than time stamp specified with ContentResolver.QUERY_ARG_OFFSET.
* QUERY_SORT_DIRECTION_ASCENDING - recent entries are queried; QUERY_SORT_DIRECTION_DESCENDING - older entries are queried.
*/
public class HistoryStoreContract {
public static final String AUTHORITY = "io.esper.titanium.browser.history_store";
public static final String HISTORY_STORE = "history_store";
public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/" + HISTORY_STORE);
public static class Columns {
public static final String ID = "id";
public static final String TIME_STAMP = "time_stamp";
public static final String HOST = "host"; // portion of the url till top-level doamin; example: URL: 'www.esper.io/android-device-management', HOST: 'www.esper.io'
public static final String PATH = "path"; // portion of the url after top-level doamin; example: URL: 'www.esper.io/android-device-management', PATH: '/android-device-management'
public static final String ALLOWED = "allowed";
}
}
To access History store data, a ContentProvider authority and a permission has to be specified in the AndroidManifest.xml file as specified below.
<queries>
<provider android:authorities="io.esper.titanium.browser.history_store" />
</queries>
<uses-permission android:name="io.esper.titanium.browser.history_store.READ" />
This sample Kotlin code reads entries from the history store:
@WorkerThread
private fun readEntries(timeStamp: Long, noOfEntries: Int, recent: Boolean) {
try {
val queryArgs = Bundle()
queryArgs.putLong(ContentResolver.QUERY_ARG_OFFSET, timeStamp)
queryArgs.putInt(ContentResolver.QUERY_ARG_LIMIT, noOfEntries)
queryArgs.putInt(
ContentResolver.QUERY_ARG_SORT_DIRECTION,
if (recent) ContentResolver.QUERY_SORT_DIRECTION_ASCENDING else ContentResolver.QUERY_SORT_DIRECTION_DESCENDING
)
val resolver = mApplicationContext.contentResolver
val beforeTimeStamp = System.currentTimeMillis()
val cursor = resolver.query(
HistoryStoreContract.CONTENT_URI,
arrayOf(
HistoryStoreContract.Columns.TIME_STAMP,
HistoryStoreContract.Columns.HOST,
HistoryStoreContract.Columns.PATH,
HistoryStoreContract.Columns.ALLOWED
),
queryArgs,
null
)
if (cursor != null) {
try {
val idColumnIndex = cursor.getColumnIndexOrThrow(HistoryStoreContract.Columns.ID)
val timeStampColumnIndex = cursor.getColumnIndexOrThrow(HistoryStoreContract.Columns.TIME_STAMP)
val hostColumnIndex = cursor.getColumnIndexOrThrow(HistoryStoreContract.Columns.HOST)
val pathColumnIndex = cursor.getColumnIndexOrThrow(HistoryStoreContract.Columns.PATH)
val allowedColumnIndex = cursor.getColumnIndexOrThrow(HistoryStoreContract.Columns.ALLOWED)
while (cursor.moveToNext()) {
val id = cursor.getLong(idColumnIndex)
val timeStamp = cursor.getLong(timeStampColumnIndex)
val host = cursor.getString(hostColumnIndex)
val path = cursor.getString(pathColumnIndex)
val allowed = cursor.getInt(allowedColumnIndex)
// process hsitory store entry
}
} catch (e: IllegalArgumentException) {
// handle exception
} finally {
cursor.close()
}
}
} catch (e: Exception){
// handle exception
}
}
Managed Configuration Copy/Paste File
Copy the file. Note that all keys are set to their default values.
{
"URLAllowlist": [
"*"
],
"URLBlocklist": [
"example.com"
],
"HomepageLocation": "https://esper.io",
"URLBarVisible": false,
"HideMainMenu": false,
"DisableLongPressMenu": true,
"AudioCaptureAllowedUrls": [
"https://example.com"
],
"VideoCaptureAllowedUrls": [
"https://example.com"
],
"EnableFullTextSelectMenu": false,
"DisableTabManagement": true,
"HistoryStoreMaxSize": 0
}