Java tutorial
/* 2010 Stephan Reichholf <stephan at reichholf dot net> * * Licensed under the Create-Commons Attribution-Noncommercial-Share Alike 3.0 Unported * http://creativecommons.org/licenses/by-nc-sa/3.0/ */ package net.reichholf.dreamdroid.fragment; import android.app.Activity; import android.app.ProgressDialog; import android.content.ActivityNotFoundException; import android.content.Intent; import android.content.SharedPreferences; import android.os.Build; import android.os.Bundle; import android.preference.PreferenceManager; import android.support.v4.content.Loader; import android.support.v4.widget.SlidingPaneLayout; import android.support.v7.widget.PopupMenu; import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; import android.widget.AbsListView; import android.widget.AdapterView; import android.widget.AdapterView.OnItemClickListener; import android.widget.AdapterView.OnItemLongClickListener; import android.widget.BaseAdapter; import android.widget.GridView; import android.widget.ListAdapter; import android.widget.ListView; import android.widget.SimpleAdapter; import com.nostra13.universalimageloader.core.ImageLoader; import com.nostra13.universalimageloader.core.listener.PauseOnScrollListener; import net.reichholf.dreamdroid.DatabaseHelper; import net.reichholf.dreamdroid.DreamDroid; import net.reichholf.dreamdroid.Profile; import net.reichholf.dreamdroid.R; import net.reichholf.dreamdroid.adapter.ServiceListAdapter; import net.reichholf.dreamdroid.fragment.abs.AbstractHttpEventListFragment; import net.reichholf.dreamdroid.fragment.dialogs.ActionDialog; import net.reichholf.dreamdroid.fragment.dialogs.EpgDetailDialog; import net.reichholf.dreamdroid.fragment.helper.DreamDroidHttpFragmentHelper; import net.reichholf.dreamdroid.helpers.ExtendedHashMap; import net.reichholf.dreamdroid.helpers.ExtendedHashMapHelper; import net.reichholf.dreamdroid.helpers.Statics; import net.reichholf.dreamdroid.helpers.SyncService; import net.reichholf.dreamdroid.helpers.enigma2.Event; import net.reichholf.dreamdroid.helpers.enigma2.Service; import net.reichholf.dreamdroid.helpers.enigma2.URIStore; import net.reichholf.dreamdroid.helpers.enigma2.requesthandler.AbstractListRequestHandler; import net.reichholf.dreamdroid.helpers.enigma2.requesthandler.EpgNowNextListRequestHandler; import net.reichholf.dreamdroid.helpers.enigma2.requesthandler.EventListRequestHandler; import net.reichholf.dreamdroid.helpers.enigma2.requesthandler.ServiceListRequestHandler; import net.reichholf.dreamdroid.intents.IntentFactory; import net.reichholf.dreamdroid.loader.AsyncListLoader; import net.reichholf.dreamdroid.loader.LoaderResult; import org.apache.http.NameValuePair; import org.apache.http.message.BasicNameValuePair; import java.io.Serializable; import java.util.ArrayList; import java.util.HashMap; /** * Handles ServiceLists of (based on service references). * * If called with Intent.ACTION_PICK it can be used for selecting services (e.g. * to set a timer).<br/> * In Pick-Mode no EPG will be loaded/shown.<br/> * For any other action it will be a full-featured ServiceList Browser capable * of showing EPG of running events or calling a * <code>ServiceEpgListActivity</code> to show the whole EPG of a service * * @author sreichholf * */ public class ServiceListFragment extends AbstractHttpEventListFragment implements ActionDialog.DialogActionListener { private static final int LOADER_BOUQUETLIST_ID = 1; public static final String SERVICE_REF_ROOT = "root"; public static final String BUNDLE_KEY_CURRENT_SERVICE = "currentService"; public static final String BUNDLE_KEY_NAVNAME = "navname"; public static final String BUNDLE_KEY_NAVREFERENCE = "navreference"; public static final String BUNDLE_KEY_DETAILNAME = "detailname"; public static final String BUNDLE_KEY_DETAILREFERENCE = "detailreference"; public static final String BUNDLE_KEY_HISTORY = "history"; public static final String BUNDLE_KEY_NAVITEMS = "navitems"; public static final String BUNDLE_KEY_DETAILITEMS = "detailitems"; private boolean mPickMode; private boolean mReload; private ListView mNavList; private AbsListView mDetailList; private View mEmpty; private ProgressDialog mProgress; private String mBaseTitle; private String mCurrentTitle; private String mNavReference; private String mNavName; private String mDetailReference; private String mDetailName; private ArrayList<ExtendedHashMap> mHistory; private Bundle mExtras; private ExtendedHashMap mData; private ArrayList<ExtendedHashMap> mNavItems; private ArrayList<ExtendedHashMap> mDetailItems; private ExtendedHashMap mCurrentService; private SlidingPaneLayout mSlidingPane; private ArrayList<NameValuePair> mNavHttpParams; private ArrayList<NameValuePair> mDetailHttpParams; @SuppressWarnings("unchecked") @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); mCurrentTitle = mBaseTitle = getString(R.string.services); mReload = true; Bundle args = getArguments(); String mode = null; if (args != null) { mode = args.getString("action"); } if (Intent.ACTION_PICK.equals(mode)) { mPickMode = true; } else { mPickMode = false; } if (savedInstanceState != null && !mPickMode) { mNavName = savedInstanceState.getString(BUNDLE_KEY_NAVNAME); mNavReference = savedInstanceState.getString(BUNDLE_KEY_NAVREFERENCE); mDetailName = savedInstanceState.getString(BUNDLE_KEY_DETAILNAME); mDetailReference = savedInstanceState.getString(BUNDLE_KEY_DETAILREFERENCE); mHistory = ExtendedHashMapHelper.restoreListFromBundle(savedInstanceState, BUNDLE_KEY_HISTORY); mNavItems = ExtendedHashMapHelper.restoreListFromBundle(savedInstanceState, BUNDLE_KEY_NAVITEMS); mDetailItems = ExtendedHashMapHelper.restoreListFromBundle(savedInstanceState, BUNDLE_KEY_DETAILITEMS); mCurrentService = ExtendedHashMapHelper.restoreFromBundle(savedInstanceState, BUNDLE_KEY_CURRENT_SERVICE); mReload = false; } else { mHistory = new ArrayList<ExtendedHashMap>(); if (!SERVICE_REF_ROOT.equals(mNavReference)) { ExtendedHashMap map = new ExtendedHashMap(); map.put(Event.KEY_SERVICE_REFERENCE, mNavReference); map.put(Event.KEY_SERVICE_NAME, mNavName); mHistory.add(map); mExtras = getArguments(); mNavItems = new ArrayList<ExtendedHashMap>(); mDetailItems = new ArrayList<ExtendedHashMap>(); } } if (mDetailReference == null) { mDetailReference = DreamDroid.getCurrentProfile().getDefaultRef(); mDetailName = DreamDroid.getCurrentProfile().getDefaultRefName(); } // if( mNavReference == null ){ // mNavReference = DreamDroid.getCurrentProfile().getDefaultRef2(); // mNavName = DreamDroid.getCurrentProfile().getDefaultRef2Name(); // } if (mExtras != null) { HashMap<String, Object> map = (HashMap<String, Object>) mExtras.getSerializable("data"); if (map != null) { mData = new ExtendedHashMap(); mData.putAll(map); } } else { mExtras = new Bundle(); } } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View v = inflater.inflate(R.layout.dual_list_view, null, false); mEmpty = v.findViewById(android.R.id.empty); mNavList = (ListView) v.findViewById(android.R.id.list); mDetailList = (AbsListView) v.findViewById(R.id.list2); // Some may call this a Hack, but I think it a proper solution // On devices with resolutions other than xlarge, there is no second // ListView (@id/listView2). // So we just use the only one available and the rest will work as // normal with almost no additional adjustments. if (mDetailList == null) { mDetailList = mNavList; mDetailItems = mNavItems; } if (GridView.class.isInstance(mDetailList)) { SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getActionBarActivity()); ((GridView) mDetailList).setNumColumns(Integer.parseInt( prefs.getString(DreamDroid.PREFS_KEY_GRID_MAX_COLS, Integer.toString(GridView.AUTO_FIT)))); } mNavList.setFastScrollEnabled(true); mDetailList.setFastScrollEnabled(true); PauseOnScrollListener listener = new PauseOnScrollListener(ImageLoader.getInstance(), false, true); mDetailList.setOnScrollListener(listener); mSlidingPane = (SlidingPaneLayout) v.findViewById(R.id.sliding_pane); mSlidingPane.setPanelSlideListener(new SlidingPaneLayout.PanelSlideListener() { @Override public void onPanelSlide(View panel, float slideOffset) { } @Override public void onPanelOpened(View panel) { mNavList.setEnabled(true); } @Override public void onPanelClosed(View panel) { mNavList.setEnabled(false); } }); if (mDetailReference == null || "".equals(mDetailReference)) mSlidingPane.openPane(); setAdapter(); return v; } /** * @param key * @return */ public String getDataForKey(String key) { if (mData != null) { return (String) mData.get(key); } return null; } /** * @param key * @param dfault * @return */ public String getDataForKey(String key, String dfault) { if (mData != null) { String str = (String) mData.get(key); if (str != null) { return str; } } return dfault; } @Override public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); getActionBarActivity().supportInvalidateOptionsMenu(); getActionBarActivity().setTitle(mCurrentTitle); mNavList.setOnItemClickListener(new OnItemClickListener() { @Override public void onItemClick(AdapterView<?> a, View v, int position, long id) { onListItemClick((AbsListView) a, v, position, id); } }); mDetailList.setOnItemClickListener(new OnItemClickListener() { @Override public void onItemClick(AdapterView<?> a, View v, int position, long id) { onListItemClick((AbsListView) a, v, position, id); } }); mNavList.setOnItemLongClickListener(new OnItemLongClickListener() { @Override public boolean onItemLongClick(AdapterView<?> a, View v, int position, long id) { return onListItemLongClick((ListView) a, v, position, id); } }); mDetailList.setOnItemLongClickListener(new OnItemLongClickListener() { @Override public boolean onItemLongClick(AdapterView<?> a, View v, int position, long id) { return onListItemLongClick((AbsListView) a, v, position, id); } }); if (mReload) { loadNavRoot(); reloadDetail(false); } else { getActionBarActivity().setTitle(mDetailName); } } @Override public void onSaveInstanceState(Bundle outState) { outState.putString(BUNDLE_KEY_NAVNAME, mNavName); outState.putString(BUNDLE_KEY_NAVREFERENCE, mNavReference); outState.putString(BUNDLE_KEY_DETAILNAME, mDetailName); outState.putString(BUNDLE_KEY_DETAILREFERENCE, mDetailReference); outState.putSerializable(BUNDLE_KEY_HISTORY, mHistory); outState.putSerializable(BUNDLE_KEY_NAVITEMS, mNavItems); outState.putSerializable(BUNDLE_KEY_DETAILITEMS, mDetailItems); outState.putParcelable(BUNDLE_KEY_CURRENT_SERVICE, mCurrentService); super.onSaveInstanceState(outState); } @Override public void onResume() { super.onResume(); } public String genWindowTitle(String title) { return title + " - " + mNavName; } /** * */ private void setAdapter() { ListAdapter adapter; if (!mNavList.equals(mDetailList)) { adapter = new SimpleAdapter(getActionBarActivity(), mNavItems, android.R.layout.simple_list_item_1, new String[] { Event.KEY_SERVICE_NAME }, new int[] { android.R.id.text1 }); mNavList.setAdapter(adapter); } adapter = new ServiceListAdapter(getActionBarActivity(), mDetailItems); if (Build.VERSION.SDK_INT < 11) { ((ListView) mDetailList).setAdapter(adapter); } else { mDetailList.setAdapter(adapter); } } public void onListItemClick(AbsListView l, View v, int position, long id) { onListItemClick(l, v, position, id, false); } /** * @param l * @param v * @param position * @param id * @return */ protected boolean onListItemLongClick(AbsListView l, View v, int position, long id) { onListItemClick(l, v, position, id, true); return true; } public void checkMenuReload(Menu menu, MenuInflater inflater) { SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getActionBarActivity()); if (sp.getBoolean("disable_fab_reload", false)) { detachFabReload(); inflater.inflate(R.menu.reload, menu); } else { connectFabReload(getView(), mDetailList); } } @Override public void createOptionsMenu(Menu menu, MenuInflater inflater) { checkMenuReload(menu, inflater); inflater.inflate(R.menu.servicelist, menu); } @Override public void onPrepareOptionsMenu(Menu menu) { if (getMultiPaneHandler().isDrawerOpen()) return; MenuItem setDefault = menu.findItem(R.id.menu_default); String defaultReference = DreamDroid.getCurrentProfile().getDefaultRef(); setDefault.setVisible(true); if (defaultReference != null) { if (defaultReference.equals(mDetailReference)) { setDefault.setIcon(R.drawable.ic_action_fav); setDefault.setTitle(R.string.reset_default); } else { setDefault.setIcon(R.drawable.ic_action_nofav); setDefault.setTitle(R.string.set_default); } } } @Override protected boolean onItemSelected(int id) { switch (id) { case Statics.ITEM_OVERVIEW: if (!mSlidingPane.isOpen()) { mSlidingPane.openPane(); return true; } if ((mSlidingPane.isOpen() || !mSlidingPane.isSlideable()) && mNavReference != SERVICE_REF_ROOT) { mNavReference = SERVICE_REF_ROOT; mNavName = (String) getText(R.string.bouquet_overview); reloadNav(); return true; } mSlidingPane.closePane(); return true; case Statics.ITEM_SET_DEFAULT: if (mDetailReference != null || mNavReference != null) { Profile p = DreamDroid.getCurrentProfile(); boolean reset = false; if (p.getDefaultRef() != null && p.getDefaultRef().equals(mDetailReference)) { p.setDefaultRef(null); reset = true; } if (p.getDefaultRef2() != null && p.getDefaultRef2().equals(mNavReference)) { p.setDefaultRef2(null); reset = true; } if (!reset) { if (mDetailReference != null) p.setDefaultRefValues(mDetailReference, mDetailName); if (mNavReference != null) p.setDefaultRef2Values(mNavReference, mNavName); } DatabaseHelper dbh = DatabaseHelper.getInstance(getActionBarActivity()); if (dbh.updateProfile(p)) { if (!reset) showToast(getText(R.string.default_bouquet_set_to) + " '" + mDetailName + "'"); } else { showToast(getText(R.string.default_bouquet_not_set)); } } else { showToast(getText(R.string.default_bouquet_not_set)); } getActionBarActivity().supportInvalidateOptionsMenu(); return true; case Statics.ITEM_SYNC_EPG: syncEpg(); return true; default: return super.onItemSelected(id); } } private void syncEpg() { Intent intent = new Intent(getActivity().getApplicationContext(), SyncService.class); intent.putExtra(Event.KEY_SERVICE_REFERENCE, mDetailReference); getActivity().startService(intent); } @Override public ArrayList<NameValuePair> getHttpParams(int loader) { switch (loader) { case DreamDroidHttpFragmentHelper.LOADER_DEFAULT_ID: return mDetailHttpParams; case LOADER_BOUQUETLIST_ID: return mNavHttpParams; default: return super.getHttpParams(loader); } } @Override public Loader<LoaderResult<ArrayList<ExtendedHashMap>>> onCreateLoader(int id, Bundle args) { AbstractListRequestHandler handler; if (id == LOADER_BOUQUETLIST_ID) { handler = new ServiceListRequestHandler(); } else { if (DreamDroid.featureNowNext()) handler = new EpgNowNextListRequestHandler(); else handler = new EventListRequestHandler(URIStore.EPG_NOW); } return new AsyncListLoader(getActionBarActivity(), handler, true, args); } @Override public void onLoadFinished(Loader<LoaderResult<ArrayList<ExtendedHashMap>>> loader, LoaderResult<ArrayList<ExtendedHashMap>> result) { getActionBarActivity().supportInvalidateOptionsMenu(); if (loader.getId() == LOADER_BOUQUETLIST_ID) { mNavItems.clear(); ((BaseAdapter) mNavList.getAdapter()).notifyDataSetChanged(); } else { mDetailItems.clear(); ((BaseAdapter) mDetailList.getAdapter()).notifyDataSetChanged(); } String title = mNavName; if (isDetailAvail()) title = mDetailName; mHttpHelper.finishProgress(title); if (result.isError()) { setEmptyText(result.getErrorText()); return; } ArrayList<ExtendedHashMap> list = result.getResult(); if (list == null) { showToast(getString(R.string.error)); return; } if (loader.getId() == LOADER_BOUQUETLIST_ID) { mNavItems.addAll(list); ((BaseAdapter) mNavList.getAdapter()).notifyDataSetChanged(); } else { mEmpty.setVisibility(View.GONE); mDetailList.setVisibility(View.VISIBLE); mDetailItems.addAll(list); ((BaseAdapter) mDetailList.getAdapter()).notifyDataSetChanged(); } } /** * @param ref * The ServiceReference to catch the EPG for * @param nam * The name of the Service for the reference */ public void openEpg(String ref, String nam) { ServiceEpgListFragment f = new ServiceEpgListFragment(); ExtendedHashMap map = new ExtendedHashMap(); map.put(Event.KEY_SERVICE_REFERENCE, ref); map.put(Event.KEY_SERVICE_NAME, nam); Bundle args = new Bundle(); args.putSerializable(sData, map); f.setArguments(args); getMultiPaneHandler().showDetails(f, true); } /** * @param l * @param v * @param position * @param id * @param isLong */ private void onListItemClick(AbsListView l, View v, int position, long id, boolean isLong) { @SuppressWarnings("unchecked") ExtendedHashMap item = new ExtendedHashMap((HashMap<String, Object>) l.getItemAtPosition(position)); final String ref = item.getString(Event.KEY_SERVICE_REFERENCE); final String nam = item.getString(Event.KEY_SERVICE_NAME); if (Service.isBouquet(ref)) { if (l.equals(mNavList)) { // without FROM it's a "all" reference if (SERVICE_REF_ROOT.equals(mNavReference) && ref.toUpperCase().contains("FROM")) { ExtendedHashMap map = new ExtendedHashMap(); map.put(Event.KEY_SERVICE_REFERENCE, String.valueOf(ref)); map.put(Event.KEY_SERVICE_NAME, String.valueOf(nam)); mHistory.add(map); mNavReference = ref; mNavName = nam; mNavList.setSelectionAfterHeaderView(); reloadNav(); } else { mDetailReference = ref; mDetailName = nam; // mDetailList.setSelectionAfterHeaderView(); reloadDetail(false); } } mBaseTitle = nam; } else { // It's a listitem in the servicelist if (mPickMode) { ExtendedHashMap map = new ExtendedHashMap(); map.put(Event.KEY_SERVICE_REFERENCE, ref); map.put(Event.KEY_SERVICE_NAME, nam); Intent intent = new Intent(); intent.putExtra(sData, (Serializable) map); finish(Activity.RESULT_OK, intent); } else { boolean instantZap = PreferenceManager.getDefaultSharedPreferences(getActionBarActivity()) .getBoolean("instant_zap", false); if ((instantZap && !isLong) || (!instantZap && isLong)) { zapTo(ref); } else { mCurrentService = item; showPopupMenu(v); } } } } public void showPopupMenu(View v) { PopupMenu menu = new PopupMenu(getActionBarActivity(), v); menu.getMenuInflater().inflate(R.menu.popup_servicelist, menu.getMenu()); menu.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() { @Override public boolean onMenuItemClick(MenuItem menuItem) { String ref = mCurrentService.getString(Service.KEY_REFERENCE); String name = mCurrentService.getString(Service.KEY_NAME); switch (menuItem.getItemId()) { case R.id.menu_current_event: Bundle args = new Bundle(); args.putParcelable("currentItem", mCurrentService); getMultiPaneHandler().showDialogFragment(EpgDetailDialog.class, args, "epg_detail_dialog"); break; case R.id.menu_browse_epg: openEpg(ref, name); break; case R.id.menu_zap: zapTo(ref); break; case R.id.menu_stream: try { startActivity(IntentFactory.getStreamServiceIntent(ref, name)); } catch (ActivityNotFoundException e) { showToast(getText(R.string.missing_stream_player)); } break; default: return false; } return true; } }); menu.show(); } public void reloadNav() { reload(mNavReference, true); } public void reloadDetail(boolean keepCurrent) { if (mDetailReference != null && !"".equals(mDetailReference)) { // Hide ListView show empty/progress if (!keepCurrent) { setEmptyText(getString(R.string.loading)); mEmpty.setVisibility(View.VISIBLE); mDetailList.setVisibility(View.GONE); getActionBarActivity().setTitle(mDetailName); } reload(mDetailReference, false); } else { setEmptyText(getString(R.string.no_list_item)); } } @Override protected void reload() { reloadDetail(true); } public void reload(String ref, boolean isBouquetList) { mReload = false; mHttpHelper.onLoadStarted(); ExtendedHashMap data = new ExtendedHashMap(); data.put(Event.KEY_SERVICE_REFERENCE, String.valueOf(ref)); data.put(Event.KEY_SERVICE_NAME, String.valueOf(ref)); mExtras.putSerializable(sData, data); ArrayList<NameValuePair> params = new ArrayList<NameValuePair>(); if (isBouquetList || mPickMode) { mSlidingPane.openPane(); if (ref.equals(SERVICE_REF_ROOT)) { loadNavRoot(); mHttpHelper.onLoadFinished(); return; } params.add(new BasicNameValuePair("sRef", ref)); mNavHttpParams = params; mHttpHelper.reload(LOADER_BOUQUETLIST_ID); } else { if (DreamDroid.checkInitial(getActionBarActivity(), DreamDroid.INITIAL_SERVICELIST_PANE)) { mSlidingPane.openPane(); DreamDroid.setNotInitial(getActionBarActivity(), DreamDroid.INITIAL_SERVICELIST_PANE); } else { mSlidingPane.closePane(); } params.add(new BasicNameValuePair("bRef", ref)); mDetailHttpParams = params; mHttpHelper.reload(DreamDroidHttpFragmentHelper.LOADER_DEFAULT_ID); } } public void loadNavRoot() { getActionBarActivity().setTitle(getString(R.string.services)); mNavItems.clear(); String[] servicelist = getResources().getStringArray(R.array.servicelist); String[] servicerefs = getResources().getStringArray(R.array.servicerefs); for (int i = 0; i < servicelist.length; i++) { ExtendedHashMap map = new ExtendedHashMap(); map.put(Event.KEY_SERVICE_NAME, servicelist[i]); map.put(Event.KEY_SERVICE_REFERENCE, servicerefs[i]); mNavItems.add(map); } mNavReference = SERVICE_REF_ROOT; mNavName = ""; getActionBarActivity().supportInvalidateOptionsMenu(); ((BaseAdapter) mNavList.getAdapter()).notifyDataSetChanged(); } @Override public void onSimpleResult(boolean success, ExtendedHashMap result) { if (mProgress != null) { if (mProgress.isShowing()) { mProgress.dismiss(); } } super.onSimpleResult(success, result); } protected boolean isDetailAvail() { return !(mDetailReference == null) && !"".equals(mDetailReference.trim()); } /* * (non-Javadoc) * * @see net.reichholf.dreamdroid.fragment.dialogs.PrimitiveDialog. * DialogActionListener#onDialogAction(int) */ @Override public void onDialogAction(int action, Object details, String dialogTag) { switch (action) { case Statics.ACTION_SET_TIMER: setTimerById(mCurrentService); break; case Statics.ACTION_EDIT_TIMER: setTimerByEventData(mCurrentService); break; case Statics.ACTION_FIND_SIMILAR: mHttpHelper.findSimilarEvents(mCurrentService); break; case Statics.ACTION_IMDB: IntentFactory.queryIMDb(getActionBarActivity(), mCurrentService); break; } } }