/*
* 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.service;
import android.content.Context;
import android.util.Log;
import de.unikassel.android.sdcframework.devices.SensorDeviceConfigurationUpdateVisitor;
import de.unikassel.android.sdcframework.devices.facade.SensorDeviceIdentifier;
import de.unikassel.android.sdcframework.devices.facade.SensorDeviceVisitor;
import de.unikassel.android.sdcframework.preferences.SensorDeviceConfigurationChangeEventImpl;
import de.unikassel.android.sdcframework.preferences.facade.SensorDeviceConfiguration;
import de.unikassel.android.sdcframework.preferences.facade.SensorDeviceConfigurationChangeEvent;
import de.unikassel.android.sdcframework.service.facade.ServiceManager;
import de.unikassel.android.sdcframework.util.AbstractTimeProviderErrorStrategy;
import de.unikassel.android.sdcframework.util.AlarmBuilder;
import de.unikassel.android.sdcframework.util.AlarmEvent;
import de.unikassel.android.sdcframework.util.Logger;
import de.unikassel.android.sdcframework.util.NetworkConnectionObserver;
import de.unikassel.android.sdcframework.util.ObservableAlarm;
import de.unikassel.android.sdcframework.util.TimeErrorEvent;
import de.unikassel.android.sdcframework.util.TimeProvider;
import de.unikassel.android.sdcframework.util.facade.EventObserver;
import de.unikassel.android.sdcframework.util.facade.NetworkStateChangeEvent;
import de.unikassel.android.sdcframework.util.facade.ObservableEventSource;
import de.unikassel.android.sdcframework.util.facade.TimeProviderErrorStrategyDescription;
/**
* Simple ignore strategy in case of time provider synchronization errors.
*
* @author Katy Hilgenberg
*
*/
public class TimeProviderOutOfSyncIgnoreStrategy
extends AbstractTimeProviderErrorStrategy
implements EventObserver< NetworkStateChangeEvent >
{
/**
* The time offset for synchronization retries.
*/
private static final long RETRY_SYNC_OFFSET = 600000L;// 3600000L;
/**
* The alarm for retry attempts.
*/
private final ObservableAlarm alarm;
/**
* The alarm observer to delegate to.
*/
private final EventObserver< AlarmEvent > alarmObserver;
/**
* The service manager.
*/
private final ServiceManager manager;
/**
* The flag is the time sync state device was enabled or not.
*/
private boolean timeSyncStateDeviceWasEnabeled;
/**
* The network connection observer
*/
private final NetworkConnectionObserver connectionObserver;
/**
* Constructor
*
* @param manager
* the service manager
*/
public TimeProviderOutOfSyncIgnoreStrategy( ServiceManager manager )
{
super( TimeProviderErrorStrategyDescription.IgnoreAndObserveSyncStates );
this.manager = manager;
this.alarm = AlarmBuilder.createAlarm( this, manager.getContext() );
this.alarmObserver = new EventObserver< AlarmEvent >()
{
@Override
public void onEvent(
ObservableEventSource< ? extends AlarmEvent > eventSource,
AlarmEvent observedEvent )
{
startSyncProcess();
}
};
alarm.onCreate( manager.getContext() );
alarm.registerEventObserver( alarmObserver );
connectionObserver =
NetworkConnectionObserver.getInstance( manager.getContext() );
}
/*
* (non-Javadoc)
*
* @see
* de.unikassel.android.sdcframework.util.facade.TimeProviderErrorStrategy
* #handleTimeErrorEvent
* (de.unikassel.android.sdcframework.util.TimeErrorEvent,
* de.unikassel.android.sdcframework.service.facade.ServiceManager)
*/
@Override
public final boolean handleTimeErrorEvent( TimeErrorEvent event,
ServiceManager serviceManager )
{
switch ( event.getError() )
{
case TIME_SYNC_ERROR:
{
// schedule a retry attempt
Logger.getInstance().debug( this,
"Scheduling a new attempt for time synchronization" );
alarm.setAlarm( RETRY_SYNC_OFFSET );
connectionObserver.registerEventObserver( this );
return true;
}
}
return false;
}
/*
* (non-Javadoc)
*
* @see
* de.unikassel.android.sdcframework.util.facade.TimeProviderErrorStrategy
* #enable(android.content.Context)
*/
@Override
public final void prepare( Context context )
{
alarm.onResume( context );
// force the time sync state device to be enabled
SensorDeviceConfiguration config =
manager.getPreferenceManager().getDeviceConfiguration(
SensorDeviceIdentifier.TimeSyncStateChanges, context );
timeSyncStateDeviceWasEnabeled = config.isEnabled();
if ( !timeSyncStateDeviceWasEnabeled )
{
config.setEnabled( true );
SensorDeviceConfigurationChangeEvent deviceChangeEvent =
new SensorDeviceConfigurationChangeEventImpl( config,
SensorDeviceIdentifier.TimeSyncStateChanges );
SensorDeviceVisitor visitor =
new SensorDeviceConfigurationUpdateVisitor( deviceChangeEvent,
context );
manager.getSensorDeviceManager().accept( visitor );
}
}
/*
* (non-Javadoc)
*
* @see
* de.unikassel.android.sdcframework.util.facade.TimeProviderErrorStrategy
* #disable(android.content.Context)
*/
@Override
public final void finalize( Context context )
{
alarm.onPause( context );
if ( timeSyncStateDeviceWasEnabeled )
{
// reset to configuration states
SensorDeviceConfiguration config =
manager.getPreferenceManager().getDeviceConfiguration(
SensorDeviceIdentifier.TimeSyncStateChanges, context );
SensorDeviceConfigurationChangeEvent deviceChangeEvent =
new SensorDeviceConfigurationChangeEventImpl( config,
SensorDeviceIdentifier.TimeSyncStateChanges );
SensorDeviceVisitor visitor =
new SensorDeviceConfigurationUpdateVisitor( deviceChangeEvent,
context );
manager.getSensorDeviceManager().accept( visitor );
}
}
/*
* (non-Javadoc)
*
* @see
* de.unikassel.android.sdcframework.util.facade.EventObserver#onEvent(de.
* unikassel.android.sdcframework.util.facade.ObservableEventSource,
* de.unikassel.android.sdcframework.util.facade.ObservableEvent)
*/
@Override
public void onEvent(
ObservableEventSource< ? extends NetworkStateChangeEvent > eventSource,
NetworkStateChangeEvent observedEvent )
{
if( observedEvent.isNetworkAvailable() )
{
startSyncProcess();
}
}
/**
* Method to trigger a synchronization process
*/
protected void startSyncProcess()
{
Log.d( this.getClass().getSimpleName(), "startSyncProcess called" );
if ( !TimeProvider.getInstance().isSynced() )
{
Logger.getInstance().debug( this,
"Started a new asynchronous time synchronization" );
TimeProvider.getInstance().asynchronousUpdateTime(
TimeProviderOutOfSyncIgnoreStrategy.this.manager.getContext() );
}
alarm.cancelAlarm();
connectionObserver.unregisterEventObserver( this );
Log.d( this.getClass().getSimpleName(), "startSyncProcess finished" );
}
}