/**
* Copyright (C) 2013 - 2015 the enviroCar community
*
* This file is part of the enviroCar app.
*
* The enviroCar app is free software: you can redistribute it and/or
* modify it under the terms of the GNU General Public License as published
* by the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* The enviroCar app 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 General
* Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with the enviroCar app. If not, see http://www.gnu.org/licenses/.
*/
package org.envirocar.app.activity;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.preference.PreferenceManager;
import org.envirocar.app.BaseMainActivity;
import org.envirocar.app.R;
import org.envirocar.app.handler.TrackRecordingHandler;
import org.envirocar.app.activity.DialogUtil.DialogCallback;
import org.envirocar.app.handler.CarPreferenceHandler;
import org.envirocar.obd.service.BluetoothServiceState;
import org.envirocar.app.services.OBDConnectionService;
import org.envirocar.app.handler.PreferenceConstants;
import org.envirocar.core.injection.InjectionActivityScope;
import org.envirocar.core.injection.Injector;
import org.envirocar.core.logging.Logger;
import javax.inject.Inject;
/**
* Outsource of the start/stop button interaction and content updates.
* objects of this class can be created without leaking any resources -
* they simply hold the state-related flags and backlinks to the Activity.
*
* @author matthes rieke
*/
public class StartStopButtonUtil {
private static final Logger LOG = Logger.getLogger(StartStopButtonUtil.class);
@Inject
@InjectionActivityScope
protected Context mContext;
@Inject
protected CarPreferenceHandler mCarManager;
@Inject
protected TrackRecordingHandler mTrackRecordingHandler;
private int trackMode;
private BluetoothServiceState serviceState = BluetoothServiceState.SERVICE_STOPPED;
private boolean deviceDiscoveryActive;
/**
* @param context
* @param trackMode
* @param serviceState
* @param deviceDiscoveryActive
*/
public StartStopButtonUtil(Context context, int trackMode,
BluetoothServiceState serviceState, boolean deviceDiscoveryActive) {
// Inject variables.
((Injector) context).injectObjects(this);
this.trackMode = trackMode;
this.serviceState = serviceState;
this.deviceDiscoveryActive = deviceDiscoveryActive;
}
/**
* Update the UI contents of the button. This method
* DOES NOT fire any remoteService state changes, it is completely
* passive.
*
* @param button the drawer button
*/
public void updateStartStopButtonOnServiceStateChange(NavMenuItem button) {
LOG.info("updateStartStopButtonOnServiceStateChange called with state: " +
serviceState + " / trackMode: " + trackMode +
" discovery: " + deviceDiscoveryActive);
switch (serviceState) {
case SERVICE_STOPPED:
handleServiceStoppedState(button);
break;
case SERVICE_DEVICE_DISCOVERY_PENDING:
handleServiceDeviceDiscoveryPendingState(button);
// TODO ist das so gewollt ohne break?
case SERVICE_STARTING:
handleServiceStartingState(button);
break;
case SERVICE_STARTED:
handleServiceStartedState(button);
break;
default:
break;
}
}
/**
* React to a button click, considering the current state of the
* application and its services. This method fires events
* and remoteService starts actively.
*
* @param trackModeListener a callback to handle the inputs of the user
*/
public void processButtonClick(OnTrackModeChangeListener trackModeListener) {
LOG.info("processButtonClick called with state: " + serviceState + " / trackMode: " +
trackMode +
" discovery: " + deviceDiscoveryActive);
switch (serviceState) {
case SERVICE_STOPPED:
processStoppedStateClick(trackModeListener);
break;
case SERVICE_DEVICE_DISCOVERY_PENDING:
// processPendingStateClick();
break;
case SERVICE_STARTING:
processStartingStateClick();
break;
case SERVICE_STARTED:
processStartedStateClick(trackModeListener);
break;
default:
break;
}
}
/**
* convenience method to define the contents of a button,
* using String objects.
*/
public void defineButtonContents(NavMenuItem button, boolean enabled,
int iconRes, String subtitle, String title) {
button.setEnabled(enabled);
button.setIconRes(iconRes);
button.setSubtitle(subtitle);
if (title != null) {
button.setTitle(title);
}
}
/**
* convenience method to define the contents of a button,
* using string resource id for subtitle and String for title.
*/
public void defineButtonContents(NavMenuItem button, boolean enabled,
int iconRes, String subtitle) {
defineButtonContents(button, enabled, iconRes, subtitle, null);
}
private void defineButtonContents(NavMenuItem button, boolean enabled,
int iconRes, int subtitleRes) {
defineButtonContents(button, enabled, iconRes, mContext.getString(subtitleRes));
}
private void createStopTrackDialog(final OnTrackModeChangeListener trackModeListener) {
int titleId;
int messageId;
switch (trackMode) {
case BaseMainActivity.TRACK_MODE_SINGLE:
titleId = R.string.finish_track;
messageId = R.string.finish_track_long;
break;
case BaseMainActivity.TRACK_MODE_AUTO:
titleId = R.string.stop_automatic_mode;
messageId = R.string.stop_automatic_mode_long;
break;
default:
// Crouton.makeText(mContext, "not supported", Style.INFO).show();
return;
}
DialogUtil.createTitleMessageDialog(titleId, messageId,
new DialogUtil.PositiveNegativeCallback() {
@Override
public void positive() {
mTrackRecordingHandler.finishCurrentTrack();
trackModeListener.onTrackModeChange(BaseMainActivity.TRACK_MODE_SINGLE);
}
@Override
public void negative() {
}
}, mContext);
}
private void createStartTrackDialog(final OnTrackModeChangeListener listener) {
String[] items = new String[]{mContext.getString(R.string.track_mode_single),
mContext.getString(R.string.track_mode_auto)};
DialogUtil.createSingleChoiceItemsDialog(
mContext.getString(R.string.question_track_mode),
items,
new DialogCallback() {
@Override
public void itemSelected(int which) {
switch (which) {
case 0:
listener.onTrackModeChange(BaseMainActivity.TRACK_MODE_SINGLE);
mContext.getApplicationContext().startService(
new Intent(mContext, OBDConnectionService.class));
break;
case 1:
// listener.onTrackModeChange
// (BaseMainActivity.TRACK_MODE_AUTO);
// mContext.getApplicationContext
// ().startService(
// new Intent(mContext,
// DeviceInRangeService.class));
break;
}
// Crouton.makeText(mContext, R.string
// .start_connection, Style.INFO).show();
}
@Override
public void cancelled() {
}
}, mContext);
}
private void handleServiceStoppedState(NavMenuItem button) {
switch (trackMode) {
case BaseMainActivity.TRACK_MODE_SINGLE:
resetToStartButtonState(button);
break;
case BaseMainActivity.TRACK_MODE_AUTO:
if (deviceDiscoveryActive) {
button.setTitle(mContext.getString(R.string.menu_cancel));
defineButtonContents(button, true, R.drawable.av_stop, "");
} else {
resetToStartButtonState(button);
}
break;
default:
break;
}
}
private void handleServiceDeviceDiscoveryPendingState(NavMenuItem button) {
button.setTitle(mContext.getString(R.string.menu_cancel));
defineButtonContents(button, true, R.drawable.av_cancel, R.string.device_discovery_pending);
}
private void handleServiceStartingState(NavMenuItem button) {
button.setTitle(mContext.getString(R.string.menu_cancel));
defineButtonContents(button, true, R.drawable.av_cancel, R.string.menu_starting);
}
private void handleServiceStartedState(NavMenuItem button) {
button.setTitle(mContext.getString(R.string.menu_stop));
int subtitleRes;
switch (trackMode) {
case BaseMainActivity.TRACK_MODE_SINGLE:
subtitleRes = R.string.track_mode_single;
break;
case BaseMainActivity.TRACK_MODE_AUTO:
subtitleRes = R.string.track_mode_auto;
break;
default:
subtitleRes = R.string.track_mode_single;
break;
}
defineButtonContents(button, true, R.drawable.av_stop, subtitleRes);
}
private void resetToStartButtonState(NavMenuItem button) {
button.setTitle(mContext.getString(R.string.menu_start));
SharedPreferences preferences = PreferenceManager
.getDefaultSharedPreferences(mContext);
String remoteDevice = preferences.getString(PreferenceConstants
.PREF_BLUETOOTH_LIST, null);
if (remoteDevice != null) {
if (mCarManager.getCar() == null) {
defineButtonContents(button, false, R.drawable.not_available, R.string
.no_sensor_selected);
} else {
defineButtonContents(button, true, R.drawable.av_play, preferences.getString
(PreferenceConstants.PREF_BLUETOOTH_NAME, ""));
}
} else {
defineButtonContents(button, false, R.drawable.not_available, R.string
.pref_bluetooth_select_adapter_summary);
}
}
private void processStoppedStateClick(
OnTrackModeChangeListener onTrackModeChangeListener) {
createStartTrackDialog(onTrackModeChangeListener);
}
// private void processPendingStateClick() {
// /*
// * this broadcast stops the DeviceInRangeService
// */
// mContext.getApplicationContext().stopService(
// new Intent(mContext.getApplicationContext(), DeviceInRangeService.class));
// }
private void processStartingStateClick() {
mContext.getApplicationContext().stopService(
new Intent(mContext, OBDConnectionService.class));
// Crouton.makeText(mContext, R.string.stop_connection, Style.INFO).show();
}
private void processStartedStateClick(OnTrackModeChangeListener l) {
createStopTrackDialog(l);
}
/*
* CALLBACK INTERFACES
*/
public interface OnTrackModeChangeListener {
/**
* called when the mode changes on user input or
* a certain state change.
*
* @param trackModeSingle the track mode
*/
void onTrackModeChange(int trackModeSingle);
}
}