/* Copyright (C) 2008-2011, Dirk Trossen, airs@dirk-trossen.de This program is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation as version 2.1 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package com.airs; import java.io.File; import com.airs.platform.HandlerManager; import android.app.Activity; import android.app.AlertDialog; import android.content.ComponentName; import android.content.DialogInterface; import android.content.Intent; import android.content.ServiceConnection; import android.content.res.Configuration; import android.database.Cursor; import android.net.Uri; import android.os.Bundle; import android.os.Environment; import android.os.IBinder; import android.provider.MediaStore.Images; import android.view.KeyEvent; import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; import android.view.View; import android.view.View.OnClickListener; import android.view.Window; import android.widget.AdapterView; import android.widget.AdapterView.OnItemClickListener; import android.widget.AdapterView.OnItemLongClickListener; import android.widget.Button; import android.widget.ListView; import android.widget.TextView; import android.widget.Toast; /** * Activity to view the current measurements of the ongoing local recording * * @see AIRS_local */ public class AIRS_measurements extends Activity implements OnItemClickListener, OnItemLongClickListener, OnClickListener { private TextView mTitle; private TextView mTitle2; private AIRS_local AIRS_locally; private ListView values; private Activity act; private Button exit; /** Called when the activity is first created. * @param savedInstanceState a Bundle of the saved state, according to Android lifecycle model */ @Override public void onCreate(Bundle savedInstanceState) { // Set up the window layout super.onCreate(savedInstanceState); act = this; requestWindowFeature(Window.FEATURE_CUSTOM_TITLE); setContentView(R.layout.values); getWindow().setFeatureInt(Window.FEATURE_CUSTOM_TITLE, R.layout.custom_title); // get window title fields mTitle = (TextView) findViewById(R.id.title_left_text); mTitle2 = (TextView) findViewById(R.id.title_right_text); mTitle.setText(R.string.app_name); // Find and set up the ListView for values values = (ListView)findViewById(R.id.valueList); // set listener for sensor list values.setOnItemClickListener(this); values.setOnItemLongClickListener(this); // Find and set up the ListView for values exit = (Button)findViewById(R.id.valuesExit); // set listener for EXIT button exit.setOnClickListener(this); // bind to service if (bindService(new Intent(this, AIRS_local.class), mConnection, 0)==false) Toast.makeText(getApplicationContext(), getString(R.string.binding_failed), Toast.LENGTH_LONG).show(); } /** Called when the activity is restarted. */ @Override public synchronized void onRestart() { super.onRestart(); // ask service to update value adapter if (AIRS_locally!=null) { AIRS_locally.show_values = true; AIRS_locally.refresh_values(); } } /** Called when the activity is stopped. */ @Override public void onStop() { super.onStop(); // stop service from updating value adapter if (AIRS_locally!=null) AIRS_locally.show_values = false; } /** Called when the activity is destroyed. */ @Override public void onDestroy() { super.onDestroy(); // stop service from updating value adapter if (AIRS_locally!=null) { AIRS_locally.show_values = false; unbindService(mConnection); } } /** * Called when called {@link android.app.Activity} has finished. See {@link android.app.Activity} how it works * @param requestCode ID being used when calling the Activity * @param resultCode result code being set by the called Activity * @param data Reference to the {@link android.content.Intent} with result data from the called Activity */ public void onActivityResult(int requestCode, int resultCode, Intent data) { return; } /** Called when the configuration of the activity has changed. * @param newConfig new configuration after change */ @Override public void onConfigurationChanged(Configuration newConfig) { //ignore orientation change super.onConfigurationChanged(newConfig); } @Override /** * Called for dispatching key events sent to the Activity * @param event Reference to the {@link android.view.KeyEvent} being pressed * @return true, if consumed, false otherwise */ public boolean dispatchKeyEvent(KeyEvent event) { // key de-pressed? if (event.getAction() == KeyEvent.ACTION_UP) // is it the BACK key? if (event.getKeyCode()==KeyEvent.KEYCODE_BACK) { finish(); return true; } return super.dispatchKeyEvent(event); } /** Called when the Options menu is opened * @param menu Reference to the {@link android.view.Menu} */ @Override public boolean onPrepareOptionsMenu(Menu menu) { MenuInflater inflater; menu.clear(); inflater = getMenuInflater(); inflater.inflate(R.menu.options_local_sensing, menu); return true; } /** Called when a button has been clicked on by the user * @param v Reference to the {android.view.View} of the button */ public void onClick(View v) { AlertDialog.Builder builder = new AlertDialog.Builder(this); builder.setMessage(getString(R.string.Exit_AIRS)) .setTitle(getString(R.string.AIRS_Local_Sensing)) .setCancelable(false) .setPositiveButton(getString(R.string.Yes), new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int id) { if (AIRS_locally != null) { // first unbind before stopping service! unbindService(mConnection); stopService(new Intent(act, AIRS_local.class)); AIRS_locally = null; } finish(); } }) .setNegativeButton(getString(R.string.No), new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int id) { dialog.cancel(); } }); AlertDialog alert = builder.create(); alert.show(); } /** Called when an option menu item has been selected by the user * @param item Reference to the {@link android.view.Menuitem} clicked on */ @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case R.id.main_about: Toast.makeText(getApplicationContext(), R.string.ValuesAbout, Toast.LENGTH_LONG).show(); return true; case R.id.local_pause: if (AIRS_locally != null) { mTitle2.setText(getString(R.string.Local_Sensing) + "..." + getString(R.string.paused)); AIRS_locally.pause_threads(); } break; case R.id.local_resume: if (AIRS_locally != null) { mTitle2.setText(R.string.Local_Sensing); AIRS_locally.resume_threads(); } break; } return false; } /** Called when a button has been long-clicked on by the user * @param parent Reference to parent view * @param view Reference to the View of the button * @param position position within parent view * @param id index in a list view */ public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) { String value; // show info for sensor selected if (AIRS_locally != null) { // do we share media? if (AIRS_locally.getSymbol((int)id).compareTo("MW") == 0) { value = AIRS_locally.getValue((int)id); String [] tokens = value.split(":"); // is it a camera picture? if (tokens[0] != null) if (tokens[1].trim().compareTo("camera") == 0) { // get filename if (tokens[2] != null) { // cut off '[file]' suffix String name = tokens[2].trim().substring(0, tokens[2].length() - " [file]".length()); // form full path File file = new File(HandlerManager.readRMS("MediaWatcherHandler::CameraDirectory", Environment.getExternalStorageDirectory()+"/DCIM/Camera"), name.trim()); Uri shareUri; // search for file in media store Cursor c = act.getContentResolver().query(Images.Media.EXTERNAL_CONTENT_URI, null, Images.Media.DATA + "=?", new String[] { file.getAbsolutePath() }, null); // if found -> share if (c.getCount() > 0 && c.moveToFirst()) { shareUri = Uri.withAppendedPath(Images.Media.EXTERNAL_CONTENT_URI, ""+ c.getInt(c.getColumnIndex(Images.Media._ID))); // now build and start chooser intent Intent intent = new Intent(Intent.ACTION_SEND); intent.setType("*/*"); intent.putExtra(Intent.EXTRA_STREAM, shareUri); intent.putExtra(Intent.EXTRA_TEXT, getString(R.string.Snapshot_publish) + " (https://market.android.com/details?id=com.airs)\n"); intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); act.startActivity(Intent.createChooser(intent,getString(R.string.Snapshot_share))); } else Toast.makeText(getApplicationContext(), getString(R.string.Snapshot_nothing_to_share), Toast.LENGTH_LONG).show(); c.close(); } } else Toast.makeText(getApplicationContext(), getString(R.string.Snapshot_only_pictures), Toast.LENGTH_LONG).show(); } else { // get sharing text first value = AIRS_locally.share((int)id); // only share if there's something to share if (value != null) { // now build and start chooser intent Intent intent = new Intent(Intent.ACTION_SEND); intent.setType("text/plain"); intent.putExtra(Intent.EXTRA_TEXT, value + "\n\n-------------------------------------------\n" + getString(R.string.Snapshot_publish) + " (https://market.android.com/details?id=com.airs)\n"); act.startActivity(Intent.createChooser(intent,getString(R.string.Measurements_share))); } } } return true; } /** * Called when clicking on a list item * @param av parent view * @param v View of clicked item * @param arg2 don't actually know * @param arg3 item in {@link android.view.ListView} being clicked */ public void onItemClick(AdapterView<?> av, View v, int arg2, long arg3) { // show info for sensor selected if (AIRS_locally != null) AIRS_locally.show_info((int)arg3); } private final ServiceConnection mConnection = new ServiceConnection() { public void onServiceConnected(ComponentName className, IBinder service) { // This is called when the connection with the service has been // established, giving us the service object we can use to // interact with the service. Because we have bound to a explicit // service that we know is running in our own process, we can // cast its IBinder to a concrete class and directly access it. AIRS_locally = ((AIRS_local.LocalBinder)service).getService(); if (AIRS_locally.running == false) Toast.makeText(getApplicationContext(), "AIRS local::Sensing not running!\nThe service might have crashed!", Toast.LENGTH_SHORT).show(); // now set the adapter for the values values.setAdapter(AIRS_locally.mValuesArrayAdapter); // set threads to show values and refresh latest they have AIRS_locally.show_values = true; AIRS_locally.refresh_values(); // set title according to paused state of local service if (AIRS_locally.paused == true) mTitle2.setText("Local Sensing...Paused"); // construct title right side with possible template name if (AIRS_locally.template != null) mTitle2.setText("Local Sensing: " + AIRS_locally.template); else mTitle2.setText("Local Sensing"); } public void onServiceDisconnected(ComponentName className) { // This is called when the connection with the service has been // unexpectedly disconnected -- that is, its process crashed. // Because it is running in our same process, we should never // see this happen. AIRS_locally = null; } }; }