package com.jens.automation2; import android.bluetooth.BluetoothDevice; import android.content.Context; import android.os.Build; import android.os.Bundle; import android.service.notification.StatusBarNotification; import android.telephony.TelephonyManager; import android.util.Log; import androidx.annotation.RequiresApi; import com.jens.automation2.location.LocationProvider; import com.jens.automation2.location.WifiBroadcastReceiver; import com.jens.automation2.receivers.BatteryReceiver; import com.jens.automation2.receivers.BluetoothReceiver; import com.jens.automation2.receivers.ConnectivityReceiver; import com.jens.automation2.receivers.DeviceOrientationListener; import com.jens.automation2.receivers.HeadphoneJackListener; import com.jens.automation2.receivers.NfcReceiver; import com.jens.automation2.receivers.NoiseListener; import com.jens.automation2.receivers.NotificationListener; import com.jens.automation2.receivers.PhoneStatusListener; import com.jens.automation2.receivers.ProcessListener; import static com.jens.automation2.receivers.NotificationListener.EXTRA_TEXT; import static com.jens.automation2.receivers.NotificationListener.EXTRA_TITLE; import org.apache.commons.lang3.StringUtils; import java.sql.Time; import java.util.ArrayList; import java.util.Calendar; import java.util.Date; public class Trigger { Rule parentRule = null; Calendar lastTimeNotApplied = null; public boolean applies(Object triggeringObject, Context context) { boolean result = true; try { switch(this.getTriggerType()) { case timeFrame: if(!checkDateTime(triggeringObject, false)) result = false; break; case pointOfInterest: if(!checkLocation()) result = false; break; case charging: if(!checkCharging()) result = false; break; case usb_host_connection: if(!checkUsbHostConnection()) result = false; break; case batteryLevel: if(!checkBatteryLevel()) result = false; break; case speed: if(!checkSpeed()) result = false; break; case noiseLevel: if(!checkNoiseLevel()) result = false; break; case wifiConnection: if(!checkWifiConnection()) result = false; break; case process_started_stopped: if(!checkProcess()) result = false; break; case airplaneMode: if(!checkAirplaneMode()) result = false; break; case roaming: if(!checkRoaming()) result = false; break; case phoneCall: if(!checkPhoneCall()) result = false; break; case nfcTag: if(!checkNfc()) result = false; break; case bluetoothConnection: if(!checkBluetooth()) result = false; break; case headsetPlugged: if(!checkHeadsetPlugged()) result = false; break; case notification: if(!checkNotification()) result = false; break; case deviceOrientation: if(!checkDeviceOrientation()) result = false; break; case activityDetection: if(!getParentRule().checkActivityDetection(this)) result = false; break; default: break; } } catch(Exception e) { Miscellaneous.logEvent("e", "Trigger", "Error while checking if rule " + getParentRule().getName() + " applies." + Miscellaneous.lineSeparator + Log.getStackTraceString(e), 1); result = false; } if(!result) lastTimeNotApplied = Calendar.getInstance(); return result; } boolean checkNotification() { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { String[] params = this.getTriggerParameter2().split(triggerParameter2Split); String myApp = params[0]; String myTitleDir = params[1]; String requiredTitle = params[2]; String myTextDir = params[3]; String requiredText; if (params.length >= 5) requiredText = params[4]; else requiredText = ""; if(this.getTriggerParameter()) { // Check an active notification that is still there boolean foundMatch = false; for (StatusBarNotification sbn : NotificationListener.getInstance().getActiveNotifications()) { if(getParentRule().getLastExecution() == null || sbn.getPostTime() > this.getParentRule().getLastExecution().getTimeInMillis()) { String notificationApp = sbn.getPackageName(); String notificationTitle = null; String notificationText = null; Miscellaneous.logEvent("i", "NotificationCheck", "Checking if this notification matches our rule " + this.getParentRule().getName() + ". App: " + notificationApp + ", title: " + notificationTitle + ", text: " + notificationText, 5); if (!myApp.equals("-1")) { if (!notificationApp.equalsIgnoreCase(myApp)) { Miscellaneous.logEvent("i", "NotificationCheck", "Notification app name does not match rule.", 5); continue; } } else { if(myApp.equals(BuildConfig.APPLICATION_ID)) { return false; } } /* If there are multiple notifications ("stacked") title or text might be null: https://stackoverflow.com/questions/28047767/notificationlistenerservice-not-reading-text-of-stacked-notifications */ Bundle extras = sbn.getNotification().extras; // T I T L E if (extras.containsKey(EXTRA_TITLE)) notificationTitle = sbn.getNotification().extras.getString(EXTRA_TITLE); if (!StringUtils.isEmpty(requiredTitle)) { if (!Miscellaneous.compare(myTitleDir, requiredTitle, notificationTitle)) { Miscellaneous.logEvent("i", "NotificationCheck", "Notification title does not match rule.", 5); continue; } } else Miscellaneous.logEvent("i", "NotificationCheck", "A required title for a notification trigger was not specified.", 5); // T E X T if (extras.containsKey(EXTRA_TEXT)) notificationText = sbn.getNotification().extras.getString(EXTRA_TEXT); if (!StringUtils.isEmpty(requiredText)) { if (!Miscellaneous.compare(myTextDir, requiredText, notificationText)) { Miscellaneous.logEvent("i", "NotificationCheck", "Notification text does not match rule.", 5); continue; } } else Miscellaneous.logEvent("i", "NotificationCheck", "A required text for a notification trigger was not specified.", 5); foundMatch = true; break; } } if(!foundMatch) return false; } else { // check a notification that is gone if(NotificationListener.getLastNotification() != null) { if(!NotificationListener.getLastNotification().isCreated()) { String app = NotificationListener.getLastNotification().getApp(); String title = NotificationListener.getLastNotification().getTitle(); String text = NotificationListener.getLastNotification().getText(); if (!myApp.equals("-1")) { if (!app.equalsIgnoreCase(myApp)) return false; } else { if(myApp.equals(BuildConfig.APPLICATION_ID)) { return false; } } if (requiredTitle.length() > 0) { if (!Miscellaneous.compare(myTitleDir, title, requiredTitle)) return false; } if (requiredText.length() > 0) { if (!Miscellaneous.compare(myTextDir, text, requiredText)) return false; } } else return false; } } } return true; } boolean checkDeviceOrientation() { String deviceOrientationPieces[] = getTriggerParameter2().split(Trigger.triggerParameter2Split); float desiredAzimuth = Float.parseFloat(deviceOrientationPieces[0]); float desiredAzimuthTolerance = Float.parseFloat(deviceOrientationPieces[1]); float desiredPitch = Float.parseFloat(deviceOrientationPieces[2]); float desiredPitchTolerance = Float.parseFloat(deviceOrientationPieces[3]); float desiredRoll = Float.parseFloat(deviceOrientationPieces[4]); float desiredRollTolerance = Float.parseFloat(deviceOrientationPieces[5]); float currentAzimuth = DeviceOrientationListener.getInstance().getAzimuth(); float currentPitch = DeviceOrientationListener.getInstance().getPitch(); float currentRoll = DeviceOrientationListener.getInstance().getRoll(); if(desiredAzimuthTolerance < 180) { if ( !( Math.abs(currentAzimuth) <= Math.abs(desiredAzimuth - desiredAzimuthTolerance) || Math.abs(currentAzimuth) <= desiredAzimuth + desiredAzimuthTolerance ) ) { Miscellaneous.logEvent("i", "DeviceOrientation", "Azimuth outside of tolerance area.", 5); if (getTriggerParameter()) return false; else return true; } } if(desiredPitchTolerance < 180) { if ( !( ( Math.abs(currentPitch) <= Math.abs(desiredPitch - desiredPitchTolerance) || Math.abs(currentPitch) <= desiredPitch + desiredPitchTolerance ) ) ) { Miscellaneous.logEvent("i", "DeviceOrientation", "Pitch outside of tolerance area.", 5); if (getTriggerParameter()) return false; else return true; } } if(desiredRollTolerance < 180) { if ( !( ( Math.abs(currentRoll) <= Math.abs(desiredRoll - desiredRollTolerance) || Math.abs(currentRoll) <= desiredRoll + desiredRollTolerance ) ) ) { Miscellaneous.logEvent("i", "DeviceOrientation", "Roll outside of tolerance area.", 5); if (getTriggerParameter()) return false; else return true; } } if(getTriggerParameter()) return true; else return false; } boolean checkHeadsetPlugged() { if(HeadphoneJackListener.isHeadsetConnected() != this.getTriggerParameter()) return false; else if(this.getHeadphoneType() != 2 && this.getHeadphoneType() != HeadphoneJackListener.getHeadphoneType()) { Miscellaneous.logEvent("i", Miscellaneous.getAnyContext().getResources().getString(R.string.ruleCheckOf), String.format(Miscellaneous.getAnyContext().getResources().getString(R.string.ruleDoesntApplyWrongHeadphoneType), this.getParentRule().getName()), 3); return false; } return true; } boolean checkBluetooth() { Miscellaneous.logEvent("i", Miscellaneous.getAnyContext().getResources().getString(R.string.ruleCheckOf), String.format("Checking for bluetooth...", this.getParentRule().getName()), 4); if(this.getBluetoothDeviceAddress().equals("")) { if(this.getBluetoothEvent().equals(BluetoothDevice.ACTION_ACL_CONNECTED)) { if(BluetoothReceiver.isAnyDeviceConnected() != this.getTriggerParameter()) return false; } else if((this.getBluetoothEvent().equals(BluetoothDevice.ACTION_ACL_DISCONNECTED))) { if(BluetoothReceiver.isAnyDeviceConnected() != this.getTriggerParameter()) return false; } else { // range if(BluetoothReceiver.isAnyDeviceInRange() != this.getTriggerParameter()) return false; } } else if(this.getBluetoothDeviceAddress().equals("")) { if(this.getBluetoothEvent().equals(BluetoothDevice.ACTION_ACL_CONNECTED)) { if(BluetoothReceiver.isAnyDeviceConnected() == this.getTriggerParameter()) return false; } else if((this.getBluetoothEvent().equals(BluetoothDevice.ACTION_ACL_DISCONNECTED))) { if(BluetoothReceiver.isAnyDeviceConnected() == this.getTriggerParameter()) return false; } else { // range if(BluetoothReceiver.isAnyDeviceInRange() == this.getTriggerParameter()) return false; } } else if(this.getBluetoothDeviceAddress().length() > 0) { if(this.getBluetoothEvent().equals(BluetoothDevice.ACTION_ACL_CONNECTED)) { if(BluetoothReceiver.isDeviceCurrentlyConnected(BluetoothReceiver.getDeviceByAddress(this.getBluetoothDeviceAddress())) != this.getTriggerParameter()) return false; } else if((this.getBluetoothEvent().equals(BluetoothDevice.ACTION_ACL_DISCONNECTED))) { if(BluetoothReceiver.isDeviceCurrentlyConnected(BluetoothReceiver.getDeviceByAddress(this.getBluetoothDeviceAddress())) != this.getTriggerParameter()) return false; } else { // range if(BluetoothReceiver.isDeviceInRange(BluetoothReceiver.getDeviceByAddress(this.getBluetoothDeviceAddress())) != this.getTriggerParameter()) return false; } } else { Miscellaneous.logEvent("i", Miscellaneous.getAnyContext().getResources().getString(R.string.ruleCheckOf), String.format(Miscellaneous.getAnyContext().getResources().getString(R.string.ruleDoesntApplyStateNotCorrect), this.getParentRule().getName()), 3); return false; } return true; } boolean checkNfc() { if(NfcReceiver.lastReadLabel == null) { Miscellaneous.logEvent("i", Miscellaneous.getAnyContext().getResources().getString(R.string.ruleCheckOf), String.format(Miscellaneous.getAnyContext().getResources().getString(R.string.ruleDoesntApplyNoTagLabel), this.getParentRule().getName()),3); return false; } else if(!NfcReceiver.lastReadLabel.equals(this.getNfcTagId())) { Miscellaneous.logEvent("i", Miscellaneous.getAnyContext().getResources().getString(R.string.ruleCheckOf), String.format(Miscellaneous.getAnyContext().getResources().getString(R.string.ruleDoesntApplyWrongTagLabel) + " " + NfcReceiver.lastReadLabel + " / " + this.getNfcTagId(), this.getParentRule().getName()), 3); return false; } return true; } boolean checkPhoneCall() { String[] elements = this.getTriggerParameter2().split(triggerParameter2Split); // state dir number if(elements[2].equals(Trigger.triggerPhoneCallNumberAny) || Miscellaneous.comparePhoneNumbers(PhoneStatusListener.getLastPhoneNumber(), elements[2]) || (Miscellaneous.isRegularExpression(elements[2]) && PhoneStatusListener.getLastPhoneNumber().matches(elements[2]))) { //if(PhoneStatusListener.isInACall() == oneTrigger.getTriggerParameter()) if( (elements[0].equals(Trigger.triggerPhoneCallStateRinging) && PhoneStatusListener.getCurrentState() == TelephonyManager.CALL_STATE_RINGING) || (elements[0].equals(Trigger.triggerPhoneCallStateStarted) && PhoneStatusListener.getCurrentState() == TelephonyManager.CALL_STATE_OFFHOOK) || (elements[0].equals(Trigger.triggerPhoneCallStateStopped) && PhoneStatusListener.getCurrentState() == TelephonyManager.CALL_STATE_IDLE) ) { if( elements[1].equals(Trigger.triggerPhoneCallDirectionAny) || (elements[1].equals(Trigger.triggerPhoneCallDirectionIncoming) && PhoneStatusListener.getLastPhoneDirection() == 1) || (elements[1].equals(Trigger.triggerPhoneCallDirectionOutgoing) && PhoneStatusListener.getLastPhoneDirection() == 2) ) { // Trigger conditions are met } else { Miscellaneous.logEvent("i", "Rule", "A trigger of rule " + getParentRule().getName() + " doesn't apply. Wrong direction. Demanded: " + String.valueOf(this.getPhoneDirection()) + ", got: " + String.valueOf(PhoneStatusListener.getLastPhoneDirection()), 4); return false; } } else { Miscellaneous.logEvent("i", "Rule", "A trigger of rule " + getParentRule().getName() + " doesn't apply. Wrong call status. Demanded: " + elements[0] + ", got: " + String.valueOf(PhoneStatusListener.getCurrentState()) + " (0=idle, 1=ringing, 2=offhook)", 4); return false; } } else { Miscellaneous.logEvent("i", "Rule", "A trigger of rule " + getParentRule().getName() + " doesn't apply. Wrong phone number. Demanded: " + this.getPhoneNumber() + ", got: " + PhoneStatusListener.getLastPhoneNumber(), 4); return false; } return true; } boolean checkRoaming() { if(ConnectivityReceiver.isRoaming(Miscellaneous.getAnyContext()) != this.getTriggerParameter()) { return false; } return true; } boolean checkAirplaneMode() { if(ConnectivityReceiver.isAirplaneMode(Miscellaneous.getAnyContext()) != this.getTriggerParameter()) { return false; } return true; } boolean checkProcess() { boolean running = ProcessListener.getRunningApps().contains(this.getProcessName()); if(running) Miscellaneous.logEvent("i", "ProcessMonitoring", "App " + this.getProcessName() + " is currently running.", 4); else Miscellaneous.logEvent("i", "ProcessMonitoring", "App " + this.getProcessName() + " is not running.", 4); if(running != this.getTriggerParameter()) { Miscellaneous.logEvent("i", "ProcessMonitoring", "Trigger doesn't apply.", 4); return false; } Miscellaneous.logEvent("i", "ProcessMonitoring", "Trigger applies.", 4); return true; } boolean checkWifiConnection() { Miscellaneous.logEvent("i", Miscellaneous.getAnyContext().getResources().getString(R.string.ruleCheckOf), String.format( "Checking for wifi state", this.getParentRule().getName()),4); if(this.getTriggerParameter() == WifiBroadcastReceiver.lastConnectedState) // connected / disconnected { if(this.getTriggerParameter2().length() > 0) // only check if any wifi name specified, otherwise any wifi will do { Miscellaneous.logEvent("i", Miscellaneous.getAnyContext().getResources().getString(R.string.ruleCheckOf), String.format("Wifi name specified, checking that.", this.getParentRule().getName()), 4); if(!WifiBroadcastReceiver.getLastWifiSsid().equals(this.getTriggerParameter2())) { Miscellaneous.logEvent("i", Miscellaneous.getAnyContext().getResources().getString(R.string.ruleCheckOf), String.format(String.format(Miscellaneous.getAnyContext().getResources().getString(R.string.ruleDoesntApplyNotTheCorrectSsid), getParentRule().getName(), this.getTriggerParameter2(), WifiBroadcastReceiver.getLastWifiSsid()),this.getParentRule().getName()), 3); return false; } else Miscellaneous.logEvent("i", Miscellaneous.getAnyContext().getResources().getString(R.string.ruleCheckOf), String.format("Wifi name matches. Rule will apply.", this.getParentRule().getName()), 4); } else Miscellaneous.logEvent("i", Miscellaneous.getAnyContext().getResources().getString(R.string.ruleCheckOf), String.format("No wifi name specified, any will do.", this.getParentRule().getName()), 4); } else { Miscellaneous.logEvent("i", Miscellaneous.getAnyContext().getResources().getString(R.string.ruleCheckOf), String.format("Wifi state not correct, demanded " + String.valueOf(this.getTriggerParameter() + ", got " + String.valueOf(WifiBroadcastReceiver.lastConnectedState)), this.getParentRule().getName()), 4); return false; } return true; } boolean checkNoiseLevel() { if(this.getTriggerParameter()) { if(NoiseListener.getNoiseLevelDb() < this.getNoiseLevelDb()) { Miscellaneous.logEvent("i", Miscellaneous.getAnyContext().getResources().getString(R.string.ruleCheckOf), String.format(Miscellaneous.getAnyContext().getResources().getString(R.string.ruleDoesntApplyItsQuieterThan) + " " + String.valueOf(this.getNoiseLevelDb()), this.getParentRule().getName()), 3); return false; } } else { if(NoiseListener.getNoiseLevelDb() > this.getNoiseLevelDb()) { Miscellaneous.logEvent("i", Miscellaneous.getAnyContext().getResources().getString(R.string.ruleCheckOf), String.format(Miscellaneous.getAnyContext().getResources().getString(R.string.ruleDoesntApplyItsLouderThan) + " " + String.valueOf(this.getNoiseLevelDb()), this.getParentRule().getName()), 3); return false; } } return true; } boolean checkSpeed() { if(this.getTriggerParameter()) { if(LocationProvider.getSpeed() < this.getSpeed()) { Miscellaneous.logEvent("i", Miscellaneous.getAnyContext().getResources().getString(R.string.ruleCheckOf), String.format(Miscellaneous.getAnyContext().getResources().getString(R.string.ruleDoesntApplyWeAreSlowerThan) + " " + String.valueOf(this.getSpeed()), this.getParentRule().getName()), 3); return false; } } else { if(LocationProvider.getSpeed() > this.getSpeed()) { Miscellaneous.logEvent("i", Miscellaneous.getAnyContext().getResources().getString(R.string.ruleCheckOf), String.format(Miscellaneous.getAnyContext().getResources().getString(R.string.ruleDoesntApplyWeAreFasterThan) + " " + String.valueOf(this.getSpeed()), this.getParentRule().getName()), 3); return false; } } return true; } boolean checkBatteryLevel() { if(this.getTriggerParameter()) { if(BatteryReceiver.getBatteryLevel() <= this.getBatteryLevel()) { Miscellaneous.logEvent("i", Miscellaneous.getAnyContext().getResources().getString(R.string.ruleCheckOf), String.format(Miscellaneous.getAnyContext().getResources().getString(R.string.ruleDoesntApplyBatteryLowerThan) + " " + String.valueOf(this.getBatteryLevel()), this.getParentRule().getName()), 3); return false; } } else { if(this.getBatteryLevel() >= this.getBatteryLevel()) { Miscellaneous.logEvent("i", Miscellaneous.getAnyContext().getResources().getString(R.string.ruleCheckOf), String.format(Miscellaneous.getAnyContext().getResources().getString(R.string.ruleDoesntApplyBatteryHigherThan) + " " + String.valueOf(this.getBatteryLevel()), this.getParentRule().getName()), 3); return false; } } return true; } boolean checkUsbHostConnection() { if(BatteryReceiver.isUsbHostConnected() != this.getTriggerParameter()) { return false; } return true; } boolean checkLocation() { // Am I here? PointOfInterest activePoi = PointOfInterest.getActivePoi(); if(activePoi != null) //entering one { if(this.getPointOfInterest() != null) { if(activePoi.equals(this.getPointOfInterest())) { if(!this.getTriggerParameter()) { Miscellaneous.logEvent("i", String.format(Miscellaneous.getAnyContext().getResources().getString(R.string.ruleCheckOf), this.getParentRule().getName()), String.format("Rule %1$s doesn't apply. We're entering POI: " + this.getPointOfInterest().getName() + ", not leaving it.", getParentRule().getName()), 4); return false; } } else { Miscellaneous.logEvent("i", String.format(Miscellaneous.getAnyContext().getResources().getString(R.string.ruleCheckOf), this.getParentRule().getName()), String.format("Rule %1$s doesn't apply. This is " + activePoi.getName() + ", not " + this.getPointOfInterest().getName() + ".", getParentRule().getName()), 4); return false; } } else if(this.getPointOfInterest() == null) { if(this.getTriggerParameter()) { Miscellaneous.logEvent("i", String.format(Miscellaneous.getAnyContext().getResources().getString(R.string.ruleCheckOf), this.getParentRule().getName()), String.format("Rule %s$s doesn't apply. We're at a POI. Rule specifies not at none, so leaving any.",getParentRule().getName()), 4); return false; } } } else //leaving one { // We are not at any POI. But if this trigger requires us NOT to be there, that may be fine. if(this.getPointOfInterest() != null) { // if(activePoi.equals(oneTrigger.getPointOfInterest())) // { if(!this.getTriggerParameter()) { Miscellaneous.logEvent("i", String.format(Miscellaneous.getAnyContext().getResources().getString(R.string.ruleCheckOf), this.getParentRule().getName()), "We are not at POI \"" + this.getPointOfInterest().getName() + "\". But since that's required by this rule that's fine.", 4); } else { Miscellaneous.logEvent("i", String.format(Miscellaneous.getAnyContext().getResources().getString(R.string.ruleCheckOf), this.getParentRule().getName()), String.format("Rule %1$s doesn't apply. We're not at POI \"" + this.getPointOfInterest().getName() + "\".", getParentRule().getName()), 3); return false; } // } } else if(this.getPointOfInterest() == null) { if(!this.getTriggerParameter()) { Miscellaneous.logEvent("i", String.format(Miscellaneous.getAnyContext().getResources().getString(R.string.ruleCheckOf), this.getParentRule().getName()), String.format("Rule %1$s doesn't apply. We're at no POI. Rule specifies to be at anyone.", getParentRule().getName()), 5); return false; } } } return true; } public boolean hasStateNotAppliedSinceLastRuleExecution() { if(getParentRule().getLastExecution() == null) { Miscellaneous.logEvent("i", "Trigger", "Trigger " + this.toString() + " of rule " + getParentRule().getName() + " has NOT applied since the parent rule\'s last activation.", 4); return true; } else if(lastTimeNotApplied != null) { if(lastTimeNotApplied.getTimeInMillis() > getParentRule().getLastExecution().getTimeInMillis()) { Miscellaneous.logEvent("i", "Trigger", "Trigger " + this.toString() + " of rule " + getParentRule().getName() + " has NOT applied since the parent rule\'s last activation.", 4); return true; } } Miscellaneous.logEvent("i", "Trigger", "Trigger " + this.toString() + " of rule " + getParentRule().getName() + " may apply currently, but has not NOT applied since the rule\'s last execution.", 4); return false; } boolean checkCharging() { if(BatteryReceiver.isDeviceCharging(Miscellaneous.getAnyContext()) == 0) { return false; // unknown charging state, can't activate rule under these conditions } else if(BatteryReceiver.isDeviceCharging(Miscellaneous.getAnyContext()) == 1) { if(this.getTriggerParameter()) //rule says when charging, but we're currently discharging return false; } else if(BatteryReceiver.isDeviceCharging(Miscellaneous.getAnyContext()) == 2) { if(!this.getTriggerParameter()) //rule says when discharging, but we're currently charging return false; } return true; } public boolean checkDateTime(Object triggeringObject, boolean checkifStateChangedSinceLastRuleExecution) { /* * Use format known from Automation * 07:30:00/17:30:00/23456/300 <-- last parameter is optional: repetition in seconds * Also required: inside or outside that interval */ Date triggeringTime; if(triggeringObject instanceof Date) triggeringTime = (Date)triggeringObject; else triggeringTime = new Date(); String timeString = String.valueOf(triggeringTime.getHours()) + ":" + String.valueOf(triggeringTime.getMinutes()) + ":" + String.valueOf(triggeringTime.getSeconds()); Time nowTime = Time.valueOf(timeString); Calendar calNow = Calendar.getInstance(); try { TimeFrame tf = new TimeFrame(getTriggerParameter2()); if(tf.getDayList().contains(calNow.get(Calendar.DAY_OF_WEEK))) { if( // Regular case, start time is lower than end time ( Miscellaneous.compareTimes(tf.getTriggerTimeStart(), nowTime) >= 0 && Miscellaneous.compareTimes(nowTime, tf.getTriggerTimeStop()) > 0 ) | // Other case, start time higher than end time, timeframe goes over midnight ( Miscellaneous.compareTimes(tf.getTriggerTimeStart(), tf.getTriggerTimeStop()) < 0 && (Miscellaneous.compareTimes(tf.getTriggerTimeStart(), nowTime) >= 0 | Miscellaneous.compareTimes(nowTime, tf.getTriggerTimeStop()) > 0) ) ) { // We are in the timeframe Miscellaneous.logEvent("i", "Trigger", "TimeFrame: We're currently (" + calNow.getTime().toString() + ") in the specified TimeFrame (" + tf.toString() + ").", 4); if(getTriggerParameter()) { if(checkifStateChangedSinceLastRuleExecution) { /* * Was there a target repetition time between last execution and now? * If not -> return false. */ Calendar compareCal = Calendar.getInstance(); compareCal.setTimeInMillis(triggeringTime.getTime()); if(tf.getRepetition() > 0) { if(!isSupposedToRepeatSinceLastExecution(compareCal)) { Miscellaneous.logEvent("i", "TimeFrame", "TimeFrame: Trigger of rule " + this.getParentRule().getName() + " applies, but repeated execution is not due, yet.", 4); return false; } } else { /* * This is not a repeating rule. Have we left * the relevant timeframe since the last run? * Determine if it has ran today already. If yes * return false because every rule that is not * repeating can only be executed once per day. */ if( getParentRule().getLastExecution().get(Calendar.YEAR) == calNow.get(Calendar.YEAR) && getParentRule().getLastExecution().get(Calendar.MONTH) == calNow.get(Calendar.MONTH) && getParentRule().getLastExecution().get(Calendar.DAY_OF_MONTH) == calNow.get(Calendar.DAY_OF_MONTH) ) { Miscellaneous.logEvent("i", "TimeFrame", "TimeFrame: Trigger of rule " + this.getParentRule().getName() + " applies, but it was already executed today.", 4); return false; } } } Miscellaneous.logEvent("i", "Trigger", "TimeFrame: That's what's specified. Trigger of rule " + this.getParentRule().getName() + " applies.", 4); return true; } else { Miscellaneous.logEvent("i", "Trigger", "TimeFrame: That's not what's specified. Trigger of rule " + this.getParentRule().getName() + " doesn't apply.", 4); return false; } } else { Miscellaneous.logEvent("i", "Trigger", "TimeFrame: We're currently (" + calNow.getTime().toString() + ", Day: " + String.valueOf(calNow.get(Calendar.DAY_OF_WEEK)) + ") not in the specified TimeFrame (" + tf.toString() + ") because of the time.", 5); if(!getTriggerParameter()) { if(checkifStateChangedSinceLastRuleExecution) { /* * Was there a target repetition time between last execution and now? * If not -> return false. */ Calendar compareCal = Calendar.getInstance(); compareCal.setTimeInMillis(triggeringTime.getTime()); if(tf.getRepetition() > 0) { if(!isSupposedToRepeatSinceLastExecution(compareCal)) { Miscellaneous.logEvent("i", "Trigger", "TimeFrame: Trigger of rule " + this.getParentRule().getName() + " applies, but repeated execution is not due, yet.", 4); return false; } } else { /* * This is not a repeating rule. Have we left * the relevant timeframe since the last run? * Determine if it has ran today already. If yes * return false because every rule that is not * repeating can only be executed once per day. */ if( getParentRule().getLastExecution().get(Calendar.YEAR) == calNow.get(Calendar.YEAR) && getParentRule().getLastExecution().get(Calendar.MONTH) == calNow.get(Calendar.MONTH) && getParentRule().getLastExecution().get(Calendar.DAY_OF_MONTH) == calNow.get(Calendar.DAY_OF_MONTH) ) { Miscellaneous.logEvent("i", "Trigger", "TimeFrame: Trigger of rule " + this.getParentRule().getName() + " applies, but it was already executed today.", 4); return false; } } } Miscellaneous.logEvent("i", "Trigger", "TimeFrame: That's what's specified. Trigger of rule " + this.getParentRule().getName() + " applies.", 5); return true; } else { Miscellaneous.logEvent("i", "Trigger", "TimeFrame: That's not what's specified. Trigger of rule " + this.getParentRule().getName() + " doesn't apply.", 5); return false; } } } else { Miscellaneous.logEvent("i", "Trigger", "TimeFrame: We're currently (" + calNow.getTime().toString() + ", Day: " + String.valueOf(calNow.get(Calendar.DAY_OF_WEEK)) + ") not in the specified TimeFrame (" + tf.toString() + ") because of the day.", 5); return false; } } catch(Exception e) { Miscellaneous.logEvent("e", "Trigger", "There was an error while checking if the time based trigger applies: " + Log.getStackTraceString(e), 1); return false; } } public static Calendar getNextRepeatedExecutionAfter(Trigger trigger, Calendar now) { Calendar calSet; Time setTime; TimeFrame tf = new TimeFrame(trigger.getTriggerParameter2()); if(tf.getRepetition() > 0) { if(trigger.getTriggerParameter()) setTime = tf.getTriggerTimeStart(); else setTime = tf.getTriggerTimeStop(); calSet = (Calendar) now.clone(); calSet.set(Calendar.HOUR_OF_DAY, setTime.getHours()); calSet.set(Calendar.MINUTE, setTime.getMinutes()); calSet.set(Calendar.SECOND, 0); calSet.set(Calendar.MILLISECOND, 0); // if(this.applies(null)) // { // If the starting time is a day ahead remove 1 day. if(calSet.getTimeInMillis() > now.getTimeInMillis()) calSet.add(Calendar.DAY_OF_MONTH, -1); long differenceInSeconds = Math.abs(now.getTimeInMillis() - calSet.getTimeInMillis()) / 1000; long nextExecutionMultiplier = Math.floorDiv(differenceInSeconds, tf.getRepetition()) + 1; long nextScheduleTimestamp = (calSet.getTimeInMillis() / 1000) + (nextExecutionMultiplier * tf.getRepetition()); Calendar calSchedule = Calendar.getInstance(); calSchedule.setTimeInMillis(nextScheduleTimestamp * 1000); /* * Das war mal aktiviert. Allerdings: Die ganze Funktion liefert zurück, wenn die Regel NOCH nicht * zutrifft, aber wir z.B. gleich den zeitlichen Bereich betreten. */ // if(trigger.checkDateTime(calSchedule.getTime(), false)) // { return calSchedule; // } // } } else Miscellaneous.logEvent("i", "Trigger", "Trigger " + trigger.toString() + " is not executed repeatedly.", 5); return null; } boolean isSupposedToRepeatSinceLastExecution(Calendar now) { TimeFrame tf = new TimeFrame(getTriggerParameter2()); Calendar lastExec = getParentRule().getLastExecution(); // the simple stuff: if(lastExec == null) // rule never run, go any way return true; else if(tf.getRepetition() <= 0) // is not set to repeat at all return false; /* * We don't need to check if the trigger currently applies, that has * been done externally via the applies() function. We can safely assume * we're inside the specified timeframe. */ Calendar timeSupposedToRunNext = getNextRepeatedExecutionAfter(this, lastExec); if(now.getTimeInMillis() > timeSupposedToRunNext.getTimeInMillis()) return true; return false; } /* * Can be several things: * -PointOfInterest * -TimeFrame * -Event (like charging, cable plugged, etc.) */ public enum Trigger_Enum { pointOfInterest, timeFrame, charging, batteryLevel, usb_host_connection, speed, noiseLevel, wifiConnection, process_started_stopped, airplaneMode, roaming, nfcTag, activityDetection, bluetoothConnection, headsetPlugged, notification, deviceOrientation, phoneCall; //phoneCall always needs to be at the very end because of Google's shitty so called privacy public String getFullName(Context context) { switch(this) { case pointOfInterest: return context.getResources().getString(R.string.triggerPointOfInterest); case timeFrame: return context.getResources().getString(R.string.triggerTimeFrame); case charging: return context.getResources().getString(R.string.triggerCharging); case batteryLevel: return context.getResources().getString(R.string.batteryLevel); case usb_host_connection: return context.getResources().getString(R.string.triggerUsb_host_connection); case speed: return context.getResources().getString(R.string.triggerSpeed); case noiseLevel: return context.getResources().getString(R.string.triggerNoiseLevel); case wifiConnection: return context.getResources().getString(R.string.wifiConnection); case process_started_stopped: return context.getResources().getString(R.string.anotherAppIsRunning); case airplaneMode: return context.getResources().getString(R.string.airplaneMode); case roaming: return context.getResources().getString(R.string.roaming); case phoneCall: return context.getResources().getString(R.string.phoneCall); case nfcTag: return context.getResources().getString(R.string.nfcTag); case activityDetection: return context.getResources().getString(R.string.activityDetection); case bluetoothConnection: return context.getResources().getString(R.string.bluetoothConnection); case headsetPlugged: return context.getResources().getString(R.string.triggerHeadsetPlugged); case notification: return context.getResources().getString(R.string.notification); case deviceOrientation: return context.getResources().getString(R.string.deviceOrientation); default: return "Unknown"; } } }; private boolean triggerParameter; //if true->started event, if false->stopped private String triggerParameter2; public static final String triggerParameter2Split = "tp2split"; private Trigger_Enum triggerType = null; private PointOfInterest pointOfInterest = null; private TimeFrame timeFrame; public static String triggerPhoneCallStateRinging = "ringing"; public static String triggerPhoneCallStateStarted = "started"; public static String triggerPhoneCallStateStopped = "stopped"; public static String triggerPhoneCallDirectionIncoming = "incoming"; public static String triggerPhoneCallDirectionOutgoing = "outgoing"; public static String triggerPhoneCallDirectionAny = "any"; public static String triggerPhoneCallNumberAny = "any"; private double speed; //km/h private long noiseLevelDb; private String processName = null; private int batteryLevel; private int phoneDirection = 0; // 0=any, 1=incoming, 2=outgoing private String phoneNumber = null; private String nfcTagId = null; private String bluetoothEvent = null; private String bluetoothDeviceAddress = null; private int activityDetectionType = -1; private int headphoneType = -1; public int getHeadphoneType() { return headphoneType; } public void setHeadphoneType(int headphoneType) { this.headphoneType = headphoneType; } public String getNfcTagId() { return nfcTagId; } public void setNfcTagId(String nfcTagId) { this.nfcTagId = nfcTagId; } public int getActivityDetectionType() { return activityDetectionType; } public void setActivityDetectionType(int activityDetectionType) { this.activityDetectionType = activityDetectionType; } public String getBluetoothDeviceAddress() { return bluetoothDeviceAddress; } public void setBluetoothDeviceAddress(String bluetoothDeviceAddress) { this.bluetoothDeviceAddress = bluetoothDeviceAddress; } public void setPhoneNumber(String phoneNumber) { this.phoneNumber = phoneNumber; } public String getPhoneNumber() { return phoneNumber; } public void setPhoneDirection(int phoneDirection) { this.phoneDirection = phoneDirection; } public int getPhoneDirection() { return phoneDirection; } public int getBatteryLevel() { return batteryLevel; } public void setBatteryLevel(int batteryLevel) { this.batteryLevel = batteryLevel; } public String getProcessName() { return processName; } public void setProcessName(String processName) { this.processName = processName; } public PointOfInterest getPointOfInterest() { return pointOfInterest; } public void setPointOfInterest(PointOfInterest setPointOfInterest) { this.pointOfInterest = setPointOfInterest; } public double getSpeed() { return speed; } public void setSpeed(double speed) { this.speed = speed; } public long getNoiseLevelDb() { return noiseLevelDb; } public void setNoiseLevelDb(long noiseLevelDb) { this.noiseLevelDb = noiseLevelDb; } public Trigger_Enum getTriggerType() { return triggerType; } public void setTriggerType(Trigger_Enum settriggerType) { this.triggerType = settriggerType; } public boolean getTriggerParameter() { return triggerParameter; } public void setTriggerParameter(boolean triggerParameter) { this.triggerParameter = triggerParameter; } public String getTriggerParameter2() { return triggerParameter2; } public void setTriggerParameter2(String triggerParameter2) { this.triggerParameter2 = triggerParameter2; } public TimeFrame getTimeFrame() { return timeFrame; } public void setTimeFrame(TimeFrame timeFrame) { this.timeFrame = timeFrame; } @RequiresApi(api = Build.VERSION_CODES.KITKAT) @SuppressWarnings("unused") @Override public String toString() { StringBuilder returnString = new StringBuilder(); switch(this.getTriggerType()) { case charging: if(getTriggerParameter()) returnString.append(Miscellaneous.getAnyContext().getResources().getString(R.string.starting) + " "); else returnString.append(Miscellaneous.getAnyContext().getResources().getString(R.string.stopping) + " "); returnString.append(Miscellaneous.getAnyContext().getResources().getString(R.string.triggerCharging)); break; case batteryLevel: returnString.append(Miscellaneous.getAnyContext().getResources().getString(R.string.batteryLevel)); if(getTriggerParameter()) returnString.append(" " + Miscellaneous.getAnyContext().getResources().getString(R.string.exceeds) + " "); else returnString.append(" " + Miscellaneous.getAnyContext().getResources().getString(R.string.dropsBelow) + " "); returnString.append(String.valueOf(this.getBatteryLevel()) + " %"); break; case usb_host_connection: if(getTriggerParameter()) returnString.append(Miscellaneous.getAnyContext().getResources().getString(R.string.connecting) + " "); else returnString.append(Miscellaneous.getAnyContext().getResources().getString(R.string.disconnecting) + " "); returnString.append(Miscellaneous.getAnyContext().getResources().getString(R.string.triggerUsb_host_connection)); break; case pointOfInterest: if(this.getPointOfInterest() != null) { if(getTriggerParameter()) returnString.append(Miscellaneous.getAnyContext().getResources().getString(R.string.entering) + " "); else returnString.append(Miscellaneous.getAnyContext().getResources().getString(R.string.leaving) + " "); returnString.append(this.getPointOfInterest().getName().toString()); } else { if(getTriggerParameter()) returnString.append(Miscellaneous.getAnyContext().getResources().getString(R.string.leaving) + " " + Miscellaneous.getAnyContext().getResources().getString(R.string.anyLocation)); else returnString.append(Miscellaneous.getAnyContext().getResources().getString(R.string.entering) + " " + Miscellaneous.getAnyContext().getResources().getString(R.string.anyLocation)); } break; case timeFrame: if(getTriggerParameter()) returnString.append(Miscellaneous.getAnyContext().getResources().getString(R.string.entering) + " "); else returnString.append(Miscellaneous.getAnyContext().getResources().getString(R.string.leaving) + " "); String repeat = ", no repetition"; if(this.getTimeFrame().getRepetition() > 0) repeat = ", " + String.format(Miscellaneous.getAnyContext().getResources().getString(R.string.repeatEveryXsecondsWithVariable), String.valueOf(this.getTimeFrame().getRepetition())); returnString.append(Miscellaneous.getAnyContext().getResources().getString(R.string.triggerTimeFrame) + ": " + this.getTimeFrame().getTriggerTimeStart().toString() + " " + Miscellaneous.getAnyContext().getResources().getString(R.string.until) + " " + this.getTimeFrame().getTriggerTimeStop().toString() + " on days " + this.getTimeFrame().getDayList().toString() + repeat); break; case speed: if(getTriggerParameter()) returnString.append(Miscellaneous.getAnyContext().getResources().getString(R.string.exceeding) + " "); else returnString.append(Miscellaneous.getAnyContext().getResources().getString(R.string.droppingBelow) + " "); returnString.append(Miscellaneous.getAnyContext().getResources().getString(R.string.triggerSpeed) + ": " + String.valueOf(this.getSpeed()) + " km/h"); break; case noiseLevel: if(getTriggerParameter()) returnString.append(Miscellaneous.getAnyContext().getResources().getString(R.string.exceeding) + " "); else returnString.append(Miscellaneous.getAnyContext().getResources().getString(R.string.droppingBelow) + " "); returnString.append(Miscellaneous.getAnyContext().getResources().getString(R.string.triggerNoiseLevel) + ": " + String.valueOf(this.getNoiseLevelDb()) + " dB"); break; case wifiConnection: String wifiDisplayName = ""; if(this.getTriggerParameter2().length() == 0) wifiDisplayName += Miscellaneous.getAnyContext().getResources().getString(R.string.anyWifi); else wifiDisplayName += this.getTriggerParameter2(); if(getTriggerParameter()) returnString.append(String.format(Miscellaneous.getAnyContext().getResources().getString(R.string.connectedToWifi), wifiDisplayName)); else returnString.append(String.format(Miscellaneous.getAnyContext().getResources().getString(R.string.disconnectedFromWifi), wifiDisplayName)); break; case process_started_stopped: returnString.append(Miscellaneous.getAnyContext().getResources().getString(R.string.application) + " " + this.getProcessName() + " " + Miscellaneous.getAnyContext().getResources().getString(R.string.is) + " "); if(this.triggerParameter) returnString.append(Miscellaneous.getAnyContext().getResources().getString(R.string.started)); else returnString.append(Miscellaneous.getAnyContext().getResources().getString(R.string.stopped)); break; case airplaneMode: if(getTriggerParameter()) returnString.append(Miscellaneous.getAnyContext().getResources().getString(R.string.activated) + " "); else returnString.append(Miscellaneous.getAnyContext().getResources().getString(R.string.deactivated) + " "); returnString.append(Miscellaneous.getAnyContext().getResources().getString(R.string.airplaneMode)); break; case roaming: if(getTriggerParameter()) returnString.append(Miscellaneous.getAnyContext().getResources().getString(R.string.activated) + " "); else returnString.append(Miscellaneous.getAnyContext().getResources().getString(R.string.deactivated) + " "); returnString.append(Miscellaneous.getAnyContext().getResources().getString(R.string.roaming)); break; case phoneCall: String[] elements = triggerParameter2.split(triggerParameter2Split); returnString.append(Miscellaneous.getAnyContext().getResources().getString(R.string.phoneCall)); returnString.append(" "); if(elements[1].equals(triggerPhoneCallDirectionAny)) returnString.append(Miscellaneous.getAnyContext().getResources().getString(R.string.with)); else if(elements[1].equals(triggerPhoneCallDirectionIncoming)) returnString.append(Miscellaneous.getAnyContext().getResources().getString(R.string.from)); else if(elements[1].equals(triggerPhoneCallDirectionOutgoing)) returnString.append(Miscellaneous.getAnyContext().getResources().getString(R.string.to)); returnString.append(" "); if(elements[2].equals(Trigger.triggerPhoneCallNumberAny)) returnString.append(Miscellaneous.getAnyContext().getResources().getString(R.string.any) + " " + Miscellaneous.getAnyContext().getResources().getString(R.string.number)); else returnString.append(Miscellaneous.getAnyContext().getResources().getString(R.string.number) + " " + Miscellaneous.getAnyContext().getResources().getString(R.string.matching) + " " + elements[2]); returnString.append(" "); if(elements[0].equals(Trigger.triggerPhoneCallStateRinging)) returnString.append(Miscellaneous.getAnyContext().getResources().getString(R.string.ringing)); else if(elements[0].equals(Trigger.triggerPhoneCallStateStarted)) returnString.append(Miscellaneous.getAnyContext().getResources().getString(R.string.started)); else if(elements[0].equals(Trigger.triggerPhoneCallStateStopped)) returnString.append(Miscellaneous.getAnyContext().getResources().getString(R.string.stopped)); // returnString.append(Miscellaneous.getAnyContext().getResources().getString(R.string.phoneCall)); // if(phoneNumber != null && !phoneNumber.equals("any")) // returnString.append(" " + Miscellaneous.getAnyContext().getResources().getString(R.string.with) + " " + Miscellaneous.getAnyContext().getResources().getString(R.string.number) + " " + phoneNumber); // else // returnString.append(" " + Miscellaneous.getAnyContext().getResources().getString(R.string.with) + " " + Miscellaneous.getAnyContext().getResources().getString(R.string.anyNumber)); // // if(getTriggerParameter()) // returnString.append(" " + Miscellaneous.getAnyContext().getResources().getString(R.string.started)); // else // returnString.append(" " + Miscellaneous.getAnyContext().getResources().getString(R.string.stopped)); break; case nfcTag: // This type doesn't have an activate/deactivate equivalent // if(getTriggerParameter()) // returnString += Miscellaneous.getAnyContext().getResources().getString(R.string.activated) + " "; // else // returnString += Miscellaneous.getAnyContext().getResources().getString(R.string.deactivated) + " "; returnString.append(Miscellaneous.getAnyContext().getResources().getString(R.string.closeTo) + " " + Miscellaneous.getAnyContext().getResources().getString(R.string.nfcTag) + " " + Miscellaneous.getAnyContext().getResources().getString(R.string.withLabel) + " " + this.getNfcTagId()); break; case activityDetection: try { Class testClass = Class.forName(ActivityManageRule.activityDetectionClassPath); if (ActivityPermissions.isPermissionDeclaratedInManifest(Miscellaneous.getAnyContext(), "com.google.android.gms.permission.ACTIVITY_RECOGNITION")) { // This type doesn't have an activate/deactivate equivalent, at least not yet. // try // { returnString.append(Miscellaneous.runMethodReflective(ActivityManageRule.activityDetectionClassPath, "getDescription", new Object[]{getActivityDetectionType()})); // for(Method method : activityDetection.getMethods()) // { // if(method.getName().equalsIgnoreCase("getDescription")) // returnString.append(method.invoke()); //// returnString.append(Miscellaneous.getAnyContext().getResources().getString(R.string.detectedActivity) + " " + activityDetection.getDescription(getActivityDetectionType())); // } // } // catch (ClassNotFoundException | IllegalAccessException | InvocationTargetException e) // { // e.printStackTrace(); // } } else returnString.append(Miscellaneous.getAnyContext().getResources().getString(R.string.featureNotInFdroidVersion)); } catch(ClassNotFoundException e) { returnString.append(Miscellaneous.getAnyContext().getResources().getString(R.string.featureNotInFdroidVersion)); } break; case bluetoothConnection: String device = Miscellaneous.getAnyContext().getResources().getString(R.string.anyDevice); if(bluetoothDeviceAddress.equals("")) { device = Miscellaneous.getAnyContext().getResources().getString(R.string.any); } else if(bluetoothDeviceAddress.equals("")) { device = Miscellaneous.getAnyContext().getResources().getString(R.string.noDevice); } else { try { device = BluetoothReceiver.getDeviceByAddress(bluetoothDeviceAddress).getName() + " (" + this.bluetoothDeviceAddress + ")"; } catch(NullPointerException e) { device = Miscellaneous.getAnyContext().getResources().getString(R.string.invalidDevice) + ": " + this.bluetoothDeviceAddress; Miscellaneous.logEvent("w", "Trigger", device, 3); } } if(bluetoothEvent.equals(BluetoothDevice.ACTION_ACL_CONNECTED) || bluetoothEvent.equals(BluetoothDevice.ACTION_ACL_DISCONNECTED)) { if (this.triggerParameter) returnString.append(String.format(Miscellaneous.getAnyContext().getResources().getString(R.string.bluetoothConnectionTo), device)); else returnString.append(String.format(Miscellaneous.getAnyContext().getResources().getString(R.string.bluetoothDisconnectFrom), device)); } else if(bluetoothEvent.equals(BluetoothDevice.ACTION_FOUND)) { if (this.triggerParameter) returnString.append(String.format(Miscellaneous.getAnyContext().getResources().getString(R.string.bluetoothDeviceInRange), device)); else returnString.append(String.format(Miscellaneous.getAnyContext().getResources().getString(R.string.bluetoothDeviceOutOfRange), device)); } break; case headsetPlugged: String type; switch(headphoneType) { case 0: type = Miscellaneous.getAnyContext().getResources().getString(R.string.headphoneSimple); break; case 1: type = Miscellaneous.getAnyContext().getResources().getString(R.string.headphoneMicrophone); break; case 2: type = Miscellaneous.getAnyContext().getResources().getString(R.string.headphoneAny); break; default: type = "not set"; break; } if(getTriggerParameter()) returnString.append(String.format(Miscellaneous.getAnyContext().getResources().getString(R.string.headsetConnected), type)); else returnString.append(String.format(Miscellaneous.getAnyContext().getResources().getString(R.string.headsetDisconnected), type)); break; case notification: if(this.getTriggerParameter2().contains(triggerParameter2Split)) { String[] params = getTriggerParameter2().split(triggerParameter2Split); String app = params[0]; String titleDir = params[1]; String title = params[2]; String textDir = params[3]; String text; if (params.length >= 5) text = params[4]; else text = ""; StringBuilder triggerBuilder = new StringBuilder(); String appString; if (app.equalsIgnoreCase("-1")) appString = Miscellaneous.getAnyContext().getResources().getString(R.string.anyApp); else appString = "app " + app; if(triggerParameter) triggerBuilder.append(String.format(Miscellaneous.getAnyContext().getResources().getString(R.string.postsNotification), appString)); else triggerBuilder.append(String.format(Miscellaneous.getAnyContext().getResources().getString(R.string.removedNotification), appString)); if (title.length() > 0) triggerBuilder.append(", " + Miscellaneous.getAnyContext().getString(R.string.title) + " " + Trigger.getMatchString(titleDir) + " " + title); if (text.length() > 0) triggerBuilder.append(", " + Miscellaneous.getAnyContext().getString(R.string.text) + " " + Trigger.getMatchString(textDir) + " " + text); returnString.append(triggerBuilder.toString()); } else { setTriggerParameter2("-1" + triggerParameter2Split + directionEquals + triggerParameter2Split + triggerParameter2Split + directionEquals + triggerParameter2Split + triggerParameter2Split); } break; case deviceOrientation: returnString.append(Miscellaneous.getAnyContext().getString(R.string.deviceIsInCertainOrientation)); break; default: returnString.append("error"); break; } return returnString.toString(); } public static final String directionEquals = "eq"; public static final String directionContains = "ct"; public static final String directionStartsWith = "sw"; public static final String directionEndsWith = "ew"; public static final String directionNotEquals = "ne"; public static String getMatchString(String direction) { switch(direction) { case directionEquals: return Miscellaneous.getAnyContext().getString(R.string.directionStringEquals); case directionContains: return Miscellaneous.getAnyContext().getString(R.string.directionStringContains); case directionStartsWith: return Miscellaneous.getAnyContext().getString(R.string.directionStringStartsWith); case directionEndsWith: return Miscellaneous.getAnyContext().getString(R.string.directionStringEndsWith); case directionNotEquals: return Miscellaneous.getAnyContext().getString(R.string.directionStringNotEquals); default: return Miscellaneous.getAnyContext().getString(R.string.error); } } public static String getMatchCode(String direction) { if(direction.equalsIgnoreCase(Miscellaneous.getAnyContext().getString(R.string.directionStringEquals))) return directionEquals; else if(direction.equalsIgnoreCase(Miscellaneous.getAnyContext().getString(R.string.directionStringContains))) return directionContains; else if(direction.equalsIgnoreCase(Miscellaneous.getAnyContext().getString(R.string.directionStringStartsWith))) return directionStartsWith; else if(direction.equalsIgnoreCase(Miscellaneous.getAnyContext().getString(R.string.directionStringEndsWith))) return directionEndsWith; else if(direction.equalsIgnoreCase(Miscellaneous.getAnyContext().getString(R.string.directionStringNotEquals))) return directionNotEquals; else return Miscellaneous.getAnyContext().getString(R.string.error); } public static String[] getTriggerTypesAsArray() { ArrayList triggerTypesList = new ArrayList(); /*for(int i=0; i triggerTypesList = new ArrayList(); /*for(int i=0; i