@Override
    public void run() {
        while(mRunning) {
            waitForCallback();
            Log.d(TAG, "Starting trace playback from beginning of " + mFilename);
            BufferedReader reader = null;
            if (checkPermission()) {
                try {

                    reader = openFile(mFilename);
                } catch (DataSourceException e) {
                    Log.w(TAG, "Couldn't open the trace file " + mFilename, e);
                    break;
                }

                String line;
                long startingTime = System.currentTimeMillis();
                // In the future may want to support binary traces
                try {
                    while (mRunning && (line = reader.readLine()) != null) {
                        VehicleMessage measurement;
                        try {
                            measurement = JsonFormatter.deserialize(line);
                        } catch (UnrecognizedMessageTypeException e) {
                            Log.w(TAG, "A trace line was not in the expected " +
                                    "format: " + line);
                            continue;
                        }

                        if (measurement == null) {
                            continue;
                        }

                        if (measurement != null && !measurement.isTimestamped()) {
                            Log.w(TAG, "A trace line was missing a timestamp: " +
                                    line);
                            continue;
                        }

                        try {
                            waitForNextRecord(startingTime, measurement.getTimestamp());
                        } catch (NumberFormatException e) {
                            Log.w(TAG, "A trace line was not in the expected " +
                                    "format: " + line);
                            continue;
                        }
                        measurement.untimestamp();
                        if (!mTraceValid) {
                            connected();
                            mTraceValid = true;
                        }
                        handleMessage(measurement);
                    }
                } catch (IOException e) {
                    Log.w(TAG, "An exception occurred when reading the trace " +
                            reader, e);
                    break;
                } finally {
                    try {
                        if (reader != null) {
                            reader.close();
                        }
                    } catch (IOException e) {
                        Log.w(TAG, "Couldn't even close the trace file", e);
                    }
                }

                if (!mLoop) {
                    Log.d(TAG, "Not looping trace.");
                    break;
                }

                disconnected();
                Log.d(TAG, "Restarting playback of trace " + mFilename);
                // Set this back to false so the VI shows as "disconnected" for
                // a second before reconnecting.
                mTraceValid = false;
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                }
            }
            disconnected();
            mRunning = false;
            Log.d(TAG, "Playback of trace " + mFilename + " is finished");
        }
    }
@ Override public void run ( ) { while ( mRunning ) { waitForCallback ( ) ; Log . d ( TAG , "Starting trace playback from beginning of " + mFilename ) ; BufferedReader reader = null ; if ( checkPermission ( ) ) { try { reader = openFile ( mFilename ) ; } catch ( DataSourceException e ) { Log . w ( TAG , "Couldn't open the trace file " + mFilename , e ) ; break ; } String line ; long startingTime = System . currentTimeMillis ( ) ; try { while ( mRunning && ( line = reader . readLine ( ) ) != null ) { VehicleMessage measurement ; try { measurement = JsonFormatter . deserialize ( line ) ; } catch ( UnrecognizedMessageTypeException e ) { Log . w ( TAG , "A trace line was not in the expected " + "format: " + line ) ; continue ; } if ( measurement == null ) { continue ; } if ( measurement != null && ! measurement . isTimestamped ( ) ) { Log . w ( TAG , "A trace line was missing a timestamp: " + line ) ; continue ; } try { waitForNextRecord ( startingTime , measurement . getTimestamp ( ) ) ; } catch ( NumberFormatException e ) { Log . w ( TAG , "A trace line was not in the expected " + "format: " + line ) ; continue ; } measurement . untimestamp ( ) ; if ( ! mTraceValid ) { connected ( ) ; mTraceValid = true ; } handleMessage ( measurement ) ; } } catch ( IOException e ) { Log . w ( TAG , "An exception occurred when reading the trace " + reader , e ) ; break ; } finally { try { if ( reader != null ) { reader . close ( ) ; } } catch ( IOException e ) { Log . w ( TAG , "Couldn't even close the trace file" , e ) ; } } if ( ! mLoop ) { Log . d ( TAG , "Not looping trace." ) ; break ; } disconnected ( ) ; Log . d ( TAG , "Restarting playback of trace " + mFilename ) ; mTraceValid = false ; try { Thread . sleep ( 1000 ) ; } catch ( InterruptedException e ) { } } disconnected ( ) ; mRunning = false ; Log . d ( TAG , "Playback of trace " + mFilename + " is finished" ) ; } }
While running, continuously read from the trace file and send messages
to the callback.

If the callback is not set, this function will exit immediately and the
thread will die a quick death.