at.alladin.rmbt.android.test.RMBTTestFragment.java Source code

Java tutorial

Introduction

Here is the source code for at.alladin.rmbt.android.test.RMBTTestFragment.java

Source

/*******************************************************************************
 * Copyright 2013-2016 alladin-IT GmbH
 * 
 * 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 at.alladin.rmbt.android.test;

import java.text.DecimalFormat;
import java.text.Format;
import java.text.MessageFormat;
import java.util.List;
import java.util.Locale;

import android.app.AlertDialog;
import android.app.Dialog;
import android.app.ProgressDialog;
import android.content.ComponentName;
import android.content.Context;
import android.content.DialogInterface;
import android.content.DialogInterface.OnClickListener;
import android.content.DialogInterface.OnDismissListener;
import android.content.Intent;
import android.content.ServiceConnection;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.graphics.Color;
import android.location.Location;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.support.v4.app.Fragment;
import android.util.Log;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;
import at.alladin.openrmbt.android.R;
import at.alladin.rmbt.android.graphview.GraphService;
import at.alladin.rmbt.android.graphview.GraphService.GraphData;
import at.alladin.rmbt.android.graphview.GraphView;
import at.alladin.rmbt.android.main.RMBTMainActivity;
import at.alladin.rmbt.android.test.RMBTService.RMBTBinder;
import at.alladin.rmbt.android.test.SmoothGraph.SmoothingFunction;
import at.alladin.rmbt.android.util.Helperfunctions;
import at.alladin.rmbt.android.util.InformationCollector;
import at.alladin.rmbt.android.util.net.NetworkUtil;
import at.alladin.rmbt.android.util.net.NetworkUtil.MinMax;
import at.alladin.rmbt.android.views.GroupCountView;
import at.alladin.rmbt.android.views.ProgressView;
import at.alladin.rmbt.android.views.ResultGraphView;
import at.alladin.rmbt.client.helper.IntermediateResult;
import at.alladin.rmbt.client.helper.NdtStatus;
import at.alladin.rmbt.client.helper.TestStatus;
import at.alladin.rmbt.client.v2.task.QoSTestEnum;

public class RMBTTestFragment extends Fragment implements ServiceConnection {
    private static final String TAG = "RMBTTestFragment";

    /**
     * used for smoothing the speed graph: amount of data needed for smoothing function
     */
    public static final int SMOOTHING_DATA_AMOUNT = 3; // min 3

    /**
     * smoothing function used for speed graph.
     * BEWARE: different functions could require different data amounts
     */
    public static final SmoothingFunction SMOOTHING_FUNCTION = SmoothingFunction.CENTERED_MOVING_AVARAGE;

    private static final long UPDATE_DELAY = 100;
    private static final int SLOW_UPDATE_COUNT = 20;

    private static final int PROGRESS_SEGMENTS_TOTAL = 132;
    private static final int PROGRESS_SEGMENTS_INIT = 16;
    private static final int PROGRESS_SEGMENTS_PING = 17;
    private static final int PROGRESS_SEGMENTS_DOWN = 33;
    private static final int PROGRESS_SEGMENTS_UP = 33;
    private static final int PROGRESS_SEGMENTS_QOS = 33;

    private static final long GRAPH_MAX_NSECS = 8000000000L;

    private final Format pingFormat = new DecimalFormat("@@ ms");
    private Format speedFormat;
    private final Format percentFormat = DecimalFormat.getPercentInstance();

    private boolean qosMode = false;

    private Context context;

    private TestView testView;
    private GraphView graphView;
    private GraphService speedGraph;
    private GraphService signalGraph;
    private boolean uploadGraph;
    private boolean graphStarted;
    private TextView textView;
    private ViewGroup groupCountContainerView;
    private ViewGroup qosProgressView;
    private ViewGroup infoView;

    private IntermediateResult intermediateResult;
    private int lastNetworkType;
    private String lastNetworkTypeString;

    private Integer lastSignal;
    private int lastSignalType;

    private RMBTService rmbtService;

    private long updateCounter;

    private String bottomText;
    private Location lastLocation;
    private String lastOperatorName;
    private String lastServerName;
    private String lastIP;
    private TestStatus lastStatus;
    private String lastStatusString;
    private long lastShownWaitTime = -1;
    private String waitText;
    private boolean stopLoop;

    private Dialog errorDialog;
    private Dialog abortDialog;
    private ProgressDialog progressDialog;

    private boolean showQoSErrorToast = false;

    private Handler handler;

    private static final long MAX_COUNTER_WITHOUT_RESULT = 100;

    GraphData signalGraphData;
    GraphData speedGraphData;

    private final Runnable resultSwitcherRunnable = new Runnable() {
        @Override
        public void run() {
            final RMBTMainActivity mainActivity = getMainActivity();
            if (mainActivity == null)
                return;

            mainActivity.setHistoryDirty(true);
            mainActivity.checkSettings(true, null);
            if (getMainActivity() == null)
                return;
            if (isVisible())
                switchToResult();
        }
    };

    @Override
    public void onCreate(final Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setRetainInstance(true);

        handler = new Handler();
        context = getActivity().getApplicationContext();

        bottomText = getResources().getString(R.string.test_bottom_test);
        waitText = getResources().getString(R.string.test_progress_text_wait);

        speedFormat = new DecimalFormat(
                String.format("@@ %s", getActivity().getResources().getString(R.string.test_mbps)));

    }

    protected RMBTMainActivity getMainActivity() {
        return (RMBTMainActivity) getActivity();
    }

    @Override
    public void onServiceConnected(final ComponentName name, final IBinder service) {
        Log.d(TAG, "service connected");
        final RMBTBinder binder = (RMBTBinder) service;
        rmbtService = binder.getService();
    }

    @Override
    public void onServiceDisconnected(final ComponentName name) {
        Log.d(TAG, "service disconnected");
        rmbtService = null;
    }

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

        speedGraphData = speedGraph.getGraphData();
        signalGraphData = signalGraph.getGraphData();

        handler.removeCallbacks(updateTask);
        handler.removeCallbacks(resultSwitcherRunnable);

        context.unbindService(this);

        getActivity().getActionBar().show();
        ((RMBTMainActivity) getActivity()).setLockNavigationDrawer(false);

        //getActivity().getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
        getActivity().getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
    }

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

        getActivity().getActionBar().hide();
        ((RMBTMainActivity) getActivity()).setLockNavigationDrawer(true);

        // Bind to RMBTService
        final Intent serviceIntent = new Intent(context, RMBTService.class);
        context.bindService(serviceIntent, this, Context.BIND_AUTO_CREATE);

        handler.post(updateTask);

        //getActivity().getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
        getActivity().getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
    }

    @Override
    public View onCreateView(final LayoutInflater inflater, final ViewGroup container,
            final Bundle savedInstanceState) {
        final View view = inflater.inflate(R.layout.test, container, false);

        return createView(view, inflater, savedInstanceState);
    }

    /**
     * 
     * @param view
     * @param inflater
     * @return
     */
    private View createView(final View view, final LayoutInflater inflater, final Bundle savedInstanceState) {
        testView = (TestView) view.findViewById(R.id.test_view);
        graphView = (GraphView) view.findViewById(R.id.test_graph);
        infoView = (ViewGroup) view.findViewById(R.id.test_view_info_container);
        textView = (TextView) view.findViewById(R.id.test_text);
        qosProgressView = (ViewGroup) view.findViewById(R.id.test_view_qos_container);
        groupCountContainerView = (ViewGroup) view.findViewById(R.id.test_view_group_count_container);

        if (savedInstanceState != null) {
            if (testView != null) {
                testView.setHeaderString(savedInstanceState.getString("header_string"));
                testView.setSubHeaderString(
                        savedInstanceState.getString("sub_header_string", testView.getSubHeaderString()));
                testView.setResultPingString(
                        savedInstanceState.getString("ping_string", testView.getResultPingString()));
                testView.setResultDownString(
                        savedInstanceState.getString("down_string", testView.getResultDownString()));
                testView.setResultUpString(savedInstanceState.getString("up_string", testView.getResultUpString()));
            }

            if (textView != null) {
                textView.setText(savedInstanceState.getString("test_info"));
            }
        } else {
            if (textView != null) {
                textView.setText("\n\n\n");
            }
        }

        if (graphView != null) {
            if (speedGraphData == null) {
                speedGraph = SmoothGraph.addGraph(graphView, Color.parseColor("#00f940"), SMOOTHING_DATA_AMOUNT,
                        SMOOTHING_FUNCTION, false);
            } else {
                speedGraph = SmoothGraph.addGraph(graphView, SMOOTHING_DATA_AMOUNT, SMOOTHING_FUNCTION, false,
                        speedGraphData);
            }

            speedGraph.setMaxTime(GRAPH_MAX_NSECS);

            if (signalGraphData == null) {
                signalGraph = SimpleGraph.addGraph(graphView, Color.parseColor("#f8a000"), GRAPH_MAX_NSECS);
            } else {
                signalGraph = SimpleGraph.addGraph(graphView, GRAPH_MAX_NSECS, signalGraphData);
            }

            //graphView.getLabelInfoVerticalList().add(new GraphLabel(getActivity().getString(R.string.test_dbm), "#f8a000"));
            graphView.setRowLinesLabelList(ResultGraphView.SPEED_LABELS);
        }
        //uploadGraph = false;
        graphStarted = false;

        final Resources res = getActivity().getResources();
        final String progressTitle = res.getString(R.string.test_progress_title);
        final String progressText = res.getString(R.string.test_progress_text);

        lastShownWaitTime = -1;
        if (progressDialog == null) {
            progressDialog = ProgressDialog.show(getActivity(), progressTitle, progressText, true, false);
            progressDialog.setOnKeyListener(backKeyListener);
        }

        return view;
    }

    @Override
    public void onDestroyView() {
        super.onDestroyView();
        if (progressDialog != null) {
            progressDialog.dismiss();
            progressDialog = null;
        }
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        if (testView != null)
            testView.recycle();
        if (graphView != null)
            graphView.recycle();
        dismissDialogs();
        System.gc();
    }

    @Override
    public void onDetach() {
        super.onDetach();
        dismissDialogs();
    }

    private void dismissDialogs() {
        dismissDialog(errorDialog);
        errorDialog = null;
        dismissDialog(abortDialog);
        abortDialog = null;
        dismissDialog(progressDialog);
        progressDialog = null;
    }

    private static void dismissDialog(Dialog dialog) {
        if (dialog != null)
            dialog.dismiss();
    }

    private void resetGraph() {
        if (signalGraph != null)
            signalGraph.reset();
        if (speedGraph != null)
            speedGraph.reset();
        uploadGraph = false;
        graphStarted = false;
        if (graphView != null)
            graphView.invalidate();
    }

    private final Runnable updateTask = new Runnable() {
        @Override
        public void run() {
            if (getActivity() == null)
                return;

            if (qosMode)
                updateQoSUI();
            else
                updateUI();

            if (rmbtService != null) {
                //               System.out.println(rmbtService.isCompleted() + " - " + rmbtService.isConnectionError());
                if (rmbtService.isCompleted() && rmbtService.getTestUuid(false) != null) {
                    handler.postDelayed(resultSwitcherRunnable, 300);
                }
            }

            if (!stopLoop)
                handler.postDelayed(this, UPDATE_DELAY);
        }
    };

    private final DialogInterface.OnKeyListener backKeyListener = new DialogInterface.OnKeyListener() {
        @Override
        public boolean onKey(DialogInterface dialog, int keyCode, KeyEvent event) {
            if (keyCode == KeyEvent.KEYCODE_BACK)
                return onBackPressedHandler();
            return false;
        }
    };

    private void updateUI() {
        String teststatus;
        updateCounter++;

        if (rmbtService == null)
            return;

        intermediateResult = rmbtService.getIntermediateResult(intermediateResult);

        if (intermediateResult == null) {
            if (rmbtService.isConnectionError()) {
                if (progressDialog != null) {
                    progressDialog.dismiss();
                    progressDialog = null;
                }
                if (!rmbtService.isLoopMode()) {
                    showErrorDialog(R.string.test_dialog_error_control_server_conn);
                    return;
                }
            }

            if (!rmbtService.isTestRunning() && updateCounter > MAX_COUNTER_WITHOUT_RESULT
                    && !(errorDialog != null && errorDialog.isShowing()))
                getActivity().getSupportFragmentManager().popBackStack(); // leave
            return;
        }

        if (intermediateResult.status == TestStatus.WAIT) {
            if (progressDialog != null) {
                long wait = (intermediateResult.remainingWait + 999) / 1000; // round
                                                                             // up
                if (wait < 0)
                    wait = 0;
                if (wait != lastShownWaitTime) {
                    lastShownWaitTime = wait;
                    progressDialog.setMessage(MessageFormat.format(waitText, wait));
                }
            }
            return;
        }

        if (progressDialog != null) {
            progressDialog.dismiss();
            progressDialog = null;
        }

        boolean forceUpdate = false;

        if (rmbtService.getNdtStatus() == NdtStatus.RUNNING) {
            final String ndtStatus = String.format(Locale.US, "NDT (%d%%)",
                    Math.round(rmbtService.getNDTProgress() * 100));
            if (lastStatusString == null || !ndtStatus.equals(lastStatusString)) {
                forceUpdate = true;
                lastStatusString = ndtStatus;
            }
        } else if (lastStatus != intermediateResult.status) {
            lastStatus = intermediateResult.status;
            lastStatusString = Helperfunctions.getTestStatusString(getResources(), intermediateResult.status);
            forceUpdate = true;
        }

        if (updateCounter % SLOW_UPDATE_COUNT == 0 || forceUpdate) {
            final int networkType = rmbtService.getNetworkType();
            if (lastNetworkType != networkType && networkType != 0) {
                lastNetworkType = networkType;
                lastNetworkTypeString = Helperfunctions.getNetworkTypeName(networkType);
            }

            final String operatorName = rmbtService.getOperatorName();
            if (operatorName != null)
                lastOperatorName = operatorName;
            testView.setHeaderString(lastOperatorName);
            testView.setSubHeaderString(lastNetworkTypeString);
            final String serverName = rmbtService.getServerName();
            if (serverName != null)
                lastServerName = serverName;
            if (lastServerName == null)
                lastServerName = "?";

            final Location location = rmbtService.getLocation();
            if (location != null && !location.equals(lastLocation))
                lastLocation = location;

            final String locationStr_line1;
            final String locationStr_line2;
            if (lastLocation != null) {
                locationStr_line1 = Helperfunctions.getLocationString(context, getResources(), lastLocation, 1);
                locationStr_line2 = Helperfunctions.getLocationString(context, getResources(), lastLocation, 2);
            } else {
                locationStr_line1 = "";
                locationStr_line2 = "";
            }

            final String ip = rmbtService.getIP();
            if (ip != null)
                lastIP = ip;
            if (lastIP == null)
                lastIP = "?";

            teststatus = lastStatusString;

            textView.setText(MessageFormat.format(bottomText, teststatus, lastServerName, lastIP, locationStr_line1,
                    locationStr_line2));
        }

        Integer signal = rmbtService.getSignal();
        int signalType = rmbtService.getSignalType();

        if (signal == null || signal == 0)
            signalType = InformationCollector.SINGAL_TYPE_NO_SIGNAL;

        boolean signalTypeChanged = false;

        if (signalType != InformationCollector.SINGAL_TYPE_NO_SIGNAL) {
            signalTypeChanged = lastSignalType != signalType;
            lastSignal = signal;
            lastSignalType = signalType;
        }

        if (signalType == InformationCollector.SINGAL_TYPE_NO_SIGNAL
                && lastSignalType != InformationCollector.SINGAL_TYPE_NO_SIGNAL) {
            // keep old signal if we had one before
            signal = lastSignal;
            signalType = lastSignalType;
        }

        Double relativeSignal = null;
        MinMax<Integer> signalBounds = NetworkUtil.getSignalStrengthBounds(signalType);
        if (!(signalBounds.min == Integer.MIN_VALUE || signalBounds.max == Integer.MAX_VALUE))
            relativeSignal = (double) (signal - signalBounds.min) / (double) (signalBounds.max - signalBounds.min);

        if (signalTypeChanged && graphView != null) {
            if (signalGraph != null)
                signalGraph.clearGraphDontResetTime();
            if (relativeSignal != null)
                graphView.setSignalRange(signalBounds.min, signalBounds.max);
            else
                graphView.removeSignalRange();
            graphView.invalidate();
        }

        double speedValueRelative = 0d;
        int progressSegments = 0;
        switch (intermediateResult.status) {
        case WAIT:
            textView.setText("UDP progress: " + intermediateResult.progress);
            break;

        case INIT:
            progressSegments = Math.round(PROGRESS_SEGMENTS_INIT * intermediateResult.progress);
            if (graphStarted)
                resetGraph();
            break;

        case PING:
            progressSegments = PROGRESS_SEGMENTS_INIT
                    + Math.round(PROGRESS_SEGMENTS_PING * intermediateResult.progress);
            break;

        case DOWN:
            progressSegments = PROGRESS_SEGMENTS_INIT + PROGRESS_SEGMENTS_PING
                    + Math.round(PROGRESS_SEGMENTS_DOWN * intermediateResult.progress);
            speedValueRelative = intermediateResult.downBitPerSecLog;

            if (graphView != null) {
                if (uploadGraph)
                    resetGraph();

                if (graphStarted || speedValueRelative != 0) {
                    graphStarted = true;
                    speedGraph.addValue(speedValueRelative, SmoothGraph.FLAG_USE_CURRENT_NODE_TIME);
                    if (relativeSignal != null)
                        signalGraph.addValue(relativeSignal);
                    graphView.invalidate();
                }
            }
            break;

        case INIT_UP:
            progressSegments = PROGRESS_SEGMENTS_INIT + PROGRESS_SEGMENTS_PING + PROGRESS_SEGMENTS_DOWN;
            speedValueRelative = intermediateResult.downBitPerSecLog;
            break;

        case UP:
            progressSegments = PROGRESS_SEGMENTS_INIT + PROGRESS_SEGMENTS_PING + PROGRESS_SEGMENTS_DOWN
                    + Math.round(PROGRESS_SEGMENTS_UP * intermediateResult.progress);
            speedValueRelative = intermediateResult.upBitPerSecLog;

            if (graphView != null) {
                if (!uploadGraph) {
                    resetGraph();
                    uploadGraph = true;
                }
                if (graphStarted || speedValueRelative != 0) {
                    graphStarted = true;
                    speedGraph.addValue(speedValueRelative, SmoothGraph.FLAG_USE_CURRENT_NODE_TIME);
                    if (relativeSignal != null)
                        signalGraph.addValue(relativeSignal);
                    graphView.invalidate();
                }
            }
            break;

        case SPEEDTEST_END:
        case QOS_TEST_RUNNING:
            progressSegments = PROGRESS_SEGMENTS_INIT + PROGRESS_SEGMENTS_PING + PROGRESS_SEGMENTS_DOWN
                    + PROGRESS_SEGMENTS_UP;
            speedValueRelative = intermediateResult.upBitPerSecLog;

            qosMode = true;

            break;

        case ERROR:
        case ABORTED:
            progressSegments = 0;
            resetGraph();

            if (!rmbtService.isLoopMode())
                showErrorDialog(R.string.test_dialog_error_text);
            return;
        }
        testView.setSpeedValue(speedValueRelative);

        testView.setSignalType(signalType);
        if (signal != null)
            testView.setSignalString(String.valueOf(signal));
        if (relativeSignal != null)
            testView.setSignalValue(relativeSignal);

        final double progressValue = (double) progressSegments / PROGRESS_SEGMENTS_TOTAL;
        final double correctProgressValue = testView.setProgressValue(progressValue);
        testView.setProgressString(percentFormat.format(correctProgressValue));

        final String pingStr;
        if (intermediateResult.pingNano < 0)
            pingStr = "";
        else
            pingStr = pingFormat.format(intermediateResult.pingNano / 1000000.0);
        testView.setResultPingString(pingStr);
        final String downStr;
        if (intermediateResult.downBitPerSec < 0)
            downStr = "";
        else
            downStr = speedFormat.format(intermediateResult.downBitPerSec / 1000000.0);
        testView.setResultDownString(downStr);
        final String upStr;
        if (intermediateResult.upBitPerSec < 0)
            upStr = "";
        else
            upStr = speedFormat.format(intermediateResult.upBitPerSec / 1000000.0);
        testView.setResultUpString(upStr);

        testView.setTestStatus(intermediateResult.status);

        testView.invalidate();
    }

    public boolean onBackPressed() {
        if (rmbtService == null || !rmbtService.isTestRunning())
            return false;
        return onBackPressedHandler();
    }

    public boolean onBackPressedHandler() {
        Log.d("RMBTTestFragment", "onbackpressed");
        final RMBTMainActivity activity = (RMBTMainActivity) getActivity();
        if (activity == null)
            return false;
        if ((errorDialog != null && errorDialog.isShowing())
                || (progressDialog != null && progressDialog.isShowing())) {
            if (rmbtService != null)
                rmbtService.stopTest(RMBTService.BROADCAST_TEST_ABORTED);
            else {
                // to be sure test is stopped:
                final Intent service = new Intent(RMBTService.ACTION_ABORT_TEST, null, context, RMBTService.class);
                context.startService(service);
            }
            dismissDialogs();
            activity.getSupportFragmentManager().popBackStack();
            return true;
        }

        if (abortDialog != null && abortDialog.isShowing()) {
            dismissDialog(abortDialog);
            abortDialog = null;
        } else {
            final AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
            builder.setTitle(R.string.test_dialog_abort_title);
            builder.setMessage(R.string.test_dialog_abort_text);
            builder.setPositiveButton(R.string.test_dialog_abort_yes, new OnClickListener() {
                @Override
                public void onClick(final DialogInterface dialog, final int which) {
                    if (rmbtService != null)
                        rmbtService.stopTest(RMBTService.BROADCAST_TEST_ABORTED);
                    getActivity().getSupportFragmentManager().popBackStack();
                }
            });
            builder.setNegativeButton(R.string.test_dialog_abort_no, null);

            dismissDialogs();
            abortDialog = builder.show();
        }
        return true;
    }

    protected void showErrorDialog(int errorMessageId) {
        stopLoop = true;

        final AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
        builder.setTitle(R.string.test_dialog_error_title);
        builder.setMessage(errorMessageId);
        builder.setNeutralButton(android.R.string.ok, null);
        dismissDialogs();
        errorDialog = builder.create();
        errorDialog.setOnDismissListener(new OnDismissListener() {
            @Override
            public void onDismiss(DialogInterface dialog) {
                final RMBTMainActivity activity = (RMBTMainActivity) getActivity();
                if (activity != null)
                    activity.getSupportFragmentManager().popBackStack();
            }
        });
        errorDialog.show();
    }

    private void switchToResult() {
        if (!isVisible()) {
            return;
        }

        if (showQoSErrorToast) {
            final Toast toast = Toast.makeText(getActivity(), R.string.test_toast_error_text_qos,
                    Toast.LENGTH_LONG);
            toast.show();
        }

        dismissDialogs();

        final String testUuid = rmbtService == null ? null : rmbtService.getTestUuid(true);
        if (testUuid == null) {
            showErrorDialog(R.string.test_dialog_error_text);
            return;
        }

        ((RMBTMainActivity) getActivity()).showResultsAfterTest(testUuid);
    }

    private ProgressView extendedProgressView;
    private Button extendedResultButtonCancel;
    private Button extendedButtonDetails;

    private QoSTestEnum lastQoSTestStatus;

    public void updateQoSUI() {

        if (progressDialog != null) {
            progressDialog.dismiss();
            progressDialog = null;
        }

        QoSTestEnum status = null;
        float progress = 0f;

        try {
            if (rmbtService != null) {
                QoSTestEnum _status = rmbtService.getQoSTestStatus();
                if (_status == null) {
                    _status = lastQoSTestStatus == null ? QoSTestEnum.START : lastQoSTestStatus;
                }
                status = _status;
                lastQoSTestStatus = status;
                progress = rmbtService.getQoSTestProgress();
            } else {
                //                        Log.d(DEBUG_TAG, "we have no service");
                QoSTestEnum _status = lastQoSTestStatus;
                if (_status == null)
                    _status = QoSTestEnum.START;
                if (_status == QoSTestEnum.QOS_RUNNING)
                    _status = QoSTestEnum.STOP;

                status = _status;
            }

            //            Log.d(" DEBUG TEST", String.format("status: %s", status == null ? "null" : status.toString()));

            switch (status) {
            case START:
            case ERROR:
                progress = 0f;
                break;

            case STOP:
                progress = 1f;
                break;
            }

            double progressSegments = 0;

            if (extendedProgressView != null) {
                extendedProgressView.setProgress((progress / rmbtService.getQoSTestSize()));
            }

            switch (status) {
            case START:
                progressSegments = PROGRESS_SEGMENTS_INIT + PROGRESS_SEGMENTS_PING + PROGRESS_SEGMENTS_DOWN
                        + PROGRESS_SEGMENTS_UP
                        + Math.round(PROGRESS_SEGMENTS_QOS * (progress / rmbtService.getQoSTestSize()));
                break;

            case QOS_RUNNING:
                progressSegments = PROGRESS_SEGMENTS_INIT + PROGRESS_SEGMENTS_PING + PROGRESS_SEGMENTS_DOWN
                        + PROGRESS_SEGMENTS_UP
                        + Math.round(PROGRESS_SEGMENTS_QOS * (float) (progress / rmbtService.getQoSTestSize()));
                break;

            case QOS_FINISHED:
                progressSegments = PROGRESS_SEGMENTS_TOTAL - 1;
                break;

            case NDT_RUNNING:
                progressSegments = PROGRESS_SEGMENTS_TOTAL - 1;
                break;

            case STOP:
                progressSegments = PROGRESS_SEGMENTS_INIT + PROGRESS_SEGMENTS_PING + PROGRESS_SEGMENTS_DOWN
                        + PROGRESS_SEGMENTS_UP + PROGRESS_SEGMENTS_QOS;
                break;

            case ERROR:
            default:
                break;
            }

            final double progressValue = (double) progressSegments / PROGRESS_SEGMENTS_TOTAL;

            Integer signal = rmbtService.getSignal();
            int signalType = rmbtService.getSignalType();

            if (signal == null || signal == 0)
                signalType = InformationCollector.SINGAL_TYPE_NO_SIGNAL;

            if (signalType != InformationCollector.SINGAL_TYPE_NO_SIGNAL) {
                lastSignal = signal;
                lastSignalType = signalType;
            }

            if (signalType == InformationCollector.SINGAL_TYPE_NO_SIGNAL
                    && lastSignalType != InformationCollector.SINGAL_TYPE_NO_SIGNAL) {
                // keep old signal if we had one before
                signal = lastSignal;
                signalType = lastSignalType;
            }

            Double relativeSignal = null;
            MinMax<Integer> signalBoungs = NetworkUtil.getSignalStrengthBounds(signalType);
            if (!(signalBoungs.min == Integer.MIN_VALUE || signalBoungs.max == Integer.MAX_VALUE))
                relativeSignal = (double) (signal - signalBoungs.min)
                        / (double) (signalBoungs.max - signalBoungs.min);

            testView.setSignalType(signalType);
            if (signal != null)
                testView.setSignalString(String.valueOf(signal));
            if (relativeSignal != null)
                testView.setSignalValue(relativeSignal);

            final double correctProgressValue = testView.setProgressValue(progressValue);
            testView.setProgressString(percentFormat.format(correctProgressValue));
            testView.invalidate();

            if (status == QoSTestEnum.QOS_RUNNING && extendedResultButtonCancel != null
                    && extendedResultButtonCancel.getVisibility() == View.GONE) {
                extendedResultButtonCancel.setVisibility(View.VISIBLE);
                if (extendedButtonDetails != null)
                    extendedButtonDetails.setVisibility(View.GONE);
            }

            if (qosProgressView != null && qosProgressView.getVisibility() != View.VISIBLE && rmbtService != null
                    && rmbtService.getQoSTest() != null) {
                final GroupCountView groupCountView = new GroupCountView(getMainActivity());
                qosProgressView.setVisibility(View.VISIBLE);
                //register group counter view as a test progress listener:
                rmbtService.getQoSTest().getTestSettings().addTestProgressListener(groupCountView);
                groupCountView.setTaskMap(rmbtService.getQoSTest().getTestMap());
                groupCountContainerView.addView(groupCountView);
                groupCountContainerView.invalidate();
                ((GroupCountView) groupCountContainerView.getChildAt(0))
                        .setNdtProgress(rmbtService.getNDTProgress());
                if (graphView != null) {
                    graphView.setVisibility(View.GONE);
                }
                if (infoView != null) {
                    infoView.setVisibility(View.GONE);
                }
            } else if (qosProgressView != null && qosProgressView.getVisibility() == View.VISIBLE
                    && rmbtService.getQoSGroupCounterMap() != null) {
                ((GroupCountView) groupCountContainerView.getChildAt(0))
                        .setTaskMap(rmbtService.getQoSTest().getTestMap());
                ((GroupCountView) groupCountContainerView.getChildAt(0))
                        .setNdtProgress(rmbtService.getNDTProgress());
                ((GroupCountView) groupCountContainerView.getChildAt(0))
                        .setQoSTestStatus(rmbtService.getQoSTestStatus());
                ((GroupCountView) groupCountContainerView.getChildAt(0))
                        .updateView(rmbtService.getQoSGroupCounterMap());
            }

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (status != null && status == QoSTestEnum.ERROR)
                showQoSErrorToast = true;
        }
    }

    @Override
    public void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        if (testView != null) {
            outState.putString("header_string", testView.getHeaderString());
            outState.putString("sub_header_string", testView.getSubHeaderString());
            outState.putString("ping_string", testView.getResultPingString());
            outState.putString("down_string", testView.getResultDownString());
            outState.putString("up_string", testView.getResultUpString());
        }

        if (textView != null) {
            outState.putString("test_info", textView.getText().toString());
        }
    }

    @Override
    public void onConfigurationChanged(Configuration newConfig) {
        super.onConfigurationChanged(newConfig);
        LayoutInflater inflater = LayoutInflater.from(getActivity());
        populateViewForOrientation(inflater, (ViewGroup) getView());
    }

    private final String OPTION_ON_CREATE_VIEW_CREATE_SPEED_GRAPH = "create_speed_graph";
    private final String OPTION_ON_CREATE_VIEW_CREATE_SIGNAL_GRAPH = "create_signal_graph";

    /**
     * 
     * @param inflater
     * @param view
     */
    private void populateViewForOrientation(final LayoutInflater inflater, final ViewGroup view) {

        System.out.println("RECREATING INSTANCE FOR ORIENTATION CHANGE");

        GroupCountView groupCountView = null;
        if (groupCountContainerView != null && groupCountContainerView.getChildAt(0) != null) {
            groupCountView = (GroupCountView) groupCountContainerView.getChildAt(0);
            groupCountContainerView.removeAllViews();
        }

        final String infoText = String.valueOf(textView.getText());
        final String header = testView.getHeaderString();

        final String subHeader = testView.getSubHeaderString();
        final String resultPing = testView.getResultPingString();
        final String resultDown = testView.getResultDownString();
        final String resultUp = testView.getResultUpString();

        final GraphData signalGraphData;
        final GraphData speedGraphData;

        final MinMax<Integer> currentSignalBounds;
        final List<GraphView.GraphLabel> graphLabelList;

        if (graphView != null) {
            graphLabelList = graphView.getLabelInfoVerticalList();
            currentSignalBounds = graphView.getSignalRange();
        } else {
            graphLabelList = null;
            currentSignalBounds = null;
        }

        if (signalGraph != null) {
            signalGraphData = signalGraph.getGraphData();
        } else {
            signalGraphData = null;
        }

        if (speedGraph != null) {
            speedGraphData = speedGraph.getGraphData();
        } else {
            speedGraphData = null;
        }

        view.removeAllViewsInLayout();
        final View v = inflater.inflate(R.layout.test, view);

        final Bundle options = new Bundle();
        options.putBoolean(OPTION_ON_CREATE_VIEW_CREATE_SIGNAL_GRAPH, false);
        options.putBoolean(OPTION_ON_CREATE_VIEW_CREATE_SPEED_GRAPH, false);

        createView(v, inflater, options);

        if (groupCountContainerView != null && groupCountView != null && qosProgressView != null) {
            groupCountContainerView.addView(groupCountView);
            qosProgressView.setVisibility(View.VISIBLE);
            //groupCountContainerView.setVisibility(View.VISIBLE);

            if (graphView != null) {
                graphView.setVisibility(View.GONE);
            }
            if (infoView != null) {
                infoView.setVisibility(View.GONE);
            }
        }

        if (testView != null) {
            testView.setHeaderString(header);
            testView.setSubHeaderString(subHeader);
            testView.setResultPingString(resultPing);
            testView.setResultDownString(resultDown);
            testView.setResultUpString(resultUp);
        }

        if (textView != null) {
            textView.setText(infoText);
        }

        if (graphView != null) {
            graphView.setRowLinesLabelList(ResultGraphView.SPEED_LABELS);

            if (signalGraphData != null) {
                signalGraph = SimpleGraph.addGraph(graphView, GRAPH_MAX_NSECS, signalGraphData);

                if (currentSignalBounds != null) {
                    graphView.setLabelInfoVerticalList(graphLabelList);
                    graphView.setSignalRange(currentSignalBounds.min, currentSignalBounds.max);
                }
            }
            if (speedGraphData != null) {
                speedGraph = SmoothGraph.addGraph(graphView, SMOOTHING_DATA_AMOUNT, SMOOTHING_FUNCTION, false,
                        speedGraphData);
                speedGraph.setMaxTime(GRAPH_MAX_NSECS);
            }
        }

    }

    public static double calculateProgress(IntermediateResult result, final float qosTestProgress,
            final int qosTestSize) {
        double progressSegments = 0;
        switch (result.status) {
        case WAIT:
            break;

        case INIT:
            progressSegments = Math.round(PROGRESS_SEGMENTS_INIT * result.progress);
            break;

        case PING:
            progressSegments = PROGRESS_SEGMENTS_INIT + Math.round(PROGRESS_SEGMENTS_PING * result.progress);
            break;

        case DOWN:
            progressSegments = PROGRESS_SEGMENTS_INIT + PROGRESS_SEGMENTS_PING
                    + Math.round(PROGRESS_SEGMENTS_DOWN * result.progress);
            break;

        case INIT_UP:
            progressSegments = PROGRESS_SEGMENTS_INIT + PROGRESS_SEGMENTS_PING + PROGRESS_SEGMENTS_DOWN;
            break;

        case UP:
            progressSegments = PROGRESS_SEGMENTS_INIT + PROGRESS_SEGMENTS_PING + PROGRESS_SEGMENTS_DOWN
                    + Math.round(PROGRESS_SEGMENTS_UP * result.progress);
            break;

        case SPEEDTEST_END:
            progressSegments = PROGRESS_SEGMENTS_INIT + PROGRESS_SEGMENTS_PING + PROGRESS_SEGMENTS_DOWN
                    + PROGRESS_SEGMENTS_UP;
            break;

        case QOS_TEST_RUNNING:
            progressSegments = PROGRESS_SEGMENTS_INIT + PROGRESS_SEGMENTS_PING + PROGRESS_SEGMENTS_DOWN
                    + PROGRESS_SEGMENTS_UP
                    + Math.round((PROGRESS_SEGMENTS_QOS - 1) * (float) (qosTestProgress / qosTestSize));
            break;

        case QOS_END:
            progressSegments = PROGRESS_SEGMENTS_TOTAL - 1;
            break;

        case ERROR:
        case ABORTED:
            progressSegments = 0;
            break;
        default:
            break;
        }
        return (progressSegments / (double) PROGRESS_SEGMENTS_TOTAL);
    }
}