ruby-macrodroid 0.5.0 → 0.7.1
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 +800 -89
- metadata +66 -6
- metadata.gz.sig +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a2f43b1d737df8ffc21bb31f9a7df56964963ba3b88a6e51e008c45ca0d4e5f6
|
4
|
+
data.tar.gz: 6e587a62b683867b37f28dfba70728971e19647cfa803a804ea123c1eb0955b3
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b247e2d22eac6c837d9bcacf38697b63ab80a41c2affca2adb7389b39423813c9d1816f9c9dd697a013ad75b5417ca2143ca4e040be819a09a67a939765aae2f
|
7
|
+
data.tar.gz: 1a91db74afbbfbe1622d3e19241c9a99ddd05c0ef975e7ac037102104497d12a191c305a4ceb9ab0f5d7d7d476060398b4648ea927bc3135ab52b5633f562e0f
|
checksums.yaml.gz.sig
CHANGED
Binary file
|
data.tar.gz.sig
CHANGED
Binary file
|
data/lib/ruby-macrodroid.rb
CHANGED
@@ -2,11 +2,126 @@
|
|
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'
|
6
115
|
require 'rxfhelper'
|
7
116
|
require 'chronic_cron'
|
8
117
|
|
9
118
|
|
119
|
+
MODEL =<<EOF
|
120
|
+
device
|
121
|
+
connectivity
|
122
|
+
airplane_mode is disabled
|
123
|
+
EOF
|
124
|
+
|
10
125
|
class TriggersNlp
|
11
126
|
include AppRoutes
|
12
127
|
|
@@ -20,11 +135,50 @@ class TriggersNlp
|
|
20
135
|
|
21
136
|
def triggers(params)
|
22
137
|
|
23
|
-
get /^at (\d+:\d+(?:[ap]m)?) on (.*)/i do |time, days|
|
138
|
+
get /^(?:at )?(\d+:\d+(?:[ap]m)?) (?:on )?(.*)/i do |time, days|
|
24
139
|
[TimerTrigger, {time: time, days: days}]
|
25
140
|
end
|
26
141
|
|
142
|
+
# time.is? 'at 18:30pm on Mon or Tue'
|
143
|
+
get /^time.is\? ['"](?:at )?(\d+:\d+(?:[ap]m)?) (?:on )?(.*)['"]/i do |time, days|
|
144
|
+
[TimerTrigger, {time: time, days: days.gsub(' or ',', ')}]
|
145
|
+
end
|
146
|
+
|
147
|
+
get /^shake[ _]device\??$/i do
|
148
|
+
[ShakeDeviceTrigger, {}]
|
149
|
+
end
|
150
|
+
|
151
|
+
get /^Flip Device (.*)$/i do |motion|
|
152
|
+
facedown = motion =~ /Face Up (?:->|to) Face Down/i
|
153
|
+
[FlipDeviceTrigger, {face_down: facedown }]
|
154
|
+
end
|
155
|
+
|
156
|
+
get /^flip_device_down\?$/i do
|
157
|
+
[FlipDeviceTrigger, {face_down: true }]
|
158
|
+
end
|
27
159
|
|
160
|
+
get /^flip_device_up\?$/i do
|
161
|
+
[FlipDeviceTrigger, {face_down: false }]
|
162
|
+
end
|
163
|
+
|
164
|
+
get /^Failed Login Attempt$/i do
|
165
|
+
[FailedLoginTrigger, {}]
|
166
|
+
end
|
167
|
+
|
168
|
+
get /^failed_login?$/i do
|
169
|
+
[FailedLoginTrigger, {}]
|
170
|
+
end
|
171
|
+
|
172
|
+
get /^Geofence (Entry|Exit) \(([^\)]+)/i do |direction, name|
|
173
|
+
enter_area = direction.downcase.to_sym == :entry
|
174
|
+
[GeofenceTrigger, {name: name, enter_area: enter_area}]
|
175
|
+
end
|
176
|
+
|
177
|
+
get /^location (entered|exited) \(([^\)]+)/i do |direction, name|
|
178
|
+
enter_area = direction.downcase.to_sym == :entered
|
179
|
+
[GeofenceTrigger, {name: name, enter_area: enter_area}]
|
180
|
+
end
|
181
|
+
|
28
182
|
end
|
29
183
|
|
30
184
|
alias find_trigger run_route
|
@@ -44,10 +198,79 @@ class ActionsNlp
|
|
44
198
|
|
45
199
|
def actions(params)
|
46
200
|
|
201
|
+
# e.g. message popup: hello world!
|
47
202
|
get /^message popup: (.*)/i do |msg|
|
48
203
|
[ToastAction, {msg: msg}]
|
49
204
|
end
|
50
205
|
|
206
|
+
# e.g. Popup Message 'hello world!'
|
207
|
+
get /^Popup[ _]Message ['"]([^'"]+)/i do |msg|
|
208
|
+
[ToastAction, {msg: msg}]
|
209
|
+
end
|
210
|
+
|
211
|
+
# e.g. say current time
|
212
|
+
get /^say current[ _]time/i do
|
213
|
+
[SayTimeAction, {}]
|
214
|
+
end
|
215
|
+
|
216
|
+
get /^Torch :?(.*)/i do |onoffstate|
|
217
|
+
state = onoffstate.downcase == 'on' ? 0 : 1
|
218
|
+
[CameraFlashLightAction, {state: state}]
|
219
|
+
end
|
220
|
+
|
221
|
+
get /^Take Picture/i do
|
222
|
+
[TakePictureAction, {}]
|
223
|
+
end
|
224
|
+
|
225
|
+
get /^take_picture/i do
|
226
|
+
[TakePictureAction, {}]
|
227
|
+
end
|
228
|
+
|
229
|
+
# e.g. Display Notification: Hi there: This is the body of the message
|
230
|
+
get /^Display Notification: ([^:]+): [^$]+$/i do |subject, text|
|
231
|
+
[NotificationAction, {subject: subject, text: text}]
|
232
|
+
end
|
233
|
+
|
234
|
+
|
235
|
+
# e.g. Enable Wifi
|
236
|
+
get /^(Enable|Disable) Wifi$/i do |raw_state|
|
237
|
+
|
238
|
+
state = raw_state.downcase.to_sym == :enable ? 0 : 1
|
239
|
+
[SetWifiAction, {state: state}]
|
240
|
+
|
241
|
+
end
|
242
|
+
|
243
|
+
# e.g. Play: Altair
|
244
|
+
get /^Play: (.*)$/i do |name|
|
245
|
+
|
246
|
+
[PlaySoundAction, {file_path: name}]
|
247
|
+
|
248
|
+
end
|
249
|
+
|
250
|
+
# e.g. Launch Settings
|
251
|
+
get /^Launch (.*)$/i do |application|
|
252
|
+
|
253
|
+
h = {
|
254
|
+
application_name: application,
|
255
|
+
package_to_launch: 'com.android.' + application.downcase
|
256
|
+
}
|
257
|
+
[LaunchActivityAction, h]
|
258
|
+
|
259
|
+
end
|
260
|
+
|
261
|
+
# e.g. HTTP GET http://someurl.com/something
|
262
|
+
get /^HTTP GET ([^$]+)$/i do |url|
|
263
|
+
|
264
|
+
[OpenWebPageAction, url_to_open: url]
|
265
|
+
|
266
|
+
end
|
267
|
+
|
268
|
+
# e.g. webhook entered_kitchen
|
269
|
+
#
|
270
|
+
get /webhook|HTTP GET/i do
|
271
|
+
[OpenWebPageAction, {}]
|
272
|
+
end
|
273
|
+
|
51
274
|
|
52
275
|
end
|
53
276
|
|
@@ -136,11 +359,11 @@ class Macro
|
|
136
359
|
using Params
|
137
360
|
|
138
361
|
attr_reader :local_variables, :triggers, :actions, :constraints, :guid
|
139
|
-
attr_accessor :title
|
362
|
+
attr_accessor :title, :description
|
140
363
|
|
141
|
-
def initialize(name=nil, debug: false)
|
364
|
+
def initialize(name=nil, geofences: geofences, debug: false)
|
142
365
|
|
143
|
-
@title, @debug = name, debug
|
366
|
+
@title, @geofences, @debug = name, geofences, debug
|
144
367
|
|
145
368
|
puts 'inside Macro#initialize' if @debug
|
146
369
|
|
@@ -178,7 +401,7 @@ class Macro
|
|
178
401
|
m_action_list: @actions.map(&:to_h),
|
179
402
|
m_constraint_list: @constraints.map(&:to_h),
|
180
403
|
m_description: '',
|
181
|
-
m_name:
|
404
|
+
m_name: title(),
|
182
405
|
m_excludeLog: false,
|
183
406
|
m_GUID: guid(),
|
184
407
|
m_isOrCondition: false,
|
@@ -194,6 +417,14 @@ class Macro
|
|
194
417
|
|
195
418
|
def import_h(h)
|
196
419
|
|
420
|
+
if @debug then
|
421
|
+
puts 'inside import_h'
|
422
|
+
puts 'h:' + h.inspect
|
423
|
+
end
|
424
|
+
|
425
|
+
@title = h[:name]
|
426
|
+
@description = h[:description]
|
427
|
+
|
197
428
|
# fetch the local variables
|
198
429
|
@local_variables = h['local_variables']
|
199
430
|
|
@@ -223,18 +454,20 @@ class Macro
|
|
223
454
|
end
|
224
455
|
|
225
456
|
def import_xml(node)
|
226
|
-
|
457
|
+
|
227
458
|
if @debug then
|
228
459
|
puts 'inside Macro#import_xml'
|
229
460
|
puts 'node: ' + node.xml.inspect
|
230
461
|
end
|
231
462
|
|
232
|
-
@title = node.attributes[:name]
|
233
|
-
|
234
463
|
if node.element('triggers') then
|
235
|
-
|
464
|
+
|
236
465
|
# level 2
|
237
466
|
|
467
|
+
@title = node.attributes[:name]
|
468
|
+
@description = node.attributes[:description]
|
469
|
+
|
470
|
+
|
238
471
|
# get all the triggers
|
239
472
|
@triggers = node.xpath('triggers/*').map do |e|
|
240
473
|
|
@@ -270,6 +503,12 @@ class Macro
|
|
270
503
|
|
271
504
|
# Level 1
|
272
505
|
|
506
|
+
puts 'import_xml: inside level 1' if @debug
|
507
|
+
|
508
|
+
@title = node.text('macro') || node.attributes[:name]
|
509
|
+
|
510
|
+
#@description = node.attributes[:description]
|
511
|
+
|
273
512
|
tp = TriggersNlp.new
|
274
513
|
|
275
514
|
@triggers = node.xpath('trigger').map do |e|
|
@@ -279,7 +518,11 @@ class Macro
|
|
279
518
|
puts 'found trigger ' + r.inspect if @debug
|
280
519
|
|
281
520
|
if r then
|
282
|
-
r[0]
|
521
|
+
if r[0] == GeofenceTrigger then
|
522
|
+
GeofenceTrigger.new(r[1], geofences: @geofences)
|
523
|
+
else
|
524
|
+
r[0].new(r[1])
|
525
|
+
end
|
283
526
|
end
|
284
527
|
|
285
528
|
end
|
@@ -288,11 +531,21 @@ class Macro
|
|
288
531
|
|
289
532
|
@actions = node.xpath('action').map do |e|
|
290
533
|
|
534
|
+
puts 'action e: ' + e.xml.inspect if @debug
|
291
535
|
r = ap.find_action e.text
|
292
536
|
puts 'found action ' + r.inspect if @debug
|
293
537
|
|
294
538
|
if r then
|
295
|
-
|
539
|
+
|
540
|
+
a = e.xpath('item/*')
|
541
|
+
|
542
|
+
h = if a.any? then
|
543
|
+
a.map {|node| [node.name.to_sym, node.text.to_s]}.to_h
|
544
|
+
else
|
545
|
+
{}
|
546
|
+
end
|
547
|
+
|
548
|
+
r[0].new(r[1].merge(h))
|
296
549
|
end
|
297
550
|
|
298
551
|
end
|
@@ -316,16 +569,16 @@ class Macro
|
|
316
569
|
|
317
570
|
end
|
318
571
|
|
319
|
-
def match?(triggerx, detail={time: $env[:time]} )
|
572
|
+
def match?(triggerx, detail={time: $env[:time]}, model=nil )
|
320
573
|
|
321
|
-
if @triggers.any? {|x| x.type == triggerx and x.match?(detail) } then
|
574
|
+
if @triggers.any? {|x| x.type == triggerx and x.match?(detail, model) } then
|
322
575
|
|
323
576
|
if @debug then
|
324
577
|
puts 'checking constraints ...'
|
325
578
|
puts '@constraints: ' + @constraints.inspect
|
326
579
|
end
|
327
580
|
|
328
|
-
if @constraints.all? {|x| x.match?($env.merge(detail)) } then
|
581
|
+
if @constraints.all? {|x| x.match?($env.merge(detail), model) } then
|
329
582
|
|
330
583
|
true
|
331
584
|
|
@@ -339,9 +592,65 @@ class Macro
|
|
339
592
|
|
340
593
|
end
|
341
594
|
|
595
|
+
# invokes the actions
|
596
|
+
#
|
342
597
|
def run()
|
343
598
|
@actions.map(&:invoke)
|
344
|
-
end
|
599
|
+
end
|
600
|
+
|
601
|
+
# prepares the environment in order for triggers to test fire successfully
|
602
|
+
# Used for testing
|
603
|
+
#
|
604
|
+
def set_env()
|
605
|
+
@triggers.each(&:set_env)
|
606
|
+
end
|
607
|
+
|
608
|
+
def to_pc()
|
609
|
+
|
610
|
+
heading = '# ' + @title
|
611
|
+
heading += '\n# ' + @description if @description
|
612
|
+
condition = @triggers.first.to_pc
|
613
|
+
actions = @actions.map(&:to_pc).join("\n")
|
614
|
+
|
615
|
+
<<EOF
|
616
|
+
#{heading}
|
617
|
+
|
618
|
+
if #{condition} then
|
619
|
+
#{actions}
|
620
|
+
end
|
621
|
+
EOF
|
622
|
+
end
|
623
|
+
|
624
|
+
def to_s()
|
625
|
+
|
626
|
+
a = [
|
627
|
+
'm: ' + @title,
|
628
|
+
@triggers.map {|x| "t: %s" % x}.join("\n"),
|
629
|
+
@actions.map {|x| "a: %s" % x}.join("\n"),
|
630
|
+
@constraints.map {|x| "a: %s" % x}.join("\n")
|
631
|
+
]
|
632
|
+
|
633
|
+
if @description and @description.length >= 1 then
|
634
|
+
a.insert(1, 'd: ' + @description)
|
635
|
+
end
|
636
|
+
|
637
|
+
a.join("\n")
|
638
|
+
|
639
|
+
end
|
640
|
+
|
641
|
+
def to_summary()
|
642
|
+
|
643
|
+
a = [
|
644
|
+
'm: ' + @title,
|
645
|
+
't: ' + @triggers.map(&:to_s).join(", "),
|
646
|
+
'a: ' + @actions.map(&:to_s).join(", "),
|
647
|
+
]
|
648
|
+
|
649
|
+
a << 'c: ' + @constraints.map(&:to_s).join(", ") if @constraints.any?
|
650
|
+
|
651
|
+
a.join("\n") + "\n"
|
652
|
+
|
653
|
+
end
|
345
654
|
|
346
655
|
private
|
347
656
|
|
@@ -353,34 +662,86 @@ class Macro
|
|
353
662
|
|
354
663
|
puts ('inside object h:' + h.inspect).debug if @debug
|
355
664
|
klass = Object.const_get h[:class_type]
|
356
|
-
klass.
|
665
|
+
puts klass.inspect.highlight if $debug
|
666
|
+
|
667
|
+
if klass == GeofenceTrigger then
|
668
|
+
puts 'GeofenceTrigger found'.highlight if $debug
|
669
|
+
GeofenceTrigger.new(h, geofences: @geofences)
|
670
|
+
else
|
671
|
+
klass.new h
|
672
|
+
end
|
673
|
+
|
357
674
|
end
|
358
675
|
|
359
676
|
end
|
360
677
|
|
361
678
|
|
679
|
+
class MacroDroidError < Exception
|
680
|
+
end
|
681
|
+
|
362
682
|
class MacroDroid
|
363
683
|
using ColouredText
|
364
684
|
using Params
|
365
685
|
|
366
|
-
attr_reader :macros
|
686
|
+
attr_reader :macros, :geofences
|
367
687
|
|
368
688
|
def initialize(obj=nil, debug: false)
|
369
689
|
|
370
690
|
@debug = debug
|
371
691
|
|
692
|
+
@geofences = {}
|
693
|
+
|
372
694
|
if obj then
|
373
695
|
|
374
|
-
|
696
|
+
raw_s, _ = RXFHelper.read(obj)
|
697
|
+
|
698
|
+
s = raw_s.strip
|
375
699
|
|
376
700
|
if s[0] == '{' then
|
701
|
+
|
377
702
|
import_json(s)
|
703
|
+
|
378
704
|
elsif s[0] == '<'
|
705
|
+
|
379
706
|
import_xml(s)
|
380
707
|
@h = build_h
|
708
|
+
|
381
709
|
else
|
382
|
-
|
710
|
+
|
711
|
+
puts 's: ' + s.inspect if @debug
|
712
|
+
|
713
|
+
if s =~ /m(?:acro)?:\s/ then
|
714
|
+
|
715
|
+
puts 'before RowX.new' if @debug
|
716
|
+
|
717
|
+
s2 = s.gsub(/^g:/,'geofence:').gsub(/^m:/,'macro:')\
|
718
|
+
.gsub(/^t:/,'trigger:').gsub(/^a:/,'action:')\
|
719
|
+
.gsub(/^c:/,'constraint:').gsub(/^#.*/,'')
|
720
|
+
|
721
|
+
raw_macros, raw_geofences = s2.split(/(?=^macro:)/,2).reverse
|
722
|
+
|
723
|
+
if raw_geofences then
|
724
|
+
|
725
|
+
geoxml = RowX.new(raw_geofences).to_xml
|
726
|
+
|
727
|
+
geodoc = Rexle.new(geoxml)
|
728
|
+
geofences = geodoc.root.xpath('item/geofence')
|
729
|
+
@geofences = fetch_geofences(geofences) if geofences.any?
|
730
|
+
|
731
|
+
end
|
732
|
+
|
733
|
+
xml = RowX.new(raw_macros).to_xml
|
734
|
+
import_rowxml(xml)
|
735
|
+
|
736
|
+
elsif s =~ /^# /
|
737
|
+
xml = pc_to_xml(s)
|
738
|
+
import_xml(xml)
|
739
|
+
else
|
740
|
+
raise MacroDroidError, 'invalid input'
|
741
|
+
end
|
742
|
+
|
383
743
|
@h = build_h
|
744
|
+
|
384
745
|
end
|
385
746
|
|
386
747
|
else
|
@@ -432,15 +793,85 @@ class MacroDroid
|
|
432
793
|
|
433
794
|
alias to_json export_json
|
434
795
|
|
435
|
-
def import_json(s)
|
436
796
|
|
437
|
-
|
438
|
-
|
797
|
+
def to_h()
|
798
|
+
|
799
|
+
h = {
|
800
|
+
geofence_data: {
|
801
|
+
geofence_map: @geofences.map {|key, value| [key, value.to_h] }.to_h
|
802
|
+
},
|
803
|
+
macro_list: @macros.map(&:to_h)
|
804
|
+
}
|
805
|
+
@h.merge(h).to_camel_case
|
806
|
+
|
807
|
+
end
|
808
|
+
|
809
|
+
# returns pseudocode
|
810
|
+
#
|
811
|
+
def to_pc()
|
812
|
+
@macros.map(&:to_pc).join("\n\n")
|
813
|
+
end
|
814
|
+
|
815
|
+
def to_s()
|
816
|
+
@macros.map(&:to_s).join("\n")
|
817
|
+
end
|
818
|
+
|
819
|
+
def to_summary()
|
820
|
+
@macros.map(&:to_summary).join("\n")
|
821
|
+
end
|
822
|
+
|
823
|
+
private
|
824
|
+
|
825
|
+
def fetch_geofences(nodes)
|
826
|
+
|
827
|
+
nodes.map do |e|
|
828
|
+
|
829
|
+
name = e.text.to_s.strip
|
830
|
+
item = e.element('item')
|
831
|
+
coordinates = item.text('coordinates')
|
832
|
+
latitude, longitude = coordinates.split(/, */,2)
|
833
|
+
radius = item.text('radius')
|
834
|
+
|
835
|
+
id = UUID.new.generate
|
836
|
+
|
837
|
+
h = {
|
838
|
+
name: name,
|
839
|
+
longitude: longitude,
|
840
|
+
latitude: latitude,
|
841
|
+
radius: radius,
|
842
|
+
id: id
|
843
|
+
}
|
844
|
+
|
845
|
+
[id.to_sym, GeofenceMap.new(h)]
|
846
|
+
|
847
|
+
end.to_h
|
439
848
|
|
849
|
+
end
|
850
|
+
|
851
|
+
def import_json(s)
|
852
|
+
|
853
|
+
h = JSON.parse(s, symbolize_names: true)
|
854
|
+
puts 'json_to_yaml: ' + h.to_yaml if @debug
|
855
|
+
|
856
|
+
@h = h.to_snake_case
|
857
|
+
puts ('@h: ' + @h.inspect).debug if @debug
|
858
|
+
|
859
|
+
|
860
|
+
# fetch the geofence data
|
861
|
+
if @h[:geofence_data] then
|
862
|
+
|
863
|
+
@geofences = @h[:geofence_data][:geofence_map].map do |id, properties|
|
864
|
+
[id, GeofenceMap.new(properties)]
|
865
|
+
end.to_h
|
866
|
+
|
867
|
+
end
|
868
|
+
|
440
869
|
@macros = @h[:macro_list].map do |macro|
|
441
870
|
|
442
|
-
puts ('macro: ' + macro.
|
443
|
-
|
871
|
+
puts ('macro: ' + macro.inspect).debug if @debug
|
872
|
+
# puts '@geofences: ' + @geofences.inspect if @debug
|
873
|
+
|
874
|
+
m = Macro.new(geofences: @geofences.map(&:last), debug: @debug )
|
444
875
|
m.import_h(macro)
|
445
876
|
m
|
446
877
|
|
@@ -450,57 +881,92 @@ class MacroDroid
|
|
450
881
|
|
451
882
|
end
|
452
883
|
|
884
|
+
def import_rowxml(raws)
|
885
|
+
|
886
|
+
s = RXFHelper.read(raws).first
|
887
|
+
puts 's: ' + s.inspect if @debug
|
888
|
+
doc = Rexle.new(s)
|
889
|
+
puts 'after doc' if @debug
|
890
|
+
puts 'import_rowxml: @geofences: ' + @geofences.inspect if @debug
|
891
|
+
geofences = @geofences
|
892
|
+
|
893
|
+
@macros = doc.root.xpath('item').map do |node|
|
894
|
+
puts ('geofences: ' + geofences.inspect).highlight if @debug
|
895
|
+
Macro.new(geofences: geofences.map(&:last), debug: @debug).import_xml(node)
|
896
|
+
|
897
|
+
end
|
898
|
+
|
899
|
+
end
|
900
|
+
|
453
901
|
def import_xml(raws)
|
454
902
|
|
903
|
+
if @debug then
|
904
|
+
puts 'inside import_xml'
|
905
|
+
|
906
|
+
puts 'raws: ' + raws.inspect
|
907
|
+
end
|
455
908
|
s = RXFHelper.read(raws).first
|
456
909
|
puts 's: ' + s.inspect if @debug
|
457
910
|
doc = Rexle.new(s)
|
458
|
-
puts 'after doc' if @debug
|
459
911
|
|
912
|
+
if @debug then
|
913
|
+
puts 'doc: ' + doc.root.xml
|
914
|
+
end
|
915
|
+
|
460
916
|
@macros = doc.root.xpath('macro').map do |node|
|
461
917
|
|
462
|
-
|
463
|
-
macro.import_xml(node)
|
464
|
-
macro
|
918
|
+
Macro.new(geofences: @geofences.map(&:last), debug: @debug).import_xml(node)
|
465
919
|
|
466
920
|
end
|
467
921
|
end
|
468
922
|
|
469
|
-
def
|
923
|
+
def pc_to_xml(s)
|
470
924
|
|
471
|
-
|
472
|
-
a.map!(&:chomp)
|
473
|
-
|
474
|
-
macros = a.map do |x|
|
475
|
-
|
476
|
-
lines = x.lines
|
477
|
-
puts 'lines: ' + lines.inspect if @debug
|
478
|
-
|
479
|
-
name = lines.shift[/^m: +(.*)/,1]
|
480
|
-
h = {t: [], a: [], c: []}
|
925
|
+
macros = s.strip.split(/(?=#)/).map do |raw_macro|
|
481
926
|
|
482
|
-
|
483
|
-
|
484
|
-
|
485
|
-
|
927
|
+
a = raw_macro.lines
|
928
|
+
name = a.shift[/(?<=# ).*/]
|
929
|
+
description = a.shift[/(?<=# ).*/] if a[0][/^# /]
|
930
|
+
body = a.join.strip
|
486
931
|
|
487
|
-
|
932
|
+
a2 = body.lines
|
933
|
+
# get the trigger
|
934
|
+
trigger = [:trigger, {}, a2[0][/^if (.*) then/,1]]
|
935
|
+
action = [:action, {}, a2[1].strip]
|
936
|
+
[:macro, {name: name, description: description}, trigger, action, []]
|
488
937
|
|
489
938
|
end
|
490
939
|
|
491
940
|
doc = Rexle.new([:macros, {}, '', *macros])
|
492
941
|
doc.root.xml pretty: true
|
493
942
|
|
494
|
-
end
|
495
|
-
|
496
|
-
def to_h()
|
943
|
+
end
|
497
944
|
|
498
|
-
|
945
|
+
end
|
499
946
|
|
947
|
+
class GeofenceMap
|
948
|
+
|
949
|
+
attr_accessor :name, :longitude, :latitude, :radius, :id
|
950
|
+
|
951
|
+
def initialize(id: '', longitude: '', latitude: '', name: '', radius: '')
|
952
|
+
|
953
|
+
@id, @latitude, @longitude, @name, @radius = id, latitude, \
|
954
|
+
longitude, name, radius
|
955
|
+
|
500
956
|
end
|
501
|
-
|
502
|
-
|
503
|
-
|
957
|
+
|
958
|
+
def to_h()
|
959
|
+
|
960
|
+
{
|
961
|
+
id: @id,
|
962
|
+
longitude: @longitude,
|
963
|
+
latitude: @latitude,
|
964
|
+
name: @name,
|
965
|
+
radius: @radius
|
966
|
+
}
|
967
|
+
|
968
|
+
end
|
969
|
+
|
504
970
|
end
|
505
971
|
|
506
972
|
class MacroObject
|
@@ -511,6 +977,8 @@ class MacroObject
|
|
511
977
|
|
512
978
|
def initialize(h={})
|
513
979
|
|
980
|
+
$env ||= {}
|
981
|
+
|
514
982
|
@h = {constraint_list: [], is_or_condition: false,
|
515
983
|
is_disabled: false}.merge(h)
|
516
984
|
@list = []
|
@@ -539,6 +1007,10 @@ class MacroObject
|
|
539
1007
|
h2.merge('m_classType' => self.class.to_s)
|
540
1008
|
|
541
1009
|
end
|
1010
|
+
|
1011
|
+
def to_s()
|
1012
|
+
"#<%s %s>" % [self.class, @h.inspect]
|
1013
|
+
end
|
542
1014
|
|
543
1015
|
protected
|
544
1016
|
|
@@ -562,10 +1034,11 @@ class Trigger < MacroObject
|
|
562
1034
|
@list << 'fakeIcon'
|
563
1035
|
end
|
564
1036
|
|
565
|
-
def match?(detail={})
|
1037
|
+
def match?(detail={}, model=nil)
|
1038
|
+
|
1039
|
+
# only match where the key exists in the trigger object
|
1040
|
+
detail.select {|k,v| @h.include? k }.all? {|key,value| @h[key] == value}
|
566
1041
|
|
567
|
-
detail.all? {|key,value| @h[key] == value}
|
568
|
-
|
569
1042
|
end
|
570
1043
|
|
571
1044
|
end
|
@@ -1052,27 +1525,50 @@ class TimerTrigger < Trigger
|
|
1052
1525
|
use_alarm: false
|
1053
1526
|
}
|
1054
1527
|
|
1055
|
-
super(options.merge filter(options,h))
|
1528
|
+
super(options.merge filter(options, h))
|
1056
1529
|
|
1057
1530
|
end
|
1058
1531
|
|
1059
|
-
def match?(detail={time: $env[:time]})
|
1532
|
+
def match?(detail={time: $env[:time]}, model=nil)
|
1533
|
+
|
1534
|
+
time() == detail[:time]
|
1060
1535
|
|
1061
|
-
|
1062
|
-
|
1536
|
+
end
|
1537
|
+
|
1538
|
+
# sets the environmental conditions for this trigger to fire
|
1539
|
+
#
|
1540
|
+
def set_env()
|
1541
|
+
$env[:time] = time()
|
1542
|
+
end
|
1543
|
+
|
1544
|
+
def to_pc()
|
1545
|
+
"time.is? '%s'" % self.to_s.gsub(',', ' or')
|
1546
|
+
end
|
1547
|
+
|
1548
|
+
def to_s()
|
1549
|
+
|
1550
|
+
dow = @h[:days_of_week]
|
1063
1551
|
|
1064
|
-
|
1552
|
+
a = Date::ABBR_DAYNAMES
|
1065
1553
|
|
1066
|
-
|
1554
|
+
time = Time.parse("%s:%s" % [@h[:hour], @h[:minute]]).strftime("%-H:%M%P")
|
1555
|
+
days = (a[1..-1] << a.first).zip(dow).select {|_,b| b}.map(&:first)
|
1067
1556
|
|
1068
|
-
|
1069
|
-
|
1070
|
-
|
1071
|
-
|
1072
|
-
|
1557
|
+
"at %s on %s" % [time, days.join(', ')]
|
1558
|
+
end
|
1559
|
+
|
1560
|
+
private
|
1561
|
+
|
1562
|
+
def time()
|
1073
1563
|
|
1074
|
-
|
1564
|
+
a = @h[:days_of_week].clone
|
1565
|
+
a.unshift a.pop
|
1075
1566
|
|
1567
|
+
dow = a.map.with_index {|x, i| x ? i : nil }.compact.join(',')
|
1568
|
+
s = "%s %s * * %s" % [@h[:minute], @h[:hour], dow]
|
1569
|
+
recent_time = ($env && $env[:time]) ? $env[:time] : Time.now
|
1570
|
+
ChronicCron.new(s, recent_time).to_time
|
1571
|
+
|
1076
1572
|
end
|
1077
1573
|
|
1078
1574
|
end
|
@@ -1145,6 +1641,15 @@ class RegularIntervalTrigger < Trigger
|
|
1145
1641
|
|
1146
1642
|
end
|
1147
1643
|
|
1644
|
+
class DeviceEventsTrigger < Trigger
|
1645
|
+
|
1646
|
+
def initialize(h={})
|
1647
|
+
super(h)
|
1648
|
+
@group = 'device_events'
|
1649
|
+
end
|
1650
|
+
|
1651
|
+
end
|
1652
|
+
|
1148
1653
|
# Category: Device Events
|
1149
1654
|
#
|
1150
1655
|
# Airplane Mode Changed
|
@@ -1156,7 +1661,7 @@ end
|
|
1156
1661
|
# shorthand example:
|
1157
1662
|
# airplanemode: enabled
|
1158
1663
|
#
|
1159
|
-
class AirplaneModeTrigger <
|
1664
|
+
class AirplaneModeTrigger < DeviceEventsTrigger
|
1160
1665
|
|
1161
1666
|
def initialize(h={})
|
1162
1667
|
|
@@ -1172,7 +1677,7 @@ end
|
|
1172
1677
|
|
1173
1678
|
# Category: Device Events
|
1174
1679
|
#
|
1175
|
-
class AutoSyncChangeTrigger <
|
1680
|
+
class AutoSyncChangeTrigger < DeviceEventsTrigger
|
1176
1681
|
|
1177
1682
|
def initialize(h={})
|
1178
1683
|
|
@@ -1188,7 +1693,7 @@ end
|
|
1188
1693
|
|
1189
1694
|
# Category: Device Events
|
1190
1695
|
#
|
1191
|
-
class DayDreamTrigger <
|
1696
|
+
class DayDreamTrigger < DeviceEventsTrigger
|
1192
1697
|
|
1193
1698
|
def initialize(h={})
|
1194
1699
|
|
@@ -1204,7 +1709,7 @@ end
|
|
1204
1709
|
|
1205
1710
|
# Category: Device Events
|
1206
1711
|
#
|
1207
|
-
class DockTrigger <
|
1712
|
+
class DockTrigger < DeviceEventsTrigger
|
1208
1713
|
|
1209
1714
|
def initialize(h={})
|
1210
1715
|
|
@@ -1220,7 +1725,30 @@ end
|
|
1220
1725
|
|
1221
1726
|
# Category: Device Events
|
1222
1727
|
#
|
1223
|
-
class
|
1728
|
+
class FailedLoginTrigger < DeviceEventsTrigger
|
1729
|
+
|
1730
|
+
def initialize(h={})
|
1731
|
+
|
1732
|
+
options = {
|
1733
|
+
num_failures: 1
|
1734
|
+
}
|
1735
|
+
|
1736
|
+
super(options.merge h)
|
1737
|
+
|
1738
|
+
end
|
1739
|
+
|
1740
|
+
def to_pc()
|
1741
|
+
'failed_login?'
|
1742
|
+
end
|
1743
|
+
|
1744
|
+
def to_s()
|
1745
|
+
'Failed Login Attempt'
|
1746
|
+
end
|
1747
|
+
end
|
1748
|
+
|
1749
|
+
# Category: Device Events
|
1750
|
+
#
|
1751
|
+
class GPSEnabledTrigger < DeviceEventsTrigger
|
1224
1752
|
|
1225
1753
|
def initialize(h={})
|
1226
1754
|
|
@@ -1236,7 +1764,7 @@ end
|
|
1236
1764
|
|
1237
1765
|
# Category: Device Events
|
1238
1766
|
#
|
1239
|
-
class MusicPlayingTrigger <
|
1767
|
+
class MusicPlayingTrigger < DeviceEventsTrigger
|
1240
1768
|
|
1241
1769
|
def initialize(h={})
|
1242
1770
|
|
@@ -1253,7 +1781,7 @@ end
|
|
1253
1781
|
|
1254
1782
|
# Category: Device Events
|
1255
1783
|
#
|
1256
|
-
class DeviceUnlockedTrigger <
|
1784
|
+
class DeviceUnlockedTrigger < DeviceEventsTrigger
|
1257
1785
|
|
1258
1786
|
def initialize(h={})
|
1259
1787
|
|
@@ -1268,7 +1796,7 @@ end
|
|
1268
1796
|
|
1269
1797
|
# Category: Device Events
|
1270
1798
|
#
|
1271
|
-
class AutoRotateChangeTrigger <
|
1799
|
+
class AutoRotateChangeTrigger < DeviceEventsTrigger
|
1272
1800
|
|
1273
1801
|
def initialize(h={})
|
1274
1802
|
|
@@ -1284,7 +1812,7 @@ end
|
|
1284
1812
|
|
1285
1813
|
# Category: Device Events
|
1286
1814
|
#
|
1287
|
-
class ClipboardChangeTrigger <
|
1815
|
+
class ClipboardChangeTrigger < DeviceEventsTrigger
|
1288
1816
|
|
1289
1817
|
def initialize(h={})
|
1290
1818
|
|
@@ -1301,7 +1829,7 @@ end
|
|
1301
1829
|
|
1302
1830
|
# Category: Device Events
|
1303
1831
|
#
|
1304
|
-
class BootTrigger <
|
1832
|
+
class BootTrigger < DeviceEventsTrigger
|
1305
1833
|
|
1306
1834
|
def initialize(h={})
|
1307
1835
|
|
@@ -1316,7 +1844,7 @@ end
|
|
1316
1844
|
|
1317
1845
|
# Category: Device Events
|
1318
1846
|
#
|
1319
|
-
class IntentReceivedTrigger <
|
1847
|
+
class IntentReceivedTrigger < DeviceEventsTrigger
|
1320
1848
|
|
1321
1849
|
def initialize(h={})
|
1322
1850
|
|
@@ -1336,7 +1864,7 @@ end
|
|
1336
1864
|
|
1337
1865
|
# Category: Device Events
|
1338
1866
|
#
|
1339
|
-
class NotificationTrigger <
|
1867
|
+
class NotificationTrigger < DeviceEventsTrigger
|
1340
1868
|
|
1341
1869
|
def initialize(h={})
|
1342
1870
|
|
@@ -1362,7 +1890,7 @@ end
|
|
1362
1890
|
|
1363
1891
|
# Category: Device Events
|
1364
1892
|
#
|
1365
|
-
class ScreenOnOffTrigger <
|
1893
|
+
class ScreenOnOffTrigger < DeviceEventsTrigger
|
1366
1894
|
|
1367
1895
|
def initialize(h={})
|
1368
1896
|
|
@@ -1378,7 +1906,7 @@ end
|
|
1378
1906
|
|
1379
1907
|
# Category: Device Events
|
1380
1908
|
#
|
1381
|
-
class SilentModeTrigger <
|
1909
|
+
class SilentModeTrigger < DeviceEventsTrigger
|
1382
1910
|
|
1383
1911
|
def initialize(h={})
|
1384
1912
|
|
@@ -1421,8 +1949,15 @@ end
|
|
1421
1949
|
#
|
1422
1950
|
class GeofenceTrigger < Trigger
|
1423
1951
|
|
1424
|
-
def initialize(h={})
|
1952
|
+
def initialize( h={}, geofences: {})
|
1425
1953
|
|
1954
|
+
if h[:name] then
|
1955
|
+
puts ('geofences2: ' + geofences.inspect)
|
1956
|
+
found = geofences.find {|x| x.name.downcase == h[:name].downcase}
|
1957
|
+
h[:geofence_id] = found.id if found
|
1958
|
+
|
1959
|
+
end
|
1960
|
+
|
1426
1961
|
options = {
|
1427
1962
|
update_rate_text: '5 Minutes',
|
1428
1963
|
geofence_id: '',
|
@@ -1431,8 +1966,27 @@ class GeofenceTrigger < Trigger
|
|
1431
1966
|
enter_area: true
|
1432
1967
|
}
|
1433
1968
|
|
1434
|
-
super(options.merge h)
|
1969
|
+
super(options.merge filter(options, h))
|
1970
|
+
@geofences = geofences
|
1971
|
+
|
1972
|
+
end
|
1973
|
+
|
1974
|
+
def to_s()
|
1975
|
+
|
1976
|
+
if $debug then
|
1977
|
+
puts ' @geofences: ' + @geofences.inspect
|
1978
|
+
puts '@h: ' + @h.inspect
|
1979
|
+
puts '@h[:geofence_id]: ' + @h[:geofence_id].inspect
|
1980
|
+
end
|
1981
|
+
|
1982
|
+
direction = @h[:enter_area] ? 'Entry' : 'Exit'
|
1983
|
+
|
1984
|
+
found = @geofences.find {|x| x.id == @h[:geofence_id]}
|
1985
|
+
puts 'found: ' + found.inspect
|
1986
|
+
label = found ? found.name : 'error: name not found'
|
1435
1987
|
|
1988
|
+
"Geofence %s (%s)" % [direction, label]
|
1989
|
+
|
1436
1990
|
end
|
1437
1991
|
|
1438
1992
|
end
|
@@ -1454,9 +2008,19 @@ class SunriseSunsetTrigger < Trigger
|
|
1454
2008
|
|
1455
2009
|
end
|
1456
2010
|
|
2011
|
+
|
2012
|
+
class SensorsTrigger < Trigger
|
2013
|
+
|
2014
|
+
def initialize(h={})
|
2015
|
+
super(h)
|
2016
|
+
@group = 'sensors'
|
2017
|
+
end
|
2018
|
+
|
2019
|
+
end
|
2020
|
+
|
1457
2021
|
# Category: Sensors
|
1458
2022
|
#
|
1459
|
-
class ActivityRecognitionTrigger <
|
2023
|
+
class ActivityRecognitionTrigger < SensorsTrigger
|
1460
2024
|
|
1461
2025
|
def initialize(h={})
|
1462
2026
|
|
@@ -1473,7 +2037,7 @@ end
|
|
1473
2037
|
|
1474
2038
|
# Category: Sensors
|
1475
2039
|
#
|
1476
|
-
class ProximityTrigger <
|
2040
|
+
class ProximityTrigger < SensorsTrigger
|
1477
2041
|
|
1478
2042
|
def initialize(h={})
|
1479
2043
|
|
@@ -1490,7 +2054,7 @@ end
|
|
1490
2054
|
|
1491
2055
|
# Category: Sensors
|
1492
2056
|
#
|
1493
|
-
class ShakeDeviceTrigger <
|
2057
|
+
class ShakeDeviceTrigger < SensorsTrigger
|
1494
2058
|
|
1495
2059
|
def initialize(h={})
|
1496
2060
|
|
@@ -1500,12 +2064,25 @@ class ShakeDeviceTrigger < Trigger
|
|
1500
2064
|
super(options.merge h)
|
1501
2065
|
|
1502
2066
|
end
|
2067
|
+
|
2068
|
+
def to_pc()
|
2069
|
+
'shake_device?'
|
2070
|
+
end
|
2071
|
+
|
2072
|
+
def to_s()
|
2073
|
+
'Shake Device'
|
2074
|
+
end
|
1503
2075
|
|
1504
2076
|
end
|
1505
2077
|
|
1506
2078
|
# Category: Sensors
|
1507
2079
|
#
|
1508
|
-
|
2080
|
+
# options:
|
2081
|
+
# Face Up -> Face Down
|
2082
|
+
# Face Down -> Face Up
|
2083
|
+
# Any -> Face Down
|
2084
|
+
#
|
2085
|
+
class FlipDeviceTrigger < SensorsTrigger
|
1509
2086
|
|
1510
2087
|
def initialize(h={})
|
1511
2088
|
|
@@ -1517,13 +2094,23 @@ class FlipDeviceTrigger < Trigger
|
|
1517
2094
|
|
1518
2095
|
super(options.merge h)
|
1519
2096
|
|
2097
|
+
end
|
2098
|
+
|
2099
|
+
def to_pc()
|
2100
|
+
@h[:face_down] ? 'flip_device_down?' : 'flip_device_up?'
|
1520
2101
|
end
|
2102
|
+
|
2103
|
+
def to_s()
|
2104
|
+
|
2105
|
+
action = @h[:face_down] ? 'Face Up -> Face Down' : 'Face Down -> Face Up'
|
2106
|
+
'Flip Device ' + action
|
2107
|
+
end
|
1521
2108
|
|
1522
2109
|
end
|
1523
2110
|
|
1524
2111
|
# Category: Sensors
|
1525
2112
|
#
|
1526
|
-
class OrientationTrigger <
|
2113
|
+
class OrientationTrigger < SensorsTrigger
|
1527
2114
|
|
1528
2115
|
def initialize(h={})
|
1529
2116
|
|
@@ -1705,6 +2292,10 @@ class LaunchActivityAction < ApplicationAction
|
|
1705
2292
|
super(options.merge h)
|
1706
2293
|
|
1707
2294
|
end
|
2295
|
+
|
2296
|
+
def to_s()
|
2297
|
+
'Launch ' + @h[:application_name]
|
2298
|
+
end
|
1708
2299
|
|
1709
2300
|
end
|
1710
2301
|
|
@@ -1730,6 +2321,8 @@ end
|
|
1730
2321
|
class OpenWebPageAction < ApplicationAction
|
1731
2322
|
|
1732
2323
|
def initialize(h={})
|
2324
|
+
|
2325
|
+
h[:url_to_open] = h[:url] if h[:url]
|
1733
2326
|
|
1734
2327
|
options = {
|
1735
2328
|
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},
|
@@ -1739,9 +2332,13 @@ class OpenWebPageAction < ApplicationAction
|
|
1739
2332
|
block_next_action: false
|
1740
2333
|
}
|
1741
2334
|
|
1742
|
-
super(options.merge h)
|
2335
|
+
super(options.merge filter(options,h))
|
1743
2336
|
|
1744
2337
|
end
|
2338
|
+
|
2339
|
+
def to_s()
|
2340
|
+
"HTTP GET\n url: " + @h[:url_to_open]
|
2341
|
+
end
|
1745
2342
|
|
1746
2343
|
end
|
1747
2344
|
|
@@ -1789,6 +2386,15 @@ class TakePictureAction < CameraAction
|
|
1789
2386
|
super(options.merge h)
|
1790
2387
|
|
1791
2388
|
end
|
2389
|
+
|
2390
|
+
def to_pc()
|
2391
|
+
camera = @h[:use_front_camera] ? :front : :back
|
2392
|
+
'take_photo :' + camera.to_s
|
2393
|
+
end
|
2394
|
+
|
2395
|
+
def to_s()
|
2396
|
+
'Take Picture'
|
2397
|
+
end
|
1792
2398
|
|
1793
2399
|
end
|
1794
2400
|
|
@@ -1817,6 +2423,11 @@ class SetWifiAction < ConnectivityAction
|
|
1817
2423
|
super(options.merge h)
|
1818
2424
|
|
1819
2425
|
end
|
2426
|
+
|
2427
|
+
def to_s()
|
2428
|
+
action = @h[:state] == 0 ? 'Enable' : 'Disable'
|
2429
|
+
action + ' Wifi'
|
2430
|
+
end
|
1820
2431
|
|
1821
2432
|
end
|
1822
2433
|
|
@@ -1947,6 +2558,20 @@ class SayTimeAction < DateTimeAction
|
|
1947
2558
|
super(options.merge h)
|
1948
2559
|
|
1949
2560
|
end
|
2561
|
+
|
2562
|
+
def invoke()
|
2563
|
+
time = ($env and $env[:time]) ? $env[:time] : Time.now
|
2564
|
+
tformat = @h['12_hour'] ? "%-I:%M%P" : "%H:%M"
|
2565
|
+
super(time.strftime(tformat))
|
2566
|
+
end
|
2567
|
+
|
2568
|
+
def to_pc()
|
2569
|
+
'say current_time()'
|
2570
|
+
end
|
2571
|
+
|
2572
|
+
def to_s()
|
2573
|
+
'Say Current Time'
|
2574
|
+
end
|
1950
2575
|
|
1951
2576
|
end
|
1952
2577
|
|
@@ -2118,6 +2743,14 @@ class CameraFlashLightAction < DeviceSettingsAction
|
|
2118
2743
|
|
2119
2744
|
end
|
2120
2745
|
|
2746
|
+
def to_pc()
|
2747
|
+
'torch :on'
|
2748
|
+
end
|
2749
|
+
|
2750
|
+
def to_s()
|
2751
|
+
'Torch On'
|
2752
|
+
end
|
2753
|
+
|
2121
2754
|
end
|
2122
2755
|
|
2123
2756
|
# Category: Device Settings
|
@@ -2455,6 +3088,10 @@ class PlaySoundAction < MediaAction
|
|
2455
3088
|
super(options.merge h)
|
2456
3089
|
|
2457
3090
|
end
|
3091
|
+
|
3092
|
+
def to_s()
|
3093
|
+
'Play: ' + @h[:file_path]
|
3094
|
+
end
|
2458
3095
|
|
2459
3096
|
end
|
2460
3097
|
|
@@ -2659,6 +3296,9 @@ end
|
|
2659
3296
|
class NotificationAction < NotificationsAction
|
2660
3297
|
|
2661
3298
|
def initialize(h={})
|
3299
|
+
|
3300
|
+
h[:notification_subject] = h[:subject] if h[:subject]
|
3301
|
+
h[:notification_text] = h[:text] if h[:text]
|
2662
3302
|
|
2663
3303
|
options = {
|
2664
3304
|
ringtone_name: 'Default',
|
@@ -2674,9 +3314,13 @@ class NotificationAction < NotificationsAction
|
|
2674
3314
|
run_macro_when_pressed: false
|
2675
3315
|
}
|
2676
3316
|
|
2677
|
-
super(options.merge h)
|
3317
|
+
super(options.merge filter(options, h))
|
2678
3318
|
|
2679
3319
|
end
|
3320
|
+
|
3321
|
+
def to_s()
|
3322
|
+
'Display Notification: ' + "%s: %s" % [@h[:notification_subject], @h[:notification_text]]
|
3323
|
+
end
|
2680
3324
|
|
2681
3325
|
end
|
2682
3326
|
|
@@ -2709,6 +3353,14 @@ class ToastAction < NotificationsAction
|
|
2709
3353
|
def invoke()
|
2710
3354
|
super(@h[:message_text])
|
2711
3355
|
end
|
3356
|
+
|
3357
|
+
def to_pc()
|
3358
|
+
"popup_message '%s'" % @h[:message_text]
|
3359
|
+
end
|
3360
|
+
|
3361
|
+
def to_s()
|
3362
|
+
"Popup Message '%s'" % @h[:message_text]
|
3363
|
+
end
|
2712
3364
|
|
2713
3365
|
end
|
2714
3366
|
|
@@ -3037,6 +3689,30 @@ class Constraint < MacroObject
|
|
3037
3689
|
def initialize(h={})
|
3038
3690
|
super(h)
|
3039
3691
|
end
|
3692
|
+
|
3693
|
+
def match?(detail={}, model=nil)
|
3694
|
+
|
3695
|
+
detail.select {|k,v| @h.include? k }.all? {|key,value| @h[key] == value}
|
3696
|
+
|
3697
|
+
end
|
3698
|
+
|
3699
|
+
#def to_s()
|
3700
|
+
# ''
|
3701
|
+
#end
|
3702
|
+
|
3703
|
+
protected
|
3704
|
+
|
3705
|
+
def toggle_match?(key, val)
|
3706
|
+
|
3707
|
+
if @h[key] == true and val == key.to_s then
|
3708
|
+
true
|
3709
|
+
elsif @h[key] == false and val != key.to_s
|
3710
|
+
true
|
3711
|
+
else
|
3712
|
+
false
|
3713
|
+
end
|
3714
|
+
|
3715
|
+
end
|
3040
3716
|
|
3041
3717
|
end
|
3042
3718
|
|
@@ -3398,6 +4074,41 @@ class AirplaneModeConstraint < Constraint
|
|
3398
4074
|
super(options.merge h)
|
3399
4075
|
|
3400
4076
|
end
|
4077
|
+
|
4078
|
+
def match?(detail={}, model=nil)
|
4079
|
+
|
4080
|
+
puts 'inside airplaneModeConstraint#match?' if $debug
|
4081
|
+
|
4082
|
+
if detail.has_key? :enabled then
|
4083
|
+
|
4084
|
+
puts 'detail has the key' if $debug
|
4085
|
+
super(detail)
|
4086
|
+
|
4087
|
+
elsif model
|
4088
|
+
|
4089
|
+
if $debug then
|
4090
|
+
puts 'checking the model'
|
4091
|
+
switch = model.connectivity.airplane_mode.switch
|
4092
|
+
puts 'switch: ' + switch.inspect
|
4093
|
+
end
|
4094
|
+
|
4095
|
+
toggle_match?(:enabled, switch)
|
4096
|
+
|
4097
|
+
end
|
4098
|
+
|
4099
|
+
end
|
4100
|
+
|
4101
|
+
def to_pc()
|
4102
|
+
status = @h[:enabled] ? 'enabled?' : 'disabled?'
|
4103
|
+
'airplane_mode.' + status
|
4104
|
+
end
|
4105
|
+
|
4106
|
+
def to_s()
|
4107
|
+
|
4108
|
+
status = @h[:enabled] ? 'Enabled' : 'Disabled'
|
4109
|
+
'Airplane Mode ' + status
|
4110
|
+
|
4111
|
+
end
|
3401
4112
|
|
3402
4113
|
end
|
3403
4114
|
|