/* * Copyright (C) 2011 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.rubika.aotalk.aou; import java.io.IOException; import java.io.StringReader; import java.io.UnsupportedEncodingException; import java.text.Collator; import java.util.ArrayList; import java.util.Comparator; import java.util.List; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import org.apache.http.HttpEntity; import org.apache.http.HttpResponse; import org.apache.http.client.ClientProtocolException; import org.apache.http.client.methods.HttpPost; import org.apache.http.impl.client.DefaultHttpClient; import org.apache.http.util.EntityUtils; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import org.xml.sax.InputSource; import org.xml.sax.SAXException; import com.actionbarsherlock.app.SherlockListFragment; import com.actionbarsherlock.view.Menu; import com.actionbarsherlock.view.MenuInflater; import com.google.analytics.tracking.android.EasyTracker; import com.google.analytics.tracking.android.Tracker; import com.rubika.aotalk.AOTalk; import com.rubika.aotalk.R; import com.rubika.aotalk.item.AouGuide; import com.rubika.aotalk.util.Logging; import com.rubika.aotalk.util.Statics; import android.content.Context; import android.content.Intent; import android.content.pm.ActivityInfo; import android.content.res.Configuration; import android.content.res.Resources; import android.os.Bundle; import android.preference.PreferenceManager; import android.support.v4.app.LoaderManager; import android.support.v4.content.AsyncTaskLoader; import android.support.v4.content.Loader; import android.text.Html; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.view.animation.Animation; import android.view.animation.ScaleAnimation; import android.widget.ArrayAdapter; import android.widget.ListView; import android.widget.TextView; /** * Demonstration of the implementation of a custom Loader. */ public class FragmentGuides extends SherlockListFragment implements LoaderManager.LoaderCallbacks<List<AouGuide>> { private static final String APP_TAG = "--> The Leet :: FragmentGuides"; private ListAdapter mAdapter; private static Tracker tracker; private static AOU aou; private Bundle extras; public static FragmentGuides newInstance(AOU a, String search) { FragmentGuides f = new FragmentGuides(); Bundle args = new Bundle(); args.putString("search", search); f.setArguments(args); aou = a; return f; } @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); EasyTracker.getInstance().setContext(AOTalk.getContext()); tracker = EasyTracker.getTracker(); } /** * Perform alphabetical comparison of application entry objects. */ public static final Comparator<AouGuide> ALPHA_COMPARATOR = new Comparator<AouGuide>() { private final Collator sCollator = Collator.getInstance(); @Override public int compare(AouGuide object1, AouGuide object2) { return sCollator.compare(object1.getLabel(), object2.getLabel()); } }; /** * Helper for determining if the configuration has changed in an interesting * way so we need to rebuild the app list. */ public static class InterestingConfigChanges { final Configuration mLastConfiguration = new Configuration(); int mLastDensity; boolean applyNewConfig(Resources res) { int configChanges = mLastConfiguration.updateFrom(res.getConfiguration()); boolean densityChanged = mLastDensity != res.getDisplayMetrics().densityDpi; if (densityChanged || (configChanges&(ActivityInfo.CONFIG_LOCALE |ActivityInfo.CONFIG_UI_MODE|ActivityInfo.CONFIG_SCREEN_LAYOUT)) != 0) { mLastDensity = res.getDisplayMetrics().densityDpi; return true; } return false; } } public static class ListLoader extends AsyncTaskLoader<List<AouGuide>> { List<AouGuide> dataList; ListAdapter adapter; Document folders = null; final InterestingConfigChanges mLastConfig = new InterestingConfigChanges(); public ListLoader(Context context, ListAdapter adapter) { super(context); this.adapter = adapter; } @Override public List<AouGuide> loadInBackground() { long loadTime = System.currentTimeMillis(); String searchUrl = null; if (adapter.getSearchString() != null && adapter.getSearchString().length() > 0) { searchUrl = String.format(Statics.GUIDES_SEARCH_URL, adapter.getSearchString()); } List<AouGuide> items = new ArrayList<AouGuide>(); String xml = null; Document doc = null; if (folders == null && searchUrl == null) { try { DefaultHttpClient httpClient = new DefaultHttpClient(); HttpPost httpPost = new HttpPost(Statics.GUIDES_FOLDERS_URL); HttpResponse httpResponse = httpClient.execute(httpPost); HttpEntity httpEntity = httpResponse.getEntity(); xml = EntityUtils.toString(httpEntity); } catch (UnsupportedEncodingException e) { Logging.log(APP_TAG, e.getMessage()); } catch (ClientProtocolException e) { Logging.log(APP_TAG, e.getMessage()); } catch (IOException e) { Logging.log(APP_TAG, e.getMessage()); } if (xml != null) { DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); try { DocumentBuilder db = dbf.newDocumentBuilder(); InputSource is = new InputSource(); is.setCharacterStream(new StringReader(xml)); folders = db.parse(is); } catch (ParserConfigurationException e) { Logging.log(APP_TAG, e.getMessage()); return null; } catch (SAXException e) { Logging.log(APP_TAG, e.getMessage()); return null; } catch (IOException e) { Logging.log(APP_TAG, e.getMessage()); return null; } } } try { DefaultHttpClient httpClient = new DefaultHttpClient(); HttpPost httpPost; if (searchUrl != null) { httpPost = new HttpPost(String.format(Statics.GUIDES_SEARCH_URL, adapter.getSearchString())); } else { httpPost = new HttpPost(String.format(Statics.GUIDES_FOLDER_URL, adapter.getFolder())); } HttpResponse httpResponse = httpClient.execute(httpPost); HttpEntity httpEntity = httpResponse.getEntity(); xml = EntityUtils.toString(httpEntity); } catch (UnsupportedEncodingException e) { Logging.log(APP_TAG, e.getMessage()); } catch (ClientProtocolException e) { Logging.log(APP_TAG, e.getMessage()); } catch (IOException e) { Logging.log(APP_TAG, e.getMessage()); } if (xml != null) { DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); try { DocumentBuilder db = dbf.newDocumentBuilder(); InputSource is = new InputSource(); is.setCharacterStream(new StringReader(xml)); doc = db.parse(is); } catch (ParserConfigurationException e) { Logging.log(APP_TAG, e.getMessage()); return null; } catch (SAXException e) { Logging.log(APP_TAG, e.getMessage()); return null; } catch (IOException e) { Logging.log(APP_TAG, e.getMessage()); return null; } } if (!adapter.getFolder().equals("0")) { items.add(new AouGuide(this, "Start", "0", R.drawable.icon_grid, 2)); } if (doc != null && !adapter.getFolder().equals("0")) { NodeList nl = doc.getElementsByTagName("folder"); for (int i = nl.getLength() - 1; i >= 0; i--) { Element e = (Element) nl.item(i); String title = Html.fromHtml(getValue(e, "name").replace("<![", "").replace("]]>", "").trim()).toString(); String id = getValue(e, "id"); int icon = R.drawable.icon_undo; if (i == 0) { icon = R.drawable.icon_replay; } AouGuide entry = new AouGuide(this, title, id, icon, 0); items.add(entry); } } if (folders != null) { NodeList nl = folders.getElementsByTagName("folder"); for (int i = 0; i < nl.getLength(); i++) { Element e = (Element) nl.item(i); String title = Html.fromHtml(getValue(e, "name").replace("<![", "").replace("]]>", "").trim()).toString(); String id = getValue(e, "id"); if (getValue(e, "parent").equals(adapter.getFolder())) { AouGuide entry = new AouGuide(this, title, id, R.drawable.icon_archive, 0); items.add(entry); } } } if (doc != null) { NodeList nl = doc.getElementsByTagName("guide"); for (int i = 0; i < nl.getLength(); i++) { Element e = (Element) nl.item(i); String title = Html.fromHtml(getValue(e, "name").replace("<![", "").replace("]]>", "").trim()).toString(); String id = getValue(e, "id"); AouGuide entry = new AouGuide(this, title, id, R.drawable.icon_directions, 1); items.add(entry); } } if (items.size() > 0) { tracker.sendTiming("Loading", System.currentTimeMillis() - loadTime, "AOU Guides", null); } return items; } private String getValue(Element item, String str) { NodeList n = item.getElementsByTagName(str); return getElementValue(n.item(0)); } private final String getElementValue( Node elem ) { Node child; if (elem != null) { if (elem.hasChildNodes()) { for (child = elem.getFirstChild(); child != null; child = child.getNextSibling()) { if (child.getNodeType() == Node.TEXT_NODE) { return child.getNodeValue(); } } } } return ""; } @Override public void deliverResult(List<AouGuide> news) { if (isReset()) { if (news != null) { onReleaseResources(news); } } List<AouGuide> oldNews = news; dataList = news; if (isStarted()) { super.deliverResult(news); } if (oldNews != null) { onReleaseResources(oldNews); } } @Override protected void onStartLoading() { if (dataList != null) { deliverResult(dataList); } boolean configChange = mLastConfig.applyNewConfig(getContext().getResources()); if (takeContentChanged() || dataList == null || configChange) { forceLoad(); } } /** * Handles a request to stop the Loader. */ @Override protected void onStopLoading() { cancelLoad(); } /** * Handles a request to cancel a load. */ @Override public void onCanceled(List<AouGuide> news) { super.onCanceled(news); onReleaseResources(news); } /** * Handles a request to completely reset the Loader. */ @Override protected void onReset() { super.onReset(); onStopLoading(); if (dataList != null) { onReleaseResources(dataList); dataList = null; } } /** * Helper function to take care of releasing resources associated * with an actively loaded data set. */ protected void onReleaseResources(List<AouGuide> news) { } } public static class ListAdapter extends ArrayAdapter<AouGuide> { private final LayoutInflater mInflater; private String folder = "0"; private boolean animationEnabled; private String searchString = null; public ListAdapter(Context context, boolean enableAnimation) { super(context, android.R.layout.simple_list_item_2); mInflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); animationEnabled = enableAnimation; } public void setData(List<AouGuide> data) { clear(); if (data != null) { for (AouGuide entry : data) { add(entry); } } } /** * Populate new items in the list. */ @Override public View getView(int position, View convertView, ViewGroup parent) { if (convertView == null) { convertView = mInflater.inflate(R.layout.list_item_guide, parent, false); } AouGuide item = getItem(position); ((TextView)convertView.findViewById(R.id.text)).setText(item.getLabel()); ((TextView)convertView.findViewById(R.id.text)).setCompoundDrawablesWithIntrinsicBounds(item.getIcon(), null, null, null); if (animationEnabled) { Animation animation = new ScaleAnimation(0, 1, 0, 1, Animation.RELATIVE_TO_SELF, (float)0, Animation.RELATIVE_TO_SELF, (float)0.5); animation.setDuration(200); animation.setFillAfter(true); convertView.setAnimation(animation); convertView.startAnimation(animation); } return convertView; } public void setFolder(String folder) { this.folder = folder; } public String getFolder() { return folder; } public String getSearchString() { return searchString; } public void setSearchString(String search) { Logging.log(APP_TAG, "setSearchId was called with id " + search); searchString = search; } } @Override public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); setEmptyText(getString(R.string.no_guides)); setHasOptionsMenu(true); extras = this.getArguments(); mAdapter = new ListAdapter(getActivity(), PreferenceManager.getDefaultSharedPreferences(this.getActivity().getBaseContext()).getBoolean("enableAnimations", true)); mAdapter.setSearchString(extras.getString("search")); setListAdapter(mAdapter); getListView().setFastScrollEnabled(true); getListView().setScrollingCacheEnabled(false); getListView().setDividerHeight(0); setListShown(false); getLoaderManager().initLoader(0, null, this); } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { container.setBackgroundResource(0); return super.onCreateView(inflater, container, savedInstanceState); } @Override public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { } @Override public void onListItemClick(ListView l, View v, int position, long id) { Logging.log(APP_TAG, "Item clicked: " + mAdapter.getItem(position).getLabel()); if (mAdapter.getItem(position).getType() == 1) { Intent intent = new Intent(); intent.setClass(mAdapter.getContext(), ActivityGuide.class); intent.putExtra("title", mAdapter.getItem(position).getLabel()); intent.putExtra("id", mAdapter.getItem(position).getID()); if (AOU.isTablet) { aou.loadFragment(intent, 2); } else { mAdapter.getContext().startActivity(intent); } } else { mAdapter.setFolder(mAdapter.getItem(position).getID()); setListShown(false); getLoaderManager().restartLoader(0, null, this); } } @Override public Loader<List<AouGuide>> onCreateLoader(int id, Bundle args) { return new ListLoader(getActivity(), mAdapter); } @Override public void onLoadFinished(Loader<List<AouGuide>> loader, List<AouGuide> data) { mAdapter.setData(data); if (isResumed()) { setListShown(true); } else { setListShownNoAnimation(true); } } @Override public void onLoaderReset(Loader<List<AouGuide>> loader) { // Clear the data in the adapter. mAdapter.setData(null); } }