<NME> TapLatencyFragment.java
<BEF> /*
 * Copyright (C) 2015 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.chromium.latency.walt;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageButton;
import android.widget.TextView;

import java.io.IOException;

public class TapLatencyFragment extends Fragment
    implements View.OnClickListener {
    TextView mLogTextView;
    MainActivity activity;
    TextView mTapCatcher;
    int moveCount = 0;
    int allDownConunt = 0;
    private SimpleLogger logger;
    private TraceLogger traceLogger;
    private WaltDevice waltDevice;
    private TextView logTextView;
    private TextView tapCatcherView;
    private TextView tapCountsView;
    private TextView moveCountsView;
    private ImageButton finishButton;
    private ImageButton restartButton;
    private HistogramChart latencyChart;
    private int moveCount = 0;
    private int allDownCount = 0;
    private int allUpCount = 0;
    private int okDownCount = 0;
    private int okUpCount = 0;
    private boolean shouldShowLatencyChart = false;

    ArrayList<UsMotionEvent> eventList = new ArrayList<>();
    ArrayList<Double> p2kDown = new ArrayList<>();
    ArrayList<Double> p2kUp = new ArrayList<>();
    ArrayList<Double> k2cDown = new ArrayList<>();
    ArrayList<Double> k2cUp = new ArrayList<>();

            if(tapEvent.action != MotionEvent.ACTION_UP && tapEvent.action != MotionEvent.ACTION_DOWN) {
                moveCount++;
                activity.logger.log("Ignoring " + action + " " + moveCount);
                updateCountsDisplay();
                return true;
            }

            activity.logger.log("\n"+ action + " event received: " + tapEvent.toStringLong());
            tapEvent.physicalTime = activity.clockManager.readLastShockTime();

            tapEvent.isOk = checkTapSanity(tapEvent);
            UsMotionEvent tapEvent = new UsMotionEvent(event, waltDevice.clock.baseTime);

            if(tapEvent.action != MotionEvent.ACTION_UP && tapEvent.action != MotionEvent.ACTION_DOWN) {
                moveCount++;
                updateCountsDisplay();
                return true;
            }

            // Debug: logger.log("\n"+ action + " event received: " + tapEvent.toStringLong());
            tapEvent.physicalTime = waltDevice.readLastShockTime();

            tapEvent.isOk = checkTapSanity(tapEvent);
            // Save it in any case so we can do stats on bad events later
            eventList.add(tapEvent);

            final double physicalToKernelTime = (tapEvent.kernelTime - tapEvent.physicalTime) / 1000.;
            final double kernelToCallbackTime = (tapEvent.createTime - tapEvent.kernelTime) / 1000.;
            if (tapEvent.action == MotionEvent.ACTION_DOWN) {
                allDownCount++;
                if (tapEvent.isOk) {
                    okDownCount++;
                    p2kDown.add(physicalToKernelTime);
                    k2cDown.add(kernelToCallbackTime);
                    if (shouldShowLatencyChart) latencyChart.addEntry(ACTION_DOWN_INDEX, physicalToKernelTime);
                    logger.log(String.format(Locale.US,
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        // Inflate the layout for this fragment
        activity = (MainActivity) getActivity();
        View view =  inflater.inflate(R.layout.fragment_tap_latency, container, false);

        return view;
    }

    @Override
                    logger.log(String.format(Locale.US,
                            "ACTION_UP:\ntouch2kernel: %.1f ms\nkernel2java: %.1f ms",
        restartMeasurement();
        mLogTextView = (TextView) activity.findViewById(R.id.txt_log_tap_latency);

        mLogTextView.setText(activity.logger.getLogText());
        activity.logger.broadcastManager.registerReceiver(mLogReceiver,
                new IntentFilter(activity.logger.LOG_INTENT));

        // Register this fregment class as the listener for some button clicks
        ((ImageButton)activity.findViewById(R.id.button_restart_tap)).setOnClickListener(this);
    };

    private void traceLogEvent(UsMotionEvent tapEvent) {
        if (!tapEvent.isOk) return;
        if (traceLogger == null) return;

    @Override
    public void onPause() {
        activity.logger.broadcastManager.unregisterReceiver(mLogReceiver);
        super.onPause();
    }

                "Bar starts at kernel time of tap event and ends at app callback time");
    }

    public TapLatencyFragment() {
        // Required empty public constructor
    }
        double dt = (e.kernelTime - e.physicalTime) / 1000.0;

        if (e.physicalTime == 0) {
            activity.logger.log(action + " no shock found");
            return false;
        }

        if (dt < 0 || dt > 200) {
            activity.logger.log(action + " bogus kernelTime, ignored, dt=" + dt);
            return  false;
        }

        activity.logger.log(String.format("%s: dt_p2k = %.1f ms", action, dt));
        return true;
    }

        tapCountsView = (TextView) view.findViewById(R.id.txt_tap_counts);
        moveCountsView = (TextView) view.findViewById(R.id.txt_move_count);
        latencyChart = (HistogramChart) view.findViewById(R.id.latency_chart);
        logTextView.setMovementMethod(new ScrollingMovementMethod());
        finishButton.setEnabled(false);
        return view;
    }

    @Override
    public void onResume() {
        super.onResume();

    }

    void restartMeasurement() {
        activity.logger.log("\n## Restarting tap latency  measurement. Re-sync clocks ...");
        activity.clockManager.syncClock();

        eventList.clear();

    @Override
    public void onPause() {
        logger.unregisterReceiver(logReceiver);
        super.onPause();
    }

    public void appendLogText(String msg) {
    }

    void finishAndShowStats() {
        activity.logger.log("\n\n## Processing tap latency data");
        activity.logger.log(String.format(
                "Counts: ACTION_DOWN %d (bad %d), ACTION_UP %d (bad %d), ACTION_MOVE %d",
                okDownCount,
                allDownConunt - okDownCount,
            logger.log(action + " no shock found");
            return false;
        }

        if (dt < 0 || dt > 200) {
            logger.log(action + " bogus kernelTime, ignored, dt=" + dt);
            return  false;
        activity.clockManager.updateBounds();
        int minE = activity.clockManager.getMinE();
        int maxE = activity.clockManager.getMaxE();
        activity.logger.log(String.format("Remote clock delayed between %d and %d us", minE, maxE));
        // TODO: check the drift and display warning if too high. Optionally interpolate drift as linear.

        // TODO: Here we should fire up a new fragment with histogram(s)
        // For now do the stats here and save them to log

        activity.logger.log("\nACTION_DOWN:");
        printStats(MotionEvent.ACTION_DOWN);
        activity.logger.log("\nACTION_UP:");
        printStats(MotionEvent.ACTION_UP);

        restartMeasurement();
    }

    void restartMeasurement() {
        logger.log("\n## Restarting tap latency measurement. Re-sync clocks ...");
        try {
            waltDevice.softReset();
            waltDevice.syncClock();
        } catch (IOException e) {
            logger.log("Error syncing clocks: " + e.getMessage());
            restartButton.setImageResource(R.drawable.ic_play_arrow_black_24dp);
            finishButton.setEnabled(false);
            latencyChart.setVisibility(View.GONE);
            return;
            k2c.add((event.createTime - event.kernelTime) / 1000.);
        }

        activity.logger.log(p2k.toString());
        activity.logger.log(k2c.toString());

        activity.logger.log(String.format(
                "Medians, p2k & k2c [ms]: %.1f    %.1f",
                Utils.median(p2k),
                Utils.median(k2c)
        allUpCount = 0;
        okDownCount = 0;
        okUpCount = 0;

        updateCountsDisplay();
        tapCatcherView.setOnTouchListener(touchListener);
    }

    void finishAndShowStats() {
        tapCatcherView.setOnTouchListener(null);
        waltDevice.checkDrift();
        logger.log("\n-------------------------------");
        logger.log(String.format(Locale.US,
                "Tap latency results:\n" +
                        "Number of events recorded:\n" +
                        "   ACTION_DOWN %d (bad %d)\n" +
                        "   ACTION_UP %d (bad %d)\n" +
                        "   ACTION_MOVE %d",
                okDownCount,
                allDownCount - okDownCount,
                okUpCount,
                allUpCount - okUpCount,
                moveCount
        ));

        logger.log("ACTION_DOWN median times:");
        logger.log(String.format(Locale.US,
                "   Touch to kernel: %.1f ms\n   Kernel to Java: %.1f ms",
                Utils.median(p2kDown),
                Utils.median(k2cDown)
        ));
        logger.log("ACTION_UP median times:");
        logger.log(String.format(Locale.US,
                "   Touch to kernel: %.1f ms\n   Kernel to Java: %.1f ms",
                Utils.median(p2kUp),
                Utils.median(k2cUp)
        ));
        logger.log("-------------------------------");
        if (traceLogger != null) traceLogger.flush(getContext());

        if (shouldShowLatencyChart) {
            latencyChart.setLabel(ACTION_DOWN_INDEX, String.format(Locale.US, "ACTION_DOWN median=%.1f ms", Utils.median(p2kDown)));
            latencyChart.setLabel(ACTION_UP_INDEX, String.format(Locale.US, "ACTION_UP median=%.1f ms", Utils.median(p2kUp)));
        }
        LogUploader.uploadIfAutoEnabled(getContext());
    }

    @Override
    public void onClick(View v) {
        if (v.getId() == R.id.button_restart_tap) {
            restartButton.setImageResource(R.drawable.ic_refresh_black_24dp);
            finishButton.setEnabled(true);
            if (shouldShowLatencyChart) {
                latencyChart.setVisibility(View.VISIBLE);
                latencyChart.clearData();
                latencyChart.setLabel(ACTION_DOWN_INDEX, "ACTION_DOWN");
                latencyChart.setLabel(ACTION_UP_INDEX, "ACTION_UP");
            }
            restartMeasurement();
            return;
        }

        if (v.getId() == R.id.button_finish_tap) {
            finishButton.setEnabled(false);
            finishAndShowStats();
            restartButton.setImageResource(R.drawable.ic_play_arrow_black_24dp);
            return;
        }

    }
}

<MSG> Refactor SimpleLogger into a singleton

<DFF> @@ -19,7 +19,6 @@ package org.chromium.latency.walt;
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
-import android.content.IntentFilter;
 import android.os.Bundle;
 import android.support.v4.app.Fragment;
 import android.view.LayoutInflater;
@@ -34,8 +33,10 @@ import java.util.HashMap;
 
 public class TapLatencyFragment extends Fragment
     implements View.OnClickListener {
-    TextView mLogTextView;
+
     MainActivity activity;
+    private SimpleLogger logger;
+    TextView mLogTextView;
     TextView mTapCatcher;
     int moveCount = 0;
     int allDownConunt = 0;
@@ -64,12 +65,12 @@ public class TapLatencyFragment extends Fragment
 
             if(tapEvent.action != MotionEvent.ACTION_UP && tapEvent.action != MotionEvent.ACTION_DOWN) {
                 moveCount++;
-                activity.logger.log("Ignoring " + action + " " + moveCount);
+                logger.log("Ignoring " + action + " " + moveCount);
                 updateCountsDisplay();
                 return true;
             }
 
-            activity.logger.log("\n"+ action + " event received: " + tapEvent.toStringLong());
+            logger.log("\n"+ action + " event received: " + tapEvent.toStringLong());
             tapEvent.physicalTime = activity.clockManager.readLastShockTime();
 
             tapEvent.isOk = checkTapSanity(tapEvent);
@@ -101,11 +102,10 @@ public class TapLatencyFragment extends Fragment
     @Override
     public View onCreateView(LayoutInflater inflater, ViewGroup container,
                              Bundle savedInstanceState) {
-        // Inflate the layout for this fragment
         activity = (MainActivity) getActivity();
-        View view =  inflater.inflate(R.layout.fragment_tap_latency, container, false);
-
-        return view;
+        logger = SimpleLogger.getInstance(getContext());
+        // Inflate the layout for this fragment
+        return inflater.inflate(R.layout.fragment_tap_latency, container, false);
     }
 
     @Override
@@ -114,9 +114,8 @@ public class TapLatencyFragment extends Fragment
         restartMeasurement();
         mLogTextView = (TextView) activity.findViewById(R.id.txt_log_tap_latency);
 
-        mLogTextView.setText(activity.logger.getLogText());
-        activity.logger.broadcastManager.registerReceiver(mLogReceiver,
-                new IntentFilter(activity.logger.LOG_INTENT));
+        mLogTextView.setText(logger.getLogText());
+        logger.registerReceiver(mLogReceiver);
 
         // Register this fregment class as the listener for some button clicks
         ((ImageButton)activity.findViewById(R.id.button_restart_tap)).setOnClickListener(this);
@@ -128,7 +127,7 @@ public class TapLatencyFragment extends Fragment
 
     @Override
     public void onPause() {
-        activity.logger.broadcastManager.unregisterReceiver(mLogReceiver);
+        logger.unregisterReceiver(mLogReceiver);
         super.onPause();
     }
 
@@ -141,16 +140,16 @@ public class TapLatencyFragment extends Fragment
         double dt = (e.kernelTime - e.physicalTime) / 1000.0;
 
         if (e.physicalTime == 0) {
-            activity.logger.log(action + " no shock found");
+            logger.log(action + " no shock found");
             return false;
         }
 
         if (dt < 0 || dt > 200) {
-            activity.logger.log(action + " bogus kernelTime, ignored, dt=" + dt);
+            logger.log(action + " bogus kernelTime, ignored, dt=" + dt);
             return  false;
         }
 
-        activity.logger.log(String.format("%s: dt_p2k = %.1f ms", action, dt));
+        logger.log(String.format("%s: dt_p2k = %.1f ms", action, dt));
         return true;
     }
 
@@ -169,7 +168,7 @@ public class TapLatencyFragment extends Fragment
     }
 
     void restartMeasurement() {
-        activity.logger.log("\n## Restarting tap latency  measurement. Re-sync clocks ...");
+        logger.log("\n## Restarting tap latency  measurement. Re-sync clocks ...");
         activity.clockManager.syncClock();
 
         eventList.clear();
@@ -184,8 +183,8 @@ public class TapLatencyFragment extends Fragment
     }
 
     void finishAndShowStats() {
-        activity.logger.log("\n\n## Processing tap latency data");
-        activity.logger.log(String.format(
+        logger.log("\n\n## Processing tap latency data");
+        logger.log(String.format(
                 "Counts: ACTION_DOWN %d (bad %d), ACTION_UP %d (bad %d), ACTION_MOVE %d",
                 okDownCount,
                 allDownConunt - okDownCount,
@@ -199,15 +198,15 @@ public class TapLatencyFragment extends Fragment
         activity.clockManager.updateBounds();
         int minE = activity.clockManager.getMinE();
         int maxE = activity.clockManager.getMaxE();
-        activity.logger.log(String.format("Remote clock delayed between %d and %d us", minE, maxE));
+        logger.log(String.format("Remote clock delayed between %d and %d us", minE, maxE));
         // TODO: check the drift and display warning if too high. Optionally interpolate drift as linear.
 
         // TODO: Here we should fire up a new fragment with histogram(s)
         // For now do the stats here and save them to log
 
-        activity.logger.log("\nACTION_DOWN:");
+        logger.log("\nACTION_DOWN:");
         printStats(MotionEvent.ACTION_DOWN);
-        activity.logger.log("\nACTION_UP:");
+        logger.log("\nACTION_UP:");
         printStats(MotionEvent.ACTION_UP);
 
         restartMeasurement();
@@ -227,10 +226,10 @@ public class TapLatencyFragment extends Fragment
             k2c.add((event.createTime - event.kernelTime) / 1000.);
         }
 
-        activity.logger.log(p2k.toString());
-        activity.logger.log(k2c.toString());
+        logger.log(p2k.toString());
+        logger.log(k2c.toString());
 
-        activity.logger.log(String.format(
+        logger.log(String.format(
                 "Medians, p2k & k2c [ms]: %.1f    %.1f",
                 Utils.median(p2k),
                 Utils.median(k2c)

Refactor SimpleLogger into a singleton