diff --git a/android/AndroidManifest.xml b/android/AndroidManifest.xml index de2637f05..db3d21f0d 100644 --- a/android/AndroidManifest.xml +++ b/android/AndroidManifest.xml @@ -71,8 +71,8 @@ - - + + diff --git a/android/res/layout/motor_hierarch_list.xml b/android/res/layout/motor_hierarch_list.xml deleted file mode 100644 index 9d17a2c24..000000000 --- a/android/res/layout/motor_hierarch_list.xml +++ /dev/null @@ -1,18 +0,0 @@ - - - - - - - - - \ No newline at end of file diff --git a/android/res/menu/motor_browser_option_menu.xml b/android/res/menu/motor_browser_option_menu.xml index 5c1f1b440..154bd5955 100644 --- a/android/res/menu/motor_browser_option_menu.xml +++ b/android/res/menu/motor_browser_option_menu.xml @@ -1,6 +1,12 @@ - - - - + + + + + + \ No newline at end of file diff --git a/android/src/net/sf/openrocket/android/ActivityHelpers.java b/android/src/net/sf/openrocket/android/ActivityHelpers.java index bc6db510b..aaef2c6fa 100644 --- a/android/src/net/sf/openrocket/android/ActivityHelpers.java +++ b/android/src/net/sf/openrocket/android/ActivityHelpers.java @@ -1,6 +1,7 @@ package net.sf.openrocket.android; -import net.sf.openrocket.android.motor.MotorHierarchicalBrowser; +import net.sf.openrocket.android.motor.MotorBrowserActivity; +import net.sf.openrocket.android.thrustcurve.TCQueryActivity; import android.app.Activity; import android.content.Intent; @@ -8,14 +9,18 @@ public abstract class ActivityHelpers { public static void browseMotors( Activity parent ) { - Intent i = new Intent(parent, MotorHierarchicalBrowser.class); + Intent i = new Intent(parent, MotorBrowserActivity.class); parent.startActivity(i); - } public static void startPreferences( Activity parent ) { Intent intent = new Intent(parent, PreferencesActivity.class); parent.startActivity(intent); - } + + public static void downloadFromThrustcurve( Activity parent ) { + Intent i = new Intent(parent, TCQueryActivity.class); + parent.startActivity(i); + } + } diff --git a/android/src/net/sf/openrocket/android/db/ConversionUtils.java b/android/src/net/sf/openrocket/android/db/ConversionUtils.java index a66fc28cf..62fbddb9d 100644 --- a/android/src/net/sf/openrocket/android/db/ConversionUtils.java +++ b/android/src/net/sf/openrocket/android/db/ConversionUtils.java @@ -8,7 +8,7 @@ import java.io.ObjectOutputStream; import net.sf.openrocket.motor.Motor; import net.sf.openrocket.util.Coordinate; -abstract class ConversionUtils { +public abstract class ConversionUtils { static double[] stringToDelays( String value ) { if (value == null || "".equals(value) ) { @@ -28,7 +28,7 @@ abstract class ConversionUtils { return values; } - static String delaysToString( double[] delays ) { + public static String delaysToString( double[] delays ) { StringBuilder s = new StringBuilder(); boolean first = true; for( double d:delays ) { diff --git a/android/src/net/sf/openrocket/android/motor/MotorBrowserActivity.java b/android/src/net/sf/openrocket/android/motor/MotorBrowserActivity.java new file mode 100644 index 000000000..e059da133 --- /dev/null +++ b/android/src/net/sf/openrocket/android/motor/MotorBrowserActivity.java @@ -0,0 +1,91 @@ +package net.sf.openrocket.android.motor; + +import net.sf.openrocket.R; +import net.sf.openrocket.android.ActivityHelpers; +import net.sf.openrocket.android.PreferencesActivity; +import net.sf.openrocket.android.simulation.SimulationChart; +import net.sf.openrocket.android.simulation.SimulationFragment; +import net.sf.openrocket.android.simulation.SimulationViewActivity; +import net.sf.openrocket.android.thrustcurve.TCQueryActivity; +import net.sf.openrocket.android.util.AndroidLogWrapper; +import net.sf.openrocket.document.Simulation; +import android.content.Intent; +import android.os.Bundle; +import android.support.v4.app.Fragment; +import android.support.v4.app.FragmentActivity; +import android.support.v4.app.FragmentTransaction; +import android.view.Menu; +import android.view.MenuInflater; +import android.view.MenuItem; +import android.view.View; + +public class MotorBrowserActivity extends FragmentActivity +implements MotorListFragment.OnMotorSelectedListener +{ + + MotorListFragment motorList; + + /** Called when the activity is first created. */ + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + if (getSupportFragmentManager().findFragmentById(android.R.id.content) == null) { + motorList = MotorListFragment.newInstance(); + FragmentTransaction ft = getSupportFragmentManager().beginTransaction(); + ft.add(android.R.id.content, motorList); + ft.commit(); + } + } + + @Override + public boolean onCreateOptionsMenu(Menu menu) { + MenuInflater inflater = getMenuInflater(); + inflater.inflate(R.menu.motor_browser_option_menu, menu); + return true; + } + + @Override + public boolean onMenuItemSelected(int featureId, MenuItem item) { + AndroidLogWrapper.d(MotorBrowserActivity.class,"onMenuItemSelected" + item.getItemId()); + switch(item.getItemId()) { + case R.id.download_from_thrustcurve_menu_option: + ActivityHelpers.downloadFromThrustcurve(this); + return true; + case R.id.preference_menu_option: + Intent intent = new Intent().setClass(this, PreferencesActivity.class); + this.startActivity(intent); + return true; + } + return super.onMenuItemSelected(featureId, item); + } + + @Override + public void onMotorSelected(long motorId) { + + View sidepane = findViewById(R.id.sidepane); + if ( /* if multi pane */ sidepane != null ) { + /* + Simulation sim = app.getRocketDocument().getSimulation(simulationId); + SimulationChart chart = new SimulationChart(simulationId); + + Fragment graph = SimulationFragment.newInstance(chart); + + FragmentTransaction ft = getSupportFragmentManager().beginTransaction(); + ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE); + // probably only want to update back stack for first time. + ft.addToBackStack("simulationplot"); + ft.replace(R.id.sidepane, graph); + ft.show(graph); + ft.commit(); +*/ + + } else { + Intent i = new Intent(this,MotorDetailsActivity.class); + i.putExtra("Motor", motorId); + startActivity(i); + } + + } + +} diff --git a/android/src/net/sf/openrocket/android/motor/MotorDetails.java b/android/src/net/sf/openrocket/android/motor/MotorDetailsActivity.java similarity index 93% rename from android/src/net/sf/openrocket/android/motor/MotorDetails.java rename to android/src/net/sf/openrocket/android/motor/MotorDetailsActivity.java index df31f3be2..ed97b837a 100644 --- a/android/src/net/sf/openrocket/android/motor/MotorDetails.java +++ b/android/src/net/sf/openrocket/android/motor/MotorDetailsActivity.java @@ -12,7 +12,7 @@ import android.view.MenuItem; import android.widget.ImageView; import android.widget.SlidingDrawer; -public class MotorDetails extends FragmentActivity +public class MotorDetailsActivity extends FragmentActivity implements SlidingDrawer.OnDrawerCloseListener, SlidingDrawer.OnDrawerOpenListener { private final static String TAG = "MotorDetails"; diff --git a/android/src/net/sf/openrocket/android/motor/MotorDetailsFragment.java b/android/src/net/sf/openrocket/android/motor/MotorDetailsFragment.java index 874f43439..f9083b646 100644 --- a/android/src/net/sf/openrocket/android/motor/MotorDetailsFragment.java +++ b/android/src/net/sf/openrocket/android/motor/MotorDetailsFragment.java @@ -1,8 +1,7 @@ package net.sf.openrocket.android.motor; -import java.util.Arrays; - import net.sf.openrocket.R; +import net.sf.openrocket.android.db.ConversionUtils; import net.sf.openrocket.motor.ThrustCurveMotor; import android.os.Bundle; import android.support.v4.app.Fragment; @@ -39,7 +38,7 @@ public class MotorDetailsFragment extends Fragment { ThrustCurveMotor tcm = m.getThrustCurveMotor(); manuField.setText( tcm.getManufacturer().getDisplayName()); nameField.setText( tcm.getDesignation() ); - delaysField.setText( Arrays.toString(tcm.getStandardDelays()) ); + delaysField.setText( ConversionUtils.delaysToString(tcm.getStandardDelays()) ); caseField.setText( m.getCaseInfo()); impulseClassField.setText( m.getImpulseClass()); diameterField.setText( String.valueOf(tcm.getDiameter()*1000.0) ); diff --git a/android/src/net/sf/openrocket/android/motor/MotorHierarchicalBrowser.java b/android/src/net/sf/openrocket/android/motor/MotorListFragment.java similarity index 70% rename from android/src/net/sf/openrocket/android/motor/MotorHierarchicalBrowser.java rename to android/src/net/sf/openrocket/android/motor/MotorListFragment.java index f940e110d..f7559854f 100644 --- a/android/src/net/sf/openrocket/android/motor/MotorHierarchicalBrowser.java +++ b/android/src/net/sf/openrocket/android/motor/MotorListFragment.java @@ -1,10 +1,12 @@ package net.sf.openrocket.android.motor; import net.sf.openrocket.R; -import net.sf.openrocket.android.PreferencesActivity; import net.sf.openrocket.android.db.DbAdapter; import net.sf.openrocket.android.db.MotorDao; -import net.sf.openrocket.android.thrustcurve.TCQueryActivity; +import net.sf.openrocket.android.util.AndroidLogWrapper; +import net.sf.openrocket.android.util.PersistentExpandableListFragment; +import net.sf.openrocket.motor.Motor; +import android.app.Activity; import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; @@ -12,11 +14,9 @@ import android.content.res.Resources; import android.database.Cursor; import android.os.Bundle; import android.preference.PreferenceManager; -import android.util.Log; import android.view.ContextMenu; import android.view.ContextMenu.ContextMenuInfo; import android.view.Menu; -import android.view.MenuInflater; import android.view.MenuItem; import android.view.View; import android.widget.CursorTreeAdapter; @@ -25,14 +25,23 @@ import android.widget.ResourceCursorTreeAdapter; import android.widget.TextView; -public class MotorHierarchicalBrowser -extends PersistentExpandableListActivity +/* + * TODO - make this work with PersistentExpandableListFragment. + * + */ +public class MotorListFragment extends PersistentExpandableListFragment implements SharedPreferences.OnSharedPreferenceChangeListener { - private static final String TAG = "MotorHierarchicalBrowser"; - - private static final int ACTIVITY_DOWNLOAD=0; - + public interface OnMotorSelectedListener { + public void onMotorSelected( long motorId ); + } + + public static MotorListFragment newInstance( ) { + + MotorListFragment frag = new MotorListFragment(); + return frag; + } + private static final int CONTEXTMENU_DELETE = Menu.FIRST+1; private String groupColumnPreferenceKey; @@ -48,6 +57,13 @@ implements SharedPreferences.OnSharedPreferenceChangeListener private CursorTreeAdapter mAdapter; private DbAdapter mDbHelper; + + private OnMotorSelectedListener motorSelectedListener; + + public void setMotorSelectedListener( + OnMotorSelectedListener motorSelectedListener) { + this.motorSelectedListener = motorSelectedListener; + } public class MotorHierarchicalListAdapter extends ResourceCursorTreeAdapter { @@ -62,12 +78,12 @@ implements SharedPreferences.OnSharedPreferenceChangeListener @Override protected Cursor getChildrenCursor(Cursor arg0) { - Log.d(TAG,"getChildrenCursor"); + AndroidLogWrapper.d(MotorListFragment.class,"getChildrenCursor"); String group = arg0.getString(arg0.getColumnIndex(groupColumn)); - Log.d(TAG," for: "+ groupColumn + " = " + group); + AndroidLogWrapper.d(MotorListFragment.class," for: "+ groupColumn + " = " + group); Cursor c = mDbHelper.getMotorDao().fetchAllInGroups(groupColumn,group); - Log.d(TAG," got cursor"); - startManagingCursor(c); + AndroidLogWrapper.d(MotorListFragment.class," got cursor"); + getActivity().startManagingCursor(c); return c; } @@ -111,8 +127,6 @@ implements SharedPreferences.OnSharedPreferenceChangeListener } } - - } @Override @@ -124,20 +138,8 @@ implements SharedPreferences.OnSharedPreferenceChangeListener } @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - mDbHelper = new DbAdapter(this); - mDbHelper.open(); - - Resources resources = this.getResources(); - groupColumnPreferenceKey = resources.getString(R.string.PreferenceMotorBrowserGroupingOption); - SharedPreferences pref = PreferenceManager.getDefaultSharedPreferences(this); - - setGroupColumnFromPreferences(pref); - - pref.registerOnSharedPreferenceChangeListener(this); - + public void onViewCreated(View view, Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); refreshData(); registerForContextMenu(getExpandableListView()); @@ -145,37 +147,29 @@ implements SharedPreferences.OnSharedPreferenceChangeListener } @Override - public boolean onCreateOptionsMenu(Menu menu) { - MenuInflater inflater = getMenuInflater(); - inflater.inflate(R.menu.motor_browser_option_menu, menu); - return true; - } + public void onAttach(Activity activity) { + super.onAttach(activity); + mDbHelper = new DbAdapter(getActivity()); + mDbHelper.open(); - @Override - public boolean onMenuItemSelected(int featureId, MenuItem item) { - Log.d(TAG,"onMenuItemSelected" + item.getItemId()); - switch(item.getItemId()) { - case R.id.download_from_thrustcurve_menu_option: - tcDownload(); - return true; - case R.id.preference_menu_option: - Intent intent = new Intent().setClass(this, PreferencesActivity.class); - this.startActivity(intent); - return true; + Resources resources = this.getResources(); + groupColumnPreferenceKey = resources.getString(R.string.PreferenceMotorBrowserGroupingOption); + SharedPreferences pref = PreferenceManager.getDefaultSharedPreferences(getActivity()); + + setGroupColumnFromPreferences(pref); + + pref.registerOnSharedPreferenceChangeListener(this); + + if ( activity instanceof OnMotorSelectedListener ) { + motorSelectedListener = (OnMotorSelectedListener) activity; } - return super.onMenuItemSelected(featureId, item); + } @Override public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) { - Log.d(TAG,"onCreateContextMenu " + menuInfo); - Log.d(TAG, "v.getId() = " + v.getId()); - Log.d(TAG, "motorListView = " + R.id.motorListView); - // if (v.getId() == R.id.motorListView) { - ExpandableListView.ExpandableListContextMenuInfo info = (ExpandableListView.ExpandableListContextMenuInfo) menuInfo; - menu.setHeaderTitle("context menu"); + menu.setHeaderTitle("Motor Operations"); menu.add(Menu.NONE,CONTEXTMENU_DELETE,CONTEXTMENU_DELETE,"Delete"); - // } super.onCreateContextMenu(menu, v, menuInfo); } @@ -183,7 +177,7 @@ implements SharedPreferences.OnSharedPreferenceChangeListener public boolean onContextItemSelected(MenuItem item) { ExpandableListView.ExpandableListContextMenuInfo info = (ExpandableListView.ExpandableListContextMenuInfo) item.getMenuInfo(); long motorId = info.id; - Log.d(TAG,"ContextMenu: " + motorId); + AndroidLogWrapper.d(MotorListFragment.class,"ContextMenu: " + motorId); switch(item.getItemId()) { case CONTEXTMENU_DELETE: mDbHelper.getMotorDao().deleteMotor(motorId); @@ -193,28 +187,20 @@ implements SharedPreferences.OnSharedPreferenceChangeListener return super.onContextItemSelected(item); } - @Override - protected void onActivityResult(int requestCode, int resultCode, Intent intent) { - super.onActivityResult(requestCode, resultCode, intent); - refreshData(); - } - - @Override public boolean onChildClick(ExpandableListView parent, View v, int groupPosition, int childPosition, long id) { super.onChildClick(parent, v, groupPosition, childPosition, id); //Intent i = new Intent(this, BurnPlotActivity.class); - Intent i = new Intent(this,MotorDetails.class); - i.putExtra("Motor", id); - startActivity(i); + if( motorSelectedListener != null ) { + motorSelectedListener.onMotorSelected(id); + } return true; } @Override - protected void onDestroy() { - super.onDestroy(); - - SharedPreferences pref = PreferenceManager.getDefaultSharedPreferences(this); + public void onDetach() { + super.onDetach(); + SharedPreferences pref = PreferenceManager.getDefaultSharedPreferences(getActivity()); pref.unregisterOnSharedPreferenceChangeListener(this); // Null out the group cursor. This will cause the group cursor and all of the child cursors @@ -225,11 +211,6 @@ implements SharedPreferences.OnSharedPreferenceChangeListener mDbHelper.close(); } - private void tcDownload() { - Intent i = new Intent(this, TCQueryActivity.class); - startActivityForResult(i, ACTIVITY_DOWNLOAD); - } - private void setGroupColumnFromPreferences( SharedPreferences prefs ) { String indexStr = prefs.getString(groupColumnPreferenceKey, "1"); int index; @@ -250,10 +231,10 @@ implements SharedPreferences.OnSharedPreferenceChangeListener mAdapter.changeCursor(null); } Cursor motorCursor = mDbHelper.getMotorDao().fetchGroups(groupColumn); - startManagingCursor(motorCursor); + getActivity().startManagingCursor(motorCursor); // Set up our adapter mAdapter = new MotorHierarchicalListAdapter( - this, + getActivity(), motorCursor, R.layout.motor_list_group, R.layout.motor_list_child); diff --git a/android/src/net/sf/openrocket/android/motor/PersistentExpandableListActivity.java b/android/src/net/sf/openrocket/android/motor/PersistentExpandableListActivity.java deleted file mode 100644 index f179374a0..000000000 --- a/android/src/net/sf/openrocket/android/motor/PersistentExpandableListActivity.java +++ /dev/null @@ -1,91 +0,0 @@ -package net.sf.openrocket.android.motor; - -import java.util.ArrayList; -import java.util.List; - -import android.app.ExpandableListActivity; -import android.os.Bundle; -import android.widget.ExpandableListAdapter; -import android.widget.ExpandableListView; - -public class PersistentExpandableListActivity extends ExpandableListActivity { - private long[] expandedIds; - - @Override - protected void onStart() { - super.onStart(); - if (this.expandedIds != null) { - restoreExpandedState(expandedIds); - } - } - - @Override - protected void onStop() { - super.onStop(); - expandedIds = getExpandedIds(); - } - - @Override - protected void onSaveInstanceState(Bundle outState) { - super.onSaveInstanceState(outState); - this.expandedIds = getExpandedIds(); - outState.putLongArray("ExpandedIds", this.expandedIds); - } - - @Override - protected void onRestoreInstanceState(Bundle state) { - super.onRestoreInstanceState(state); - long[] expandedIds = state.getLongArray("ExpandedIds"); - if (expandedIds != null) { - restoreExpandedState(expandedIds); - } - } - - private long[] getExpandedIds() { - ExpandableListView list = getExpandableListView(); - ExpandableListAdapter adapter = getExpandableListAdapter(); - if (adapter != null) { - int length = adapter.getGroupCount(); - ArrayList expandedIds = new ArrayList(); - for(int i=0; i < length; i++) { - if(list.isGroupExpanded(i)) { - expandedIds.add(adapter.getGroupId(i)); - } - } - return toLongArray(expandedIds); - } else { - return null; - } - } - - private void restoreExpandedState(long[] expandedIds) { - this.expandedIds = expandedIds; - if (expandedIds != null) { - ExpandableListView list = getExpandableListView(); - ExpandableListAdapter adapter = getExpandableListAdapter(); - if (adapter != null) { - for (int i=0; i list) { - long[] ret = new long[list.size()]; - int i = 0; - for (Long e : list) - ret[i++] = e.longValue(); - return ret; - } -} diff --git a/android/src/net/sf/openrocket/android/util/AndroidLogWrapper.java b/android/src/net/sf/openrocket/android/util/AndroidLogWrapper.java new file mode 100644 index 000000000..456136a16 --- /dev/null +++ b/android/src/net/sf/openrocket/android/util/AndroidLogWrapper.java @@ -0,0 +1,55 @@ +package net.sf.openrocket.android.util; + +import java.text.MessageFormat; + +import android.util.Log; + +public class AndroidLogWrapper { + + private static final boolean logEnabled = true; + + public static void d( Class clzz, String msg, Object ... args ) { + + if ( logEnabled ) { + String tag = getTagForClass(clzz); + String formatted = MessageFormat.format(msg, args); + Log.d(tag,formatted); + } + } + + public static void e( Class clzz, String msg, Object ... args ) { + if ( logEnabled ) { + String tag = getTagForClass(clzz); + String formatted = MessageFormat.format(msg, args); + Log.e(tag,formatted); + } + } + + public static void i( Class clzz, String msg, Object ... args ) { + if ( logEnabled ) { + String tag = getTagForClass(clzz); + String formatted = MessageFormat.format(msg, args); + Log.i(tag,formatted); + } + } + public static void v( Class clzz, String msg, Object ... args ) { + if ( logEnabled ) { + String tag = getTagForClass(clzz); + String formatted = MessageFormat.format(msg, args); + Log.v(tag,formatted); + } + } + public static void w( Class clzz, String msg, Object ... args ) { + if ( logEnabled ) { + String tag = getTagForClass(clzz); + String formatted = MessageFormat.format(msg, args); + Log.w(tag,formatted); + } + } + + private static String getTagForClass( Class clzz ) { + String s = clzz.getSimpleName(); + return s; + } + +} diff --git a/android/src/net/sf/openrocket/android/util/ExpandableListFragment.java b/android/src/net/sf/openrocket/android/util/ExpandableListFragment.java new file mode 100644 index 000000000..47fc7fe2d --- /dev/null +++ b/android/src/net/sf/openrocket/android/util/ExpandableListFragment.java @@ -0,0 +1,344 @@ +package net.sf.openrocket.android.util; + +import android.os.Bundle; +import android.os.Handler; +import android.support.v4.app.Fragment; +import android.view.ContextMenu; +import android.view.ContextMenu.ContextMenuInfo; +import android.view.Gravity; +import android.view.LayoutInflater; +import android.view.View; +import android.view.View.OnCreateContextMenuListener; +import android.view.ViewGroup; +import android.view.animation.AnimationUtils; +import android.widget.AdapterView; +import android.widget.ExpandableListAdapter; +import android.widget.ExpandableListView; +import android.widget.FrameLayout; +import android.widget.ListAdapter; +import android.widget.ListView; +import android.widget.TextView; + +/** + * + * Pulled from https://gist.github.com/1316903 + * + * This class has originally been taken from + * http://stackoverflow.com/questions/6051050/expandablelistfragment-with-loadermanager-for-compatibility-package + * and then modified by Manfred Moser to get it to work with the v4 r4 compatibility + * library. With inspirations from the library source. + * + * All ASLv2 licensed. + */ +public class ExpandableListFragment extends Fragment +implements OnCreateContextMenuListener, ExpandableListView.OnChildClickListener, +ExpandableListView.OnGroupCollapseListener, ExpandableListView.OnGroupExpandListener +{ + + static final int INTERNAL_EMPTY_ID = 0x00ff0001; + static final int INTERNAL_LIST_CONTAINER_ID = 0x00ff0003; + + final private Handler mHandler = new Handler(); + + final private Runnable mRequestFocus = new Runnable() { + public void run() { + mList.focusableViewAvailable(mList); + } + }; + + final private AdapterView.OnItemClickListener mOnClickListener = new AdapterView.OnItemClickListener() { + public void onItemClick(AdapterView parent, View v, int position, long id) { + onListItemClick((ListView) parent, v, position, id); + } + }; + + ExpandableListAdapter mAdapter; + ExpandableListView mList; + View mEmptyView; + TextView mStandardEmptyView; + View mListContainer; + boolean mSetEmptyText; + boolean mListShown; + boolean mFinishedStart = false; + + public ExpandableListFragment() { + } + + /** + * Provide default implementation to return a simple list view. Subclasses + * can override to replace with their own layout. If doing so, the + * returned view hierarchy must have a ListView whose id + * is {@link android.R.id#list android.R.id.list} and can optionally + * have a sibling view id {@link android.R.id#empty android.R.id.empty} + * that is to be shown when the list is empty. + *

+ *

If you are overriding this method with your own custom content, + * consider including the standard layout {@link android.R.layout#list_content} + * in your layout file, so that you continue to retain all of the standard + * behavior of ListFragment. In particular, this is currently the only + * way to have the built-in indeterminant progress state be shown. + */ + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + FrameLayout root = new FrameLayout(getActivity()); + + FrameLayout lframe = new FrameLayout(getActivity()); + lframe.setId(INTERNAL_LIST_CONTAINER_ID); + + TextView tv = new TextView(getActivity()); + tv.setId(INTERNAL_EMPTY_ID); + tv.setGravity(Gravity.CENTER); + lframe.addView(tv, + new FrameLayout.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT, ViewGroup.LayoutParams.FILL_PARENT)); + + ExpandableListView lv = new ExpandableListView(getActivity()); + lv.setId(android.R.id.list); + lv.setDrawSelectorOnTop(false); + lv.setOnChildClickListener(this); + lv.setOnGroupExpandListener(this); + lv.setOnGroupCollapseListener(this); + + lframe.addView(lv, + new FrameLayout.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT, ViewGroup.LayoutParams.FILL_PARENT)); + + root.addView(lframe, new FrameLayout.LayoutParams( + ViewGroup.LayoutParams.FILL_PARENT, ViewGroup.LayoutParams.FILL_PARENT)); + + ListView.LayoutParams lp = + new ListView.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT, ViewGroup.LayoutParams.FILL_PARENT); + root.setLayoutParams(lp); + + return root; + } + + /** + * Attach to list view once the view hierarchy has been created. + */ + @Override + public void onViewCreated(View view, Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + ensureList(); + } + + /** Detach from list view. */ + @Override + public void onDestroyView() { + mHandler.removeCallbacks(mRequestFocus); + mList = null; + super.onDestroyView(); + } + + /** + * This method will be called when an item in the list is selected. + * Subclasses should override. Subclasses can call + * getListView().getItemAtPosition(position) if they need to access the + * data associated with the selected item. + * @param l The ListView where the click happened + * @param v The view that was clicked within the ListView + * @param position The position of the view in the list + * @param id The row id of the item that was clicked + */ + public void onListItemClick(ListView l, View v, int position, long id) { + } + + /** Provide the cursor for the list view. */ + public void setListAdapter(ExpandableListAdapter adapter) { + boolean hadAdapter = mAdapter != null; + mAdapter = adapter; + if (mList != null) { + mList.setAdapter((ExpandableListAdapter) null); + mList.setAdapter(adapter); + if (!mListShown && !hadAdapter) { + // The list was hidden, and previously didn't have an + // adapter. It is now time to show it. + setListShown(true, getView().getWindowToken() != null); + } + } + } + + /** + * Set the currently selected list item to the specified + * position with the adapter's data + */ + public void setSelection(int position) { + ensureList(); + mList.setSelection(position); + } + + public long getSelectedPosition() { + ensureList(); + return mList.getSelectedPosition(); + } + + public long getSelectedId() { + ensureList(); + return mList.getSelectedId(); + } + + public ExpandableListView getExpandableListView() { + ensureList(); + return mList; + } + + /** + * The default content for a ListFragment has a TextView that can + * be shown when the list is empty. If you would like to have it + * shown, call this method to supply the text it should use. + */ + public void setEmptyText(CharSequence text) { + ensureList(); + if (mStandardEmptyView == null) { + throw new IllegalStateException("Can't be used with a custom content view"); + } + mStandardEmptyView.setText(text); + if (!mSetEmptyText) { + mList.setEmptyView(mStandardEmptyView); + mSetEmptyText = true; + } + } + + /** + * Control whether the list is being displayed. You can make it not + * displayed if you are waiting for the initial data to show in it. During + * this time an indeterminant progress indicator will be shown instead. + *

+ *

Applications do not normally need to use this themselves. The default + * behavior of ListFragment is to start with the list not being shown, only + * showing it once an adapter is given with {@link #setListAdapter(ListAdapter)}. + * If the list at that point had not been shown, when it does get shown + * it will be do without the user ever seeing the hidden state. + * @param shown If true, the list view is shown; if false, the progress + * indicator. The initial value is true. + */ + public void setListShown(boolean shown) { + setListShown(shown, true); + } + + /** + * Like {@link #setListShown(boolean)}, but no animation is used when + * transitioning from the previous state. + */ + public void setListShownNoAnimation(boolean shown) { + setListShown(shown, false); + } + + /** + * Control whether the list is being displayed. You can make it not + * displayed if you are waiting for the initial data to show in it. During + * this time an indeterminant progress indicator will be shown instead. + * @param shown If true, the list view is shown; if false, the progress + * indicator. The initial value is true. + * @param animate If true, an animation will be used to transition to the + * new state. + */ + private void setListShown(boolean shown, boolean animate) { + ensureList(); + if (mListShown == shown) { + return; + } + mListShown = shown; + if (mListContainer != null) { + if (shown) { + if (animate) { + mListContainer.startAnimation(AnimationUtils.loadAnimation(getActivity(), android.R.anim.fade_in)); + } + mListContainer.setVisibility(View.VISIBLE); + } else { + if (animate) { + mListContainer.startAnimation(AnimationUtils.loadAnimation(getActivity(), android.R.anim.fade_out)); + } + mListContainer.setVisibility(View.GONE); + } + } + } + + /** Get the ListAdapter associated with this activity's ListView. */ + public ExpandableListAdapter getExpandableListAdapter() { + return mAdapter; + } + + private void ensureList() { + if (mList != null) { + return; + } + View root = getView(); + if (root == null) { + throw new IllegalStateException("Content view not yet created"); + } + if (root instanceof ExpandableListView) { + mList = (ExpandableListView) root; + } else { + mStandardEmptyView = (TextView) root.findViewById(INTERNAL_EMPTY_ID); + if (mStandardEmptyView == null) { + mEmptyView = root.findViewById(android.R.id.empty); + } + mListContainer = root.findViewById(INTERNAL_LIST_CONTAINER_ID); + View rawListView = root.findViewById(android.R.id.list); + if (!(rawListView instanceof ExpandableListView)) { + if (rawListView == null) { + throw new RuntimeException("Your content must have a ExpandableListView whose id attribute is " + + "'android.R.id.list'"); + } + throw new RuntimeException("Content has view with id attribute 'android.R.id.list' " + + "that is not a ExpandableListView class"); + } + mList = (ExpandableListView) rawListView; + if (mEmptyView != null) { + mList.setEmptyView(mEmptyView); + } + } + mListShown = true; + mList.setOnItemClickListener(mOnClickListener); + if (mAdapter != null) { + setListAdapter(mAdapter); + } else { + // We are starting without an adapter, so assume we won't + // have our data right away and start with the progress indicator. + setListShown(false, false); + } + mHandler.post(mRequestFocus); + } + + @Override + public void onGroupExpand(int arg0) { + // TODO Auto-generated method stub + + } + + @Override + public void onGroupCollapse(int arg0) { + // TODO Auto-generated method stub + + } + + @Override + public boolean onChildClick(ExpandableListView arg0, View arg1, int arg2, int arg3, long arg4) { + // TODO Auto-generated method stub + return false; + } + + @Override + public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) { + } + + public void onContentChanged() { + View emptyView = getView().findViewById(android.R.id.empty); + mList = (ExpandableListView) getView().findViewById(android.R.id.list); + if (mList == null) { + throw new RuntimeException( + "Your content must have a ExpandableListView whose id attribute is " + "'android.R.id.list'"); + } + if (emptyView != null) { + mList.setEmptyView(emptyView); + } + mList.setOnChildClickListener(this); + mList.setOnGroupExpandListener(this); + mList.setOnGroupCollapseListener(this); + + if (mFinishedStart) { + setListAdapter(mAdapter); + } + mFinishedStart = true; + } +} + diff --git a/android/src/net/sf/openrocket/android/util/PersistentExpandableListFragment.java b/android/src/net/sf/openrocket/android/util/PersistentExpandableListFragment.java new file mode 100644 index 000000000..1cc8e6590 --- /dev/null +++ b/android/src/net/sf/openrocket/android/util/PersistentExpandableListFragment.java @@ -0,0 +1,145 @@ +package net.sf.openrocket.android.util; + +/* + * TODO - this isn't working. + */ +import java.util.ArrayList; +import java.util.List; + +import android.os.Bundle; +import android.widget.ExpandableListAdapter; +import android.widget.ExpandableListView; + +public class PersistentExpandableListFragment extends ExpandableListFragment { + private long[] expandedIds; + + @Override + public void onCreate(Bundle savedInstanceState) { + AndroidLogWrapper.d(PersistentExpandableListFragment.class, "onCreate"); + super.onCreate(savedInstanceState); + if ( savedInstanceState != null ) { + expandedIds = savedInstanceState.getLongArray("ExpandedIds"); + } + } + + @Override + public void onStop() { + AndroidLogWrapper.d(PersistentExpandableListFragment.class, "onStop"); + super.onStop(); + expandedIds = getExpandedIds(); + } + + @Override + public void onStart() { + AndroidLogWrapper.d(PersistentExpandableListFragment.class, "onStart"); + super.onStart(); + if (this.expandedIds != null) { + restoreExpandedState(expandedIds); + } + } + + @Override + public void onPause() { + AndroidLogWrapper.d(PersistentExpandableListFragment.class, "onPause"); + super.onPause(); + expandedIds = getExpandedIds(); + } + + + @Override + public void onResume() { + AndroidLogWrapper.d(PersistentExpandableListFragment.class, "onResume"); + super.onResume(); + if (this.expandedIds != null) { + restoreExpandedState(expandedIds); + } + } + + @Override + public void onSaveInstanceState(Bundle outState) { + super.onSaveInstanceState(outState); + this.expandedIds = getExpandedIds(); + outState.putLongArray("ExpandedIds", this.expandedIds); + } + + /* + @Override + protected void onStart() { + super.onStart(); + if (this.expandedIds != null) { + restoreExpandedState(expandedIds); + } + } + + @Override + protected void onStop() { + super.onStop(); + expandedIds = getExpandedIds(); + } + + @Override + protected void onSaveInstanceState(Bundle outState) { + super.onSaveInstanceState(outState); + this.expandedIds = getExpandedIds(); + outState.putLongArray("ExpandedIds", this.expandedIds); + } + + @Override + protected void onRestoreInstanceState(Bundle state) { + super.onRestoreInstanceState(state); + long[] expandedIds = state.getLongArray("ExpandedIds"); + if (expandedIds != null) { + restoreExpandedState(expandedIds); + } + } + */ + + + private long[] getExpandedIds() { + ExpandableListView list = getExpandableListView(); + ExpandableListAdapter adapter = getExpandableListAdapter(); + if (adapter != null) { + int length = adapter.getGroupCount(); + ArrayList expandedIds = new ArrayList(); + for(int i=0; i < length; i++) { + if(list.isGroupExpanded(i)) { + expandedIds.add(adapter.getGroupId(i)); + } + } + return toLongArray(expandedIds); + } else { + return null; + } + } + + private void restoreExpandedState(long[] expandedIds) { + this.expandedIds = expandedIds; + if (expandedIds != null) { + ExpandableListView list = getExpandableListView(); + ExpandableListAdapter adapter = getExpandableListAdapter(); + if (adapter != null) { + for (int i=0; i list) { + long[] ret = new long[list.size()]; + int i = 0; + for (Long e : list) + ret[i++] = e.longValue(); + return ret; + } +}