/** * */ package org.commcare.android.view; import java.util.Hashtable; import org.commcare.android.javarosa.AndroidLogger; import org.commcare.android.models.Entity; import org.commcare.android.util.DetailCalloutListener; import org.commcare.android.util.FileUtil; import org.commcare.android.util.MediaUtil; import org.commcare.dalvik.R; import org.commcare.suite.model.Detail; import org.commcare.suite.model.graph.GraphData; import org.commcare.util.CommCareSession; import org.javarosa.core.reference.InvalidReferenceException; import org.javarosa.core.reference.ReferenceManager; import org.javarosa.core.services.Logger; import org.odk.collect.android.views.media.AudioButton; import org.odk.collect.android.views.media.AudioController; import org.odk.collect.android.views.media.ViewId; import android.content.Context; import android.content.Intent; import android.graphics.Bitmap; import android.view.Display; import android.view.GestureDetector; import android.view.MotionEvent; import android.view.View; import android.view.ViewGroup; import android.view.WindowManager; import android.widget.Button; import android.widget.FrameLayout; import android.widget.ImageButton; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.TextView; /** * @author ctsims * */ public class EntityDetailView extends FrameLayout { private TextView label; private TextView data; private TextView spacer; private Button callout; private View addressView; private Button addressButton; private TextView addressText; private ImageView imageView; private AspectRatioLayout graphLayout; private Hashtable<Integer, Hashtable<Integer, View>> graphViewsCache; // index => { orientation => GraphView } private Hashtable<Integer, Intent> graphIntentsCache; // index => intent private ImageButton videoButton; private AudioButton audioButton; private View valuePane; private View currentView; private AudioController controller; private LinearLayout detailRow; private LinearLayout.LayoutParams origValue; private LinearLayout.LayoutParams origLabel; private LinearLayout.LayoutParams fill; private static final String FORM_VIDEO = MediaUtil.FORM_VIDEO; private static final String FORM_AUDIO = MediaUtil.FORM_AUDIO; private static final String FORM_PHONE = "phone"; private static final String FORM_ADDRESS = "address"; private static final String FORM_IMAGE = MediaUtil.FORM_IMAGE; private static final String FORM_GRAPH = "graph"; private static final int TEXT = 0; private static final int PHONE = 1; private static final int ADDRESS = 2; private static final int IMAGE = 3; private static final int VIDEO = 4; private static final int AUDIO = 5; private static final int GRAPH = 6; int current = TEXT; DetailCalloutListener listener; public EntityDetailView(Context context, CommCareSession session, Detail d, Entity e, int index, AudioController controller, int detailNumber) { super(context); this.controller = controller; detailRow = (LinearLayout)View.inflate(context, R.layout.component_entity_detail_item, null); label = (TextView)detailRow.findViewById(R.id.detail_type_text); spacer = (TextView)detailRow.findViewById(R.id.entity_detail_spacer); data = (TextView)detailRow.findViewById(R.id.detail_value_text); currentView = data; valuePane = detailRow.findViewById(R.id.detail_value_pane); videoButton = (ImageButton)detailRow.findViewById(R.id.detail_video_button); ViewId uniqueId = new ViewId(detailNumber, index, true); String audioText = e.getFieldString(index); audioButton = new AudioButton(context, audioText, uniqueId, controller, false); detailRow.addView(audioButton); audioButton.setVisibility(View.GONE); callout = (Button)detailRow.findViewById(R.id.detail_value_phone); //TODO: Still useful? //callout.setInputType(InputType.TYPE_CLASS_PHONE); addressView = (View)detailRow.findViewById(R.id.detail_address_view); addressText = (TextView)addressView.findViewById(R.id.detail_address_text); addressButton = (Button)addressView.findViewById(R.id.detail_address_button); imageView = (ImageView)detailRow.findViewById(R.id.detail_value_image); graphLayout = (AspectRatioLayout)detailRow.findViewById(R.id.graph); graphViewsCache = new Hashtable<Integer, Hashtable<Integer, View>>(); graphIntentsCache = new Hashtable<Integer, Intent>(); origLabel = (LinearLayout.LayoutParams)label.getLayoutParams(); origValue = (LinearLayout.LayoutParams)valuePane.getLayoutParams(); fill = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.FILL_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT); this.addView(detailRow, FrameLayout.LayoutParams.FILL_PARENT, FrameLayout.LayoutParams.WRAP_CONTENT); setParams(session, d, e, index, detailNumber); } public void setCallListener(final DetailCalloutListener listener) { this.listener = listener; } public void setParams(CommCareSession session, Detail d, Entity e, int index, int detailNumber) { String labelText = d.getFields()[index].getHeader().evaluate(); label.setText(labelText); spacer.setText(labelText); Object field = e.getField(index); String textField = e.getFieldString(index); boolean veryLong = false; String form = d.getTemplateForms()[index]; if(FORM_PHONE.equals(form)) { callout.setText(textField); if(current != PHONE) { callout.setOnClickListener(new OnClickListener() { public void onClick(View v) { listener.callRequested(callout.getText().toString()); } }); this.removeView(currentView); updateCurrentView(PHONE, callout); } } else if(FORM_ADDRESS.equals(form)) { final String address = textField; addressText.setText(address); if(current != ADDRESS) { addressButton.setOnClickListener(new OnClickListener() { public void onClick(View v) { listener.addressRequested(MediaUtil.getGeoIntentURI(address)); } }); updateCurrentView(ADDRESS, addressView); } } else if(FORM_IMAGE.equals(form)) { String imageLocation = textField; Bitmap b = MediaUtil.getScaledImageFromReference(imageLocation); if(b == null) { imageView.setImageDrawable(null); } else { //Ok, so. We should figure out whether our image is large or small. if(b.getWidth() > (getScreenWidth() / 2)) { veryLong = true; } imageView.setPadding(10, 10, 10, 10); imageView.setAdjustViewBounds(true); imageView.setImageBitmap(b); imageView.setId(23422634); } updateCurrentView(IMAGE, imageView); } else if (FORM_GRAPH.equals(form) && field instanceof GraphData) { // if graph parsing had errors, they'll be stored as a string // Fetch graph view from cache, or create it View graphView = null; int orientation = getResources().getConfiguration().orientation; if (graphViewsCache.get(index) != null) { graphView = graphViewsCache.get(index).get(orientation); } else { graphViewsCache.put(index, new Hashtable<Integer, View>()); } if (graphView == null) { GraphView g = new GraphView(getContext(), labelText); g.setClickable(true); graphView = g.getView((GraphData) field); graphViewsCache.get(index).put(orientation, graphView); } // Fetch full-screen graph intent from cache, or create it Intent graphIntent = graphIntentsCache.get(index); final Context context = getContext(); if (graphIntent == null) { GraphView g = new GraphView(context, labelText); graphIntent = g.getIntent((GraphData) field); graphIntentsCache.put(index, graphIntent); } final Intent finalIntent = graphIntent; // Open full-screen graph intent on double tap final GestureDetector detector = new GestureDetector(context, new GestureDetector.SimpleOnGestureListener() { @Override public boolean onDown(MotionEvent e) { return true; } @Override public boolean onDoubleTap(MotionEvent e) { context.startActivity(finalIntent); return true; } }); graphView.setOnTouchListener(new OnTouchListener() { @Override public boolean onTouch(View view, MotionEvent event) { return detector.onTouchEvent(event); } }); graphLayout.removeAllViews(); graphLayout.addView(graphView, GraphView.getLayoutParams()); if (current != GRAPH) { // Hide field label and expand value to take up full screen width LinearLayout.LayoutParams graphValueLayout = new LinearLayout.LayoutParams((ViewGroup.LayoutParams)origValue); graphValueLayout.weight = 10; valuePane.setLayoutParams(graphValueLayout); label.setVisibility(View.GONE); data.setVisibility(View.GONE); updateCurrentView(GRAPH, graphLayout); } } else if (FORM_AUDIO.equals(form)) { ViewId uniqueId = new ViewId(detailNumber, index, true); audioButton.modifyButtonForNewView(uniqueId, textField, true); updateCurrentView(AUDIO, audioButton); } else if(FORM_VIDEO.equals(form)) { //TODO: Why is this given a special string? String videoLocation = textField; String localLocation = null; try{ localLocation = ReferenceManager._().DeriveReference(videoLocation).getLocalURI(); if(localLocation.startsWith("/")) { //TODO: This should likely actually be happening with the getLocalURI _anyway_. localLocation = FileUtil.getGlobalStringUri(localLocation); } } catch(InvalidReferenceException ire) { Logger.log(AndroidLogger.TYPE_ERROR_CONFIG_STRUCTURE, "Couldn't understand video reference format: " + localLocation + ". Error: " + ire.getMessage()); } final String location = localLocation; videoButton.setOnClickListener(new OnClickListener() { public void onClick(View v) { listener.playVideo(location); } }); if(location == null) { videoButton.setEnabled(false); Logger.log(AndroidLogger.TYPE_ERROR_CONFIG_STRUCTURE, "No local video reference available for ref: " + videoLocation); } else { videoButton.setEnabled(true); } updateCurrentView(VIDEO, videoButton); } else { String text = textField; data.setText(text); if(text != null && text.length() > this.getContext().getResources().getInteger(R.integer.detail_size_cutoff)) { veryLong = true; } updateCurrentView(TEXT, data); } if(veryLong) { detailRow.setOrientation(LinearLayout.VERTICAL); spacer.setVisibility(View.GONE); label.setLayoutParams(fill); valuePane.setLayoutParams(fill); } else { if(detailRow.getOrientation() != LinearLayout.HORIZONTAL) { detailRow.setOrientation(LinearLayout.HORIZONTAL); spacer.setVisibility(View.INVISIBLE); label.setLayoutParams(origLabel); valuePane.setLayoutParams(origValue); } } } /* * Appropriately set current & currentView. */ private void updateCurrentView(int newCurrent, View newView) { if (newCurrent != current) { currentView.setVisibility(View.GONE); newView.setVisibility(View.VISIBLE); currentView = newView; current = newCurrent; } if (current != GRAPH) { label.setVisibility(View.VISIBLE); LinearLayout.LayoutParams graphValueLayout = new LinearLayout.LayoutParams((ViewGroup.LayoutParams)origValue); graphValueLayout.weight = 10; valuePane.setLayoutParams(origValue); } } /* * Get current device screen width */ private int getScreenWidth() { Display display = ((WindowManager) this.getContext().getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay(); return display.getWidth(); } }