How-tos with Sample Code for Android
Privacy mask controls
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 TealeafBasicConfig.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
How to privacy mask specific rows of a RecycleView
You can privacy mask specific rows of a RecycleView by adjusting your privacy masking settings.
- 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);
fun onBindViewHolder(productViewHolder: ProductViewHolder, i: Int) {
productViewHolder.productName.setText(products.get(i).name)
productViewHolder.productDescription.setText(products.get(i).description)
productViewHolder.productPhoto.setImageResource(products.get(i).photoId)
}
- 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");
}
if (productViewHolder.getLayoutPosition() === 0 || productViewHolder.getLayoutPosition() === 6) {
productViewHolder.productName.setTag("customTag")
}
- 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
How to privacy mask specific rows of a ListView that is reused by two activities
You can privacy mask specific rows of a ListView that is reused by two activities, similar to masking specific rows of RecycleView.
- 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);
}
fun getView(position: Int, convertView: View?, parent: ViewGroup?): View {
var convertView = convertView
holder = null
val mInflater = context!!.getSystemService(Activity.LAYOUT_INFLATER_SERVICE) as LayoutInflater
if (convertView == null) {
convertView = mInflater.inflate(R.layout.custom_main_list_row, parent, false)
holder =
ViewHolder()
holder.txtDesc = convertView!!.findViewById<View>(R.id.desc) as TextView
holder.imageView = convertView.findViewById<View>(R.id.icon) as ImageView
convertView.tag = holder
} else {
holder = convertView.tag as ViewHolder
}
val rowItem: RowItem = getItem(position) as RowItem
val 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");
}
if (indexRow === 2 && context.getClass().equals(MainActivity::class.java)) {
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
Instrument Form Completion in your application
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.
Example when a form is complete and ready to submit:
Button addToCart = (Button) productView.findViewById(R.id.buttonAddCart);
addToCart.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Tealeaf.logFormCompletion(true);
val addToCart = productView.findViewById(R.id.buttonAddCart) as Button
addToCart.setOnClickListener(object : View.OnClickListener {
override fun onClick(view: View) {
Tealeaf.logFormCompletion(true)
Extract and capture application images for replay
Acoustic Tealeaf provides capabilities to capture and replay an application's local and external images.
Local images
Images that are bundled within an application can be extracted by using the Acoustic Tealeaf Android Image Extraction tool as an initial step for Tealeaf SDK integration and better replay experience. To get started, find 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 Tealeaf SDK by using one of the following mechanisms:
- 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 Tealeaf tag to
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);
}
val myView = findViewById(R.i.d.image1) as ImageView
//Potential XML tag found
val tag = myView.tag
//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!!.id !== 0 && tag != null) {
myView.setTag(myView.id, 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
- It defaults to
true
. If you used manual instrumentation, then you can set it tofalse
.
TextViewEnabled=true
Updated about 1 month ago