/* * Copyright (C) 2007 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 edu.fsu.cs.contextprovider; import java.io.BufferedWriter; import java.io.File; import java.io.FileWriter; import java.io.IOException; import java.io.Writer; import java.net.MalformedURLException; import java.net.URL; import java.util.ArrayList; import java.util.HashMap; import java.util.LinkedHashMap; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Timer; import java.util.TimerTask; import java.util.Vector; import javax.xml.parsers.ParserConfigurationException; import javax.xml.parsers.SAXParser; import javax.xml.parsers.SAXParserFactory; import org.xml.sax.InputSource; import org.xml.sax.SAXException; import org.xml.sax.XMLReader; import android.app.AlarmManager; import android.app.AlertDialog; import android.app.Dialog; import android.app.ExpandableListActivity; import android.app.PendingIntent; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.ServiceConnection; import android.content.SharedPreferences; import android.content.SharedPreferences.OnSharedPreferenceChangeListener; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.location.Geocoder; import android.net.Uri; import android.os.Bundle; import android.os.Environment; import android.os.Handler; import android.os.IBinder; import android.os.RemoteException; import android.os.SystemClock; import android.preference.PreferenceManager; import android.speech.tts.TextToSpeech; import android.text.ClipboardManager; import android.util.Log; import android.view.ContextMenu; import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.widget.AdapterView; import android.widget.ArrayAdapter; import android.widget.BaseExpandableListAdapter; import android.widget.ExpandableListAdapter; import android.widget.ExpandableListView; import android.widget.ExpandableListView.OnChildClickListener; import android.widget.SimpleExpandableListAdapter; import android.widget.Toast; import edu.fsu.cs.contextprovider.data.ContextConstants; import edu.fsu.cs.contextprovider.dialog.AddressDialog; import edu.fsu.cs.contextprovider.monitor.DerivedMonitor; import edu.fsu.cs.contextprovider.monitor.LocationMonitor; import edu.fsu.cs.contextprovider.monitor.MovementMonitor; import edu.fsu.cs.contextprovider.monitor.SocialMonitor; import edu.fsu.cs.contextprovider.monitor.SystemMonitor; import edu.fsu.cs.contextprovider.monitor.WeatherMonitor; import edu.fsu.cs.contextprovider.rpc.ContextProviderService; import edu.fsu.cs.contextprovider.rpc.IContextProviderService; import edu.fsu.cs.contextprovider.sensor.AccelerometerService; import edu.fsu.cs.contextprovider.sensor.LightService; public class ContextExpandableListActivity extends ExpandableListActivity implements OnChildClickListener, TextToSpeech.OnInitListener, OnSharedPreferenceChangeListener { private static final String TAG = "ContextExpandableListActivity"; private static final boolean DEBUG = true; private static final String NAME = "NAME"; private static final String VALUE = "VALUE"; private ExpandableListAdapter mAdapter; private static Timer timer = new Timer(); // private static final int MENU_ADD_ID = Menu.FIRST + 2; // private static final int MENU_SHARE_ID = Menu.FIRST + 3; private static final int MENU_SET_HOME_ID = Menu.FIRST + 1; private static final int MENU_SET_WORK_ID = Menu.FIRST + 2; private static final int MENU_REFRESH_ID = Menu.FIRST + 3; private static final int MENU_PREFS_ID = Menu.FIRST + 4; private static final int MENU_ABOUT_ID = Menu.FIRST + 5; private static final int CONTEXT_DELETE_ID = 0; private static final int PREFS_EDIT = 0; private static final int DIALOG_ABOUT = 0; private static final String CSV_FILENAME = "Context.csv"; private boolean locationEnabled; private boolean movementEnabled; private boolean weatherEnabled; private boolean socialEnabled; private boolean systemEnabled; private boolean derivedEnabled; // general prefs private boolean startupEnabled; private boolean accuracyPopupEnabled; private boolean accuracyAudioEnabled; private String accuracyPopupString; private long accuracyPopupPeriod; private int accuracyDismissDelay; private boolean ttsEnabled; SharedPreferences prefs; public static boolean running = false; public static TextToSpeech tts; ClipboardManager clip = null; List<Map<String, String>> groupData = new ArrayList<Map<String, String>>(); List<List<Map<String, String>>> childData = new ArrayList<List<Map<String, String>>>(); public static IContextProviderService mService = null; Vector<ContextListItem> Clist = new Vector<ContextListItem>(); // ArrayAdapter<ContextListItem> adapter = null; ArrayAdapter<ContextListItem> addressAdapter = null; private CopyState copyState = new CopyState(); private ServiceConnection conn = new ServiceConnection() { public void onServiceConnected(ComponentName name, IBinder service) { mService = IContextProviderService.Stub.asInterface(service); } public void onServiceDisconnected(ComponentName name) { unbindService(conn); } }; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); PreferenceManager.setDefaultValues(this, ContextConstants.CONTEXT_PREFS, MODE_WORLD_READABLE, R.xml.prefs, false); prefs = getSharedPreferences(ContextConstants.CONTEXT_PREFS, MODE_PRIVATE); getPrefs(); if (!prefs.contains(ContextConstants.PREFS_FIRST_RUN)) { Toast.makeText(this, "First Run", Toast.LENGTH_LONG).show(); SharedPreferences.Editor prefsEditor = prefs.edit(); prefsEditor.putBoolean(ContextConstants.PREFS_FIRST_RUN, false); prefsEditor.commit(); // startup the primary context service (if just installed) startService(new Intent(this, ContextService.class)); AlarmManager manager = (AlarmManager) getSystemService(Context.ALARM_SERVICE); Intent intent = new Intent(getBaseContext(), edu.fsu.cs.contextprovider.wakeup.WakeupAlarmReceiver.class); PendingIntent pi = PendingIntent.getBroadcast(getBaseContext(), 0, intent, 0); manager.setRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP, SystemClock.elapsedRealtime() + 10000, accuracyPopupPeriod * 1000, pi); } tts = new TextToSpeech(this, this); running = true; if (clip == null) { clip = (ClipboardManager) getSystemService(CLIPBOARD_SERVICE); } /* Start ContextProviderService */ bindService(new Intent(this, ContextProviderService.class), conn, Context.BIND_AUTO_CREATE); if (locationEnabled) { refreshLocation(); } if (movementEnabled) { refreshMovement(); } if (weatherEnabled) { refreshWeather(); } if (systemEnabled) { refreshSystem(); } if (socialEnabled) { refreshSocial(); } if (derivedEnabled) { refreshDerived(); } mAdapter = new SimpleExpandableListAdapter(this, groupData, android.R.layout.simple_expandable_list_item_1, new String[] { NAME, VALUE }, new int[] { android.R.id.text1, android.R.id.text2 }, childData, android.R.layout.simple_expandable_list_item_2, new String[] { NAME, VALUE }, new int[] { android.R.id.text1, android.R.id.text2 }); setListAdapter(mAdapter); Handler handler = new Handler(); handler.postDelayed(new Runnable() { public void run() { refresh(); } }, 1000); } public void onInit(int status) { Locale loc = Locale.getDefault(); if (tts.isLanguageAvailable(loc) >= TextToSpeech.LANG_AVAILABLE) { tts.setLanguage(loc); } if (ttsEnabled) tts.speak("Text to Speach Initialized", TextToSpeech.QUEUE_FLUSH, null); } private void getPrefs() { locationEnabled = prefs.getBoolean("PREFS_LOCATION_ENABLED", true); movementEnabled = prefs.getBoolean("PREFS_MOVEMENT_ENABLED", true); weatherEnabled = prefs.getBoolean("PREFS_WEATHER_ENABLED", true); socialEnabled = prefs.getBoolean("PREFS_SOCIAL_ENABLED", true); systemEnabled = prefs.getBoolean("PREFS_SYSTEM_ENABLED", true); derivedEnabled = prefs.getBoolean("PREFS_DERIVED_ENABLED", true); // accuracyPopupPeriod = prefs.getLong(ContextConstants.PREFS_ACCURACY_POPUP_FREQ, 30); accuracyPopupString = prefs.getString(ContextConstants.PREFS_ACCURACY_POPUP_FREQ, "30"); accuracyPopupPeriod = Long.parseLong(accuracyPopupString); ttsEnabled = prefs.getBoolean("PREFS_TTS_ENABLED", false); } private void refresh() { if (mService == null) { return; } Map<String, String> cntx = null; try { cntx = (Map<String, String>) mService.getAll(); } catch (RemoteException e) { // TODO Auto-generated catch block e.printStackTrace(); } groupData.clear(); childData.clear(); if (locationEnabled) refreshLocation(); if (movementEnabled) refreshMovement(); if (weatherEnabled) refreshWeather(); if (systemEnabled) refreshSystem(); if (socialEnabled) refreshSocial(); if (derivedEnabled) refreshDerived(); BaseExpandableListAdapter refresh = (BaseExpandableListAdapter) mAdapter; refresh.notifyDataSetChanged(); copyState.reset(); } private void refreshLocation() { if (mService == null) { return; } Map<String, String> locationMap = new HashMap<String, String>(); groupData.add(locationMap); locationMap.put(NAME, "Location"); locationMap.put(VALUE, "Location"); List<Map<String, String>> location = new ArrayList<Map<String, String>>(); Map<String, String> curChildMap = new HashMap<String, String>(); location.add(curChildMap); curChildMap.put(NAME, ContextConstants.LOCATION_ADDRESS); curChildMap.put(VALUE, LocationMonitor.getAddress()); curChildMap = new HashMap<String, String>(); location.add(curChildMap); curChildMap.put(NAME, ContextConstants.LOCATION_HOOD); curChildMap.put(VALUE, LocationMonitor.getNeighborhood()); curChildMap = new HashMap<String, String>(); location.add(curChildMap); curChildMap.put(NAME, ContextConstants.LOCATION_ZIP); curChildMap.put(VALUE, LocationMonitor.getZip()); curChildMap = new HashMap<String, String>(); location.add(curChildMap); curChildMap.put(NAME, ContextConstants.LOCATION_LATITUDE); curChildMap.put(VALUE, String.valueOf(LocationMonitor.getLatitude())); curChildMap = new HashMap<String, String>(); location.add(curChildMap); curChildMap.put(NAME, ContextConstants.LOCATION_LONGITUDE); curChildMap.put(VALUE, String.valueOf(LocationMonitor.getLongitude())); curChildMap = new HashMap<String, String>(); location.add(curChildMap); curChildMap.put(NAME, ContextConstants.LOCATION_ALTITUDE); curChildMap.put(VALUE, String.valueOf(LocationMonitor.getAltitude())); childData.add(location); } private void refreshMovement() { if (mService == null) { return; } Map<String, String> movementMap = new HashMap<String, String>(); groupData.add(movementMap); movementMap.put(NAME, "Movement"); movementMap.put(VALUE, "Movement"); List<Map<String, String>> movement = new ArrayList<Map<String, String>>(); Map<String, String> curChildMap = new HashMap<String, String>(); movement.add(curChildMap); curChildMap.put(NAME, ContextConstants.MOVEMENT_STATE); curChildMap.put(VALUE, MovementMonitor.getMovementState()); curChildMap = new HashMap<String, String>(); movement.add(curChildMap); curChildMap.put(NAME, ContextConstants.MOVEMENT_SPEED); curChildMap.put(VALUE, String.valueOf(MovementMonitor.getSpeedMph())); curChildMap = new HashMap<String, String>(); movement.add(curChildMap); curChildMap.put(NAME, ContextConstants.MOVEMENT_BEARING); curChildMap.put(VALUE, String.valueOf(LocationMonitor.getBearing())); curChildMap = new HashMap<String, String>(); movement.add(curChildMap); curChildMap.put(NAME, ContextConstants.MOVEMENT_STEP_COUNT); curChildMap.put(VALUE, String.valueOf(AccelerometerService.getStepCount())); curChildMap = new HashMap<String, String>(); movement.add(curChildMap); curChildMap.put(NAME, ContextConstants.MOVEMENT_LAST_STEP); curChildMap.put(VALUE, String.valueOf(AccelerometerService.getStepTimestamp())); childData.add(movement); } private void refreshProximity() { if (mService == null) { return; } Map<String, String> proximityMap = new HashMap<String, String>(); groupData.add(proximityMap); proximityMap.put(NAME, "Proximity"); proximityMap.put(VALUE, "Proximity"); List<Map<String, String>> proximity = new ArrayList<Map<String, String>>(); SharedPreferences pref = getSharedPreferences(ContextConstants.PREFS_ADDRESS, 0); Map<String, String> list = (Map<String, String>) pref.getAll(); for (Map.Entry<String, String> entry : list.entrySet()) { Map<String, String> curChildMap = new HashMap<String, String>(); proximity.add(curChildMap); curChildMap.put(NAME, entry.getKey()); double prox = 0; try { prox = mService.proximityToAddress(entry.getValue()); } catch (RemoteException e) { // TODO Auto-generated catch block e.printStackTrace(); } curChildMap.put(VALUE, String.valueOf(prox)); } childData.add(proximity); } private void refreshWeather() { if (mService == null) { return; } Map<String, String> weatherMap = new HashMap<String, String>(); groupData.add(weatherMap); weatherMap.put(NAME, "Weather"); weatherMap.put(VALUE, "Weather"); List<Map<String, String>> weather = new ArrayList<Map<String, String>>(); Map<String, String> curChildMap = new HashMap<String, String>(); weather.add(curChildMap); curChildMap.put(NAME, ContextConstants.WEATHER_TEMPERATURE); curChildMap.put(VALUE, WeatherMonitor.getWeatherTemp() + " degrees F"); curChildMap = new HashMap<String, String>(); weather.add(curChildMap); curChildMap.put(NAME, ContextConstants.WEATHER_CONDITION); curChildMap.put(VALUE, WeatherMonitor.getWeatherCond()); curChildMap = new HashMap<String, String>(); weather.add(curChildMap); curChildMap.put(NAME, ContextConstants.WEATHER_HUMIDITY); curChildMap.put(VALUE, WeatherMonitor.getWeatherHumid()); curChildMap = new HashMap<String, String>(); weather.add(curChildMap); curChildMap.put(NAME, ContextConstants.WEATHER_WIND); curChildMap.put(VALUE, WeatherMonitor.getWeatherWindCond()); curChildMap = new HashMap<String, String>(); weather.add(curChildMap); curChildMap.put(NAME, ContextConstants.WEATHER_HAZARD); curChildMap.put(VALUE, WeatherMonitor.getWeatherHazard()); childData.add(weather); } private void refreshSocial() { if (mService == null) { return; } Map<String, String> socialMap = new HashMap<String, String>(); groupData.add(socialMap); socialMap.put(NAME, "Social"); socialMap.put(VALUE, "Social"); List<Map<String, String>> social = new ArrayList<Map<String, String>>(); Map<String, String> curChildMap = new HashMap<String, String>(); social.add(curChildMap); curChildMap.put(NAME, ContextConstants.SOCIAL_CONTACT); String status = SocialMonitor.getContact(); curChildMap = new HashMap<String, String>(); social.add(curChildMap); curChildMap.put(NAME, ContextConstants.SOCIAL_COMMUNICATION); curChildMap.put(VALUE, SocialMonitor.getCommunication()); curChildMap = new HashMap<String, String>(); social.add(curChildMap); curChildMap.put(NAME, ContextConstants.SOCIAL_MESSAGE); curChildMap.put(VALUE, SocialMonitor.getMessage()); curChildMap = new HashMap<String, String>(); social.add(curChildMap); curChildMap.put(NAME, ContextConstants.SOCIAL_LAST_IN); curChildMap.put(VALUE, String.valueOf(SocialMonitor.getLastIn())); curChildMap = new HashMap<String, String>(); social.add(curChildMap); curChildMap.put(NAME, ContextConstants.SOCIAL_LAST_OUT); curChildMap.put(VALUE, String.valueOf(SocialMonitor.getLastOut())); childData.add(social); } private void refreshSystem() { if (mService == null) { return; } Map<String, String> systemMap = new HashMap<String, String>(); groupData.add(systemMap); systemMap.put(NAME, "System"); systemMap.put(VALUE, "System"); List<Map<String, String>> system = new ArrayList<Map<String, String>>(); Map<String, String> curChildMap = new HashMap<String, String>(); system.add(curChildMap); curChildMap.put(NAME, ContextConstants.SYSTEM_STATE); curChildMap.put(VALUE, String.valueOf(SystemMonitor.getState())); curChildMap = new HashMap<String, String>(); system.add(curChildMap); curChildMap.put(NAME, ContextConstants.SYSTEM_BATTERY_LEVEL); curChildMap.put(VALUE, String.valueOf(SystemMonitor.getBatteryLevel())); curChildMap = new HashMap<String, String>(); system.add(curChildMap); curChildMap.put(NAME, ContextConstants.SYSTEM_PLUGGED); curChildMap.put(VALUE, String.valueOf(SystemMonitor.isBatteryPlugged())); curChildMap = new HashMap<String, String>(); system.add(curChildMap); curChildMap.put(NAME, ContextConstants.SYSTEM_LAST_PLUGGED); curChildMap.put(VALUE, String.valueOf(SystemMonitor.getBatteryLastPlugged())); curChildMap = new HashMap<String, String>(); system.add(curChildMap); curChildMap.put(NAME, ContextConstants.SYSTEM_LAST_PRESENT); curChildMap.put(VALUE, String.valueOf(SystemMonitor.getUserLastPresent())); curChildMap = new HashMap<String, String>(); system.add(curChildMap); curChildMap.put(NAME, ContextConstants.SYSTEM_WIFI_SSID); curChildMap.put(VALUE, String.valueOf(SystemMonitor.getSSID())); curChildMap = new HashMap<String, String>(); system.add(curChildMap); curChildMap.put(NAME, ContextConstants.SYSTEM_WIFI_SIGNAL); curChildMap.put(VALUE, String.valueOf(SystemMonitor.getSignal())); childData.add(system); } private void refreshDerived() { if (mService == null) { return; } Map<String, String> derivedMap = new HashMap<String, String>(); groupData.add(derivedMap); derivedMap.put(NAME, "Derived"); derivedMap.put(VALUE, "Derived"); List<Map<String, String>> derived = new ArrayList<Map<String, String>>(); Map<String, String> curChildMap = new HashMap<String, String>(); derived.add(curChildMap); curChildMap.put(NAME, ContextConstants.DERIVED_PLACE); curChildMap.put(VALUE, "Home"); curChildMap = new HashMap<String, String>(); derived.add(curChildMap); curChildMap.put(NAME, ContextConstants.DERIVED_ACTIVITY); curChildMap.put(VALUE, "Sleeping"); curChildMap = new HashMap<String, String>(); derived.add(curChildMap); curChildMap.put(NAME, ContextConstants.DERIVED_ONPERSON); curChildMap.put(VALUE, String.valueOf(LightService.isInPocket())); curChildMap = new HashMap<String, String>(); derived.add(curChildMap); curChildMap.put(NAME, ContextConstants.DERIVED_SHELTER); curChildMap.put(VALUE, String.valueOf(LocationMonitor.isInside())); curChildMap = new HashMap<String, String>(); derived.add(curChildMap); curChildMap.put(NAME, ContextConstants.DERIVED_MOOD); curChildMap.put(VALUE, "Happy"); childData.add(derived); } @Override public void onDestroy() { // MovementMonitor.StopThread(); super.onDestroy(); tts.shutdown(); unbindService(conn); } @Override public boolean onCreateOptionsMenu(Menu menu) { // menu.add(Menu.NONE, MENU_ADD_ID, Menu.NONE, // "Add").setIcon(android.R.drawable.ic_menu_add).setAlphabeticShortcut('a'); menu.add(Menu.NONE, MENU_SET_HOME_ID, Menu.NONE, "Set Home").setIcon(android.R.drawable.ic_menu_compass).setAlphabeticShortcut('h'); menu.add(Menu.NONE, MENU_SET_WORK_ID, Menu.NONE, "Set Work").setIcon(android.R.drawable.ic_menu_compass).setAlphabeticShortcut('w'); menu.add(Menu.NONE, MENU_REFRESH_ID, Menu.NONE, "Refresh").setIcon(android.R.drawable.ic_menu_rotate).setAlphabeticShortcut('r'); // menu.add(Menu.NONE, MENU_SHARE_ID, Menu.NONE, // "Share").setIcon(android.R.drawable.ic_menu_share).setAlphabeticShortcut('s'); menu.add(Menu.NONE, MENU_PREFS_ID, Menu.NONE, "Prefs").setIcon(android.R.drawable.ic_menu_preferences).setAlphabeticShortcut('p'); menu.add(Menu.NONE, MENU_ABOUT_ID, Menu.NONE, "About").setIcon(android.R.drawable.ic_menu_info_details).setAlphabeticShortcut('i'); return (super.onCreateOptionsMenu(menu)); } @Override public boolean onOptionsItemSelected(MenuItem item) { Intent intent = null; switch (item.getItemId()) { case MENU_REFRESH_ID: refresh(); return true; case MENU_SET_HOME_ID: intent = new Intent(getApplicationContext(), edu.fsu.cs.contextprovider.map.AddPlaceMapActivity.class); intent.putExtra(ContextConstants.PLACE_REQUEST_ID, ContextConstants.SET_HOME_REQUEST); startActivityForResult(intent, ContextConstants.SET_HOME_REQUEST); // refresh(); return true; case MENU_SET_WORK_ID: intent = new Intent(getApplicationContext(), edu.fsu.cs.contextprovider.map.AddPlaceMapActivity.class); intent.putExtra(ContextConstants.PLACE_REQUEST_ID, ContextConstants.SET_WORK_REQUEST); startActivityForResult(intent, ContextConstants.SET_WORK_REQUEST); // startActivityForResult(new Intent(getApplicationContext(), // edu.fsu.cs.contextprovider.map.AddPlaceMapActivity.class), // ContextConstants.SET_WORK_REQUEST); // refresh(); return true; // case MENU_ADD_ID: // refresh(); // Context context = getApplicationContext(); // String address = null; // try { // address = mService.getCurrentAddress(); // } catch (RemoteException e) { // // TODO Auto-generated catch block // e.printStackTrace(); // } // AddressDialog.add addAddressDialog = new AddressDialog.add(this, // address); // addAddressDialog.show(); // this.refreshProximity(); // return (true); // case MENU_SHARE_ID: // try { // exportToFile(); // } catch (IOException e) { // // TODO Auto-generated catch block // e.printStackTrace(); // } // return true; case MENU_PREFS_ID: editPrefs(); return true; case MENU_ABOUT_ID: showDialog(DIALOG_ABOUT); return true; } return (super.onOptionsItemSelected(item)); } protected void onActivityResult(int requestCode, int resultCode, Intent data) { if (requestCode == ContextConstants.SET_HOME_REQUEST) { if (resultCode == RESULT_OK) { Toast.makeText(this, "Home Set Sucessfully", Toast.LENGTH_LONG).show(); } } else if (requestCode == ContextConstants.SET_WORK_REQUEST) { if (resultCode == RESULT_OK) { Toast.makeText(this, "Work Set Sucessfully", Toast.LENGTH_LONG).show(); } } } @Override public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) { menu.add(Menu.NONE, CONTEXT_DELETE_ID, Menu.NONE, "Delete").setIcon(android.R.drawable.ic_menu_delete).setAlphabeticShortcut('d'); } @Override public boolean onContextItemSelected(MenuItem item) { switch (item.getItemId()) { case CONTEXT_DELETE_ID: AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) item.getMenuInfo(); return true; } return (super.onOptionsItemSelected(item)); } private class ContextListItem { private String name; private String value; public String getName() { return name; } public void setName(String name) { this.name = name; } public String getValue() { return value; } public void setValue(String value) { this.value = value; } public String toString() { return name + ": " + value; } } @Override public boolean onChildClick(ExpandableListView parent, View v, int groupPosition, int childPosition, long id) { String copiedString = null; Context context = getApplicationContext(); List<Map<String, String>> category = childData.get(groupPosition); Map<String, String> item = category.get(childPosition); String name = item.get(NAME); String value = item.get(VALUE); boolean wasClicked = copyState.click(groupPosition, childPosition); /* copy value on first click */ if (wasClicked == false) { copiedString = value; /* copy name on second click */ } else { copiedString = name; } Toast.makeText(context, "Copied: [" + copiedString + "]", Toast.LENGTH_SHORT).show(); clip.setText(copiedString); Log.i("LIST", "Name [" + name + "] | Value [" + value + "] | id [" + id + "]"); return true; } private class CopyState { int groupPosition = -1; int childPosition = -1; boolean wasClicked = false; CopyState() { } void reset() { wasClicked = false; groupPosition = -1; childPosition = -1; } boolean click(int group, int child) { if (groupPosition != group || childPosition != child) { wasClicked = true; groupPosition = group; childPosition = child; return false; } if (wasClicked == true) { wasClicked = false; return true; } else { wasClicked = true; return false; } } } private void editPrefs() { Intent i = new Intent(this, PrefsActivity.class); startActivityForResult(i, PREFS_EDIT); } @Override protected Dialog onCreateDialog(int id) { Dialog dialog; switch (id) { case DIALOG_ABOUT: dialog = getAboutBox(); break; default: dialog = null; } return dialog; } private AlertDialog getAboutBox() { String title = getString(R.string.app_name) + " build " + getVersion(this); return new AlertDialog.Builder(ContextExpandableListActivity.this).setTitle(title).setView(View.inflate(this, R.layout.about, null)).setIcon( R.drawable.context64).setPositiveButton("OK", null).create(); } public static String getVersion(Context context) { String version = "1.0"; try { PackageInfo pi = context.getPackageManager().getPackageInfo(context.getPackageName(), 0); version = pi.versionName; } catch (PackageManager.NameNotFoundException e) { Log.e(TAG, "Package name not found", e); } return version; } public void exportToFile() throws IOException { String path = Environment.getExternalStorageDirectory() + "/" + CSV_FILENAME; File file = new File(path); file.createNewFile(); if (!file.isFile()) { throw new IllegalArgumentException("Should not be a directory: " + file); } if (!file.canWrite()) { throw new IllegalArgumentException("File cannot be written: " + file); } Writer output = new BufferedWriter(new FileWriter(file)); HashMap<String, String> cntx = null; String line; // ContextProvider.getAll(cntx); cntx = ContextProvider.getAllUnordered(); for (LinkedHashMap.Entry<String, String> entry : cntx.entrySet()) { ContextListItem item = new ContextListItem(); item.setName(entry.getKey()); item.setValue(entry.getValue()); // Clist.add(item); line = item.toString(); output.write(line + "\n"); } output.close(); Toast.makeText(this, String.format("Saved", path), Toast.LENGTH_LONG).show(); Intent shareIntent = new Intent(Intent.ACTION_SEND); shareIntent.putExtra(Intent.EXTRA_STREAM, Uri.parse("file://" + path)); shareIntent.setType("text/plain"); startActivity(Intent.createChooser(shareIntent, "Share Context Using...")); } @Override public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) { if (DEBUG) { Toast.makeText(this, "ContextExpandableList prefs changed", Toast.LENGTH_SHORT).show(); } } }