ruby-macrodroid 0.5.1 → 0.7.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data.tar.gz.sig +0 -0
- data/lib/ruby-macrodroid.rb +831 -87
- metadata +84 -4
- metadata.gz.sig +1 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 70dd1172a7d2ad827ff72771851910b140616b3f41fd7843ef65dc5bdf55fd5e
|
4
|
+
data.tar.gz: d5ef7e748dd16bfbc83e0ca05932a2b7723c61ea2ee2fbc8f69ef1c77c651ef0
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 91746fa312b8c1c5069c16f5c7337b1f6f438af8afecedc5e6469f21e00f98108788f3248d8d93284d9829858b0bf11ce5ad1591bba4a7f8f4ed1005a71c111c
|
7
|
+
data.tar.gz: bd1cefc341fd57809b563f1a4f21f013b3fe3e93143cef0c07862bdfe738ca6479e39c86a80355c110bd786da5b63849cc59616c7d67be58750c4ff2c68a47c3
|
checksums.yaml.gz.sig
CHANGED
Binary file
|
data.tar.gz.sig
CHANGED
Binary file
|
data/lib/ruby-macrodroid.rb
CHANGED
@@ -2,7 +2,117 @@
|
|
2
2
|
|
3
3
|
# file: ruby-macrodroid.rb
|
4
4
|
|
5
|
+
# This file contains the following classes:
|
6
|
+
#
|
7
|
+
# ## Nlp classes
|
8
|
+
#
|
9
|
+
# TriggersNlp ActionsNlp ConstraintsNlp
|
10
|
+
#
|
11
|
+
#
|
12
|
+
# ## Macro class
|
13
|
+
#
|
14
|
+
# Macro
|
15
|
+
#
|
16
|
+
#
|
17
|
+
# ## Error class
|
18
|
+
#
|
19
|
+
# MacroDroidError
|
20
|
+
#
|
21
|
+
#
|
22
|
+
# ## Droid class
|
23
|
+
#
|
24
|
+
# MacroDroid
|
25
|
+
#
|
26
|
+
#
|
27
|
+
# ## Map class
|
28
|
+
#
|
29
|
+
# GeofenceMap
|
30
|
+
#
|
31
|
+
#
|
32
|
+
# ## Object class
|
33
|
+
#
|
34
|
+
# MacroObject
|
35
|
+
#
|
36
|
+
#
|
37
|
+
# ## Trigger classes
|
38
|
+
#
|
39
|
+
# Trigger WebHookTrigger WifiConnectionTrigger
|
40
|
+
# ApplicationInstalledRemovedTrigger ApplicationLaunchedTrigger
|
41
|
+
# BatteryLevelTrigger BatteryTemperatureTrigger PowerButtonToggleTrigger
|
42
|
+
# ExternalPowerTrigger CallActiveTrigger IncomingCallTrigger
|
43
|
+
# OutgoingCallTrigger CallEndedTrigger CallMissedTrigger IncomingSMSTrigger
|
44
|
+
# WebHookTrigger WifiConnectionTrigger BluetoothTrigger HeadphonesTrigger
|
45
|
+
# SignalOnOffTrigger UsbDeviceConnectionTrigger WifiSSIDTrigger
|
46
|
+
# CalendarTrigger TimerTrigger StopwatchTrigger DayTrigger
|
47
|
+
# RegularIntervalTrigger DeviceEventsTrigger AirplaneModeTrigger
|
48
|
+
# AutoSyncChangeTrigger DayDreamTrigger DockTrigger FailedLoginTrigger
|
49
|
+
# GPSEnabledTrigger MusicPlayingTrigger DeviceUnlockedTrigger
|
50
|
+
# AutoRotateChangeTrigger ClipboardChangeTrigger BootTrigger
|
51
|
+
# IntentReceivedTrigger NotificationTrigger ScreenOnOffTrigger
|
52
|
+
# SilentModeTrigger WeatherTrigger GeofenceTrigger SunriseSunsetTrigger
|
53
|
+
# SensorsTrigger ActivityRecognitionTrigger ProximityTrigger
|
54
|
+
# ShakeDeviceTrigger FlipDeviceTrigger OrientationTrigger
|
55
|
+
# FloatingButtonTrigger ShortcutTrigger VolumeButtonTrigger
|
56
|
+
# MediaButtonPressedTrigger SwipeTrigger
|
57
|
+
#
|
58
|
+
#
|
59
|
+
# ## Action classes
|
60
|
+
#
|
61
|
+
# Action LocationAction ShareLocationAction ApplicationAction
|
62
|
+
# LaunchActivityAction KillBackgroundAppAction OpenWebPageAction CameraAction
|
63
|
+
# UploadPhotoAction TakePictureAction ConnectivityAction SetWifiAction
|
64
|
+
# SetBluetoothAction SetBluetoothAction SendIntentAction DateTimeAction
|
65
|
+
# SetAlarmClockAction StopWatchAction SayTimeAction DeviceAction
|
66
|
+
# AndroidShortcutsAction ClipboardAction PressBackAction SpeakTextAction
|
67
|
+
# UIInteractionAction VoiceSearchAction DeviceSettingsAction
|
68
|
+
# ExpandCollapseStatusBarAction LaunchHomeScreenAction CameraFlashLightAction
|
69
|
+
# VibrateAction SetAutoRotateAction DayDreamAction SetKeyboardAction
|
70
|
+
# SetKeyguardAction CarModeAction ChangeKeyboardAction SetWallpaperAction
|
71
|
+
# FileAction OpenFileAction LocationAction ForceLocationUpdateAction
|
72
|
+
# ShareLocationAction SetLocationUpdateRateAction LoggingAction
|
73
|
+
# AddCalendarEntryAction LogAction ClearLogAction MediaAction
|
74
|
+
# RecordMicrophoneAction PlaySoundAction MessagingAction SendEmailAction
|
75
|
+
# SendSMSAction UDPCommandAction NotificationsAction ClearNotificationsAction
|
76
|
+
# MessageDialogAction AllowLEDNotificationLightAction
|
77
|
+
# SetNotificationSoundAction SetNotificationSoundAction
|
78
|
+
# SetNotificationSoundAction NotificationAction ToastAction PhoneAction
|
79
|
+
# AnswerCallAction ClearCallLogAction OpenCallLogAction RejectCallAction
|
80
|
+
# MakeCallAction SetRingtoneAction ScreenAction SetBrightnessAction
|
81
|
+
# ForceScreenRotationAction ScreenOnAction DimScreenAction KeepAwakeAction
|
82
|
+
# SetScreenTimeoutAction VolumeAction SilentModeVibrateOffAction
|
83
|
+
# SetVibrateAction VolumeIncrementDecrementAction SpeakerPhoneAction
|
84
|
+
# SetVolumeAction
|
85
|
+
#
|
86
|
+
#
|
87
|
+
# ## Constraint classes
|
88
|
+
#
|
89
|
+
# Constraint TimeOfDayConstraint BatteryLevelConstraint
|
90
|
+
# BatterySaverStateConstraint BatteryTemperatureConstraint
|
91
|
+
# ExternalPowerConstraint BluetoothConstraint GPSEnabledConstraint
|
92
|
+
# LocationModeConstraint SignalOnOffConstraint WifiConstraint
|
93
|
+
# CellTowerConstraint IsRoamingConstraint DataOnOffConstraint
|
94
|
+
# WifiHotSpotConstraint CalendarConstraint DayOfWeekConstraint
|
95
|
+
# TimeOfDayConstraint DayOfMonthConstraint MonthOfYearConstraint
|
96
|
+
# SunsetSunriseConstraint AirplaneModeConstraint AutoRotateConstraint
|
97
|
+
# DeviceLockedConstraint RoamingOnOffConstraint TimeSinceBootConstraint
|
98
|
+
# AutoSyncConstraint NFCStateConstraint IsRootedConstraint VpnConstraint
|
99
|
+
# MacroEnabledConstraint ModeConstraint TriggerThatInvokedConstraint
|
100
|
+
# LastRunTimeConstraint HeadphonesConnectionConstraint MusicActiveConstraint
|
101
|
+
# NotificationPresentConstraint PriorityModeConstraint
|
102
|
+
# NotificationVolumeConstraint InCallConstraint PhoneRingingConstraint
|
103
|
+
# BrightnessConstraint VolumeConstraint SpeakerPhoneConstraint
|
104
|
+
# DarkThemeConstraint ScreenOnOffConstraint VolumeLevelConstraint
|
105
|
+
# FaceUpDownConstraint LightLevelConstraint DeviceOrientationConstraint
|
106
|
+
# ProximitySensorConstraint
|
107
|
+
|
108
|
+
|
109
|
+
|
110
|
+
require 'yaml'
|
111
|
+
require 'rowx'
|
5
112
|
require 'uuid'
|
113
|
+
#require 'glw'
|
114
|
+
#require 'geozone'
|
115
|
+
require 'subunit'
|
6
116
|
require 'rxfhelper'
|
7
117
|
require 'chronic_cron'
|
8
118
|
|
@@ -30,7 +140,55 @@ class TriggersNlp
|
|
30
140
|
[TimerTrigger, {time: time, days: days}]
|
31
141
|
end
|
32
142
|
|
143
|
+
# time.is? 'at 18:30pm on Mon or Tue'
|
144
|
+
get /^time.is\? ['"](?:at )?(\d+:\d+(?:[ap]m)?) (?:on )?(.*)['"]/i do |time, days|
|
145
|
+
[TimerTrigger, {time: time, days: days.gsub(' or ',', ')}]
|
146
|
+
end
|
147
|
+
|
148
|
+
get /^shake[ _]device\??$/i do
|
149
|
+
[ShakeDeviceTrigger, {}]
|
150
|
+
end
|
151
|
+
|
152
|
+
get /^Flip Device (.*)$/i do |motion|
|
153
|
+
facedown = motion =~ /Face Up (?:->|to) Face Down/i
|
154
|
+
[FlipDeviceTrigger, {face_down: facedown }]
|
155
|
+
end
|
156
|
+
|
157
|
+
get /^flip_device_down\?$/i do
|
158
|
+
[FlipDeviceTrigger, {face_down: true }]
|
159
|
+
end
|
160
|
+
|
161
|
+
get /^flip_device_up\?$/i do
|
162
|
+
[FlipDeviceTrigger, {face_down: false }]
|
163
|
+
end
|
164
|
+
|
165
|
+
get /^Failed Login Attempt$/i do
|
166
|
+
[FailedLoginTrigger, {}]
|
167
|
+
end
|
168
|
+
|
169
|
+
get /^failed_login?$/i do
|
170
|
+
[FailedLoginTrigger, {}]
|
171
|
+
end
|
172
|
+
|
173
|
+
get /^Geofence (Entry|Exit) \(([^\)]+)/i do |direction, name|
|
174
|
+
enter_area = direction.downcase.to_sym == :entry
|
175
|
+
[GeofenceTrigger, {name: name, enter_area: enter_area}]
|
176
|
+
end
|
177
|
+
|
178
|
+
get /^location (entered|exited) \(([^\)]+)/i do |direction, name|
|
179
|
+
enter_area = direction.downcase.to_sym == :entered
|
180
|
+
[GeofenceTrigger, {name: name, enter_area: enter_area}]
|
181
|
+
end
|
182
|
+
|
183
|
+
# eg. Proximity Sensor (Near)
|
184
|
+
#
|
185
|
+
get /^Proximity Sensor \(([^\)]+)\)/i do |distance|
|
186
|
+
|
187
|
+
[ProximityTrigger, {distance: distance}]
|
188
|
+
end
|
33
189
|
|
190
|
+
|
191
|
+
|
34
192
|
end
|
35
193
|
|
36
194
|
alias find_trigger run_route
|
@@ -50,13 +208,105 @@ class ActionsNlp
|
|
50
208
|
|
51
209
|
def actions(params)
|
52
210
|
|
211
|
+
# e.g. message popup: hello world!
|
53
212
|
get /^message popup: (.*)/i do |msg|
|
54
213
|
[ToastAction, {msg: msg}]
|
55
214
|
end
|
56
215
|
|
57
|
-
|
216
|
+
# e.g. Popup Message 'hello world!'
|
217
|
+
get /^Popup[ _]Message ['"]([^'"]+)/i do |msg|
|
58
218
|
[ToastAction, {msg: msg}]
|
59
219
|
end
|
220
|
+
|
221
|
+
# e.g. say current time
|
222
|
+
get /^say current[ _]time/i do
|
223
|
+
[SayTimeAction, {}]
|
224
|
+
end
|
225
|
+
|
226
|
+
get /^Torch :?(.*)/i do |onoffstate|
|
227
|
+
state = onoffstate.downcase == 'on' ? 0 : 1
|
228
|
+
[CameraFlashLightAction, {state: state}]
|
229
|
+
end
|
230
|
+
|
231
|
+
get /^Take Picture/i do
|
232
|
+
[TakePictureAction, {}]
|
233
|
+
end
|
234
|
+
|
235
|
+
get /^take_picture/i do
|
236
|
+
[TakePictureAction, {}]
|
237
|
+
end
|
238
|
+
|
239
|
+
# e.g. Display Notification: Hi there: This is the body of the message
|
240
|
+
get /^Display Notification: ([^:]+): [^$]+$/i do |subject, text|
|
241
|
+
[NotificationAction, {subject: subject, text: text}]
|
242
|
+
end
|
243
|
+
|
244
|
+
|
245
|
+
# e.g. Enable Wifi
|
246
|
+
get /^(Enable|Disable) Wifi$/i do |raw_state|
|
247
|
+
|
248
|
+
state = raw_state.downcase.to_sym == :enable ? 0 : 1
|
249
|
+
[SetWifiAction, {state: state}]
|
250
|
+
|
251
|
+
end
|
252
|
+
|
253
|
+
# e.g. Play: Altair
|
254
|
+
get /^Play: (.*)$/i do |name|
|
255
|
+
|
256
|
+
[PlaySoundAction, {file_path: name}]
|
257
|
+
|
258
|
+
end
|
259
|
+
|
260
|
+
# e.g. Launch Settings
|
261
|
+
get /^Launch (.*)$/i do |application|
|
262
|
+
|
263
|
+
h = {
|
264
|
+
application_name: application,
|
265
|
+
package_to_launch: 'com.android.' + application.downcase
|
266
|
+
}
|
267
|
+
[LaunchActivityAction, h]
|
268
|
+
|
269
|
+
end
|
270
|
+
|
271
|
+
# e.g. HTTP GET http://someurl.com/something
|
272
|
+
get /^HTTP GET ([^$]+)$/i do |url|
|
273
|
+
|
274
|
+
[OpenWebPageAction, url_to_open: url]
|
275
|
+
|
276
|
+
end
|
277
|
+
|
278
|
+
# e.g. webhook entered_kitchen
|
279
|
+
#
|
280
|
+
get /webhook|HTTP GET/i do
|
281
|
+
[OpenWebPageAction, {}]
|
282
|
+
end
|
283
|
+
|
284
|
+
#a: Keep Device Awake Screen On Until Disabled
|
285
|
+
#
|
286
|
+
get /Keep Device Awake Screen On Until Disabled/i do
|
287
|
+
[KeepAwakeAction, {enabled: true, permanent: true, screen_option: 0}]
|
288
|
+
end
|
289
|
+
|
290
|
+
|
291
|
+
#a: Keep Device Awake Screen On 1h 1m 1s
|
292
|
+
#
|
293
|
+
get /Keep Device Awake Screen On ([^$]+)/i do |duration|
|
294
|
+
|
295
|
+
a = duration.split.map(&:to_i)
|
296
|
+
secs = Subunit.new(units={minutes:60, hours:60, seconds: 60}, a).to_i
|
297
|
+
|
298
|
+
h = {
|
299
|
+
permanent: true, screen_option: 0, seconds_to_stay_awake_for: secs
|
300
|
+
}
|
301
|
+
[KeepAwakeAction, h]
|
302
|
+
end
|
303
|
+
|
304
|
+
#a: Disable Keep Awake
|
305
|
+
#
|
306
|
+
get /Disable Keep Awake/i do
|
307
|
+
[KeepAwakeAction, {enabled: false, screen_option: 0}]
|
308
|
+
end
|
309
|
+
|
60
310
|
|
61
311
|
end
|
62
312
|
|
@@ -145,11 +395,11 @@ class Macro
|
|
145
395
|
using Params
|
146
396
|
|
147
397
|
attr_reader :local_variables, :triggers, :actions, :constraints, :guid
|
148
|
-
attr_accessor :title
|
398
|
+
attr_accessor :title, :description
|
149
399
|
|
150
|
-
def initialize(name=nil, debug: false)
|
400
|
+
def initialize(name=nil, geofences: geofences, debug: false)
|
151
401
|
|
152
|
-
@title, @debug = name, debug
|
402
|
+
@title, @geofences, @debug = name, geofences, debug
|
153
403
|
|
154
404
|
puts 'inside Macro#initialize' if @debug
|
155
405
|
|
@@ -209,6 +459,7 @@ class Macro
|
|
209
459
|
end
|
210
460
|
|
211
461
|
@title = h[:name]
|
462
|
+
@description = h[:description]
|
212
463
|
|
213
464
|
# fetch the local variables
|
214
465
|
@local_variables = h['local_variables']
|
@@ -239,18 +490,20 @@ class Macro
|
|
239
490
|
end
|
240
491
|
|
241
492
|
def import_xml(node)
|
242
|
-
|
493
|
+
|
243
494
|
if @debug then
|
244
495
|
puts 'inside Macro#import_xml'
|
245
496
|
puts 'node: ' + node.xml.inspect
|
246
497
|
end
|
247
498
|
|
248
|
-
@title = node.attributes[:name]
|
249
|
-
|
250
499
|
if node.element('triggers') then
|
251
|
-
|
500
|
+
|
252
501
|
# level 2
|
253
502
|
|
503
|
+
@title = node.attributes[:name]
|
504
|
+
@description = node.attributes[:description]
|
505
|
+
|
506
|
+
|
254
507
|
# get all the triggers
|
255
508
|
@triggers = node.xpath('triggers/*').map do |e|
|
256
509
|
|
@@ -286,6 +539,12 @@ class Macro
|
|
286
539
|
|
287
540
|
# Level 1
|
288
541
|
|
542
|
+
puts 'import_xml: inside level 1' if @debug
|
543
|
+
|
544
|
+
@title = node.text('macro') || node.attributes[:name]
|
545
|
+
|
546
|
+
#@description = node.attributes[:description]
|
547
|
+
|
289
548
|
tp = TriggersNlp.new
|
290
549
|
|
291
550
|
@triggers = node.xpath('trigger').map do |e|
|
@@ -295,7 +554,11 @@ class Macro
|
|
295
554
|
puts 'found trigger ' + r.inspect if @debug
|
296
555
|
|
297
556
|
if r then
|
298
|
-
r[0]
|
557
|
+
if r[0] == GeofenceTrigger then
|
558
|
+
GeofenceTrigger.new(r[1], geofences: @geofences)
|
559
|
+
else
|
560
|
+
r[0].new(r[1])
|
561
|
+
end
|
299
562
|
end
|
300
563
|
|
301
564
|
end
|
@@ -304,11 +567,21 @@ class Macro
|
|
304
567
|
|
305
568
|
@actions = node.xpath('action').map do |e|
|
306
569
|
|
570
|
+
puts 'action e: ' + e.xml.inspect if @debug
|
307
571
|
r = ap.find_action e.text
|
308
572
|
puts 'found action ' + r.inspect if @debug
|
309
573
|
|
310
574
|
if r then
|
311
|
-
|
575
|
+
|
576
|
+
a = e.xpath('item/*')
|
577
|
+
|
578
|
+
h = if a.any? then
|
579
|
+
a.map {|node| [node.name.to_sym, node.text.to_s]}.to_h
|
580
|
+
else
|
581
|
+
{}
|
582
|
+
end
|
583
|
+
|
584
|
+
r[0].new(r[1].merge(h))
|
312
585
|
end
|
313
586
|
|
314
587
|
end
|
@@ -355,17 +628,64 @@ class Macro
|
|
355
628
|
|
356
629
|
end
|
357
630
|
|
631
|
+
# invokes the actions
|
632
|
+
#
|
358
633
|
def run()
|
359
634
|
@actions.map(&:invoke)
|
360
|
-
end
|
635
|
+
end
|
636
|
+
|
637
|
+
# prepares the environment in order for triggers to test fire successfully
|
638
|
+
# Used for testing
|
639
|
+
#
|
640
|
+
def set_env()
|
641
|
+
@triggers.each(&:set_env)
|
642
|
+
end
|
643
|
+
|
644
|
+
def to_pc()
|
645
|
+
|
646
|
+
heading = '# ' + @title
|
647
|
+
heading += '\n# ' + @description if @description
|
648
|
+
condition = @triggers.first.to_pc
|
649
|
+
actions = @actions.map(&:to_pc).join("\n")
|
650
|
+
|
651
|
+
<<EOF
|
652
|
+
#{heading}
|
653
|
+
|
654
|
+
if #{condition} then
|
655
|
+
#{actions}
|
656
|
+
end
|
657
|
+
EOF
|
658
|
+
end
|
361
659
|
|
362
660
|
def to_s()
|
363
|
-
|
661
|
+
|
662
|
+
a = [
|
364
663
|
'm: ' + @title,
|
365
664
|
@triggers.map {|x| "t: %s" % x}.join("\n"),
|
366
665
|
@actions.map {|x| "a: %s" % x}.join("\n"),
|
367
666
|
@constraints.map {|x| "a: %s" % x}.join("\n")
|
368
|
-
]
|
667
|
+
]
|
668
|
+
|
669
|
+
if @description and @description.length >= 1 then
|
670
|
+
a.insert(1, 'd: ' + @description)
|
671
|
+
end
|
672
|
+
|
673
|
+
a.join("\n")
|
674
|
+
|
675
|
+
end
|
676
|
+
|
677
|
+
def to_summary()
|
678
|
+
|
679
|
+
a = [
|
680
|
+
'm: ' + @title,
|
681
|
+
't: ' + @triggers.map(&:to_summary).join(", "),
|
682
|
+
'a: ' + @actions.map(&:to_summary).join(", "),
|
683
|
+
]
|
684
|
+
|
685
|
+
a << 'c: ' + @constraints.map(&:to_summary).join(", ") if @constraints.any?
|
686
|
+
|
687
|
+
a.join("\n") + "\n"
|
688
|
+
|
369
689
|
end
|
370
690
|
|
371
691
|
private
|
@@ -378,34 +698,86 @@ class Macro
|
|
378
698
|
|
379
699
|
puts ('inside object h:' + h.inspect).debug if @debug
|
380
700
|
klass = Object.const_get h[:class_type]
|
381
|
-
klass.
|
701
|
+
puts klass.inspect.highlight if $debug
|
702
|
+
|
703
|
+
if klass == GeofenceTrigger then
|
704
|
+
puts 'GeofenceTrigger found'.highlight if $debug
|
705
|
+
GeofenceTrigger.new(h, geofences: @geofences)
|
706
|
+
else
|
707
|
+
klass.new h
|
708
|
+
end
|
709
|
+
|
382
710
|
end
|
383
711
|
|
384
712
|
end
|
385
713
|
|
386
714
|
|
715
|
+
class MacroDroidError < Exception
|
716
|
+
end
|
717
|
+
|
387
718
|
class MacroDroid
|
388
719
|
using ColouredText
|
389
720
|
using Params
|
390
721
|
|
391
|
-
attr_reader :macros
|
722
|
+
attr_reader :macros, :geofences
|
392
723
|
|
393
724
|
def initialize(obj=nil, debug: false)
|
394
725
|
|
395
726
|
@debug = debug
|
396
727
|
|
728
|
+
@geofences = {}
|
729
|
+
|
397
730
|
if obj then
|
398
731
|
|
399
|
-
|
732
|
+
raw_s, _ = RXFHelper.read(obj)
|
733
|
+
|
734
|
+
s = raw_s.strip
|
400
735
|
|
401
736
|
if s[0] == '{' then
|
737
|
+
|
402
738
|
import_json(s)
|
739
|
+
|
403
740
|
elsif s[0] == '<'
|
741
|
+
|
404
742
|
import_xml(s)
|
405
743
|
@h = build_h
|
744
|
+
|
406
745
|
else
|
407
|
-
|
746
|
+
|
747
|
+
puts 's: ' + s.inspect if @debug
|
748
|
+
|
749
|
+
if s =~ /m(?:acro)?:\s/ then
|
750
|
+
|
751
|
+
puts 'before RowX.new' if @debug
|
752
|
+
|
753
|
+
s2 = s.gsub(/^g:/,'geofence:').gsub(/^m:/,'macro:')\
|
754
|
+
.gsub(/^t:/,'trigger:').gsub(/^a:/,'action:')\
|
755
|
+
.gsub(/^c:/,'constraint:').gsub(/^#.*/,'')
|
756
|
+
|
757
|
+
raw_macros, raw_geofences = s2.split(/(?=^macro:)/,2).reverse
|
758
|
+
|
759
|
+
if raw_geofences then
|
760
|
+
|
761
|
+
geoxml = RowX.new(raw_geofences).to_xml
|
762
|
+
|
763
|
+
geodoc = Rexle.new(geoxml)
|
764
|
+
geofences = geodoc.root.xpath('item/geofence')
|
765
|
+
@geofences = fetch_geofences(geofences) if geofences.any?
|
766
|
+
|
767
|
+
end
|
768
|
+
|
769
|
+
xml = RowX.new(raw_macros).to_xml
|
770
|
+
import_rowxml(xml)
|
771
|
+
|
772
|
+
elsif s =~ /^# /
|
773
|
+
xml = pc_to_xml(s)
|
774
|
+
import_xml(xml)
|
775
|
+
else
|
776
|
+
raise MacroDroidError, 'invalid input'
|
777
|
+
end
|
778
|
+
|
408
779
|
@h = build_h
|
780
|
+
|
409
781
|
end
|
410
782
|
|
411
783
|
else
|
@@ -457,15 +829,94 @@ class MacroDroid
|
|
457
829
|
|
458
830
|
alias to_json export_json
|
459
831
|
|
832
|
+
|
833
|
+
def to_h()
|
834
|
+
|
835
|
+
h = {
|
836
|
+
geofence_data: {
|
837
|
+
geofence_map: @geofences.map {|key, value| [key, value.to_h] }.to_h
|
838
|
+
},
|
839
|
+
macro_list: @macros.map(&:to_h)
|
840
|
+
}
|
841
|
+
@h.merge(h).to_camel_case
|
842
|
+
|
843
|
+
end
|
844
|
+
|
845
|
+
# returns pseudocode
|
846
|
+
#
|
847
|
+
def to_pc()
|
848
|
+
@macros.map(&:to_pc).join("\n\n")
|
849
|
+
end
|
850
|
+
|
851
|
+
def to_s()
|
852
|
+
|
853
|
+
lines = []
|
854
|
+
|
855
|
+
if @geofences.any? then
|
856
|
+
lines << @geofences.map {|_, value| 'g: ' + value.to_s}.join("\n\n") + "\n"
|
857
|
+
end
|
858
|
+
|
859
|
+
lines << @macros.map(&:to_s).join("\n")
|
860
|
+
lines.join("\n")
|
861
|
+
|
862
|
+
end
|
863
|
+
|
864
|
+
def to_summary()
|
865
|
+
@macros.map(&:to_summary).join("\n")
|
866
|
+
end
|
867
|
+
|
868
|
+
private
|
869
|
+
|
870
|
+
def fetch_geofences(nodes)
|
871
|
+
|
872
|
+
nodes.map do |e|
|
873
|
+
|
874
|
+
name = e.text.to_s.strip
|
875
|
+
item = e.element('item')
|
876
|
+
coordinates = item.text('coordinates')
|
877
|
+
latitude, longitude = coordinates.split(/, */,2)
|
878
|
+
radius = item.text('radius')
|
879
|
+
|
880
|
+
id = UUID.new.generate
|
881
|
+
|
882
|
+
h = {
|
883
|
+
name: name,
|
884
|
+
longitude: longitude,
|
885
|
+
latitude: latitude,
|
886
|
+
radius: radius,
|
887
|
+
id: id
|
888
|
+
}
|
889
|
+
|
890
|
+
[id.to_sym, GeofenceMap.new(h)]
|
891
|
+
|
892
|
+
end.to_h
|
893
|
+
|
894
|
+
end
|
895
|
+
|
460
896
|
def import_json(s)
|
461
897
|
|
462
|
-
|
898
|
+
h = JSON.parse(s, symbolize_names: true)
|
899
|
+
puts 'json_to_yaml: ' + h.to_yaml if @debug
|
900
|
+
|
901
|
+
@h = h.to_snake_case
|
463
902
|
puts ('@h: ' + @h.inspect).debug if @debug
|
464
|
-
|
903
|
+
|
904
|
+
|
905
|
+
# fetch the geofence data
|
906
|
+
if @h[:geofence_data] then
|
907
|
+
|
908
|
+
@geofences = @h[:geofence_data][:geofence_map].map do |id, properties|
|
909
|
+
[id, GeofenceMap.new(properties)]
|
910
|
+
end.to_h
|
911
|
+
|
912
|
+
end
|
913
|
+
|
465
914
|
@macros = @h[:macro_list].map do |macro|
|
466
915
|
|
467
916
|
puts ('macro: ' + macro.inspect).debug if @debug
|
468
|
-
|
917
|
+
# puts '@geofences: ' + @geofences.inspect if @debug
|
918
|
+
|
919
|
+
m = Macro.new(geofences: @geofences.map(&:last), debug: @debug )
|
469
920
|
m.import_h(macro)
|
470
921
|
m
|
471
922
|
|
@@ -475,59 +926,99 @@ class MacroDroid
|
|
475
926
|
|
476
927
|
end
|
477
928
|
|
929
|
+
def import_rowxml(raws)
|
930
|
+
|
931
|
+
s = RXFHelper.read(raws).first
|
932
|
+
puts 's: ' + s.inspect if @debug
|
933
|
+
doc = Rexle.new(s)
|
934
|
+
puts 'after doc' if @debug
|
935
|
+
puts 'import_rowxml: @geofences: ' + @geofences.inspect if @debug
|
936
|
+
geofences = @geofences
|
937
|
+
|
938
|
+
@macros = doc.root.xpath('item').map do |node|
|
939
|
+
puts ('geofences: ' + geofences.inspect).highlight if @debug
|
940
|
+
Macro.new(geofences: geofences.map(&:last), debug: @debug).import_xml(node)
|
941
|
+
|
942
|
+
end
|
943
|
+
|
944
|
+
end
|
945
|
+
|
478
946
|
def import_xml(raws)
|
479
947
|
|
948
|
+
if @debug then
|
949
|
+
puts 'inside import_xml'
|
950
|
+
|
951
|
+
puts 'raws: ' + raws.inspect
|
952
|
+
end
|
480
953
|
s = RXFHelper.read(raws).first
|
481
954
|
puts 's: ' + s.inspect if @debug
|
482
955
|
doc = Rexle.new(s)
|
483
|
-
puts 'after doc' if @debug
|
484
956
|
|
957
|
+
if @debug then
|
958
|
+
puts 'doc: ' + doc.root.xml
|
959
|
+
end
|
960
|
+
|
485
961
|
@macros = doc.root.xpath('macro').map do |node|
|
486
962
|
|
487
|
-
|
488
|
-
macro.import_xml(node)
|
489
|
-
macro
|
963
|
+
Macro.new(geofences: @geofences.map(&:last), debug: @debug).import_xml(node)
|
490
964
|
|
491
965
|
end
|
492
966
|
end
|
493
967
|
|
494
|
-
def
|
968
|
+
def pc_to_xml(s)
|
495
969
|
|
496
|
-
|
497
|
-
a.map!(&:chomp)
|
498
|
-
|
499
|
-
macros = a.map do |x|
|
500
|
-
|
501
|
-
lines = x.lines
|
502
|
-
puts 'lines: ' + lines.inspect if @debug
|
503
|
-
|
504
|
-
name = lines.shift[/^m: +(.*)/,1]
|
505
|
-
h = {t: [], a: [], c: []}
|
970
|
+
macros = s.strip.split(/(?=#)/).map do |raw_macro|
|
506
971
|
|
507
|
-
|
508
|
-
|
509
|
-
|
510
|
-
|
972
|
+
a = raw_macro.lines
|
973
|
+
name = a.shift[/(?<=# ).*/]
|
974
|
+
description = a.shift[/(?<=# ).*/] if a[0][/^# /]
|
975
|
+
body = a.join.strip
|
511
976
|
|
512
|
-
|
977
|
+
a2 = body.lines
|
978
|
+
# get the trigger
|
979
|
+
trigger = [:trigger, {}, a2[0][/^if (.*) then/,1]]
|
980
|
+
action = [:action, {}, a2[1].strip]
|
981
|
+
[:macro, {name: name, description: description}, trigger, action, []]
|
513
982
|
|
514
983
|
end
|
515
984
|
|
516
985
|
doc = Rexle.new([:macros, {}, '', *macros])
|
517
986
|
doc.root.xml pretty: true
|
518
987
|
|
519
|
-
end
|
520
|
-
|
521
|
-
def to_h()
|
988
|
+
end
|
522
989
|
|
523
|
-
|
990
|
+
end
|
524
991
|
|
992
|
+
class GeofenceMap
|
993
|
+
|
994
|
+
attr_accessor :name, :longitude, :latitude, :radius, :id
|
995
|
+
|
996
|
+
def initialize(id: '', longitude: '', latitude: '', name: '', radius: '')
|
997
|
+
|
998
|
+
@id, @latitude, @longitude, @name, @radius = id, latitude, \
|
999
|
+
longitude, name, radius
|
1000
|
+
|
525
1001
|
end
|
526
|
-
|
1002
|
+
|
1003
|
+
def to_h()
|
1004
|
+
|
1005
|
+
{
|
1006
|
+
id: @id,
|
1007
|
+
longitude: @longitude,
|
1008
|
+
latitude: @latitude,
|
1009
|
+
name: @name,
|
1010
|
+
radius: @radius
|
1011
|
+
}
|
1012
|
+
|
1013
|
+
end
|
1014
|
+
|
527
1015
|
def to_s()
|
528
|
-
|
1016
|
+
|
1017
|
+
coordinates = "%s, %s" % [@longitude, @latitude]
|
1018
|
+
"%s\n coordinates: %s\n radius: %s" % [@name, coordinates, @radius]
|
1019
|
+
|
529
1020
|
end
|
530
|
-
|
1021
|
+
|
531
1022
|
end
|
532
1023
|
|
533
1024
|
class MacroObject
|
@@ -538,6 +1029,8 @@ class MacroObject
|
|
538
1029
|
|
539
1030
|
def initialize(h={})
|
540
1031
|
|
1032
|
+
$env ||= {}
|
1033
|
+
|
541
1034
|
@h = {constraint_list: [], is_or_condition: false,
|
542
1035
|
is_disabled: false}.merge(h)
|
543
1036
|
@list = []
|
@@ -566,6 +1059,12 @@ class MacroObject
|
|
566
1059
|
h2.merge('m_classType' => self.class.to_s)
|
567
1060
|
|
568
1061
|
end
|
1062
|
+
|
1063
|
+
def to_s()
|
1064
|
+
"#<%s %s>" % [self.class, @h.inspect]
|
1065
|
+
end
|
1066
|
+
|
1067
|
+
alias to_summary to_s
|
569
1068
|
|
570
1069
|
protected
|
571
1070
|
|
@@ -1080,29 +1579,26 @@ class TimerTrigger < Trigger
|
|
1080
1579
|
use_alarm: false
|
1081
1580
|
}
|
1082
1581
|
|
1083
|
-
super(options.merge filter(options,h))
|
1582
|
+
super(options.merge filter(options, h))
|
1084
1583
|
|
1085
1584
|
end
|
1086
1585
|
|
1087
1586
|
def match?(detail={time: $env[:time]}, model=nil)
|
1088
|
-
|
1089
|
-
a = @h[:days_of_week]
|
1090
|
-
a.unshift a.pop
|
1091
|
-
|
1092
|
-
dow = a.map.with_index {|x, i| x ? i : nil }.compact.join(',')
|
1093
|
-
|
1094
|
-
s = "%s %s * * %s" % [@h[:minute], @h[:hour], dow]
|
1095
|
-
|
1096
|
-
if $debug then
|
1097
|
-
puts 's: ' + s.inspect
|
1098
|
-
puts 'detail: ' + detail.inspect
|
1099
|
-
puts '@h: ' + @h.inspect
|
1100
|
-
end
|
1101
1587
|
|
1102
|
-
|
1588
|
+
time() == detail[:time]
|
1103
1589
|
|
1104
1590
|
end
|
1105
1591
|
|
1592
|
+
# sets the environmental conditions for this trigger to fire
|
1593
|
+
#
|
1594
|
+
def set_env()
|
1595
|
+
$env[:time] = time()
|
1596
|
+
end
|
1597
|
+
|
1598
|
+
def to_pc()
|
1599
|
+
"time.is? '%s'" % self.to_s.gsub(',', ' or')
|
1600
|
+
end
|
1601
|
+
|
1106
1602
|
def to_s()
|
1107
1603
|
|
1108
1604
|
dow = @h[:days_of_week]
|
@@ -1114,6 +1610,20 @@ class TimerTrigger < Trigger
|
|
1114
1610
|
|
1115
1611
|
"at %s on %s" % [time, days.join(', ')]
|
1116
1612
|
end
|
1613
|
+
|
1614
|
+
private
|
1615
|
+
|
1616
|
+
def time()
|
1617
|
+
|
1618
|
+
a = @h[:days_of_week].clone
|
1619
|
+
a.unshift a.pop
|
1620
|
+
|
1621
|
+
dow = a.map.with_index {|x, i| x ? i : nil }.compact.join(',')
|
1622
|
+
s = "%s %s * * %s" % [@h[:minute], @h[:hour], dow]
|
1623
|
+
recent_time = ($env && $env[:time]) ? $env[:time] : Time.now
|
1624
|
+
ChronicCron.new(s, recent_time).to_time
|
1625
|
+
|
1626
|
+
end
|
1117
1627
|
|
1118
1628
|
end
|
1119
1629
|
|
@@ -1185,6 +1695,15 @@ class RegularIntervalTrigger < Trigger
|
|
1185
1695
|
|
1186
1696
|
end
|
1187
1697
|
|
1698
|
+
class DeviceEventsTrigger < Trigger
|
1699
|
+
|
1700
|
+
def initialize(h={})
|
1701
|
+
super(h)
|
1702
|
+
@group = 'device_events'
|
1703
|
+
end
|
1704
|
+
|
1705
|
+
end
|
1706
|
+
|
1188
1707
|
# Category: Device Events
|
1189
1708
|
#
|
1190
1709
|
# Airplane Mode Changed
|
@@ -1196,7 +1715,7 @@ end
|
|
1196
1715
|
# shorthand example:
|
1197
1716
|
# airplanemode: enabled
|
1198
1717
|
#
|
1199
|
-
class AirplaneModeTrigger <
|
1718
|
+
class AirplaneModeTrigger < DeviceEventsTrigger
|
1200
1719
|
|
1201
1720
|
def initialize(h={})
|
1202
1721
|
|
@@ -1212,7 +1731,7 @@ end
|
|
1212
1731
|
|
1213
1732
|
# Category: Device Events
|
1214
1733
|
#
|
1215
|
-
class AutoSyncChangeTrigger <
|
1734
|
+
class AutoSyncChangeTrigger < DeviceEventsTrigger
|
1216
1735
|
|
1217
1736
|
def initialize(h={})
|
1218
1737
|
|
@@ -1228,7 +1747,7 @@ end
|
|
1228
1747
|
|
1229
1748
|
# Category: Device Events
|
1230
1749
|
#
|
1231
|
-
class DayDreamTrigger <
|
1750
|
+
class DayDreamTrigger < DeviceEventsTrigger
|
1232
1751
|
|
1233
1752
|
def initialize(h={})
|
1234
1753
|
|
@@ -1244,7 +1763,7 @@ end
|
|
1244
1763
|
|
1245
1764
|
# Category: Device Events
|
1246
1765
|
#
|
1247
|
-
class DockTrigger <
|
1766
|
+
class DockTrigger < DeviceEventsTrigger
|
1248
1767
|
|
1249
1768
|
def initialize(h={})
|
1250
1769
|
|
@@ -1260,7 +1779,30 @@ end
|
|
1260
1779
|
|
1261
1780
|
# Category: Device Events
|
1262
1781
|
#
|
1263
|
-
class
|
1782
|
+
class FailedLoginTrigger < DeviceEventsTrigger
|
1783
|
+
|
1784
|
+
def initialize(h={})
|
1785
|
+
|
1786
|
+
options = {
|
1787
|
+
num_failures: 1
|
1788
|
+
}
|
1789
|
+
|
1790
|
+
super(options.merge h)
|
1791
|
+
|
1792
|
+
end
|
1793
|
+
|
1794
|
+
def to_pc()
|
1795
|
+
'failed_login?'
|
1796
|
+
end
|
1797
|
+
|
1798
|
+
def to_s()
|
1799
|
+
'Failed Login Attempt'
|
1800
|
+
end
|
1801
|
+
end
|
1802
|
+
|
1803
|
+
# Category: Device Events
|
1804
|
+
#
|
1805
|
+
class GPSEnabledTrigger < DeviceEventsTrigger
|
1264
1806
|
|
1265
1807
|
def initialize(h={})
|
1266
1808
|
|
@@ -1276,7 +1818,7 @@ end
|
|
1276
1818
|
|
1277
1819
|
# Category: Device Events
|
1278
1820
|
#
|
1279
|
-
class MusicPlayingTrigger <
|
1821
|
+
class MusicPlayingTrigger < DeviceEventsTrigger
|
1280
1822
|
|
1281
1823
|
def initialize(h={})
|
1282
1824
|
|
@@ -1293,7 +1835,7 @@ end
|
|
1293
1835
|
|
1294
1836
|
# Category: Device Events
|
1295
1837
|
#
|
1296
|
-
class DeviceUnlockedTrigger <
|
1838
|
+
class DeviceUnlockedTrigger < DeviceEventsTrigger
|
1297
1839
|
|
1298
1840
|
def initialize(h={})
|
1299
1841
|
|
@@ -1308,7 +1850,7 @@ end
|
|
1308
1850
|
|
1309
1851
|
# Category: Device Events
|
1310
1852
|
#
|
1311
|
-
class AutoRotateChangeTrigger <
|
1853
|
+
class AutoRotateChangeTrigger < DeviceEventsTrigger
|
1312
1854
|
|
1313
1855
|
def initialize(h={})
|
1314
1856
|
|
@@ -1324,7 +1866,7 @@ end
|
|
1324
1866
|
|
1325
1867
|
# Category: Device Events
|
1326
1868
|
#
|
1327
|
-
class ClipboardChangeTrigger <
|
1869
|
+
class ClipboardChangeTrigger < DeviceEventsTrigger
|
1328
1870
|
|
1329
1871
|
def initialize(h={})
|
1330
1872
|
|
@@ -1341,7 +1883,7 @@ end
|
|
1341
1883
|
|
1342
1884
|
# Category: Device Events
|
1343
1885
|
#
|
1344
|
-
class BootTrigger <
|
1886
|
+
class BootTrigger < DeviceEventsTrigger
|
1345
1887
|
|
1346
1888
|
def initialize(h={})
|
1347
1889
|
|
@@ -1356,7 +1898,7 @@ end
|
|
1356
1898
|
|
1357
1899
|
# Category: Device Events
|
1358
1900
|
#
|
1359
|
-
class IntentReceivedTrigger <
|
1901
|
+
class IntentReceivedTrigger < DeviceEventsTrigger
|
1360
1902
|
|
1361
1903
|
def initialize(h={})
|
1362
1904
|
|
@@ -1376,7 +1918,7 @@ end
|
|
1376
1918
|
|
1377
1919
|
# Category: Device Events
|
1378
1920
|
#
|
1379
|
-
class NotificationTrigger <
|
1921
|
+
class NotificationTrigger < DeviceEventsTrigger
|
1380
1922
|
|
1381
1923
|
def initialize(h={})
|
1382
1924
|
|
@@ -1402,7 +1944,7 @@ end
|
|
1402
1944
|
|
1403
1945
|
# Category: Device Events
|
1404
1946
|
#
|
1405
|
-
class ScreenOnOffTrigger <
|
1947
|
+
class ScreenOnOffTrigger < DeviceEventsTrigger
|
1406
1948
|
|
1407
1949
|
def initialize(h={})
|
1408
1950
|
|
@@ -1418,7 +1960,7 @@ end
|
|
1418
1960
|
|
1419
1961
|
# Category: Device Events
|
1420
1962
|
#
|
1421
|
-
class SilentModeTrigger <
|
1963
|
+
class SilentModeTrigger < DeviceEventsTrigger
|
1422
1964
|
|
1423
1965
|
def initialize(h={})
|
1424
1966
|
|
@@ -1461,8 +2003,15 @@ end
|
|
1461
2003
|
#
|
1462
2004
|
class GeofenceTrigger < Trigger
|
1463
2005
|
|
1464
|
-
def initialize(h={})
|
2006
|
+
def initialize( h={}, geofences: {})
|
1465
2007
|
|
2008
|
+
if h[:name] then
|
2009
|
+
puts ('geofences2: ' + geofences.inspect)
|
2010
|
+
found = geofences.find {|x| x.name.downcase == h[:name].downcase}
|
2011
|
+
h[:geofence_id] = found.id if found
|
2012
|
+
|
2013
|
+
end
|
2014
|
+
|
1466
2015
|
options = {
|
1467
2016
|
update_rate_text: '5 Minutes',
|
1468
2017
|
geofence_id: '',
|
@@ -1471,9 +2020,28 @@ class GeofenceTrigger < Trigger
|
|
1471
2020
|
enter_area: true
|
1472
2021
|
}
|
1473
2022
|
|
1474
|
-
super(options.merge h)
|
2023
|
+
super(options.merge filter(options, h))
|
2024
|
+
@geofences = geofences
|
1475
2025
|
|
1476
2026
|
end
|
2027
|
+
|
2028
|
+
def to_s()
|
2029
|
+
|
2030
|
+
if $debug then
|
2031
|
+
puts ' @geofences: ' + @geofences.inspect
|
2032
|
+
puts '@h: ' + @h.inspect
|
2033
|
+
puts '@h[:geofence_id]: ' + @h[:geofence_id].inspect
|
2034
|
+
end
|
2035
|
+
|
2036
|
+
direction = @h[:enter_area] ? 'Entry' : 'Exit'
|
2037
|
+
|
2038
|
+
found = @geofences.find {|x| x.id == @h[:geofence_id]}
|
2039
|
+
puts 'found: ' + found.inspect if @debug
|
2040
|
+
label = found ? found.name : 'error: name not found'
|
2041
|
+
|
2042
|
+
"Geofence %s (%s)" % [direction, label]
|
2043
|
+
|
2044
|
+
end
|
1477
2045
|
|
1478
2046
|
end
|
1479
2047
|
|
@@ -1494,9 +2062,19 @@ class SunriseSunsetTrigger < Trigger
|
|
1494
2062
|
|
1495
2063
|
end
|
1496
2064
|
|
2065
|
+
|
2066
|
+
class SensorsTrigger < Trigger
|
2067
|
+
|
2068
|
+
def initialize(h={})
|
2069
|
+
super(h)
|
2070
|
+
@group = 'sensors'
|
2071
|
+
end
|
2072
|
+
|
2073
|
+
end
|
2074
|
+
|
1497
2075
|
# Category: Sensors
|
1498
2076
|
#
|
1499
|
-
class ActivityRecognitionTrigger <
|
2077
|
+
class ActivityRecognitionTrigger < SensorsTrigger
|
1500
2078
|
|
1501
2079
|
def initialize(h={})
|
1502
2080
|
|
@@ -1506,31 +2084,70 @@ class ActivityRecognitionTrigger < Trigger
|
|
1506
2084
|
}
|
1507
2085
|
|
1508
2086
|
super(options.merge h)
|
2087
|
+
|
2088
|
+
@activity = ['In Vehicle', 'On Bicycle', 'Running', 'Walking', 'Still']
|
1509
2089
|
|
1510
2090
|
end
|
2091
|
+
|
2092
|
+
def to_s()
|
2093
|
+
activity = @activity[@h[:selected_index]]
|
2094
|
+
'Activity - ' + activity
|
2095
|
+
end
|
2096
|
+
|
2097
|
+
def to_summary
|
2098
|
+
|
2099
|
+
activity = @activity[@h[:selected_index]]
|
2100
|
+
s = if activity.length > 10 then
|
2101
|
+
activity[0..7] + '..'
|
2102
|
+
else
|
2103
|
+
activity
|
2104
|
+
end
|
2105
|
+
|
2106
|
+
'Activity - ' + s
|
2107
|
+
|
2108
|
+
end
|
1511
2109
|
|
1512
2110
|
end
|
1513
2111
|
|
1514
2112
|
# Category: Sensors
|
1515
2113
|
#
|
1516
|
-
class ProximityTrigger <
|
2114
|
+
class ProximityTrigger < SensorsTrigger
|
1517
2115
|
|
1518
2116
|
def initialize(h={})
|
1519
2117
|
|
2118
|
+
if h[:distance] then
|
2119
|
+
|
2120
|
+
case h[:distance].to_sym
|
2121
|
+
when :near
|
2122
|
+
options[:near] = true
|
2123
|
+
end
|
2124
|
+
end
|
2125
|
+
|
1520
2126
|
options = {
|
1521
2127
|
near: true,
|
1522
2128
|
selected_option: 0
|
1523
2129
|
}
|
1524
2130
|
|
1525
|
-
super(options.merge h)
|
2131
|
+
super(options.merge filter(options,h))
|
1526
2132
|
|
1527
2133
|
end
|
2134
|
+
|
2135
|
+
def to_s()
|
2136
|
+
|
2137
|
+
distance = if @h[:near] then
|
2138
|
+
'Near'
|
2139
|
+
else
|
2140
|
+
'Far'
|
2141
|
+
end
|
2142
|
+
|
2143
|
+
"Proximity Sensor (%s)" % distance
|
2144
|
+
end
|
1528
2145
|
|
1529
2146
|
end
|
1530
2147
|
|
1531
2148
|
# Category: Sensors
|
1532
2149
|
#
|
1533
|
-
class ShakeDeviceTrigger <
|
2150
|
+
class ShakeDeviceTrigger < SensorsTrigger
|
1534
2151
|
|
1535
2152
|
def initialize(h={})
|
1536
2153
|
|
@@ -1540,12 +2157,25 @@ class ShakeDeviceTrigger < Trigger
|
|
1540
2157
|
super(options.merge h)
|
1541
2158
|
|
1542
2159
|
end
|
2160
|
+
|
2161
|
+
def to_pc()
|
2162
|
+
'shake_device?'
|
2163
|
+
end
|
2164
|
+
|
2165
|
+
def to_s()
|
2166
|
+
'Shake Device'
|
2167
|
+
end
|
1543
2168
|
|
1544
2169
|
end
|
1545
2170
|
|
1546
2171
|
# Category: Sensors
|
1547
2172
|
#
|
1548
|
-
|
2173
|
+
# options:
|
2174
|
+
# Face Up -> Face Down
|
2175
|
+
# Face Down -> Face Up
|
2176
|
+
# Any -> Face Down
|
2177
|
+
#
|
2178
|
+
class FlipDeviceTrigger < SensorsTrigger
|
1549
2179
|
|
1550
2180
|
def initialize(h={})
|
1551
2181
|
|
@@ -1557,13 +2187,23 @@ class FlipDeviceTrigger < Trigger
|
|
1557
2187
|
|
1558
2188
|
super(options.merge h)
|
1559
2189
|
|
2190
|
+
end
|
2191
|
+
|
2192
|
+
def to_pc()
|
2193
|
+
@h[:face_down] ? 'flip_device_down?' : 'flip_device_up?'
|
1560
2194
|
end
|
2195
|
+
|
2196
|
+
def to_s()
|
2197
|
+
|
2198
|
+
action = @h[:face_down] ? 'Face Up -> Face Down' : 'Face Down -> Face Up'
|
2199
|
+
'Flip Device ' + action
|
2200
|
+
end
|
1561
2201
|
|
1562
2202
|
end
|
1563
2203
|
|
1564
2204
|
# Category: Sensors
|
1565
2205
|
#
|
1566
|
-
class OrientationTrigger <
|
2206
|
+
class OrientationTrigger < SensorsTrigger
|
1567
2207
|
|
1568
2208
|
def initialize(h={})
|
1569
2209
|
|
@@ -1745,6 +2385,10 @@ class LaunchActivityAction < ApplicationAction
|
|
1745
2385
|
super(options.merge h)
|
1746
2386
|
|
1747
2387
|
end
|
2388
|
+
|
2389
|
+
def to_s()
|
2390
|
+
'Launch ' + @h[:application_name]
|
2391
|
+
end
|
1748
2392
|
|
1749
2393
|
end
|
1750
2394
|
|
@@ -1770,6 +2414,8 @@ end
|
|
1770
2414
|
class OpenWebPageAction < ApplicationAction
|
1771
2415
|
|
1772
2416
|
def initialize(h={})
|
2417
|
+
|
2418
|
+
h[:url_to_open] = h[:url] if h[:url]
|
1773
2419
|
|
1774
2420
|
options = {
|
1775
2421
|
variable_to_save_response: {:m_stringValue=>"", :m_name=>"", :m_decimalValue=>0.0, :isLocal=>true, :m_booleanValue=>false, :excludeFromLog=>false, :m_intValue=>0, :m_type=>2},
|
@@ -1779,9 +2425,13 @@ class OpenWebPageAction < ApplicationAction
|
|
1779
2425
|
block_next_action: false
|
1780
2426
|
}
|
1781
2427
|
|
1782
|
-
super(options.merge h)
|
2428
|
+
super(options.merge filter(options,h))
|
1783
2429
|
|
1784
2430
|
end
|
2431
|
+
|
2432
|
+
def to_s()
|
2433
|
+
"HTTP GET\n url: " + @h[:url_to_open]
|
2434
|
+
end
|
1785
2435
|
|
1786
2436
|
end
|
1787
2437
|
|
@@ -1829,6 +2479,15 @@ class TakePictureAction < CameraAction
|
|
1829
2479
|
super(options.merge h)
|
1830
2480
|
|
1831
2481
|
end
|
2482
|
+
|
2483
|
+
def to_pc()
|
2484
|
+
camera = @h[:use_front_camera] ? :front : :back
|
2485
|
+
'take_photo :' + camera.to_s
|
2486
|
+
end
|
2487
|
+
|
2488
|
+
def to_s()
|
2489
|
+
'Take Picture'
|
2490
|
+
end
|
1832
2491
|
|
1833
2492
|
end
|
1834
2493
|
|
@@ -1857,6 +2516,11 @@ class SetWifiAction < ConnectivityAction
|
|
1857
2516
|
super(options.merge h)
|
1858
2517
|
|
1859
2518
|
end
|
2519
|
+
|
2520
|
+
def to_s()
|
2521
|
+
action = @h[:state] == 0 ? 'Enable' : 'Disable'
|
2522
|
+
action + ' Wifi'
|
2523
|
+
end
|
1860
2524
|
|
1861
2525
|
end
|
1862
2526
|
|
@@ -1987,6 +2651,20 @@ class SayTimeAction < DateTimeAction
|
|
1987
2651
|
super(options.merge h)
|
1988
2652
|
|
1989
2653
|
end
|
2654
|
+
|
2655
|
+
def invoke()
|
2656
|
+
time = ($env and $env[:time]) ? $env[:time] : Time.now
|
2657
|
+
tformat = @h['12_hour'] ? "%-I:%M%P" : "%H:%M"
|
2658
|
+
super(time.strftime(tformat))
|
2659
|
+
end
|
2660
|
+
|
2661
|
+
def to_pc()
|
2662
|
+
'say current_time()'
|
2663
|
+
end
|
2664
|
+
|
2665
|
+
def to_s()
|
2666
|
+
'Say Current Time'
|
2667
|
+
end
|
1990
2668
|
|
1991
2669
|
end
|
1992
2670
|
|
@@ -2067,6 +2745,10 @@ class SpeakTextAction < DeviceAction
|
|
2067
2745
|
super(options.merge h)
|
2068
2746
|
|
2069
2747
|
end
|
2748
|
+
|
2749
|
+
def to_s()
|
2750
|
+
"Speak Text (%s)" % @h[:text_to_say]
|
2751
|
+
end
|
2070
2752
|
|
2071
2753
|
end
|
2072
2754
|
|
@@ -2158,6 +2840,14 @@ class CameraFlashLightAction < DeviceSettingsAction
|
|
2158
2840
|
|
2159
2841
|
end
|
2160
2842
|
|
2843
|
+
def to_pc()
|
2844
|
+
'torch :on'
|
2845
|
+
end
|
2846
|
+
|
2847
|
+
def to_s()
|
2848
|
+
'Torch On'
|
2849
|
+
end
|
2850
|
+
|
2161
2851
|
end
|
2162
2852
|
|
2163
2853
|
# Category: Device Settings
|
@@ -2495,6 +3185,10 @@ class PlaySoundAction < MediaAction
|
|
2495
3185
|
super(options.merge h)
|
2496
3186
|
|
2497
3187
|
end
|
3188
|
+
|
3189
|
+
def to_s()
|
3190
|
+
'Play: ' + @h[:file_path]
|
3191
|
+
end
|
2498
3192
|
|
2499
3193
|
end
|
2500
3194
|
|
@@ -2699,6 +3393,9 @@ end
|
|
2699
3393
|
class NotificationAction < NotificationsAction
|
2700
3394
|
|
2701
3395
|
def initialize(h={})
|
3396
|
+
|
3397
|
+
h[:notification_subject] = h[:subject] if h[:subject]
|
3398
|
+
h[:notification_text] = h[:text] if h[:text]
|
2702
3399
|
|
2703
3400
|
options = {
|
2704
3401
|
ringtone_name: 'Default',
|
@@ -2714,9 +3411,13 @@ class NotificationAction < NotificationsAction
|
|
2714
3411
|
run_macro_when_pressed: false
|
2715
3412
|
}
|
2716
3413
|
|
2717
|
-
super(options.merge h)
|
3414
|
+
super(options.merge filter(options, h))
|
2718
3415
|
|
2719
3416
|
end
|
3417
|
+
|
3418
|
+
def to_s()
|
3419
|
+
'Display Notification: ' + "%s: %s" % [@h[:notification_subject], @h[:notification_text]]
|
3420
|
+
end
|
2720
3421
|
|
2721
3422
|
end
|
2722
3423
|
|
@@ -2750,6 +3451,10 @@ class ToastAction < NotificationsAction
|
|
2750
3451
|
super(@h[:message_text])
|
2751
3452
|
end
|
2752
3453
|
|
3454
|
+
def to_pc()
|
3455
|
+
"popup_message '%s'" % @h[:message_text]
|
3456
|
+
end
|
3457
|
+
|
2753
3458
|
def to_s()
|
2754
3459
|
"Popup Message '%s'" % @h[:message_text]
|
2755
3460
|
end
|
@@ -2945,6 +3650,10 @@ end
|
|
2945
3650
|
|
2946
3651
|
# Category: Screen
|
2947
3652
|
#
|
3653
|
+
# options:
|
3654
|
+
# keep awake, screen on => enabled: true
|
3655
|
+
# disable keep awake => enabled: false
|
3656
|
+
#
|
2948
3657
|
class KeepAwakeAction < ScreenAction
|
2949
3658
|
|
2950
3659
|
def initialize(h={})
|
@@ -2959,7 +3668,30 @@ class KeepAwakeAction < ScreenAction
|
|
2959
3668
|
super(options.merge h)
|
2960
3669
|
|
2961
3670
|
end
|
2962
|
-
|
3671
|
+
|
3672
|
+
def to_s()
|
3673
|
+
|
3674
|
+
screen = @h[:screen_option] == 0 ? 'Screen On' : 'Screen Off'
|
3675
|
+
|
3676
|
+
if @h[:enabled] then
|
3677
|
+
|
3678
|
+
whenx = if @h[:seconds_to_stay_awake_for] == 0 then
|
3679
|
+
|
3680
|
+
'Until Disabled'
|
3681
|
+
|
3682
|
+
else
|
3683
|
+
scnds = @h[:seconds_to_stay_awake_for]
|
3684
|
+
Subunit.new(units={minutes:60, hours:60}, seconds: scnds).strfunit("%x")
|
3685
|
+
end
|
3686
|
+
|
3687
|
+
'Keep Device Awake ' + screen + ' ' + whenx
|
3688
|
+
|
3689
|
+
else
|
3690
|
+
'Disable Keep Awake'
|
3691
|
+
end
|
3692
|
+
|
3693
|
+
|
3694
|
+
end
|
2963
3695
|
end
|
2964
3696
|
|
2965
3697
|
# Category: Screen
|
@@ -3489,6 +4221,18 @@ class AirplaneModeConstraint < Constraint
|
|
3489
4221
|
end
|
3490
4222
|
|
3491
4223
|
end
|
4224
|
+
|
4225
|
+
def to_pc()
|
4226
|
+
status = @h[:enabled] ? 'enabled?' : 'disabled?'
|
4227
|
+
'airplane_mode.' + status
|
4228
|
+
end
|
4229
|
+
|
4230
|
+
def to_s()
|
4231
|
+
|
4232
|
+
status = @h[:enabled] ? 'Enabled' : 'Disabled'
|
4233
|
+
'Airplane Mode ' + status
|
4234
|
+
|
4235
|
+
end
|
3492
4236
|
|
3493
4237
|
end
|
3494
4238
|
|