From b78239e7be4038bc639d90740fd1bc9627e794d3 Mon Sep 17 00:00:00 2001 From: Andreas Shimokawa Date: Wed, 11 Dec 2019 22:11:52 +0100 Subject: [PATCH] Fossil Q: Remove tasker code and dependency --- app/build.gradle | 5 - app/src/main/AndroidManifest.xml | 20 - .../devices/qhybrid/TaskerPlugin.java | 1017 ----------------- .../devices/qhybrid/TaskerPluginActivity.java | 109 -- .../devices/qhybrid/TaskerPluginReceiver.java | 51 - .../res/layout/activity_tasker_plugin.xml | 41 - app/src/main/res/values/strings.xml | 1 - 7 files changed, 1244 deletions(-) delete mode 100644 app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/qhybrid/TaskerPlugin.java delete mode 100644 app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/qhybrid/TaskerPluginActivity.java delete mode 100644 app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/qhybrid/TaskerPluginReceiver.java delete mode 100644 app/src/main/res/layout/activity_tasker_plugin.xml diff --git a/app/build.gradle b/app/build.gradle index 8b7abe2e0..893e36c2a 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -85,11 +85,6 @@ dependencies { implementation "net.e175.klaus:solarpositioning:0.0.9" // use pristine greendao instead of our custom version, since our custom jitpack-packaged // version contains way too much and our custom patches are in the generator only. - - implementation 'com.twofortyfouram:android-plugin-client-sdk-for-locale:[4.0.3, 5.0[' - implementation 'com.twofortyfouram:android-plugin-host-sdk-for-locale:[2.0.3,3.0[' - implementation 'com.twofortyfouram:android-plugin-api-for-locale:[1.0.2,2.0[' - implementation "org.greenrobot:greendao:2.2.1" implementation "org.apache.commons:commons-lang3:3.7" implementation "org.cyanogenmod:platform.sdk:6.0" diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index e7585523d..995a10efd 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -505,26 +505,6 @@ - - - - - - - - - - - - - diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/qhybrid/TaskerPlugin.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/qhybrid/TaskerPlugin.java deleted file mode 100644 index 4c53e875b..000000000 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/qhybrid/TaskerPlugin.java +++ /dev/null @@ -1,1017 +0,0 @@ -/* Copyright (C) 2019 Daniel Dakhno - - This file is part of Gadgetbridge. - - Gadgetbridge is free software: you can redistribute it and/or modify - it under the terms of the GNU Affero General Public License as published - by the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Gadgetbridge 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 Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License - along with this program. If not, see . */ -package nodomain.freeyourgadget.gadgetbridge.devices.qhybrid; - - -// Constants and functions for Tasker *extensions* to the plugin protocol -// See Also: http://tasker.dinglisch.net/plugins.html - -// Release Notes - -// v1.1 20140202 -// added function variableNameValid() -// fixed some javadoc entries (thanks to David Stone) - -// v1.2 20140211 -// added ACTION_EDIT_EVENT - -// v1.3 20140227 -// added REQUESTED_TIMEOUT_MS_NONE, REQUESTED_TIMEOUT_MS_MAX and REQUESTED_TIMEOUT_MS_NEVER -// requestTimeoutMS(): added range check - -// v1.4 20140516 -// support for data pass through in REQUEST_QUERY intent -// some javadoc entries fixed (thanks again David :-)) - -// v1.5 20141120 -// added RESULT_CODE_FAILED_PLUGIN_FIRST -// added Setting.VARNAME_ERROR_MESSAGE - -// v1.6 20150213 -// added Setting.getHintTimeoutMS() -// added Host.addHintTimeoutMS() - -// v1.7 20160619 -// null check for getCallingActivity() in hostSupportsOnFireVariableReplacement( Activity editActivity ) - -// v1.8 20161002 -// added hostSupportsKeyEncoding(), setKeyEncoding() and Host.getKeysWithEncoding() - -import java.net.URISyntaxException; -import java.security.SecureRandom; -import java.util.regex.Pattern; - -import android.app.Activity; -import android.content.ComponentName; -import android.content.Context; -import android.content.Intent; -import android.content.pm.PackageInfo; -import android.content.pm.PackageManager; -import android.net.Uri; -import android.os.Bundle; -import android.util.Log; - -public class TaskerPlugin { - - private final static String TAG = "TaskerPlugin"; - - private final static String BASE_KEY = "net.dinglisch.android.tasker"; - - private final static String EXTRAS_PREFIX = BASE_KEY + ".extras."; - - private final static int FIRST_ON_FIRE_VARIABLES_TASKER_VERSION = 80; - - public final static String VARIABLE_PREFIX = "%"; - - // when generating non-repeating integers, look this far back for repeats - // see getPositiveNonRepeatingRandomInteger() - private final static int RANDOM_HISTORY_SIZE = 100; - - /** - * Action that the EditActivity for an event plugin should be launched by - */ - public final static String ACTION_EDIT_EVENT = BASE_KEY + ".ACTION_EDIT_EVENT"; - - private final static String VARIABLE_NAME_START_EXPRESSION = "[\\w&&[^_]]"; - private final static String VARIABLE_NAME_MID_EXPRESSION = "[\\w0-9]+"; - private final static String VARIABLE_NAME_END_EXPRESSION = "[\\w0-9&&[^_]]"; - - public final static String VARIABLE_NAME_MAIN_PART_MATCH_EXPRESSION = - VARIABLE_NAME_START_EXPRESSION + VARIABLE_NAME_MID_EXPRESSION + VARIABLE_NAME_END_EXPRESSION - ; - - public final static String VARIABLE_NAME_MATCH_EXPRESSION = - VARIABLE_PREFIX + "+" + - VARIABLE_NAME_MAIN_PART_MATCH_EXPRESSION - ; - - private static Pattern VARIABLE_NAME_MATCH_PATTERN = null; - - /** - * @see #addVariableBundle(Bundle, Bundle) - * @see Host#getVariablesBundle(Bundle) - */ - private final static String EXTRA_VARIABLES_BUNDLE = EXTRAS_PREFIX + "VARIABLES"; - - /** - * Host capabilities, passed to plugin with edit intents - */ - private final static String EXTRA_HOST_CAPABILITIES = EXTRAS_PREFIX + "HOST_CAPABILITIES"; - - /** - * @see Setting#hostSupportsVariableReturn(Bundle) - */ - public final static int EXTRA_HOST_CAPABILITY_SETTING_RETURN_VARIABLES = 2; - - /** - * @see Condition#hostSupportsVariableReturn(Bundle) - */ - public final static int EXTRA_HOST_CAPABILITY_CONDITION_RETURN_VARIABLES = 4; - - /** - * @see Setting#hostSupportsOnFireVariableReplacement(Bundle) - */ - public final static int EXTRA_HOST_CAPABILITY_SETTING_FIRE_VARIABLE_REPLACEMENT = 8; - - /** - * @see Setting#hostSupportsVariableReturn(Bundle) - */ - private final static int EXTRA_HOST_CAPABILITY_RELEVANT_VARIABLES = 16; - - public final static int EXTRA_HOST_CAPABILITY_SETTING_SYNCHRONOUS_EXECUTION = 32; - - public final static int EXTRA_HOST_CAPABILITY_REQUEST_QUERY_DATA_PASS_THROUGH = 64; - - public final static int EXTRA_HOST_CAPABILITY_ENCODING_JSON = 128; - - public final static int EXTRA_HOST_CAPABILITY_ALL = - EXTRA_HOST_CAPABILITY_SETTING_RETURN_VARIABLES | - EXTRA_HOST_CAPABILITY_CONDITION_RETURN_VARIABLES | - EXTRA_HOST_CAPABILITY_SETTING_FIRE_VARIABLE_REPLACEMENT | - EXTRA_HOST_CAPABILITY_RELEVANT_VARIABLES| - EXTRA_HOST_CAPABILITY_SETTING_SYNCHRONOUS_EXECUTION | - EXTRA_HOST_CAPABILITY_REQUEST_QUERY_DATA_PASS_THROUGH | - EXTRA_HOST_CAPABILITY_ENCODING_JSON - ; - - /** - * Possible encodings of text in bundle values - * - * @see #setKeyEncoding(Bundle,String[],Encoding) - */ - public enum Encoding { JSON }; - - private final static String BUNDLE_KEY_ENCODING_JSON_KEYS = BASE_KEY + ".JSON_ENCODED_KEYS"; - - public static boolean hostSupportsKeyEncoding( Bundle extrasFromHost, Encoding encoding ) { - switch ( encoding ) { - case JSON: - return hostSupports( extrasFromHost, EXTRA_HOST_CAPABILITY_ENCODING_JSON ); - default: - return false; - } - } - - /** - * - * Miscellaneous operational hints going one way or the other - * @see Setting#hostSupportsVariableReturn(Bundle) - */ - - private final static String EXTRA_HINTS_BUNDLE = EXTRAS_PREFIX + "HINTS"; - - private final static String BUNDLE_KEY_HINT_PREFIX = ".hints."; - - private final static String BUNDLE_KEY_HINT_TIMEOUT_MS = BUNDLE_KEY_HINT_PREFIX + "TIMEOUT"; - - /** - * - * @see #hostSupportsRelevantVariables(Bundle) - * @see #addRelevantVariableList(Intent, String[]) - * @see #getRelevantVariableList(Bundle) - */ - private final static String BUNDLE_KEY_RELEVANT_VARIABLES = BASE_KEY + ".RELEVANT_VARIABLES"; - - public static boolean hostSupportsRelevantVariables( Bundle extrasFromHost ) { - return hostSupports( extrasFromHost, EXTRA_HOST_CAPABILITY_RELEVANT_VARIABLES ); - } - - /** - * Specifies to host which variables might be used by the plugin. - * - * Used in EditActivity, before setResult(). - * - * @param intentToHost the intent being returned to the host - * @param variableNames array of relevant variable names - */ - public static void addRelevantVariableList( Intent intentToHost, String [] variableNames ) { - intentToHost.putExtra( BUNDLE_KEY_RELEVANT_VARIABLES, variableNames ); - } - - /** - * Validate a variable name. - * - * The basic requirement for variables from a plugin is that they must be all lower-case. - * - * @param varName name to check - */ - public static boolean variableNameValid( String varName ) { - - boolean validFlag = false; - - if ( varName == null ) - Log.d( TAG, "variableNameValid: null name" ); - else { - if ( VARIABLE_NAME_MATCH_PATTERN == null ) - VARIABLE_NAME_MATCH_PATTERN = Pattern.compile( VARIABLE_NAME_MATCH_EXPRESSION, 0 ); - - if ( VARIABLE_NAME_MATCH_PATTERN.matcher( varName ).matches() ) { - - if ( variableNameIsLocal( varName ) ) - validFlag = true; - else - Log.d( TAG, "variableNameValid: name not local: " + varName ); - } - else - Log.d( TAG, "variableNameValid: invalid name: " + varName ); - } - - return validFlag; - } - - /** - * Allows the plugin/host to indicate to each other a set of variables which they are referencing. - * The host may use this to e.g. show a variable selection list in it's UI. - * The host should use this if it previously indicated to the plugin that it supports relevant vars - * - * @param fromHostIntentExtras usually from getIntent().getExtras() - * @return variableNames an array of relevant variable names - */ - public static String [] getRelevantVariableList( Bundle fromHostIntentExtras ) { - - String [] relevantVars = (String []) getBundleValueSafe( fromHostIntentExtras, BUNDLE_KEY_RELEVANT_VARIABLES, String [].class, "getRelevantVariableList" ); - - if ( relevantVars == null ) - relevantVars = new String [0]; - - return relevantVars; - } - - /** - * Used by: plugin QueryReceiver, FireReceiver - * - * Add a bundle of variable name/value pairs. - * - * Names must be valid Tasker local variable names. - * Values must be String, String [] or ArrayList - * Null values cause deletion of possible already-existing variables - * A null value where the variable does not already exist results in attempted deletion - * of any existing array indices (%arr1, %arr2 etc) - * - * @param resultExtras the result extras from the receiver onReceive (from a call to getResultExtras()) - * @param variables the variables to send - * @see Setting#hostSupportsVariableReturn(Bundle) - * @see #variableNameValid(String) - */ - public static void addVariableBundle( Bundle resultExtras, Bundle variables ) { - resultExtras.putBundle( EXTRA_VARIABLES_BUNDLE, variables ); - } - - /** - * Used by: plugin EditActivity - * - * Specify the encoding for a set of bundle keys. - * - * This is completely optional and currently only necessary if using Setting#setVariableReplaceKeys - * where the corresponding values of some of the keys specified are JSON encoded. - * - * @param resultBundleToHost the bundle being returned to the host - * @param keys the keys being returned to the host which are encoded in some way - * @param encoding the encoding of the values corresponding to the specified keys - * @see #setVariableReplaceKeys(Bundle,String[]) - * @see #hostSupportsKeyEncoding(Bundle, Encoding) - */ - public static void setKeyEncoding( Bundle resultBundleToHost, String [] keys, Encoding encoding ) { - if ( Encoding.JSON.equals( encoding ) ) - addStringArrayToBundleAsString( - keys, resultBundleToHost, BUNDLE_KEY_ENCODING_JSON_KEYS, "setValueEncoding" - ); - else - Log.e( TAG, "unknown encoding: " + encoding ); - } - - // ----------------------------- SETTING PLUGIN ONLY --------------------------------- // - - public static class Setting { - - /** - * Variable name into which a description of any error that occurred can be placed - * for the user to process. - * - * Should *only* be set when the BroadcastReceiver result code indicates a failure. - * - * Note that the user needs to have configured the task to continue after failure of the plugin - * action otherwise they will not be able to make use of the error message. - * - * For use with #addRelevantVariableList(Intent, String[]) and #addVariableBundle(Bundle, Bundle) - * - */ - public final static String VARNAME_ERROR_MESSAGE = VARIABLE_PREFIX + "errmsg"; - - /** - * @see #setVariableReplaceKeys(Bundle, String[]) - */ - private final static String BUNDLE_KEY_VARIABLE_REPLACE_STRINGS = EXTRAS_PREFIX + "VARIABLE_REPLACE_KEYS"; - - /** - * @see #requestTimeoutMS(android.content.Intent, int) - */ - private final static String EXTRA_REQUESTED_TIMEOUT = EXTRAS_PREFIX + "REQUESTED_TIMEOUT"; - - /** - * @see #requestTimeoutMS(android.content.Intent, int) - */ - - public final static int REQUESTED_TIMEOUT_MS_NONE = 0; - - /** - * @see #requestTimeoutMS(android.content.Intent, int) - */ - - public final static int REQUESTED_TIMEOUT_MS_MAX = 3599000; - - /** - * @see #requestTimeoutMS(android.content.Intent, int) - */ - - public final static int REQUESTED_TIMEOUT_MS_NEVER = REQUESTED_TIMEOUT_MS_MAX + 1000; - - /** - * @see #signalFinish(Context, Intent, int, Bundle) - * @see Host#addCompletionIntent(Intent, Intent) - */ - private final static String EXTRA_PLUGIN_COMPLETION_INTENT = EXTRAS_PREFIX + "COMPLETION_INTENT"; - - /** - * @see #signalFinish(Context, Intent, int, Bundle) - * @see Host#getSettingResultCode(Intent) - */ - public final static String EXTRA_RESULT_CODE = EXTRAS_PREFIX + "RESULT_CODE"; - - /** - * @see #signalFinish(Context, Intent, int, Bundle) - * @see Host#getSettingResultCode(Intent) - */ - - public final static int RESULT_CODE_OK = Activity.RESULT_OK; - public final static int RESULT_CODE_OK_MINOR_FAILURES = Activity.RESULT_FIRST_USER; - public final static int RESULT_CODE_FAILED = Activity.RESULT_FIRST_USER + 1; - public final static int RESULT_CODE_PENDING = Activity.RESULT_FIRST_USER + 2; - public final static int RESULT_CODE_UNKNOWN = Activity.RESULT_FIRST_USER + 3; - - /** - * If a plugin wants to define it's own error codes, start numbering them here. - * The code will be placed in an error variable (%err in the case of Tasker) for - * the user to process after the plugin action. - */ - - public final static int RESULT_CODE_FAILED_PLUGIN_FIRST = Activity.RESULT_FIRST_USER + 9; - - /** - * Used by: plugin EditActivity. - * - * Indicates to plugin that host will replace variables in specified bundle keys. - * - * Replacement takes place every time the setting is fired, before the bundle is - * passed to the plugin FireReceiver. - * - * @param extrasFromHost intent extras from the intent received by the edit activity - * @see #setVariableReplaceKeys(Bundle, String[]) - */ - public static boolean hostSupportsOnFireVariableReplacement( Bundle extrasFromHost ) { - return hostSupports( extrasFromHost, EXTRA_HOST_CAPABILITY_SETTING_FIRE_VARIABLE_REPLACEMENT ); - } - - /** - * Used by: plugin EditActivity. - * - * Description as above. - * - * This version also includes backwards compatibility with pre 4.2 Tasker versions. - * At some point this function will be deprecated. - * - * @param editActivity the plugin edit activity, needed to test calling Tasker version - * @see #setVariableReplaceKeys(Bundle, String[]) - */ - - public static boolean hostSupportsOnFireVariableReplacement( Activity editActivity ) { - - boolean supportedFlag = hostSupportsOnFireVariableReplacement( editActivity.getIntent().getExtras() ); - - if ( ! supportedFlag ) { - - ComponentName callingActivity = editActivity.getCallingActivity(); - - if ( callingActivity == null ) - Log.w( TAG, "hostSupportsOnFireVariableReplacement: null callingActivity, defaulting to false" ); - else { - String callerPackage = callingActivity.getPackageName(); - - // Tasker only supporteed this from 1.0.10 - supportedFlag = - ( callerPackage.startsWith( BASE_KEY ) ) && - ( getPackageVersionCode( editActivity.getPackageManager(), callerPackage ) > FIRST_ON_FIRE_VARIABLES_TASKER_VERSION ) - ; - } - } - - return supportedFlag; - } - - public static boolean hostSupportsSynchronousExecution( Bundle extrasFromHost ) { - return hostSupports( extrasFromHost, EXTRA_HOST_CAPABILITY_SETTING_SYNCHRONOUS_EXECUTION ); - } - - /** - * Request the host to wait the specified number of milliseconds before continuing. - * Note that the host may choose to ignore the request. - * - * Maximum value is REQUESTED_TIMEOUT_MS_MAX. - * Also available are REQUESTED_TIMEOUT_MS_NONE (continue immediately without waiting - * for the plugin to finish) and REQUESTED_TIMEOUT_MS_NEVER (wait forever for - * a result). - * - * Used in EditActivity, before setResult(). - * - * @param intentToHost the intent being returned to the host - * @param timeoutMS - */ - public static void requestTimeoutMS( Intent intentToHost, int timeoutMS ) { - if ( timeoutMS < 0 ) - Log.w( TAG, "requestTimeoutMS: ignoring negative timeout (" + timeoutMS + ")" ); - else { - if ( - ( timeoutMS > REQUESTED_TIMEOUT_MS_MAX ) && - ( timeoutMS != REQUESTED_TIMEOUT_MS_NEVER ) - ) { - Log.w( TAG, "requestTimeoutMS: requested timeout " + timeoutMS + " exceeds maximum, setting to max (" + REQUESTED_TIMEOUT_MS_MAX + ")" ); - timeoutMS = REQUESTED_TIMEOUT_MS_MAX; - } - intentToHost.putExtra( EXTRA_REQUESTED_TIMEOUT, timeoutMS ); - } - } - - /** - * Used by: plugin EditActivity - * - * Indicates to host which bundle keys should be replaced. - * - * @param resultBundleToHost the bundle being returned to the host - * @param listOfKeyNames which bundle keys to replace variables in when setting fires - * @see #hostSupportsOnFireVariableReplacement(Bundle) - * @see #setKeyEncoding(Bundle,String[],Encoding) - */ - public static void setVariableReplaceKeys( Bundle resultBundleToHost, String [] listOfKeyNames ) { - addStringArrayToBundleAsString( - listOfKeyNames, resultBundleToHost, BUNDLE_KEY_VARIABLE_REPLACE_STRINGS, - "setVariableReplaceKeys" - ); - } - - /** - * Used by: plugin FireReceiver - * - * Indicates to plugin whether the host will process variables which it passes back - * - * @param extrasFromHost intent extras from the intent received by the FireReceiver - * @see #signalFinish(Context, Intent, int, Bundle) - */ - public static boolean hostSupportsVariableReturn( Bundle extrasFromHost ) { - return hostSupports( extrasFromHost, EXTRA_HOST_CAPABILITY_SETTING_RETURN_VARIABLES ); - } - - /** - * Used by: plugin FireReceiver - * - * Tell the host that the plugin has finished execution. - * - * This should only be used if RESULT_CODE_PENDING was returned by FireReceiver.onReceive(). - * - * @param originalFireIntent the intent received from the host (via onReceive()) - * @param resultCode level of success in performing the settings - * @param vars any variables that the plugin wants to set in the host - * @see #hostSupportsSynchronousExecution(Bundle) - */ - public static boolean signalFinish( Context context, Intent originalFireIntent, int resultCode, Bundle vars ) { - - String errorPrefix = "signalFinish: "; - - boolean okFlag = false; - - String completionIntentString = (String) getExtraValueSafe( originalFireIntent, Setting.EXTRA_PLUGIN_COMPLETION_INTENT, String.class, "signalFinish" ); - - if ( completionIntentString != null ) { - - Uri completionIntentUri = null; - try { - completionIntentUri = Uri.parse( completionIntentString ); - } - // should only throw NullPointer but don't particularly trust it - catch ( Exception e ) { - Log.w( TAG, errorPrefix + "couldn't parse " + completionIntentString ); - } - - if ( completionIntentUri != null ) { - try { - Intent completionIntent = Intent.parseUri( completionIntentString, Intent.URI_INTENT_SCHEME ); - - completionIntent.putExtra( EXTRA_RESULT_CODE, resultCode ); - - if ( vars != null ) - completionIntent.putExtra( EXTRA_VARIABLES_BUNDLE, vars ); - - context.sendBroadcast( completionIntent ); - - okFlag = true; - } - catch ( URISyntaxException e ) { - Log.w( TAG, errorPrefix + "bad URI: " + completionIntentUri ); - } - } - } - - return okFlag; - } - - /** - * Check for a hint on the timeout value the host is using. - * Used by: plugin FireReceiver. - * Requires Tasker 4.7+ - * - * @param extrasFromHost intent extras from the intent received by the FireReceiver - * @return timeoutMS the hosts timeout setting for the action or -1 if no hint is available. - * - * @see #REQUESTED_TIMEOUT_MS_NONE, REQUESTED_TIMEOUT_MS_MAX, REQUESTED_TIMEOUT_MS_NEVER - */ - public static int getHintTimeoutMS( Bundle extrasFromHost ) { - - int timeoutMS = -1; - - Bundle hintsBundle = (Bundle) TaskerPlugin.getBundleValueSafe( extrasFromHost, EXTRA_HINTS_BUNDLE, Bundle.class, "getHintTimeoutMS" ); - - if ( hintsBundle != null ) { - - Integer val = (Integer) getBundleValueSafe( hintsBundle, BUNDLE_KEY_HINT_TIMEOUT_MS, Integer.class, "getHintTimeoutMS" ); - - if ( val != null ) - timeoutMS = val; - } - - return timeoutMS; - } - } - - // ----------------------------- CONDITION/EVENT PLUGIN ONLY --------------------------------- // - - public static class Condition { - - /** - * Used by: plugin QueryReceiver - * - * Indicates to plugin whether the host will process variables which it passes back - * - * @param extrasFromHost intent extras from the intent received by the QueryReceiver - * @see #addVariableBundle(Bundle, Bundle) - */ - public static boolean hostSupportsVariableReturn( Bundle extrasFromHost ) { - return hostSupports( extrasFromHost, EXTRA_HOST_CAPABILITY_CONDITION_RETURN_VARIABLES ); - } - } - - // ----------------------------- EVENT PLUGIN ONLY --------------------------------- // - - public static class Event { - - public final static String PASS_THROUGH_BUNDLE_MESSAGE_ID_KEY = BASE_KEY + ".MESSAGE_ID"; - - private final static String EXTRA_REQUEST_QUERY_PASS_THROUGH_DATA = EXTRAS_PREFIX + "PASS_THROUGH_DATA"; - - /** - * @param extrasFromHost intent extras from the intent received by the QueryReceiver - * @see #addPassThroughData(Intent, Bundle) - */ - public static boolean hostSupportsRequestQueryDataPassThrough( Bundle extrasFromHost ) { - return hostSupports( extrasFromHost, EXTRA_HOST_CAPABILITY_REQUEST_QUERY_DATA_PASS_THROUGH ); - } - - /** - * Specify a bundle of data (probably representing whatever change happened in the condition) - * which will be included in the QUERY_CONDITION broadcast sent by the host for each - * event instance of the plugin. - * - * The minimal purpose is to enable the plugin to associate a QUERY_CONDITION to the - * with the REQUEST_QUERY that caused it. - * - * Note that for security reasons it is advisable to also store a message ID with the bundle - * which can be compared to known IDs on receipt. The host cannot validate the source of - * REQUEST_QUERY intents so fake data may be passed. Replay attacks are also possible. - * addPassThroughMesssageID() can be used to add an ID if the plugin doesn't wish to add it's - * own ID to the pass through bundle. - * - * Note also that there are several situations where REQUEST_QUERY will not result in a - * QUERY_CONDITION intent (e.g. event throttling by the host), so plugin-local data - * indexed with a message ID needs to be timestamped and eventually timed-out. - * - * This function can be called multiple times, each time all keys in data will be added to - * that of previous calls. - * - * @param requestQueryIntent intent being sent to the host - * @param data the data to be passed-through - * @see #hostSupportsRequestQueryDataPassThrough(Bundle) - * @see #retrievePassThroughData(Intent) - * @see #addPassThroughMessageID - * - */ - public static void addPassThroughData( Intent requestQueryIntent, Bundle data ) { - - Bundle passThroughBundle = retrieveOrCreatePassThroughBundle( requestQueryIntent ); - - passThroughBundle.putAll( data ); - } - - /** - * Retrieve the pass through data from a QUERY_REQUEST from the host which was generated - * by a REQUEST_QUERY from the plugin. - * - * Note that if addPassThroughMessageID() was previously called, the data will contain an extra - * key TaskerPlugin.Event.PASS_THOUGH_BUNDLE_MESSAGE_ID_KEY. - * - * @param queryConditionIntent QUERY_REQUEST sent from host - * @return data previously added to the REQUEST_QUERY intent - * @see #hostSupportsRequestQueryDataPassThrough(Bundle) - * @see #addPassThroughData(Intent,Bundle) - */ - public static Bundle retrievePassThroughData( Intent queryConditionIntent ) { - return (Bundle) getExtraValueSafe( - queryConditionIntent, - EXTRA_REQUEST_QUERY_PASS_THROUGH_DATA, - Bundle.class, - "retrievePassThroughData" - ); - } - - /** - * Add a message ID to a REQUEST_QUERY intent which will then be included in the corresponding - * QUERY_CONDITION broadcast sent by the host for each event instance of the plugin. - * - * The minimal purpose is to enable the plugin to associate a QUERY_CONDITION to the - * with the REQUEST_QUERY that caused it. It also allows the message to be verified - * by the plugin to prevent e.g. replay attacks - * - * @param requestQueryIntent intent being sent to the host - * @return a guaranteed non-repeating within 100 calls message ID - * @see #hostSupportsRequestQueryDataPassThrough(Bundle) - * @see #retrievePassThroughData(Intent) - * @return an ID for the bundle so it can be identified and the caller verified when it is again received by the plugin - * - */ - public static int addPassThroughMessageID( Intent requestQueryIntent ) { - - Bundle passThroughBundle = retrieveOrCreatePassThroughBundle( requestQueryIntent ); - - int id = getPositiveNonRepeatingRandomInteger(); - - passThroughBundle.putInt( PASS_THROUGH_BUNDLE_MESSAGE_ID_KEY, id ); - - return id; - } - - /* - * Retrieve the pass through data from a QUERY_REQUEST from the host which was generated - * by a REQUEST_QUERY from the plugin. - * - * @param queryConditionIntent QUERY_REQUEST sent from host - * @return the ID which was passed through by the host, or -1 if no ID was found - * @see #hostSupportsRequestQueryDataPassThrough(Bundle) - * @see #addPassThroughData(Intent,Bundle) - */ - public static int retrievePassThroughMessageID( Intent queryConditionIntent ) { - - int toReturn = -1; - - Bundle passThroughData = Event.retrievePassThroughData( queryConditionIntent ); - - if ( passThroughData != null ) { - Integer id = (Integer) getBundleValueSafe( - passThroughData, - PASS_THROUGH_BUNDLE_MESSAGE_ID_KEY, - Integer.class, - "retrievePassThroughMessageID" - ); - - if ( id != null ) - toReturn = id; - } - - return toReturn; - } - - // internal use - private static Bundle retrieveOrCreatePassThroughBundle( Intent requestQueryIntent ) { - - Bundle passThroughBundle; - - if ( requestQueryIntent.hasExtra( EXTRA_REQUEST_QUERY_PASS_THROUGH_DATA ) ) - passThroughBundle = requestQueryIntent.getBundleExtra( EXTRA_REQUEST_QUERY_PASS_THROUGH_DATA ); - else { - passThroughBundle = new Bundle(); - requestQueryIntent.putExtra( EXTRA_REQUEST_QUERY_PASS_THROUGH_DATA, passThroughBundle ); - } - - return passThroughBundle; - } - } - // ---------------------------------- HOST ----------------------------------------- // - - public static class Host { - - /** - * Tell the plugin what capabilities the host support. This should be called when sending - * intents to any EditActivity, FireReceiver or QueryReceiver. - * - * @param toPlugin the intent we're sending - * @return capabilities one or more of the EXTRA_HOST_CAPABILITY_XXX flags - */ - public static Intent addCapabilities( Intent toPlugin, int capabilities ) { - return toPlugin.putExtra( EXTRA_HOST_CAPABILITIES, capabilities ); - } - - /** - * Add an intent to the fire intent before it goes to the plugin FireReceiver, which the plugin - * can use to signal when it is finished. Only use if @code{pluginWantsSychronousExecution} is true. - * - * @param fireIntent fire intent going to the plugin - * @param completionIntent intent which will signal the host that the plugin is finished. - * Implementation is host-dependent. - */ - public static void addCompletionIntent( Intent fireIntent, Intent completionIntent ) { - fireIntent.putExtra( - Setting.EXTRA_PLUGIN_COMPLETION_INTENT, - completionIntent.toUri( Intent.URI_INTENT_SCHEME ) - ); - } - - /** - * When a setting plugin is finished, it sends the host the intent which was passed to it - * via @code{addCompletionIntent}. - * - * @param completionIntent intent returned from the plugin when it finished. - * @return resultCode measure of plugin success, defaults to UNKNOWN - */ - public static int getSettingResultCode( Intent completionIntent ) { - - Integer val = (Integer) getExtraValueSafe( completionIntent, Setting.EXTRA_RESULT_CODE, Integer.class, "getSettingResultCode" ); - - return ( val == null ) ? Setting.RESULT_CODE_UNKNOWN : val; - } - - /** - * Extract a bundle of variables from an intent received from the FireReceiver. This - * should be called if the host previously indicated to the plugin - * that it supports setting variable return. - * - * @param resultExtras getResultExtras() from BroadcastReceiver:onReceive() - * @return variables a bundle of variable name/value pairs - * @see #addCapabilities(Intent, int) - */ - - public static Bundle getVariablesBundle( Bundle resultExtras ) { - return (Bundle) getBundleValueSafe( - resultExtras, EXTRA_VARIABLES_BUNDLE, Bundle.class, "getVariablesBundle" - ); - } - - /** - * Inform a setting plugin of the timeout value the host is using. - * - * @param toPlugin the intent we're sending - * @param timeoutMS the hosts timeout setting for the action. Note that this may differ from - * that which the plugin requests. - * @see #REQUESTED_TIMEOUT_MS_NONE, REQUESTED_TIMEOUT_MS_MAX, REQUESTED_TIMEOUT_MS_NEVER - */ - public static void addHintTimeoutMS( Intent toPlugin, int timeoutMS ) { - getHintsBundle( toPlugin, "addHintTimeoutMS" ).putInt( BUNDLE_KEY_HINT_TIMEOUT_MS, timeoutMS ); - } - - private static Bundle getHintsBundle( Intent intent, String funcName ) { - - Bundle hintsBundle = (Bundle) getExtraValueSafe( intent, EXTRA_HINTS_BUNDLE, Bundle.class, funcName ); - - if ( hintsBundle == null ) { - hintsBundle = new Bundle(); - intent.putExtra( EXTRA_HINTS_BUNDLE, hintsBundle ); - } - - return hintsBundle; - } - - public static boolean haveRequestedTimeout( Bundle extrasFromPluginEditActivity ) { - return extrasFromPluginEditActivity.containsKey( Setting.EXTRA_REQUESTED_TIMEOUT ); - } - - public static int getRequestedTimeoutMS( Bundle extrasFromPluginEditActivity ) { - return - (Integer) getBundleValueSafe( - extrasFromPluginEditActivity, Setting.EXTRA_REQUESTED_TIMEOUT, Integer.class, "getRequestedTimeout" - ) - ; - } - - public static String [] getSettingVariableReplaceKeys( Bundle fromPluginEditActivity ) { - return getStringArrayFromBundleString( - fromPluginEditActivity, Setting.BUNDLE_KEY_VARIABLE_REPLACE_STRINGS, - "getSettingVariableReplaceKeys" - ); - } - - public static String [] getKeysWithEncoding( Bundle fromPluginEditActivity, Encoding encoding ) { - - String [] toReturn = null; - - if ( Encoding.JSON.equals( encoding ) ) - toReturn = getStringArrayFromBundleString( - fromPluginEditActivity, TaskerPlugin.BUNDLE_KEY_ENCODING_JSON_KEYS, - "getKeyEncoding:JSON" - ); - else - Log.w( TAG, "Host.getKeyEncoding: unknown encoding " + encoding ); - - return toReturn; - } - - public static boolean haveRelevantVariables( Bundle b ) { - return b.containsKey( BUNDLE_KEY_RELEVANT_VARIABLES ); - } - - public static void cleanRelevantVariables( Bundle b ) { - b.remove( BUNDLE_KEY_RELEVANT_VARIABLES ); - } - - public static void cleanHints( Bundle extras ) { - extras.remove( TaskerPlugin.EXTRA_HINTS_BUNDLE ); - } - - public static void cleanRequestedTimeout( Bundle extras ) { - extras.remove( Setting.EXTRA_REQUESTED_TIMEOUT ); - } - - public static void cleanSettingReplaceVariables( Bundle b ) { - b.remove( Setting.BUNDLE_KEY_VARIABLE_REPLACE_STRINGS ); - } - } - - // ---------------------------------- HELPER FUNCTIONS -------------------------------- // - - private static Object getBundleValueSafe( Bundle b, String key, Class expectedClass, String funcName ) { - Object value = null; - - if ( b != null ) { - if ( b.containsKey( key ) ) { - Object obj = b.get( key ); - if ( obj == null ) - Log.w( TAG, funcName + ": " + key + ": null value" ); - else if ( obj.getClass() != expectedClass ) - Log.w( TAG, funcName + ": " + key + ": expected " + expectedClass.getClass().getName() + ", got " + obj.getClass().getName() ); - else - value = obj; - } - } - return value; - } - - private static Object getExtraValueSafe( Intent i, String key, Class expectedClass, String funcName ) { - return ( i.hasExtra( key ) ) ? - getBundleValueSafe( i.getExtras(), key, expectedClass, funcName ) : - null; - } - - private static boolean hostSupports( Bundle extrasFromHost, int capabilityFlag ) { - Integer flags = (Integer) getBundleValueSafe( extrasFromHost, EXTRA_HOST_CAPABILITIES, Integer.class, "hostSupports" ); - return - ( flags != null ) && - ( ( flags & capabilityFlag ) > 0 ) - ; - } - - public static int getPackageVersionCode( PackageManager pm, String packageName ) { - - int code = -1; - - if ( pm != null ) { - try { - PackageInfo pi = pm.getPackageInfo( packageName, 0 ); - if ( pi != null ) - code = pi.versionCode; - } - catch ( Exception e ) { - Log.e( TAG, "getPackageVersionCode: exception getting package info" ); - } - } - - return code; - } - - private static boolean variableNameIsLocal( String varName ) { - - int digitCount = 0; - int length = varName.length(); - - for ( int x = 0; x < length; x++ ) { - char ch = varName.charAt( x ); - - if ( Character.isUpperCase( ch ) ) - return false; - else if ( Character.isDigit( ch ) ) - digitCount++; - } - - if ( digitCount == ( varName.length() - 1 ) ) - return false; - - return true; - } - - private static String [] getStringArrayFromBundleString( Bundle bundle, String key, String funcName ) { - - String spec = (String) getBundleValueSafe( bundle, key, String.class, funcName ); - - String [] toReturn = null; - - if ( spec != null ) - toReturn = spec.split( " " ); - - return toReturn; - } - - private static void addStringArrayToBundleAsString( String [] toAdd, Bundle bundle, String key, String callerName ) { - - StringBuilder builder = new StringBuilder(); - - if ( toAdd != null ) { - - for ( String keyName : toAdd ) { - - if ( keyName.contains( " " ) ) - Log.w( TAG, callerName + ": ignoring bad keyName containing space: " + keyName ); - else { - if ( builder.length() > 0 ) - builder.append( ' ' ); - - builder.append( keyName ); - } - - if ( builder.length() > 0 ) - bundle.putString( key, builder.toString() ); - } - } - } - - // state tracking for random number sequence - private static int [] lastRandomsSeen = null; - private static int randomInsertPointer = 0; - private static SecureRandom sr = null; - - /** - * Generate a sequence of secure random positive integers which is guaranteed not to repeat - * in the last 100 calls to this function. - * - * @return a random positive integer - */ - public static int getPositiveNonRepeatingRandomInteger() { - - // initialize on first call - if ( sr == null ) { - sr = new SecureRandom(); - lastRandomsSeen = new int[RANDOM_HISTORY_SIZE]; - - for ( int x = 0; x < lastRandomsSeen.length; x++ ) - lastRandomsSeen[x] = -1; - } - - int toReturn; - do { - // pick a number - toReturn = sr.nextInt( Integer.MAX_VALUE ); - - // check we havn't see it recently - for ( int seen : lastRandomsSeen ) { - if ( seen == toReturn ) { - toReturn = -1; - break; - } - } - } - while ( toReturn == -1 ); - - // update history - lastRandomsSeen[randomInsertPointer] = toReturn; - randomInsertPointer = ( randomInsertPointer + 1 ) % lastRandomsSeen.length; - - return toReturn; - } - -} diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/qhybrid/TaskerPluginActivity.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/qhybrid/TaskerPluginActivity.java deleted file mode 100644 index d3f8b8a5d..000000000 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/qhybrid/TaskerPluginActivity.java +++ /dev/null @@ -1,109 +0,0 @@ -/* Copyright (C) 2019 Daniel Dakhno - - This file is part of Gadgetbridge. - - Gadgetbridge is free software: you can redistribute it and/or modify - it under the terms of the GNU Affero General Public License as published - by the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Gadgetbridge 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 Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License - along with this program. If not, see . */ -package nodomain.freeyourgadget.gadgetbridge.devices.qhybrid; - -import android.content.Intent; -import android.os.Bundle; -import android.widget.EditText; -import android.widget.RadioButton; -import android.widget.RadioGroup; -import android.widget.TextView; - -import com.twofortyfouram.locale.sdk.client.ui.activity.AbstractPluginActivity; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import nodomain.freeyourgadget.gadgetbridge.R; -import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.misfit.PlayNotificationRequest; - -public class TaskerPluginActivity extends AbstractPluginActivity { - public static final String key_hours = "qhybrid_hours"; - public static final String key_minute = "qhybrid_minutes"; - public static final String key_vibration = "qhybrid_vibration"; - - RadioGroup group; - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.activity_tasker_plugin); - - group = findViewById(R.id.qhybrid_tasker_vibration); - for(PlayNotificationRequest.VibrationType type : PlayNotificationRequest.VibrationType.values()){ - RadioButton button = new RadioButton(this); - button.setText(type.name() + " (" + type.name() + ")"); - button.setId(type.getValue()); - group.addView(button); - } - group.check(PlayNotificationRequest.VibrationType.NO_VIBE.getValue()); - RadioButton custom = new RadioButton(this); - custom.setText("variable %vibration"); - custom.setId(10); - group.addView(custom); - - Intent intent = getIntent(); - if(intent.hasExtra(key_hours)){ - ((TextView) findViewById(R.id.qhybrid_hour_degrees)).setText(intent.getStringExtra(key_hours)); - } - if(intent.hasExtra(key_minute)){ - ((TextView) findViewById(R.id.qhybrid_minute_degrees)).setText(intent.getStringExtra(key_minute)); - } - if(intent.hasExtra(key_vibration)){ - String vibe = intent.getStringExtra(key_vibration); - if(vibe.equals("%vibration")){ - group.check(10); - }else { - group.check(Integer.parseInt(vibe)); - } - } - } - - @Override - public boolean isBundleValid(@NonNull Bundle bundle) { - return true; - } - - @Override - public void onPostCreateWithPreviousResult(@NonNull Bundle bundle, @NonNull String s) { - - } - - @Nullable - @Override - public Bundle getResultBundle() { - int vibration = group.getCheckedRadioButtonId(); - - Bundle bundle = new Bundle(); - bundle.putString(key_hours, ((EditText) findViewById(R.id.qhybrid_hour_degrees)).getText().toString()); - bundle.putString(key_minute, ((EditText) findViewById(R.id.qhybrid_minute_degrees)).getText().toString()); - - if(vibration == 10){ - bundle.putString(key_vibration, "%vibration"); - }else{ - bundle.putString(key_vibration, String.valueOf(vibration)); - } - TaskerPlugin.Setting.setVariableReplaceKeys(bundle, new String[]{key_hours, key_minute, key_vibration}); - - return bundle; - } - - @NonNull - @Override - public String getResultBlurb(@NonNull Bundle bundle) { - return "nope"; - } -} diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/qhybrid/TaskerPluginReceiver.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/qhybrid/TaskerPluginReceiver.java deleted file mode 100644 index 5d7241406..000000000 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/qhybrid/TaskerPluginReceiver.java +++ /dev/null @@ -1,51 +0,0 @@ -/* Copyright (C) 2019 Daniel Dakhno - - This file is part of Gadgetbridge. - - Gadgetbridge is free software: you can redistribute it and/or modify - it under the terms of the GNU Affero General Public License as published - by the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Gadgetbridge 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 Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License - along with this program. If not, see . */ -package nodomain.freeyourgadget.gadgetbridge.devices.qhybrid; - -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.Intent; - -import androidx.localbroadcastmanager.content.LocalBroadcastManager; -import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.QHybridSupport; -import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.misfit.PlayNotificationRequest; - -public class TaskerPluginReceiver extends BroadcastReceiver { - - @Override - public void onReceive(Context context, Intent intent) { - String min = intent.getStringExtra(TaskerPluginActivity.key_minute); - String hour = intent.getStringExtra(TaskerPluginActivity.key_hours); - String vibration = intent.getStringExtra(TaskerPluginActivity.key_vibration); - - int minDegrees = (int)Float.parseFloat(min); - int hourDegrees = (int)Float.parseFloat(hour); - - NotificationConfiguration config = new NotificationConfiguration( - (short)minDegrees, - (short)hourDegrees, - null, - null, - false, - PlayNotificationRequest.VibrationType.fromValue(Byte.parseByte(vibration)) - ); - - Intent send = new Intent(QHybridSupport.QHYBRID_COMMAND_NOTIFICATION); - send.putExtra("CONFIG", config); - LocalBroadcastManager.getInstance(context).sendBroadcast(send); - } -} diff --git a/app/src/main/res/layout/activity_tasker_plugin.xml b/app/src/main/res/layout/activity_tasker_plugin.xml deleted file mode 100644 index de35d6215..000000000 --- a/app/src/main/res/layout/activity_tasker_plugin.xml +++ /dev/null @@ -1,41 +0,0 @@ - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index a0598e541..98c5018c9 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -717,7 +717,6 @@ Calibrate Watch 9 pairing Watch 9 calibration - Play Q Hybrid notification Contextual Arabic Enable this to support contextual Arabic Right To Left Support