1 package ro
.ieval
.fonbot
;
3 import static ro
.ieval
.fonbot
.R
.string
.*;
4 import static ro
.ieval
.fonbot
.Utils
.toNonNull
;
6 import java
.io
.BufferedReader
;
8 import java
.io
.FileInputStream
;
9 import java
.io
.FileOutputStream
;
10 import java
.io
.FileNotFoundException
;
11 import java
.io
.InputStream
;
12 import java
.io
.InputStreamReader
;
13 import java
.io
.IOException
;
14 import java
.io
.OutputStream
;
15 import java
.lang
.reflect
.InvocationTargetException
;
16 import java
.lang
.reflect
.Method
;
17 import java
.net
.InetSocketAddress
;
18 import java
.net
.Socket
;
19 import java
.net
.UnknownHostException
;
21 import java
.net
.URLConnection
;
22 import java
.nio
.channels
.FileChannel
;
23 import java
.nio
.channels
.SocketChannel
;
24 import java
.util
.ArrayList
;
25 import java
.util
.Date
;
27 import org
.eclipse
.jdt
.annotation
.Nullable
;
29 import ro
.ieval
.fonbot
.Utils
.Command
;
30 import ro
.ieval
.fonbot
.Utils
.MessageType
;
31 import ro
.ieval
.fonbot
.Utils
.OngoingEvent
;
32 import ro
.ieval
.fonbot
.Utils
.RingerMode
;
33 import ro
.ieval
.fonbot
.Utils
.WipeType
;
34 import android
.annotation
.SuppressLint
;
35 import android
.app
.AlarmManager
;
36 import android
.app
.NotificationManager
;
37 import android
.app
.PendingIntent
;
38 import android
.app
.admin
.DevicePolicyManager
;
39 import android
.bluetooth
.BluetoothAdapter
;
40 import android
.content
.ActivityNotFoundException
;
41 import android
.content
.Context
;
42 import android
.content
.Intent
;
43 import android
.content
.IntentFilter
;
44 import android
.database
.Cursor
;
45 import android
.graphics
.ImageFormat
;
46 import android
.hardware
.Camera
;
47 import android
.hardware
.Camera
.PictureCallback
;
48 import android
.location
.Location
;
49 import android
.location
.LocationListener
;
50 import android
.location
.LocationManager
;
51 import android
.location
.LocationProvider
;
52 import android
.media
.AudioManager
;
53 import android
.media
.Ringtone
;
54 import android
.media
.RingtoneManager
;
55 import android
.net
.ConnectivityManager
;
56 import android
.net
.Uri
;
57 import android
.net
.wifi
.WifiManager
;
58 import android
.os
.AsyncTask
;
59 import android
.os
.BatteryManager
;
60 import android
.os
.Bundle
;
61 import android
.os
.Handler
;
62 import android
.os
.PowerManager
;
63 import android
.os
.SystemClock
;
64 import android
.os
.Vibrator
;
65 import android
.preference
.PreferenceManager
;
66 import android
.provider
.BaseColumns
;
67 import android
.provider
.CallLog
.Calls
;
68 import android
.provider
.ContactsContract
.CommonDataKinds
;
69 import android
.provider
.ContactsContract
.CommonDataKinds
.BaseTypes
;
70 import android
.provider
.ContactsContract
.CommonDataKinds
.Phone
;
71 import android
.provider
.ContactsContract
.Contacts
;
72 import android
.provider
.ContactsContract
.Data
;
73 import android
.provider
.Settings
.Secure
;
74 import android
.speech
.tts
.TextToSpeech
;
75 import android
.speech
.tts
.TextToSpeech
.OnInitListener
;
76 import android
.support
.v4
.app
.NotificationCompat
;
77 import android
.telephony
.SmsManager
;
78 import android
.telephony
.TelephonyManager
;
79 import android
.util
.Log
;
80 import android
.view
.SurfaceView
;
81 import android
.widget
.Toast
;
83 import com
.android
.internal
.telephony
.ITelephony
;
86 * Copyright © 2013 Marius Gavrilescu
88 * This file is part of FonBot.
90 * FonBot is free software: you can redistribute it and/or modify
91 * it under the terms of the GNU General Public License as published by
92 * the Free Software Foundation, either version 3 of the License, or
93 * (at your option) any later version.
95 * FonBot is distributed in the hope that it will be useful,
96 * but WITHOUT ANY WARRANTY; without even the implied warranty of
97 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
98 * GNU General Public License for more details.
100 * You should have received a copy of the GNU General Public License
101 * along with FonBot. If not, see <http://www.gnu.org/licenses/>.
105 * Implementation of all FonBot commands. The methods of this class do not do argument checking.
107 * @author Marius Gavrilescu <marius@ieval.ro>
111 * LocationListener that sends notifications to the user.
113 * @author Marius Gavrilescu <marius@ieval.ro>
115 private static final class FonBotLocationListener
implements LocationListener
{
116 /** Context instance */
117 private final Context context
;
118 /** Destination address for notifications */
119 private final Address replyTo
;
122 * Construct a FonBotLocationListener.
124 * @param context Context instance
125 * @param replyTo the reply address
127 FonBotLocationListener(final Context context
, final Address replyTo
) {
128 this.context
=context
;
129 this.replyTo
=replyTo
;
133 public void onLocationChanged(@Nullable final Location loc
) {
136 final StringBuilder sb
=new StringBuilder(toNonNull(context
.getString(location
)));
138 sb
.append(toNonNull(context
.getString(latitude
)));
140 sb
.append(loc
.getLatitude());
142 sb
.append(toNonNull(context
.getString(longitude
)));
144 sb
.append(loc
.getLongitude());
146 if(loc
.hasAccuracy()){
148 sb
.append(toNonNull(context
.getString(accuracy
)));
150 sb
.append(loc
.getAccuracy());
153 if(loc
.hasAltitude()){
155 sb
.append(toNonNull(context
.getString(altitude
)));
157 sb
.append(loc
.getAltitude());
160 if(loc
.hasBearing()){
162 sb
.append(toNonNull(context
.getString(bearing
)));
164 sb
.append(loc
.getBearing());
169 sb
.append(toNonNull(context
.getString(speed
)));
171 sb
.append(loc
.getSpeed());
174 final Date locationDate
=new Date(loc
.getTime());
176 sb
.append(toNonNull(context
.getString(at
)));
178 sb
.append(locationDate
.toString());
181 sb
.append("http://openstreetmap.org/?zoom=15&mlat=");
182 sb
.append(loc
.getLatitude());
184 sb
.append(loc
.getLongitude());
185 Utils
.sendMessage(toNonNull(context
), toNonNull(replyTo
), toNonNull(sb
.toString()));
189 public void onProviderDisabled(@Nullable final String provider
) {
190 Utils
.sendMessage(toNonNull(context
), toNonNull(replyTo
), location_provider_disabled
, provider
);
194 public void onProviderEnabled(@Nullable final String provider
) {
195 Utils
.sendMessage(toNonNull(context
), toNonNull(replyTo
), location_provider_enabled
, provider
);
199 public void onStatusChanged(@Nullable final String provider
, final int status
, @Nullable final Bundle extras
) {
202 case LocationProvider
.AVAILABLE
:
203 state
=location_provider_available
;
205 case LocationProvider
.TEMPORARILY_UNAVAILABLE
:
206 state
=location_provider_temporary_unavailable
;
208 case LocationProvider
.OUT_OF_SERVICE
:
209 state
=location_provider_out_of_service
;
212 state
=location_provider_unknown_state
;
214 Utils
.sendMessage(toNonNull(context
), toNonNull(replyTo
), state
, provider
);
218 * Currently active FonBotLocationListener
220 private static FonBotLocationListener locationListener
= null;
223 * AsyncTask that sends a byte[] to a server
225 * @author Marius Gavrilescu <marius@ieval.ro>
228 private static class SendDataAsyncTask
extends AsyncTask
<Void
, Void
, Void
>{
230 * Context instance used by this class
232 private final Context context
;
236 private final String hostname
;
240 private final int port
;
244 private final byte[] data
;
246 * Address for sending back errors and success messages
248 private final Address replyTo
;
251 * Constructs a SendDataAsyncTasks from its parameters
253 * @param context the context
254 * @param replyTo the reply Address
255 * @param hostname the server hostname
256 * @param port the server port
257 * @param data the data to send
259 public SendDataAsyncTask(final Context context
,final Address replyTo
, final String hostname
, final int port
, final byte[] data
) {//NOPMD array is immutable
261 this.context
=context
;
262 this.hostname
=hostname
;
265 this.replyTo
=replyTo
;
269 protected @Nullable Void
doInBackground(@Nullable final Void
... params
) {
272 sock
= new Socket(hostname
, port
);
274 sock
.getOutputStream().write(data
);
275 } catch (IOException e
) {
276 Utils
.sendMessage(toNonNull(context
), toNonNull(replyTo
), error_writing_to_socket
, e
.getMessage());
282 } catch (IOException e
) {
283 Utils
.sendMessage(toNonNull(context
), toNonNull(replyTo
), cannot_close_socket
, e
.getMessage());
286 } catch (UnknownHostException e
) {
287 Utils
.sendMessage(toNonNull(context
), toNonNull(replyTo
), unknown_host
, hostname
);
289 } catch (IOException e
) {
290 Utils
.sendMessage(toNonNull(context
), toNonNull(replyTo
), cannot_connect_to_host_on_port
, hostname
, Integer
.valueOf(port
));
293 Utils
.sendConfirmMessage(toNonNull(context
), toNonNull(replyTo
), photo_sent
);
299 * ExecutableRunnable that uploads a file to a given host and port, netcat-style
301 * @author Marius Gavrilescu <marius@ieval.ro>
303 private static final class NcfileExecutableRunnable
extends ExecutableRunnable
{
304 private final Context context
;
305 private final Address replyTo
;
306 private final String filename
;
307 private final String hostname
;
308 private final int port
;
311 * Construct a NcfileExecutableRunnable
313 * @param context Context instance
314 * @param replyTo reply Address
315 * @param filename filename to upload
316 * @param hostname hostname to upload to
317 * @param port port to upload to
319 NcfileExecutableRunnable(final Context context
, final Address replyTo
, final String filename
, final String hostname
, final int port
){
320 this.context
=context
;
321 this.replyTo
=replyTo
;
322 this.filename
=filename
;
323 this.hostname
=hostname
;
327 @Override public void run(){
328 final FileChannel in
;
329 final SocketChannel sock
;
331 in
=new FileInputStream(filename
).getChannel();
332 } catch (final FileNotFoundException e
){
333 Utils
.sendMessage(context
, replyTo
, file_not_found
, filename
);
338 sock
= SocketChannel
.open(new InetSocketAddress(hostname
, port
));
339 } catch (final IOException e
){
340 Utils
.sendMessage(context
, replyTo
, cannot_connect_to_host_on_port
, hostname
, Integer
.valueOf(port
));
343 } catch (IOException ex
) {
350 in
.transferTo(0, in
.size(), sock
);
351 } catch (final IOException e
){
352 Utils
.sendMessage(context
, replyTo
, io_error
, e
.getMessage());
356 } catch (IOException e
){
361 } catch(IOException e
){
365 Utils
.sendConfirmMessage(context
, replyTo
, file_sent
);
370 * ExecutableRunnable that downloads a file from a given host and port, netcat-style
372 * @author Marius Gavrilescu <marius@ieval.ro>
374 private static final class GetfileExecutableRunnable
extends ExecutableRunnable
{
375 private final Context context
;
376 private final Address replyTo
;
377 private final String filename
;
378 private final String hostname
;
379 private final int port
;
382 * Construct a GetfileExecutableRunnable
384 * @param context Context instance
385 * @param replyTo reply Address
386 * @param filename filename to save to
387 * @param hostname hostname to download from
388 * @param port port to download from
390 GetfileExecutableRunnable(final Context context
, final Address replyTo
, final String filename
, final String hostname
, final int port
){
391 this.context
=context
;
392 this.replyTo
=replyTo
;
393 this.filename
=filename
;
394 this.hostname
=hostname
;
398 @Override public void run(){
399 final InputStream in
;
400 final FileOutputStream out
;
403 out
=new FileOutputStream(filename
);
404 } catch (final IOException e
){
405 Utils
.sendMessage(context
, replyTo
, error_opening_file
, filename
, e
.getMessage());
410 sock
= new Socket(hostname
, port
);
411 in
= sock
.getInputStream();
412 } catch (final IOException e
){
413 Utils
.sendMessage(context
, replyTo
, cannot_connect_to_host_on_port
, hostname
, Integer
.valueOf(port
));
416 } catch (IOException ex
) {
423 byte[] buffer
=new byte[1024*1024*2];
425 while((nread
= in
.read(buffer
)) > 0)
426 out
.write(buffer
, 0, nread
);
427 } catch (final IOException e
){
428 Utils
.sendMessage(context
, replyTo
, io_error
, e
.getMessage());
432 } catch (IOException e
){
437 } catch(IOException e
){
441 Utils
.sendConfirmMessage(context
, replyTo
, file_received
);
446 * PictureCallback that sends the picture to a server.
448 * @author Marius Gavrilescu <marius@ieval.ro>
450 private static final class FonBotPictureCallback
implements PictureCallback
{
451 /** Server hostname */
452 private final String hostname
;
454 private final int port
;
455 /** Context instance */
456 private final Context context
;
458 private final Address replyTo
;
461 * Construct a FonBotPictureCallback.
463 * @param context Context instance
464 * @param replyTo reply Address
465 * @param hostname server hostname
466 * @param port server port
468 FonBotPictureCallback(final Context context
, final Address replyTo
, final String hostname
, final int port
) {
469 this.hostname
=hostname
;
471 this.context
=context
;
472 this.replyTo
=replyTo
;
476 @SuppressWarnings("hiding")
477 public void onPictureTaken(final @Nullable byte[] data
, final @Nullable Camera camera
) {
478 if(camera
==null || data
==null)
480 camera
.stopPreview();
482 Utils
.sendConfirmMessage(toNonNull(context
), toNonNull(replyTo
), sending_photo
);
483 new SendDataAsyncTask(toNonNull(context
), toNonNull(replyTo
), toNonNull(hostname
), port
, data
).execute();
488 * Runnable that takes a screen capture and stores it in a file.
490 private static final class ScreencapRunnable
implements Runnable
{
491 private final Context context
;
492 private final Address replyTo
;
493 private final String filename
;
495 ScreencapRunnable(final Context context
, final Address replyTo
, final String filename
){
496 this.context
=context
;
497 this.replyTo
=replyTo
;
498 this.filename
=filename
;
505 exitCode
=Runtime
.getRuntime().exec(new String
[]{
508 "screencap -p \"" + filename
+ "\""
510 } catch (final Exception e
){
512 Utils
.sendMessage(toNonNull(context
), toNonNull(replyTo
), screencap_failed
);
516 if(exitCode
== 0 && new File(filename
).exists())
517 Utils
.sendConfirmMessage(toNonNull(context
), toNonNull(replyTo
), screencap_successful
);
519 Utils
.sendMessage(toNonNull(context
), toNonNull(replyTo
), screencap_failed
);
524 * Get help for a particular command
526 * @param context Context instance
527 * @param replyTo reply Address
528 * @param command command to get help for
530 public static void help(final Context context
, final Address replyTo
, final Command command
){//NOPMD method is a big switch statement. Nothing confusing.
533 Utils
.sendMessage(context
, replyTo
, answer_help
);
536 Utils
.sendMessage(context
, replyTo
, batt_help
);
539 Utils
.sendMessage(context
, replyTo
, bluetooth_help
);
542 Utils
.sendMessage(context
, replyTo
, calllog_help
);
545 Utils
.sendMessage(context
, replyTo
, contacts_help
);
548 Utils
.sendMessage(context
, replyTo
, data_help
);
550 case DELNOTIFICATION
:
551 Utils
.sendMessage(context
, replyTo
, delnotification_help
, Utils
.join(", ", toNonNull(MessageType
.values())));
554 Utils
.sendMessage(context
, replyTo
, dial_help
);
557 Utils
.sendMessage(context
, replyTo
, dialog_help
);
560 Utils
.sendMessage(context
, replyTo
, disable_help
, Utils
.join(", ", toNonNull(Command
.values())));
563 Utils
.sendMessage(context
, replyTo
, echo_help
);
566 Utils
.sendMessage(context
, replyTo
, enable_help
, Utils
.join(", ", toNonNull(Command
.values())));
569 Utils
.sendMessage(context
, replyTo
, flash_help
);
572 Utils
.sendMessage(context
, replyTo
, glocation_help
);
575 Utils
.sendMessage(context
, replyTo
, gps_help
);
578 Utils
.sendMessage(context
, replyTo
, hangup_help
);
581 Utils
.sendMessage(context
, replyTo
, help_help
, Utils
.join(", ",toNonNull(Command
.values())));
584 Utils
.sendMessage(context
, replyTo
, launch_help
);
587 Utils
.sendMessage(context
, replyTo
, location_help
, Utils
.join(", ",toNonNull(Utils
.LocationProvider
.values())));
590 Utils
.sendMessage(context
, replyTo
, lock_help
);
593 Utils
.sendMessage(context
, replyTo
, ls_help
);
596 Utils
.sendMessage(context
, replyTo
, ncfile_help
);
599 Utils
.sendMessage(context
, replyTo
, next_help
);
602 Utils
.sendMessage(context
, replyTo
, nolocation_help
);
605 Utils
.sendMessage(context
, replyTo
, pause_help
);
608 Utils
.sendMessage(context
, replyTo
, photo_help
);
611 Utils
.sendMessage(context
, replyTo
, play_help
);
614 Utils
.sendMessage(context
, replyTo
, poll_help
);
617 Utils
.sendMessage(context
, replyTo
, prev_help
);
620 Utils
.sendMessage(context
, replyTo
, ring_help
);
623 Utils
.sendMessage(context
, replyTo
, ringer_help
, Utils
.join(", ", toNonNull(RingerMode
.values())));
626 Utils
.sendMessage(context
, replyTo
, rm_help
);
628 case SETNOTIFICATION
:
629 Utils
.sendMessage(context
, replyTo
, setnotification_help
, Utils
.join(", ", toNonNull(MessageType
.values())));
632 Utils
.sendMessage(context
, replyTo
, setpassword_help
);
635 Utils
.sendMessage(context
, replyTo
, sms_help
);
638 Utils
.sendMessage(context
, replyTo
, smsq_help
);
641 Utils
.sendMessage(context
, replyTo
, smslog_help
);
644 Utils
.sendMessage(context
, replyTo
, speak_help
);
647 Utils
.sendMessage(context
, replyTo
, toast_help
);
650 Utils
.sendMessage(context
, replyTo
, vibrate_help
);
653 Utils
.sendMessage(context
, replyTo
, view_help
);
656 Utils
.sendMessage(context
, replyTo
, wifi_help
);
659 Utils
.sendMessage(context
, replyTo
, wipe_help
, Utils
.WIPE_CONFIRM_STRING
);
662 Utils
.sendMessage(context
, replyTo
, reboot_help
);
665 Utils
.sendMessage(context
, replyTo
, notify_help
);
668 Utils
.sendMessage(context
, replyTo
, screencap_help
);
671 Utils
.sendMessage(context
, replyTo
, torch_help
);
674 Utils
.sendMessage(context
, replyTo
, getfile_help
);
677 Utils
.sendMessage(context
, replyTo
, sh_help
);
680 Utils
.sendMessage(context
, replyTo
, rootsh_help
);
683 Utils
.sendMessage(context
, replyTo
, command_not_documented
);
690 * @see #startCamera(Context, Address)
693 private static Camera camera
;
695 * Ringtone used by the {@link Utils.Command#RING RING} command.
697 * @see #setupRingtone(Context)
699 private static Ringtone ringtone
;
701 * Saved ringer volume.
703 * @see #startAlarm(Context, Address)
704 * @see #stopAlarm(Context, Address)
706 private static int savedRingVolume
;
710 * @see #startAlarm(Context, Address)
711 * @see #stopAlarm(Context, Address)
713 private static int savedRingerMode
;
715 /** Private constructor */
721 * Convert a phone number type to a string
723 * @param context Context instance
724 * @param type phone number type
725 * @param label name of a custom phone type
726 * @return the phone number type
728 private static @Nullable String
phoneNumberType(final Context context
, final int type
, final @Nullable String label
) {
730 case BaseTypes
.TYPE_CUSTOM
:
732 case Phone
.TYPE_ASSISTANT
:
733 return context
.getString(phone_numer_type_assistant
);
734 case Phone
.TYPE_CALLBACK
:
735 return context
.getString(phone_number_type_callback
);
737 return context
.getString(phone_number_type_car
);
738 case Phone
.TYPE_COMPANY_MAIN
:
739 return context
.getString(phone_number_type_company_main
);
740 case Phone
.TYPE_FAX_HOME
:
741 return context
.getString(phone_number_type_home_fax
);
742 case Phone
.TYPE_FAX_WORK
:
743 return context
.getString(phone_number_type_work_fax
);
744 case Phone
.TYPE_HOME
:
745 return context
.getString(phone_number_type_home
);
746 case Phone
.TYPE_ISDN
:
747 return context
.getString(phone_number_type_isdn
);
748 case Phone
.TYPE_MAIN
:
749 return context
.getString(phone_number_type_main
);
751 return context
.getString(phone_number_type_mms
);
752 case Phone
.TYPE_MOBILE
:
753 return context
.getString(phone_number_type_mobile
);
754 case Phone
.TYPE_OTHER
:
755 return context
.getString(phone_number_type_other
);
756 case Phone
.TYPE_OTHER_FAX
:
757 return context
.getString(phone_number_type_other_fax
);
758 case Phone
.TYPE_PAGER
:
759 return context
.getString(phone_number_type_pager
);
760 case Phone
.TYPE_RADIO
:
761 return context
.getString(phone_number_type_radio
);
762 case Phone
.TYPE_TELEX
:
763 return context
.getString(phone_number_type_telex
);
764 case Phone
.TYPE_TTY_TDD
:
765 return context
.getString(phone_number_type_textphone
);
766 case Phone
.TYPE_WORK
:
767 return context
.getString(phone_number_type_work
);
768 case Phone
.TYPE_WORK_MOBILE
:
769 return context
.getString(phone_number_type_work_mobile
);
770 case Phone
.TYPE_WORK_PAGER
:
771 return context
.getString(phone_number_type_work_pager
);
774 return context
.getString(phone_number_type_unknown
, Integer
.valueOf(type
));
778 * Setup the ringtone used by the {@link Utils.Command#RING RING} command
780 * @param context Context
782 private static void setupRingtone(final Context context
){
783 if(ringtone
==null){//NOPMD not supposed to be thread-safe
784 final Uri alert
=RingtoneManager
.getDefaultUri(RingtoneManager
.TYPE_RINGTONE
);
785 ringtone
=RingtoneManager
.getRingtone(context
, alert
);
790 * Make the phone start ringing. Turns up the volume and sets the ringer mode to NORMAL
792 * @param context Context instance
793 * @param replyTo reply Address
795 private static void startAlarm(final Context context
, final Address replyTo
){
796 Utils
.registerOngoing(context
, toNonNull(OngoingEvent
.RING
));
797 final AudioManager man
=(AudioManager
) context
.getSystemService(Context
.AUDIO_SERVICE
);
798 savedRingerMode
=man
.getRingerMode();
799 man
.setRingerMode(AudioManager
.RINGER_MODE_NORMAL
);
800 savedRingVolume
=man
.getStreamVolume(AudioManager
.STREAM_RING
);
801 man
.setStreamVolume(AudioManager
.STREAM_RING
, man
.getStreamMaxVolume(AudioManager
.STREAM_RING
), 0);
802 Utils
.sendConfirmMessage(context
, replyTo
, ringing
);
807 * Get a camera instance.
809 * @param context Context instance
810 * @param replyTo reply Address
812 private static void startCamera(final Context context
, final Address replyTo
, final int cameraNumber
){
817 camera
=Camera
.open(cameraNumber
);
818 } catch (Exception ex
){
819 camera
=Camera
.open();
821 } catch (Exception e
){
822 Utils
.sendMessage(context
, replyTo
, cannot_grab_camera
);
827 * Make the phone stop ringing. Restores the volume and ringer mode.
829 * @param context Context instance
830 * @param replyTo reply Address
832 private static void stopAlarm(final Context context
, final Address replyTo
){
833 Utils
.unregisterOngoing(context
, toNonNull(OngoingEvent
.RING
));
834 final AudioManager man
=(AudioManager
) context
.getSystemService(Context
.AUDIO_SERVICE
);
835 Utils
.sendConfirmMessage(context
, replyTo
, no_longer_ringing
);
837 man
.setStreamVolume(AudioManager
.STREAM_RING
, savedRingVolume
, 0);
838 man
.setRingerMode(savedRingerMode
);
842 * Release the previously grabbed camera instance
844 * @see #startCamera(Context, Address)
846 private static void stopCamera(){
854 * Send battery status information to an Address
856 * @param context Context instance
857 * @param replyTo destination Address
859 * @see #describeBatteryLevel(Context, Address, MessageType)
861 public static void batt(final Context context
, final Address replyTo
){
862 describeBatteryLevel(context
, replyTo
, null);
866 * Show the bluetooth radio status.
868 * @param context Context instance
869 * @param replyTo destination Address
871 public static void bluetooth(final Context context
, final Address replyTo
) {
872 final BluetoothAdapter adapter
=BluetoothAdapter
.getDefaultAdapter();
874 Utils
.sendMessage(context
, replyTo
, no_bluetooth_adapter
);
878 if(adapter
.isEnabled())
879 Utils
.sendMessage(context
, replyTo
, bluetooth_on
);
881 Utils
.sendMessage(context
, replyTo
, bluetooth_off
);
885 * Set the bluetooth radio status.
887 * @param context Context instance
888 * @param replyTo destination Address
889 * @param on the requested radio status
891 public static void bluetooth(final Context context
, final Address replyTo
, final boolean on
){
892 final BluetoothAdapter adapter
=BluetoothAdapter
.getDefaultAdapter();
894 Utils
.sendMessage(context
, replyTo
, no_bluetooth_adapter
);
900 Utils
.sendConfirmMessage(context
, replyTo
, enabling_bluetooth
);
904 Utils
.sendConfirmMessage(context
, replyTo
, disabling_bluetooth
);
909 * Cancel an ongoing event.
911 * @param context Context instance
912 * @param event the event to cancel
914 public static void cancelOngoing(final Context context
, final OngoingEvent event
){
917 nolocation(context
, toNonNull(Address
.BLACKHOLE
));
920 ring(context
, toNonNull(Address
.BLACKHOLE
), false);
926 * Send the last calls to an Address.
928 * @param context Context instance
929 * @param replyTo destination Address
930 * @param numCalls how many calls to send
932 public static void calllog(final Context context
, final Address replyTo
, final int numCalls
) {
933 final String
[] fields
= {
934 Calls
.TYPE
, Calls
.NUMBER
, Calls
.CACHED_NAME
, Calls
.DURATION
, Calls
.DATE
937 final Cursor cursor
= context
.getContentResolver().query(
945 if (cursor
.moveToFirst()) {
947 final StringBuilder sb
=new StringBuilder(50);//NOPMD different strings
948 final int type
=cursor
.getInt(0);
949 final String from
=cursor
.getString(1);
952 case Calls
.INCOMING_TYPE
:
953 sb
.append(context
.getString(incoming_call_from
, from
));
955 case Calls
.MISSED_TYPE
:
956 sb
.append(context
.getString(missed_call_from
, from
));
958 case Calls
.OUTGOING_TYPE
:
959 sb
.append(context
.getString(outgoing_call_to
, from
));
963 if (cursor
.getString(2) != null)
964 sb
.append('(').append(cursor
.getString(2)).append(") ");
966 sb
.append(context
.getString(duration_seconds_starting_at
,
967 Long
.valueOf(cursor
.getLong(3)),
968 new Date(cursor
.getLong(4))));
970 Utils
.sendMessage(context
, replyTo
, toNonNull(sb
.toString()));
971 } while (cursor
.moveToNext() && cursor
.getPosition() < numCalls
);
978 * Search for contacts by name/nickname and send matching entries to an Address.
980 * @param context Context instance
981 * @param replyTo destination Address
982 * @param name name/nickname part to search for
984 @SuppressLint("StringFormatMatches")
985 public static void contacts(final Context context
, final Address replyTo
, final String name
){
986 final Cursor cursor
=context
.getContentResolver().query(Uri
.withAppendedPath(
987 Contacts
.CONTENT_FILTER_URI
, name
),
988 new String
[]{Contacts
.DISPLAY_NAME
, BaseColumns
._ID
, Contacts
.LOOKUP_KEY
},
989 null, null, Contacts
.DISPLAY_NAME
);
991 if(cursor
.getCount()==0)
992 Utils
.sendMessage(context
, replyTo
, no_matching_contacts_found
);
994 while(cursor
.moveToNext()){
995 final String
[] fields
= {
996 CommonDataKinds
.Phone
.NUMBER
,
997 CommonDataKinds
.Phone
.TYPE
,
998 CommonDataKinds
.Phone
.LABEL
,
1001 final Cursor inCursor
=context
.getContentResolver().query(Data
.CONTENT_URI
,
1003 Data
.CONTACT_ID
+" = ? AND "+Data
.MIMETYPE
+ " = ?",
1004 new String
[]{Long
.toString(cursor
.getLong(1)), CommonDataKinds
.Phone
.CONTENT_ITEM_TYPE
},
1005 CommonDataKinds
.Phone
.LABEL
);
1007 while(inCursor
.moveToNext())
1008 Utils
.sendMessage(context
, replyTo
, contact_info
,
1009 cursor
.getString(0),
1010 inCursor
.getString(0),
1011 phoneNumberType(context
, inCursor
.getInt(1), inCursor
.getString(2)));
1020 * Send battery status information to an Address or as a notification
1022 * @param context Context instance
1023 * @param replyTo Address to send the information to, if sending to a direct address. Null otherwise.
1024 * @param type Notification type, if sending as a notification. Null otherwise.
1026 public static void describeBatteryLevel(final Context context
, final @Nullable Address replyTo
, final @Nullable MessageType type
) {
1027 if(replyTo
==null&&type
==null)
1029 final Intent intent
=context
.registerReceiver(null, new IntentFilter(Intent
.ACTION_BATTERY_CHANGED
));
1032 final double level
=intent
.getIntExtra(BatteryManager
.EXTRA_LEVEL
, 0);
1033 final int scale
=intent
.getIntExtra(BatteryManager
.EXTRA_SCALE
, 100);
1034 final int plugged
=intent
.getIntExtra(BatteryManager
.EXTRA_PLUGGED
, 0);
1035 final int status
=intent
.getIntExtra(BatteryManager
.EXTRA_STATUS
, BatteryManager
.BATTERY_STATUS_UNKNOWN
);
1036 final int temp
=intent
.getIntExtra(BatteryManager
.EXTRA_TEMPERATURE
, 0);
1037 final int volt
=intent
.getIntExtra(BatteryManager
.EXTRA_VOLTAGE
, 0);
1039 final StringBuilder sb
=new StringBuilder(100);
1040 sb
.append(context
.getString(battery_level
, Double
.valueOf(level
*100/scale
)));
1044 sb
.append(context
.getString(not_plugged_in
));
1046 case BatteryManager
.BATTERY_PLUGGED_AC
:
1047 sb
.append(context
.getString(plugged_in_ac
));
1049 case BatteryManager
.BATTERY_PLUGGED_USB
:
1050 sb
.append(context
.getString(plugged_in_usb
));
1052 case BatteryManager
.BATTERY_PLUGGED_WIRELESS
:
1053 sb
.append(context
.getString(plugged_in_wireless
));
1058 case BatteryManager
.BATTERY_STATUS_CHARGING
:
1059 sb
.append(context
.getString(status_charging
));
1061 case BatteryManager
.BATTERY_STATUS_DISCHARGING
:
1062 sb
.append(context
.getString(status_discharging
));
1064 case BatteryManager
.BATTERY_STATUS_FULL
:
1065 sb
.append(context
.getString(status_full
));
1067 case BatteryManager
.BATTERY_STATUS_NOT_CHARGING
:
1068 sb
.append(context
.getString(status_not_charging
));
1070 case BatteryManager
.BATTERY_STATUS_UNKNOWN
:
1071 sb
.append(context
.getString(status_unknown
));
1075 sb
.append(context
.getString(temperature
, Integer
.valueOf(temp
)));
1077 sb
.append(context
.getString(voltage
, Integer
.valueOf(volt
)));
1079 Utils
.sendMessage(context
, toNonNull(replyTo
), toNonNull(sb
.toString()));
1081 Utils
.sendMessage(context
, type
, toNonNull(sb
.toString()));
1085 * Dial a phone number.
1087 * @param context Context instance
1088 * @param replyTo reply Address
1089 * @param nr phone number to dial
1091 public static void dial(final Context context
, final Address replyTo
, final String nr
){
1092 final Intent intent
=new Intent(Intent
.ACTION_CALL
,Uri
.parse("tel:"+nr
));
1093 intent
.addFlags(Intent
.FLAG_ACTIVITY_NEW_TASK
);
1094 final String name
=Utils
.callerId(context
, nr
);
1096 Utils
.sendConfirmMessage(context
, replyTo
, dialing
, nr
);
1098 Utils
.sendConfirmMessage(context
, replyTo
, dialing
, nr
+" ("+name
+")");
1099 context
.startActivity(intent
);
1103 * Show a dialog with a message and a list of buttons.
1105 * @param context Context instance
1106 * @param replyTo reply Address
1107 * @param message dialog message
1108 * @param buttons dialog buttons
1110 public static void dialog(final Context context
, final Address replyTo
, final String message
, final String
[] buttons
){
1111 final Intent intent
=new Intent(context
, DialogActivity
.class);
1112 intent
.putExtra(DialogActivity
.EXTRA_MESSAGE
, message
);
1113 intent
.putExtra(DialogActivity
.EXTRA_BUTTONS
, buttons
);
1114 intent
.putExtra(DialogActivity
.EXTRA_REPLYTO
, replyTo
.toString());
1116 Intent
.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
|
1117 Intent
.FLAG_ACTIVITY_NEW_TASK
|
1118 Intent
.FLAG_ACTIVITY_NO_USER_ACTION
|
1119 Intent
.FLAG_FROM_BACKGROUND
);
1120 Utils
.sendConfirmMessage(context
, toNonNull(replyTo
), showing_dialog
);
1121 context
.startActivity(intent
);
1125 * Turns the flashlight on or off.
1127 * @param context Context instance
1128 * @param replyTo reply Address
1129 * @param on requested flashlight state
1131 public static void flash(final Context context
, final Address replyTo
, final boolean on
){
1132 startCamera(context
, replyTo
, 0);
1135 final Camera
.Parameters parms
=camera
.getParameters();
1137 parms
.setFlashMode(Camera
.Parameters
.FLASH_MODE_TORCH
);
1138 camera
.setParameters(parms
);
1140 parms
.setFlashMode(Camera
.Parameters
.FLASH_MODE_AUTO
);
1141 camera
.setParameters(parms
);
1147 * Start sending location updates to an Address.
1149 * @param context Context instance
1150 * @param replyTo destination Address
1151 * @param provider LocationProvider
1152 * @param minTime minimum time between two consecutive updates (in ms)
1153 * @param minDistance minimum distance between two consecutive updates (in meters)
1155 * @see LocationManager#requestLocationUpdates(String, long, float, LocationListener)
1157 public static void location(final Context context
, final Address replyTo
, final String provider
,final long minTime
,final float minDistance
){
1158 final LocationManager man
=(LocationManager
) context
.getApplicationContext().getSystemService(Context
.LOCATION_SERVICE
);
1159 if(locationListener
!=null)
1160 nolocation(context
, toNonNull(Address
.BLACKHOLE
));
1161 Utils
.registerOngoing(context
, toNonNull(OngoingEvent
.LOCATION
));
1162 locationListener
=new FonBotLocationListener(context
, replyTo
);
1163 man
.removeUpdates(locationListener
);
1164 final Location lastKnownLocation
=man
.getLastKnownLocation(provider
);
1165 if(lastKnownLocation
!=null){
1166 Utils
.sendMessage(context
, replyTo
, last_known_location
);
1167 locationListener
.onLocationChanged(lastKnownLocation
);
1169 Utils
.sendConfirmMessage(context
, replyTo
, listening_for_location_updates
);
1170 man
.requestLocationUpdates(provider
, minTime
, minDistance
, locationListener
);
1176 * @param context Context instance
1177 * @param replyTo reply Address
1179 public static void lock(final Context context
, final Address replyTo
) {
1180 final DevicePolicyManager dpm
=(DevicePolicyManager
) context
.getSystemService(Context
.DEVICE_POLICY_SERVICE
);
1182 Utils
.sendConfirmMessage(context
, replyTo
, device_locked
);
1186 * Send a command to a running instance of the music player
1188 * @param context Context instance
1189 * @param replyTo reply Address
1190 * @param command command to send
1192 public static void musicPlayerCommand(final Context context
, final Address replyTo
, final String command
) {
1193 final Intent intent
=new Intent("com.android.music.musicservicecommand");
1194 intent
.putExtra("command", command
);
1195 context
.sendBroadcast(intent
);
1196 Utils
.sendConfirmMessage(context
, replyTo
, command_sent
);
1200 * Send a file to a server.
1202 * @param context Context instance
1203 * @param replyTo reply Address
1204 * @param filename file to send
1205 * @param hostname server hostname
1206 * @param port server port
1208 public static void ncfile(final Context context
, final Address replyTo
, final String filename
,final String hostname
,final int port
){
1209 new NcfileExecutableRunnable(context
, replyTo
, filename
, hostname
, port
).execute();
1213 * Stop sending location updates.
1215 * @param context Context instance
1216 * @param replyTo reply Address
1218 public static void nolocation(final Context context
, final Address replyTo
){
1219 Utils
.unregisterOngoing(context
, toNonNull(OngoingEvent
.LOCATION
));
1220 final LocationManager man
=(LocationManager
) context
.getApplicationContext().getSystemService(Context
.LOCATION_SERVICE
);
1221 man
.removeUpdates(locationListener
);
1222 locationListener
=null;
1223 Utils
.sendConfirmMessage(context
, replyTo
, no_longer_listening_for_location_updates
);
1227 * Take a photo and send it to a server.
1229 * @param context Context instance
1230 * @param replyTo reply Address
1231 * @param cameraNumber camera to take photo with
1232 * @param hostname server hostname
1233 * @param port server port
1235 public static void photo(final Context context
, final Address replyTo
, final int cameraNumber
, final String hostname
, final int port
){
1236 startCamera(context
, replyTo
, cameraNumber
);
1239 final Camera
.Parameters parms
=camera
.getParameters();
1240 parms
.setJpegQuality(70);
1241 parms
.setPictureFormat(ImageFormat
.JPEG
);
1242 camera
.setParameters(parms
);
1244 final SurfaceView fakeView
=new SurfaceView(context
);
1246 camera
.setPreviewDisplay(fakeView
.getHolder());
1247 } catch (IOException e
) {
1248 Utils
.sendMessage(context
, replyTo
, error_setting_preview_display
);
1251 camera
.startPreview();
1252 final Handler handler
=new Handler();
1254 new Thread(new Runnable() {
1257 SystemClock
.sleep(2000);
1259 handler
.post(new Runnable() {
1263 camera
.takePicture(null, null, new FonBotPictureCallback(context
, replyTo
, hostname
, port
));
1264 } catch(Exception e
){
1265 Utils
.sendMessage(context
, replyTo
, error_while_processing_command
, e
.getClass().getName(), e
.getMessage());
1274 * Send a directory listing to an Address
1276 * @param context Context instance
1277 * @param replyTo destination Address
1278 * @param directory directory to list
1280 public static void ls(final Context context
, final Address replyTo
, final String directory
) {
1281 final File
[] files
=new File(directory
).listFiles();
1283 Utils
.sendMessage(context
, replyTo
, string_is_not_a_directory
, directory
);
1287 final StringBuilder sb
=new StringBuilder(context
.getString(files_in_directory
,directory
));
1288 for(final File file
: files
){
1289 sb
.append(file
.getName());
1290 if(file
.isDirectory())
1295 Utils
.sendMessage(context
, replyTo
, toNonNull(sb
.toString()));
1299 * Make the phone start ringing if it is not ringing or stop ringing if it is.
1301 * @param context Context instance
1302 * @param replyTo reply Address
1304 public static void ring(final Context context
, final Address replyTo
){
1305 setupRingtone(context
);
1307 Utils
.sendMessage(context
, replyTo
, no_ringtone_found
);
1310 if(ringtone
.isPlaying())
1311 stopAlarm(context
, replyTo
);
1313 startAlarm(context
, replyTo
);
1317 * Make the phone start/stop ringing.
1319 * @param context Context instance
1320 * @param replyTo reply Address
1321 * @param on true if the phone should start ringing, false otherwise
1323 public static void ring(final Context context
, final Address replyTo
, final boolean on
){
1324 setupRingtone(context
);
1326 Utils
.sendMessage(context
, replyTo
, no_ringtone_found
);
1329 if(on
&&!ringtone
.isPlaying())
1330 startAlarm(context
, replyTo
);
1331 else if(ringtone
.isPlaying()&&!on
)
1332 stopAlarm(context
, replyTo
);
1336 * Send the current ringer mode to an Address
1338 * @param context Context instance
1339 * @param replyTo destination Address
1341 public static void ringer(final Context context
, final Address replyTo
){
1342 final AudioManager man
=(AudioManager
) context
.getSystemService(Context
.AUDIO_SERVICE
);
1343 switch(man
.getRingerMode()){
1344 case AudioManager
.RINGER_MODE_NORMAL
:
1345 Utils
.sendMessage(context
, replyTo
, ringer_mode_normal
);
1347 case AudioManager
.RINGER_MODE_VIBRATE
:
1348 Utils
.sendMessage(context
, replyTo
, ringer_mode_vibrate
);
1350 case AudioManager
.RINGER_MODE_SILENT
:
1351 Utils
.sendMessage(context
, replyTo
, ringer_mode_silent
);
1354 Utils
.sendMessage(context
, replyTo
, unknown_ringer_mode
);
1359 * Set the ringer mode.
1361 * @param context Context instance
1362 * @param replyTo reply Address
1363 * @param ringerMode requested ringer mode
1365 * @see Utils.RingerMode
1367 public static void ringer(final Context context
, final Address replyTo
, final int ringerMode
){
1368 final AudioManager man
=(AudioManager
) context
.getSystemService(Context
.AUDIO_SERVICE
);
1369 man
.setRingerMode(ringerMode
);
1370 ringer(context
, replyTo
);
1374 * Remove a file or empty directory.
1376 * @param context Context instance
1377 * @param replyTo reply Address
1378 * @param filename file/empty directory to delete
1380 public static void rm(final Context context
, final Address replyTo
, final String filename
){
1381 if(new File(filename
).delete())
1382 Utils
.sendConfirmMessage(context
, replyTo
, file_deleted
);
1384 Utils
.sendMessage(context
, replyTo
, error_while_deleting_file
);
1388 * Clear the keyguard password.
1390 * @param context Context instance
1391 * @param replyTo reply Address
1392 * @throws SecurityException if FonBot does not have device administration permissions
1394 public static void setPassword(final Context context
, final Address replyTo
) throws SecurityException
{
1395 final DevicePolicyManager dpm
=(DevicePolicyManager
) context
.getSystemService(Context
.DEVICE_POLICY_SERVICE
);
1397 dpm
.resetPassword("", 0);
1398 Utils
.sendConfirmMessage(context
, replyTo
, password_cleared
);
1402 * Change the keyguard password.
1404 * @param context Context instance
1405 * @param replyTo reply Address
1406 * @param password new password
1407 * @throws SecurityException if FonBot does not have device administration permissions
1409 public static void setPassword(final Context context
, final Address replyTo
, final String password
) throws SecurityException
{
1410 final DevicePolicyManager dpm
=(DevicePolicyManager
) context
.getSystemService(Context
.DEVICE_POLICY_SERVICE
);
1412 dpm
.resetPassword(password
, 0);
1413 Utils
.sendConfirmMessage(context
, replyTo
, password_set
);
1417 * Send a text message.
1419 * @param context Context instance
1420 * @param replyTo reply Address
1421 * @param destination destination phone number
1422 * @param text text message contents
1424 public static void sms(final Context context
, final Address replyTo
, final String destination
, final String text
, final boolean quiet
){
1425 final SmsManager manager
=SmsManager
.getDefault();
1426 final ArrayList
<String
> messages
=manager
.divideMessage(text
);
1427 if(messages
.size() > 1)
1428 Utils
.sendConfirmMessage(context
, replyTo
, message_was_split_into_parts
, Integer
.valueOf(messages
.size()));
1430 final ArrayList
<PendingIntent
> sents
=new ArrayList
<PendingIntent
>(messages
.size());
1431 final ArrayList
<PendingIntent
> delivereds
=new ArrayList
<PendingIntent
>(messages
.size());
1433 final String name
=Utils
.callerId(context
, destination
);
1434 final String fullDestination
;
1436 fullDestination
=destination
;
1438 fullDestination
=destination
+" ("+name
+")";
1440 for(int i
=0;i
<messages
.size();i
++){
1441 final Intent sent
=new Intent(context
,SmsStatusReceiver
.class);
1442 sent
.putExtra(SmsStatusReceiver
.EXTRA_DESTINATION
, fullDestination
);
1443 sent
.putExtra(SmsStatusReceiver
.EXTRA_PART
, i
+1);
1444 sent
.putExtra(SmsStatusReceiver
.EXTRA_TOTAL
, messages
.size());
1445 sent
.putExtra(SmsStatusReceiver
.EXTRA_REPLY_TO
, replyTo
.toString());
1446 sent
.setAction(SmsStatusReceiver
.SENT_ACTION
+i
+System
.currentTimeMillis());//actions must be unique
1447 sents
.add(PendingIntent
.getBroadcast(context
, 0, sent
, PendingIntent
.FLAG_UPDATE_CURRENT
));
1449 final Intent delivered
=new Intent(context
, SmsStatusReceiver
.class);
1450 delivered
.putExtra(SmsStatusReceiver
.EXTRA_DESTINATION
, fullDestination
);
1451 delivered
.putExtra(SmsStatusReceiver
.EXTRA_PART
, i
+1);
1452 delivered
.putExtra(SmsStatusReceiver
.EXTRA_TOTAL
, messages
.size());
1453 delivered
.putExtra(SmsStatusReceiver
.EXTRA_REPLY_TO
, replyTo
.toString());
1454 delivered
.setAction(SmsStatusReceiver
.DELIVERED_ACTION
+i
+System
.currentTimeMillis());//actions must be unique
1455 delivereds
.add(PendingIntent
.getBroadcast(context
, 0, delivered
, PendingIntent
.FLAG_UPDATE_CURRENT
));
1458 Log
.d(Heavy
.class.getName(), "Sending sms to "+destination
);
1459 manager
.sendMultipartTextMessage(destination
, null, messages
, sents
, quiet ?
null : delivereds
);
1463 * Send the last SMSes to an Address.
1465 * @param context Context instance
1466 * @param replyTo destination Address
1467 * @param numSms how many SMSes to send
1469 public static void smslog(final Context context
, final Address replyTo
, final int numSms
) {
1470 final String
[] fields
= {"type","address", "body", "date"};
1472 final Cursor cursor
= context
.getContentResolver().query (
1473 Uri
.parse("content://sms"),
1480 if (cursor
.moveToFirst()) {
1482 final String fromNumber
=cursor
.getString(1);
1484 if(fromNumber
== null)
1487 final String name
=Utils
.callerId(context
, Utils
.toNonNull(fromNumber
));
1491 from
=fromNumber
+" ("+name
+')';
1494 final String message
=cursor
.getString(2).replace("\n", "\n ");
1495 final Date date
=new Date(cursor
.getLong(3));
1497 if(cursor
.getInt(0)==1)
1498 Utils
.sendMessage(context
, replyTo
, incoming_message
, from
, message
, date
);
1500 Utils
.sendMessage(context
, replyTo
, outgoing_message
, from
, message
, date
);
1501 } while (cursor
.moveToNext() && cursor
.getPosition() < numSms
);
1507 /** TTS instance, only used by {@link #speak(Context, Address, String)} */
1508 private static TextToSpeech tts
;
1511 * Speak a String using the text-to-speech engine.
1513 * @param context Context instance
1514 * @param replyTo reply Address
1515 * @param text text to speak
1517 public static void speak(final Context context
, final Address replyTo
, final String text
){
1518 tts
=new TextToSpeech(context
, new OnInitListener() {
1520 public void onInit(final int status
) {
1521 if(status
==TextToSpeech
.SUCCESS
){
1522 Utils
.sendConfirmMessage(context
, replyTo
, speaking
);
1523 tts
.speak(text
, TextToSpeech
.QUEUE_ADD
, null);
1525 Utils
.sendMessage(context
, replyTo
, tts_engine_not_available
);
1531 * Show a toast notification with the default duration.
1533 * @param context Context instance
1534 * @param replyTo reply Address
1535 * @param text toast text
1537 public static void toast(final Context context
, final Address replyTo
, final String text
){
1538 toast(context
, replyTo
, text
, Toast
.LENGTH_SHORT
);
1542 * Show a toast notification.
1544 * @param context Context instance
1545 * @param replyTo reply Address
1546 * @param text toast text
1547 * @param duration toast duration
1549 public static void toast(final Context context
, final Address replyTo
, final String text
, final int duration
){
1550 Toast
.makeText(context
,text
,duration
).show();
1551 Utils
.sendConfirmMessage(context
, replyTo
, toast_shown
);
1555 * Make the phone vibrate for a number of milliseconds.
1557 * @param context Context instance
1558 * @param replyTo reply Address
1559 * @param ms vibrate duration, in milliseconds
1561 public static void vibrate(final Context context
, final Address replyTo
, final long ms
){
1562 final Vibrator v
=(Vibrator
) context
.getSystemService(Context
.VIBRATOR_SERVICE
);
1563 Utils
.sendConfirmMessage(context
, replyTo
, vibrating
);
1568 * View an URI in an appropriate activity.
1570 * @param context Context instance
1571 * @param replyTo reply Address
1572 * @param uri URI to view
1574 public static void view(final Context context
, final Address replyTo
, final Uri uri
) {
1576 final Intent intent
=new Intent(Intent
.ACTION_VIEW
);
1577 intent
.setData(uri
);
1578 intent
.setFlags(Intent
.FLAG_FROM_BACKGROUND
|Intent
.FLAG_ACTIVITY_NEW_TASK
);
1579 context
.startActivity(intent
);
1580 Utils
.sendConfirmMessage(context
, replyTo
, url_opened
);
1581 } catch(ActivityNotFoundException e
){
1582 Utils
.sendMessage(context
, replyTo
, no_activity_found_for_this_url
);
1583 } catch(Exception e
){
1584 Utils
.sendMessage(context
, replyTo
, invalid_url
);
1589 * Get the current WiFi state.
1591 * @param context Context instance
1592 * @param replyTo reply Address
1594 public static void wifi(final Context context
, final Address replyTo
){
1595 final WifiManager man
=(WifiManager
) context
.getSystemService(Context
.WIFI_SERVICE
);
1596 if(man
.isWifiEnabled())
1597 Utils
.sendMessage(context
, replyTo
, wifi_on
);
1599 Utils
.sendMessage(context
, replyTo
, wifi_off
);
1603 * Set the WiFi state.
1605 * @param context Context instance
1606 * @param replyTo reply Address
1607 * @param on the requested WiFi state
1609 public static void wifi(final Context context
, final Address replyTo
, final boolean on
){
1610 final WifiManager man
=(WifiManager
) context
.getSystemService(Context
.WIFI_SERVICE
);
1611 man
.setWifiEnabled(on
);
1613 Utils
.sendConfirmMessage(context
, replyTo
, enabling_wifi
);
1615 Utils
.sendConfirmMessage(context
, replyTo
, disabling_wifi
);
1619 * Factory reset the phone, optionally deleting the SD card too.
1621 * @param context Context instance
1622 * @param type {@link Utils.WipeType} instance
1623 * @throws SecurityException if FonBot does not have device administration permissions
1625 @SuppressLint("InlinedApi")
1626 public static void wipe(final Context context
, final WipeType type
) throws SecurityException
{
1627 final DevicePolicyManager dpm
=(DevicePolicyManager
) context
.getSystemService(Context
.DEVICE_POLICY_SERVICE
);
1634 dpm
.wipeData(DevicePolicyManager
.WIPE_EXTERNAL_STORAGE
);
1640 * Disable a Command. The command cannot be used until enabled again with the {@link Utils.Command#ENABLE ENABLE} command.
1642 * @param context Context instance
1643 * @param replyTo reply Address
1644 * @param command Command to disable
1646 public static void disable(final Context context
, final Address replyTo
, final Command command
){
1647 PreferenceManager
.getDefaultSharedPreferences(context
).edit()
1648 .putBoolean(command
+"disabled", true).commit();
1649 Utils
.sendConfirmMessage(context
, replyTo
, command_disabled
, command
);
1653 * Re-enable a disabled Command.
1655 * @param context Context instance
1656 * @param replyTo reply Address
1657 * @param command Command to re-enable
1659 public static void enable(final Context context
, final Address replyTo
, final Command command
){
1660 PreferenceManager
.getDefaultSharedPreferences(context
).edit()
1661 .remove(command
+"disabled").commit();
1662 Utils
.sendConfirmMessage(context
, replyTo
, command_enabled
, command
);
1667 * Check whether a Command is disabled.
1669 * @param context Context instance
1670 * @param command Command to check
1671 * @return true if the Command is disabled, false otherwise
1673 public static boolean isCommandDisabled(final Context context
, final Command command
){
1674 return PreferenceManager
.getDefaultSharedPreferences(context
).getBoolean(command
+"disabled", false);
1678 * Start long polling if stopped
1680 * @param context Context instance
1681 * @param replyTo reply Address
1683 public static void poll(final Context context
, final Address replyTo
) {
1684 Utils
.sendConfirmMessage(context
, replyTo
, starting_long_polling_if_stopped
);
1685 context
.startService(new Intent(context
, FonBotMainService
.class));
1689 * Get an instance of {@link ITelephony}
1691 * @param context Context instance
1692 * @return an instance of {@link ITelephony}
1693 * @throws NoSuchMethodException thrown by reflection
1694 * @throws IllegalArgumentException thrown by reflection
1695 * @throws IllegalAccessException thrown by reflection
1696 * @throws InvocationTargetException thrown by reflection
1698 private static ITelephony
getITelephony(final Context context
) throws NoSuchMethodException
, IllegalArgumentException
, IllegalAccessException
, InvocationTargetException
{
1699 final TelephonyManager man
=(TelephonyManager
) context
.getSystemService(Context
.TELEPHONY_SERVICE
);
1700 final Method m
=TelephonyManager
.class.getDeclaredMethod("getITelephony");
1701 m
.setAccessible(true);
1702 return toNonNull((ITelephony
) m
.invoke(man
));
1706 * Hang up the phone.
1708 * @param context Context instance
1709 * @param replyTo reply Address
1711 public static void hangup(final Context context
, final Address replyTo
){
1713 getITelephony(context
).endCall();
1714 } catch(Exception e
){
1715 Utils
.sendMessage(context
, replyTo
, exception_while_hanging_up_call
,
1716 e
.getClass().getName(), e
.getMessage());
1721 * Answer the phone if it is ringing.
1723 * @param context Context instance
1724 * @param replyTo reply Address
1726 public static void answer(final Context context
, final Address replyTo
){
1728 getITelephony(context
).answerRingingCall();
1729 } catch(Exception e
){
1730 Utils
.sendMessage(context
, replyTo
, exception_while_answering_call
,
1731 e
.getClass().getName(), e
.getMessage());
1738 * @param context Context instance
1739 * @param replyTo reply Address
1740 * @param pkg name of the package to launch
1742 public static void launch(final Context context
, final Address replyTo
, final String pkg
){
1743 final Intent intent
=context
.getPackageManager().getLaunchIntentForPackage(pkg
);
1745 Utils
.sendMessage(context
, replyTo
, no_such_package
);
1748 context
.startActivity(intent
);
1749 Utils
.sendConfirmMessage(context
, replyTo
, app_launched
);
1753 * Get the mobile data enabled status.
1755 * @param context Context instance
1756 * @param replyTo reply Address
1758 public static void data(final Context context
, final Address replyTo
){
1760 final ConnectivityManager man
=(ConnectivityManager
) context
.getSystemService(Context
.CONNECTIVITY_SERVICE
);
1761 final Method m
=ConnectivityManager
.class.getDeclaredMethod("getMobileDataEnabled");
1762 m
.setAccessible(true);
1763 if(((Boolean
)m
.invoke(man
)).booleanValue())
1764 Utils
.sendMessage(context
, replyTo
, data_on
);
1766 Utils
.sendMessage(context
, replyTo
, data_off
);
1767 } catch(Exception e
){
1768 Utils
.sendMessage(context
, replyTo
, exception_while_determining_data_state
,
1769 e
.getClass().getName(), e
.getMessage());
1774 * Set the mobile data enabled status.
1776 * @param context Context instance
1777 * @param replyTo reply Address
1778 * @param enable whether to enable mobile data
1780 public static void data(final Context context
, final Address replyTo
, final boolean enable
) {
1783 getITelephony(context
).enableDataConnectivity();
1784 Utils
.sendConfirmMessage(context
, replyTo
, enabling_data
);
1786 getITelephony(context
).disableDataConnectivity();
1787 Utils
.sendConfirmMessage(context
, replyTo
, disabling_data
);
1789 } catch(Exception e
){
1790 Utils
.sendMessage(context
, replyTo
, exception_while_getting_itelephony
,
1791 e
.getClass().getName(), e
.getMessage());
1796 * Get the GPS status.
1798 * @param context Context instance
1799 * @param replyTo reply Address
1801 public static void gps(final Context context
, final Address replyTo
){
1802 if(Secure
.isLocationProviderEnabled(context
.getContentResolver(), LocationManager
.GPS_PROVIDER
))
1803 Utils
.sendMessage(context
, replyTo
, gps_on
);
1805 Utils
.sendMessage(context
, replyTo
, gps_off
);
1809 * Set the GPS status.
1811 * @param context Context instance
1812 * @param replyTo reply Address
1813 * @param enabled requested GPS status
1815 public static void gps(final Context context
, final Address replyTo
, final boolean enabled
) {
1816 Secure
.setLocationProviderEnabled(context
.getContentResolver(), LocationManager
.GPS_PROVIDER
, enabled
);
1818 Utils
.sendConfirmMessage(context
, replyTo
, enabling_gps
);
1820 Utils
.sendConfirmMessage(context
, replyTo
, disabling_gps
);
1824 * Get the Google location (aka network location) state.
1826 * @param context Context instance
1827 * @param replyTo reply Address
1829 public static void glocation(final Context context
, final Address replyTo
){
1830 if(Secure
.isLocationProviderEnabled(context
.getContentResolver(), LocationManager
.NETWORK_PROVIDER
))
1831 Utils
.sendMessage(context
, replyTo
, network_location_on
);
1833 Utils
.sendMessage(context
, replyTo
, network_location_off
);
1837 * Set the Google location (aka network location) state.
1839 * @param context Context instance
1840 * @param replyTo reply Address
1841 * @param enabled requested Google location state
1843 public static void glocation(final Context context
, final Address replyTo
, final boolean enabled
) {
1844 Secure
.setLocationProviderEnabled(context
.getContentResolver(), LocationManager
.NETWORK_PROVIDER
, enabled
);
1846 Utils
.sendConfirmMessage(context
, replyTo
, enabling_network_location
);
1848 Utils
.sendConfirmMessage(context
, replyTo
, disabling_network_location
);
1854 * @param context Context instance
1855 * @param replyTo reply Address
1856 * @param reason reboot reason
1858 * @see PowerManager#reboot(String)
1860 public static void reboot(final Context context
, final Address replyTo
, final @Nullable String reason
) {
1861 final PowerManager pm
=(PowerManager
) context
.getSystemService(Context
.POWER_SERVICE
);
1862 Utils
.sendConfirmMessage(context
, replyTo
, rebooting
);
1865 } catch (final Exception e
){
1866 e
.printStackTrace();
1869 Runtime
.getRuntime().exec(new String
[]{
1874 } catch (final Exception e
){
1875 e
.printStackTrace();
1877 Utils
.sendMessage(toNonNull(context
), toNonNull(replyTo
), reboot_failed
);
1881 * Cancel a notification.
1883 * @param context Context instance
1884 * @param replyTo reply Address
1885 * @param id notification ID
1887 public static void notify(final Context context
, final Address replyTo
, final int id
) {
1888 final NotificationManager man
=(NotificationManager
) context
.getSystemService(Context
.NOTIFICATION_SERVICE
);
1890 Utils
.sendConfirmMessage(context
, replyTo
, notification_canceled
);
1894 * Show a notification.
1896 * @param context Context instance
1897 * @param replyTo reply Address
1898 * @param id notification ID
1899 * @param title notificationO title
1900 * @param text notification text
1902 public static void notify(final Context context
, final Address replyTo
, final int id
, final String title
, final String text
) {
1903 final NotificationManager man
=(NotificationManager
) context
.getSystemService(Context
.NOTIFICATION_SERVICE
);
1904 man
.notify(id
, new NotificationCompat
.Builder(context
).
1905 setContentTitle(title
).
1906 setContentText(text
).
1907 setSmallIcon(android
.R
.drawable
.stat_notify_sync_noanim
).
1909 Utils
.sendConfirmMessage(context
, replyTo
, notification_shown
);
1913 * Take a screen capture. Uses the screencap utility and requires root.
1915 * @param context Context instance
1916 * @param replyTo reply Address
1917 * @param filename capture file location
1919 public static void screencap(final Context context
, final Address replyTo
, final String filename
){
1920 new Thread(new ScreencapRunnable(context
, replyTo
, filename
)).start();
1924 * Toggle the torch state using the Torch (net.cactii.torch2) app.
1926 * @param context Context instance
1927 * @param replyTo reply Address
1929 public static void torch(final Context context
, final Address replyTo
){
1930 context
.sendBroadcast(new Intent("net.cactii.flash2.TOGGLE_FLASHLIGHT"));
1931 Utils
.sendConfirmMessage(context
, replyTo
, toggling_torch_state
);
1935 * Download a file from a given URL to a given filename
1937 * @param context Context instance
1938 * @param replyTo reply Address
1939 * @param filename filename to save to
1940 * @param hostname hostname to download from
1941 * @param port port to download from
1943 public static void getfile(final Context context
, final Address replyTo
, final String filename
, final String hostname
, final int port
){
1944 new GetfileExecutableRunnable(context
, replyTo
, filename
, hostname
, port
).execute();
1948 * Execute a command using a given shell and reply with the output.
1950 * @param context Context instance
1951 * @param replyTo reply Address
1952 * @param shell The shell to execute with. Usually sh or su.
1953 * @param command The command to pass to the shell.
1955 public static void execute(final Context context
, final Address replyTo
, final String shell
, final String command
) {
1957 final Process proc
= Runtime
.getRuntime().exec(new String
[]{
1962 final BufferedReader br
= new BufferedReader (new InputStreamReader(proc
.getInputStream()));
1964 while((line
= br
.readLine()) != null)
1965 Utils
.sendMessage(context
, replyTo
, line
);
1967 } catch (final Exception e
){
1968 Utils
.sendMessage(context
, replyTo
, error_while_processing_command
, e
.getClass().getName(), e
.getMessage());
1969 Log
.w(Heavy
.class.getName(), "Error while processing command", e
);