diff --git a/app/src/org/commcare/android/adapters/EntityDetailPagerAdapter.java b/app/src/org/commcare/android/adapters/EntityDetailPagerAdapter.java index f3dba9d494..cc011bc04f 100755 --- a/app/src/org/commcare/android/adapters/EntityDetailPagerAdapter.java +++ b/app/src/org/commcare/android/adapters/EntityDetailPagerAdapter.java @@ -1,14 +1,10 @@ package org.commcare.android.adapters; -import java.util.List; - import org.commcare.android.framework.EntityDetailFragment; -import org.commcare.android.models.Entity; -import org.commcare.android.util.DetailCalloutListener; +import org.commcare.android.util.SerializationUtil; import org.commcare.suite.model.Detail; -import org.odk.collect.android.views.media.AudioController; +import org.javarosa.core.model.instance.TreeReference; -import android.content.Context; import android.os.Bundle; import android.support.v4.app.Fragment; import android.support.v4.app.FragmentManager; @@ -23,12 +19,14 @@ public class EntityDetailPagerAdapter extends FragmentStatePagerAdapter { Detail detail; int detailIndex; boolean hasDetailCalloutListener; + TreeReference mEntityReference; - public EntityDetailPagerAdapter(FragmentManager fm, Detail detail, int detailIndex, boolean hasDetailCalloutListener) { + public EntityDetailPagerAdapter(FragmentManager fm, Detail detail, int detailIndex, TreeReference reference, boolean hasDetailCalloutListener) { super(fm); this.detail = detail; this.detailIndex = detailIndex; this.hasDetailCalloutListener = hasDetailCalloutListener; + this.mEntityReference = reference; } /* @@ -45,6 +43,7 @@ public Fragment getItem(int i) { } args.putInt(EntityDetailFragment.DETAIL_INDEX, detailIndex); args.putBoolean(EntityDetailFragment.HAS_DETAIL_CALLOUT_LISTENER, hasDetailCalloutListener); + SerializationUtil.serializeToBundle(args, EntityDetailFragment.CHILD_REFERENCE, mEntityReference); fragment.setArguments(args); return fragment; } diff --git a/app/src/org/commcare/android/framework/BreadcrumbBarFragment.java b/app/src/org/commcare/android/framework/BreadcrumbBarFragment.java index 8e26441535..4f2b80ab3a 100644 --- a/app/src/org/commcare/android/framework/BreadcrumbBarFragment.java +++ b/app/src/org/commcare/android/framework/BreadcrumbBarFragment.java @@ -7,6 +7,7 @@ import org.commcare.android.models.Entity; import org.commcare.android.models.NodeEntityFactory; import org.commcare.android.util.CommCareInstanceInitializer; +import org.commcare.android.util.SerializationUtil; import org.commcare.android.util.SessionUnavailableException; import org.commcare.android.view.GridEntityView; import org.commcare.android.view.TabbedDetailView; @@ -24,7 +25,6 @@ import android.app.ActionBar; import android.app.ActionBar.LayoutParams; import android.app.Activity; -import android.graphics.Point; import android.os.Build; import android.os.Bundle; import android.support.v4.app.Fragment; @@ -217,7 +217,8 @@ public boolean willChangeBounds() { private View findAndLoadCaseTile(final Activity activity) { final View holder = LayoutInflater.from(activity).inflate(R.layout.com_tile_holder, null); - View tile = this.loadTile(activity); + final Pair tileData = this.loadTile(activity); + View tile = tileData == null ? null : tileData.first; if(tile == null) { return null;} final ImageButton openButton = ((ImageButton)holder.findViewById(R.id.com_tile_holder_btn_open)); @@ -244,7 +245,7 @@ public void onClick(View v) { Detail detail = factory.getDetail(); mInternalDetailView.setDetail(detail); - mInternalDetailView.refresh(factory.getDetail(), 0, false); + mInternalDetailView.refresh(factory.getDetail(), tileData.second,0, false); } openButton.setVisibility(View.INVISIBLE); expand(activity, holder.findViewById(R.id.com_tile_holder_detail_master)); @@ -272,7 +273,7 @@ public void run() { } - private View loadTile(Activity activity) { + private Pair loadTile(Activity activity) { try { AndroidSessionWrapper asw = CommCareApplication._().getCurrentSessionWrapper(); CommCareSession session = asw.getSession(); @@ -290,7 +291,7 @@ private View loadTile(Activity activity) { } } - View tile = buildContextTile(activity, stepToFrame, asw); + Pair tile = buildContextTile(activity, stepToFrame, asw); //some contexts may provide a tile that isn't really part of the current session's stack if(tile == null && activity instanceof CommCareActivity) { Pair entityContext = ((CommCareActivity)activity).requestEntityContext(); @@ -574,35 +575,33 @@ public void onClick(View arg0) { View tile; - private View buildContextTile(Activity activity, String[] stepToFrame, AndroidSessionWrapper asw) { + private Pair buildContextTile(Activity activity, String[] stepToFrame, AndroidSessionWrapper asw) { if(stepToFrame == null) { return null; } //check to make sure we can look up this child SessionDatum d = asw.getSession().findDatumDefinition(stepToFrame[1]); - if(d == null || d.getShortDetail() == null) { return null; } + if(d == null || d.getPersistentDetail() == null) { return null; } //Make sure there is a valid reference to the entity we can build - Detail detail = asw.getSession().getDetail(d.getShortDetail()); + Detail detail = asw.getSession().getDetail(d.getPersistentDetail()); EvaluationContext ec = asw.getEvaluationContext(); TreeReference ref = asw.getSession().getEntityFromID(ec, d, stepToFrame[2]); if(ref == null) { return null; } - View v = buildContextTile(activity, detail, ref, asw); - v.setTag(d.getInlineDetail()); - return v; + Pair r = buildContextTile(activity, detail, ref, asw); + r.first.setTag(d.getInlineDetail()); + return r; } - private View buildContextTile(Activity activity, Detail detail, TreeReference ref, AndroidSessionWrapper asw) { + private Pair buildContextTile(Activity activity, Detail detail, TreeReference ref, AndroidSessionWrapper asw) { NodeEntityFactory nef = new NodeEntityFactory(detail, asw.getEvaluationContext()); - CommCareApplication._().serializeToIntent(activity.getIntent(), EntityDetailActivity.CONTEXT_REFERENCE, ref); - Entity entity = nef.getEntity(ref); - GridEntityView tile = new GridEntityView(this.getActivity(), detail, entity, null); - return tile; + View tile = new GridEntityView(this.getActivity(), detail, entity, null); + return Pair.create(tile, ref); } diff --git a/app/src/org/commcare/android/framework/EntityDetailFragment.java b/app/src/org/commcare/android/framework/EntityDetailFragment.java index 3e9df3b8fe..963d3e0eff 100755 --- a/app/src/org/commcare/android/framework/EntityDetailFragment.java +++ b/app/src/org/commcare/android/framework/EntityDetailFragment.java @@ -5,8 +5,8 @@ import org.commcare.android.models.Entity; import org.commcare.android.models.NodeEntityFactory; import org.commcare.android.util.DetailCalloutListener; +import org.commcare.android.util.SerializationUtil; import org.commcare.dalvik.R; -import org.commcare.dalvik.activities.EntityDetailActivity; import org.commcare.dalvik.application.CommCareApplication; import org.commcare.suite.model.Detail; import org.javarosa.core.model.instance.TreeReference; @@ -30,6 +30,7 @@ public class EntityDetailFragment extends Fragment { public static final String DETAIL_ID = "edf_detail_id"; public static final String DETAIL_INDEX = "edf_detail_index"; public static final String HAS_DETAIL_CALLOUT_LISTENER = "edf_has_detail_callout_listener"; + public static final String CHILD_REFERENCE = "edf_detail_reference"; private AndroidSessionWrapper asw; private NodeEntityFactory factory; @@ -56,8 +57,8 @@ public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle sa } factory = new NodeEntityFactory(childDetail, asw.getEvaluationContext()); - Entity entity = factory.getEntity(CommCareApplication._().deserializeFromIntent( - getActivity().getIntent(), EntityDetailActivity.CONTEXT_REFERENCE, TreeReference.class) + Entity entity = factory.getEntity(SerializationUtil.deserializeFromBundle( + args, CHILD_REFERENCE, TreeReference.class) ); View rootView = inflater.inflate(R.layout.entity_detail_list, container, false); diff --git a/app/src/org/commcare/android/util/SerializationUtil.java b/app/src/org/commcare/android/util/SerializationUtil.java new file mode 100644 index 0000000000..e3e326c812 --- /dev/null +++ b/app/src/org/commcare/android/util/SerializationUtil.java @@ -0,0 +1,75 @@ +/** + * + */ +package org.commcare.android.util; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +import org.commcare.android.database.DbUtil; +import org.commcare.dalvik.application.CommCareApplication; +import org.javarosa.core.util.externalizable.DeserializationException; +import org.javarosa.core.util.externalizable.Externalizable; + +import android.content.Intent; +import android.os.Bundle; + +/** + * @author ctsims + * + */ +public class SerializationUtil { + public static byte[] serialize(Externalizable data) { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + try { + data.writeExternal(new DataOutputStream(baos)); + } catch (IOException e) { + e.printStackTrace(); + throw new RuntimeException(e); + } + return baos.toByteArray(); + } + + public static T deserialize(byte[] bytes, String name, Class type) { + T t; + try { + t = type.newInstance(); + t.readExternal(new DataInputStream(new ByteArrayInputStream(bytes)), DbUtil.getPrototypeFactory(CommCareApplication._())); + } catch (IOException e) { + e.printStackTrace(); + throw new RuntimeException(e); + } catch (DeserializationException e) { + e.printStackTrace(); + throw new RuntimeException(e); + } catch (IllegalAccessException e1) { + e1.printStackTrace(); + throw new RuntimeException(e1); + } catch (InstantiationException e1) { + e1.printStackTrace(); + throw new RuntimeException(e1); + } + return t; + } + + + public static void serializeToIntent(Intent i, String name, Externalizable data) { + i.putExtra(name, serialize(data)); + } + + public static T deserializeFromIntent(Intent i, String name, Class type) { + if(!i.hasExtra(name)) { return null;} + return deserialize(i.getByteArrayExtra(name), name, type); + } + + public static void serializeToBundle(Bundle b, String name, Externalizable data) { + b.putByteArray(name, serialize(data)); + } + + public static T deserializeFromBundle(Bundle b, String name, Class type) { + if(!b.containsKey(name)) { return null;} + return deserialize(b.getByteArray(name), name, type); + } +} diff --git a/app/src/org/commcare/android/view/TabbedDetailView.java b/app/src/org/commcare/android/view/TabbedDetailView.java index 86f2ba38c7..e9f86c5101 100755 --- a/app/src/org/commcare/android/view/TabbedDetailView.java +++ b/app/src/org/commcare/android/view/TabbedDetailView.java @@ -1,10 +1,10 @@ package org.commcare.android.view; import org.commcare.android.adapters.EntityDetailPagerAdapter; -import org.commcare.android.util.MediaUtil; import org.commcare.dalvik.R; import org.commcare.suite.model.Detail; import org.commcare.suite.model.DisplayUnit; +import org.javarosa.core.model.instance.TreeReference; import android.annotation.SuppressLint; import android.content.Context; @@ -16,10 +16,8 @@ import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; -import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.RelativeLayout; -import android.widget.TextView; /** * Widget that combines a ViewPager with a set of page titles styled to look like tabs. @@ -131,8 +129,8 @@ public void onClick(View v) { /* * Get form list from database and insert into view. */ - public void refresh(Detail detail, int index, boolean hasDetailCalloutListener) { - mEntityDetailPagerAdapter = new EntityDetailPagerAdapter(mContext.getSupportFragmentManager(), detail, index, hasDetailCalloutListener); + public void refresh(Detail detail, TreeReference reference, int index, boolean hasDetailCalloutListener) { + mEntityDetailPagerAdapter = new EntityDetailPagerAdapter(mContext.getSupportFragmentManager(), detail, index, reference, hasDetailCalloutListener); mViewPager.setAdapter(mEntityDetailPagerAdapter); markSelectedTab(0); } diff --git a/app/src/org/commcare/dalvik/activities/EntityDetailActivity.java b/app/src/org/commcare/dalvik/activities/EntityDetailActivity.java index 12c03134f8..1f4465ba56 100644 --- a/app/src/org/commcare/dalvik/activities/EntityDetailActivity.java +++ b/app/src/org/commcare/dalvik/activities/EntityDetailActivity.java @@ -10,13 +10,13 @@ import org.commcare.android.models.Entity; import org.commcare.android.models.NodeEntityFactory; import org.commcare.android.util.DetailCalloutListener; +import org.commcare.android.util.SerializationUtil; import org.commcare.android.util.SessionUnavailableException; import org.commcare.android.view.TabbedDetailView; import org.commcare.dalvik.R; import org.commcare.dalvik.application.CommCareApplication; import org.commcare.suite.model.Detail; import org.commcare.suite.model.Entry; -import org.commcare.suite.model.SessionDatum; import org.commcare.util.CommCareSession; import org.commcare.util.SessionFrame; import org.javarosa.core.model.instance.TreeReference; @@ -45,7 +45,7 @@ public class EntityDetailActivity extends CommCareActivity implements DetailCall public static final String IS_DEAD_END = "eda_ide"; public static final String CONTEXT_REFERENCE = "eda_crid"; public static final String DETAIL_ID = "eda_detail_id"; - public static final String DETAIL_SHORT_ID = "eda_short_id"; + public static final String DETAIL_PERSISTENT_ID = "eda_persistent_id"; Entry prototype; Entity entity; @@ -53,6 +53,8 @@ public class EntityDetailActivity extends CommCareActivity implements DetailCall NodeEntityFactory factory; Pair mEntityContext; + TreeReference mTreeReference; + private int detailIndex; @UiElement(value=R.id.entity_detail) @@ -81,14 +83,14 @@ public void onCreate(Bundle savedInstanceState) { factory = new NodeEntityFactory(session.getDetail(getIntent().getStringExtra(EntityDetailActivity.DETAIL_ID)), asw.getEvaluationContext()); - TreeReference ref = CommCareApplication._().deserializeFromIntent(getIntent(), EntityDetailActivity.CONTEXT_REFERENCE, TreeReference.class); - String shortDetailId = getIntent().getStringExtra(EntityDetailActivity.DETAIL_SHORT_ID); + mTreeReference = SerializationUtil.deserializeFromIntent(getIntent(), EntityDetailActivity.CONTEXT_REFERENCE, TreeReference.class); + String shortDetailId = getIntent().getStringExtra(EntityDetailActivity.DETAIL_PERSISTENT_ID); if(shortDetailId != null) { Detail shortDetail = session.getDetail(shortDetailId); - this.mEntityContext = new Pair(shortDetail, ref); + this.mEntityContext = new Pair(shortDetail, mTreeReference); } - entity = factory.getEntity(ref); + entity = factory.getEntity(mTreeReference); super.onCreate(savedInstanceState); @@ -128,7 +130,7 @@ public void onClick(View v) { } mDetailView.setRoot((ViewGroup) container.findViewById(R.id.entity_detail_tabs)); - mDetailView.refresh(factory.getDetail(), detailIndex, true); + mDetailView.refresh(factory.getDetail(), mTreeReference, detailIndex, true); } catch(SessionUnavailableException sue) { //TODO: Login and return to try again } @@ -183,7 +185,7 @@ protected void onActivityResult(int requestCode, int resultCode, Intent intent) switch(requestCode) { case CALL_OUT: if(resultCode == RESULT_CANCELED) { - mDetailView.refresh(factory.getDetail(), detailIndex, true); + mDetailView.refresh(factory.getDetail(), mTreeReference, detailIndex, true); return; } else { long duration = intent.getLongExtra(CallOutActivity.CALL_DURATION, 0); diff --git a/app/src/org/commcare/dalvik/activities/EntityMapActivity.java b/app/src/org/commcare/dalvik/activities/EntityMapActivity.java index aec6ba7aff..37de45642c 100644 --- a/app/src/org/commcare/dalvik/activities/EntityMapActivity.java +++ b/app/src/org/commcare/dalvik/activities/EntityMapActivity.java @@ -10,6 +10,7 @@ import org.commcare.android.models.Entity; import org.commcare.android.models.NodeEntityFactory; import org.commcare.android.util.CommCareInstanceInitializer; +import org.commcare.android.util.SerializationUtil; import org.commcare.dalvik.R; import org.commcare.dalvik.application.CommCareApplication; import org.commcare.dalvik.geo.EntityOverlay; @@ -133,7 +134,7 @@ protected void onCreate(Bundle icicle) { @Override protected void selected(TreeReference ref) { Intent i = new Intent(EntityMapActivity.this.getIntent()); - CommCareApplication._().serializeToIntent(i, EntityDetailActivity.CONTEXT_REFERENCE, ref); + SerializationUtil.serializeToIntent(i, EntityDetailActivity.CONTEXT_REFERENCE, ref); setResult(RESULT_OK, i); diff --git a/app/src/org/commcare/dalvik/activities/EntitySelectActivity.java b/app/src/org/commcare/dalvik/activities/EntitySelectActivity.java index 3b78b56b2e..1bb3afe907 100644 --- a/app/src/org/commcare/dalvik/activities/EntitySelectActivity.java +++ b/app/src/org/commcare/dalvik/activities/EntitySelectActivity.java @@ -12,6 +12,7 @@ import org.commcare.android.tasks.EntityLoaderListener; import org.commcare.android.tasks.EntityLoaderTask; import org.commcare.android.util.CommCareInstanceInitializer; +import org.commcare.android.util.SerializationUtil; import org.commcare.android.util.SessionUnavailableException; import org.commcare.android.view.EntityView; import org.commcare.android.view.TabbedDetailView; @@ -30,9 +31,6 @@ import org.javarosa.core.model.instance.TreeReference; import org.javarosa.core.services.locale.Localization; import org.javarosa.model.xform.XPathReference; -import org.javarosa.xpath.expr.XPathEqExpr; -import org.javarosa.xpath.expr.XPathExpression; -import org.javarosa.xpath.expr.XPathStringLiteral; import android.app.Activity; import android.app.AlertDialog; @@ -295,7 +293,7 @@ public void onResume() { Intent i = getDetailIntent(entity, null); if (adapter != null) { i.putExtra("entity_detail_index", adapter.getPosition(entity)); - i.putExtra(EntityDetailActivity.DETAIL_SHORT_ID, selectDatum.getShortDetail()); + i.putExtra(EntityDetailActivity.DETAIL_PERSISTENT_ID, selectDatum.getShortDetail()); } startActivityForResult(i, CONFIRM_SELECT); return; @@ -361,11 +359,11 @@ protected Intent getDetailIntent(TreeReference contextRef, Intent i) { if(selectDatum.getLongDetail() != null) { //If so, add this. otherwise that'll be the queue to just return i.putExtra(EntityDetailActivity.DETAIL_ID, selectDatum.getLongDetail()); - i.putExtra(EntityDetailActivity.DETAIL_SHORT_ID, selectDatum.getShortDetail()); + i.putExtra(EntityDetailActivity.DETAIL_PERSISTENT_ID, selectDatum.getPersistentDetail()); } i.putExtra(SessionFrame.STATE_DATUM_VAL, value); - CommCareApplication._().serializeToIntent(i, EntityDetailActivity.CONTEXT_REFERENCE, contextRef); + SerializationUtil.serializeToIntent(i, EntityDetailActivity.CONTEXT_REFERENCE, contextRef); return i; } @@ -426,7 +424,7 @@ protected void onActivityResult(int requestCode, int resultCode, Intent intent) //Otherwise, if we're in awesome mode, make sure we retain the original selection if(inAwesomeMode) { - TreeReference r = CommCareApplication._().deserializeFromIntent(intent, EntityDetailActivity.CONTEXT_REFERENCE, TreeReference.class); + TreeReference r = SerializationUtil.deserializeFromIntent(intent, EntityDetailActivity.CONTEXT_REFERENCE, TreeReference.class); if(r != null) { this.displayReferenceAwesome(r, adapter.getPosition(r)); updateSelectedItem(r, true); @@ -437,7 +435,7 @@ protected void onActivityResult(int requestCode, int resultCode, Intent intent) } case MAP_SELECT: if(resultCode == RESULT_OK) { - TreeReference r = CommCareApplication._().deserializeFromIntent(intent, EntityDetailActivity.CONTEXT_REFERENCE, TreeReference.class); + TreeReference r = SerializationUtil.deserializeFromIntent(intent, EntityDetailActivity.CONTEXT_REFERENCE, TreeReference.class); if(inAwesomeMode) { this.displayReferenceAwesome(r, adapter.getPosition(r)); @@ -701,7 +699,7 @@ public void deliverResult(List> entities, List T deserializeFromIntent(Intent i, String name, Class type) { - if(!i.hasExtra(name)) { return null;} - T t; - try { - t = type.newInstance(); - t.readExternal(new DataInputStream(new ByteArrayInputStream(i.getByteArrayExtra(name))), DbUtil.getPrototypeFactory(this)); - } catch (IOException e) { - e.printStackTrace(); - throw new RuntimeException(e); - } catch (DeserializationException e) { - e.printStackTrace(); - throw new RuntimeException(e); - } catch (IllegalAccessException e1) { - e1.printStackTrace(); - throw new RuntimeException(e1); - } catch (InstantiationException e1) { - e1.printStackTrace(); - throw new RuntimeException(e1); - } - return t; - } /* * (non-Javadoc)