diff --git a/app/src/main/java/org/projectbuendia/client/sync/ChartDataHelper.java b/app/src/main/java/org/projectbuendia/client/sync/ChartDataHelper.java index 56576725..ec04a7cf 100644 --- a/app/src/main/java/org/projectbuendia/client/sync/ChartDataHelper.java +++ b/app/src/main/java/org/projectbuendia/client/sync/ChartDataHelper.java @@ -303,9 +303,11 @@ public Map getLatestObservationsForConcept( public List getCharts(String uuid) { Map tileGroupsById = new HashMap<>(); Map rowGroupsById = new HashMap<>(); - List Charts = new ArrayList<>(); + List charts = new ArrayList<>(); Chart currentChart = null; + LOG.start("ChartDataHelper.getCharts"); + try (Cursor c = mContentResolver.query( ChartItems.CONTENT_URI, null, ChartItems.CHART_UUID + " = ?", new String[] {uuid}, "weight")) { @@ -322,7 +324,7 @@ public List getCharts(String uuid) { if ((currentChart != null) && ((currentChart.tileGroups.size() != 0) || (currentChart.rowGroups.size() != 0))) { - Charts.add(currentChart); + charts.add(currentChart); } break; case "TILE_ROW": @@ -361,8 +363,10 @@ public List getCharts(String uuid) { } } } - Charts.add(currentChart); - return Charts; + + LOG.finish("ChartDataHelper.getCharts"); + charts.add(currentChart); + return charts; } public List
getForms() { diff --git a/app/src/main/java/org/projectbuendia/client/ui/chart/ChartRenderer.java b/app/src/main/java/org/projectbuendia/client/ui/chart/ChartRenderer.java index b631554a..29074116 100644 --- a/app/src/main/java/org/projectbuendia/client/ui/chart/ChartRenderer.java +++ b/app/src/main/java/org/projectbuendia/client/ui/chart/ChartRenderer.java @@ -42,6 +42,7 @@ import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.Set; import java.util.SortedMap; import java.util.SortedSet; @@ -64,14 +65,18 @@ public class ChartRenderer { private static final Logger LOG = Logger.create(); private static final ExecutionHistory EMPTY_HISTORY = new ExecutionHistory(); - private WebView mView; // view into which the HTML table will be rendered - private Resources mResources; // resources used for localizing the rendering + private Resources mResources; private AppSettings mSettings; - private List mLastRenderedObs; // last set of observations rendered - private List mLastRenderedOrders; // last set of orders rendered - private int mLastRenderedZoomIndex; // last zoom level index rendered - private String mLastChartName = ""; + private int mLastZoomIndex; // last zoom level index rendered + private String mLastChartName = ""; // last selected chart rendered + private List mLastObservations; // last set of observations rendered + private List mLastOrders; // last set of orders rendered + private LocalDate mLastAdmissionDate; // last admission date rendered + private LocalDate mLastFirstSymptomsDate; // last first-symptoms date rendered + + private String mLastHtml = null; // last HTML output of renderer + private WebView mLastView = null; // last WebView that was rendered into public interface JsInterface { @JavascriptInterface void onNewOrderPressed(); @@ -85,77 +90,88 @@ public interface JsInterface { @JavascriptInterface void onPageUnload(int scrollX, int scrollY); } - public ChartRenderer(WebView view, Resources resources, AppSettings settings) { - mView = view; + public ChartRenderer(Resources resources, AppSettings settings) { mResources = resources; mSettings = settings; - mView.getSettings().setRenderPriority(WebSettings.RenderPriority.HIGH); - mView.getSettings().setCacheMode(WebSettings.LOAD_NO_CACHE); - mView.setLayerType(View.LAYER_TYPE_HARDWARE, null); } /** Renders a patient's history of observations to an HTML table in the WebView. */ // TODO/cleanup: Have this take the types that getObservations and getLatestObservations return. - public void render(Chart chart, Map latestObservations, + public void render(WebView view, Chart chart, Map latestObservations, List observations, List orders, LocalDate admissionDate, LocalDate firstSymptomsDate, JsInterface controllerInterface) { if (chart == null) { - mView.loadUrl("file:///android_asset/no_chart.html"); + view.loadUrl("file:///android_asset/no_chart.html"); return; } + + String html; LOG.i("Rendering %d observations, %d orders, zoom index %d", observations.size(), orders.size(), mSettings.getChartZoomIndex()); - if (mLastChartName.equals(chart.name) && - mLastRenderedZoomIndex == mSettings.getChartZoomIndex() && - observations.equals(mLastRenderedObs) && - orders.equals(mLastRenderedOrders)) { - LOG.i("Data and zoom index have not changed; skipping render"); - return; + LOG.start("render"); + if (mSettings.getChartZoomIndex() == mLastZoomIndex && + Objects.equals(chart.name, mLastChartName) && + Objects.equals(observations, mLastObservations) && + Objects.equals(orders, mLastOrders) && + Objects.equals(admissionDate, mLastAdmissionDate) && + Objects.equals(firstSymptomsDate, mLastFirstSymptomsDate) && + mLastHtml != null) { + LOG.i("Data and zoom index have not changed; skipping HTML generation"); + html = mLastHtml; + } else { + html = new GridHtmlGenerator( + chart, latestObservations, observations, orders, + admissionDate, firstSymptomsDate).getHtml(); + LOG.elapsed("render", "HTML generated"); } - LOG.start("render"); + if (view != mLastView) { + view.getSettings().setRenderPriority(WebSettings.RenderPriority.HIGH); + view.getSettings().setCacheMode(WebSettings.LOAD_NO_CACHE); + view.setLayerType(View.LAYER_TYPE_HARDWARE, null); + view.getSettings().setJavaScriptEnabled(true); + view.setWebChromeClient(new WebChromeClient()); + } // setDefaultFontSize is supposed to take a size in sp, but in practice // the fonts don't change size when the user font size preference changes. // So, we apply the scaling factor explicitly, defining 1 em to be 10 sp. DisplayMetrics metrics = mResources.getDisplayMetrics(); - float defaultFontSize = 10*metrics.scaledDensity/metrics.density; - mView.getSettings().setDefaultFontSize((int) defaultFontSize); - - mView.getSettings().setJavaScriptEnabled(true); - mView.addJavascriptInterface(controllerInterface, "controller"); - mView.setWebChromeClient(new WebChromeClient()); - String html = new GridHtmlGenerator( - chart, latestObservations, observations, orders, - admissionDate, firstSymptomsDate).getHtml(); - - LOG.elapsed("render", "HTML generated"); + float defaultFontSize = 10 * metrics.scaledDensity / metrics.density; + view.getSettings().setDefaultFontSize((int) defaultFontSize); + view.removeJavascriptInterface("controller"); + view.addJavascriptInterface(controllerInterface, "controller"); + LOG.elapsed("render", "WebView configured"); + + if (view == mLastView && html.equals(mLastHtml)) { + LOG.i("HTML and view are unchanged; skipping page load"); + LOG.finish("render"); + return; + } // To avoid showing stale, possibly misleading data from a previous // patient, clear out any previous chart HTML before showing the WebView. - mView.loadUrl("about:blank"); - mView.clearView(); - mView.setVisibility(View.VISIBLE); - mView.loadDataWithBaseURL( + view.loadUrl("about:blank"); + view.clearView(); + view.setVisibility(View.VISIBLE); + view.loadDataWithBaseURL( "file:///android_asset/", html, "text/html; charset=utf-8", "utf-8", null); - mView.setWebContentsDebuggingEnabled(true); + view.setWebContentsDebuggingEnabled(true); - LOG.finish("render", "HTML loaded into WebView"); + LOG.elapsed("render", "HTML page loaded into WebView"); + mLastZoomIndex = mSettings.getChartZoomIndex(); mLastChartName = chart.name; - mLastRenderedZoomIndex = mSettings.getChartZoomIndex(); - mLastRenderedObs = observations; - mLastRenderedOrders = orders; + mLastObservations = observations; + mLastOrders = orders; + mLastAdmissionDate = admissionDate; + mLastFirstSymptomsDate = firstSymptomsDate; + mLastHtml = html; + mLastView = view; LOG.start("ChartJS"); } - /** Gets the starting times (in ms) of the segments into which the day is divided. */ - public int[] getSegmentStartTimes() { - int index = mSettings.getChartZoomIndex(); - return Utils.safeIndex(ZOOM_LEVELS, index).segmentStartTimes; - } - class GridHtmlGenerator { List mOrders; DateTime mNow; @@ -254,6 +270,12 @@ void addOrders(List orders) { } } + /** Gets the starting times (in ms) of the segments into which the day is divided. */ + public int[] getSegmentStartTimes() { + int index = mSettings.getChartZoomIndex(); + return Utils.safeIndex(ZOOM_LEVELS, index).segmentStartTimes; + } + /** Gets the n + 1 boundaries of the n segments of a specific day. */ public DateTime[] getSegmentFenceposts(LocalDate date) { DateTime start = date.toDateTimeAtStartOfDay(); diff --git a/app/src/main/java/org/projectbuendia/client/ui/chart/PatientChartActivity.java b/app/src/main/java/org/projectbuendia/client/ui/chart/PatientChartActivity.java index e8e97d08..c466a463 100644 --- a/app/src/main/java/org/projectbuendia/client/ui/chart/PatientChartActivity.java +++ b/app/src/main/java/org/projectbuendia/client/ui/chart/PatientChartActivity.java @@ -97,7 +97,6 @@ public final class PatientChartActivity extends BaseLoggedInActivity { private boolean mIsFetchingXform = false; private ProgressDialog mFormLoadingDialog; private ProgressDialog mFormSubmissionDialog; - private ChartRenderer mChartRenderer; private ProgressDialog mProgressDialog; private DatePickerDialog mAdmissionDateDialog; private DatePickerDialog mSymptomOnsetDateDialog; @@ -114,8 +113,9 @@ public final class PatientChartActivity extends BaseLoggedInActivity { @InjectView(R.id.attribute_symptoms_onset_days) PatientAttributeView mSymptomOnsetDaysView; @InjectView(R.id.attribute_pcr) PatientAttributeView mPcr; @InjectView(R.id.patient_chart_pregnant) TextView mPatientPregnantOrIvView; - @InjectView(R.id.chart_webview) WebView mGridWebView; + @InjectView(R.id.chart_webview) WebView mWebView; + private static ChartRenderer sChartRenderer; private static final String EN_DASH = "\u2013"; public static void start(Context caller, String uuid) { @@ -206,7 +206,7 @@ public static void start(Context caller, String uuid) { R.string.symptoms_onset_date_picker_title, ConceptUuids.FIRST_SYMPTOM_DATE_UUID); // Remembering scroll position and applying it after the chart finished loading. - mGridWebView.setWebViewClient(new WebViewClient() { + mWebView.setWebViewClient(new WebViewClient() { public void onPageFinished(WebView view, String url) { Point scrollPosition = mController.getLastScrollPosition(); if (scrollPosition != null) { @@ -215,7 +215,10 @@ public void onPageFinished(WebView view, String url) { } } }); - mChartRenderer = new ChartRenderer(mGridWebView, getResources(), mSettings); + + if (sChartRenderer == null) { + sChartRenderer = new ChartRenderer(getResources(), mSettings); + } final OdkResultSender odkResultSender = new OdkResultSender() { @Override public void sendOdkResultToServer(String patientUuid, int resultCode, Intent data) { @@ -274,9 +277,10 @@ public void onPageFinished(WebView view, String url) { @Override protected void onNewIntent(Intent intent) { String uuid = intent.getStringExtra("uuid"); if (uuid != null) { + setIntent(intent); // Immediately hide the current patient chart, to avoid giving the // misleading impression that it applies to the new patient. - mGridWebView.setVisibility(View.INVISIBLE); + mWebView.setVisibility(View.INVISIBLE); mController.setPatient(uuid); } } @@ -511,7 +515,7 @@ private final class Ui implements PatientChartController.Ui { List orders, LocalDate admissionDate, LocalDate firstSymptomsDate) { - mChartRenderer.render(chart, latestObservations, observations, orders, + sChartRenderer.render(mWebView, chart, latestObservations, observations, orders, admissionDate, firstSymptomsDate, mController); mRootView.invalidate(); } diff --git a/app/src/main/java/org/projectbuendia/client/ui/chart/PatientChartController.java b/app/src/main/java/org/projectbuendia/client/ui/chart/PatientChartController.java index cbfcc33f..a192f53b 100644 --- a/app/src/main/java/org/projectbuendia/client/ui/chart/PatientChartController.java +++ b/app/src/main/java/org/projectbuendia/client/ui/chart/PatientChartController.java @@ -459,6 +459,7 @@ else if (!startMillis.isEmpty()){ @JavascriptInterface public void finish() { LOG.finish("ChartJS"); + LOG.finish("render"); } public void setDate(String conceptUuid, LocalDate date) {