package com.samknows.ui2.activity; import java.util.ArrayList; import java.util.Calendar; import org.json.JSONObject; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.app.Activity; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.content.SharedPreferences; import android.graphics.Color; import android.graphics.Point; import android.graphics.Typeface; import android.os.AsyncTask; import android.os.Build; import android.os.Bundle; import android.os.Handler; import android.support.v4.app.Fragment; import android.support.v4.content.LocalBroadcastManager; import android.util.Log; import android.util.TypedValue; import android.view.Display; import android.view.Gravity; import android.view.KeyEvent; import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; import android.view.MotionEvent; import android.view.View; import android.view.ViewTreeObserver; import android.view.View.OnClickListener; import android.view.ViewGroup; import android.view.ViewTreeObserver.OnGlobalLayoutListener; import android.view.animation.OvershootInterpolator; import android.webkit.WebView; import android.widget.FrameLayout; import android.widget.LinearLayout; import android.widget.TextView; import android.widget.Toast; import com.samknows.libcore.SKPorting; import com.samknows.libcore.R; import com.samknows.libcore.SKTypeface; import com.samknows.measurement.SKApplication; import com.samknows.measurement.SKApplication.eNetworkTypeResults; import com.samknows.measurement.activity.components.SKGraphForResults; import com.samknows.measurement.activity.components.SKGraphForResults.DATERANGE_1w1m3m1y; import com.samknows.measurement.storage.DBHelper; import com.samknows.measurement.storage.StorageTestResult; import com.samknows.measurement.storage.SummaryResult; import com.samknows.measurement.storage.StorageTestResult.*; /** * This fragment is responsible for: * * Show average results * * Show best results * * Filter results by time period and network type * * Show graphs * <p/> * All rights reserved SamKnows * * @author pablo@samknows.com */ public class FragmentSummary extends Fragment { // *** CONSTANTS *** // private final static String C_TAG_FRAGMENT_SUMMARY = "Fragment Summary"; // Tag for this fragment // *** VARIABLES *** // private int header_section_height; // The initial position of each or the rows private float headerPositionX, headerPositionY, initialPositionUploadX, initialPositionUploadY, initialPositionLatencyX, initialPositionLatencyY, initialPositionLossX, initialPositionLossY, initialPositionJitterX, initialPositionJitterY; private boolean isListviewHidden = false; // If true, the list view is hidden, if false, the list view is shown. private long startTime; private ArrayList<SummaryResult> aList_SummaryResults = new ArrayList<>(); // List of the summary results // UI elements private Typeface typeface_Din_Condensed_Cyrillic, typeface_Roboto_Light, typeface_Roboto_Thin, typeface_Roboto_Regular; private TextView tv_summary_result_average_download; private TextView tv_summary_result_best_download; private TextView tv_summary_result_average_upload; private TextView tv_summary_result_best_upload; private TextView tv_summary_result_average_latency; private TextView tv_summary_result_best_latency; private TextView tv_summary_result_average_loss; private TextView tv_summary_result_best_loss; private TextView tv_summary_result_average_jitter; private TextView tv_summary_result_best_jitter; private TextView tv_label_average, tv_label_best; private LinearLayout mShowingThisSection = null; private LinearLayout layout_ll_summary_section_download, layout_ll_summary_section_upload, layout_ll_summary_section_latency, layout_ll_summary_section_packet_loss, layout_ll_summary_section_jitter, layout_ll_summary_result_average_download, layout_ll_summary_result_best_download, layout_ll_summary_result_average_upload, layout_ll_summary_result_best_upload, layout_ll_summary_result_average_latency, layout_ll_summary_result_best_latency, layout_ll_summary_result_average_packet_loss, layout_ll_summary_result_best_packet_loss, layout_ll_summary_result_average_jitter, layout_ll_summary_result_best_jitter; private FrameLayout layout_ll_chart; private LinearLayout layout_ll_header, layout_ll_summary_main; TextView mChartCaption; // Container for the graph private WebView graphContainer; private MenuItem menu_item_selectNetworkType, menu_Item_Select_Time_Period, menu_Item_Refresh_Spinner; private boolean asyncTask_RetrieveData_Running = false; // Whether or not the asynchronous task is running private boolean asyncTask_PrepareChart_Running = false; // Whether or not the asynchronous task is running private boolean aList_SummaryResults_No_Empty_For_Download, aList_SummaryResults_No_Empty_For_Upload, aList_SummaryResults_No_Empty_For_Latency, aList_SummaryResults_No_Empty_For_Packet_Loss, aList_SummaryResults_No_Empty_For_Jitter; private TextView mSummaryFilterButton = null; private TextView mSummaryTimePeriodButton = null; // Database private DBHelper dbHelper; // *** FRAGMENT LIFECYCLE METHODS *** // // Called to have the fragment instantiate its user interface view. @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.fragment_summary, container, false); // Create the view setUpResources(view); // Bind the resources with the elements in this class and set up them new RetrieveAverageAndBestResults().execute(); // Background process retrieving the data for the first time return view; // Inflate the layout for this fragment } // Called when the Fragment is no longer resumed. This is generally tied to Activity.onPause of the containing Activity's life cycle @Override public void onResume() { super.onResume(); registerBackButtonHandler(); // Register the local broadcast receiver listener to receive messages when the UI data needs to be refreshed. final Context context = SKApplication.getAppInstance().getApplicationContext(); LocalBroadcastManager.getInstance(context).registerReceiver(updateScreenMessageReceiver, new IntentFilter("refreshUIMessage")); View view = getView(); SKTypeface.sChangeChildrenToDefaultFontTypeface(view); // Assign fonts the the layout text fields tv_summary_result_average_download.setTypeface(typeface_Din_Condensed_Cyrillic); tv_summary_result_best_download.setTypeface(typeface_Din_Condensed_Cyrillic); tv_summary_result_average_upload.setTypeface(typeface_Din_Condensed_Cyrillic); tv_summary_result_best_upload.setTypeface(typeface_Din_Condensed_Cyrillic); tv_summary_result_average_latency.setTypeface(typeface_Din_Condensed_Cyrillic); tv_summary_result_best_latency.setTypeface(typeface_Din_Condensed_Cyrillic); tv_summary_result_average_loss.setTypeface(typeface_Din_Condensed_Cyrillic); tv_summary_result_best_loss.setTypeface(typeface_Din_Condensed_Cyrillic); tv_summary_result_average_jitter.setTypeface(typeface_Din_Condensed_Cyrillic); tv_summary_result_best_jitter.setTypeface(typeface_Din_Condensed_Cyrillic); ((TextView) view.findViewById(R.id.tv_label_average)).setTypeface(typeface_Roboto_Regular); ((TextView) view.findViewById(R.id.tv_label_best)).setTypeface(typeface_Roboto_Regular); ((TextView) view.findViewById(R.id.tv_summary_label_Mbps_1)).setTypeface(typeface_Roboto_Regular); ((TextView) view.findViewById(R.id.tv_summary_label_Mbps_2)).setTypeface(typeface_Roboto_Regular); ((TextView) view.findViewById(R.id.tv_summary_label_Mbps_3)).setTypeface(typeface_Roboto_Regular); ((TextView) view.findViewById(R.id.tv_summary_label_Mbps_4)).setTypeface(typeface_Roboto_Regular); ((TextView) view.findViewById(R.id.tv_summary_label_ms_1)).setTypeface(typeface_Roboto_Regular); ((TextView) view.findViewById(R.id.tv_summary_label_ms_2)).setTypeface(typeface_Roboto_Regular); ((TextView) view.findViewById(R.id.tv_summary_label_ms_3)).setTypeface(typeface_Roboto_Regular); ((TextView) view.findViewById(R.id.tv_summary_label_ms_4)).setTypeface(typeface_Roboto_Regular); ((TextView) view.findViewById(R.id.tv_summary_download_label)).setTypeface(typeface_Roboto_Regular); ((TextView) view.findViewById(R.id.tv_summary_upload_label)).setTypeface(typeface_Roboto_Regular); ((TextView) view.findViewById(R.id.tv_summary_latency_label)).setTypeface(typeface_Roboto_Regular); ((TextView) view.findViewById(R.id.tv_summary_packet_loss_label)).setTypeface(typeface_Roboto_Regular); ((TextView) view.findViewById(R.id.tv_summary_jitter_label)).setTypeface(typeface_Roboto_Regular); } Activity mActivity = null; @Override public void onAttach(Activity activity) { super.onAttach(activity); mActivity = activity; // WE must DEFER the chart data loading (which actually happens on the main thread!) to prevent the UI blocking on start-up // This cannot be done until we're attached to an activity! new Handler().post(new Runnable() { @Override public void run() { new PrepareChartData().execute(); // Prepare the chart data. This needs to be done here because a filter was triggered } }); } @Override public void onDetach() { super.onDetach(); mActivity = null; } // Receive the result from a previous call to startActivityForResult(Intent, int) @Override public void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); // Check if the data is different from null. Is null for instance when the user leaves the activity with the back button if (data != null) { // Check what activity was launched as startActivityForResults switch (requestCode) { // The activity that we came from is ActivitySelectNetworkType case 0: eNetworkTypeResults networkType; switch (data.getIntExtra("networkType", 0)) { case 0: networkType = eNetworkTypeResults.eNetworkTypeResults_Any; break; case 1: networkType = eNetworkTypeResults.eNetworkTypeResults_WiFi; break; case 2: networkType = eNetworkTypeResults.eNetworkTypeResults_Mobile; break; default: networkType = eNetworkTypeResults.eNetworkTypeResults_WiFi; SKPorting.sAssert(getClass(), false); break; } // If the network selection is different from the current network selection if (networkType != getNetworkTypeSelection()) { saveNetworkTypeSelection(networkType); // Save the new network selection new RetrieveAverageAndBestResults().execute(); // Retrieve the data with the current network type new PrepareChartData().execute(); // Prepare the chart data. This needs to be done here because a filter was triggered } break; // The activity that we came from is ActivitySelectTimePeriod case 1: int time_period = data.getIntExtra("timePeriod", 0); // If the time period selection is different from the current time period selection if (time_period != getTimePeriodSelection()) { saveTimePeriodSelection(time_period); // Save the new time period selection new RetrieveAverageAndBestResults().execute(); // Retrieve the data with the current time period new PrepareChartData().execute(); // Prepare the chart data. This needs to be done here because a filter was triggered } break; default: break; } } } // Called when the fragment is visible to the user and actively running @Override public void onPause() { super.onPause(); // Unregister since the activity is about to be closed. final Context context = SKApplication.getAppInstance().getApplicationContext(); LocalBroadcastManager.getInstance(context).unregisterReceiver(updateScreenMessageReceiver); } // *** BROADCAST RECEIVERS *** // // Our handler for received Intents. This will be called whenever an Intent with an action named "refreshUIMessage" is broadcasted. private final BroadcastReceiver updateScreenMessageReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { // Refresh the UI data. This it's need because the list view data was modified new RetrieveAverageAndBestResults().execute(); new PrepareChartData().execute(); // Prepare the chart data. This needs to be done here because a filter was triggered } }; private void safeRunOnUiThread(Runnable runnable) { if (getActivity() == null) { SKPorting.sAssert(getClass(), false); return; } getActivity().runOnUiThread(runnable); } // *** INNER CLASSES *** // /** * Retrieve the data from the database and update the UI */ private class RetrieveAverageAndBestResults extends AsyncTask<Void, Void, Void> { // Runs on the UI thread before doInBackground @Override protected void onPreExecute() { super.onPreExecute(); asyncTask_RetrieveData_Running = true; aList_SummaryResults_No_Empty_For_Download = false; aList_SummaryResults_No_Empty_For_Upload = false; aList_SummaryResults_No_Empty_For_Latency = false; aList_SummaryResults_No_Empty_For_Packet_Loss = false; aList_SummaryResults_No_Empty_For_Jitter = false; // Restore all the fields before set the new values // This is made because sometimes not all values are refreshed and they will show an slash safeRunOnUiThread(new Runnable() { @Override public void run() { layout_ll_summary_result_average_download.setGravity(Gravity.CENTER); layout_ll_summary_result_best_download.setGravity(Gravity.CENTER); layout_ll_summary_result_average_upload.setGravity(Gravity.CENTER); layout_ll_summary_result_best_upload.setGravity(Gravity.CENTER); layout_ll_summary_result_average_latency.setGravity(Gravity.CENTER); layout_ll_summary_result_best_latency.setGravity(Gravity.CENTER); layout_ll_summary_result_average_packet_loss.setGravity(Gravity.CENTER); layout_ll_summary_result_best_packet_loss.setGravity(Gravity.CENTER); layout_ll_summary_result_average_jitter.setGravity(Gravity.CENTER); layout_ll_summary_result_best_jitter.setGravity(Gravity.CENTER); tv_summary_result_average_download.setText(getString(R.string.slash)); tv_summary_result_best_download.setText((R.string.slash)); tv_summary_result_average_upload.setText(getString(R.string.slash)); tv_summary_result_best_upload.setText((R.string.slash)); tv_summary_result_average_latency.setText(getString(R.string.slash)); tv_summary_result_best_latency.setText((R.string.slash)); tv_summary_result_average_loss.setText(getString(R.string.slash)); tv_summary_result_best_loss.setText((R.string.slash)); tv_summary_result_average_jitter.setText(getString(R.string.slash)); tv_summary_result_best_jitter.setText((R.string.slash)); } }); // // TODO - this could fail with random SQL error when run in an async task! // ExtractSummaryValues (); } private void ExtractSummaryValues() { // Defend against "java.lang.IllegalStateException: Fragment FragmentRunTest{...} not attached to Activity" // http://stackoverflow.com/questions/10919240/fragment-myfragment-not-attached-to-activity if (isAdded() == false) { SKPorting.sAssert(getClass(), false); return; } if (getActivity() == null) { SKPorting.sAssert(getClass(), false); return; } // Get the summary values from the data base aList_SummaryResults = dbHelper.getSummaryValues(getNetworkTypeSelection(), calculateTimePeriodStart()); final FormattedValues formattedValues = new FormattedValues(); // Class to format the values // Iterate the summary results list for (final SummaryResult summaryResult : aList_SummaryResults) { switch (summaryResult.getTestType()) { // Summary result is download type case DOWNLOAD_TEST_ID: aList_SummaryResults_No_Empty_For_Download = true; safeRunOnUiThread(new Runnable() // UI modifications must be executed in the UI thread { @Override public void run() { layout_ll_summary_result_average_download.setGravity(Gravity.LEFT); layout_ll_summary_result_best_download.setGravity(Gravity.RIGHT); String testAverage = FormattedValues.sGet3DigitsNumber(summaryResult.getAverage()); String testMaximum = FormattedValues.sGet3DigitsNumber(summaryResult.getMax()); tv_summary_result_average_download.setText(testAverage); tv_summary_result_best_download.setText(testMaximum); } }); break; // Summary result is upload type case UPLOAD_TEST_ID: aList_SummaryResults_No_Empty_For_Upload = true; safeRunOnUiThread(new Runnable() // UI modifications must be executed in the UI thread { @Override public void run() { layout_ll_summary_result_average_upload.setGravity(Gravity.LEFT); layout_ll_summary_result_best_upload.setGravity(Gravity.RIGHT); String testAverage = FormattedValues.sGet3DigitsNumber(summaryResult.getAverage()); String testMaximum = FormattedValues.sGet3DigitsNumber(summaryResult.getMax()); tv_summary_result_average_upload.setText(testAverage); tv_summary_result_best_upload.setText(testMaximum); } }); break; // Summary result is latency type case LATENCY_TEST_ID: aList_SummaryResults_No_Empty_For_Latency = true; safeRunOnUiThread(new Runnable() // UI modifications must be executed in the UI thread { @Override public void run() { layout_ll_summary_result_average_latency.setGravity(Gravity.LEFT); layout_ll_summary_result_best_latency.setGravity(Gravity.RIGHT); String toShowAverage = StorageTestResult.timeMicrosecondsToMillisecondsStringNoUnits(summaryResult.getAverage() * 1000.0); tv_summary_result_average_latency.setText(toShowAverage); String toShowMin = StorageTestResult.timeMicrosecondsToMillisecondsStringNoUnits(summaryResult.getMin() * 1000.0); tv_summary_result_best_latency.setText(toShowMin); } }); break; // Summary result is packet loss type case PACKETLOSS_TEST_ID: aList_SummaryResults_No_Empty_For_Packet_Loss = true; safeRunOnUiThread(new Runnable() // UI modifications must be executed in the UI thread { @Override public void run() { layout_ll_summary_result_average_packet_loss.setGravity(Gravity.LEFT); layout_ll_summary_result_best_packet_loss.setGravity(Gravity.RIGHT); tv_summary_result_average_loss.setText(String.format("%d", (int)summaryResult.getAverage())); tv_summary_result_best_loss.setText(String.format("%d", (int)summaryResult.getMin())); } }); break; // Summary result is jitter type case JITTER_TEST_ID: aList_SummaryResults_No_Empty_For_Jitter = true; safeRunOnUiThread(new Runnable() // UI modifications must be executed in the UI thread { @Override public void run() { layout_ll_summary_result_average_jitter.setGravity(Gravity.LEFT); layout_ll_summary_result_best_jitter.setGravity(Gravity.RIGHT); String toShowAverage = StorageTestResult.timeMicrosecondsToMillisecondsStringNoUnits(summaryResult.getAverage() * 1000.0); tv_summary_result_average_jitter.setText(toShowAverage); String toShowMin = StorageTestResult.timeMicrosecondsToMillisecondsStringNoUnits(summaryResult.getMin() * 1000.0); tv_summary_result_best_jitter.setText(toShowMin); } }); break; default: break; } } } // Override this method to perform a computation on a background thread @Override protected Void doInBackground(Void... params) { ExtractSummaryValues(); return null; } @Override protected void onPostExecute(Void result) { super.onPostExecute(result); asyncTask_RetrieveData_Running = false; if (menu_Item_Refresh_Spinner != null & asyncTask_PrepareChart_Running == false) { // Make invisible the progress spinner menu_Item_Refresh_Spinner.setVisible(false); } } } /** * Prepare the chart data */ private class PrepareChartData extends AsyncTask<Void, Void, Void> { @Override protected void onPreExecute() { super.onPreExecute(); asyncTask_PrepareChart_Running = true; // Set the possibility to display the graphs to true chartsAvailable(false); if (menu_Item_Refresh_Spinner != null) { // Make visible the progress spinner menu_Item_Refresh_Spinner.setVisible(true); } // TODO - this CANNOT be run in the background - achartengine simply doesn't allow for it! // TODO - 0 is the DOWNLOAD etc. test id! if ((mActivity == null) || (isAdded() == false) || (getActivity() == null)) { SKPorting.sAssert(getClass(), false); } else { prepareChartEnvironment(0, getTimePeriodSelection()); } } // Override this method to perform a computation on a background thread @Override protected Void doInBackground(Void... params) { return null; } @Override protected void onPostExecute(Void result) { super.onPostExecute(result); asyncTask_PrepareChart_Running = false; if (menu_Item_Refresh_Spinner != null & asyncTask_RetrieveData_Running == false) { // Make invisible the progress spinner menu_Item_Refresh_Spinner.setVisible(false); } // Set the possibility to display the graphs to true chartsAvailable(true); } } private boolean hide_ll_chart_generic() { if (mShowingThisSection == layout_ll_summary_section_download) { hide_ll_chart_download(); } else if (mShowingThisSection == layout_ll_summary_section_upload) { hide_ll_chart_upload(); } else if (mShowingThisSection == layout_ll_summary_section_latency) { hide_ll_chart_latency(); } else if (mShowingThisSection == layout_ll_summary_section_packet_loss) { hide_ll_chart_packetloss(); } else if (mShowingThisSection == layout_ll_summary_section_jitter) { hide_ll_chart_jitter(); } else { SKPorting.sAssert(getClass(), false); return false; } return true; } private void hide_ll_chart_download() { // Hide the chart mChartCaption.setAlpha(0.0F); layout_ll_chart.animate().setDuration(300).alpha(0.0f).setListener(new AnimatorListenerAdapter() { // Executed at the end of the animation @Override public void onAnimationEnd(Animator animation) { super.onAnimationEnd(animation); layout_ll_chart.animate().setListener(null); layout_ll_chart.setVisibility(View.GONE); // Set the position of the other rows to the initial position with an animation. layout_ll_summary_section_upload.animate().x(headerPositionX).setDuration(300).alpha(1.0f).setInterpolator(new OvershootInterpolator(1.2f)); layout_ll_summary_section_latency.animate().x(headerPositionX).setDuration(300).alpha(1.0f).setInterpolator(new OvershootInterpolator(1.2f)); layout_ll_summary_section_jitter.animate().x(headerPositionX).setDuration(300).alpha(1.0f).setInterpolator(new OvershootInterpolator(1.2f)); layout_ll_summary_section_packet_loss.animate().x(headerPositionX).setDuration(300).alpha(1.0f).setInterpolator(new OvershootInterpolator(1.2f)).setListener(new AnimatorListenerAdapter() { // Executed at the end of the animation @Override public void onAnimationEnd(Animator animation) { super.onAnimationEnd(animation); // Enable click events setLayoutsClickable(true); // Update toolbar/menu items! doUpdateToolbarSetIsListViewHidden(false); } }); } }); } void doUpdateToolbarSetIsListViewHidden(boolean value) { isListviewHidden = value; // mSummaryFilterButton.setVisibility(View.GONE); // mSummaryTimePeriodButton.setVisibility(View.GONE); // // if (isListviewHidden == true) { // // Showing result details... // } else { // // Not showing result details. Show the button. // mSummaryFilterButton.setVisibility(View.VISIBLE); // mSummaryTimePeriodButton.setVisibility(View.VISIBLE); // } if (getActivity() != null) { getActivity().invalidateOptionsMenu(); } } private void hide_ll_chart_upload() { // Hide the chart mChartCaption.setAlpha(0.0F); layout_ll_chart.animate().setDuration(300).alpha(0.0f).setListener(new AnimatorListenerAdapter() { // Executed at the end of the animation @Override public void onAnimationEnd(Animator animation) { super.onAnimationEnd(animation); layout_ll_chart.animate().setListener(null); // Delete the listener to avoid side effects layout_ll_chart.setVisibility(View.GONE); layout_ll_summary_section_upload.animate().setDuration(300).x(initialPositionUploadX).y(initialPositionUploadY).setInterpolator(new OvershootInterpolator(1.2f)).setListener(new AnimatorListenerAdapter() { // Executed at the end of the animation @Override public void onAnimationEnd(Animator animation) { super.onAnimationEnd(animation); // Set the position of the other rows to the initial position with an animation. layout_ll_summary_section_download.animate().x(headerPositionX).setDuration(300).alpha(1.0f).setInterpolator(new OvershootInterpolator(1.2f)); layout_ll_summary_section_latency.animate().x(headerPositionX).setDuration(300).alpha(1.0f).setInterpolator(new OvershootInterpolator(1.2f)); layout_ll_summary_section_packet_loss.animate().x(headerPositionX).setDuration(300).alpha(1.0f).setInterpolator(new OvershootInterpolator(1.2f)); layout_ll_summary_section_jitter.animate().x(headerPositionX).setDuration(300).alpha(1.0f).setInterpolator(new OvershootInterpolator(1.2f)); // Delete the listener of the row to avoid side effects layout_ll_summary_section_upload.animate().setListener(null); // Enable click events setLayoutsClickable(true); // Update toolbar/menu items! doUpdateToolbarSetIsListViewHidden(false); } }); } }); } private void hide_ll_chart_latency() { // Hide the chart mChartCaption.setAlpha(0.0F); layout_ll_chart.animate().setDuration(300).alpha(0.0f).setListener(new AnimatorListenerAdapter() { // Executed at the end of the animation @Override public void onAnimationEnd(Animator animation) { super.onAnimationEnd(animation); layout_ll_chart.animate().setListener(null); layout_ll_chart.setVisibility(View.GONE); layout_ll_summary_section_latency.animate().setDuration(300).x(initialPositionLatencyX).y(initialPositionLatencyY).setInterpolator(new OvershootInterpolator(1.2f)).setListener(new AnimatorListenerAdapter() { // Executed at the end of the animation @Override public void onAnimationEnd(Animator animation) { // Set the position of the other rows to the initial position with an animation. layout_ll_summary_section_upload.animate().x(headerPositionX).setDuration(300).alpha(1.0f).setInterpolator(new OvershootInterpolator(1.2f)); layout_ll_summary_section_download.animate().x(headerPositionX).setDuration(300).alpha(1.0f).setInterpolator(new OvershootInterpolator(1.2f)); layout_ll_summary_section_packet_loss.animate().x(headerPositionX).setDuration(300).alpha(1.0f).setInterpolator(new OvershootInterpolator(1.2f)); layout_ll_summary_section_jitter.animate().x(headerPositionX).setDuration(300).alpha(1.0f).setInterpolator(new OvershootInterpolator(1.2f)); // Delete the listener of the row to avoid side effects layout_ll_summary_section_latency.animate().setListener(null); // Enable click events setLayoutsClickable(true); // Update toolbar/menu items! doUpdateToolbarSetIsListViewHidden(false); } }); } }); } private void hide_ll_chart_packetloss() { // Hide the chart mChartCaption.setAlpha(0.0F); layout_ll_chart.animate().setDuration(300).alpha(0.0f).setListener(new AnimatorListenerAdapter() { // Executed at the end of the animation @Override public void onAnimationEnd(Animator animation) { super.onAnimationEnd(animation); layout_ll_chart.animate().setListener(null); // Delete animation listener to avoid side effects layout_ll_chart.setVisibility(View.GONE); layout_ll_summary_section_packet_loss.animate().setDuration(300).x(initialPositionLossX).y(initialPositionLossY).setInterpolator(new OvershootInterpolator(1.2f)).setListener(new AnimatorListenerAdapter() { // Executed at the end of the animation @Override public void onAnimationEnd(Animator animation) { // Set the position of the other rows to the initial position with an animation. layout_ll_summary_section_download.animate().x(headerPositionX).setDuration(300).alpha(1.0f).setInterpolator(new OvershootInterpolator(1.2f)); layout_ll_summary_section_upload.animate().x(headerPositionX).setDuration(300).alpha(1.0f).setInterpolator(new OvershootInterpolator(1.2f)); layout_ll_summary_section_latency.animate().x(headerPositionX).setDuration(300).alpha(1.0f).setInterpolator(new OvershootInterpolator(1.2f)); layout_ll_summary_section_jitter.animate().x(headerPositionX).setDuration(300).alpha(1.0f).setInterpolator(new OvershootInterpolator(1.2f)); // Delete the listener of the row to avoid side effects layout_ll_summary_section_packet_loss.animate().setListener(null); // Enable click events setLayoutsClickable(true); // Update toolbar/menu items! doUpdateToolbarSetIsListViewHidden(false); } }); } }); } private void hide_ll_chart_jitter() { // Hide the chart mChartCaption.setAlpha(0.0F); layout_ll_chart.animate().setDuration(300).alpha(0.0f).setListener(new AnimatorListenerAdapter() { // Executed at the end of the animation @Override public void onAnimationEnd(Animator animation) { super.onAnimationEnd(animation); layout_ll_chart.animate().setListener(null); // Delete the listener to avoid side effects layout_ll_chart.setVisibility(View.GONE); layout_ll_summary_section_jitter.animate().setDuration(300).x(initialPositionJitterX).y(initialPositionJitterY).setInterpolator(new OvershootInterpolator(1.2f)).setListener(new AnimatorListenerAdapter() { // Executed at the end of the animation @Override public void onAnimationEnd(Animator animation) { super.onAnimationEnd(animation); // Set the position of the other rows to the initial position with an animation. layout_ll_summary_section_download.animate().x(headerPositionX).setDuration(300).alpha(1.0f).setInterpolator(new OvershootInterpolator(1.2f)); layout_ll_summary_section_upload.animate().x(headerPositionX).setDuration(300).alpha(1.0f).setInterpolator(new OvershootInterpolator(1.2f)); layout_ll_summary_section_latency.animate().x(headerPositionX).setDuration(300).alpha(1.0f).setInterpolator(new OvershootInterpolator(1.2f)); layout_ll_summary_section_packet_loss.animate().x(headerPositionX).setDuration(300).alpha(1.0f).setInterpolator(new OvershootInterpolator(1.2f)); // Delete the listener of the row to avoid side effects layout_ll_summary_section_jitter.animate().setListener(null); // Enable click events setLayoutsClickable(true); // Update toolbar/menu items! doUpdateToolbarSetIsListViewHidden(false); } }); } }); } private void registerBackButtonHandler() { View view = getView(); view.setFocusableInTouchMode(true); view.requestFocus(); view.setOnKeyListener(new View.OnKeyListener() { @Override public boolean onKey(View v, int keyCode, KeyEvent event) { if (keyCode == KeyEvent.KEYCODE_BACK) { // TODO - should we handle this ourselves, or not?! if (isListviewHidden == false) { // Don't handle it... return false; } // Handle the back button event directly. // The gauge elements are invisible - show them and hide the passive metrics. if (hide_ll_chart_generic() == false) { SKPorting.sAssert(getClass(), false); return false; } return true; } else { // Don't handle it... return false; } } }); } // // Get the height that would be taken by an action bar on this Android system. // https://stackoverflow.com/questions/12301510/how-to-get-the-actionbar-height // Works even if action bar hidden... note that simply doing getActivity().getActionBar().getHeight() returns 0 // if the action bar is hidden. // int getActionBarHeight() { TypedValue tv = new TypedValue(); if (getActivity() == null) { return 0; } if (getActivity().getTheme().resolveAttribute(android.R.attr.actionBarSize, tv, true)) { int actionBarHeight = TypedValue.complexToDimensionPixelSize(tv.data, getResources().getDisplayMetrics()); return actionBarHeight; } return 0; } // *** CUSTOM METHODS *** // /** * Bind the resources of the layout with the objects in this class and set up them * * @param pView View to inflate */ private void setUpResources(View pView) { final Context context = SKApplication.getAppInstance().getApplicationContext(); // Create the dbHelper to query the data base dbHelper = new DBHelper(context); // Report that this fragment would like to participate in populating the options menu by receiving a call to onCreateOptionsMenu(Menu, MenuInflater) and related methods. setHasOptionsMenu(true); // Main layout layout_ll_summary_main = (LinearLayout) pView.findViewById(R.id.ll_summary_main); // Header fields layout_ll_header = (LinearLayout) pView.findViewById(R.id.ll_header); tv_label_average = (TextView) pView.findViewById(R.id.tv_label_average); tv_label_best = (TextView) pView.findViewById(R.id.tv_label_best); mSummaryFilterButton = (TextView)pView.findViewById(R.id.summary_filter_button); mSummaryFilterButton.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { showSelectNetwork(); } }); mSummaryTimePeriodButton = (TextView)pView.findViewById(R.id.summary_time_period_button); mSummaryTimePeriodButton.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { showSelectTimePeriod(); } }); setNetworkTypeButtonText(); setTimePeriodButtonText(); // // Set up the on click listener to perform a shake animation // OnClickListener shakeOnClickListener = new OnClickListener() { // @Override // public void onClick(View v) { // if (getActivity() != null) { // v.startAnimation(AnimationUtils.loadAnimation(getActivity(), R.anim.shake)); // } // } // }; // // // Assign the on click listener to the header fields // tv_label_average.setOnClickListener(shakeOnClickListener); // tv_label_best.setOnClickListener(shakeOnClickListener); // Main sections of the layout layout_ll_summary_section_download = (LinearLayout) pView.findViewById(R.id.ll_summary_section_download); layout_ll_summary_section_upload = (LinearLayout) pView.findViewById(R.id.ll_summary_section_upload); layout_ll_summary_section_latency = (LinearLayout) pView.findViewById(R.id.ll_summary_section_latency); layout_ll_summary_section_packet_loss = (LinearLayout) pView.findViewById(R.id.ll_summary_section_loss); layout_ll_summary_section_jitter = (LinearLayout) pView.findViewById(R.id.ll_summary_section_jitter); if (SKApplication.getAppInstance().hideJitter()) { layout_ll_summary_section_jitter.setVisibility(View.INVISIBLE); } if (SKApplication.getAppInstance().hideLoss()) { layout_ll_summary_section_packet_loss.setVisibility(View.INVISIBLE); } // Results layouts layout_ll_summary_result_average_download = (LinearLayout) pView.findViewById(R.id.fragment_summary_download_ll_average); layout_ll_summary_result_best_download = (LinearLayout) pView.findViewById(R.id.fragment_summary_download_ll_best); layout_ll_summary_result_average_upload = (LinearLayout) pView.findViewById(R.id.fragment_summary_upload_ll_average); layout_ll_summary_result_best_upload = (LinearLayout) pView.findViewById(R.id.fragment_summary_upload_ll_best); layout_ll_summary_result_average_latency = (LinearLayout) pView.findViewById(R.id.fragment_summary_latency_ll_average); layout_ll_summary_result_best_latency = (LinearLayout) pView.findViewById(R.id.fragment_summary_latency_ll_best); layout_ll_summary_result_average_packet_loss = (LinearLayout) pView.findViewById(R.id.fragment_summary_packet_loss_ll_average); layout_ll_summary_result_best_packet_loss = (LinearLayout) pView.findViewById(R.id.fragment_summary_packet_loss_ll_best); layout_ll_summary_result_average_jitter = (LinearLayout) pView.findViewById(R.id.fragment_summary_jitter_ll_average); layout_ll_summary_result_best_jitter = (LinearLayout) pView.findViewById(R.id.fragment_summary_jitter_ll_best); // Result fields tv_summary_result_average_download = (TextView) pView.findViewById(R.id.tv_summary_result_average_download); tv_summary_result_best_download = (TextView) pView.findViewById(R.id.tv_summary_result_best_download); tv_summary_result_average_upload = (TextView) pView.findViewById(R.id.tv_summary_result_average_upload); tv_summary_result_best_upload = (TextView) pView.findViewById(R.id.tv_summary_result_best_upload); tv_summary_result_average_latency = (TextView) pView.findViewById(R.id.tv_summary_result_average_latency); tv_summary_result_best_latency = (TextView) pView.findViewById(R.id.tv_summary_result_best_latency); tv_summary_result_average_loss = (TextView) pView.findViewById(R.id.tv_summary_result_average_packet_loss); tv_summary_result_best_loss = (TextView) pView.findViewById(R.id.tv_summary_result_best_packet_loss); tv_summary_result_average_jitter = (TextView) pView.findViewById(R.id.tv_summary_result_average_jitter); tv_summary_result_best_jitter = (TextView) pView.findViewById(R.id.tv_summary_result_best_jitter); tv_summary_result_average_download.setText(R.string.slash); tv_summary_result_best_download.setText(R.string.slash); tv_summary_result_average_upload.setText(R.string.slash); tv_summary_result_best_upload.setText(R.string.slash); tv_summary_result_average_latency.setText(R.string.slash); tv_summary_result_best_latency.setText(R.string.slash); tv_summary_result_average_loss.setText(R.string.slash); tv_summary_result_best_loss.setText(R.string.slash); tv_summary_result_average_jitter.setText(R.string.slash); tv_summary_result_best_jitter.setText(R.string.slash); // Set up the fonts to be used typeface_Din_Condensed_Cyrillic = SKTypeface.sGetTypefaceWithPathInAssets( "fonts/roboto_condensed_regular.ttf"); typeface_Roboto_Light = SKTypeface.sGetTypefaceWithPathInAssets( "fonts/roboto_light.ttf"); typeface_Roboto_Thin = SKTypeface.sGetTypefaceWithPathInAssets( "fonts/roboto_thin.ttf"); typeface_Roboto_Regular = SKTypeface.sGetTypefaceWithPathInAssets( "fonts/roboto_regular.ttf"); // Chart elements layout_ll_chart = (FrameLayout) pView.findViewById(R.id.fragment_summary_ll_chart); mChartCaption = (TextView) pView.findViewById(R.id.download_caption); graphsSetup(pView); // Hide the chart layout for now! mChartCaption.setAlpha(0.0F); layout_ll_chart.setAlpha(0.0f); layout_ll_chart.setVisibility(View.GONE); // Get the width of the screen in pixels Display display = getActivity().getWindowManager().getDefaultDisplay(); Point size = new Point(); display.getSize(size); final int screenWidth = size.x; // Get the height of the header layout layout_ll_header.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() { @Override public void onGlobalLayout() { header_section_height = layout_ll_header.getHeight(); ViewTreeObserver observer = layout_ll_header.getViewTreeObserver(); if (observer != null) { // http://stackoverflow.com/questions/15162821/why-does-removeongloballayoutlistener-throw-a-nosuchmethoderror try { if (Build.VERSION.SDK_INT >= 16) { observer.removeOnGlobalLayoutListener(this); } } catch (NoSuchMethodError x) { observer.removeGlobalOnLayoutListener(this); } } } }); // Get the position of the header row when it's already drawn layout_ll_summary_section_download.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() { @Override public void onGlobalLayout() { //final int actionBarHeight = getActionBarHeight(); headerPositionX = layout_ll_summary_section_download.getLeft(); headerPositionY = layout_ll_summary_section_download.getTop(); ViewTreeObserver observer = layout_ll_summary_section_download.getViewTreeObserver(); if (observer != null) { // http://stackoverflow.com/questions/15162821/why-does-removeongloballayoutlistener-throw-a-nosuchmethoderror try { if (Build.VERSION.SDK_INT >= 16) { observer.removeOnGlobalLayoutListener(this); } } catch (NoSuchMethodError x) { observer.removeGlobalOnLayoutListener(this); } } } }); // Get the initial position of the upload row when it's already drawn layout_ll_summary_section_upload.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() { @Override public void onGlobalLayout() { initialPositionUploadX = layout_ll_summary_section_upload.getLeft(); initialPositionUploadY = layout_ll_summary_section_upload.getTop(); ViewTreeObserver observer = layout_ll_summary_section_upload.getViewTreeObserver(); if (observer != null) { // http://stackoverflow.com/questions/15162821/why-does-removeongloballayoutlistener-throw-a-nosuchmethoderror try { if (Build.VERSION.SDK_INT >= 16) { observer.removeOnGlobalLayoutListener(this); } } catch (NoSuchMethodError x) { observer.removeGlobalOnLayoutListener(this); } } } }); // Get the initial position of the latency row when it's already drawn layout_ll_summary_section_latency.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() { @Override public void onGlobalLayout() { initialPositionLatencyX = layout_ll_summary_section_latency.getLeft(); initialPositionLatencyY = layout_ll_summary_section_latency.getTop(); ViewTreeObserver observer = layout_ll_summary_section_latency.getViewTreeObserver(); if (observer != null) { // http://stackoverflow.com/questions/15162821/why-does-removeongloballayoutlistener-throw-a-nosuchmethoderror try { if (Build.VERSION.SDK_INT >= 16) { observer.removeOnGlobalLayoutListener(this); } } catch (NoSuchMethodError x) { observer.removeGlobalOnLayoutListener(this); } } } }); // Get the initial position of the packet loss row when it's already drawn layout_ll_summary_section_packet_loss.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() { @Override public void onGlobalLayout() { initialPositionLossX = layout_ll_summary_section_packet_loss.getLeft(); initialPositionLossY = layout_ll_summary_section_packet_loss.getTop(); ViewTreeObserver observer = layout_ll_summary_section_packet_loss.getViewTreeObserver(); if (observer != null) { // http://stackoverflow.com/questions/15162821/why-does-removeongloballayoutlistener-throw-a-nosuchmethoderror try { if (Build.VERSION.SDK_INT >= 16) { observer.removeOnGlobalLayoutListener(this); } } catch (NoSuchMethodError x) { observer.removeGlobalOnLayoutListener(this); } } } }); // Get the initial position of the packet loss row when it's already drawn layout_ll_summary_section_jitter.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() { @Override public void onGlobalLayout() { initialPositionJitterX = layout_ll_summary_section_jitter.getLeft(); initialPositionJitterY = layout_ll_summary_section_jitter.getTop(); ViewTreeObserver observer = layout_ll_summary_section_jitter.getViewTreeObserver(); if (observer != null) { // http://stackoverflow.com/questions/15162821/why-does-removeongloballayoutlistener-throw-a-nosuchmethoderror try { if (Build.VERSION.SDK_INT >= 16) { observer.removeOnGlobalLayoutListener(this); } } catch (NoSuchMethodError x) { observer.removeGlobalOnLayoutListener(this); } } } }); // Get the width of the linear layout hosting the charts layout_ll_chart.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() { @Override public void onGlobalLayout() { ViewTreeObserver observer = layout_ll_chart.getViewTreeObserver(); if (observer != null) { // http://stackoverflow.com/questions/15162821/why-does-removeongloballayoutlistener-throw-a-nosuchmethoderror try { if (Build.VERSION.SDK_INT >= 16) { observer.removeOnGlobalLayoutListener(this); } } catch (NoSuchMethodError x) { observer.removeGlobalOnLayoutListener(this); } } } }); // Set the click listener for the download layout element (Download average and best result) if (SKApplication.getAppInstance().getRevealGraphFromSummary()) { layout_ll_summary_section_download.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { if (!aList_SummaryResults_No_Empty_For_Download) { Toast.makeText(context, getString(R.string.no_results_for_period_and_network), Toast.LENGTH_SHORT).show(); } else { // Disable click events to avoid side effects setLayoutsClickable(false); // If the rows are hidden (we are showing the graph) if (isListviewHidden) { // Hide the chart hide_ll_chart_download(); //hide_ll_chart_generic(layout_ll_summary_section_download); } // If all the rows are showed (we are not showing the graph) else { // Prepare chart for download test type prepareChartEnvironment(0, getTimePeriodSelection()); // Disable action bar filters hideNetworkAndTimePeriodMenuItems(); // Move out of the screen the other rows layout_ll_summary_section_upload.animate().x(-screenWidth).setDuration(300).alpha(0.0f).setInterpolator(null); layout_ll_summary_section_latency.animate().x(-screenWidth).setDuration(300).alpha(0.0f).setInterpolator(null); layout_ll_summary_section_jitter.animate().x(-screenWidth).setDuration(300).alpha(0.0f).setInterpolator(null); layout_ll_summary_section_packet_loss.animate().x(-screenWidth).setDuration(300).alpha(0.0f).setInterpolator(null).setListener(new AnimatorListenerAdapter() { // Enable click events on the rows when the animation ends. @Override public void onAnimationEnd(Animator animation) { super.onAnimationEnd(animation); // Enable click events setLayoutsClickable(true); // Show the chart mChartCaption.setAlpha(1.0F); layout_ll_chart.animate().setDuration(300).alpha(1.0f); layout_ll_chart.setVisibility(View.VISIBLE); mShowingThisSection = layout_ll_summary_section_download; // Change the value of the variable to the opposite. This is if we were showing the graphs set to not showing them and reverse. doUpdateToolbarSetIsListViewHidden(true); } }); } } } }); } // Set the click listener for the upload layout element (Upload average and best result) if (SKApplication.getAppInstance().getRevealGraphFromSummary()) { layout_ll_summary_section_upload.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { if (!aList_SummaryResults_No_Empty_For_Upload) { Toast.makeText(context, getString(R.string.no_results_for_period_and_network), Toast.LENGTH_SHORT).show(); } else { // Disable click events to avoid side effects setLayoutsClickable(false); // If the rows are hidden (we are showing the graph) if (isListviewHidden) { // Hide the chart hide_ll_chart_upload(); } // If all the rows are showed (we are not showing the graph) else { // Prepare chart for upload test type prepareChartEnvironment(1, getTimePeriodSelection()); // Disable action bar filters hideNetworkAndTimePeriodMenuItems(); // Move out of the screen the other rows layout_ll_summary_section_download.animate().x(-screenWidth).setDuration(300).alpha(0.0f).setInterpolator(null); layout_ll_summary_section_latency.animate().x(-screenWidth).setDuration(300).alpha(0.0f).setInterpolator(null); layout_ll_summary_section_jitter.animate().x(-screenWidth).setDuration(300).alpha(0.0f).setInterpolator(null); layout_ll_summary_section_packet_loss.animate().x(-screenWidth).setDuration(300).alpha(0.0f).setInterpolator(null).setListener(new AnimatorListenerAdapter() { // Executed at the end of the animation @Override public void onAnimationEnd(Animator animation) { super.onAnimationEnd(animation); layout_ll_summary_section_upload.animate().setDuration(300).x(headerPositionX).y(headerPositionY).setInterpolator(new OvershootInterpolator(1.2f)); // Delete the listener of the row to avoid side effects layout_ll_summary_section_packet_loss.animate().setListener(null); // Enable click events setLayoutsClickable(true); // Show the chart mChartCaption.setAlpha(1.0F); layout_ll_chart.animate().setDuration(300).alpha(1.0f); layout_ll_chart.setVisibility(View.VISIBLE); mShowingThisSection = layout_ll_summary_section_upload; // Change the value of the variable to the opposite. This is if we were showing the graphs set to not showing them and reverse. doUpdateToolbarSetIsListViewHidden(true); } }); } } } }); } // Set the click listener for the latency layout element (Latency average and best result) if (SKApplication.getAppInstance().getRevealGraphFromSummary()) { layout_ll_summary_section_latency.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { if (!aList_SummaryResults_No_Empty_For_Latency) { Toast.makeText(context, getString(R.string.no_results_for_period_and_network), Toast.LENGTH_SHORT).show(); } else { // Disable click events to avoid side effects setLayoutsClickable(false); // If the rows are hidden (we are showing the graph) if (isListviewHidden) { // Hide the chart hide_ll_chart_latency(); } // If all the rows are showed (we are not showing the graph) else { // Prepare chart for latency test type prepareChartEnvironment(2, getTimePeriodSelection()); // Disable action bar filters hideNetworkAndTimePeriodMenuItems(); // Move out of the screen the other rows layout_ll_summary_section_download.animate().x(-screenWidth).setDuration(300).alpha(0.0f).setInterpolator(null); layout_ll_summary_section_upload.animate().x(-screenWidth).setDuration(300).alpha(0.0f).setInterpolator(null); layout_ll_summary_section_jitter.animate().x(-screenWidth).setDuration(300).alpha(0.0f).setInterpolator(null); layout_ll_summary_section_packet_loss.animate().x(-screenWidth).setDuration(300).alpha(0.0f).setInterpolator(null).setListener(new AnimatorListenerAdapter() { // Executed at the end of the animation @Override public void onAnimationEnd(Animator animation) { super.onAnimationEnd(animation); layout_ll_summary_section_latency.animate().setDuration(300).x(headerPositionX).y(headerPositionY).setInterpolator(new OvershootInterpolator(1.2f)); layout_ll_summary_section_packet_loss.animate().setListener(null); // Delete the listener of the row to avoid side effects // Enable click events setLayoutsClickable(true); // Show the chart mChartCaption.setAlpha(1.0F); layout_ll_chart.animate().setDuration(300).alpha(1.0f); layout_ll_chart.setVisibility(View.VISIBLE); mShowingThisSection = layout_ll_summary_section_latency; doUpdateToolbarSetIsListViewHidden(true); } }); } // Change the value of the variable to the opposite. This is if we were showing the graphs set to not showing them and reverse. } } }); } // Set the click listener for the packet loss layout element (Packet loss average and best result) if (SKApplication.getAppInstance().getRevealGraphFromSummary()) { layout_ll_summary_section_packet_loss.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { if (!aList_SummaryResults_No_Empty_For_Packet_Loss) { Toast.makeText(context, getString(R.string.no_results_for_period_and_network), Toast.LENGTH_SHORT).show(); } else { // Disable click events to avoid side effects setLayoutsClickable(false); // If the rows are hidden (we are showing the graph) if (isListviewHidden) { // Hide the chart hide_ll_chart_packetloss(); } // If all the rows are showed (we are not showing the graph) else { // Prepare chart for packet loss test type prepareChartEnvironment(3, getTimePeriodSelection()); // Disable action bar filters hideNetworkAndTimePeriodMenuItems(); // Move out of the screen the other rows layout_ll_summary_section_download.animate().x(-screenWidth).setDuration(300).alpha(0.0f).setInterpolator(null); layout_ll_summary_section_upload.animate().x(-screenWidth).setDuration(300).alpha(0.0f).setInterpolator(null); layout_ll_summary_section_jitter.animate().x(-screenWidth).setDuration(300).alpha(0.0f).setInterpolator(null); layout_ll_summary_section_latency.animate().x(-screenWidth).setDuration(300).alpha(0.0f).setInterpolator(null).setListener(new AnimatorListenerAdapter() { // Executed at the end of the animation @Override public void onAnimationEnd(Animator animation) { layout_ll_summary_section_packet_loss.animate().setDuration(300).x(headerPositionX).y(headerPositionY).setInterpolator(new OvershootInterpolator(1.2f)); // Delete the listener of the row to avoid side effects layout_ll_summary_section_latency.animate().setListener(null); // Enable click events setLayoutsClickable(true); // Show the chart mChartCaption.setAlpha(1.0F); layout_ll_chart.animate().setDuration(300).alpha(1.0f); layout_ll_chart.setVisibility(View.VISIBLE); mShowingThisSection = layout_ll_summary_section_packet_loss; doUpdateToolbarSetIsListViewHidden(true); } }); } // Change the value of the variable to the opposite. This is if we were showing the graphs set to not showing them and reverse. } } }); } // Set the click listener for the jitter layout element (Jitter average and best result) if (SKApplication.getAppInstance().getRevealGraphFromSummary()) { layout_ll_summary_section_jitter.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { if (!aList_SummaryResults_No_Empty_For_Jitter) { Toast.makeText(context, getString(R.string.no_results_for_period_and_network), Toast.LENGTH_SHORT).show(); } else { // Disable click events to avoid side effects setLayoutsClickable(false); // If the rows are hidden (we are showing the graph) if (isListviewHidden) { // Hide the chart hide_ll_chart_jitter(); } // If all the rows are showed (we are not showing the graph) else { // Prepare chart for upload test type prepareChartEnvironment(4, getTimePeriodSelection()); // Disable action bar filters hideNetworkAndTimePeriodMenuItems(); // Move out of the screen the other rows layout_ll_summary_section_download.animate().x(-screenWidth).setDuration(300).alpha(0.0f).setInterpolator(null); layout_ll_summary_section_upload.animate().x(-screenWidth).setDuration(300).alpha(0.0f).setInterpolator(null); layout_ll_summary_section_latency.animate().x(-screenWidth).setDuration(300).alpha(0.0f).setInterpolator(null); layout_ll_summary_section_packet_loss.animate().x(-screenWidth).setDuration(300).alpha(0.0f).setInterpolator(null).setListener(new AnimatorListenerAdapter() { // Executed at the end of the animation @Override public void onAnimationEnd(Animator animation) { super.onAnimationEnd(animation); layout_ll_summary_section_jitter.animate().setDuration(300).x(headerPositionX).y(headerPositionY).setInterpolator(new OvershootInterpolator(1.2f)); // Delete the listener of the row to avoid side effects layout_ll_summary_section_packet_loss.animate().setListener(null); // Enable click events setLayoutsClickable(true); // Show the chart mChartCaption.setAlpha(1.0F); layout_ll_chart.animate().setDuration(300).alpha(1.0f); layout_ll_chart.setVisibility(View.VISIBLE); mShowingThisSection = layout_ll_summary_section_jitter; doUpdateToolbarSetIsListViewHidden(true); } }); } // Change the value of the variable to the opposite. This is if we were showing the graphs set to not showing them and reverse. } } }); } } private void graphsSetup(View pView) { //Trace.beginSection("graphsSetup"); graphContainer = (WebView) pView.findViewById(R.id.download_graph); // http://stackoverflow.com/questions/2527899/disable-scrolling-in-webview // disable scroll on touch graphContainer.setOnTouchListener(new View.OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { return (event.getAction() == MotionEvent.ACTION_MOVE); } }); final Context context = SKApplication.getAppInstance().getApplicationContext(); graphHandlerDownload = new SKGraphForResults(context, graphContainer, mChartCaption, "download"); //graphContainer.setBackgroundColor(Color.RED); // TODO - remove me, set transparent? //graphContainer.setBackgroundColor(Color.TRANSPARENT); // TODO - remove me, set transparent? } private SKGraphForResults graphHandlerDownload; private void setGraphDataForColumnIdAndHideIfNoResultsFound(DETAIL_TEST_ID PColumnId) { // Switch depending on the network type currently selected - this affects the underlying query. switch (getNetworkTypeSelection()) { case eNetworkTypeResults_Any: SKApplication.setNetworkTypeResults(eNetworkTypeResults.eNetworkTypeResults_Any); break; case eNetworkTypeResults_WiFi: SKApplication.setNetworkTypeResults(eNetworkTypeResults.eNetworkTypeResults_WiFi); break; case eNetworkTypeResults_Mobile: SKApplication.setNetworkTypeResults(eNetworkTypeResults.eNetworkTypeResults_Mobile); break; default: SKPorting.sAssert(getClass(), false); break; } JSONObject data = null; //try { data = fetchGraphDataForColumnId(PColumnId); //} catch (JSONException e1) { //} // When using achartengine, the background CANNOT be TRANSPARENT. // Otherwise, the fill area *below the y axis* will be filled with the fill colour - which is ugly! graphHandlerDownload.updateGraphWithTheseResults(data, mDateRange, sGetGraphColourBackground(), sGetGraphColourTopAreaFill()); //graphHandlerDownload.updateGraphWithTheseResults(data, mDateRange); } public static int sGetSamKnowsBlue() { // "#009fe3" return Color.rgb(0, 159, 227); } public static int sGetGraphColourBackground() { return SKApplication.getAppInstance().getApplicationContext().getResources().getColor(R.color.GraphColourBackground); } public static int sGetGraphColourAverageFill() { return SKApplication.getAppInstance().getApplicationContext().getResources().getColor(R.color.GraphColourTopAreaFill); } public static int sGetGraphColourTopAreaFill() { return SKApplication.getAppInstance().getApplicationContext().getResources().getColor(R.color.GraphColourTopAreaFill); } public static int sGetGraphColourBottomAreaFill() { return SKApplication.getAppInstance().getApplicationContext().getResources().getColor(R.color.GraphColourBottomAreaFill); } private JSONObject fetchGraphDataForColumnId(DETAIL_TEST_ID PColumnId) { Calendar fromCal = Calendar.getInstance(); lookBackwardInTime(fromCal); long startTime = fromCal.getTimeInMillis(); Calendar upToCal = Calendar.getInstance(); long upToTime = upToCal.getTimeInMillis(); if (!(startTime < upToTime)) { Log.e(this.getClass().toString(), "getDataForColumnId - startTime/upToTime out of range mis-matched"); } JSONObject data = dbHelper.fetchGraphData(PColumnId, startTime, upToTime, mDateRange); return data; } private DATERANGE_1w1m3m1y mDateRange = DATERANGE_1w1m3m1y.DATERANGE_1w1m3m1y_ONE_WEEK; private DATERANGE_1w1m3m1y convertDataPeriodToDateRange(int pDataPeriod) { switch (pDataPeriod) { // 1 Day case 0: return DATERANGE_1w1m3m1y.DATERANGE_1w1m3m1y_ONE_DAY; // 1 Week case 1: return DATERANGE_1w1m3m1y.DATERANGE_1w1m3m1y_ONE_WEEK; // 1 Month case 2: return DATERANGE_1w1m3m1y.DATERANGE_1w1m3m1y_ONE_MONTH; // 3 Months case 3: return DATERANGE_1w1m3m1y.DATERANGE_1w1m3m1y_THREE_MONTHS; // 1 Year case 4: return DATERANGE_1w1m3m1y.DATERANGE_1w1m3m1y_ONE_YEAR; // Default: 1 Week default: SKPorting.sAssert(getClass(), false); return DATERANGE_1w1m3m1y.DATERANGE_1w1m3m1y_ONE_WEEK; } } private void lookBackwardInTime(Calendar fromCal) { // Convert the "new app" time period, into a usable enumerated value. int dataPeriod = getTimePeriodSelection(); mDateRange = convertDataPeriodToDateRange(dataPeriod); switch (mDateRange) { case DATERANGE_1w1m3m1y_ONE_DAY: fromCal.add(Calendar.DAY_OF_YEAR, -1); break; case DATERANGE_1w1m3m1y_ONE_WEEK: fromCal.add(Calendar.WEEK_OF_YEAR, -1); break; case DATERANGE_1w1m3m1y_ONE_MONTH: fromCal.add(Calendar.WEEK_OF_YEAR, -4); break; case DATERANGE_1w1m3m1y_THREE_MONTHS: fromCal.add(Calendar.WEEK_OF_YEAR, -12); break; case DATERANGE_1w1m3m1y_ONE_YEAR: fromCal.add(Calendar.WEEK_OF_YEAR, -52); break; default: SKPorting.sAssert(getClass(), false); fromCal.add(Calendar.WEEK_OF_YEAR, -1); break; } } private void setNetworkTypeButtonText() { String text = ""; switch(getNetworkTypeSelection()) { case eNetworkTypeResults_Any: text = getString(R.string.network_type_all); break; case eNetworkTypeResults_Mobile: text = getString(R.string.network_type_mobile); break; case eNetworkTypeResults_WiFi: text = getString(R.string.network_type_wifi); break; default: SKPorting.sAssert(false); text = getString(R.string.network_type_all); break; } mSummaryFilterButton.setText(text); } private void setTimePeriodButtonText() { String text = ""; switch(getTimePeriodSelection()) { // 1 Day case 0: text = getString(R.string.time_period_1_day); // DATERANGE_1w1m3m1y.DATERANGE_1w1m3m1y_ONE_DAY; break; // 1 Week case 1: text = getString(R.string.time_period_1_week); // DATERANGE_1w1m3m1y.DATERANGE_1w1m3m1y_ONE_WEEK; break; // 1 Month case 2: text = getString(R.string.time_period_1_month); // DATERANGE_1w1m3m1y.DATERANGE_1w1m3m1y_ONE_MONTH; break; // 3 Months case 3: text = getString(R.string.time_period_3_months); // DATERANGE_1w1m3m1y.DATERANGE_1w1m3m1y_THREE_MONTHS; break; // 1 Year case 4: text = getString(R.string.time_period_1_year); // DATERANGE_1w1m3m1y.DATERANGE_1w1m3m1y_ONE_YEAR; break; // Default: 1 Week default: SKPorting.sAssert(getClass(), false); text = getString(R.string.time_period_1_week); // DATERANGE_1w1m3m1y.DATERANGE_1w1m3m1y_ONE_WEEK; break; } mSummaryTimePeriodButton.setText(text); } /** * Save the state of the network type filter in shared preferences * * @param pNetworkType is the network type value stored in shared preferences for the Summary fragment */ private void saveNetworkTypeSelection(eNetworkTypeResults pNetworkType) // 0 wifi, 1 mobile { // Get shared preferences editor final Context context = SKApplication.getAppInstance().getApplicationContext(); SharedPreferences.Editor editor = context.getSharedPreferences(getString(R.string.sharedPreferencesIdentifier), Context.MODE_PRIVATE).edit(); switch (pNetworkType) { case eNetworkTypeResults_Any: editor.putInt("networkTypeSummary", 0); // Save the state of network type filter break; case eNetworkTypeResults_WiFi: editor.putInt("networkTypeSummary", 1); // Save the state of network type filter break; case eNetworkTypeResults_Mobile: editor.putInt("networkTypeSummary", 2); // Save the state of network type filter break; default: SKPorting.sAssert(getClass(), false); break; } editor.commit(); // Commit changes // Verify that the value was saved properly. SKPorting.sAssert(getClass(), getNetworkTypeSelection() == pNetworkType); setNetworkTypeButtonText(); } /** * Get the state of the network type filter from shared preferences. 0 is All, 1 is Wifi and 2 is mobile. * * @return networkTypeSummary is the value stored in shared preferences for the network type in the Summary fragment */ private eNetworkTypeResults getNetworkTypeSelection() // 0 wifi, 1 mobile { // Get the shared preferences final Context context = SKApplication.getAppInstance().getApplicationContext(); SharedPreferences prefs = context.getSharedPreferences(getString(R.string.sharedPreferencesIdentifier), Context.MODE_PRIVATE); int networkTypeFromPreferences = prefs.getInt("networkTypeSummary", 0); // Return the state of network type selection switch (networkTypeFromPreferences) { case 0: return eNetworkTypeResults.eNetworkTypeResults_Any; case 1: return eNetworkTypeResults.eNetworkTypeResults_WiFi; case 2: return eNetworkTypeResults.eNetworkTypeResults_Mobile; default: SKPorting.sAssert(getClass(), false); return eNetworkTypeResults.eNetworkTypeResults_WiFi; } } /** * Save the state of the time period filter in shared preferences * * @param pTimePeriod is the value stored in shared preferences for the time period in the Summary fragment */ private void saveTimePeriodSelection(int pTimePeriod) { // Get the shared preferences editor final Context context = SKApplication.getAppInstance().getApplicationContext(); SharedPreferences.Editor editor = context.getSharedPreferences(getString(R.string.sharedPreferencesIdentifier), Context.MODE_PRIVATE).edit(); editor.putInt("timePeriodSummary", pTimePeriod); // Save the state of the time period filter editor.commit(); // Commit changes setTimePeriodButtonText(); } /** * Get the state of the network type filter from shared preferences * * @return timePeriodSummary is the value stored in shared preferences for the time period in the Summary fragment */ private int getTimePeriodSelection() { // Get the shared preferences final Context context = SKApplication.getAppInstance().getApplicationContext(); SharedPreferences prefs = context.getSharedPreferences(getString(R.string.sharedPreferencesIdentifier), Context.MODE_PRIVATE); // Return the state of the time period selection. The default value is 4 (1 week) return prefs.getInt("timePeriodSummary", 4); } /** * Calculate the initial date of the period of time in milliseconds * * @return the time in milliseconds equals to the current time minus the time passed as parameter */ private long calculateTimePeriodStart() { Calendar fromCal = Calendar.getInstance(); lookBackwardInTime(fromCal); long startTime = fromCal.getTimeInMillis(); return startTime; } /** * Set the linear layouts clickable property to true or false. This is to disable click events while transitions are happening in the screen. * * @param pClickable that is true or false */ private void setLayoutsClickable(boolean pClickable) { layout_ll_summary_section_download.setClickable(pClickable); layout_ll_summary_section_upload.setClickable(pClickable); layout_ll_summary_section_latency.setClickable(pClickable); layout_ll_summary_section_packet_loss.setClickable(pClickable); layout_ll_summary_section_jitter.setClickable(pClickable); } /** * Prepare the chart for the selected test type * * @param pChartType * @param pDataPeriod */ private void prepareChartEnvironment(int pChartType, int pDataPeriod) { // Prepare data for the download chart DETAIL_TEST_ID chartType = DETAIL_TEST_ID.DOWNLOAD_TEST_ID; switch (pChartType) { case 0: // Case download chartType = DETAIL_TEST_ID.DOWNLOAD_TEST_ID; mChartCaption.setText(R.string.units_Mbps); break; case 1: // Case upload chartType = DETAIL_TEST_ID.UPLOAD_TEST_ID; mChartCaption.setText(R.string.units_Mbps); break; case 2: // Case latency chartType = DETAIL_TEST_ID.LATENCY_TEST_ID; mChartCaption.setText(R.string.units_ms); break; case 3: // Case packet loss chartType = DETAIL_TEST_ID.PACKETLOSS_TEST_ID; mChartCaption.setText(R.string.units_percent); break; case 4: // Case jitter chartType = DETAIL_TEST_ID.JITTER_TEST_ID; mChartCaption.setText(R.string.units_percent); break; default: SKPorting.sAssert(getClass(), false); } setGraphDataForColumnIdAndHideIfNoResultsFound(chartType); } /** * Set the possibility of display the charts true or false * * @param pAvailable that is true or false */ private void chartsAvailable(boolean pAvailable) { layout_ll_summary_section_download.setClickable(pAvailable); layout_ll_summary_section_upload.setClickable(pAvailable); layout_ll_summary_section_latency.setClickable(pAvailable); layout_ll_summary_section_packet_loss.setClickable(pAvailable); layout_ll_summary_section_jitter.setClickable(pAvailable); } private void hideNetworkAndTimePeriodMenuItems() { if (menu_item_selectNetworkType != null) { menu_item_selectNetworkType.setVisible(false); } if (menu_Item_Select_Time_Period != null) { menu_Item_Select_Time_Period.setVisible(false); } } // *** MENUS *** // // Initialise the contents of the Activity's standard options menu. // You should place your menu items in to menu. For this method to be called, you must have first called setHasOptionsMenu(boolean). @Override public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { inflater.inflate(R.menu.menu_fragment_summary, menu); super.onCreateOptionsMenu(menu, inflater); // Identify the action bar menu filters menu_item_selectNetworkType = menu.findItem(R.id.menu_item_fragment_summary_select_network); menu_Item_Select_Time_Period = menu.findItem(R.id.menu_item_fragment_summary_select_time_period); // Identify and initialise the refresh spinner in the action bar menu_Item_Refresh_Spinner = menu.findItem(R.id.menu_item_fragment_summary_refreshSpinner); menu_Item_Refresh_Spinner.setVisible(asyncTask_RetrieveData_Running || asyncTask_PrepareChart_Running); menu_Item_Refresh_Spinner.setActionView(R.layout.actionbar_indeterminate_progress); // If the rows are hidden, hide the menu filters if (isListviewHidden) { hideNetworkAndTimePeriodMenuItems(); } } private void showSelectNetwork() { Intent intent_select_network = new Intent(getActivity(), ActivitySelectNetworkType.class); // Intent launching the activity to select the network type intent_select_network.putExtra("currentFragment", 2); // Set the current fragment. This will determine the background of the activity startActivityForResult(intent_select_network, 0); // Activity is started with requestCode 0 } private void showSelectTimePeriod() { Intent intent_select_time_period = new Intent(getActivity(), ActivitySelectTimePeriod.class); // Intent launching the activity to select the time period intent_select_time_period.putExtra("currentFragment", 2); // Set the current fragment. This will determine the background of the activity startActivityForResult(intent_select_time_period, 1); // Activity is started with requestCode 1 } // This hook is called whenever an item in your options menu is selected @Override public boolean onOptionsItemSelected(MenuItem item) { int itemId = item.getItemId(); if (itemId == R.id.menu_item_fragment_summary_select_network) { // Case select network showSelectNetwork(); return true; } if (itemId == R.id.menu_item_fragment_summary_select_time_period) { // Case select time period showSelectTimePeriod(); return true; } // Default case return true; } }