Privacy

Due to the fact the screen is being recorded at all times, in some cases you might want to protect some sensitive data from showing up in the recording. Depending on the nature of the app, in some cases even beta testers might have something on their screen they don't want to share with developer.

Fortunately, this is an easily solvable problem. We have few options to tackle this problem:

Protected activity

You can protect any activity and prevent it from being recorded by adding it's class to the list of secure activities. Whenever user navigates to such activity, we substitute the actual screen content with black frames and stop recording touch events.

    Bugsee.addSecureActivity(MySecretActivity.class.getName());

Activities with system flag FLAG_SECURE are protected from video and touches recording without necessity to call any Bugsee methods. This flag can be set to activity in the following way.

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    getWindow().setFlags(WindowManager.LayoutParams.FLAG_SECURE, WindowManager.LayoutParams.FLAG_SECURE);
    //...
}

Protected view

You can prevent any view from being recorded by adding it to the list of secure views. When such views are visible, we substitute actual view with black rectangle in video frame.

Marking view as protected in xml layout

Protected views can be marked in xml layout by adding app:bugsee_secure attribute to the protected view. This attribute can be set to boolean or reference to boolean value. In order to prevent showing Lint warning, related to the attribute, you can add tools:ignore="MissingPrefix" line to your protected view declaration. Protected view must have id attribute.

<!-- LinearLayout is used only for example -->
<LinearLayout 
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    xmlns:app="http://schemas.android.com/apk/res-auto" <!-- You can use arbitrary name instead of "app" -->
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <View android:id="@+id/my_secret_view1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:bugsee_secure="true" <!-- Boolean value -->
        tools:ignore="MissingPrefix"/>

    <View android:id="@+id/my_secret_view2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:bugsee_secure="@bool/enable_bugsee_hide" <!-- Reference to boolean value -->
        tools:ignore="MissingPrefix"/>
</LinearLayout>

Then it is enough to call one method in code of your activity just after setContentView() method call.

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.your_layout_name);

    Bugsee.addSecureViews(R.layout.your_layout_name, this);
}

Marking view as protected in code

The alternative approach is to mark each protected view in code.

    Bugsee.addSecureView(mySecretView);

    // View is substituted by black rectangle in video.

    Bugsee.removeSecureView(mySecretView);

Protected web page elements

You can also prevent any web page element, shown in WebView, from being recorded by adding class="bugsee-hide" to it.

<input type="text" class="bugsee-hide">

Elements with type="password" are not recorded by default. If you want such web page element to be recorded, add class="bugsee-show" to it.

<input type="password" class="bugsee-show">

Bugsee detects WebViews automatically, but if you use WebView.setWebViewClient() method, it is necessary to call Bugsee.addSecureWebView() method to prevent recording of protected web page elements in this WebView.

WebView webView;
// Initialize WebView
//...
webView.setWebViewClient(new WebViewClient());
Bugsee.addSecureWebView(webView);

There is one more case, when it is necessary to call Bugsee.addSecureWebView() method - if you add WebView to Activity dynamically and set ViewGroup.OnHierarchyChangeListener to the WebView parent.

public class WebViewActivity extends BaseActivity {
  @Override
    protected void onResume() {
        super.onResume();

        ViewGroup contentContainer = (ViewGroup)findViewById(R.id.content_container); // ViewGroup in Activity layout.
        contentContainer.setOnHierarchyChangeListener(mHierarchyChangeListener);
        WebView webView;
        // Initialize WebView
        //...
        contentContainer.addView(webView);
        Bugsee.addSecureWebView(webView);
    }

    private final ViewGroup.OnHierarchyChangeListener mHierarchyChangeListener = new ViewGroup.OnHierarchyChangeListener() {
        //...
    };
}

Protected rectangles

You can also protect rectangle on screen from being recorded by adding it to the list of secure rectangles. It can be especially useful in games, since there is no views there which can be made secure, and objects are drawn on canvas in case of 2D and on surface in case of 3D.

// Add secure rectangle.
Bugsee.addSecureRectangle(new Rect(100, 100, 200, 200));
// Get all secure rectangles.
ArrayList<Rect> secureRects = Bugsee.getAllSecureRectangles();
// Remove single rectangle from the list of secure rectangles.
Bugsee.removeSecureRectangle(new Rect(100, 100, 200, 200));
// Clear the list of secure rectangles.
Bugsee.removeAllSecureRectangles();

Note, that secure rectangle coordinates remain the same after screen orientation change. But if necessary you can remove old secure rectangles and add new ones when, for example, Activity is being recreated on orientation change.

Manual Pause & Resume

The following APIs will come in handy, no video or touch events are being gathered between the calls to pause() and resume() below:

    // To stop video recording use   
    Bugsee.pause();

    // No touches are recorded, black frame is being recorded instead of actual data in the video.

    // And to continue
    Bugsee.resume();

Network traffic

Bugsee captures network activity from the application and stores headers and in some cases body of the request and response. In order to allow you to hide user identifiable and other sensitive data from these network logs, we provide a way to register a filter and process each event before it's being recorded into Bugsee logs.

The principle is simple, for every event to be recorded, Bugsee will call your method and provide you with BugseeNetworkEvent object. It is your method's responsibility to clean up all user identifiable data from that structure and call listener.onEvent(event) to pass it back to Bugsee. listener.onEvent(event) can be called in other thread than calling thread.

    Bugsee.setNetworkEventFilter(new NetworkEventFilter() {
        @Override
        public void filter(BugseeNetworkEvent event, NetworkEventListener listener) {
            String body = event.getBody();
            if (body != null) {
                // ..make changes
                event.setBody(body);
            }
            String errorDescription = event.getErrorDescription();
            if (errorDescription != null) {
                // ..make changes
                event.setErrorDescription(errorDescription);
            }
            String errorShortMessage = event.getErrorShortMessage();
            if (errorShortMessage != null) {
                // ..make changes
                event.setErrorShortMessage(errorShortMessage);
            }
            Map<String, Object> headers = event.getHeaders();
            if (headers != null) {
                // ..make changes
                event.setHeaders(headers);
            }
            String url = event.getUrl();
            if (url != null) {
                // ..make changes
                event.setUrl(url);
            }

            // Send the sanitized event back to Bugsee to record
            // Skip this in order to completely omit the event from Bugsee recording!
            listener.onEvent(event);
        }
    });

Logcat logs

Bugsee captures Logcat logs. In order to allow you to hide user identifiable and other sensitive data from these logs, we provide a way to register a filter and process each log message before it's being recorded into Bugsee logs. Bugsee will call your method for every event to be recorded and provide you with BugseeLog object. It is your method's responsibility to clean up all user identifiable data from that structure and call listener.onLog(log) to pass it back to Bugsee. listener.onLog(log) can be called in other thread than calling thread.

    Bugsee.setLogFilter(new LogFilter() {
        @Override
        public void filter(BugseeLog log, LogListener listener) {
            String message  = log.getMessage();
            if (message != null) {
                // ..make changes
                log.setMessage(message);
            }

            // Send the sanitized log back to Bugsee to record
            // Skip this in order to completely omit the log from Bugsee recording!
            listener.onLog(log);
        }
    });