Back to project page virtual-stat.
The source code is released under:
Copyright (c) 2014, Delta Controls Inc. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are...
If you think the Android project virtual-stat listed in this page is inappropriate, such as containing malicious code/tools or violating the copyright, please email info at java2s dot com, thanks.
/* Copyright (c) 2014, Delta Controls Inc. All rights reserved.// w w w .j ava 2 s. c om Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /** * StatListFragment.java */ package com.deltacontrols.virtualstat.fragment; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.HashMap; import java.util.Iterator; import org.apache.http.HttpStatus; import org.json.JSONObject; import android.app.Activity; import android.content.Context; import android.os.Bundle; import android.support.v4.app.Fragment; import android.text.Editable; import android.text.TextWatcher; import android.util.Log; import android.view.LayoutInflater; import android.view.SoundEffectConstants; import android.view.View; import android.view.View.OnClickListener; import android.view.ViewGroup; import android.view.animation.AnimationUtils; import android.view.inputmethod.InputMethodManager; import android.widget.AdapterView; import android.widget.AdapterView.OnItemClickListener; import android.widget.EditText; import android.widget.Filter; import android.widget.ImageView; import android.widget.ListView; import com.deltacontrols.eweb.support.api.EwebConnection; import com.deltacontrols.eweb.support.api.FetchJSON; import com.deltacontrols.eweb.support.interfaces.GenericCallback; import com.deltacontrols.virtualstat.App; import com.deltacontrols.virtualstat.R; import com.deltacontrols.virtualstat.StatListItem; import com.deltacontrols.virtualstat.StatListItemAdapter; import com.deltacontrols.virtualstat.UIFactory; import com.deltacontrols.virtualstat.VirtualStat; import com.deltacontrols.virtualstat.VirtualStat.ExposeVirtualStat; import com.deltacontrols.virtualstat.activity.SummaryActivity; import com.deltacontrols.virtualstat.controls.ToggleBar; import com.deltacontrols.virtualstat.controls.ToggleBar.ToggleInteractionListener; /** * StatListFragment * * Controls user interaction with the stat list fragment. Responsible for loading in stat data from eWEB, caching stat data, and allowing * users to load stats based on list selections. */ public class StatListFragment extends Fragment implements VirtualStat.UseVirtualStat { // -------------------------------------------------------------------------------- // Static helper classes // -------------------------------------------------------------------------------- /** * Caching class helper - cache Stat JSON strings to avoid extra requests. Made static so other activities can update the cached JSON to * include updated values */ public static class StatListCache { private static HashMap<String, String> cachedJSONStrs = new HashMap<String, String>(); public static String get(String id) { return cachedJSONStrs.containsKey(id) ? cachedJSONStrs.get(id) : null; } public static void clear() { cachedJSONStrs.clear(); } public static void set(String id, String json) { cachedJSONStrs.put(id, json); } } /** * Demo values for stats */ public static class Demo { /* * getAllStats Mimics EwebConnection.getAllStats. */ public static FetchJSON.Result getAllStats() { // It's fake! We're ok! FetchJSON.Result result = new FetchJSON.Result(); result.success = true; result.statusCode = HttpStatus.SC_OK; // Fake values String[][] demoArr = new String[][] { new String[] { "Training Room Demo", "0000-0000-0001", "TEMP_SP", "16", "//Demo/100.AV1", "TEMP", "18", "//Demo/100.AI1", "LIGHTS1", "75", "//Demo/100.AV2", "LIGHTS2", "75", "//Demo/100.AV3", "LIGHTS3", "Active", "//Demo/100.BV1", "LIGHTS4", "Active", "//Demo/100.BV2", "FAN", "4", "//Demo/100.MV1", "BLINDS", "50", "//Demo/100.AV3" }, new String[] { "Front Hallway Demo", "0000-0000-0002", "TEMP_SP", "20", "//Demo/100.AV1", "TEMP", "14", "//Demo/100.AI1", "LIGHTS1", "100", "//Demo/100.AV2", "LIGHTS2", "Active", "//Demo/100.BV1", "LIGHTS3", "", "", "LIGHTS4", "", "", "FAN", "", "", "BLINDS", "", "" }, new String[] { "Emma's Office Demo", "0000-0000-0003", "TEMP_SP", "22", "//Demo/100.AV1", "TEMP", "", "", "LIGHTS1", "0", "//Demo/100.BV1", "LIGHTS2", "", "", "LIGHTS3", "", "", "LIGHTS4", "", "", "FAN", "", "", "BLINDS", "", "" }, new String[] { "Liam's Office Demo", "0000-0000-0004", "TEMP_SP", "19", "//Demo/100.AV1", "TEMP", "", "", "LIGHTS1", "0", "//Demo/100.AV1", "LIGHTS2", "Inactive", "//Demo/100.BV1", "LIGHTS3", "", "", "LIGHTS4", "", "", "FAN", "", "", "BLINDS", "", "" } }; // System format (based on result from eweb api/systems/list request String formatString = " \"%s\": { id: \"%s\", " + // name, id "\"%s\": { value: \"%s\", ref: \"%s\" }, " + // TEMP_SP "\"%s\": { value: \"%s\", ref: \"%s\" }, " + // TEMP "\"%s\": { value: \"%s\", ref: \"%s\" }, " + // LIGHTS1 "\"%s\": { value: \"%s\", ref: \"%s\" }, " + // LIGHTS2 "\"%s\": { value: \"%s\", ref: \"%s\" }, " + // LIGHTS3 "\"%s\": { value: \"%s\", ref: \"%s\" }, " + // LIGHTS4 "\"%s\": { value: \"%s\", ref: \"%s\" }, " + // FAN "\"%s\": { value: \"%s\", ref: \"%s\" } " + // BLINDS "},"; StringBuffer fakeData = new StringBuffer(); JSONObject fakeJSON; try { fakeData.append("{ "); for (int i = 0; i < demoArr.length; i++) { fakeData.append(String.format(formatString, (Object[]) demoArr[i])); } fakeData.deleteCharAt(fakeData.length() - 1); // remove last , fakeData.append("}"); fakeJSON = new JSONObject(fakeData.toString()); } catch (Exception e) { fakeJSON = new JSONObject(); } result.json = fakeJSON; // Pass fake data back return result; } } // -------------------------------------------------------------------------------- // Properties // -------------------------------------------------------------------------------- Context ctx; InputMethodManager inputManager; // List ListView statList; View statListHeader; Filter statFilter; StatListItemAdapter listAdapter; ArrayList<StatListItem> listItemsArray = new ArrayList<StatListItem>(); // Outlets EditText searchText; ToggleBar switcher_toggle_onlist; ImageView icon_refresh; // VirtualStat (model) Interface delegate private VirtualStat virtualStatDelegate = null; /** * Listener used to handle clicks on the stat list. When an item in the stat list is selected, load the stat's points so that the summary * fragment can show the data. Also, depending on screen size, hide the soft keyboard automatically. */ private OnItemClickListener selectListItemListener = new OnItemClickListener() { /* * (non-Javadoc) When item is clicked in the stat list, attempt to load the stat that corresponds to the selection. * * @see android.widget.AdapterView.OnItemClickListener#onItemClick(android.widget.AdapterView, android.view.View, int, long) */ public void onItemClick(AdapterView<?> parent, final View view, int position, long id) { Object o = statList.getItemAtPosition(position); if (o instanceof StatListItem) { // Get ID from the stat list item clicked and use it to load the stat. String statId = ((StatListItem) o).id; loadStatJSON(statId); // Auto hide the soft keyboard inputManager.hideSoftInputFromWindow(searchText.getWindowToken(), 0); // If switcher_toggle_onlist exists then we are on a 4" device, so auto hide the stat list as well. if (switcher_toggle_onlist != null) { hideStatList(); } } } }; // -------------------------------------------------------------------------------- // Life cycle // -------------------------------------------------------------------------------- @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); getStatDelegate(); } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { ctx = getActivity(); inputManager = (InputMethodManager) ctx.getSystemService(Context.INPUT_METHOD_SERVICE); View view = inflater.inflate(R.layout.fragment_stat_list, container, false); icon_refresh = (ImageView) view.findViewById(R.id.icon_refresh); // Setup list statList = (ListView) view.findViewById(R.id.statListView); statList.setOnItemClickListener(selectListItemListener); // switcher_toggle_onlist exists on < large screens (where the list takes up the full layout) // If this toggler exists then hookup gesture listeners. // Note: Currently, toggler only visible if list is being shown; this means we only have to listen for a tap/swipe down // and implement the hide list functionality. switcher_toggle_onlist = (ToggleBar) view.findViewById(R.id.switcher_toggle_onlist); if (switcher_toggle_onlist != null) { switcher_toggle_onlist.setToggleInteractionListener(new ToggleInteractionListener() { @Override public void onTap() { hideStatList(); } @Override public void onSwipeUp() { } @Override public void onSwipeDown() { hideStatList(); } }); } // Search text will apply a real time filter on the stat list. searchText = ((EditText) view.findViewById(R.id.statListFilterText)); searchText.addTextChangedListener(new TextWatcher() { @Override public void onTextChanged(CharSequence s, int start, int before, int count) { } @Override public void beforeTextChanged(CharSequence s, int start, int count, int after) { } @Override public void afterTextChanged(Editable s) { applyFilterToList(s.toString()); } }); // Setup clear icon ((ImageView) view.findViewById(R.id.icon_clear)).setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { getView().playSoundEffect(SoundEffectConstants.CLICK); searchText.setText(null); } }); icon_refresh.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { getView().playSoundEffect(SoundEffectConstants.CLICK); updateList(); } }); return view; } @Override public void onResume() { super.onResume(); if (listItemsArray.isEmpty()) { updateList(); // Do an initial update of the list; all subsequent updates must be triggered through the refresh button } else { setListAdapter(); // If coming back from a long period away, reset the list. } } // -------------------------------------------------------------------------------- // Methods // -------------------------------------------------------------------------------- /** * Listener used to handle the result of a request for the stat list. Loads the stat list with a given JSONObject containing a list of * systems (from either eWEB or with demo data) */ private GenericCallback<FetchJSON.Result> getListListener = new GenericCallback<FetchJSON.Result>() { @SuppressWarnings("unchecked") @Override public void onCallback(FetchJSON.Result result) { try { String name, id, jsonStr; Object value; StatListItem singleListItem; JSONObject valueObj; showLoadingIcon(false); listItemsArray.clear(); // Iterate over system result to get each system. for (Iterator<String> iter = result.json.keys(); iter.hasNext();) { try { name = iter.next(); value = result.json.get(name); valueObj = (JSONObject) value; // Cache based on ID (not name) id = valueObj.getString("id"); // Add stat into the list of stats, showing the name, but indexing on ID. singleListItem = new StatListItem(name, id); listItemsArray.add(singleListItem); // Since current web response contains full system info, add to cache to avoid a second request. // Cache json string, including name so that we can easily parse it out later. jsonStr = "{ \"" + name + "\" :" + valueObj.toString() + "}"; StatListCache.cachedJSONStrs.put(id, jsonStr); } catch (Exception e) { continue; } } // Sort list alphabetically by name Collections.sort(listItemsArray, new Comparator<StatListItem>() { public int compare(StatListItem o1, StatListItem o2) { return o1.name.toLowerCase().compareTo(o2.name.toLowerCase()); } }); setListAdapter(); // If nothing selected, default to show first. if (virtualStatDelegate.ID.isEmpty()) { loadFirstItemInList(); } } catch (Exception e) { Log.e(App.TAG, "Error in getListListener: " + e.getMessage()); } } }; /** * Update the stat list with live or demo data depending on the connection to eWEB. */ private void updateList() { // Get data from eWEB EwebConnection eweb = App.getEwebConnection(); if (App.getDemoMode()) { // Get demo values getListListener.onCallback(Demo.getAllStats()); } else if (eweb.isConnected()) { // Attempt to talk to eWEB showLoadingIcon(true); App.getStat(null, getListListener); } } /** * (Re)sets the list adapter with the items in listItemsArray */ @SuppressWarnings("unchecked") private void setListAdapter() { // Note, make a clone of the full data list; because the adapter will keep a reference to to data, and that data may become filtered, we want // to preserve the original list for a case when we may want to reset it. ArrayList<StatListItem> observableData = (ArrayList<StatListItem>) listItemsArray.clone(); if (listAdapter == null) { listAdapter = new StatListItemAdapter(ctx, R.layout.view_summary_list_item_layout, observableData); statList.setAdapter(listAdapter); statFilter = ((StatListItemAdapter) listAdapter).getFilter(); } else { listAdapter.updateData(observableData); } applyFilterToList(searchText.getText().toString()); } /** * Applies the string as a filter to the items in the list. */ private void applyFilterToList(String s) { if (statFilter != null) { statFilter.filter(s); } } private void showLoadingIcon(boolean show) { if (show) { icon_refresh.setImageResource(R.drawable.icon_refresh_loading); icon_refresh.startAnimation(AnimationUtils.loadAnimation(ctx, R.animator.login_image_rotate)); } else { icon_refresh.setImageResource(R.drawable.icon_refresh); icon_refresh.clearAnimation(); } } private void loadFirstItemInList() { Object o = statList.getItemAtPosition(0); if (o instanceof StatListItem) { // Get ID from the stat list item clicked and use it to load the stat. String statId = ((StatListItem) o).id; loadStatJSON(statId); } } // -------------------------------------------------------------------------------- // Stat loading functionality // -------------------------------------------------------------------------------- /** * Call into the parent activity to hide the stat list (since the parent owns the display of the stat list, it must know how to hide it). */ private void hideStatList() { ((SummaryActivity) getActivity()).hideStatList(); } /** * loadStatJSON Given an id, lookup the stat's JSON String in cache, and load it into the virtual stat delegate. * * @param id The ID of the stat to load */ private void loadStatJSON(String id) { try { String statStr = StatListCache.get(id); if (statStr == null) { loadFirstItemInList(); return; // If no cache, return, cannot load. } // Save statStr in shared preferences so that it can be used by other activities in the future. App.saveStatIntoSharedPreferences(statStr); // Load stat with new statStr and start the data refresh. virtualStatDelegate.loadFromJSON(statStr); virtualStatDelegate.startDataRefresh(0); // get data. } catch (Exception e) { UIFactory.deltaToast(getActivity(), "Error loading stat JSON", null); } } // -------------------------------------------------------------------------------- // VirtualStat.UseVirtualStat Interface // -------------------------------------------------------------------------------- @Override public void getStatDelegate() { Activity activity = getActivity(); try { virtualStatDelegate = ((ExposeVirtualStat) activity).getCurrentStat(); } catch (ClassCastException e) { throw new ClassCastException(activity.toString() + " must implement ExposeVirtualStat"); } } @Override public void updateWithDelegate() { // Stat list does not use delegate. } }