1 package ro
.ieval
.fonbot
;
3 import static ro
.ieval
.fonbot
.R
.string
.cannot_parse_count
;
4 import static ro
.ieval
.fonbot
.R
.string
.cannot_parse_interval
;
5 import static ro
.ieval
.fonbot
.R
.string
.cannot_parse_min_distance
;
6 import static ro
.ieval
.fonbot
.R
.string
.cannot_parse_min_time
;
7 import static ro
.ieval
.fonbot
.R
.string
.cannot_parse_port
;
8 import static ro
.ieval
.fonbot
.R
.string
.cannot_parse_provider_allowed_values_are
;
9 import static ro
.ieval
.fonbot
.R
.string
.command_disabled
;
10 import static ro
.ieval
.fonbot
.R
.string
.could_not_parse_argument_allowed_values_are
;
11 import static ro
.ieval
.fonbot
.R
.string
.could_not_parse_ms
;
12 import static ro
.ieval
.fonbot
.R
.string
.error_while_processing_command
;
13 import static ro
.ieval
.fonbot
.R
.string
.invalid_length_allowed_values_are
;
14 import static ro
.ieval
.fonbot
.R
.string
.invalid_ringer_mode_valid_values_are
;
15 import static ro
.ieval
.fonbot
.R
.string
.location_tracking_is_active
;
16 import static ro
.ieval
.fonbot
.R
.string
.messagetype_should_be_one_of
;
17 import static ro
.ieval
.fonbot
.R
.string
.no_such_command_command_list
;
18 import static ro
.ieval
.fonbot
.R
.string
.notification_disabled
;
19 import static ro
.ieval
.fonbot
.R
.string
.notification_enabled
;
20 import static ro
.ieval
.fonbot
.R
.string
.ringing
;
21 import static ro
.ieval
.fonbot
.R
.string
.security_exception
;
22 import static ro
.ieval
.fonbot
.R
.string
.the_polling_service_is_running
;
23 import static ro
.ieval
.fonbot
.R
.string
.the_second_argument_to_wipe_must_be
;
24 import static ro
.ieval
.fonbot
.R
.string
.unknown_command
;
25 import static ro
.ieval
.fonbot
.R
.string
.wipetype_should_be_one_of
;
27 import java
.net
.MalformedURLException
;
29 import java
.util
.Arrays
;
30 import java
.util
.Locale
;
32 import org
.eclipse
.jdt
.annotation
.NonNull
;
33 import org
.eclipse
.jdt
.annotation
.Nullable
;
35 import ro
.ieval
.fonbot
.Address
.Protocol
;
36 import android
.content
.Context
;
37 import android
.content
.Intent
;
38 import android
.content
.SharedPreferences
;
39 import android
.database
.Cursor
;
40 import android
.location
.LocationManager
;
41 import android
.media
.AudioManager
;
42 import android
.net
.Uri
;
43 import android
.preference
.PreferenceManager
;
44 import android
.provider
.ContactsContract
.PhoneLookup
;
45 import android
.telephony
.SmsManager
;
46 import android
.util
.Log
;
47 import android
.widget
.Toast
;
50 * Copyright © 2013 Marius Gavrilescu
52 * This file is part of FonBot.
54 * FonBot is free software: you can redistribute it and/or modify
55 * it under the terms of the GNU General Public License as published by
56 * the Free Software Foundation, either version 3 of the License, or
57 * (at your option) any later version.
59 * FonBot is distributed in the hope that it will be useful,
60 * but WITHOUT ANY WARRANTY; without even the implied warranty of
61 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
62 * GNU General Public License for more details.
64 * You should have received a copy of the GNU General Public License
65 * along with FonBot. If not, see <http://www.gnu.org/licenses/>.
69 * Utility functions and enums used in various places.
71 * @author Marius Gavrilescu <marius@ieval.ro>
73 public final class Utils
{
75 * Enum of all FonBot commands.
77 * @author Marius Gavrilescu <marius@ieval.ro>
79 @SuppressWarnings("javadoc")
80 public static enum Command
{
81 TOAST
, ECHO
, SMS
, FLASH
, WIFI
,
82 BLUETOOTH
, DIAL
, RING
, SPEAK
, VIBRATE
,
83 DIALOG
, LOCATION
, NOLOCATION
, RINGER
, NCFILE
,
84 PHOTO
, SETNOTIFICATION
, DELNOTIFICATION
, SETPASSWORD
, HELP
,
85 WIPE
, LOCK
, VIEW
, PLAY
, PAUSE
,
86 NEXT
, PREV
, BATT
, CALLLOG
, SMSLOG
,
87 LS
, RM
, CONTACTS
, DISABLE
, ENABLE
,
88 POLL
, HANGUP
, ANSWER
, LAUNCH
, DATA
,
89 GPS
, GLOCATION
, REBOOT
, NOTIFY
, SCREENCAP
,
94 * Enum of all message types. Each message type is a kind of notification which can be enabled/disabled by the user and directed to a certain address.
96 * @author Marius Gavrilescu <marius@ieval.ro>
99 public static enum MessageType
{
100 /** SMS notifications */
102 /** Phone state (idle, offhook or ringing) notifications */
104 /** Lockscreen failed password notifications */
106 /** Device admin enable/disable notifications */
108 /** Coarse battery status (low battery, ok battery) notifications */
110 /** Fine battery status notifications */
112 /** Headset plug/unplug notifications */
114 /** Phone booted notifications */
119 * Enum of wipe types. The two defined types are the data wipe (which does not include the SD card) and the full wipe (which includes the SD card).
121 * @author Marius Gavrilescu <marius@ieval.ro>
123 public static enum WipeType
{
124 /** Factory reset the phone, without touching the SD card */
126 /** Factory reset the phone and wipe the SD card too */
131 * Enum of ringer modes.
133 * @author Marius Gavrilescu <marius@ieval.ro>
135 public static enum RingerMode
{
138 /** Sound is off, vibrate is on */
140 /** Sound is off, vibrate is off */
145 * Enum of location providers
147 * @author Marius Gavrilescu <marius@ieval.ro>
149 public static enum LocationProvider
{
150 /** The network location provider */
152 /** The GPS location provider */
157 * Enum of toast lengths.
159 * @author Marius Gavrilescu <marius@ieval.ro>
161 private static enum ToastLength
{
169 * Enum of the values on and off. Used for boolean arguments.
171 * @author Marius Gavrilescu <marius@ieval.ro>
173 @SuppressWarnings("javadoc")
174 private static enum OnOff
{
179 * Enum of ongoing event types
181 * @author Marius Gavrilescu <marius@ieval.ro>
183 public static enum OngoingEvent
{
184 /** Location tracking is active. Registered by {@link Command#LOCATION}, unregistered by {@link Command#NOLOCATION} */
185 LOCATION(location_tracking_is_active
),
186 /** The phone is ringing. Registered/unregistered by {@link Command#RING} */
188 /** The polling alarm is on. Registered/unregistered by {@link Command#POLL} */
189 POLL(the_polling_service_is_running
);
191 /** String resource: the event description */
192 public final int resource
;
195 * Constructs an OngoingEvent from its event description.
197 * @param resource the event description
199 private OngoingEvent(final int resource
) {
200 this.resource
=resource
;
204 /** Confirmation string for the {@link Command#WIPE WIPE} command. */
205 public static final String WIPE_CONFIRM_STRING
="I am aware this cannot be undone";
208 * Converts a Nullable object into a NonNull one.
210 * @param object the Nullable object to convert
211 * @return a NonNull object equivalent to the Nullable parameter
212 * @throws AssertionError if the given object is null
214 public static <T
> T
toNonNull(@Nullable T object
) throws AssertionError
{
216 Log
.wtf(Utils
.class.getName(), "toNonNull called with null");
217 throw new AssertionError("Log.wtf did not terminate the process");
223 * Join an array of Objects with elements separated by a separator into a single string.
225 * @param separator the separator
226 * @param offset the offset into the array
227 * @param args the array of Objects to join
228 * @return the joined string
230 public static String
join(final String separator
,final int offset
,final Object
[] args
){
231 final StringBuilder sb
=new StringBuilder(240);
232 sb
.append(args
[offset
]);
233 for (int i
= offset
+1; i
< args
.length
; i
++) {
234 sb
.append(separator
);
237 return toNonNull(sb
.toString());
241 * Join an array of Objects with elements separated by a separator into a single string.
243 * @param separator the separator
244 * @param args the array of objects to join
245 * @return the joined string
247 public static String
join(final String separator
, final Object
[] args
){
248 return join(separator
,0,args
);
252 * Send a notification to the user.
254 * @param context Context instance
255 * @param type notification type
256 * @param resource String resource for the message text
258 public static void sendMessage(final Context context
, final MessageType type
, final int resource
){
259 sendMessage(context
, type
, toNonNull(context
.getString(resource
)));
263 * Send a notification to the user.
265 * @param context Context instance
266 * @param type notification type
267 * @param resource String resource for the message text
268 * @param args format parameters for the resource
270 public static void sendMessage(final Context context
, final MessageType type
, final int resource
, final Object
... args
){
271 sendMessage(context
, type
, toNonNull(context
.getString(resource
, args
)));
275 * Send a message to a certain Address.
277 * @param context Context instance
278 * @param address destination Address
279 * @param resource String resource for the message text
281 public static void sendMessage(final Context context
, final Address address
, final int resource
){
282 sendMessage(context
, address
, toNonNull(context
.getString(resource
)));
286 * Send a message to a certain Address.
288 * @param context Context instance
289 * @param address destination Address
290 * @param resource String resource for the message text
291 * @param args format parameters for the resource
293 public static void sendMessage(final Context context
, final Address address
, final int resource
, final Object
... args
){
294 sendMessage(context
, address
, toNonNull(context
.getString(resource
, args
)));
298 * Send a notification to the user.
300 * @param context Context instance
301 * @param type notification type
302 * @param msg the notification text
304 public static void sendMessage(final Context context
, final MessageType type
,final String msg
){
305 final SharedPreferences sp
=PreferenceManager
.getDefaultSharedPreferences(context
);
306 final String address
=sp
.getString(type
.toString(),null);
309 sendMessage(context
, new Address(address
), msg
);
313 * Send a message to a certain Address.
315 * @param context Context instance
316 * @param address destination Address
317 * @param message the message text
319 public static void sendMessage(final Context context
, final Address address
, final String message
){
320 switch(address
.protocol
){
322 new HttpCallExecutableRunnable("/send", toNonNull(Arrays
.asList(
323 new Header("X-Destination", toNonNull(address
.data
)))), context
, null, true, message
).execute();
327 SmsManager
.getDefault().sendTextMessage(address
.data
, null, message
, null, null);
331 final Intent intent
= new Intent(FonBotLocalActivity
.RESPONSE_RECEIVED_ACTION
);
332 intent
.putExtra(FonBotLocalActivity
.EXTRA_RESPONSE
, message
);
333 context
.sendBroadcast(intent
);
342 * Splits a string into words.
344 * @param string the string
345 * @return an array of words
347 public static String
[] shellwords(final String string
){
348 return toNonNull(string
.split("[ ]+(?=([^\"]*\"[^\"]*\")*[^\"]*$)"));//TODO: Make this handle backslash escapes
352 * Returns the name associated with a phone number.
354 * @param context Context instance
355 * @param number phone number to search for
356 * @return the name associated with this number, or null if the number was not found in the contacts.
358 public static @Nullable String
callerId(final Context context
, final String number
){
359 final Cursor cursor
=context
.getContentResolver().query(
360 Uri
.withAppendedPath(PhoneLookup
.CONTENT_FILTER_URI
, Uri
.encode(number
)),
361 new String
[]{PhoneLookup
.DISPLAY_NAME
},
366 if(cursor
.moveToFirst()){
367 final String name
=cursor
.getString(0);
376 * Registers an ongoing event.
378 * @param context Context instance
379 * @param event event to register
381 public static void registerOngoing(final Context context
, final OngoingEvent event
){
382 final Intent intent
=new Intent(context
, FonBotMainService
.class);
383 intent
.setAction(FonBotMainService
.ACTION_PUT_ONGOING
);
384 intent
.putExtra(FonBotMainService
.EXTRA_ONGOING_ID
, event
.ordinal());
385 context
.startService(intent
);
389 * Unregisters an ongoing event
391 * @param context Context instance
392 * @param event event to unregister
394 public static void unregisterOngoing(final Context context
, final OngoingEvent event
){
395 final Intent intent
=new Intent(context
, FonBotMainService
.class);
396 intent
.setAction(FonBotMainService
.ACTION_DELETE_ONGOING
);
397 intent
.putExtra(FonBotMainService
.EXTRA_ONGOING_ID
, event
.ordinal());
398 context
.startService(intent
);
402 * Gets the server URL according to the user preferences.
404 * @param context Context instance
405 * @param path URL path
406 * @return the server URL
407 * @throws MalformedURLException if the user preferences create an invalid URL
409 public static URL
getServerURL(final Context context
, final String path
) throws MalformedURLException
{
410 final String hostname
=PreferenceManager
.getDefaultSharedPreferences(context
).getString("hostname", "fonbot.ieval.ro");
411 final int port
=Integer
.parseInt(PreferenceManager
.getDefaultSharedPreferences(context
).getString("port", "443"));
412 final URL url
=new URL("https", hostname
, port
, path
);
417 * Poll the server for pending commands. This function must not be called from BroadcastReceivers
419 * @param context Context instance
421 public static void pollServer(final Context context
){
422 new HttpCallExecutableRunnable("/get", null, context
, new PollResultCallback(context
), false).execute();
426 * Poll the server for pending commands from {@link FonBotMainService}. This function should be used from BroadcastReceviers instead of {@link #pollServer}
428 * @param context Context instance
430 public static void safePollServer(final Context context
){
431 final Intent intent
=new Intent(context
, FonBotMainService
.class);
432 intent
.setAction(FonBotMainService
.ACTION_TRIGGER_POLL
);
433 context
.startService(intent
);
436 * Executes a given command
438 * @param context Context instance
439 * @param cmd Command to execute
440 * @param args arguments for the command
441 * @param replyTo Address to send replies to
443 private static void processCommand(final Context context
, final Command cmd
,final String
[] args
,final Address replyTo
){
444 if(Heavy
.isCommandDisabled(context
, cmd
)){
445 sendMessage(context
, replyTo
, command_disabled
, cmd
.toString());
451 if(args
.length
< 1 || args
.length
> 2){
452 Heavy
.help(context
, replyTo
, toNonNull(Command
.TOAST
));
457 Heavy
.toast(context
, replyTo
, toNonNull(args
[0]));
460 switch(ToastLength
.valueOf(args
[1].toUpperCase(Locale
.ENGLISH
))){
462 Heavy
.toast(context
, replyTo
, toNonNull(args
[0]), Toast
.LENGTH_LONG
);
465 Heavy
.toast(context
, replyTo
, toNonNull(args
[0]), Toast
.LENGTH_SHORT
);
467 } catch(IllegalArgumentException e
){
468 sendMessage(context
, replyTo
, invalid_length_allowed_values_are
, join(", ",toNonNull(ToastLength
.values())));
475 Heavy
.help(context
, replyTo
, toNonNull(Command
.ECHO
));
478 sendMessage(context
, replyTo
, join(" ",args
));
483 Heavy
.help(context
, replyTo
, toNonNull(Command
.SMS
));
486 Heavy
.sms(context
, replyTo
, toNonNull(args
[0]), join(" ", 1, args
));
490 if(args
.length
!= 1){
491 Heavy
.help(context
, replyTo
, toNonNull(Command
.FLASH
));
496 Heavy
.flash(context
, replyTo
, OnOff
.valueOf(args
[0].toUpperCase(Locale
.ENGLISH
)) == OnOff
.ON
);
497 } catch(IllegalArgumentException e
) {
498 sendMessage(context
, replyTo
, could_not_parse_argument_allowed_values_are
, join(", ", toNonNull(OnOff
.values())));
504 Heavy
.help(context
, replyTo
, toNonNull(Command
.WIFI
));
508 Heavy
.wifi(context
, replyTo
);
511 Heavy
.wifi(context
, replyTo
, OnOff
.valueOf(args
[0].toUpperCase(Locale
.ENGLISH
)) == OnOff
.ON
);
512 } catch(IllegalArgumentException e
) {
513 sendMessage(context
, replyTo
, could_not_parse_argument_allowed_values_are
, join(", ", toNonNull(OnOff
.values())));
520 Heavy
.help(context
, replyTo
, toNonNull(Command
.BLUETOOTH
));
524 Heavy
.bluetooth(context
, replyTo
);
527 Heavy
.bluetooth(context
, replyTo
, OnOff
.valueOf(args
[0].toUpperCase(Locale
.ENGLISH
)) == OnOff
.ON
);
528 } catch(IllegalArgumentException e
) {
529 sendMessage(context
, replyTo
, could_not_parse_argument_allowed_values_are
, join(", ", toNonNull(OnOff
.values())));
536 Heavy
.help(context
, replyTo
, toNonNull(Command
.DIAL
));
539 Heavy
.dial(context
, replyTo
, toNonNull(args
[0]));
544 Heavy
.help(context
, replyTo
, toNonNull(Command
.RING
));
548 Heavy
.ring(context
, replyTo
);
551 Heavy
.ring(context
, replyTo
, OnOff
.valueOf(args
[0].toUpperCase(Locale
.ENGLISH
)) == OnOff
.ON
);
552 } catch(IllegalArgumentException e
){
553 sendMessage(context
, replyTo
, could_not_parse_argument_allowed_values_are
, join(", ", toNonNull(OnOff
.values())));
560 Heavy
.help(context
, replyTo
, toNonNull(Command
.SPEAK
));
563 Heavy
.speak(context
, replyTo
, join(" ",args
));
568 Heavy
.help(context
, replyTo
, toNonNull(Command
.VIBRATE
));
573 ms
=Long
.parseLong(args
[0]);
574 } catch(NumberFormatException e
){
575 sendMessage(context
, replyTo
, could_not_parse_ms
);
578 Heavy
.vibrate(context
, replyTo
, ms
);
581 case DIALOG
://TODO: Should add an edittext
583 Heavy
.help(context
, replyTo
, toNonNull(Command
.DIALOG
));
586 final String
[] buttons
=new String
[args
.length
-1];
587 System
.arraycopy(args
,1,buttons
,0,buttons
.length
);
588 Heavy
.dialog(context
, replyTo
, toNonNull(args
[0]), buttons
);
592 if(args
.length
>3||args
.length
<1){
593 Heavy
.help(context
, replyTo
, toNonNull(Command
.LOCATION
));
597 final @NonNull String provider
;
599 switch(LocationProvider
.valueOf(args
[0].toUpperCase(Locale
.ENGLISH
))){
601 provider
=toNonNull(LocationManager
.GPS_PROVIDER
);
605 provider
=toNonNull(LocationManager
.NETWORK_PROVIDER
);
608 } catch(IllegalArgumentException e
){
609 sendMessage(context
, replyTo
, cannot_parse_provider_allowed_values_are
, join(", ",toNonNull(LocationProvider
.values())));
614 final float minDistance
;
618 minTime
=Long
.parseLong(args
[1]);
619 } catch (NumberFormatException e
){
620 sendMessage(context
, replyTo
, cannot_parse_min_time
);
628 minDistance
=Float
.parseFloat(args
[2]);
629 } catch (NumberFormatException e
){
630 sendMessage(context
, replyTo
, cannot_parse_min_distance
);
635 Heavy
.location(context
, replyTo
, provider
, minTime
, minDistance
);
639 Heavy
.nolocation(context
, replyTo
);
644 Heavy
.help(context
, replyTo
, toNonNull(Command
.RINGER
));
648 Heavy
.ringer(context
, replyTo
);
651 final RingerMode rm
=RingerMode
.valueOf(args
[0].toUpperCase(Locale
.ENGLISH
));
654 Heavy
.ringer(context
, replyTo
, AudioManager
.RINGER_MODE_NORMAL
);
657 Heavy
.ringer(context
, replyTo
, AudioManager
.RINGER_MODE_VIBRATE
);
660 Heavy
.ringer(context
, replyTo
, AudioManager
.RINGER_MODE_SILENT
);
663 } catch (IllegalArgumentException e
){
664 Utils
.sendMessage(context
, replyTo
, invalid_ringer_mode_valid_values_are
, join(", ",toNonNull(RingerMode
.values())));
671 Heavy
.help(context
, replyTo
, toNonNull(Command
.NCFILE
));
675 final int ncfilePort
;
677 ncfilePort
=Integer
.parseInt(args
[2]);
678 } catch (NumberFormatException e
){
679 sendMessage(context
, replyTo
, cannot_parse_port
);
682 Heavy
.ncfile(context
, replyTo
, toNonNull(args
[0]), toNonNull(args
[1]), ncfilePort
);
687 Heavy
.help(context
, replyTo
, toNonNull(Command
.PHOTO
));
692 photoPort
=Integer
.parseInt(args
[1]);
693 } catch (NumberFormatException e
){
694 sendMessage(context
, replyTo
, cannot_parse_port
);
697 Heavy
.photo(context
, replyTo
, toNonNull(args
[0]), photoPort
);
700 case SETNOTIFICATION
:
702 Heavy
.help(context
, replyTo
, toNonNull(Command
.SETNOTIFICATION
));
707 PreferenceManager
.getDefaultSharedPreferences(context
).edit()
708 .putString(MessageType
.valueOf(args
[0].toUpperCase(Locale
.ENGLISH
)).toString(), replyTo
.toString())
710 sendMessage(context
, replyTo
, notification_enabled
);
711 } catch (IllegalArgumentException e
){
712 sendMessage(context
, replyTo
, messagetype_should_be_one_of
, join(", ",toNonNull(MessageType
.values())));
718 case DELNOTIFICATION
:
720 Heavy
.help(context
, replyTo
, toNonNull(Command
.DELNOTIFICATION
));
725 PreferenceManager
.getDefaultSharedPreferences(context
).edit()
726 .remove(MessageType
.valueOf(args
[0].toUpperCase(Locale
.ENGLISH
)).toString())
728 sendMessage(context
, replyTo
, notification_disabled
);
729 } catch (IllegalArgumentException e
){
730 sendMessage(context
, replyTo
, messagetype_should_be_one_of
, join(", ",toNonNull(MessageType
.values())));
738 Heavy
.help(context
, replyTo
, toNonNull(Command
.SETPASSWORD
));
744 Heavy
.setPassword(context
, replyTo
);
746 Heavy
.setPassword(context
, replyTo
, toNonNull(args
[0]));
747 } catch (SecurityException e
){
748 sendMessage(context
, replyTo
, security_exception
+e
.getMessage());
754 Heavy
.help(context
, replyTo
, toNonNull(Command
.WIPE
));
758 if(!args
[1].equalsIgnoreCase(WIPE_CONFIRM_STRING
)){
759 sendMessage(context
, replyTo
, the_second_argument_to_wipe_must_be
, WIPE_CONFIRM_STRING
);
764 Heavy
.wipe(context
, toNonNull(WipeType
.valueOf(args
[0].toUpperCase(Locale
.ENGLISH
))));
765 } catch (IllegalArgumentException e
){
766 sendMessage(context
, replyTo
, wipetype_should_be_one_of
, join (", ",toNonNull(WipeType
.values())));
767 } catch (SecurityException e
){
768 sendMessage(context
, replyTo
, security_exception
, e
.getMessage());
774 Heavy
.lock(context
, replyTo
);
775 } catch (SecurityException e
){
776 sendMessage(context
, replyTo
, security_exception
, e
.getMessage());
782 Heavy
.help(context
, replyTo
, toNonNull(Command
.VIEW
));
786 Heavy
.view(context
, replyTo
, toNonNull(Uri
.parse(args
[0])));
790 Heavy
.musicPlayerCommand(context
, replyTo
, "play");
794 Heavy
.musicPlayerCommand(context
, replyTo
, "pause");
798 Heavy
.musicPlayerCommand(context
, replyTo
, "next");
802 Heavy
.musicPlayerCommand(context
, replyTo
, "previous");
806 Heavy
.batt(context
, replyTo
);
810 if (args
.length
> 1) {
811 Heavy
.help(context
, replyTo
, toNonNull(Command
.CALLLOG
));
815 if (args
.length
== 0)
816 Heavy
.calllog(context
, replyTo
, 5);
819 Heavy
.calllog(context
, replyTo
, Integer
.parseInt(args
[0]));
820 } catch (IllegalArgumentException e
){
821 sendMessage(context
, replyTo
, cannot_parse_count
);
827 if (args
.length
> 1) {
828 Heavy
.help(context
, replyTo
, toNonNull(Command
.SMSLOG
));
832 if (args
.length
== 0)
833 Heavy
.smslog(context
, replyTo
, 5);
836 Heavy
.smslog(context
, replyTo
, Integer
.parseInt(args
[0]));
837 } catch (IllegalArgumentException e
) {
838 sendMessage(context
, replyTo
, cannot_parse_count
);
844 if(args
.length
!= 1){
845 Heavy
.help(context
, replyTo
, toNonNull(Command
.HELP
));
850 Heavy
.help(context
, replyTo
, toNonNull(Command
.valueOf(args
[0].toUpperCase(Locale
.ENGLISH
))));
851 } catch (IllegalArgumentException e
) {
852 sendMessage(context
, replyTo
, no_such_command_command_list
, join(", ", toNonNull(Command
.values())));
857 if(args
.length
!= 1){
858 Heavy
.help(context
, replyTo
, toNonNull(Command
.LS
));
862 Heavy
.ls(context
, replyTo
, toNonNull(args
[0]));
866 if(args
.length
!= 1){
867 Heavy
.help(context
, replyTo
, toNonNull(Command
.RM
));
871 Heavy
.rm(context
, replyTo
, toNonNull(args
[0]));
875 if(args
.length
!= 1){
876 Heavy
.help(context
, replyTo
, toNonNull(Command
.CONTACTS
));
880 Heavy
.contacts(context
, replyTo
, toNonNull(args
[0]));
884 if(replyTo
.protocol
!= Protocol
.LOCAL
|| args
.length
!= 1){
885 Heavy
.help(context
, replyTo
, toNonNull(Command
.DISABLE
));
890 Heavy
.disable(context
, replyTo
, toNonNull(Command
.valueOf(args
[0].toUpperCase(Locale
.ENGLISH
))));
891 } catch (IllegalArgumentException e
){
892 sendMessage(context
, replyTo
, no_such_command_command_list
, join(", ", toNonNull(Command
.values())));
897 if(replyTo
.protocol
!= Protocol
.LOCAL
|| args
.length
!= 1){
898 Heavy
.help(context
, replyTo
, toNonNull(Command
.ENABLE
));
903 Heavy
.enable(context
, replyTo
, toNonNull(Command
.valueOf(args
[0].toUpperCase(Locale
.ENGLISH
))));
904 } catch (IllegalArgumentException e
){
905 sendMessage(context
, replyTo
, no_such_command_command_list
, join(", ", toNonNull(Command
.values())));
911 Heavy
.help(context
, replyTo
, toNonNull(Command
.POLL
));
916 Heavy
.poll(context
, replyTo
);
922 interval
=Long
.parseLong(args
[0]);
923 } catch(NumberFormatException e
){
924 sendMessage(context
, replyTo
, cannot_parse_interval
);
928 Heavy
.poll(context
, replyTo
, interval
);
932 Heavy
.hangup(context
, replyTo
);
936 Heavy
.answer(context
, replyTo
);
941 Heavy
.help(context
, replyTo
, toNonNull(Command
.LAUNCH
));
944 Heavy
.launch(context
, replyTo
, toNonNull(args
[0]));
949 Heavy
.help(context
, replyTo
, toNonNull(Command
.DATA
));
954 Heavy
.data(context
, replyTo
);
958 Heavy
.data(context
, replyTo
, OnOff
.valueOf(args
[0].toUpperCase(Locale
.ENGLISH
)) == OnOff
.ON
);
959 } catch(IllegalArgumentException e
) {
960 sendMessage(context
, replyTo
, could_not_parse_argument_allowed_values_are
, join(", ", toNonNull(OnOff
.values())));
966 Heavy
.help(context
, replyTo
, toNonNull(Command
.GPS
));
971 Heavy
.gps(context
, replyTo
);
976 Heavy
.gps(context
, replyTo
, OnOff
.valueOf(args
[0].toUpperCase(Locale
.ENGLISH
)) == OnOff
.ON
);
977 } catch(IllegalArgumentException e
) {
978 sendMessage(context
, replyTo
, could_not_parse_argument_allowed_values_are
, join(", ", toNonNull(OnOff
.values())));
984 Heavy
.help(context
, replyTo
, toNonNull(Command
.GLOCATION
));
989 Heavy
.glocation(context
, replyTo
);
994 Heavy
.glocation(context
, replyTo
, OnOff
.valueOf(args
[0].toUpperCase(Locale
.ENGLISH
)) == OnOff
.ON
);
995 } catch(IllegalArgumentException e
) {
996 sendMessage(context
, replyTo
, could_not_parse_argument_allowed_values_are
, join(", ", toNonNull(OnOff
.values())));
1002 Heavy
.help(context
, replyTo
, toNonNull(Command
.REBOOT
));
1006 Heavy
.reboot(context
, replyTo
, args
.length
==0?
null:args
[0]);
1010 if(args
.length
!=1 && args
.length
!=3){
1011 Heavy
.help(context
, replyTo
, toNonNull(Command
.NOTIFY
));
1017 id
=Integer
.parseInt(args
[0]);
1018 } catch (NumberFormatException e
){
1019 sendMessage(context
, replyTo
, R
.string
.could_not_parse_id
);
1024 Heavy
.notify(context
, replyTo
, id
);
1026 Heavy
.notify(context
, replyTo
, id
, toNonNull(args
[1]), toNonNull(args
[2]));
1030 if(args
.length
!= 1){
1031 Heavy
.help(context
, replyTo
, toNonNull(Command
.SCREENCAP
));
1035 Heavy
.screencap(context
, replyTo
, args
[0]);
1039 Heavy
.torch(context
, replyTo
);
1046 * Executes a given command
1048 * @param context Context instance
1049 * @param cmd Command to execute
1050 * @param args arguments for the command
1051 * @param replyTo Address to send replies to
1053 public static void processCommand(final Context context
, final String cmd
,final String
[] args
,final Address replyTo
){
1054 final @NonNull Command command
;
1056 command
=toNonNull(Command
.valueOf(cmd
.toUpperCase(Locale
.ENGLISH
)));
1057 } catch (IllegalArgumentException e
){
1058 sendMessage(context
, replyTo
, unknown_command
, cmd
.toUpperCase(Locale
.ENGLISH
), e
.getMessage());
1063 processCommand(context
, command
,args
,replyTo
);
1064 } catch(Exception e
){
1065 sendMessage(context
, replyTo
, error_while_processing_command
, e
.getClass().getName(), e
.getMessage());
1066 Log
.w(Utils
.class.getName(), "Error while processing command", e
);