/*
* 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.appwidget.view.widget.base;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.os.SystemClock;
import android.support.annotation.NonNull;
import android.util.Log;
import android.widget.RemoteViews;
import com.google.common.base.Optional;
import com.google.common.collect.ImmutableList;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.lang.annotation.Annotation;
import java.util.Set;
import javax.inject.Inject;
import li.klass.fhem.R;
import li.klass.fhem.activities.AndFHEMMainActivity;
import li.klass.fhem.appwidget.WidgetConfiguration;
import li.klass.fhem.appwidget.WidgetConfigurationCreatedCallback;
import li.klass.fhem.appwidget.annotation.SupportsWidget;
import li.klass.fhem.appwidget.view.WidgetType;
import li.klass.fhem.domain.core.FhemDevice;
import li.klass.fhem.fragments.FragmentType;
import li.klass.fhem.service.connection.ConnectionService;
import li.klass.fhem.service.deviceConfiguration.DeviceConfiguration;
import li.klass.fhem.service.deviceConfiguration.DeviceConfigurationProvider;
import li.klass.fhem.service.deviceConfiguration.ViewItemConfig;
import li.klass.fhem.service.room.RoomListService;
import static li.klass.fhem.constants.BundleExtraKeys.CONNECTION_ID;
import static li.klass.fhem.constants.BundleExtraKeys.DEVICE_NAME;
import static li.klass.fhem.constants.BundleExtraKeys.FRAGMENT;
import static li.klass.fhem.util.ReflectionUtil.getValueAndDescriptionForAnnotation;
public abstract class DeviceAppWidgetView extends AppWidgetView {
public static final String TAG = DeviceAppWidgetView.class.getName();
@Inject
public RoomListService roomListService;
@Inject
public DeviceConfigurationProvider deviceConfigurationProvider;
@Inject
protected ConnectionService connectionService;
public static final Logger LOG = LoggerFactory.getLogger(DeviceAppWidgetView.class);
public boolean supports(FhemDevice<?> device) {
boolean supportsFromJson = supportsFromJsonConfiguration(device);
boolean supportsFromAnnotation = supportsFromAnnotation(device);
return supportsFromJson || supportsFromAnnotation;
}
private boolean supportsFromAnnotation(FhemDevice<?> device) {
if (!device.getClass().isAnnotationPresent(SupportsWidget.class)) return false;
if (!device.supportsWidget(this.getClass())) {
return false;
}
SupportsWidget annotation = device.getClass().getAnnotation(SupportsWidget.class);
Class<? extends DeviceAppWidgetView>[] supportedWidgetViews = annotation.value();
for (Class<? extends DeviceAppWidgetView> supportedWidgetView : supportedWidgetViews) {
if (supportedWidgetView.equals(getClass())) {
return true;
}
}
return false;
}
private boolean supportsFromJsonConfiguration(FhemDevice<?> device) {
Optional<DeviceConfiguration> deviceConfiguration = device.getDeviceConfiguration();
if (deviceConfiguration.isPresent()) {
Set<String> supportedWidgets = deviceConfiguration.get().getSupportedWidgets();
for (String supportedWidget : supportedWidgets) {
if (getClass().getSimpleName().equalsIgnoreCase(supportedWidget)) {
return true;
}
}
}
return false;
}
@Override
public RemoteViews createView(Context context, WidgetConfiguration widgetConfiguration) {
RemoteViews views = super.createView(context, widgetConfiguration);
Log.i(TAG, "creating appwidget view for " + widgetConfiguration);
if (shouldSetDeviceName()) {
String deviceName = deviceNameFrom(widgetConfiguration);
FhemDevice device = getDeviceFor(deviceName, widgetConfiguration.connectionId, context);
if (device == null) return null;
views.setTextViewText(R.id.deviceName, device.getWidgetName());
}
return views;
}
public String deviceNameFrom(WidgetConfiguration widgetConfiguration) {
return widgetConfiguration.payload.get(0);
}
public boolean shouldSetDeviceName() {
return true;
}
private FhemDevice getDeviceFor(String deviceName, Optional<String> connectionId, Context context) {
return roomListService.getDeviceForName(deviceName, connectionId, context).orNull();
}
protected void openDeviceDetailPageWhenClicking(int viewId, RemoteViews view, FhemDevice device, WidgetConfiguration widgetConfiguration, Context context) {
PendingIntent pendingIntent = createOpenDeviceDetailPagePendingIntent(device, widgetConfiguration, context);
view.setOnClickPendingIntent(viewId, pendingIntent);
}
protected PendingIntent createOpenDeviceDetailPagePendingIntent(FhemDevice device, WidgetConfiguration widgetConfiguration, Context context) {
Intent openIntent = createOpenDeviceDetailPageIntent(device, widgetConfiguration, context);
return PendingIntent.getActivity(context, widgetConfiguration.widgetId, openIntent,
PendingIntent.FLAG_UPDATE_CURRENT);
}
protected Intent createOpenDeviceDetailPageIntent(FhemDevice device, WidgetConfiguration widgetConfiguration, Context context) {
return new Intent(context, AndFHEMMainActivity.class)
.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP)
.putExtra(FRAGMENT, FragmentType.DEVICE_DETAIL)
.putExtra(DEVICE_NAME, device.getName())
.putExtra(CONNECTION_ID, widgetConfiguration.connectionId.orNull())
.putExtra("unique", "foobar://" + SystemClock.elapsedRealtime());
}
@Override
public void createWidgetConfiguration(Context context, WidgetType widgetType, int appWidgetId,
WidgetConfigurationCreatedCallback callback, String... payload) {
Optional<FhemDevice> device = roomListService.getDeviceForName(payload[0], Optional.<String>absent(), context);
if (device.isPresent()) {
createDeviceWidgetConfiguration(context, widgetType, appWidgetId, device.get(), callback);
} else {
Log.i(TAG, "cannot find device for " + payload[0]);
}
}
protected String valueForAnnotation(FhemDevice<?> device, Class<? extends Annotation> annotationCls) {
Optional<DeviceConfiguration> configuration = deviceConfigurationProvider.configurationFor(device);
if (configuration.isPresent()) {
Set<ViewItemConfig> states = configuration.get().getStates();
for (ViewItemConfig state : states) {
if (state.getMarkers().contains(annotationCls.getSimpleName())) {
return device.getXmlListDevice().stateValueFor(state.getKey()).orNull();
}
}
}
return getValueAndDescriptionForAnnotation(device, annotationCls);
}
protected void createDeviceWidgetConfiguration(Context context, WidgetType widgetType, int appWidgetId,
FhemDevice device, WidgetConfigurationCreatedCallback callback) {
Optional<String> connectionId = getCurrentConnectionId(context);
callback.widgetConfigurationCreated(new WidgetConfiguration(appWidgetId, widgetType, connectionId, ImmutableList.of(device.getName())));
}
@NonNull
protected Optional<String> getCurrentConnectionId(Context context) {
return Optional.of(connectionService.getSelectedId(context));
}
protected void fillWidgetView(Context context, RemoteViews view,
WidgetConfiguration widgetConfiguration) {
FhemDevice<?> device = getDeviceFor(deviceNameFrom(widgetConfiguration), widgetConfiguration.connectionId, context);
if (device != null) {
view.setTextViewText(R.id.deviceName, device.getWidgetName());
fillWidgetView(context, view, device, widgetConfiguration);
} else {
Log.i(TAG, "cannot find device for " + deviceNameFrom(widgetConfiguration));
}
}
protected abstract void fillWidgetView(Context context, RemoteViews view, FhemDevice<?> device,
WidgetConfiguration widgetConfiguration);
}