/* * Copyright (C) 2012, Katy Hilgenberg. * Special acknowledgments to: Knowledge & Data Engineering Group, University of Kassel (http://www.kde.cs.uni-kassel.de). * Contact: sdcf@cs.uni-kassel.de * * This file is part of the SDCFramework (Sensor Data Collection Framework) project. * * The SDCFramework 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, either version 3 of the License, or * (at your option) any later version. * * The SDCFramework 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 the SDCFramework. If not, see <http://www.gnu.org/licenses/>. */ package de.unikassel.android.sdcframework.app; import java.io.File; import java.io.FileInputStream; import java.io.InputStream; import org.simpleframework.xml.Serializer; import org.simpleframework.xml.core.Persister; import android.annotation.SuppressLint; import android.app.Activity; import android.content.Intent; import android.content.IntentFilter; import android.os.Environment; import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; import de.unikassel.android.sdcframework.R; import de.unikassel.android.sdcframework.app.facade.DialogUtils; import de.unikassel.android.sdcframework.app.facade.SDCService; import de.unikassel.android.sdcframework.app.scheduler.ScheduleService; import de.unikassel.android.sdcframework.app.scheduler.ScheduleValidator; import de.unikassel.android.sdcframework.data.SDCConfiguration; import de.unikassel.android.sdcframework.data.WeekdaySchedule; import de.unikassel.android.sdcframework.data.WeekdayScheduleEntry; import de.unikassel.android.sdcframework.data.WeeklySchedule; import de.unikassel.android.sdcframework.preferences.ApplicationPreferenceManagerImpl; import de.unikassel.android.sdcframework.preferences.SDCConfigurationManager; import de.unikassel.android.sdcframework.preferences.facade.ApplicationPreferenceManager; import de.unikassel.android.sdcframework.service.ServiceRunningStateListener; import de.unikassel.android.sdcframework.service.ServiceUtils; import de.unikassel.android.sdcframework.util.FileUtils; import de.unikassel.android.sdcframework.util.facade.Encryption; /** * Base class for service control activities. * * @author Katy Hilgenberg * */ public abstract class AbstractServiceControlActivity extends Activity { /** * The service class name */ private final Class< ? > serviceClass; /** * The service action name */ private final String action = SDCService.ACTION; /** * Extension for file backups. */ private static final String BAK_EXTENSION = ".bak"; /** * Title for RSA key file selection. */ private static final String TITLE_RSA_KEY_SELECTION = "Select RSA Public Key File"; /** * Title for XML configuration key file selection. */ private static final String TITLE_XML_CONFIG_FILE_SELECTION = "Select XML Configuration File"; /** * File selection dialog identifier for pub key file selection. */ private static final int SELECT_EXT_RSA_PUBKEY_FILE = 0; /** * File selection dialog identifier for external defaults file selection. */ private static final int SELECT_EXT_DEFAULTS_FILE = 1; /** * The service running state listener */ private final ServiceRunningStateListener serviceRunningStateListner; /** * The preference manager */ private final ApplicationPreferenceManager prefManager; /** * Constructor * * @param serviceClass */ public AbstractServiceControlActivity( Class< ? > serviceClass ) { super(); this.serviceClass = serviceClass; this.prefManager = new ApplicationPreferenceManagerImpl(); this.serviceRunningStateListner = new ServiceRunningStateListener( action ) { /* * (non-Javadoc) * * @see * de.unikassel.android.sdcframework.service.ServiceRunningStateListener * #serviceStateChanged(boolean) */ @Override protected void serviceStateChanged( boolean isRunning ) { onServiceRunningStateChanged( isRunning ); } }; } /** * Getter for the service class * * @return the service class */ public final Class< ? > getServiceClass() { return serviceClass; } /** * Getter for preference manager * * @return the preference manager */ public final ApplicationPreferenceManager getPrefManager() { return prefManager; } /** * Method to handle the selection of "load external defaults" in the option * menu * * @return true if successful, false otherwise */ private final boolean onLoadRSAPublicKey() { Intent intent = new Intent( this, SDCFileBrowserActivity.class ); intent.putExtra( SDCFileBrowserActivity.TITLE, TITLE_RSA_KEY_SELECTION ); intent.putExtra( SDCFileBrowserActivity.STARTDIR, Environment.getExternalStorageDirectory().getAbsolutePath() ); intent.putExtra( SDCFileBrowserActivity.PATTERN, "\\.*\\.key" ); startActivityForResult( intent, SELECT_EXT_RSA_PUBKEY_FILE ); return true; } /** * Method to handle the selection of "load external defaults" in the option * menu. * * @return true if successful, false otherwise */ private final boolean onLoadDefaults() { Intent intent = new Intent( this, SDCFileBrowserActivity.class ); intent.putExtra( SDCFileBrowserActivity.TITLE, TITLE_XML_CONFIG_FILE_SELECTION ); intent.putExtra( SDCFileBrowserActivity.STARTDIR, Environment.getExternalStorageDirectory().getAbsolutePath() ); intent.putExtra( SDCFileBrowserActivity.PATTERN, "\\.*\\.xml" ); startActivityForResult( intent, SELECT_EXT_DEFAULTS_FILE ); return true; } /** * Method to handle for selection of "preferences" in the option menu * * @return true if successful, false otherwise */ protected boolean onPreferences() { Intent intent = new Intent( this, SDCPreferenceActivity.class ); startActivity( intent ); return true; } @Override protected void onResume() { IntentFilter filter = new IntentFilter(); filter.addAction( SDCService.ACTION ); getApplicationContext().registerReceiver( serviceRunningStateListner, filter ); super.onResume(); } @Override protected void onPause() { getApplicationContext().unregisterReceiver( serviceRunningStateListner ); super.onPause(); } /* * (non-Javadoc) * * @see android.app.Activity#onDestroy() */ @Override protected void onDestroy() { // free field instances prefManager.onDestroy(); super.onDestroy(); } /* * (non-Javadoc) * * @see android.app.Activity#onCreateOptionsMenu(android.view.Menu) */ @Override public boolean onCreateOptionsMenu( Menu menu ) { super.onCreateOptionsMenu( menu ); MenuInflater inflater = getMenuInflater(); inflater.inflate( R.menu.basic_optionmenu, menu ); return true; } /* * (non-Javadoc) * * @see android.app.Activity#onPrepareOptionsMenu(android.view.Menu) */ @Override public boolean onPrepareOptionsMenu( Menu menu ) { boolean isServiceRunning = ServiceUtils.isServiceRunning( getApplicationContext(), getServiceClass() ); MenuItem menuItem = menu.findItem( R.id.externalConfiguration ); if ( menuItem != null ) { menuItem.setEnabled( !isServiceRunning ); } return super.onPrepareOptionsMenu( menu ); } /* * (non-Javadoc) * * @see android.app.Activity#onOptionsItemSelected(android.view.MenuItem) */ @Override public boolean onOptionsItemSelected( MenuItem item ) { boolean result = super.onOptionsItemSelected( item ); int itemId = item.getItemId(); if ( itemId == R.id.preferences ) { result = onPreferences(); } else if ( itemId == R.id.loadDefaults ) { result = onLoadDefaults(); } else if ( itemId == R.id.loadPublicKey ) { result = onLoadRSAPublicKey(); } return result; } @SuppressLint( "StringFormatMatches" ) @Override protected void onActivityResult( int requestCode, int resultCode, Intent data ) { // Make sure the request was successful if ( resultCode == RESULT_OK ) { switch ( requestCode ) { case SELECT_EXT_RSA_PUBKEY_FILE: { String srcFile = data.getStringExtra( SDCFileBrowserActivity.FILE ); String destFile = getFilesDir().getPath() + File.separatorChar + Encryption.PUBLIC_KEY_FILE; FileUtils.copy( srcFile, destFile ); break; } case SELECT_EXT_DEFAULTS_FILE: { String srcFile = data.getStringExtra( SDCFileBrowserActivity.FILE ); try { // Validate configuration first Serializer serializer = new Persister(); InputStream is = new FileInputStream( FileUtils.fileFromPath( srcFile ) ); serializer.read( SDCConfiguration.class, is ); // if we get here deserialization works String sdcfDefaultConfigFileName = getText( R.string.sdc_config_file_name ).toString(); String destFile = getFilesDir().getPath() + File.separatorChar + sdcfDefaultConfigFileName; // back up last configuration, if necessaRY String bakFilename = destFile + BAK_EXTENSION; if ( FileUtils.fileFromPath( destFile ).exists() ) { FileUtils.copy( destFile, bakFilename ); } if ( FileUtils.copy( srcFile, destFile ) ) { SDCConfigurationManager manager = new SDCConfigurationManager( this, sdcfDefaultConfigFileName ); boolean valid = manager.isUsingExternalConfiguration(); String reason = getResources().getString( R.string.str_unknown ); try { manager.updateDefaults( prefManager ); WeeklySchedule schedule = prefManager.getServicePreferences().getWeeklySchedulePreference().getConfiguration( prefManager.getSharedPreferences( getApplicationContext() ) ); if ( !ScheduleValidator.validate( schedule ) ) { for ( WeekdaySchedule daySchedule : schedule.getSchedule() ) { for ( WeekdayScheduleEntry scheduleEntry : daySchedule.getEntries() ) { if ( !scheduleEntry.isValid() ) throw new Exception( String.format( getResources().getString( R.string.err_invalid_schedule ), scheduleEntry.toString(), scheduleEntry.getWeekday().name() ) ); } } } } catch ( Exception e ) { valid = false; reason = e.getMessage(); } if ( valid ) { // if we get here the configuration should work prefManager.resetToDefaults( this.getApplicationContext() ); // trigger a scheduler update Intent intent = ScheduleService.createIntent( getApplicationContext() ); startService( intent ); } else { FileUtils.deleteFile( destFile ); // restore backup if necessary if ( FileUtils.fileFromPath( bakFilename ).exists() ) { FileUtils.copy( bakFilename, destFile ); FileUtils.deleteFile( bakFilename ); } DialogUtils.showAlertMessage( this, String.format( getResources().getString( R.string.err_external_config_invalid_params ), reason ) ); } } else { DialogUtils.showAlertMessage( this, String.format( getResources().getString( R.string.err_external_file_copy ), srcFile ) ); } } catch ( Exception e ) { DialogUtils.showAlertMessage( this, String.format( getResources().getString( R.string.err_external_config_deserialization ), e.getMessage() ) ); } break; } } } } /** * Handler to react on service running state changes. * * @param isRunning * running state flag */ protected abstract void onServiceRunningStateChanged( boolean isRunning ); }