package net.wigle.wigleandroid; import android.annotation.SuppressLint; import android.content.SharedPreferences; import android.content.res.Configuration; import android.content.res.Resources; import android.media.AudioManager; import android.os.Bundle; import android.os.Handler; import android.os.Message; import android.os.Parcelable; import android.support.v4.app.Fragment; import android.support.v4.view.MenuItemCompat; import android.support.v4.widget.SwipeRefreshLayout; 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.LinearLayout; import android.widget.ListView; import android.widget.TextView; import net.wigle.wigleandroid.background.ApiDownloader; import net.wigle.wigleandroid.background.ApiListener; import net.wigle.wigleandroid.background.DownloadHandler; import net.wigle.wigleandroid.model.Upload; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; import java.text.DecimalFormat; import java.text.NumberFormat; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.Locale; import java.util.Map; import java.util.concurrent.atomic.AtomicBoolean; public class UploadsFragment extends Fragment { private static final int MSG_RANKING_DONE = 100; private static final int MENU_USER_STATS = 200; private static final int MENU_SITE_STATS = 201; /* { "success":true, "processingQueueDepth":1, "results":[ { "transid":"20170101-00928", "username":"arkasha", "firstTime":"2017-01-01T23:59:24.000Z", "lastupdt":"2017-01-02T00:00:06.000Z", "fileName":"1483315164_WigleWifi_20170101155922.csv", "fileSize":20846, "fileLines":174, "status":"D", "discoveredGps":0, "discovered":0, "total":118, "totalGps":117, "totalLocations":172, "percentDone":100.0, "timeParsing":5, "genDiscovered":0, "genDiscoveredGps":0, "genTotal":1, "genTotalGps":1, "genTotalLocations":1, "wait":null }, ... ] } */ private static final String RESULT_LIST_KEY = "results"; private static final String KEY_TOTAL_WIFI_GPS = "discoveredGps"; private static final String KEY_TOTAL_CELL_GPS = "genDiscoveredGps"; private static final String KEY_QUEUE_DEPTH = "processingQueueDepth"; private static final String KEY_TRANSID = "transid"; private static final String KEY_STATUS = "status"; private static final String KEY_PERCENT_DONE = "percentDone"; private static final String KEY_FILE_SIZE = "fileSize"; private static final int ROW_COUNT = 100; private static final String[] ALL_ROW_KEYS = new String[] { KEY_TOTAL_WIFI_GPS, KEY_TOTAL_CELL_GPS, KEY_PERCENT_DONE, KEY_FILE_SIZE, }; private AtomicBoolean finishing; private NumberFormat numberFormat; private UploadsListAdapter listAdapter; private RankDownloadHandler handler; private static final Map<String, String> uploadStatusMap; static { Map<String, String> statusMap = new HashMap<String, String>(); statusMap.put("W", "upload_queued"); statusMap.put("I", "upload_parsing"); statusMap.put("T", "upload_trilaterating"); statusMap.put("S", "upload_stats"); statusMap.put("D", "upload_success"); statusMap.put("E", "upload_failed"); uploadStatusMap = Collections.unmodifiableMap(statusMap); } /** Called when the activity is first created. */ @Override public void onCreate( final Bundle savedInstanceState ) { MainActivity.info("UPLOADS: onCreate"); super.onCreate(savedInstanceState); setHasOptionsMenu(true); // set language MainActivity.setLocale(getActivity()); // media volume getActivity().setVolumeControlStream(AudioManager.STREAM_MUSIC); finishing = new AtomicBoolean(false); numberFormat = NumberFormat.getNumberInstance(Locale.US); if (numberFormat instanceof DecimalFormat) { numberFormat.setMinimumFractionDigits(0); numberFormat.setMaximumFractionDigits(2); } } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { final int orientation = getResources().getConfiguration().orientation; MainActivity.info("UPLOADS: onCreateView. orientation: " + orientation); final LinearLayout rootView = (LinearLayout) inflater.inflate(R.layout.uploads, container, false); setupSwipeRefresh(rootView); setupListView(rootView); handler = new RankDownloadHandler(rootView, numberFormat, getActivity().getPackageName(), getResources()); handler.setUploadsListAdapter(listAdapter); downloadUploads(); return rootView; } private void setupSwipeRefresh(final LinearLayout rootView) { // Lookup the swipe container view final SwipeRefreshLayout swipeContainer = (SwipeRefreshLayout) rootView.findViewById(R.id.uploads_swipe_container); // Setup refresh listener which triggers new data loading swipeContainer.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() { @Override public void onRefresh() { // Your code to refresh the list here. // Make sure you call swipeContainer.setRefreshing(false) // once the network request has completed successfully. downloadUploads(); } }); } private void downloadUploads() { if (handler == null) { MainActivity.error("downloadUploads handler is null"); return; } final String monthUrl = MainActivity.UPLOADS_STATS_URL + "?pageend=" + ROW_COUNT; final ApiDownloader task = new ApiDownloader(getActivity(), ListFragment.lameStatic.dbHelper, "uploads-cache.json", monthUrl, false, true, true, ApiDownloader.REQUEST_GET, new ApiListener() { @Override public void requestComplete(final JSONObject json, final boolean isCache) { handleUploads(json, handler); } }); try { task.startDownload(this); } catch (WiGLEAuthException waex) { MainActivity.info("Transactions Download Failed due to failed auth"); } } private void setupListView(final View view) { final SharedPreferences prefs = getActivity().getSharedPreferences(ListFragment.SHARED_PREFS, 0); if (listAdapter == null) { listAdapter = new UploadsListAdapter(getActivity().getApplicationContext(), R.layout.uploadrow); } else if (!listAdapter.isEmpty() && !TokenAccess.hasApiToken(prefs)) { listAdapter.clear(); } // always set our current list adapter final ListView listView = (ListView) view.findViewById(R.id.uploads_list_view); listView.setAdapter(listAdapter); } private String statusValue(String statusCode) { String packageName = "net.wigle.wigleandroid"; int stringId = getResources().getIdentifier("upload_unknown", "string", packageName); if (uploadStatusMap.containsKey(statusCode)) { stringId = getResources().getIdentifier(uploadStatusMap.get(statusCode), "string", packageName); } return getString(stringId); } private final static class RankDownloadHandler extends DownloadHandler { private UploadsListAdapter uploadsListAdapter; private RankDownloadHandler(final View view, final NumberFormat numberFormat, final String packageName, final Resources resources) { super(view, numberFormat, packageName, resources); } public void setUploadsListAdapter(final UploadsListAdapter uploadsListAdapter) { this.uploadsListAdapter = uploadsListAdapter; } @SuppressLint("SetTextI18n") @Override public void handleMessage(final Message msg) { final Bundle bundle = msg.getData(); final ArrayList<Parcelable> results = bundle.getParcelableArrayList(RESULT_LIST_KEY); // MainActivity.info("handleMessage. results: " + results); if (msg.what == MSG_RANKING_DONE && results != null && uploadsListAdapter != null) { TextView tv = (TextView) view.findViewById(R.id.queue_depth); final String queueDepthTitle = resources.getString(R.string.queue_depth); tv.setText(queueDepthTitle + ": " + bundle.getString(KEY_QUEUE_DEPTH)); uploadsListAdapter.clear(); for (final Parcelable result : results) { if (result instanceof Bundle) { final Bundle row = (Bundle) result; final Upload upload = new Upload(row.getString(KEY_TRANSID), row.getLong(KEY_TOTAL_WIFI_GPS), row.getLong(KEY_TOTAL_CELL_GPS), (int) row.getLong(KEY_PERCENT_DONE), row.getString(KEY_STATUS), row.getLong(KEY_FILE_SIZE)); uploadsListAdapter.add(upload); } } final SwipeRefreshLayout swipeRefreshLayout = (SwipeRefreshLayout) view.findViewById(R.id.uploads_swipe_container); swipeRefreshLayout.setRefreshing(false); } } } private void handleUploads(final JSONObject json, final Handler handler) { MainActivity.info("handleUploads"); if (json == null) { MainActivity.info("handleUploads null json, returning"); return; } final Bundle bundle = new Bundle(); try { final JSONArray list = json.getJSONArray(RESULT_LIST_KEY); final ArrayList<Parcelable> resultList = new ArrayList<>(list.length()); for (int i = 0; i < list.length(); i++) { final JSONObject row = list.getJSONObject(i); final Bundle rowBundle = new Bundle(); for (final String key : ALL_ROW_KEYS) { rowBundle.putLong(key, row.getLong(key)); } rowBundle.putString(KEY_TRANSID, row.getString(KEY_TRANSID)); rowBundle.putString(KEY_STATUS, this.statusValue(row.getString(KEY_STATUS))); resultList.add(rowBundle); } bundle.putParcelableArrayList(RESULT_LIST_KEY, resultList); bundle.putString(KEY_QUEUE_DEPTH, json.getString(KEY_QUEUE_DEPTH)); } catch (final JSONException ex) { MainActivity.error("json error: " + ex, ex); } catch (final Exception e) { MainActivity.error("uploads error: " + e, e); } final Message message = new Message(); message.setData(bundle); message.what = MSG_RANKING_DONE; handler.sendMessage(message); } @Override public void onDestroy() { MainActivity.info( "UPLOADS: onDestroy" ); finishing.set( true ); super.onDestroy(); } @Override public void onResume() { MainActivity.info("UPLOADS: onResume"); super.onResume(); getActivity().setTitle(R.string.uploads_app_name); } @Override public void onStart() { MainActivity.info( "UPLOADS: onStart" ); super.onStart(); } @Override public void onPause() { MainActivity.info( "UPLOADS: onPause" ); super.onPause(); } @Override public void onStop() { MainActivity.info( "UPLOADS: onStop" ); super.onStop(); } @Override public void onConfigurationChanged( final Configuration newConfig ) { MainActivity.info("UPLOADS: config changed"); super.onConfigurationChanged( newConfig ); } /* Creates the menu items */ @Override public void onCreateOptionsMenu (final Menu menu, final MenuInflater inflater) { MenuItem item = menu.add(0, MENU_USER_STATS, 0, getString(R.string.user_stats_app_name)); item.setIcon( android.R.drawable.ic_menu_myplaces ); MenuItemCompat.setShowAsAction(item, MenuItemCompat.SHOW_AS_ACTION_IF_ROOM); item = menu.add(0, MENU_USER_STATS, 0, getString(R.string.user_stats_app_name)); item.setIcon(android.R.drawable.ic_menu_myplaces); item = menu.add(0, MENU_SITE_STATS, 0, getString(R.string.site_stats_app_name)); item.setIcon( R.drawable.wiglewifi_small_black_white ); MenuItemCompat.setShowAsAction(item, MenuItemCompat.SHOW_AS_ACTION_IF_ROOM); item = menu.add(0, MENU_SITE_STATS, 0, getString(R.string.site_stats_app_name)); item.setIcon(R.drawable.wiglewifi_small_black_white); super.onCreateOptionsMenu(menu, inflater); } /* Handles item selections */ @Override public boolean onOptionsItemSelected( final MenuItem item ) { final MainActivity main = MainActivity.getMainActivity(); switch ( item.getItemId() ) { case MENU_USER_STATS: main.selectFragment(MainActivity.USER_STATS_TAB_POS); return true; case MENU_SITE_STATS: main.selectFragment(MainActivity.SITE_STATS_TAB_POS); return true; } return false; } }