From 85c3d40f5270cf14fa958d16eff3417ffbe8960b Mon Sep 17 00:00:00 2001 From: nightoftune Date: Fri, 18 Jan 2019 18:43:21 +0100 Subject: [PATCH] Finished activities. Fixed some bugs. Added scopes for preferences. Sill need to implement dynamic event activity. --- .../activities/SettingsActivity.java | 4 +- .../devices/xwatch/XWatchService.java | 11 - .../devices/xwatch/XWatchTaskerSpec.java | 2 +- .../service/devices/xwatch/XWatchSupport.java | 12 +- .../tasker/event/TaskerEvent.java | 19 + .../tasker/event/TaskerEventType.java | 11 +- .../TaskerActionCodes.java | 7 +- .../{service => plugin}/TaskerBleProfile.java | 10 +- .../tasker/plugin/TaskerConstants.java | 84 ++++ .../tasker/plugin/TaskerDevice.java | 33 ++ .../tasker/plugin/TaskerIntent.java | 452 ++++++++++++++++++ .../tasker/service/AbstractTaskerService.java | 30 +- .../service/NoTaskDefinedException.java | 3 + .../tasker/service/SpecTaskerService.java | 5 +- .../tasker/service/TaskerAbstractSpec.java | 12 - .../tasker/service/TaskerConstants.java | 78 --- .../tasker/service/TaskerIntent.java | 449 ----------------- .../tasker/service/TaskerService.java | 38 +- .../tasker/service/TaskerUtil.java | 1 + .../{event => settings}/SettingSupplier.java | 9 +- .../SettingSupplierImpl.java | 11 +- .../tasker/settings/TaskerSettings.java | 31 +- .../settings/activities/ButtonPreference.java | 16 + .../settings/activities/TaskerActivity.java | 16 +- .../activities/TaskerEventActivity.java | 85 +++- .../activities/TaskerEventsActivity.java | 18 +- .../{service => spec}/AbstractTaskerSpec.java | 17 +- .../tasker/{service => spec}/TaskerSpec.java | 8 +- .../gadgetbridge/tasker/task/TaskerTask.java | 20 +- .../tasker/task/TaskerTaskProvider.java | 9 + ...utton.xml => button_preference_layout.xml} | 0 .../main/res/layout/tasker_remove_button.xml | 14 - app/src/main/res/values-de/strings.xml | 28 +- app/src/main/res/values/strings.xml | 5 +- app/src/main/res/xml/preferences.xml | 2 +- .../main/res/xml/tasker_event_preferences.xml | 35 +- .../res/xml/tasker_events_preferences.xml | 5 +- app/src/main/res/xml/tasker_preferences.xml | 4 +- 38 files changed, 908 insertions(+), 686 deletions(-) rename app/src/main/java/nodomain/freeyourgadget/gadgetbridge/tasker/{service => plugin}/TaskerActionCodes.java (98%) rename app/src/main/java/nodomain/freeyourgadget/gadgetbridge/tasker/{service => plugin}/TaskerBleProfile.java (79%) create mode 100644 app/src/main/java/nodomain/freeyourgadget/gadgetbridge/tasker/plugin/TaskerConstants.java create mode 100644 app/src/main/java/nodomain/freeyourgadget/gadgetbridge/tasker/plugin/TaskerDevice.java create mode 100644 app/src/main/java/nodomain/freeyourgadget/gadgetbridge/tasker/plugin/TaskerIntent.java delete mode 100644 app/src/main/java/nodomain/freeyourgadget/gadgetbridge/tasker/service/TaskerAbstractSpec.java delete mode 100644 app/src/main/java/nodomain/freeyourgadget/gadgetbridge/tasker/service/TaskerConstants.java delete mode 100644 app/src/main/java/nodomain/freeyourgadget/gadgetbridge/tasker/service/TaskerIntent.java rename app/src/main/java/nodomain/freeyourgadget/gadgetbridge/tasker/{event => settings}/SettingSupplier.java (54%) rename app/src/main/java/nodomain/freeyourgadget/gadgetbridge/tasker/{event => settings}/SettingSupplierImpl.java (74%) rename app/src/main/java/nodomain/freeyourgadget/gadgetbridge/tasker/{service => spec}/AbstractTaskerSpec.java (81%) rename app/src/main/java/nodomain/freeyourgadget/gadgetbridge/tasker/{service => spec}/TaskerSpec.java (60%) rename app/src/main/res/layout/{tasker_add_button.xml => button_preference_layout.xml} (100%) delete mode 100644 app/src/main/res/layout/tasker_remove_button.xml diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/SettingsActivity.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/SettingsActivity.java index 56d64d918..d2f0fe4df 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/SettingsActivity.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/SettingsActivity.java @@ -56,7 +56,7 @@ import nodomain.freeyourgadget.gadgetbridge.devices.DeviceManager; import nodomain.freeyourgadget.gadgetbridge.devices.miband.MiBandConst; import nodomain.freeyourgadget.gadgetbridge.devices.miband.MiBandPreferencesActivity; import nodomain.freeyourgadget.gadgetbridge.model.CannedMessagesSpec; -import nodomain.freeyourgadget.gadgetbridge.tasker.service.TaskerConstants; +import nodomain.freeyourgadget.gadgetbridge.tasker.plugin.TaskerConstants; import nodomain.freeyourgadget.gadgetbridge.tasker.settings.activities.TaskerActivity; import nodomain.freeyourgadget.gadgetbridge.util.AndroidUtils; import nodomain.freeyourgadget.gadgetbridge.util.FileUtils; @@ -498,7 +498,7 @@ public class SettingsActivity extends AbstractSettingsActivity { } }); - findPreference(TaskerConstants.TASKER).setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() { + findPreference(TaskerConstants.ACTIVITY_TASKER).setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() { @Override public boolean onPreferenceClick(Preference preference) { Intent enableIntent = new Intent(SettingsActivity.this, TaskerActivity.class); diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/xwatch/XWatchService.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/xwatch/XWatchService.java index 28763a18f..79edcf6c1 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/xwatch/XWatchService.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/xwatch/XWatchService.java @@ -16,21 +16,10 @@ along with this program. If not, see . */ package nodomain.freeyourgadget.gadgetbridge.devices.xwatch; -import android.bluetooth.BluetoothGatt; -import android.bluetooth.BluetoothGattCharacteristic; - -import java.util.Arrays; import java.util.HashMap; -import java.util.List; import java.util.Map; import java.util.UUID; -import nodomain.freeyourgadget.gadgetbridge.GBApplication; -import nodomain.freeyourgadget.gadgetbridge.tasker.event.TaskerEventType; -import nodomain.freeyourgadget.gadgetbridge.tasker.service.AbstractTaskerSpec; -import nodomain.freeyourgadget.gadgetbridge.tasker.settings.TaskerSettings; -import nodomain.freeyourgadget.gadgetbridge.tasker.service.TaskerSpec; - public class XWatchService { public static final UUID UUID_NOTIFY = UUID.fromString("0000fff7-0000-1000-8000-00805f9b34fb"); public static final UUID UUID_SERVICE = UUID.fromString("0000fff0-0000-1000-8000-00805f9b34fb"); diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/xwatch/XWatchTaskerSpec.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/xwatch/XWatchTaskerSpec.java index d6acf2ede..2bdd696e1 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/xwatch/XWatchTaskerSpec.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/xwatch/XWatchTaskerSpec.java @@ -7,7 +7,7 @@ import java.util.Arrays; import java.util.List; import nodomain.freeyourgadget.gadgetbridge.tasker.event.TaskerEventType; -import nodomain.freeyourgadget.gadgetbridge.tasker.service.AbstractTaskerSpec; +import nodomain.freeyourgadget.gadgetbridge.tasker.spec.AbstractTaskerSpec; public class XWatchTaskerSpec extends AbstractTaskerSpec { diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/xwatch/XWatchSupport.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/xwatch/XWatchSupport.java index 5f289742f..5c48893e2 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/xwatch/XWatchSupport.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/xwatch/XWatchSupport.java @@ -40,7 +40,6 @@ import nodomain.freeyourgadget.gadgetbridge.database.DBHandler; import nodomain.freeyourgadget.gadgetbridge.database.DBHelper; import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventVersionInfo; import nodomain.freeyourgadget.gadgetbridge.devices.SampleProvider; -import nodomain.freeyourgadget.gadgetbridge.devices.xwatch.XWatchConstants; import nodomain.freeyourgadget.gadgetbridge.devices.xwatch.XWatchSampleProvider; import nodomain.freeyourgadget.gadgetbridge.devices.xwatch.XWatchService; import nodomain.freeyourgadget.gadgetbridge.entities.Device; @@ -60,12 +59,9 @@ import nodomain.freeyourgadget.gadgetbridge.service.btle.AbstractBTLEDeviceSuppo import nodomain.freeyourgadget.gadgetbridge.service.btle.TransactionBuilder; import nodomain.freeyourgadget.gadgetbridge.service.btle.actions.SetDeviceStateAction; import nodomain.freeyourgadget.gadgetbridge.service.devices.miband.DeviceInfo; -import nodomain.freeyourgadget.gadgetbridge.tasker.service.TaskerBleProfile; -import nodomain.freeyourgadget.gadgetbridge.tasker.service.TaskerConstants; -import nodomain.freeyourgadget.gadgetbridge.tasker.task.TaskerTaskProvider; -import nodomain.freeyourgadget.gadgetbridge.tasker.service.TaskerService; -import nodomain.freeyourgadget.gadgetbridge.tasker.event.TaskerEvent; -import nodomain.freeyourgadget.gadgetbridge.tasker.event.TaskerEventType; +import nodomain.freeyourgadget.gadgetbridge.tasker.plugin.TaskerBleProfile; +import nodomain.freeyourgadget.gadgetbridge.tasker.plugin.TaskerConstants; +import nodomain.freeyourgadget.gadgetbridge.tasker.plugin.TaskerDevice; import nodomain.freeyourgadget.gadgetbridge.util.GB; public class XWatchSupport extends AbstractBTLEDeviceSupport { @@ -82,7 +78,7 @@ public class XWatchSupport extends AbstractBTLEDeviceSupport { addSupportedService(XWatchService.UUID_SERVICE); addSupportedService(XWatchService.UUID_WRITE); addSupportedService(XWatchService.UUID_NOTIFY); - addSupportedProfile(new TaskerBleProfile<>(this, TaskerConstants.TaskerDevice.XWATCH)); + addSupportedProfile(new TaskerBleProfile<>(this, TaskerDevice.XWATCH)); } public static byte[] crcChecksum(byte[] data) { diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/tasker/event/TaskerEvent.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/tasker/event/TaskerEvent.java index 7d180a5ee..66140911d 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/tasker/event/TaskerEvent.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/tasker/event/TaskerEvent.java @@ -1,5 +1,14 @@ package nodomain.freeyourgadget.gadgetbridge.tasker.event; +import nodomain.freeyourgadget.gadgetbridge.tasker.settings.TaskerSettings; + +/** + * Tasker event that gets thrown if its corresponding {@link TaskerSettings#isEnabled()} is true. + *

+ * Provides {@link TaskerEventType} and a count. + *

+ * Count resets itself after {@link TaskerSettings#getThreshold()} is expired. + */ public class TaskerEvent { private TaskerEventType type; @@ -10,6 +19,11 @@ public class TaskerEvent { this.count = count; } + /** + * Tasker event type of this event. + * + * @return + */ public TaskerEventType getType() { return type; } @@ -18,6 +32,11 @@ public class TaskerEvent { this.type = type; } + /** + * Count how often this event is thrown in the {@link TaskerSettings#getThreshold()} + * + * @return Fired times + */ public int getCount() { return count; } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/tasker/event/TaskerEventType.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/tasker/event/TaskerEventType.java index 6b9eb9e67..390699d6b 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/tasker/event/TaskerEventType.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/tasker/event/TaskerEventType.java @@ -7,6 +7,14 @@ import java.util.Objects; import nodomain.freeyourgadget.gadgetbridge.R; +/** + * Default set of tasker events. + *

+ * Extend here if you want to add more events. Use {@link TaskerEventType#create(String)} + * and configure {@link TaskerEventType#withLocalization(int)} for {@link nodomain.freeyourgadget.gadgetbridge.tasker.settings.activities.TaskerEventsActivity} + *

+ * Don't forget to add the new event to {@link #getTypes()} method. + */ public class TaskerEventType implements Serializable { public static TaskerEventType BUTTON = TaskerEventType.create("button").withLocalization(R.string.tasker_event_button); @@ -63,12 +71,11 @@ public class TaskerEventType implements Serializable { if (o == null || getClass() != o.getClass()) return false; TaskerEventType that = (TaskerEventType) o; return index == that.index && - type == that.type; + Objects.equals(type, that.type); } @Override public int hashCode() { - return Objects.hash(type, index); } } \ No newline at end of file diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/tasker/service/TaskerActionCodes.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/tasker/plugin/TaskerActionCodes.java similarity index 98% rename from app/src/main/java/nodomain/freeyourgadget/gadgetbridge/tasker/service/TaskerActionCodes.java rename to app/src/main/java/nodomain/freeyourgadget/gadgetbridge/tasker/plugin/TaskerActionCodes.java index d297442bb..157e83ca6 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/tasker/service/TaskerActionCodes.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/tasker/plugin/TaskerActionCodes.java @@ -1,5 +1,10 @@ -package nodomain.freeyourgadget.gadgetbridge.tasker.service; +package nodomain.freeyourgadget.gadgetbridge.tasker.plugin; +/** + * Tasker action codes. + * + * @see Tasker invoke tasks for more information. + */ public class TaskerActionCodes { public static final int NONE = -1; diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/tasker/service/TaskerBleProfile.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/tasker/plugin/TaskerBleProfile.java similarity index 79% rename from app/src/main/java/nodomain/freeyourgadget/gadgetbridge/tasker/service/TaskerBleProfile.java rename to app/src/main/java/nodomain/freeyourgadget/gadgetbridge/tasker/plugin/TaskerBleProfile.java index 815963a20..ed3968609 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/tasker/service/TaskerBleProfile.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/tasker/plugin/TaskerBleProfile.java @@ -1,4 +1,4 @@ -package nodomain.freeyourgadget.gadgetbridge.tasker.service; +package nodomain.freeyourgadget.gadgetbridge.tasker.plugin; import android.bluetooth.BluetoothGatt; import android.bluetooth.BluetoothGattCharacteristic; @@ -6,7 +6,11 @@ import android.bluetooth.BluetoothGattCharacteristic; import nodomain.freeyourgadget.gadgetbridge.service.btle.AbstractBTLEDeviceSupport; import nodomain.freeyourgadget.gadgetbridge.service.btle.profiles.AbstractBleProfile; import nodomain.freeyourgadget.gadgetbridge.tasker.event.TaskerEventType; +import nodomain.freeyourgadget.gadgetbridge.tasker.service.NoTaskDefinedException; +import nodomain.freeyourgadget.gadgetbridge.tasker.service.SpecTaskerService; +import nodomain.freeyourgadget.gadgetbridge.tasker.service.TaskerUtil; import nodomain.freeyourgadget.gadgetbridge.tasker.settings.TaskerSettings; +import nodomain.freeyourgadget.gadgetbridge.tasker.spec.TaskerSpec; /** * Tasker plugin hook as BLE profile. @@ -18,9 +22,9 @@ import nodomain.freeyourgadget.gadgetbridge.tasker.settings.TaskerSettings; public class TaskerBleProfile extends AbstractBleProfile { private SpecTaskerService taskerService; - private TaskerConstants.TaskerDevice taskerDevice; + private TaskerDevice taskerDevice; - public TaskerBleProfile(T support, TaskerConstants.TaskerDevice taskerDevice) { + public TaskerBleProfile(T support, TaskerDevice taskerDevice) { super(support); this.taskerDevice = taskerDevice; taskerService = new SpecTaskerService(taskerDevice.getSpec()); diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/tasker/plugin/TaskerConstants.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/tasker/plugin/TaskerConstants.java new file mode 100644 index 000000000..fd5c89b36 --- /dev/null +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/tasker/plugin/TaskerConstants.java @@ -0,0 +1,84 @@ +package nodomain.freeyourgadget.gadgetbridge.tasker.plugin; + +import java.util.ArrayList; +import java.util.List; + +import nodomain.freeyourgadget.gadgetbridge.util.StringUtils; + +/** + * Tasker constants. + */ +public class TaskerConstants { + + /** + * Tasker intent's between {@link nodomain.freeyourgadget.gadgetbridge.activities.AbstractSettingsActivity}'s. + */ + public static final String INTENT_DEVICE = "int_tasker_device"; + public static final String INTENT_EVENT = "int_tasker_event"; + + /** + * Correspond to {@link nodomain.freeyourgadget.gadgetbridge.tasker.settings.activities.TaskerActivity} + */ + public static final String ACTIVITY_TASKER = "act_tasker"; + public static final String ACTIVITY_TASKER_ENABLED = "act_tasker_enabled"; + public static final String ACTIVITY_TASKER_GROUP = "act_tasker_group"; + /** + * Correspond to {@link nodomain.freeyourgadget.gadgetbridge.tasker.settings.activities.TaskerEventsActivity} + */ + public static final String ACTIVITY_EVENT_GROUP = "act_event_group"; + + /** + * Correspond to {@link nodomain.freeyourgadget.gadgetbridge.tasker.settings.activities.TaskerEventActivity}. + */ + public static final String ACTIVITY_TASK_ADD = "act_tasker_task_add"; + public static final ScopedString ACTIVITY_THRESHOLD = new ScopedString("act_tasker_threshold"); + public static final ScopedString ACTIVITY_TASK = new ScopedString("act_tasker_task"); + public static final ScopedString ACTIVITY_THRESHOLD_ENABLED = new ScopedString("act_tasker_threshold_enabled"); + public static final ScopedString ACTIVITY_TASKS = new ScopedString("act_tasker_task_group"); + public static final ScopedString ACTIVITY_EVENT_ENABLED = new ScopedString("act_tasker_event_enabled"); + + public static class ScopedString { + + private String constant; + private List scopes; + + private ScopedString(String constant) { + this.constant = constant; + } + + public ScopedString withScope(String scope) { + ScopedString scoped = new ScopedString(constant); + List addScope; + if (scopes == null) { + addScope = new ArrayList<>(); + } else { + addScope = new ArrayList<>(scopes); + } + addScope.add(scope); + scoped.scopes = addScope; + return scoped; + } + + public String getConstant() { + return constant; + } + + @Override + public String toString() { + StringBuilder builder = new StringBuilder(constant); + if (scopes != null && !scopes.isEmpty()) { + for (String scope : scopes) { + if (!StringUtils.isEmpty(scope)) { + continue; + } + if (scopes.indexOf(scope) < scope.length() - 1) { + builder.append("_"); + } + builder.append(scopes); + } + } + return builder.toString(); + } + } + +} diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/tasker/plugin/TaskerDevice.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/tasker/plugin/TaskerDevice.java new file mode 100644 index 000000000..ce9efd5ee --- /dev/null +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/tasker/plugin/TaskerDevice.java @@ -0,0 +1,33 @@ +package nodomain.freeyourgadget.gadgetbridge.tasker.plugin; + +import java.io.Serializable; + +import nodomain.freeyourgadget.gadgetbridge.devices.xwatch.XWatchTaskerSpec; +import nodomain.freeyourgadget.gadgetbridge.model.DeviceType; +import nodomain.freeyourgadget.gadgetbridge.tasker.spec.TaskerSpec; + +/** + * Tasker devices with corresponding {@link nodomain.freeyourgadget.gadgetbridge.impl.GBDevice}. + *

+ * Add new devices here! Provide a {@link TaskerSpec} and your ready to go. + */ +public enum TaskerDevice implements Serializable { + + XWATCH(DeviceType.XWATCH, new XWatchTaskerSpec()); + + private DeviceType type; + private TaskerSpec spec; + + TaskerDevice(DeviceType type, TaskerSpec spec) { + this.type = type; + this.spec = spec; + } + + public DeviceType getType() { + return type; + } + + public TaskerSpec getSpec() { + return spec; + } +} \ No newline at end of file diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/tasker/plugin/TaskerIntent.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/tasker/plugin/TaskerIntent.java new file mode 100644 index 000000000..5c677d14e --- /dev/null +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/tasker/plugin/TaskerIntent.java @@ -0,0 +1,452 @@ +// Version 1.3.3 + +// Changelog + +// Version 1.3.3 +// - increased MAX_NO_ARGS to 10 + +// Version 1.3.2 +// - bug setting app arg +// - pulled provider column names out of function + +// For usage examples see http://tasker.dinglisch.net/invoketasks.html + +package nodomain.freeyourgadget.gadgetbridge.tasker.plugin; + +import java.lang.reflect.Field; +import java.util.ArrayList; +import java.util.List; +import java.util.Random; + +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.content.pm.PackageManager; +import android.content.pm.ResolveInfo; +import android.database.Cursor; +import android.net.Uri; +import android.os.Bundle; +import android.os.PatternMatcher; +import android.os.Process; +import android.util.Log; + +/** + * Tasker {@link Intent}'s. + * + * @see Tasker invoke tasks for more information. + */ +public class TaskerIntent extends Intent { + + // 3 Tasker versions + public final static String TASKER_PACKAGE = "net.dinglisch.android.tasker"; + public final static String TASKER_PACKAGE_MARKET = TASKER_PACKAGE + "m"; + public final static String TASKER_PACKAGE_CUPCAKE = TASKER_PACKAGE + "cupcake"; + + // Play Store download URLs + public final static String MARKET_DOWNLOAD_URL_PREFIX = "market://details?id="; + private final static String TASKER_MARKET_URL = MARKET_DOWNLOAD_URL_PREFIX + TASKER_PACKAGE_MARKET; + private final static String TASKER_MARKET_URL_CUPCAKE = MARKET_DOWNLOAD_URL_PREFIX + TASKER_PACKAGE_CUPCAKE; + + // Direct-purchase version + private final static String TASKER_DOWNLOAD_URL = "http://tasker.dinglisch.net/download.html"; + + // Intent actions + public final static String ACTION_TASK = TASKER_PACKAGE + ".ACTION_TASK"; + public final static String ACTION_TASK_COMPLETE = TASKER_PACKAGE + ".ACTION_TASK_COMPLETE"; + public final static String ACTION_TASK_SELECT = TASKER_PACKAGE + ".ACTION_TASK_SELECT"; + + // Intent parameters + public final static String EXTRA_ACTION_INDEX_PREFIX = "action"; + public final static String TASK_NAME_DATA_SCHEME = "task"; + public final static String EXTRA_TASK_NAME = "task_name"; + public final static String EXTRA_TASK_PRIORITY = "task_priority"; + public final static String EXTRA_SUCCESS_FLAG = "success"; + public final static String EXTRA_VAR_NAMES_LIST = "varNames"; + public final static String EXTRA_VAR_VALUES_LIST = "varValues"; + public final static String EXTRA_TASK_OUTPUT = "output"; + + // Content provider columns + public static final String PROVIDER_COL_NAME_EXTERNAL_ACCESS = "ext_access"; + public static final String PROVIDER_COL_NAME_ENABLED = "enabled"; + + // DEPRECATED, use EXTRA_VAR_NAMES_LIST, EXTRA_VAR_VALUES_LIST + public final static String EXTRA_PARAM_LIST = "params"; + + // Intent data + + public final static String TASK_ID_SCHEME = "id"; + + // For particular actions + + public final static String DEFAULT_ENCRYPTION_KEY = "default"; + public final static String ENCRYPTED_AFFIX = "tec"; + public final static int MAX_NO_ARGS = 10; + + // Bundle keys + // Only useful for Tasker + public final static String ACTION_CODE = "action"; + public final static String APP_ARG_PREFIX = "app:"; + public final static String ICON_ARG_PREFIX = "icn:"; + public final static String ARG_INDEX_PREFIX = "arg:"; + public static final String PARAM_VAR_NAME_PREFIX = "par"; + + // Misc + private final static String PERMISSION_RUN_TASKS = TASKER_PACKAGE + ".PERMISSION_RUN_TASKS"; + + public final static String ACTION_OPEN_PREFS = TASKER_PACKAGE + ".ACTION_OPEN_PREFS"; + public final static String EXTRA_OPEN_PREFS_TAB_NO = "tno"; + private final static int MISC_PREFS_TAB_NO = 3; // 0 based + + // To query whether Tasker is enabled and external access is enabled + private final static String TASKER_PREFS_URI = "content://" + TASKER_PACKAGE + "/prefs"; + + private final static int CUPCAKE_SDK_VERSION = 3; + + // result values for TestSend + + // NotInstalled: Tasker package not found on device + // NoPermission: calling app does not have permission PERMISSION_RUN_TASKS + // NotEnabled: Tasker is not enabled + // AccessBlocked: user prefs disallow external access + // NoReceiver: Tasker has not created a listener for external access (probably a Tasker bug) + // OK: you should be able to send a task to run. Still need to listen for result + // for e.g. task not found + + public static enum Status {NotInstalled, NoPermission, NotEnabled, AccessBlocked, NoReceiver, OK} + + ; + + // -------------------------- PRIVATE VARS ---------------------------- // + + private final static String TAG = "TaskerIntent"; + + private final static String EXTRA_INTENT_VERSION_NUMBER = "version_number"; + private final static String INTENT_VERSION_NUMBER = "1.1"; + + // Inclusive values + private final static int MIN_PRIORITY = 0; + private final static int MAX_PRIORITY = 10; + + // For generating random names + private static Random rand = new Random(); + + // Tracking state + private int actionCount = 0; + private int argCount; + + // -------------------------- PUBLIC METHODS ---------------------------- // + + public static int getMaxPriority() { + return MAX_PRIORITY; + } + + public static boolean validatePriority(int pri) { + return ( + (pri >= MIN_PRIORITY) || + (pri <= MAX_PRIORITY) + ); + } + + // Tasker has different package names for Play Store and non- versions + // for historical reasons + + public static String getInstalledTaskerPackage(Context context) { + + String foundPackage = null; + + try { + context.getPackageManager().getPackageInfo(TASKER_PACKAGE, 0); + foundPackage = TASKER_PACKAGE; + } catch (PackageManager.NameNotFoundException e) { + } + + try { + context.getPackageManager().getPackageInfo(TASKER_PACKAGE_MARKET, 0); + foundPackage = TASKER_PACKAGE_MARKET; + } catch (PackageManager.NameNotFoundException e) { + } + + return foundPackage; + } + + // test we can send a TaskerIntent to Tasker + // use *before* sending an intent + // still need to test the *result after* sending intent + + public static Status testStatus(Context c) { + + Status result; + + if (!taskerInstalled(c)) + result = Status.NotInstalled; + else if (!havePermission(c)) + result = Status.NoPermission; + else if (!TaskerIntent.prefSet(c, PROVIDER_COL_NAME_ENABLED)) + result = Status.NotEnabled; + else if (!TaskerIntent.prefSet(c, PROVIDER_COL_NAME_EXTERNAL_ACCESS)) + result = Status.AccessBlocked; + else if (!new TaskerIntent("").receiverExists(c)) + result = Status.NoReceiver; + else + result = Status.OK; + + return result; + } + + // Check if Tasker installed + + public static boolean taskerInstalled(Context context) { + return (getInstalledTaskerPackage(context) != null); + } + + // Use with startActivity to retrieve Tasker from Android market + public static Intent getTaskerInstallIntent(boolean marketFlag) { + + return new Intent( + Intent.ACTION_VIEW, + Uri.parse( + marketFlag ? + ((SDKVersion() == CUPCAKE_SDK_VERSION) ? TASKER_MARKET_URL_CUPCAKE : TASKER_MARKET_URL) : + TASKER_DOWNLOAD_URL + ) + ); + } + + public static int SDKVersion() { + try { + Field f = android.os.Build.VERSION.class.getField("SDK_INT"); + return f.getInt(null); + } catch (Exception e) { + return CUPCAKE_SDK_VERSION; + } + } + + public static IntentFilter getCompletionFilter(String taskName) { + + IntentFilter filter = new IntentFilter(TaskerIntent.ACTION_TASK_COMPLETE); + + filter.addDataScheme(TASK_NAME_DATA_SCHEME); + filter.addDataPath(taskName, PatternMatcher.PATTERN_LITERAL); + + return filter; + } + + public static Intent getTaskSelectIntent() { + return new Intent(ACTION_TASK_SELECT). + setFlags( + Intent.FLAG_ACTIVITY_NO_USER_ACTION | + Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS | + Intent.FLAG_ACTIVITY_NO_HISTORY + ); + } + + // public access deprecated, use TaskerIntent.testSend() instead + + public static boolean havePermission(Context c) { + return c.checkPermission(PERMISSION_RUN_TASKS, Process.myPid(), Process.myUid()) == + PackageManager.PERMISSION_GRANTED; + } + + // Get an intent that will bring up the Tasker prefs screen with the External Access control(s) + // Probably you want to use startActivity or startActivityForResult with it + + public static Intent getExternalAccessPrefsIntent() { + return new Intent(ACTION_OPEN_PREFS).putExtra(EXTRA_OPEN_PREFS_TAB_NO, MISC_PREFS_TAB_NO); + } + + // ------------------------------------- INSTANCE METHODS ----------------------------- // + + public TaskerIntent() { + super(ACTION_TASK); + setRandomData(); + putMetaExtras(getRandomString()); + } + + public TaskerIntent(String taskName) { + super(ACTION_TASK); + setRandomData(); + putMetaExtras(taskName); + } + + public TaskerIntent setTaskPriority(int priority) { + + if (validatePriority(priority)) + putExtra(EXTRA_TASK_PRIORITY, priority); + else + Log.e(TAG, "priority out of range: " + MIN_PRIORITY + ":" + MAX_PRIORITY); + + return this; + } + + // Sets subsequently %par1, %par2 etc + public TaskerIntent addParameter(String value) { + + int index = 1; + + if (getExtras().containsKey(EXTRA_VAR_NAMES_LIST)) + index = getExtras().getStringArrayList(EXTRA_VAR_NAMES_LIST).size() + 1; + + Log.d(TAG, "index: " + index); + + addLocalVariable("%" + PARAM_VAR_NAME_PREFIX + index, value); + + return this; + } + + // Arbitrary specification of (local) variable names and values + public TaskerIntent addLocalVariable(String name, String value) { + + ArrayList names, values; + + if (hasExtra(EXTRA_VAR_NAMES_LIST)) { + names = getStringArrayListExtra(EXTRA_VAR_NAMES_LIST); + values = getStringArrayListExtra(EXTRA_VAR_VALUES_LIST); + } else { + names = new ArrayList(); + values = new ArrayList(); + + putStringArrayListExtra(EXTRA_VAR_NAMES_LIST, names); + putStringArrayListExtra(EXTRA_VAR_VALUES_LIST, values); + } + + names.add(name); + values.add(value); + + return this; + } + + public TaskerIntent addAction(int code) { + + actionCount++; + argCount = 1; + + Bundle actionBundle = new Bundle(); + + actionBundle.putInt(ACTION_CODE, code); + + // Add action bundle to intent + putExtra(EXTRA_ACTION_INDEX_PREFIX + Integer.toString(actionCount), actionBundle); + + return this; + } + + // string arg + public TaskerIntent addArg(String arg) { + + Bundle b = getActionBundle(); + + if (b != null) + b.putString(ARG_INDEX_PREFIX + Integer.toString(argCount++), arg); + + return this; + } + + // int arg + public TaskerIntent addArg(int arg) { + Bundle b = getActionBundle(); + + if (b != null) + b.putInt(ARG_INDEX_PREFIX + Integer.toString(argCount++), arg); + + return this; + } + + // boolean arg + public TaskerIntent addArg(boolean arg) { + Bundle b = getActionBundle(); + + if (b != null) + b.putBoolean(ARG_INDEX_PREFIX + Integer.toString(argCount++), arg); + + return this; + } + + // Application arg + public TaskerIntent addArg(String pkg, String cls) { + Bundle b = getActionBundle(); + + if (b != null) { + StringBuilder builder = new StringBuilder(); + builder.append(APP_ARG_PREFIX). + append(pkg).append(",").append(cls); + b.putString(ARG_INDEX_PREFIX + Integer.toString(argCount++), builder.toString()); + } + + return this; + } + + public IntentFilter getCompletionFilter() { + return getCompletionFilter(getTaskName()); + } + + public String getTaskName() { + return getStringExtra(EXTRA_TASK_NAME); + } + + public boolean receiverExists(Context context) { + List recs = context.getPackageManager().queryBroadcastReceivers(this, 0); + return ( + (recs != null) && + (recs.size() > 0) + ); + } + + // -------------------- PRIVATE METHODS -------------------- // + + private String getRandomString() { + return Long.toString(rand.nextLong()); + } + + // so that if multiple TaskerIntents are used in PendingIntents there's virtually no + // clash chance + private void setRandomData() { + setData(Uri.parse(TASK_ID_SCHEME + ":" + getRandomString())); + } + + private Bundle getActionBundle() { + + Bundle toReturn = null; + + if (argCount > MAX_NO_ARGS) + Log.e(TAG, "maximum number of arguments exceeded (" + MAX_NO_ARGS + ")"); + else { + String key = EXTRA_ACTION_INDEX_PREFIX + Integer.toString(actionCount); + + if (this.hasExtra(key)) + toReturn = getBundleExtra(key); + else + Log.e(TAG, "no actions added yet"); + } + + return toReturn; + } + + private void putMetaExtras(String taskName) { + putExtra(EXTRA_INTENT_VERSION_NUMBER, INTENT_VERSION_NUMBER); + putExtra(EXTRA_TASK_NAME, taskName); + } + + // for testing that Tasker is enabled and external access is allowed + + private static boolean prefSet(Context context, String col) { + + String[] proj = new String[]{col}; + + Cursor c = context.getContentResolver().query(Uri.parse(TASKER_PREFS_URI), proj, null, null, null); + + boolean acceptingFlag = false; + + if (c == null) + Log.w(TAG, "no cursor for " + TASKER_PREFS_URI); + else { + c.moveToFirst(); + + if (Boolean.TRUE.toString().equals(c.getString(0))) + acceptingFlag = true; + + c.close(); + } + + return acceptingFlag; + } +} diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/tasker/service/AbstractTaskerService.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/tasker/service/AbstractTaskerService.java index 6e4c620cb..7dc2d967f 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/tasker/service/AbstractTaskerService.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/tasker/service/AbstractTaskerService.java @@ -6,8 +6,10 @@ import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import nodomain.freeyourgadget.gadgetbridge.GBApplication; -import nodomain.freeyourgadget.gadgetbridge.tasker.event.SettingSupplier; -import nodomain.freeyourgadget.gadgetbridge.tasker.event.SettingSupplierImpl; +import nodomain.freeyourgadget.gadgetbridge.tasker.plugin.TaskerConstants; +import nodomain.freeyourgadget.gadgetbridge.tasker.plugin.TaskerIntent; +import nodomain.freeyourgadget.gadgetbridge.tasker.settings.SettingSupplier; +import nodomain.freeyourgadget.gadgetbridge.tasker.settings.SettingSupplierImpl; import nodomain.freeyourgadget.gadgetbridge.tasker.event.TaskerEventType; import nodomain.freeyourgadget.gadgetbridge.tasker.task.TaskerTask; import nodomain.freeyourgadget.gadgetbridge.tasker.task.TaskerTaskProvider; @@ -28,17 +30,28 @@ public abstract class AbstractTaskerService { this.enabled = new SettingSupplierImpl() { @Override public Boolean get() { - return GBApplication.getPrefs().getBoolean(TaskerConstants.TASKER_ENABLED, false); + return GBApplication.getPrefs().getBoolean(TaskerConstants.ACTIVITY_TASKER_ENABLED, false); } }; } - public boolean isActive() { + public boolean isEnabled() { return enabled.get(); } + /** + * Schedules tasker task for {@link TaskerEventType} if + * {@link #isEnabled()}, + * {@link #isReady()} and + * event type is not {@link TaskerEventType#NO_OP}. + *

+ * Uses {@link #DEFAULT_THRESHOLD} of '50' milliseconds if threshold is not set. + * + * @param type + * @return + */ public boolean runForType(TaskerEventType type) { - if (type != null && !TaskerEventType.NO_OP.equals(type) && isActive() && ready()) { + if (type != null && !TaskerEventType.NO_OP.equals(type) && isEnabled() && isReady()) { if (!tasks.containsKey(type)) { SettingSupplier taskProvider = taskProvider(type); if (taskProvider.isPresent()) { @@ -56,7 +69,12 @@ public abstract class AbstractTaskerService { protected abstract SettingSupplier taskProvider(TaskerEventType type); - public static boolean ready() { + /** + * Determines of tasker is installed and ready. + * + * @return True if installed and ready + */ + public static boolean isReady() { return TaskerIntent.testStatus(GBApplication.getContext()).equals(TaskerIntent.Status.OK); } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/tasker/service/NoTaskDefinedException.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/tasker/service/NoTaskDefinedException.java index d354aecb4..f9f8b7815 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/tasker/service/NoTaskDefinedException.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/tasker/service/NoTaskDefinedException.java @@ -1,5 +1,8 @@ package nodomain.freeyourgadget.gadgetbridge.tasker.service; +/** + * Gets thrown if tasker is enabled but no task name is defined. Triggers {@link TaskerUtil#noTaskDefinedInformation()}. + */ public class NoTaskDefinedException extends RuntimeException { public NoTaskDefinedException() { diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/tasker/service/SpecTaskerService.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/tasker/service/SpecTaskerService.java index fe3c7a554..88ecaf98e 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/tasker/service/SpecTaskerService.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/tasker/service/SpecTaskerService.java @@ -1,11 +1,12 @@ package nodomain.freeyourgadget.gadgetbridge.tasker.service; -import nodomain.freeyourgadget.gadgetbridge.tasker.event.SettingSupplier; +import nodomain.freeyourgadget.gadgetbridge.tasker.settings.SettingSupplier; import nodomain.freeyourgadget.gadgetbridge.tasker.event.TaskerEventType; +import nodomain.freeyourgadget.gadgetbridge.tasker.spec.TaskerSpec; import nodomain.freeyourgadget.gadgetbridge.tasker.task.TaskerTaskProvider; /** - * {@link TaskerSpec} impl for {@link AbstractTaskerService}. + * {@link TaskerSpec} implementation for {@link TaskerService}. */ public class SpecTaskerService extends AbstractTaskerService { diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/tasker/service/TaskerAbstractSpec.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/tasker/service/TaskerAbstractSpec.java deleted file mode 100644 index 40b92f342..000000000 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/tasker/service/TaskerAbstractSpec.java +++ /dev/null @@ -1,12 +0,0 @@ -package nodomain.freeyourgadget.gadgetbridge.tasker.service; - -import nodomain.freeyourgadget.gadgetbridge.tasker.event.TaskerEventType; -import nodomain.freeyourgadget.gadgetbridge.tasker.settings.TaskerSettings; - -public abstract class TaskerAbstractSpec implements TaskerSpec { - - @Override - public TaskerSettings getSettings(TaskerEventType eventType) { - return null; - } -} diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/tasker/service/TaskerConstants.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/tasker/service/TaskerConstants.java deleted file mode 100644 index afd8af24f..000000000 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/tasker/service/TaskerConstants.java +++ /dev/null @@ -1,78 +0,0 @@ -package nodomain.freeyourgadget.gadgetbridge.tasker.service; - -import java.io.Serializable; - -import nodomain.freeyourgadget.gadgetbridge.devices.xwatch.XWatchConstants; -import nodomain.freeyourgadget.gadgetbridge.devices.xwatch.XWatchService; -import nodomain.freeyourgadget.gadgetbridge.devices.xwatch.XWatchTaskerSpec; -import nodomain.freeyourgadget.gadgetbridge.model.DeviceType; - -public class TaskerConstants { - - - private static final String tasker = "tasker"; - public static final String TASKER = "pref_key_tasker"; - public static final String TASKER_SETTINGS = "pref_key_tasker_settings"; - public static final String TASKER_ENABLED = "tasker_enabled"; - public static final String TASKER_PREFERENCES = "tasker_preferences"; - public static final String TASKER_PREF_GROUP = "pref_key_tasker_group"; - public static final String DEVICE_INTENT = "intent_tasker_device"; - public static final String EVENT_INTENT = "intent_tasker_event"; - public static final String TASKER_TASK = "tasker-task"; - public static final String TASKER_PREFERENCE = "tasker_list"; - public static final String PREF_EVENT_GROUP = "pref_key_tasker_event_group"; - - public static final String ACTIVITY_THRESHOLD = "act_tasker_threshold"; - public static final String ACTIVITY_TASK_ADD = "act_tasker_task_add"; - public static final String ACTIVITY_TASK = "act_tasker_task"; - public static final String ACTIVITY_THESHOLD_ENABELD = "act_tasker_threshold_enabled"; - public static final String ACTIVITY_TASKS = "act_tasker_task_group"; - - - public enum TaskerDevice implements Serializable { - - XWATCH(DeviceType.XWATCH, new XWatchTaskerSpec()); - - private DeviceType type; - private TaskerSpec spec; - - TaskerDevice(DeviceType type, TaskerSpec spec) { - this.type = type; - this.spec = spec; - } - - public DeviceType getType() { - return type; - } - - public TaskerSpec getSpec() { - return spec; - } - } - -// public static class Settings { -// -// private static final String setting = "setting"; -// public static final String ENABLED = concate(tasker, setting, "enabled"); -// public static final String ENABLED = "tasker_enabled"; -// -// } -// -// public static class Preferences { -// private static final String prefKey = "pref_key"; -// public static final String TASKER = concate(prefKey, "tasker"); -// public static final String TASKER_SETTINGS = concate(prefKey, "tasker", "settings"); -// } - - private static String concate(String... parts) { - StringBuilder builder = new StringBuilder(); - for (int i = 0; i < parts.length; i++) { - builder.append(parts[i]); - if (i < parts.length - 1) { - builder.append("_"); - } - } - return builder.toString(); - } - -} diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/tasker/service/TaskerIntent.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/tasker/service/TaskerIntent.java deleted file mode 100644 index 412d11a97..000000000 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/tasker/service/TaskerIntent.java +++ /dev/null @@ -1,449 +0,0 @@ -// Version 1.3.3 - -// Changelog - -// Version 1.3.3 -// - increased MAX_NO_ARGS to 10 - -// Version 1.3.2 -// - bug setting app arg -// - pulled provider column names out of function - -// For usage examples see http://tasker.dinglisch.net/invoketasks.html - -package nodomain.freeyourgadget.gadgetbridge.tasker.service; - -import java.lang.reflect.Field; -import java.util.ArrayList; -import java.util.List; -import java.util.Random; - -import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; -import android.content.pm.PackageManager; -import android.content.pm.ResolveInfo; -import android.database.Cursor; -import android.net.Uri; -import android.os.Bundle; -import android.os.PatternMatcher; -import android.os.Process; -import android.util.Log; - -public class TaskerIntent extends Intent { - - // 3 Tasker versions - public final static String TASKER_PACKAGE = "net.dinglisch.android.tasker"; - public final static String TASKER_PACKAGE_MARKET = TASKER_PACKAGE + "m"; - public final static String TASKER_PACKAGE_CUPCAKE = TASKER_PACKAGE + "cupcake"; - - // Play Store download URLs - public final static String MARKET_DOWNLOAD_URL_PREFIX = "market://details?id="; - private final static String TASKER_MARKET_URL = MARKET_DOWNLOAD_URL_PREFIX + TASKER_PACKAGE_MARKET; - private final static String TASKER_MARKET_URL_CUPCAKE = MARKET_DOWNLOAD_URL_PREFIX + TASKER_PACKAGE_CUPCAKE; - - // Direct-purchase version - private final static String TASKER_DOWNLOAD_URL = "http://tasker.dinglisch.net/download.html"; - - // Intent actions - public final static String ACTION_TASK = TASKER_PACKAGE + ".ACTION_TASK"; - public final static String ACTION_TASK_COMPLETE = TASKER_PACKAGE + ".ACTION_TASK_COMPLETE"; - public final static String ACTION_TASK_SELECT = TASKER_PACKAGE + ".ACTION_TASK_SELECT"; - - // Intent parameters - public final static String EXTRA_ACTION_INDEX_PREFIX = "action"; - public final static String TASK_NAME_DATA_SCHEME = "task"; - public final static String EXTRA_TASK_NAME = "task_name"; - public final static String EXTRA_TASK_PRIORITY = "task_priority"; - public final static String EXTRA_SUCCESS_FLAG = "success"; - public final static String EXTRA_VAR_NAMES_LIST = "varNames"; - public final static String EXTRA_VAR_VALUES_LIST = "varValues"; - public final static String EXTRA_TASK_OUTPUT = "output"; - - // Content provider columns - public static final String PROVIDER_COL_NAME_EXTERNAL_ACCESS = "ext_access"; - public static final String PROVIDER_COL_NAME_ENABLED = "enabled"; - - // DEPRECATED, use EXTRA_VAR_NAMES_LIST, EXTRA_VAR_VALUES_LIST - public final static String EXTRA_PARAM_LIST = "params"; - - // Intent data - - public final static String TASK_ID_SCHEME = "id"; - - // For particular actions - - public final static String DEFAULT_ENCRYPTION_KEY= "default"; - public final static String ENCRYPTED_AFFIX = "tec"; - public final static int MAX_NO_ARGS = 10; - - // Bundle keys - // Only useful for Tasker - public final static String ACTION_CODE = "action"; - public final static String APP_ARG_PREFIX = "app:"; - public final static String ICON_ARG_PREFIX = "icn:"; - public final static String ARG_INDEX_PREFIX = "arg:"; - public static final String PARAM_VAR_NAME_PREFIX = "par"; - - // Misc - private final static String PERMISSION_RUN_TASKS = TASKER_PACKAGE + ".PERMISSION_RUN_TASKS"; - - public final static String ACTION_OPEN_PREFS = TASKER_PACKAGE + ".ACTION_OPEN_PREFS"; - public final static String EXTRA_OPEN_PREFS_TAB_NO = "tno"; - private final static int MISC_PREFS_TAB_NO = 3; // 0 based - - // To query whether Tasker is enabled and external access is enabled - private final static String TASKER_PREFS_URI = "content://" + TASKER_PACKAGE + "/prefs"; - - private final static int CUPCAKE_SDK_VERSION = 3; - - // result values for TestSend - - // NotInstalled: Tasker package not found on device - // NoPermission: calling app does not have permission PERMISSION_RUN_TASKS - // NotEnabled: Tasker is not enabled - // AccessBlocked: user prefs disallow external access - // NoReceiver: Tasker has not created a listener for external access (probably a Tasker bug) - // OK: you should be able to send a task to run. Still need to listen for result - // for e.g. task not found - - public static enum Status { NotInstalled, NoPermission, NotEnabled, AccessBlocked, NoReceiver, OK }; - - // -------------------------- PRIVATE VARS ---------------------------- // - - private final static String TAG = "TaskerIntent"; - - private final static String EXTRA_INTENT_VERSION_NUMBER = "version_number"; - private final static String INTENT_VERSION_NUMBER = "1.1"; - - // Inclusive values - private final static int MIN_PRIORITY = 0; - private final static int MAX_PRIORITY = 10; - - // For generating random names - private static Random rand = new Random(); - - // Tracking state - private int actionCount = 0; - private int argCount; - - // -------------------------- PUBLIC METHODS ---------------------------- // - - public static int getMaxPriority() { - return MAX_PRIORITY; - } - - public static boolean validatePriority( int pri ) { - return ( - ( pri >= MIN_PRIORITY ) || - ( pri <= MAX_PRIORITY ) - ); - } - - // Tasker has different package names for Play Store and non- versions - // for historical reasons - - public static String getInstalledTaskerPackage( Context context ) { - - String foundPackage = null; - - try { - context.getPackageManager().getPackageInfo( TASKER_PACKAGE, 0 ); - foundPackage = TASKER_PACKAGE; - } - catch ( PackageManager.NameNotFoundException e ) { - } - - try { - context.getPackageManager().getPackageInfo( TASKER_PACKAGE_MARKET, 0 ); - foundPackage = TASKER_PACKAGE_MARKET; - } - catch ( PackageManager.NameNotFoundException e ) { - } - - return foundPackage; - } - - // test we can send a TaskerIntent to Tasker - // use *before* sending an intent - // still need to test the *result after* sending intent - - public static Status testStatus( Context c ) { - - Status result; - - if ( ! taskerInstalled( c ) ) - result = Status.NotInstalled; - else if ( ! havePermission( c ) ) - result = Status.NoPermission; - else if ( ! TaskerIntent.prefSet( c, PROVIDER_COL_NAME_ENABLED ) ) - result = Status.NotEnabled; - else if ( ! TaskerIntent.prefSet( c, PROVIDER_COL_NAME_EXTERNAL_ACCESS ) ) - result = Status.AccessBlocked; - else if ( ! new TaskerIntent( "" ).receiverExists( c ) ) - result = Status.NoReceiver; - else - result = Status.OK; - - return result; - } - - // Check if Tasker installed - - public static boolean taskerInstalled( Context context ) { - return ( getInstalledTaskerPackage( context ) != null ); - } - - // Use with startActivity to retrieve Tasker from Android market - public static Intent getTaskerInstallIntent( boolean marketFlag ) { - - return new Intent( - Intent.ACTION_VIEW, - Uri.parse( - marketFlag ? - ( ( SDKVersion() == CUPCAKE_SDK_VERSION ) ? TASKER_MARKET_URL_CUPCAKE : TASKER_MARKET_URL ) : - TASKER_DOWNLOAD_URL - ) - ); - } - - public static int SDKVersion() { - try { - Field f = android.os.Build.VERSION.class.getField( "SDK_INT" ); - return f.getInt( null ); - } - catch ( Exception e ) { - return CUPCAKE_SDK_VERSION; - } - } - - public static IntentFilter getCompletionFilter( String taskName ) { - - IntentFilter filter = new IntentFilter( TaskerIntent.ACTION_TASK_COMPLETE ); - - filter.addDataScheme( TASK_NAME_DATA_SCHEME ); - filter.addDataPath( taskName, PatternMatcher.PATTERN_LITERAL ); - - return filter; - } - - public static Intent getTaskSelectIntent() { - return new Intent( ACTION_TASK_SELECT ). - setFlags( - Intent.FLAG_ACTIVITY_NO_USER_ACTION | - Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS | - Intent.FLAG_ACTIVITY_NO_HISTORY - ); - } - - // public access deprecated, use TaskerIntent.testSend() instead - - public static boolean havePermission( Context c ) { - return c.checkPermission( PERMISSION_RUN_TASKS, Process.myPid(), Process.myUid() ) == - PackageManager.PERMISSION_GRANTED; - } - - // Get an intent that will bring up the Tasker prefs screen with the External Access control(s) - // Probably you want to use startActivity or startActivityForResult with it - - public static Intent getExternalAccessPrefsIntent() { - return new Intent( ACTION_OPEN_PREFS ).putExtra( EXTRA_OPEN_PREFS_TAB_NO, MISC_PREFS_TAB_NO ); - } - - // ------------------------------------- INSTANCE METHODS ----------------------------- // - - public TaskerIntent() { - super( ACTION_TASK ); - setRandomData(); - putMetaExtras( getRandomString() ); - } - - public TaskerIntent( String taskName ) { - super( ACTION_TASK ); - setRandomData(); - putMetaExtras( taskName ); - } - - public TaskerIntent setTaskPriority( int priority ) { - - if ( validatePriority( priority ) ) - putExtra( EXTRA_TASK_PRIORITY, priority ); - else - Log.e( TAG, "priority out of range: " + MIN_PRIORITY + ":" + MAX_PRIORITY ); - - return this; - } - - // Sets subsequently %par1, %par2 etc - public TaskerIntent addParameter( String value ) { - - int index = 1; - - if ( getExtras().containsKey( EXTRA_VAR_NAMES_LIST ) ) - index = getExtras().getStringArrayList( EXTRA_VAR_NAMES_LIST ).size() + 1; - - Log.d(TAG, "index: " + index ); - - addLocalVariable( "%" + PARAM_VAR_NAME_PREFIX + index, value ); - - return this; - } - - // Arbitrary specification of (local) variable names and values - public TaskerIntent addLocalVariable( String name, String value ) { - - ArrayList names, values; - - if ( hasExtra( EXTRA_VAR_NAMES_LIST ) ) { - names = getStringArrayListExtra( EXTRA_VAR_NAMES_LIST ); - values = getStringArrayListExtra( EXTRA_VAR_VALUES_LIST ); - } - else { - names = new ArrayList(); - values = new ArrayList(); - - putStringArrayListExtra( EXTRA_VAR_NAMES_LIST, names ); - putStringArrayListExtra( EXTRA_VAR_VALUES_LIST, values ); - } - - names.add( name ); - values.add( value ); - - return this; - } - - public TaskerIntent addAction( int code ) { - - actionCount++; - argCount = 1; - - Bundle actionBundle = new Bundle(); - - actionBundle.putInt( ACTION_CODE, code ); - - // Add action bundle to intent - putExtra( EXTRA_ACTION_INDEX_PREFIX + Integer.toString( actionCount ), actionBundle ); - - return this; - } - - // string arg - public TaskerIntent addArg( String arg ) { - - Bundle b = getActionBundle(); - - if ( b != null ) - b.putString( ARG_INDEX_PREFIX + Integer.toString( argCount++ ), arg ); - - return this; - } - - // int arg - public TaskerIntent addArg( int arg ) { - Bundle b = getActionBundle(); - - if ( b != null ) - b.putInt( ARG_INDEX_PREFIX + Integer.toString( argCount++ ), arg ); - - return this; - } - - // boolean arg - public TaskerIntent addArg( boolean arg ) { - Bundle b = getActionBundle(); - - if ( b != null ) - b.putBoolean( ARG_INDEX_PREFIX + Integer.toString( argCount++ ), arg ); - - return this; - } - - // Application arg - public TaskerIntent addArg( String pkg, String cls ) { - Bundle b = getActionBundle(); - - if ( b != null ) { - StringBuilder builder = new StringBuilder(); - builder.append( APP_ARG_PREFIX ). - append( pkg ). append( "," ). append( cls ); - b.putString( ARG_INDEX_PREFIX + Integer.toString( argCount++ ), builder.toString() ); - } - - return this; - } - - public IntentFilter getCompletionFilter() { - return getCompletionFilter( getTaskName() ); - } - - public String getTaskName() { - return getStringExtra( EXTRA_TASK_NAME ); - } - - public boolean receiverExists( Context context ) { - List recs = context.getPackageManager().queryBroadcastReceivers( this, 0 ); - return ( - ( recs != null ) && - ( recs.size() > 0 ) - ); - } - - // -------------------- PRIVATE METHODS -------------------- // - - private String getRandomString() { - return Long.toString( rand.nextLong() ); - } - - // so that if multiple TaskerIntents are used in PendingIntents there's virtually no - // clash chance - private void setRandomData() { - setData( Uri.parse( TASK_ID_SCHEME + ":" + getRandomString() ) ); - } - - private Bundle getActionBundle() { - - Bundle toReturn = null; - - if ( argCount > MAX_NO_ARGS ) - Log.e( TAG, "maximum number of arguments exceeded (" + MAX_NO_ARGS + ")" ); - else { - String key = EXTRA_ACTION_INDEX_PREFIX + Integer.toString( actionCount ); - - if ( this.hasExtra( key ) ) - toReturn = getBundleExtra( key ); - else - Log.e( TAG, "no actions added yet" ); - } - - return toReturn; - } - - private void putMetaExtras( String taskName ) { - putExtra( EXTRA_INTENT_VERSION_NUMBER, INTENT_VERSION_NUMBER ); - putExtra( EXTRA_TASK_NAME, taskName ); - } - - // for testing that Tasker is enabled and external access is allowed - - private static boolean prefSet( Context context, String col ) { - - String [] proj = new String [] { col }; - - Cursor c = context.getContentResolver().query( Uri.parse( TASKER_PREFS_URI ), proj, null, null, null ); - - boolean acceptingFlag = false; - - if ( c == null ) - Log.w( TAG, "no cursor for " + TASKER_PREFS_URI ); - else { - c.moveToFirst(); - - if ( Boolean.TRUE.toString().equals( c.getString( 0 ) ) ) - acceptingFlag = true; - - c.close(); - } - - return acceptingFlag; - } -} diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/tasker/service/TaskerService.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/tasker/service/TaskerService.java index 1bd85dedc..0a80441b4 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/tasker/service/TaskerService.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/tasker/service/TaskerService.java @@ -1,25 +1,18 @@ package nodomain.freeyourgadget.gadgetbridge.tasker.service; -import android.widget.Toast; - import java.util.HashMap; import java.util.Map; -import java.util.concurrent.Executors; -import java.util.concurrent.ScheduledExecutorService; -import java.util.function.Supplier; -import nodomain.freeyourgadget.gadgetbridge.GBApplication; -import nodomain.freeyourgadget.gadgetbridge.tasker.event.SettingSupplier; -import nodomain.freeyourgadget.gadgetbridge.tasker.event.SettingSupplierImpl; +import nodomain.freeyourgadget.gadgetbridge.tasker.settings.SettingSupplier; +import nodomain.freeyourgadget.gadgetbridge.tasker.settings.SettingSupplierImpl; import nodomain.freeyourgadget.gadgetbridge.tasker.event.TaskerEvent; import nodomain.freeyourgadget.gadgetbridge.tasker.event.TaskerEventType; -import nodomain.freeyourgadget.gadgetbridge.tasker.task.TaskerTask; import nodomain.freeyourgadget.gadgetbridge.tasker.task.TaskerTaskProvider; /** - * Default impl for {@link AbstractTaskerService}. + * Default implementation for {@link AbstractTaskerService}. *

- * One instance per thread/device! The service is not threadsafe. + * Preferred to use with java based configuration. */ public class TaskerService extends AbstractTaskerService { @@ -30,11 +23,25 @@ public class TaskerService extends AbstractTaskerService { this.enabled = new SettingSupplierImpl<>(enabled); } + /** + * Set threshold between task calls for {@link TaskerEventType}. + * + * @param type Event + * @param threshold Threshold in milliseconds + * @return Itself + */ public TaskerService withThreshold(TaskerEventType type, long threshold) { this.threshold.put(type, new SettingSupplierImpl<>(threshold)); return this; } + /** + * Sets single task name for {@link TaskerEventType}. + * + * @param type Event + * @param task Single task name + * @return Itself + */ public TaskerService withTask(TaskerEventType type, final String task) { typeProvider.put(type, new SettingSupplierImpl(new TaskerTaskProvider() { @Override @@ -45,13 +52,18 @@ public class TaskerService extends AbstractTaskerService { return this; } + /** + * Sets {@link TaskerTaskProvider} for {@link TaskerEventType}. + * + * @param type Event + * @param provider Task name provider + * @return Itself + */ public TaskerService withProvider(TaskerEventType type, TaskerTaskProvider provider) { typeProvider.put(type, new SettingSupplierImpl<>(provider)); return this; } - // Private - protected SettingSupplier threshold(TaskerEventType type) { return threshold.get(type); } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/tasker/service/TaskerUtil.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/tasker/service/TaskerUtil.java index d724536d6..f95f902ec 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/tasker/service/TaskerUtil.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/tasker/service/TaskerUtil.java @@ -4,6 +4,7 @@ import android.widget.Toast; import nodomain.freeyourgadget.gadgetbridge.GBApplication; import nodomain.freeyourgadget.gadgetbridge.R; +import nodomain.freeyourgadget.gadgetbridge.tasker.plugin.TaskerIntent; /** * Tasker convenience methods for direct access to tasker without {@link TaskerService}. diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/tasker/event/SettingSupplier.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/tasker/settings/SettingSupplier.java similarity index 54% rename from app/src/main/java/nodomain/freeyourgadget/gadgetbridge/tasker/event/SettingSupplier.java rename to app/src/main/java/nodomain/freeyourgadget/gadgetbridge/tasker/settings/SettingSupplier.java index 8df8ff2a4..c3c1b4b95 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/tasker/event/SettingSupplier.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/tasker/settings/SettingSupplier.java @@ -1,7 +1,7 @@ -package nodomain.freeyourgadget.gadgetbridge.tasker.event; +package nodomain.freeyourgadget.gadgetbridge.tasker.settings; /** - * Simple supplier. + * Simple setting supplier. Can listen to changes throw {@link SettingListener}. * * @param Setting */ @@ -15,6 +15,11 @@ public interface SettingSupplier { SettingSupplier onChanged(SettingListener onChanged); + /** + * Listen to changes in {@link SettingSupplier}. + * + * @param + */ interface SettingListener { void changed(T object); } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/tasker/event/SettingSupplierImpl.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/tasker/settings/SettingSupplierImpl.java similarity index 74% rename from app/src/main/java/nodomain/freeyourgadget/gadgetbridge/tasker/event/SettingSupplierImpl.java rename to app/src/main/java/nodomain/freeyourgadget/gadgetbridge/tasker/settings/SettingSupplierImpl.java index 1045cad69..d05b607c8 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/tasker/event/SettingSupplierImpl.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/tasker/settings/SettingSupplierImpl.java @@ -1,5 +1,10 @@ -package nodomain.freeyourgadget.gadgetbridge.tasker.event; +package nodomain.freeyourgadget.gadgetbridge.tasker.settings; +/** + * Default implementation for {@link SettingSupplier}. + * + * @param + */ public class SettingSupplierImpl implements SettingSupplier { private T object; @@ -20,7 +25,9 @@ public class SettingSupplierImpl implements SettingSupplier { @Override public void set(T object) { this.object = object; - onChanged.changed(object); + if (onChanged != null) { + onChanged.changed(object); + } } @Override diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/tasker/settings/TaskerSettings.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/tasker/settings/TaskerSettings.java index 085c38be2..0eb16cf1f 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/tasker/settings/TaskerSettings.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/tasker/settings/TaskerSettings.java @@ -1,16 +1,45 @@ package nodomain.freeyourgadget.gadgetbridge.tasker.settings; -import nodomain.freeyourgadget.gadgetbridge.tasker.event.SettingSupplier; +import nodomain.freeyourgadget.gadgetbridge.tasker.spec.TaskerSpec; import nodomain.freeyourgadget.gadgetbridge.tasker.task.TaskerTaskProvider; +/** + * Tasker settings. There is one setting per {@link nodomain.freeyourgadget.gadgetbridge.tasker.event.TaskerEventType}. + * This is usually wrapped in {@link TaskerSpec} + * and used by {@link nodomain.freeyourgadget.gadgetbridge.tasker.settings.activities.TaskerEventActivity} to let the user customize the settings. + * {@link nodomain.freeyourgadget.gadgetbridge.tasker.service.SpecTaskerService} is the out of the box implementation that uses this settings to call tasker. + *

+ * Extend here for more settings. + */ public interface TaskerSettings { + /** + * Consumes events or just listens to them. + * + * @return True if consumes events. + */ SettingSupplier isConsumingEvents(); + /** + * Enables the settings. + * + * @return True if settings are enabled. + */ SettingSupplier isEnabled(); + /** + * Threshold for tasker calls. Determines the delay between {@link nodomain.freeyourgadget.gadgetbridge.tasker.event.TaskerEvent}'s + * and is therefore the main attribute to determine which tasker task is called. + * + * @return Threshold in milliseconds + */ SettingSupplier getThreshold(); + /** + * {@link TaskerTaskProvider} determines the task names for {@link nodomain.freeyourgadget.gadgetbridge.tasker.event.TaskerEvent}. + * + * @return Task provider + */ SettingSupplier getTaskProvider(); } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/tasker/settings/activities/ButtonPreference.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/tasker/settings/activities/ButtonPreference.java index 4b383a36a..8784185a3 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/tasker/settings/activities/ButtonPreference.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/tasker/settings/activities/ButtonPreference.java @@ -8,6 +8,11 @@ import android.widget.Button; import nodomain.freeyourgadget.gadgetbridge.R; +/** + * Simple {@link EditTextPreference} with an button. + *

+ * Exposes only {@link Button#setOnClickListener(View.OnClickListener)} and {@link Button#setText(int)} + */ public class ButtonPreference extends EditTextPreference { private View.OnClickListener onClickListener; @@ -15,6 +20,7 @@ public class ButtonPreference extends EditTextPreference { public ButtonPreference(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); + setWidgetLayoutResource(R.layout.button_preference_layout); } public ButtonPreference(Context context, AttributeSet attrs) { @@ -35,10 +41,20 @@ public class ButtonPreference extends EditTextPreference { } } + /** + * Sets an {@link View.OnClickListener} to the button. + * + * @param clickListener + */ public void setOnClickListener(View.OnClickListener clickListener) { this.onClickListener = clickListener; } + /** + * Set button text with resource id. + * + * @param resourceId {@link R.string} + */ public void setButtonText(int resourceId) { if (button != null) { button.setText(resourceId); diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/tasker/settings/activities/TaskerActivity.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/tasker/settings/activities/TaskerActivity.java index 8cc5dac3b..e13d970e0 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/tasker/settings/activities/TaskerActivity.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/tasker/settings/activities/TaskerActivity.java @@ -7,16 +7,22 @@ import android.preference.PreferenceCategory; import nodomain.freeyourgadget.gadgetbridge.R; import nodomain.freeyourgadget.gadgetbridge.activities.AbstractSettingsActivity; -import nodomain.freeyourgadget.gadgetbridge.tasker.service.TaskerConstants; +import nodomain.freeyourgadget.gadgetbridge.tasker.plugin.TaskerConstants; +import nodomain.freeyourgadget.gadgetbridge.tasker.plugin.TaskerDevice; +/** + * Tasker main {@link AbstractSettingsActivity} builds an supported list of {@link TaskerConstants.TaskerDevice}. + *

+ * Forwards to {@link TaskerEventsActivity}. + */ public class TaskerActivity extends AbstractSettingsActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); addPreferencesFromResource(R.xml.tasker_preferences); - final PreferenceCategory group = (PreferenceCategory) findPreference(TaskerConstants.TASKER_PREF_GROUP); - for (TaskerConstants.TaskerDevice device : TaskerConstants.TaskerDevice.values()) { + final PreferenceCategory group = (PreferenceCategory) findPreference(TaskerConstants.ACTIVITY_TASKER_GROUP); + for (TaskerDevice device : TaskerDevice.values()) { group.addPreference(preference(device)); } } @@ -26,14 +32,14 @@ public class TaskerActivity extends AbstractSettingsActivity { super.onPostCreate(savedInstanceState); } - private Preference preference(final TaskerConstants.TaskerDevice device) { + private Preference preference(final TaskerDevice device) { Preference devicePreference = new Preference(this); devicePreference.setTitle(device.getType().getName()); devicePreference.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() { @Override public boolean onPreferenceClick(Preference preference) { Intent intent = new Intent(TaskerActivity.this, TaskerEventsActivity.class); - intent.putExtra(TaskerConstants.DEVICE_INTENT, device); + intent.putExtra(TaskerConstants.INTENT_DEVICE, device); startActivity(intent); return true; } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/tasker/settings/activities/TaskerEventActivity.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/tasker/settings/activities/TaskerEventActivity.java index 01d862a38..badc79f29 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/tasker/settings/activities/TaskerEventActivity.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/tasker/settings/activities/TaskerEventActivity.java @@ -4,26 +4,38 @@ import android.os.Bundle; import android.preference.EditTextPreference; import android.preference.Preference; import android.preference.PreferenceScreen; +import android.preference.SwitchPreference; import android.view.View; +import java.util.ArrayList; +import java.util.List; + import nodomain.freeyourgadget.gadgetbridge.GBApplication; import nodomain.freeyourgadget.gadgetbridge.R; import nodomain.freeyourgadget.gadgetbridge.activities.AbstractSettingsActivity; import nodomain.freeyourgadget.gadgetbridge.tasker.event.TaskerEvent; import nodomain.freeyourgadget.gadgetbridge.tasker.event.TaskerEventType; -import nodomain.freeyourgadget.gadgetbridge.tasker.service.TaskerConstants; +import nodomain.freeyourgadget.gadgetbridge.tasker.plugin.TaskerConstants; +import nodomain.freeyourgadget.gadgetbridge.tasker.plugin.TaskerDevice; +import nodomain.freeyourgadget.gadgetbridge.tasker.service.NoTaskDefinedException; import nodomain.freeyourgadget.gadgetbridge.tasker.settings.TaskerSettings; +import nodomain.freeyourgadget.gadgetbridge.tasker.spec.TaskerSpec; import nodomain.freeyourgadget.gadgetbridge.tasker.task.TaskerTaskProvider; import nodomain.freeyourgadget.gadgetbridge.util.Prefs; +import nodomain.freeyourgadget.gadgetbridge.util.StringUtils; +/** + * Tasker event {@link AbstractSettingsActivity} takes {@link TaskerSpec} from {@link TaskerDevice#getSpec()} + * to configure its {@link TaskerSettings} via {@link TaskerSpec#getSettings(TaskerEventType)}. + *

+ * If you extend {@link TaskerSettings} this is the point to implement the new features for user configuration. + */ public class TaskerEventActivity extends AbstractSettingsActivity { - private TaskerConstants.TaskerDevice device; + private TaskerDevice device; private TaskerEventType eventType; private Prefs prefs = GBApplication.getPrefs(); - - public TaskerEventActivity() { - } + private List taskPreferences = new ArrayList<>(); @Override protected void onCreate(Bundle savedInstanceState) { @@ -34,16 +46,31 @@ public class TaskerEventActivity extends AbstractSettingsActivity { @Override protected void onPostCreate(Bundle savedInstanceState) { super.onPostCreate(savedInstanceState); - device = (TaskerConstants.TaskerDevice) getIntent().getSerializableExtra(TaskerConstants.DEVICE_INTENT); + device = (TaskerDevice) getIntent().getSerializableExtra(TaskerConstants.INTENT_DEVICE); + eventType = (TaskerEventType) getIntent().getSerializableExtra(TaskerConstants.INTENT_EVENT); final TaskerSettings settings = device.getSpec().getSettings(eventType); - eventType = (TaskerEventType) getIntent().getSerializableExtra(TaskerConstants.EVENT_INTENT); - final PreferenceScreen tasks = (PreferenceScreen) findPreference(TaskerConstants.ACTIVITY_TASKS); + SwitchPreference enabled = (SwitchPreference) findPreference(scoped(TaskerConstants.ACTIVITY_EVENT_ENABLED)); + settings.isEnabled().set(prefs.getBoolean(scoped(TaskerConstants.ACTIVITY_EVENT_ENABLED), false)); + enabled.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() { + @Override + public boolean onPreferenceChange(Preference preference, Object newValue) { + settings.isEnabled().set((Boolean) newValue); + return true; + } + }); + eventType = (TaskerEventType) getIntent().getSerializableExtra(TaskerConstants.INTENT_EVENT); + final PreferenceScreen tasks = (PreferenceScreen) findPreference(scoped(TaskerConstants.ACTIVITY_TASKS)); initThreshold(settings, tasks); initTasks(settings, tasks); } + private String scoped(TaskerConstants.ScopedString scopedString) { + return scopedString.withScope(device.name()).withScope(eventType.getType()).toString(); + } + private void initThreshold(final TaskerSettings settings, final PreferenceScreen tasks) { - EditTextPreference threshold = (EditTextPreference) findPreference(TaskerConstants.ACTIVITY_THRESHOLD); + final EditTextPreference threshold = (EditTextPreference) findPreference(scoped(TaskerConstants.ACTIVITY_THRESHOLD)); + setThresholdIfDefined(settings); threshold.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() { @Override public boolean onPreferenceChange(Preference preference, Object newValue) { @@ -51,28 +78,43 @@ public class TaskerEventActivity extends AbstractSettingsActivity { return true; } }); - final Preference thresholdEnabled = findPreference(TaskerConstants.ACTIVITY_THESHOLD_ENABELD); + final Preference thresholdEnabled = findPreference(scoped(TaskerConstants.ACTIVITY_THRESHOLD_ENABLED)); + if (prefs.getBoolean(scoped(TaskerConstants.ACTIVITY_THRESHOLD_ENABLED), false)) { + settings.getThreshold().set(null); + } thresholdEnabled.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() { @Override public boolean onPreferenceChange(Preference preference, Object newValue) { if (newValue.equals(Boolean.FALSE)) { - for (int i = 2; i < tasks.getPreferenceCount(); i++) { - tasks.removePreference(tasks.getPreference(tasks.getPreferenceCount())); + for (EditTextPreference taskPreference : taskPreferences) { + if (!taskPreference.getKey().equals(scoped(TaskerConstants.ACTIVITY_TASK))) { + tasks.removePreference(taskPreference); + } } + settings.getThreshold().set(null); + return true; } - settings.getThreshold().set(null); + setThresholdIfDefined(settings); return true; } }); } + private void setThresholdIfDefined(TaskerSettings settings) { + long thresholdValue = prefs.getLong(scoped(TaskerConstants.ACTIVITY_THRESHOLD), 0L); + if (thresholdValue != 0L) { + settings.getThreshold().set(prefs.getLong(scoped(TaskerConstants.ACTIVITY_THRESHOLD), 50L)); + } + } + private void initTasks(final TaskerSettings settings, final PreferenceScreen tasks) { ButtonPreference addTaskButton = (ButtonPreference) findPreference(TaskerConstants.ACTIVITY_TASK_ADD); - final EditTextPreference taskNamePreference = (EditTextPreference) findPreference(TaskerConstants.ACTIVITY_TASK); + final EditTextPreference taskNamePreference = (EditTextPreference) findPreference(scoped(TaskerConstants.ACTIVITY_TASK)); + taskPreferences.add(taskNamePreference); addTaskButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { - if (prefs.getBoolean(TaskerConstants.ACTIVITY_THESHOLD_ENABELD, false)) { + if (prefs.getBoolean(scoped(TaskerConstants.ACTIVITY_THRESHOLD_ENABLED), false)) { tasks.addPreference(task(tasks, taskNamePreference)); } } @@ -80,10 +122,12 @@ public class TaskerEventActivity extends AbstractSettingsActivity { TaskerTaskProvider taskerTaskProvider = new TaskerTaskProvider() { @Override public String getTask(TaskerEvent event) { - for (int i = 1; i < tasks.getPreferenceCount(); i++) { - if (event.getCount() == i - 1) { - return ((EditTextPreference) tasks.getPreference(i)).getText(); + if (event.getCount() < taskPreferences.size()) { + String text = taskPreferences.get(event.getCount()).getText(); + if (StringUtils.isEmpty(text)) { + throw new NoTaskDefinedException(); } + return text; } return null; } @@ -94,17 +138,18 @@ public class TaskerEventActivity extends AbstractSettingsActivity { private Preference task(final PreferenceScreen tasks, Preference build) { final ButtonPreference task = new ButtonPreference(this); - task.setKey(TaskerConstants.ACTIVITY_TASK + "_" + tasks.getPreferenceCount()); + task.setKey(scoped(TaskerConstants.ACTIVITY_TASK) + "_" + tasks.getPreferenceCount()); task.setTitle(build.getTitle()); task.setSummary(build.getSummary()); task.setButtonText(R.string.tasker_remove); - task.setWidgetLayoutResource(R.layout.tasker_add_button); + task.setWidgetLayoutResource(R.layout.button_preference_layout); task.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { tasks.removePreference(task); } }); + taskPreferences.add(task); return task; } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/tasker/settings/activities/TaskerEventsActivity.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/tasker/settings/activities/TaskerEventsActivity.java index 704dda355..302b1f908 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/tasker/settings/activities/TaskerEventsActivity.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/tasker/settings/activities/TaskerEventsActivity.java @@ -8,11 +8,17 @@ import android.preference.PreferenceCategory; import nodomain.freeyourgadget.gadgetbridge.R; import nodomain.freeyourgadget.gadgetbridge.activities.AbstractSettingsActivity; import nodomain.freeyourgadget.gadgetbridge.tasker.event.TaskerEventType; -import nodomain.freeyourgadget.gadgetbridge.tasker.service.TaskerConstants; +import nodomain.freeyourgadget.gadgetbridge.tasker.plugin.TaskerConstants; +import nodomain.freeyourgadget.gadgetbridge.tasker.plugin.TaskerDevice; +/** + * Tasker events {@link AbstractSettingsActivity}. Lists supported {@link TaskerEventType}'s for the specific {@link TaskerDevice} + *

+ * Forwards to {@link TaskerEventActivity}. + */ public class TaskerEventsActivity extends AbstractSettingsActivity { - private TaskerConstants.TaskerDevice device; + private TaskerDevice device; public TaskerEventsActivity() { } @@ -21,8 +27,8 @@ public class TaskerEventsActivity extends AbstractSettingsActivity { protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); addPreferencesFromResource(R.xml.tasker_events_preferences); - device = (TaskerConstants.TaskerDevice) getIntent().getSerializableExtra(TaskerConstants.DEVICE_INTENT); - PreferenceCategory category = (PreferenceCategory) findPreference(TaskerConstants.PREF_EVENT_GROUP); + device = (TaskerDevice) getIntent().getSerializableExtra(TaskerConstants.INTENT_DEVICE); + PreferenceCategory category = (PreferenceCategory) findPreference(TaskerConstants.ACTIVITY_EVENT_GROUP); for (final TaskerEventType eventType : device.getSpec().getSupportedTypes()) { Preference preference = new Preference(this); preference.setTitle(eventType.getLocalization()); @@ -30,8 +36,8 @@ public class TaskerEventsActivity extends AbstractSettingsActivity { @Override public boolean onPreferenceClick(Preference preference) { Intent intent = new Intent(TaskerEventsActivity.this, TaskerEventActivity.class); - intent.putExtra(TaskerConstants.EVENT_INTENT, eventType); - intent.putExtra(TaskerConstants.DEVICE_INTENT, device); + intent.putExtra(TaskerConstants.INTENT_EVENT, eventType); + intent.putExtra(TaskerConstants.INTENT_DEVICE, device); startActivity(intent); return true; } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/tasker/service/AbstractTaskerSpec.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/tasker/spec/AbstractTaskerSpec.java similarity index 81% rename from app/src/main/java/nodomain/freeyourgadget/gadgetbridge/tasker/service/AbstractTaskerSpec.java rename to app/src/main/java/nodomain/freeyourgadget/gadgetbridge/tasker/spec/AbstractTaskerSpec.java index bdc7c1239..e7adf16a9 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/tasker/service/AbstractTaskerSpec.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/tasker/spec/AbstractTaskerSpec.java @@ -1,18 +1,21 @@ -package nodomain.freeyourgadget.gadgetbridge.tasker.service; - -import android.content.Context; -import android.content.SharedPreferences; -import android.preference.PreferenceManager; +package nodomain.freeyourgadget.gadgetbridge.tasker.spec; import java.util.HashMap; import java.util.Map; -import nodomain.freeyourgadget.gadgetbridge.tasker.event.SettingSupplier; -import nodomain.freeyourgadget.gadgetbridge.tasker.event.SettingSupplierImpl; +import nodomain.freeyourgadget.gadgetbridge.tasker.settings.SettingSupplier; +import nodomain.freeyourgadget.gadgetbridge.tasker.settings.SettingSupplierImpl; import nodomain.freeyourgadget.gadgetbridge.tasker.event.TaskerEventType; import nodomain.freeyourgadget.gadgetbridge.tasker.settings.TaskerSettings; import nodomain.freeyourgadget.gadgetbridge.tasker.task.TaskerTaskProvider; +/** + * Abstract implementation that supplies a {@link TaskerSettings} object to gather user configuration + * via {@link nodomain.freeyourgadget.gadgetbridge.tasker.settings.activities.TaskerEventsActivity}. + *

+ * Its recommended to use this implementation so you don't have to take care of user configurations yourself. + * Always provides a non null {@link TaskerSettings} object regardless of the {@link TaskerEventType}. + */ public abstract class AbstractTaskerSpec implements TaskerSpec { private Map settings = new HashMap<>(); diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/tasker/service/TaskerSpec.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/tasker/spec/TaskerSpec.java similarity index 60% rename from app/src/main/java/nodomain/freeyourgadget/gadgetbridge/tasker/service/TaskerSpec.java rename to app/src/main/java/nodomain/freeyourgadget/gadgetbridge/tasker/spec/TaskerSpec.java index eee05c2da..f1c540a5d 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/tasker/service/TaskerSpec.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/tasker/spec/TaskerSpec.java @@ -1,4 +1,4 @@ -package nodomain.freeyourgadget.gadgetbridge.tasker.service; +package nodomain.freeyourgadget.gadgetbridge.tasker.spec; import android.bluetooth.BluetoothGatt; import android.bluetooth.BluetoothGattCharacteristic; @@ -6,8 +6,14 @@ import android.bluetooth.BluetoothGattCharacteristic; import java.util.List; import nodomain.freeyourgadget.gadgetbridge.tasker.event.TaskerEventType; +import nodomain.freeyourgadget.gadgetbridge.tasker.plugin.TaskerConstants; import nodomain.freeyourgadget.gadgetbridge.tasker.settings.TaskerSettings; +/** + * Tasker specification for a {@link TaskerConstants.TaskerDevice}. + *

+ * First and only thing to do if you want to support more {@link nodomain.freeyourgadget.gadgetbridge.impl.GBDevice}. + */ public interface TaskerSpec { TaskerEventType getEventType(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic); diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/tasker/task/TaskerTask.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/tasker/task/TaskerTask.java index d1eb8bdbf..fe9da7921 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/tasker/task/TaskerTask.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/tasker/task/TaskerTask.java @@ -2,14 +2,22 @@ package nodomain.freeyourgadget.gadgetbridge.tasker.task; import java.util.concurrent.Future; import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ScheduledFuture; import java.util.concurrent.TimeUnit; import nodomain.freeyourgadget.gadgetbridge.GBApplication; -import nodomain.freeyourgadget.gadgetbridge.tasker.service.TaskerIntent; +import nodomain.freeyourgadget.gadgetbridge.tasker.plugin.TaskerIntent; +import nodomain.freeyourgadget.gadgetbridge.tasker.service.NoTaskDefinedException; import nodomain.freeyourgadget.gadgetbridge.tasker.service.TaskerService; import nodomain.freeyourgadget.gadgetbridge.tasker.event.TaskerEvent; import nodomain.freeyourgadget.gadgetbridge.tasker.event.TaskerEventType; +import nodomain.freeyourgadget.gadgetbridge.tasker.service.TaskerUtil; +/** + * Tasker task used by {@link TaskerService} to run a scheduled asynchronous task. + *

+ * Uses {@link ScheduledExecutorService} with {@link Future} for scheduling. + */ public class TaskerTask implements Runnable { private Future task; @@ -39,10 +47,14 @@ public class TaskerTask implements Runnable { @Override public void run() { - if (TaskerService.ready()) { - if (task != null) { - GBApplication.getContext().sendBroadcast(new TaskerIntent(provider.getTask(new TaskerEvent(type, count)))); + try { + if (TaskerService.isReady()) { + if (task != null) { + GBApplication.getContext().sendBroadcast(new TaskerIntent(provider.getTask(new TaskerEvent(type, count)))); + } } + } catch (NoTaskDefinedException e) { + TaskerUtil.noTaskDefinedInformation(); } } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/tasker/task/TaskerTaskProvider.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/tasker/task/TaskerTaskProvider.java index 66afa128e..525fb0b33 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/tasker/task/TaskerTaskProvider.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/tasker/task/TaskerTaskProvider.java @@ -2,8 +2,17 @@ package nodomain.freeyourgadget.gadgetbridge.tasker.task; import nodomain.freeyourgadget.gadgetbridge.tasker.event.TaskerEvent; +/** + * Tasker task provider provides task names {@link TaskerEvent} based. + */ public interface TaskerTaskProvider { + /** + * Task name for specific {@link TaskerEvent} + * + * @param event + * @return Task name + */ String getTask(TaskerEvent event); } diff --git a/app/src/main/res/layout/tasker_add_button.xml b/app/src/main/res/layout/button_preference_layout.xml similarity index 100% rename from app/src/main/res/layout/tasker_add_button.xml rename to app/src/main/res/layout/button_preference_layout.xml diff --git a/app/src/main/res/layout/tasker_remove_button.xml b/app/src/main/res/layout/tasker_remove_button.xml deleted file mode 100644 index 2d5e79188..000000000 --- a/app/src/main/res/layout/tasker_remove_button.xml +++ /dev/null @@ -1,14 +0,0 @@ - - - - - \ No newline at end of file diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index 1a00dc6ae..a1ac049b2 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -625,14 +625,26 @@ Sprach- und Gebietseinstellungen - Tasker - Aktiv - Aktiviert Tasker aber deaktiviert die Steuerung der Medien - Task für einzelnes drücken - Task für doppeltes drücken - Task für dreifaches drücken + Aktiviert + Aktiviert die Tasker-Unterstützung + Hinzufügen + Entfernen + Ereignisse + Knopfdruck-Ereignis + Verbindungs-Ereignis + Daten-Ereignis + Ereignistyp aktiviert + Schwellenwert aktiviert + Aktiviert eine Verzögerung zwischen den Aufgaben + Schwellenwert in Millisekunden + Verzögerung zwischen den Aufrufen der Aufgaben. Z.B. für Schwellenwert 1000: Doppelter Knopfdruck innerhalb einer Sekunde ruft die Aufgabe an zweiter Stelle auf. + Aufgabe + Fügt eine Weitere Schwellwert-Aufgahinzube + Aufgabenname + Tasker ist eine Applikation für Android die Aufgaben (Ein Set von Aktionen) + anhand eines Kontexts (Applikation, Zeit, Datum, Ort, Ereignis, Geste) über benutzerdefinierte + Profile oder klickbare oder zeitgesteuerte Widgets ausfürt. + Tasker ist aktiviert aber es wurde keine Aufgabe angegeben! Bitte gehen sie in die Tasker Einstellungen und definieren sie Aufgaben. - - XWatch Einstellungen diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 6aa624374..cd7ddbd78 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -677,9 +677,11 @@ Enables Tasker support Add Remove + Events Button Events Connection Events Data Events + Enable event type Enable threshold Enables delay between task Threshold in milliseconds @@ -691,7 +693,4 @@ (application, time, date, location, event, gesture) in user-defined profiles or in clickable or timer home screen widgets. No task defined! Please define a task in settings. - - XWatch settings - \ No newline at end of file diff --git a/app/src/main/res/xml/preferences.xml b/app/src/main/res/xml/preferences.xml index 080d5929d..8ae010ead 100644 --- a/app/src/main/res/xml/preferences.xml +++ b/app/src/main/res/xml/preferences.xml @@ -746,7 +746,7 @@ diff --git a/app/src/main/res/xml/tasker_event_preferences.xml b/app/src/main/res/xml/tasker_event_preferences.xml index 03290a80b..3b573a1b1 100644 --- a/app/src/main/res/xml/tasker_event_preferences.xml +++ b/app/src/main/res/xml/tasker_event_preferences.xml @@ -1,26 +1,21 @@ - - - - - - + + + + diff --git a/app/src/main/res/xml/tasker_events_preferences.xml b/app/src/main/res/xml/tasker_events_preferences.xml index c84939d22..e87f236ea 100644 --- a/app/src/main/res/xml/tasker_events_preferences.xml +++ b/app/src/main/res/xml/tasker_events_preferences.xml @@ -1,5 +1,6 @@ - - + \ No newline at end of file diff --git a/app/src/main/res/xml/tasker_preferences.xml b/app/src/main/res/xml/tasker_preferences.xml index 2c7f6b87e..971d4ca25 100644 --- a/app/src/main/res/xml/tasker_preferences.xml +++ b/app/src/main/res/xml/tasker_preferences.xml @@ -1,13 +1,13 @@ - +