/* * AndFHEM - Open Source Android application to control a FHEM home automation * server. * * Copyright (c) 2011, Matthias Klass or third-party contributors as * indicated by the @author tags or express copyright attribution * statements applied by the authors. All third-party contributions are * distributed under license by Red Hat Inc. * * This copyrighted material is made available to anyone wishing to use, modify, * copy, or redistribute it subject to the terms and conditions of the GNU GENERAL PUBLIC LICENSE, as published by the Free Software Foundation. * * 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 GENERAL PUBLIC LICENSE * for more details. * * You should have received a copy of the GNU GENERAL PUBLIC LICENSE * along with this distribution; if not, write to: * Free Software Foundation, Inc. * 51 Franklin Street, Fifth Floor * Boston, MA 02110-1301 USA */ package li.klass.fhem.service.intent; import android.content.Intent; import android.os.Bundle; import android.os.ResultReceiver; import com.google.common.base.Optional; import com.google.common.collect.ImmutableMap; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.Serializable; import java.util.ArrayList; import java.util.Map; import javax.inject.Inject; import li.klass.fhem.constants.ResultCodes; import li.klass.fhem.dagger.ApplicationComponent; import li.klass.fhem.domain.core.FhemDevice; import li.klass.fhem.domain.core.RoomDeviceList; import li.klass.fhem.service.device.GraphDefinitionsForDeviceService; import li.klass.fhem.service.room.RoomListService; import li.klass.fhem.util.Tasker; import static li.klass.fhem.constants.Actions.CLEAR_DEVICE_LIST; import static li.klass.fhem.constants.Actions.GET_ALL_ROOMS_DEVICE_LIST; import static li.klass.fhem.constants.Actions.GET_DEVICE_FOR_NAME; import static li.klass.fhem.constants.Actions.GET_ROOM_DEVICE_LIST; import static li.klass.fhem.constants.Actions.GET_ROOM_NAME_LIST; import static li.klass.fhem.constants.Actions.REMOTE_UPDATE_FINISHED; import static li.klass.fhem.constants.Actions.REMOTE_UPDATE_RESET; import static li.klass.fhem.constants.Actions.UPDATE_DEVICE_WITH_UPDATE_MAP; import static li.klass.fhem.constants.Actions.UPDATE_IF_REQUIRED; import static li.klass.fhem.constants.BundleExtraKeys.CONNECTION_ID; import static li.klass.fhem.constants.BundleExtraKeys.DEVICE; import static li.klass.fhem.constants.BundleExtraKeys.DEVICE_LIST; import static li.klass.fhem.constants.BundleExtraKeys.DEVICE_NAME; import static li.klass.fhem.constants.BundleExtraKeys.LAST_UPDATE; import static li.klass.fhem.constants.BundleExtraKeys.ROOM_LIST; import static li.klass.fhem.constants.BundleExtraKeys.ROOM_NAME; import static li.klass.fhem.constants.BundleExtraKeys.SENDER; import static li.klass.fhem.constants.BundleExtraKeys.SUCCESS; import static li.klass.fhem.constants.BundleExtraKeys.UPDATE_MAP; import static li.klass.fhem.constants.BundleExtraKeys.VIBRATE; import static li.klass.fhem.service.room.RoomListService.RemoteUpdateRequired; public class RoomListIntentService extends ConvenientIntentService { @Inject RoomListService roomListService; @Inject GraphDefinitionsForDeviceService graphDefinitionsForDeviceService; private static final Logger LOG = LoggerFactory.getLogger(RoomListIntentService.class); public RoomListIntentService() { super(RoomListIntentService.class.getName()); } @Override protected State handleIntent(Intent intent, long updatePeriod, ResultReceiver resultReceiver) { String action = intent.getAction(); LOG.info("handleIntent() - receiving intent with action {}", action); Optional<String> connectionId = Optional.fromNullable(intent.getStringExtra(CONNECTION_ID)); if (REMOTE_UPDATE_RESET.equals(action)) { LOG.trace("handleIntent() - resetting update progress"); roomListService.resetUpdateProgress(this); return State.SUCCESS; } if (!REMOTE_UPDATE_FINISHED.equals(action) && roomListService.updateRoomDeviceListIfRequired(intent, updatePeriod, this) == RemoteUpdateRequired.REQUIRED) { LOG.trace("handleIntent() - need to update room device list, intent is pending, so stop here"); return State.DONE; } if (GET_ALL_ROOMS_DEVICE_LIST.equals(action)) { LOG.trace("handleIntent() - handling all rooms device list"); RoomDeviceList allRoomsDeviceList = roomListService.getAllRoomsDeviceList(connectionId, this); sendResultWithLastUpdate(resultReceiver, ResultCodes.SUCCESS, DEVICE_LIST, allRoomsDeviceList, connectionId); } else if (GET_ROOM_NAME_LIST.equals(action)) { LOG.trace("handleIntent() - resolving room name list"); ArrayList<String> roomNameList = roomListService.getRoomNameList(connectionId, this); sendResultWithLastUpdate(resultReceiver, ResultCodes.SUCCESS, ROOM_LIST, roomNameList, connectionId); } else if (GET_ROOM_DEVICE_LIST.equals(action)) { String roomName = intent.getStringExtra(ROOM_NAME); LOG.trace("handleIntent() - resolving device list for room={}", roomName); RoomDeviceList roomDeviceList = roomListService.getDeviceListForRoom(roomName, connectionId, this); sendResultWithLastUpdate(resultReceiver, ResultCodes.SUCCESS, DEVICE_LIST, roomDeviceList, connectionId); } else if (GET_DEVICE_FOR_NAME.equals(action)) { String deviceName = intent.getStringExtra(DEVICE_NAME); LOG.trace("handleIntent() - resolving device for name={}", deviceName); Optional<FhemDevice> device = roomListService.getDeviceForName(deviceName, connectionId, this); if (!device.isPresent()) { LOG.info("cannot find device for {}", deviceName); return State.ERROR; } sendResultWithLastUpdate(resultReceiver, ResultCodes.SUCCESS, DEVICE, device.get(), connectionId); } else if (UPDATE_DEVICE_WITH_UPDATE_MAP.equals(action)) { String deviceName = intent.getStringExtra(DEVICE_NAME); LOG.trace("handleIntent() - updating device with update map, device={}", deviceName); @SuppressWarnings("unchecked") Map<String, String> updates = (Map<String, String>) intent.getSerializableExtra(UPDATE_MAP); boolean vibrateUponNotification = intent.getBooleanExtra(VIBRATE, false); roomListService.parseReceivedDeviceStateMap(deviceName, updates, vibrateUponNotification, this); Tasker.requestQuery(this); } else if (REMOTE_UPDATE_FINISHED.equals(action)) { LOG.trace("handleIntent() - remote update finished"); roomListService.remoteUpdateFinished(this, intent.getBooleanExtra(SUCCESS, true)); } else if (UPDATE_IF_REQUIRED.equals(action)) { // If required, the device list will be updated by now. The resend intent will reach us // here. The only thing we have to do is notify the receiver that we have // updated the device list. LOG.trace("handleIntent() - update if required found"); if (resultReceiver != null) { LOG.trace("handleIntent() - sending success to result receiver"); sendNoResult(resultReceiver, ResultCodes.SUCCESS); } else if (intent.hasExtra(SENDER)) { Class<?> sender = (Class<?>) intent.getSerializableExtra(SENDER); LOG.trace("handleIntent() - sending success intent to {}", sender == null ? "null (?!)" : sender.getSimpleName()); startService(new Intent(intent) .setAction(REMOTE_UPDATE_FINISHED) .setClass(this, sender)); } } else if (CLEAR_DEVICE_LIST.equals(action)) { roomListService.clearDeviceList(connectionId, this); } return State.DONE; } private void sendResultWithLastUpdate(ResultReceiver receiver, int resultCode, String bundleExtrasKey, Serializable value, Optional<String> connectionId) { sendResultWithLastUpdate(receiver, resultCode, ImmutableMap.of(bundleExtrasKey, value), connectionId); } private void sendResultWithLastUpdate(ResultReceiver receiver, int resultCode, Map<String, Serializable> values, Optional<String> connectionId) { if (receiver != null) { Bundle bundle = new Bundle(); for (Map.Entry<String, Serializable> entry : values.entrySet()) { bundle.putSerializable(entry.getKey(), entry.getValue()); } bundle.putLong(LAST_UPDATE, roomListService.getLastUpdate(connectionId, this)); receiver.send(resultCode, bundle); } } @Override protected void inject(ApplicationComponent applicationComponent) { applicationComponent.inject(this); } }