/* * GeoSolutions - MapstoreMobile - GeoSpatial Framework on Android based devices * Copyright (C) 2014 GeoSolutions (www.geo-solutions.it) * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package it.geosolutions.geocollect.android.core.form; import it.geosolutions.android.map.fragment.MapFragment; import it.geosolutions.geocollect.android.app.BuildConfig; import it.geosolutions.geocollect.android.app.R; import it.geosolutions.geocollect.android.core.form.action.AndroidAction; import it.geosolutions.geocollect.android.core.form.action.CameraAction; import it.geosolutions.geocollect.android.core.form.utils.FormBuilder; import it.geosolutions.geocollect.android.core.form.utils.FormUtils; import it.geosolutions.geocollect.android.core.mission.Mission; import it.geosolutions.geocollect.android.core.mission.utils.MissionUtils; import it.geosolutions.geocollect.android.core.mission.utils.PersistenceUtils; import it.geosolutions.geocollect.android.core.widgets.UILImageAdapter; import it.geosolutions.geocollect.model.config.MissionTemplate; import it.geosolutions.geocollect.model.viewmodel.Field; import it.geosolutions.geocollect.model.viewmodel.FormAction; import it.geosolutions.geocollect.model.viewmodel.Page; import it.geosolutions.geocollect.model.viewmodel.type.XType; import android.app.Activity; import android.content.Intent; import android.os.Bundle; import android.support.v4.app.LoaderManager.LoaderCallbacks; import android.support.v4.content.AsyncTaskLoader; import android.support.v4.content.Loader; import android.support.v4.view.ViewPager.LayoutParams; import android.util.Log; import android.view.Gravity; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.GridView; import android.widget.FrameLayout; import android.widget.LinearLayout; import android.widget.ProgressBar; import android.widget.ScrollView; import android.widget.Toast; import com.actionbarsherlock.view.Menu; import com.actionbarsherlock.view.MenuInflater; import com.actionbarsherlock.view.MenuItem; import com.nostra13.universalimageloader.core.ImageLoader; /** * This Fragment contains form field for a page of the <Form>. * * @author Lorenzo Natali (lorenzo.natali@geo-solutions.it) * */ public class FormPageFragment extends MapFragment implements LoaderCallbacks<Void>{ /** * Tag for logs */ public static final String TAG = "FormPage"; /** * The argument for the page */ public static final String ARG_OBJECT = "Page"; public static final String ARG_MISSION = "MISSION"; private ScrollView mScrollView; private Page page; private LinearLayout mFormView; private ProgressBar mProgressView; private boolean mDone; private Mission mission; private boolean visibleToUser; /** * Reference to the ImageLoader instance * Has value only if this page contains a Photo gallery */ ImageLoader imageLoader; @Override public void onAttach(Activity activity) { super.onAttach(activity); Log.d(TAG, "onAttach(): activity = " + activity); } @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); Mission m = (Mission) getActivity().getIntent().getExtras().getSerializable(ARG_MISSION); mission = m; Log.d(TAG, "onCreate(): savedInstanceState = " + savedInstanceState); Integer pageNumber = (Integer) getArguments().get(ARG_OBJECT); if(pageNumber!=null){ MissionTemplate t = MissionUtils.getDefaultTemplate(getActivity()); //if page number exists i suppose pages is not empty page = t.sop_form.pages.get(pageNumber); } if(savedInstanceState !=null){ mission = (Mission)savedInstanceState.getSerializable(ARG_MISSION); } //This allow form fragments to // display actions in the action bar setHasOptionsMenu(true); } @Override public void onCreateOptionsMenu( Menu menu, MenuInflater inflater) { // add actions from the page configuration if(this.page.actions == null) return; //add actions associated to the page for(int i = 0;i< this.page.actions.size();i++){ FormAction a =this.page.actions.get(i); MenuItem item = menu.add(Menu.NONE, a.id , Menu.NONE, a.text); item.setIcon(FormUtils.getDrawable(a.iconCls)); item.setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS); Log.v("ACTION","added action"+ a.name); } super.onCreateOptionsMenu(menu,inflater); } /* (non-Javadoc) * @see com.actionbarsherlock.app.SherlockFragment#onOptionsItemSelected(com.actionbarsherlock.view.MenuItem) */ @Override public boolean onOptionsItemSelected(MenuItem item) { int id = item.getItemId(); //search for the action using the id (the index should not be supported if(this.page.actions !=null){ for(FormAction a : this.page.actions){ if(id == a.id){ performAction(a); } } } return super.onOptionsItemSelected(item); } /** * Performs and <Action> in the current page. * This function is call when the user tap an action * @param a */ private void performAction(FormAction a) { Log.v("ACTION","performing action "+a); AndroidAction aa = FormUtils.getAndroidAction(a); if(aa!=null){ aa.performAction(this, a, mission, page); } } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { Log.d(TAG, "onCreateView(): container = " + container + "savedInstanceState = " + savedInstanceState); if (mScrollView == null) { // normally inflate the view hierarchy mScrollView = (ScrollView) inflater.inflate(R.layout.form_page_fragment, container, false); mFormView = (LinearLayout) mScrollView.findViewById(R.id.formcontent); mProgressView = (ProgressBar) mScrollView .findViewById(R.id.loading); } else { // mScrollView is still attached to the previous view hierarchy // we need to remove it and re-attach it to the current one ViewGroup parent = (ViewGroup) mScrollView.getParent(); parent.removeView(mScrollView); } return mScrollView; } /** * Creates the page content cycling the page fields */ private void buildForm() { if(BuildConfig.DEBUG){ Log.d(TAG, "buildForm()"); } // if the view hierarchy was already build, skip this if (mDone){ return; } FormBuilder.buildForm(getActivity(), this.mFormView, page.fields, mission);//TODO page is not enough, some data should be accessible like constants and data // It is safe to initialize field here because buildForm is a callback of the onActivityCreated(); PersistenceUtils.loadPageData(page, mFormView, mission, getActivity(),true); // TODO: add a timer and start an animation for the tutorial if(page.attributes != null && page.attributes.containsKey("tutorial")){ if ( page.attributes.get("tutorial") != null && page.attributes.get("tutorial") instanceof Boolean && (Boolean) page.attributes.get("tutorial")){ Log.v(TAG, "Showing tutorial"); // create new Layout FrameLayout overlayFramelayout = new FrameLayout(getSherlockActivity()); View view = getSherlockActivity().getLayoutInflater().inflate( R.layout.swipe_overlay, overlayFramelayout, false ); overlayFramelayout.addView(view); // Viewpager layoutparams LayoutParams layoutParams = new LayoutParams(); layoutParams.gravity = Gravity.BOTTOM; //getSherlockActivity().addContentView(overlayFramelayout, layoutParams); this.mFormView.addView(overlayFramelayout, layoutParams); } } // the view hierarchy is now complete mDone = true; // TODO: merge this code block with the previous "tutorial" if(visibleToUser && page.attributes != null && page.attributes.containsKey("message")){ Toast.makeText(getSherlockActivity(), (String) page.attributes.get("message"), Toast.LENGTH_LONG).show(); } } @Override public void setMenuVisibility(boolean menuVisible) { super.setMenuVisibility(menuVisible); visibleToUser = menuVisible; if(imageLoader != null && imageLoader.isInited()){ if(menuVisible) imageLoader.resume(); else imageLoader.pause(); } } @Override public void onSaveInstanceState(Bundle outState) { outState.putSerializable(ARG_MISSION, mission); PersistenceUtils.storePageData(page, mFormView, mission); } @Override public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); Log.d(TAG, "onActivityCreated(): savedInstanceState = " + savedInstanceState); toggleLoading(true); getLoaderManager().restartLoader(0, null, this); } public Loader<Void> onCreateLoader(int id, Bundle args) { Log.d(TAG, "onCreateLoader(): id=" + id); Loader<Void> loader = new AsyncTaskLoader<Void>(getActivity()) { @Override public Void loadInBackground() { Activity activity = getSherlockActivity(); Mission m = (Mission) getActivity().getIntent().getExtras().getSerializable(ARG_MISSION);//TODO investigate sometimes m is null if(m!=null){ m.setTemplate(MissionUtils.getDefaultTemplate(activity)); if(activity instanceof FormEditActivity){ Log.d(TAG, "Loader: Connecting to Activity database"); m.db = ((FormEditActivity)activity).spatialiteDatabase; }else{ Log.w(TAG, "Loader: Could not connect to Activity database"); } mission =m; return null; }else{ //TODO notify error Toast.makeText(getActivity(), R.string.error_getting_data_from_database, Toast.LENGTH_LONG).show(); getActivity().finish(); return null; } } }; //TODO create loader; loader.forceLoad(); return loader; } /** * Handle the results of the CameraAction */ @Override public void onActivityResult(int requestCode, int resultCode, Intent data) { Log.d(TAG, "onActivityResult(): "+requestCode); super.onActivityResult(requestCode, resultCode, data); if(requestCode == CameraAction.CAPTURE_IMAGE_ACTIVITY_REQUEST_CODE && resultCode == Activity.RESULT_OK){ String originIDString = MissionUtils.getMissionGCID(this.mission); if( this.page.fields != null && originIDString != null && !originIDString.isEmpty()){ for(Field f : page.fields){ if(f == null || f.xtype != XType.photo) continue; // TODO: use a non-string tag GridView grid = (GridView) this.mFormView.findViewWithTag("__photo__"); if( grid != null && ImageLoader.getInstance().isInited()){ //((UILImageAdapter)grid.getAdapter()).setImageUrls(FormUtils.getPhotoUriStrings(this.mission.getOrigin().id)); ((UILImageAdapter)grid.getAdapter()).notifyDataSetChanged(); } break; } } } } /** * */ public void onLoadFinished(Loader<Void> id, Void result) { Log.d(TAG, "onLoadFinished(): id=" + id); toggleLoading(false); buildForm(); for(Field f : page.fields){ if(f == null || f.xtype != XType.photo) continue; imageLoader = ImageLoader.getInstance(); break; } } public void onLoaderReset(Loader<Void> loader) { Log.d(TAG, "onLoaderReset(): id=" + loader.getId()); } private void toggleLoading(boolean show) { mProgressView.setVisibility(show ? View.VISIBLE : View.GONE); mFormView.setGravity(show ? Gravity.CENTER : Gravity.TOP); } @Override public void onStop() { super.onStop(); Log.d(TAG, "onStop()"); //PersistenceUtils.storePageData(page, mFormView, mission); if(imageLoader != null){ imageLoader.stop(); } } @Override public void onPause() { super.onPause(); if(BuildConfig.DEBUG){ Log.d(TAG, "onPause()"); } if(imageLoader != null && imageLoader.isInited()){ imageLoader.pause(); } PersistenceUtils.storePageData(page, mFormView, mission); } @Override public void onDestroyView() { super.onDestroyView(); Log.d(TAG, "onDestroyView()"); if(imageLoader != null){ imageLoader.destroy(); } } @Override public void onDestroy() { super.onDestroy(); Log.d(TAG, "onDestroy()"); } @Override public void onDetach() { super.onDetach(); Log.d(TAG, "onDetach()"); } @Override public void onResume() { super.onResume(); if(imageLoader != null && imageLoader.isInited()){ imageLoader.resume(); } } /** * returns the formView */ public LinearLayout getFormView(){ return this.mFormView; } }