Because TextView based controls are used for text fields, to get dwell time and other data you instrument the OnFocusChangeListener to know when a user starts and completes typing.
// Get TextView based control
final EditText nameEditText = (EditText) findViewById(R.id.nameEditText);
// Create a OnFocusChangeListener
OnFocusChangeListener focusListen = new OnFocusChangeListener () {
public void onFocusChange(View view, boolean hasFocus){
if(hasFocus == false){
Tealeaf.logEvent(view, Tealeaf.TLF_ON_FOCUS_CHANGE_OUT);
}
else{
Tealeaf.logEvent(view, Tealeaf.TLF_ON_FOCUS_CHANGE_IN);
}
}
});
// Set OnFocusChangeListener on TextView based control
nameEditText.setOnFocusChangeListener(focusListen);
// Register TextView based control
Tealeaf.registerFormField(nameEditText, this);
For ExpandableListView controls, in order to know when a user expands or collapses a control you instrument the OnGroupCollapseListener and OnGroupExpandListener.
// Get ExpandableListView based control
final ExpandableListView elv = (ExpandableListView) findViewById(R.id.elv);
elv.setOnChildClickListener(new OnChildClickListener() {
public boolean onChildClick(ExpandableListView parent, View view,
int groupPosition, int childPosition, long id) {
Tealeaf.logEvent(view);
return true;
}
});
elv.setOnGroupCollapseListener(new OnGroupCollapseListener() {
public void onGroupCollapse(int groupPosition) {
Tealeaf.logEvent(elv, Tealeaf.TLF_ON_GROUP_COLLAPSE);
}
});
elv.setOnGroupExpandListener(new OnGroupExpandListener(){
public void onGroupExpand(int groupPosition) {
Tealeaf.logEvent(elv, Tealeaf.TLF_ON_GROUP_EXPAND);
}
});
For SlidingDrawer controls, to know when a user opens or closes a control you instrument the OnDrawerOpenListener and OnDrawerCloseListener.
// Get SlidingDrawer based control
<span class="keyword">final</span> SlidingDrawer sd = (SlidingDrawer) findViewById(R.id.sd);
sd.setOnDrawerOpenListener(<span class="keyword">new</span> OnDrawerOpenListener() {
<span class="keyword">public</span> void onDrawerOpened(){
Tealeaf.logEvent(slidingDrawer_c5, Tealeaf.TLF_ON_DRAWER_OPENED);
}
});
sd.setOnDrawerCloseListener(<span class="keyword">new</span> OnDrawerCloseListener(){
<span class="keyword">public</span> void onDrawerClosed(){
Tealeaf.logEvent(slidingDrawer_c5, Tealeaf.TLF_ON_DRAWER_CLOSED);
}
});
Custom privacy masking is a feature that matches specified IDs and regular expressions and then does character substitutions. In the example that follows, custom privacy masking converts actual values to the letters that are supplied as replacements. If custom privacy masking is set to false, it returns an empty string. You specify privacy masking in the TLFConfigurableItem.properties file that is in the assets folder of the Android application.
#Masking settings
HasMasking=true
#It can be a series of ids and regular expressions comma delimited
MaskIdList=com.tealeaf.sp:id\/EditText*,com.tealeaf.sp:id\/login.password
#If set to false it will return an empty string
HasCustomMask=true
#It will turn small letters to value given
SensitiveSmallCaseAlphabet=x
#It will turn capital letters to value given
SensitiveCapitalCaseAlphabet=X
#It will turn symbols to value given
SensitiveSymbol=#
#It will turn digits to value given
SensitiveNumber=9
You can privacy mask specific rows of a RecycleView by adjusting your privacy masking settings.
Procedure
- In your application, go to the RecyclerAdapter class attached to the RecycleView .
RecyclerAdapter adapter = new RecyclerAdapter(persons);
rv.setAdapter(adapter);
- Inside the RecyclerAdapter class, go to the function where you set the content of the TextView you want to mask. This function is called onBindViewHolder .
@Override
public void onBindViewHolder(final ProductViewHolder productViewHolder, int i) {
productViewHolder.productName.setText(products.get(i).name);
productViewHolder.productDescription.setText(products.get(i).description);
productViewHolder.productPhoto.setImageResource(products.get(i).photoId);tAdapter(adapter);
- Set the tag of the TextView that you would like to mask. In this example, we used the product name on rows 0 and 6, meaning the product name from the first and seventh rows.
if(productViewHolder.getLayoutPosition() == 0 || productViewHolder.getLayoutPosition() == 6){
productViewHolder.productName.setTag("customTag");
} else {
productViewHolder.productName.setTag(null);
}
- In your application folder, go to Assets and TealeafBasicConfig.properties to find the Masking Settings. Make sure that the name of your tag (in this example, customTag) is added to the MaskIdList. This indicates that every UI component that has customTag as a tag will be masked.
#Masking settings
HasMasking=true
MaskIdList=com.tealeaf.sp:id\/EditText*,com.tealeaf.sp:id\/login.password,customTag
HasCustomMask=true
SensitiveSmallCaseAlphabet=x
SensitiveCapitalCaseAlphabet=x
SensitiveSymbol=#
SensitiveNumber=9
You can privacy mask specific rows of a ListView that is reused by two activities, similar to masking specific rows of RecycleView.
Procedure
- From the first activity that is using a list view in your application, go to the adapter attached to the ListView .
mListView = (ListView) findViewById(R.id.list_view);
adapter = new CustomBaseAdapter(this, items, false);
mListView.setAdapter(adapter);
- In the CustomBaseAdapter class, go to the function where you set the content of the TextView you want to mask (this function is called onView).
public View getView(int position, View convertView, ViewGroup parent) {
holder = null;
LayoutInflater mInflater = (LayoutInflater)
context.getSystemService(Activity.LAYOUT_INFLATER_SERVICE);
if (convertView == null) {
convertView = mInflater.inflate(R.layout.custom_main_list_row, parent, false);
holder = =new ViewHolder();
holder.txtDesc = (TextView) convertView.findViewById(R.id.desc);
holder.imageView = (ImageView) convertView.findViewById(R.id.icon);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
RowItem rowItem = (RowItem) getItem(position);
final int indexRow = position;
holder.txtDesc.setText(rowItem.getDesc());
holder.imageView.setImageResource(rowItem.getImageId());
if(fromSearch){
holder.imageView.setVisibility(View.GONE);
}
- Set the tag of the TextView you want to privacy mask. In this example, the description of the third row from the MainActivity class.
if(indexRow == 2 && context.getClass().equals(MainActivity.class)){
holder.txtDesc.setTag("third-row");
}
- In your application folder, go to Assets and TealeafBasicConfig.properties to find the Masking Settings. Make sure that the name of your tag (in this example,third-row) is added to the MaskIdList. This indicates that every UI component that has third-row as a tag will be masked.
#Masking settings
HasMasking=true
MaskIdList=third-row,clicked
HasCustomMask=true
SensitiveSmallCaseAlphabet=x
SensitiveCapitalCaseAlphabet=x
SensitiveSymbol=#
SensitiveNumber=9
AdvertisingId
. The Google Play services advertising ID is a unique, user-resettable ID for advertising. The advertising ID gives users better controls and provides developers with a standard system to continue to monetize their apps. The advertising ID also gives users the ability to reset their identifier or opt out of personalized ads within Google Play applications.
Procedure
- Open
AndroidManifest.xml
, add the following snippet to theapplication
section.
<meta-data
android:name="com.google.android.gms.version"
android:value="@integer/google_play_services_version" />
- Open the
app.gradle
file for your application and add the following snippet to add the Google Play Service ads library.
dependencies {
// Requires for Google Play ads library compile
'com.google.android.gms:play-services-ads:9.4.0'
…
}
"clientEnvironment": {
"osVersion": "5.0",
"height": 1920,
"width": 1080,
"deviceWidth": 360,
"deviceHeight": 640,
"pixelDensity": 3,
"mobileEnvironment": {
"totalStorage": 6619593,
"totalMemory": 369287168,
"locale": "English (United States)",
"language": "English",
"manufacturer": "samsung",
"deviceModel": "SM-N900V",
"appName": "AuroraAuto",
"appVersion": "1.0",
"deviceId": "",
"orientationType": "PORTRAIT",
"android": {},
"advertisingId": "567eca34-2ea3-4f80-9436-ea63a7abc5b0" },
"osType": "Android",
"orientation": 0
}
If the end user has chosen to opt out of ads, advertisingId
returns the following value:
“advertisingId”: “N/A”
If you use OverStat in an Activity or Fragment, you must implement logFormCompletion
to generate reports based on user activity within a form.
Note:
This step is completely manual and will not be automated because of the different architectures that an application can have, it is difficult to instrument. The form page can also have additional custom validation that would indicate if completion was correct or not.
Button addToCart = (Button) productView.findViewById(R.id.buttonAddCart);
addToCart.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Tealeaf.logFormCompletion(true);
Local images
Images that are bundled within an application can be extracted by using the README.txt
file under the Android Release folder: AndroidRelease/Tealeaf/AndroidImageCaptureTool/README.txt
.
The tool extracts all the packaged image resources in the APK file and set an extra attribute called "tag" on the application's layout XML file for Views that contain images.
For example, android:tag="@drawable/home_background"
tag is automatically added by the tool as shown. You can also manually update it to select a different image resource ID if needed:
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/home_background"
android:tag="@drawable/home_background" />
External images
These images are usually hosted on external servers, which are loaded dynamically during an application's runtime environment via network requests.
Due to Android framework limitations on capturing runtime images and performance considerations, you would need to pass external image URL paths to
- Use the
ImageView.setTag((String) url)
method
Note:
This method assumes that you are not using the ImageView's tag object in your code.
- Use the
ImageView.setTag(resourceId,(String) url)
method
Note:
This method assumes that you are using the View's tag object in your code, then you can follow the following code snippet to redirect the ImageView.setTag(ImageView.getId(), tag)
.
The following sample ImageView definition shows an "android:tag" attribute, which would be automatically generated by the image extraction tool, or you can manually update support image replay:
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/home_background"
android:tag="@drawable/home_background" />
- For image replay, use a View's tag object. The following example shows how to redirect the tag object to the View's setTag:
ImageView myView = (ImageView) findViewById(R.i.d.image1);
//Potential XML tag found
Object tag = myView.getTag();
//Assuming myTag is the object you want to set for the view
if ((tag == null) || (tag != null && !(tag instance of myTag))) {
//Redirect the tag to the other setTag(View.setTag(resourceId, object) method which operated on a HashMap data structure.
if ( View.NO_ID !=view.getID() && view.getId() != 0 && tag != null) {
myView.setTag(myView.getId(), tag);
}
Android auto instrumentation capability configuration files
teacuts.jar
is a module that provides Android auto instrumentation capabilities. The two configuration files are shown:
TeaCutsAdvancedConfig.json
- Advanced configuration file for enabling or disabling auto instrumentation features.
{
"TeaCutsLibraryVersion":"2.0.0.1",
"DefaultAlertDialogLayoutDelay":500
}
DefaultAlertDialogLayoutDelay property is default at 500 milliseconds. You can change this value if the replay shows a timing issue when the AlertDialog is displayed.
TeaCutsBasicConfig.properties
- Basic configuration file for enabling or disabling auto instrumentation features.- Starting the 2.0.0.1 ability to auto instrument AlertDialogs
It defaults totrue
. If you used manual instrumentation for AlertDialog, then you can set it tofalse
.
AlertDialogEnabled=true
- Starting 2.0.0.1 ability to auto instrument TextView/Button/EditText without explicit OnClick listener
Note:
This feature supports only API level 15 or above.
- It defaults to
true
. If you used manual instrumentation, then you can set it tofalse
.
TextViewEnabled=true
Updated 3 months ago