Java tutorial
/* * Copyright (C) 2012-2013 Aubort Jean-Baptiste (Rorist) * Licensed under GNU's GPL 2, see README */ package ch.fixme.status; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.Iterator; import java.util.Map.Entry; import java.util.Set; import java.util.regex.Pattern; import org.json.JSONArray; import org.json.JSONObject; import android.app.Activity; import android.app.AlertDialog; import android.app.Dialog; import android.app.ProgressDialog; import android.appwidget.AppWidgetManager; import android.content.ActivityNotFoundException; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; import android.content.SharedPreferences; import android.content.SharedPreferences.Editor; import android.graphics.Bitmap; import android.graphics.drawable.AnimationDrawable; import android.net.ConnectivityManager; import android.net.NetworkInfo; import android.net.Uri; import android.os.AsyncTask; import android.os.Bundle; import android.preference.PreferenceManager; import android.text.util.Linkify; import android.util.Log; import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; import android.view.View; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.RelativeLayout; import android.widget.ScrollView; import android.widget.TextView; public class Main extends Activity { // API: http://hackerspaces.nl/spaceapi/ // http://spaceapi.net protected static String TAG = "MyHackerspace"; protected static final String PKG = "ch.fixme.status"; protected static final String OPEN = "Open"; protected static final String CLOSED = "Closed"; protected static final String PREF_API_URL_WIDGET = "api_url_widget_"; protected static final String PREF_INIT_WIDGET = "init_widget_"; protected static final String PREF_LAST_WIDGET = "last_widget_"; protected static final String PREF_FORCE_WIDGET = "force_widget_"; protected static final String STATE_HS = "hs"; protected static final String STATE_DIR = "dir"; private static final String PREF_API_URL = "apiurl"; private static final int DIALOG_LOADING = 0; private static final int DIALOG_LIST = 1; private static final String TWITTER = "https://twitter.com/#!/"; private static final String FOURSQUARE = "https://foursquare.com/v/"; private static final String MAP_SEARCH = "geo:0,0?q="; private static final String MAP_COORD = "geo:%s,%s?z=23&q=%s&"; private SharedPreferences mPrefs; private String mResultHs; public String mResultDir; private String mApiUrl; private boolean finishApi = false; private boolean finishDir = false; private GetDirTask getDirTask; private GetApiTask getApiTask; private GetImage getImageTask; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); mPrefs = PreferenceManager.getDefaultSharedPreferences(Main.this); Intent intent = getIntent(); checkNetwork(); getHsList(savedInstanceState); showHsInfo(intent, savedInstanceState); } @Override protected void onDestroy() { if (getApiTask != null) { getApiTask.cancel(true); } if (getDirTask != null) { getDirTask.cancel(true); } if (getImageTask != null) { getImageTask.cancel(true); } super.onDestroy(); } @Override public boolean onCreateOptionsMenu(Menu menu) { MenuInflater inflater = getMenuInflater(); inflater.inflate(R.menu.main, menu); return true; } @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case R.id.menu_refresh: checkNetwork(); showHsInfo(getIntent(), null); return true; case R.id.menu_choose: showDialog(DIALOG_LIST); return true; case R.id.menu_prefs: startActivity(new Intent(Main.this, Prefs.class)); return true; default: return super.onOptionsItemSelected(item); } } @Override public Bundle onRetainNonConfigurationInstance() { Bundle data = new Bundle(2); data.putString(STATE_HS, mResultHs); data.putString(STATE_DIR, mResultDir); return data; } @Override protected void onSaveInstanceState(Bundle outState) { outState.putString(STATE_HS, mResultHs); outState.putString(STATE_DIR, mResultDir); super.onSaveInstanceState(outState); } @Override protected Dialog onCreateDialog(int id) { AlertDialog dialog = null; switch (id) { case DIALOG_LOADING: dialog = new ProgressDialog(this); dialog.setCancelable(false); dialog.setMessage(getString(R.string.msg_loading)); dialog.setCancelable(true); ((ProgressDialog) dialog).setIndeterminate(true); break; case DIALOG_LIST: return createHsDialog(); } return dialog; } @Override public void startActivity(Intent intent) { // http://stackoverflow.com/questions/13691241/autolink-not-working-on-htc-htclinkifydispatcher try { /* First attempt at fixing an HTC broken by evil Apple patents. */ if (intent.getComponent() != null && ".HtcLinkifyDispatcherActivity".equals(intent.getComponent().getShortClassName())) intent.setComponent(null); super.startActivity(intent); } catch (ActivityNotFoundException e) { /* * Probably an HTC broken by evil Apple patents. This is not * perfect, but better than crashing the whole application. */ super.startActivity(Intent.createChooser(intent, null)); } } private AlertDialog createHsDialog() { // Construct hackerspaces list try { JSONObject obj = new JSONObject(mResultDir); JSONArray arr = obj.names(); int len = obj.length(); String[] names = new String[len]; final ArrayList<String> url = new ArrayList<String>(len); for (int i = 0; i < len; i++) { names[i] = arr.getString(i); } Arrays.sort(names, 0, len, String.CASE_INSENSITIVE_ORDER); for (int i = 0; i < len; i++) { url.add(i, obj.getString(names[i])); } // Create the dialog AlertDialog.Builder builder = new AlertDialog.Builder(Main.this); builder.setTitle(R.string.choose_hs).setItems(names, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { setIntent(null); Editor edit = mPrefs.edit(); edit.putString(PREF_API_URL, url.get(which)); getApiTask = new GetApiTask(); getApiTask.execute(url.get(which)); edit.commit(); } }); return builder.create(); } catch (Exception e) { e.printStackTrace(); showError(e.getClass().getCanonicalName(), e.getLocalizedMessage() + getString(R.string.error_generic)); return null; } } private void getHsList(Bundle savedInstanceState) { final Bundle data = (Bundle) getLastNonConfigurationInstance(); if (data == null || (savedInstanceState == null && !savedInstanceState.containsKey(STATE_DIR))) { getDirTask = new GetDirTask(); getDirTask.execute(ParseGeneric.API_DIRECTORY); } else { finishDir = true; mResultDir = data.getString(STATE_DIR); } } private void showHsInfo(Intent intent, Bundle savedInstanceState) { // Get hackerspace api url if (intent != null && intent.hasExtra(AppWidgetManager.EXTRA_APPWIDGET_ID)) { mApiUrl = mPrefs.getString(PREF_API_URL_WIDGET + intent.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, AppWidgetManager.INVALID_APPWIDGET_ID), ParseGeneric.API_DEFAULT); } else if (intent != null && intent.hasExtra(STATE_HS)) { mApiUrl = intent.getStringExtra(STATE_HS); } else { mApiUrl = mPrefs.getString(PREF_API_URL, ParseGeneric.API_DEFAULT); } // Get Data final Bundle data = (Bundle) getLastNonConfigurationInstance(); if (data == null || (savedInstanceState == null && !savedInstanceState.containsKey(STATE_HS))) { getApiTask = new GetApiTask(); getApiTask.execute(mApiUrl); } else { finishApi = true; mResultHs = data.getString(STATE_HS); populateDataHs(); } // Update widget Widget.UpdateAllWidgets(getApplicationContext()); } private boolean checkNetwork() { ConnectivityManager cm = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE); NetworkInfo netInfo = cm.getActiveNetworkInfo(); if (netInfo == null || !netInfo.isConnected()) { showError(getString(R.string.error_network_title), getString(R.string.error_network_msg)); return false; } return true; } private void showError(String title, String msg) { if (title != null && msg != null) { // showDialog(DIALOG_ERROR); new AlertDialog.Builder(this).setTitle(getString(R.string.error_title) + title).setMessage(msg) .setNeutralButton(getString(R.string.ok), null).show(); } } private void dismissLoading() { if (finishApi && finishDir) { try { removeDialog(DIALOG_LOADING); } catch (IllegalArgumentException e) { Log.e(TAG, e.getMessage()); } } } public class GetDirTask extends AsyncTask<String, Void, String> { private String mErrorTitle; private String mErrorMsg; @Override protected void onPreExecute() { showDialog(DIALOG_LOADING); } @Override protected String doInBackground(String... url) { try { return new Net(url[0]).getString(); } catch (Exception e) { mErrorTitle = e.getClass().getCanonicalName(); mErrorMsg = e.getLocalizedMessage(); e.printStackTrace(); } return ""; } @Override protected void onPostExecute(String result) { finishDir = true; dismissLoading(); if (mErrorMsg == null) { mResultDir = result; } else { showError(mErrorTitle, mErrorMsg + getString(R.string.error_generic)); } } @Override protected void onCancelled() { finishDir = true; dismissLoading(); } } private class GetApiTask extends AsyncTask<String, Void, String> { private String mErrorTitle; private String mErrorMsg; @Override protected void onPreExecute() { showDialog(DIALOG_LOADING); // Clean UI ((ScrollView) findViewById(R.id.scroll)).removeAllViews(); ((TextView) findViewById(R.id.space_name)).setText(getString(R.string.empty)); ((TextView) findViewById(R.id.space_url)).setText(getString(R.string.empty)); ((ImageView) findViewById(R.id.space_image)).setImageBitmap(null); } @Override protected String doInBackground(String... url) { try { return new Net(url[0]).getString(); } catch (Exception e) { mErrorTitle = e.getClass().getCanonicalName(); mErrorMsg = e.getLocalizedMessage(); e.printStackTrace(); } return ""; } @Override protected void onPostExecute(String result) { finishApi = true; dismissLoading(); if (mErrorMsg == null) { mResultHs = result; populateDataHs(); } else { showError(mErrorTitle, mErrorMsg + getString(R.string.error_generic)); } } @Override protected void onCancelled() { finishApi = true; dismissLoading(); } } private class GetImage extends AsyncTask<String, Void, Bitmap> { private int mId; private String mErrorTitle; private String mErrorMsg; public GetImage(int id) { mId = id; } @Override protected void onPreExecute() { ImageView img = (ImageView) findViewById(mId); img.setImageResource(android.R.drawable.ic_popup_sync); AnimationDrawable anim = (AnimationDrawable) img.getDrawable(); anim.start(); } @Override protected Bitmap doInBackground(String... url) { try { return new Net(url[0]).getBitmap(); } catch (Exception e) { mErrorTitle = e.getClass().getCanonicalName(); mErrorMsg = e.getLocalizedMessage(); e.printStackTrace(); } return null; } @Override protected void onPostExecute(Bitmap result) { if (mErrorMsg == null) { ((ImageView) findViewById(mId)).setImageBitmap(result); } else { showError(mErrorTitle, mErrorMsg + getString(R.string.error_generic)); ((ImageView) findViewById(mId)).setImageResource(android.R.drawable.ic_menu_report_image); } } } private void populateDataHs() { try { HashMap<String, Object> data = new ParseGeneric(mResultHs).getData(); // Initialize views LayoutInflater inflater = getLayoutInflater(); LinearLayout vg = (LinearLayout) inflater.inflate(R.layout.base, null); ScrollView scroll = (ScrollView) findViewById(R.id.scroll); scroll.removeAllViews(); scroll.addView(vg); // Mandatory fields ((TextView) findViewById(R.id.space_name)).setText((String) data.get(ParseGeneric.API_NAME)); ((TextView) findViewById(R.id.space_url)).setText((String) data.get(ParseGeneric.API_URL)); getImageTask = new GetImage(R.id.space_image); getImageTask.execute((String) data.get(ParseGeneric.API_LOGO)); // Status text String status_txt = ""; if ((Boolean) data.get(ParseGeneric.API_STATUS)) { status_txt = OPEN; ((TextView) findViewById(R.id.status_txt)) .setCompoundDrawablesWithIntrinsicBounds(android.R.drawable.presence_online, 0, 0, 0); } else { status_txt = CLOSED; ((TextView) findViewById(R.id.status_txt)) .setCompoundDrawablesWithIntrinsicBounds(android.R.drawable.presence_busy, 0, 0, 0); } if (data.containsKey(ParseGeneric.API_STATUS_TXT)) { status_txt += ": " + (String) data.get(ParseGeneric.API_STATUS_TXT); } ((TextView) findViewById(R.id.status_txt)).setText(status_txt); // Status last change if (data.containsKey(ParseGeneric.API_LASTCHANGE)) { TextView tv = (TextView) inflater.inflate(R.layout.entry, null); tv.setAutoLinkMask(0); tv.setText( getString(R.string.api_lastchange) + " " + (String) data.get(ParseGeneric.API_LASTCHANGE)); vg.addView(tv); } // Status duration if (data.containsKey(ParseGeneric.API_EXT_DURATION) && (Boolean) data.get(ParseGeneric.API_STATUS)) { TextView tv = (TextView) inflater.inflate(R.layout.entry, null); tv.setText(getString(R.string.api_duration) + " " + (String) data.get(ParseGeneric.API_EXT_DURATION) + getString(R.string.api_duration_hours)); vg.addView(tv); } // Location Pattern ptn = Pattern.compile("^.*$", Pattern.DOTALL); if (data.containsKey(ParseGeneric.API_ADDRESS) || data.containsKey(ParseGeneric.API_LON)) { TextView title = (TextView) inflater.inflate(R.layout.title, null); title.setText(getString(R.string.api_location)); vg.addView(title); inflater.inflate(R.layout.separator, vg); // Address if (data.containsKey(ParseGeneric.API_ADDRESS)) { TextView tv = (TextView) inflater.inflate(R.layout.entry, null); tv.setAutoLinkMask(0); tv.setText((String) data.get(ParseGeneric.API_ADDRESS)); Linkify.addLinks(tv, ptn, MAP_SEARCH); vg.addView(tv); } // Lon/Lat if (data.containsKey(ParseGeneric.API_LON) && data.containsKey(ParseGeneric.API_LAT)) { String addr = (data.containsKey(ParseGeneric.API_ADDRESS)) ? (String) data.get(ParseGeneric.API_ADDRESS) : getString(R.string.empty); TextView tv = (TextView) inflater.inflate(R.layout.entry, null); tv.setAutoLinkMask(0); tv.setText((String) data.get(ParseGeneric.API_LON) + ", " + (String) data.get(ParseGeneric.API_LAT)); Linkify.addLinks(tv, ptn, String.format(MAP_COORD, (String) data.get(ParseGeneric.API_LAT), (String) data.get(ParseGeneric.API_LON), addr)); vg.addView(tv); } } // Contact if (data.containsKey(ParseGeneric.API_PHONE) || data.containsKey(ParseGeneric.API_TWITTER) || data.containsKey(ParseGeneric.API_IRC) || data.containsKey(ParseGeneric.API_EMAIL) || data.containsKey(ParseGeneric.API_ML)) { TextView title = (TextView) inflater.inflate(R.layout.title, null); title.setText(R.string.api_contact); vg.addView(title); inflater.inflate(R.layout.separator, vg); // Phone if (data.containsKey(ParseGeneric.API_PHONE)) { TextView tv = (TextView) inflater.inflate(R.layout.entry, null); tv.setText((String) data.get(ParseGeneric.API_PHONE)); vg.addView(tv); } // SIP if (data.containsKey(ParseGeneric.API_SIP)) { TextView tv = (TextView) inflater.inflate(R.layout.entry, null); tv.setText((String) data.get(ParseGeneric.API_SIP)); vg.addView(tv); } // Twitter if (data.containsKey(ParseGeneric.API_TWITTER)) { TextView tv = (TextView) inflater.inflate(R.layout.entry, null); tv.setText(TWITTER + (String) data.get(ParseGeneric.API_TWITTER)); vg.addView(tv); } // Identica if (data.containsKey(ParseGeneric.API_IDENTICA)) { TextView tv = (TextView) inflater.inflate(R.layout.entry, null); tv.setText((String) data.get(ParseGeneric.API_IDENTICA)); vg.addView(tv); } // Foursquare if (data.containsKey(ParseGeneric.API_FOURSQUARE)) { TextView tv = (TextView) inflater.inflate(R.layout.entry, null); tv.setText(FOURSQUARE + (String) data.get(ParseGeneric.API_FOURSQUARE)); vg.addView(tv); } // IRC if (data.containsKey(ParseGeneric.API_IRC)) { TextView tv = (TextView) inflater.inflate(R.layout.entry, null); tv.setAutoLinkMask(0); tv.setText((String) data.get(ParseGeneric.API_IRC)); vg.addView(tv); } // Email if (data.containsKey(ParseGeneric.API_EMAIL)) { TextView tv = (TextView) inflater.inflate(R.layout.entry, null); tv.setText((String) data.get(ParseGeneric.API_EMAIL)); vg.addView(tv); } // Jabber if (data.containsKey(ParseGeneric.API_JABBER)) { TextView tv = (TextView) inflater.inflate(R.layout.entry, null); tv.setText((String) data.get(ParseGeneric.API_JABBER)); vg.addView(tv); } // Mailing-List if (data.containsKey(ParseGeneric.API_ML)) { TextView tv = (TextView) inflater.inflate(R.layout.entry, null); tv.setText((String) data.get(ParseGeneric.API_ML)); vg.addView(tv); } } // Sensors if (data.containsKey(ParseGeneric.API_SENSORS)) { // Title TextView title = (TextView) inflater.inflate(R.layout.title, null); title.setText(getString(R.string.api_sensors)); vg.addView(title); inflater.inflate(R.layout.separator, vg); HashMap<String, ArrayList<HashMap<String, String>>> sensors = (HashMap<String, ArrayList<HashMap<String, String>>>) data .get(ParseGeneric.API_SENSORS); Set<String> names = sensors.keySet(); Iterator<String> it = names.iterator(); while (it.hasNext()) { String name = it.next(); // Subtitle String name_title = name.toLowerCase().replace("_", " "); name_title = name_title.substring(0, 1).toUpperCase() + name_title.substring(1, name_title.length()); TextView subtitle = (TextView) inflater.inflate(R.layout.subtitle, null); subtitle.setText(name_title); vg.addView(subtitle); // Sensors data ArrayList<HashMap<String, String>> sensorsData = sensors.get(name); for (HashMap<String, String> elem : sensorsData) { RelativeLayout rl = (RelativeLayout) inflater.inflate(R.layout.entry_sensor, null); if (elem.containsKey(ParseGeneric.API_VALUE)) { ((TextView) rl.findViewById(R.id.entry_value)) .setText(elem.get(ParseGeneric.API_VALUE)); } else { rl.findViewById(R.id.entry_value).setVisibility(View.GONE); } if (elem.containsKey(ParseGeneric.API_UNIT)) { ((TextView) rl.findViewById(R.id.entry_unit)).setText(elem.get(ParseGeneric.API_UNIT)); } else { rl.findViewById(R.id.entry_unit).setVisibility(View.GONE); } if (elem.containsKey(ParseGeneric.API_NAME2)) { ((TextView) rl.findViewById(R.id.entry_name)).setText(elem.get(ParseGeneric.API_NAME2)); } else { rl.findViewById(R.id.entry_name).setVisibility(View.GONE); } if (elem.containsKey(ParseGeneric.API_LOCATION2)) { ((TextView) rl.findViewById(R.id.entry_location)) .setText(elem.get(ParseGeneric.API_LOCATION2)); } else { rl.findViewById(R.id.entry_location).setVisibility(View.GONE); } if (elem.containsKey(ParseGeneric.API_DESCRIPTION)) { ((TextView) rl.findViewById(R.id.entry_description)) .setText(elem.get(ParseGeneric.API_DESCRIPTION)); } else { rl.findViewById(R.id.entry_description).setVisibility(View.GONE); } if (elem.containsKey(ParseGeneric.API_PROPERTIES)) { ((TextView) rl.findViewById(R.id.entry_properties)) .setText(elem.get(ParseGeneric.API_PROPERTIES)); } else { rl.findViewById(R.id.entry_properties).setVisibility(View.GONE); } if (elem.containsKey(ParseGeneric.API_MACHINES)) { ((TextView) rl.findViewById(R.id.entry_other)) .setText(elem.get(ParseGeneric.API_MACHINES)); } else if (elem.containsKey(ParseGeneric.API_NAMES)) { ((TextView) rl.findViewById(R.id.entry_other)) .setText(elem.get(ParseGeneric.API_NAMES)); } else { rl.findViewById(R.id.entry_other).setVisibility(View.GONE); } vg.addView(rl); } } } // Stream and cam if (data.containsKey(ParseGeneric.API_STREAM) || data.containsKey(ParseGeneric.API_CAM)) { TextView title = (TextView) inflater.inflate(R.layout.title, null); title.setText(getString(R.string.api_stream)); vg.addView(title); inflater.inflate(R.layout.separator, vg); // Stream if (data.containsKey(ParseGeneric.API_STREAM)) { HashMap<String, String> stream = (HashMap<String, String>) data.get(ParseGeneric.API_STREAM); for (Entry<String, String> entry : stream.entrySet()) { final String type = entry.getKey(); final String url = entry.getValue(); TextView tv = (TextView) inflater.inflate(R.layout.entry, null); tv.setText(url); tv.setOnClickListener(new View.OnClickListener() { public void onClick(View v) { Intent i = new Intent(Intent.ACTION_VIEW); i.setDataAndType(Uri.parse(url), type); startActivity(i); } }); vg.addView(tv); } } // Cam if (data.containsKey(ParseGeneric.API_CAM)) { HashMap<String, String> cam = (HashMap<String, String>) data.get(ParseGeneric.API_CAM); for (String value : cam.values()) { TextView tv = (TextView) inflater.inflate(R.layout.entry, null); tv.setText(value); vg.addView(tv); } } } } catch (Exception e) { e.printStackTrace(); showError(e.getClass().getCanonicalName(), e.getLocalizedMessage() + getString(R.string.error_generic)); } } }