]> iEval git - fonbot.git/blob - src/ro/ieval/fonbot/Heavy.java
Remove trust managers from HttpCallExecutableRunnable
[fonbot.git] / src / ro / ieval / fonbot / Heavy.java
1 package ro.ieval.fonbot;
2
3 import static ro.ieval.fonbot.R.string.*;
4 import static ro.ieval.fonbot.Utils.toNonNull;
5
6 import java.io.File;
7 import java.io.FileInputStream;
8 import java.io.FileNotFoundException;
9 import java.io.IOException;
10 import java.lang.reflect.InvocationTargetException;
11 import java.lang.reflect.Method;
12 import java.net.InetSocketAddress;
13 import java.net.Socket;
14 import java.net.UnknownHostException;
15 import java.nio.channels.FileChannel;
16 import java.nio.channels.SocketChannel;
17 import java.util.ArrayList;
18 import java.util.Date;
19
20 import org.eclipse.jdt.annotation.Nullable;
21
22 import ro.ieval.fonbot.Utils.Command;
23 import ro.ieval.fonbot.Utils.MessageType;
24 import ro.ieval.fonbot.Utils.OngoingEvent;
25 import ro.ieval.fonbot.Utils.RingerMode;
26 import ro.ieval.fonbot.Utils.WipeType;
27 import android.annotation.SuppressLint;
28 import android.app.AlarmManager;
29 import android.app.NotificationManager;
30 import android.app.PendingIntent;
31 import android.app.admin.DevicePolicyManager;
32 import android.bluetooth.BluetoothAdapter;
33 import android.content.ActivityNotFoundException;
34 import android.content.Context;
35 import android.content.Intent;
36 import android.content.IntentFilter;
37 import android.database.Cursor;
38 import android.graphics.ImageFormat;
39 import android.hardware.Camera;
40 import android.hardware.Camera.PictureCallback;
41 import android.location.Location;
42 import android.location.LocationListener;
43 import android.location.LocationManager;
44 import android.location.LocationProvider;
45 import android.media.AudioManager;
46 import android.media.Ringtone;
47 import android.media.RingtoneManager;
48 import android.net.ConnectivityManager;
49 import android.net.Uri;
50 import android.net.wifi.WifiManager;
51 import android.os.AsyncTask;
52 import android.os.BatteryManager;
53 import android.os.Bundle;
54 import android.os.Handler;
55 import android.os.PowerManager;
56 import android.os.Vibrator;
57 import android.preference.PreferenceManager;
58 import android.provider.BaseColumns;
59 import android.provider.CallLog.Calls;
60 import android.provider.ContactsContract.CommonDataKinds;
61 import android.provider.ContactsContract.CommonDataKinds.BaseTypes;
62 import android.provider.ContactsContract.CommonDataKinds.Phone;
63 import android.provider.ContactsContract.Contacts;
64 import android.provider.ContactsContract.Data;
65 import android.provider.Settings.Secure;
66 import android.speech.tts.TextToSpeech;
67 import android.speech.tts.TextToSpeech.OnInitListener;
68 import android.support.v4.app.NotificationCompat;
69 import android.telephony.SmsManager;
70 import android.telephony.TelephonyManager;
71 import android.util.Log;
72 import android.view.SurfaceView;
73 import android.widget.Toast;
74
75 import com.android.internal.telephony.ITelephony;
76
77 /*
78 * Copyright © 2013 Marius Gavrilescu
79 *
80 * This file is part of FonBot.
81 *
82 * FonBot is free software: you can redistribute it and/or modify
83 * it under the terms of the GNU General Public License as published by
84 * the Free Software Foundation, either version 3 of the License, or
85 * (at your option) any later version.
86 *
87 * FonBot is distributed in the hope that it will be useful,
88 * but WITHOUT ANY WARRANTY; without even the implied warranty of
89 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
90 * GNU General Public License for more details.
91 *
92 * You should have received a copy of the GNU General Public License
93 * along with FonBot. If not, see <http://www.gnu.org/licenses/>.
94 */
95
96 /**
97 * Implementation of all FonBot commands. The methods of this class do not do argument checking.
98 *
99 * @author Marius Gavrilescu <marius@ieval.ro>
100 */
101 final class Heavy {
102 /**
103 * LocationListener that sends notifications to the user.
104 *
105 * @author Marius Gavrilescu <marius@ieval.ro>
106 */
107 private static final class FonBotLocationListener implements LocationListener {
108 /** Context instance */
109 private final Context context;
110 /** Destination address for notifications */
111 private final Address replyTo;
112
113 /**
114 * Construct a FonBotLocationListener.
115 *
116 * @param context Context instance
117 * @param replyTo the reply address
118 */
119 FonBotLocationListener(final Context context, final Address replyTo) {
120 this.context=context;
121 this.replyTo=replyTo;
122 }
123
124 @Override
125 public void onLocationChanged(@Nullable final Location loc) {
126 if(loc==null)
127 return;
128 final StringBuilder sb=new StringBuilder(toNonNull(context.getString(location)));
129 sb.append(": ");
130 sb.append(toNonNull(context.getString(latitude)));
131 sb.append(": ");
132 sb.append(loc.getLatitude());
133 sb.append(", ");
134 sb.append(toNonNull(context.getString(longitude)));
135 sb.append(": ");
136 sb.append(loc.getLongitude());
137
138 if(loc.hasAccuracy()){
139 sb.append(", ");
140 sb.append(toNonNull(context.getString(accuracy)));
141 sb.append(": ");
142 sb.append(loc.getAccuracy());
143 }
144
145 if(loc.hasAltitude()){
146 sb.append(", ");
147 sb.append(toNonNull(context.getString(altitude)));
148 sb.append(": ");
149 sb.append(loc.getAltitude());
150 }
151
152 if(loc.hasBearing()){
153 sb.append(", ");
154 sb.append(toNonNull(context.getString(bearing)));
155 sb.append(": ");
156 sb.append(loc.getBearing());
157 }
158
159 if(loc.hasSpeed()){
160 sb.append(", ");
161 sb.append(toNonNull(context.getString(speed)));
162 sb.append(": ");
163 sb.append(loc.getSpeed());
164 }
165
166 final Date locationDate=new Date(loc.getTime());
167 sb.append(" ");
168 sb.append(toNonNull(context.getString(at)));
169 sb.append(" ");
170 sb.append(locationDate.toString());
171 Utils.sendMessage(toNonNull(context), toNonNull(replyTo), toNonNull(sb.toString()));
172 }
173
174 @Override
175 public void onProviderDisabled(@Nullable final String provider) {
176 Utils.sendMessage(toNonNull(context), toNonNull(replyTo), location_provider_disabled, provider);
177 }
178
179 @Override
180 public void onProviderEnabled(@Nullable final String provider) {
181 Utils.sendMessage(toNonNull(context), toNonNull(replyTo), location_provider_enabled, provider);
182 }
183
184 @Override
185 public void onStatusChanged(@Nullable final String provider, final int status, @Nullable final Bundle extras) {
186 final int state;
187 switch(status){
188 case LocationProvider.AVAILABLE:
189 state=location_provider_available;
190 break;
191 case LocationProvider.TEMPORARILY_UNAVAILABLE:
192 state=location_provider_temporary_unavailable;
193 break;
194 case LocationProvider.OUT_OF_SERVICE:
195 state=location_provider_out_of_service;
196 break;
197 default:
198 state=location_provider_unknown_state;
199 }
200 Utils.sendMessage(toNonNull(context), toNonNull(replyTo), state, provider);
201 }
202 }
203 /**
204 * Currently active FonBotLocationListener
205 */
206 private static FonBotLocationListener locationListener = null;
207
208 /**
209 * AsyncTask that sends a byte[] to a server
210 *
211 * @author Marius Gavrilescu <marius@ieval.ro>
212 *
213 */
214 private static class SendDataAsyncTask extends AsyncTask<Void, Void, Void>{
215 /**
216 * Context instance used by this class
217 */
218 private final Context context;
219 /**
220 * Server hostname
221 */
222 private final String hostname;
223 /**
224 * Server port
225 */
226 private final int port;
227 /**
228 * Data to send
229 */
230 private final byte[] data;
231 /**
232 * Address for sending back errors and success messages
233 */
234 private final Address replyTo;
235
236 /**
237 * Constructs a SendDataAsyncTasks from its parameters
238 *
239 * @param context the context
240 * @param replyTo the reply Address
241 * @param hostname the server hostname
242 * @param port the server port
243 * @param data the data to send
244 */
245 public SendDataAsyncTask(final Context context,final Address replyTo, final String hostname, final int port, final byte[] data) {//NOPMD array is immutable
246 super();
247 this.context=context;
248 this.hostname=hostname;
249 this.port=port;
250 this.data=data;
251 this.replyTo=replyTo;
252 }
253
254 @Override
255 protected @Nullable Void doInBackground(@Nullable final Void... params) {
256 final Socket sock;
257 try {
258 sock = new Socket(hostname, port);
259 try {
260 sock.getOutputStream().write(data);
261 } catch (IOException e) {
262 Utils.sendMessage(toNonNull(context), toNonNull(replyTo), error_writing_to_socket, e.getMessage());
263 return null;
264 }
265
266 try {
267 sock.close();
268 } catch (IOException e) {
269 Utils.sendMessage(toNonNull(context), toNonNull(replyTo), cannot_close_socket, e.getMessage());
270 return null;
271 }
272 } catch (UnknownHostException e) {
273 Utils.sendMessage(toNonNull(context), toNonNull(replyTo), unknown_host, hostname);
274 return null;
275 } catch (IOException e) {
276 Utils.sendMessage(toNonNull(context), toNonNull(replyTo), cannot_connect_to_host_on_port, hostname, Integer.valueOf(port));
277 return null;
278 }
279 Utils.sendMessage(toNonNull(context), toNonNull(replyTo), photo_sent);
280 return null;
281 }
282 }
283
284 /**
285 * PictureCallback that sends the picture to a server.
286 *
287 * @author Marius Gavrilescu <marius@ieval.ro>
288 */
289 private static final class FonBotPictureCallback implements PictureCallback{
290 /** Server hostname */
291 private final String hostname;
292 /** Server port */
293 private final int port;
294 /** Context instance */
295 private final Context context;
296 /** Reply address */
297 private final Address replyTo;
298
299 /**
300 * Construct a FonBotPictureCallback.
301 *
302 * @param context Context instance
303 * @param replyTo reply Address
304 * @param hostname server hostname
305 * @param port server port
306 */
307 FonBotPictureCallback(final Context context, final Address replyTo, final String hostname, final int port) {
308 this.hostname=hostname;
309 this.port=port;
310 this.context=context;
311 this.replyTo=replyTo;
312 }
313
314 @Override
315 @SuppressWarnings("hiding")
316 public void onPictureTaken(final @Nullable byte[] data, final @Nullable Camera camera) {
317 if(camera==null || data==null)
318 return;
319 camera.stopPreview();
320 stopCamera();
321 Utils.sendMessage(toNonNull(context), toNonNull(replyTo), sending_photo);
322 new SendDataAsyncTask(toNonNull(context), toNonNull(replyTo), toNonNull(hostname), port, data).execute();
323 }
324 }
325
326 /**
327 * Get help for a particular command
328 *
329 * @param context Context instance
330 * @param replyTo reply Address
331 * @param command command to get help for
332 */
333 public static void help(final Context context, final Address replyTo, final Command command){//NOPMD method is a big switch statement. Nothing confusing.
334 switch(command){
335 case ANSWER:
336 Utils.sendMessage(context, replyTo, answer_help);
337 break;
338 case BATT:
339 Utils.sendMessage(context, replyTo, batt_help);
340 break;
341 case BLUETOOTH:
342 Utils.sendMessage(context, replyTo, bluetooth_help);
343 break;
344 case CALLLOG:
345 Utils.sendMessage(context, replyTo, calllog_help);
346 break;
347 case CONTACTS:
348 Utils.sendMessage(context, replyTo, contacts_help);
349 break;
350 case DATA:
351 Utils.sendMessage(context, replyTo, data_help);
352 break;
353 case DELNOTIFICATION:
354 Utils.sendMessage(context, replyTo, delnotification_help, Utils.join(", ", toNonNull(MessageType.values())));
355 break;
356 case DIAL:
357 Utils.sendMessage(context, replyTo, dial_help);
358 break;
359 case DIALOG:
360 Utils.sendMessage(context, replyTo, dialog_help);
361 break;
362 case DISABLE:
363 Utils.sendMessage(context, replyTo, disable_help, Utils.join(", ", toNonNull(Command.values())));
364 break;
365 case ECHO:
366 Utils.sendMessage(context, replyTo, echo_help);
367 break;
368 case ENABLE:
369 Utils.sendMessage(context, replyTo, enable_help, Utils.join(", ", toNonNull(Command.values())));
370 break;
371 case FLASH:
372 Utils.sendMessage(context, replyTo, flash_help);
373 break;
374 case GLOCATION:
375 Utils.sendMessage(context, replyTo, glocation_help);
376 break;
377 case GPS:
378 Utils.sendMessage(context, replyTo, gps_help);
379 break;
380 case HANGUP:
381 Utils.sendMessage(context, replyTo, hangup_help);
382 break;
383 case HELP:
384 Utils.sendMessage(context, replyTo, help_help, Utils.join(", ",toNonNull(Command.values())));
385 break;
386 case LAUNCH:
387 Utils.sendMessage(context, replyTo, launch_help);
388 break;
389 case LOCATION:
390 Utils.sendMessage(context, replyTo, location_help, Utils.join(", ",toNonNull(Utils.LocationProvider.values())));
391 break;
392 case LOCK:
393 Utils.sendMessage(context, replyTo, lock_help);
394 break;
395 case LS:
396 Utils.sendMessage(context, replyTo, ls_help);
397 break;
398 case NCFILE:
399 Utils.sendMessage(context, replyTo, ncfile_help);
400 break;
401 case NEXT:
402 Utils.sendMessage(context, replyTo, next_help);
403 break;
404 case NOLOCATION:
405 Utils.sendMessage(context, replyTo, nolocation_help);
406 break;
407 case PAUSE:
408 Utils.sendMessage(context, replyTo, pause_help);
409 break;
410 case PHOTO:
411 Utils.sendMessage(context, replyTo, photo_help);
412 break;
413 case PLAY:
414 Utils.sendMessage(context, replyTo, play_help);
415 break;
416 case POLL:
417 Utils.sendMessage(context, replyTo, poll_help);
418 break;
419 case PREV:
420 Utils.sendMessage(context, replyTo, prev_help);
421 break;
422 case RING:
423 Utils.sendMessage(context, replyTo, ring_help);
424 break;
425 case RINGER:
426 Utils.sendMessage(context, replyTo, ringer_help, Utils.join(", ", toNonNull(RingerMode.values())));
427 break;
428 case RM:
429 Utils.sendMessage(context, replyTo, rm_help);
430 break;
431 case SETNOTIFICATION:
432 Utils.sendMessage(context, replyTo, setnotification_help, Utils.join(", ", toNonNull(MessageType.values())));
433 break;
434 case SETPASSWORD:
435 Utils.sendMessage(context, replyTo, setpassword_help);
436 break;
437 case SMS:
438 Utils.sendMessage(context, replyTo, sms_help);
439 break;
440 case SMSLOG:
441 Utils.sendMessage(context, replyTo, smslog_help);
442 break;
443 case SPEAK:
444 Utils.sendMessage(context, replyTo, speak_help);
445 break;
446 case TOAST:
447 Utils.sendMessage(context, replyTo, toast_help);
448 break;
449 case VIBRATE:
450 Utils.sendMessage(context, replyTo, vibrate_help);
451 break;
452 case VIEW:
453 Utils.sendMessage(context, replyTo, view_help);
454 break;
455 case WIFI:
456 Utils.sendMessage(context, replyTo, wifi_help);
457 break;
458 case WIPE:
459 Utils.sendMessage(context, replyTo, wipe_help, Utils.WIPE_CONFIRM_STRING);
460 break;
461 case REBOOT:
462 Utils.sendMessage(context, replyTo, reboot_help);
463 break;
464 case SHUTDOWN:
465 Utils.sendMessage(context, replyTo, shutdown_help);
466 break;
467 case NOTIFY:
468 Utils.sendMessage(context, replyTo, notify_help);
469 }
470 }
471
472 /**
473 * Camera instance.
474 *
475 * @see #startCamera(Context, Address)
476 * @see #stopCamera()
477 */
478 private static Camera camera;
479 /**
480 * Ringtone used by the {@link Utils.Command#RING RING} command.
481 *
482 * @see #setupRingtone(Context)
483 */
484 private static Ringtone ringtone;
485 /**
486 * Saved ringer volume.
487 *
488 * @see #startAlarm(Context, Address)
489 * @see #stopAlarm(Context, Address)
490 */
491 private static int savedRingVolume;
492 /**
493 * Saved ringer mode.
494 *
495 * @see #startAlarm(Context, Address)
496 * @see #stopAlarm(Context, Address)
497 */
498 private static int savedRingerMode;
499
500 /** Private constructor */
501 private Heavy(){
502 //do nothing
503 }
504
505 /**
506 * Convert a phone number type to a string
507 *
508 * @param context Context instance
509 * @param type phone number type
510 * @param label name of a custom phone type
511 * @return the phone number type
512 */
513 private static @Nullable String phoneNumberType(final Context context, final int type, final @Nullable String label) {
514 switch(type){
515 case BaseTypes.TYPE_CUSTOM:
516 return label;
517 case Phone.TYPE_ASSISTANT:
518 return context.getString(phone_numer_type_assistant);
519 case Phone.TYPE_CALLBACK:
520 return context.getString(phone_number_type_callback);
521 case Phone.TYPE_CAR:
522 return context.getString(phone_number_type_car);
523 case Phone.TYPE_COMPANY_MAIN:
524 return context.getString(phone_number_type_company_main);
525 case Phone.TYPE_FAX_HOME:
526 return context.getString(phone_number_type_home_fax);
527 case Phone.TYPE_FAX_WORK:
528 return context.getString(phone_number_type_work_fax);
529 case Phone.TYPE_HOME:
530 return context.getString(phone_number_type_home);
531 case Phone.TYPE_ISDN:
532 return context.getString(phone_number_type_isdn);
533 case Phone.TYPE_MAIN:
534 return context.getString(phone_number_type_main);
535 case Phone.TYPE_MMS:
536 return context.getString(phone_number_type_mms);
537 case Phone.TYPE_MOBILE:
538 return context.getString(phone_number_type_mobile);
539 case Phone.TYPE_OTHER:
540 return context.getString(phone_number_type_other);
541 case Phone.TYPE_OTHER_FAX:
542 return context.getString(phone_number_type_other_fax);
543 case Phone.TYPE_PAGER:
544 return context.getString(phone_number_type_pager);
545 case Phone.TYPE_RADIO:
546 return context.getString(phone_number_type_radio);
547 case Phone.TYPE_TELEX:
548 return context.getString(phone_number_type_telex);
549 case Phone.TYPE_TTY_TDD:
550 return context.getString(phone_number_type_textphone);
551 case Phone.TYPE_WORK:
552 return context.getString(phone_number_type_work);
553 case Phone.TYPE_WORK_MOBILE:
554 return context.getString(phone_number_type_work_mobile);
555 case Phone.TYPE_WORK_PAGER:
556 return context.getString(phone_number_type_work_pager);
557 }
558
559 return context.getString(phone_number_type_unknown, Integer.valueOf(type));
560 }
561
562 /**
563 * Setup the ringtone used by the {@link Utils.Command#RING RING} command
564 *
565 * @param context Context
566 */
567 private static void setupRingtone(final Context context){
568 if(ringtone==null){//NOPMD not supposed to be thread-safe
569 final Uri alert=RingtoneManager.getDefaultUri(RingtoneManager.TYPE_RINGTONE);
570 ringtone=RingtoneManager.getRingtone(context, alert);
571 }
572 }
573
574 /**
575 * Make the phone start ringing. Turns up the volume and sets the ringer mode to NORMAL
576 *
577 * @param context Context instance
578 * @param replyTo reply Address
579 */
580 private static void startAlarm(final Context context, final Address replyTo){
581 Utils.registerOngoing(context, toNonNull(OngoingEvent.RING));
582 final AudioManager man=(AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
583 savedRingerMode=man.getRingerMode();
584 man.setRingerMode(AudioManager.RINGER_MODE_NORMAL);
585 savedRingVolume=man.getStreamVolume(AudioManager.STREAM_RING);
586 man.setStreamVolume(AudioManager.STREAM_RING, man.getStreamMaxVolume(AudioManager.STREAM_RING), 0);
587 Utils.sendMessage(context, replyTo, ringing);
588 ringtone.play();
589 }
590
591 /**
592 * Get a camera instance.
593 *
594 * @param context Context instance
595 * @param replyTo reply Address
596 */
597 private static void startCamera(final Context context, final Address replyTo){
598 if(camera!=null)
599 return;
600 try{
601 camera=Camera.open();
602 } catch (Exception e){
603 Utils.sendMessage(context, replyTo, cannot_grab_camera);
604 }
605 }
606
607 /**
608 * Make the phone stop ringing. Restores the volume and ringer mode.
609 *
610 * @param context Context instance
611 * @param replyTo reply Address
612 */
613 private static void stopAlarm(final Context context, final Address replyTo){
614 Utils.unregisterOngoing(context, toNonNull(OngoingEvent.RING));
615 final AudioManager man=(AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
616 Utils.sendMessage(context, replyTo, no_longer_ringing);
617 ringtone.stop();
618 man.setStreamVolume(AudioManager.STREAM_RING, savedRingVolume, 0);
619 man.setRingerMode(savedRingerMode);
620 }
621
622 /**
623 * Release the previously grabbed camera instance
624 *
625 * @see #startCamera(Context, Address)
626 */
627 private static void stopCamera(){
628 if(camera==null)
629 return;
630 camera.release();
631 camera=null;
632 }
633
634 /**
635 * Send battery status information to an Address
636 *
637 * @param context Context instance
638 * @param replyTo destination Address
639 *
640 * @see #describeBatteryLevel(Context, Address, MessageType)
641 */
642 public static void batt(final Context context, final Address replyTo){
643 describeBatteryLevel(context, replyTo, null);
644 }
645
646 /**
647 * Show the bluetooth radio status.
648 *
649 * @param context Context instance
650 * @param replyTo destination Address
651 */
652 public static void bluetooth(final Context context, final Address replyTo) {
653 final BluetoothAdapter adapter=BluetoothAdapter.getDefaultAdapter();
654 if(adapter==null){
655 Utils.sendMessage(context, replyTo, no_bluetooth_adapter);
656 return;
657 }
658
659 if(adapter.isEnabled())
660 Utils.sendMessage(context, replyTo, bluetooth_on);
661 else
662 Utils.sendMessage(context, replyTo, bluetooth_off);
663 }
664
665 /**
666 * Set the bluetooth radio status.
667 *
668 * @param context Context instance
669 * @param replyTo destination Address
670 * @param on the requested radio status
671 */
672 public static void bluetooth(final Context context, final Address replyTo, final boolean on){
673 final BluetoothAdapter adapter=BluetoothAdapter.getDefaultAdapter();
674 if(adapter==null){
675 Utils.sendMessage(context, replyTo, no_bluetooth_adapter);
676 return;
677 }
678
679 if(on) {
680 adapter.enable();
681 Utils.sendMessage(context, replyTo, enabling_bluetooth);
682 }
683 else {
684 adapter.disable();
685 Utils.sendMessage(context, replyTo, disabling_bluetooth);
686 }
687 }
688
689 /**
690 * Cancel an ongoing event.
691 *
692 * @param context Context instance
693 * @param event the event to cancel
694 */
695 public static void cancelOngoing(final Context context, final OngoingEvent event){
696 switch(event){
697 case LOCATION:
698 nolocation(context, toNonNull(Address.BLACKHOLE));
699 break;
700 case POLL:
701 poll(context, toNonNull(Address.BLACKHOLE), 0);
702 break;
703 case RING:
704 ring(context, toNonNull(Address.BLACKHOLE), false);
705 break;
706 }
707 }
708
709 /**
710 * Send the last calls to an Address.
711 *
712 * @param context Context instance
713 * @param replyTo destination Address
714 * @param numCalls how many calls to send
715 */
716 public static void calllog(final Context context, final Address replyTo, final int numCalls) {
717 final String[] fields = {
718 Calls.TYPE, Calls.NUMBER, Calls.CACHED_NAME, Calls.DURATION, Calls.DATE
719 };
720
721 final Cursor cursor = context.getContentResolver().query(
722 Calls.CONTENT_URI,
723 fields,
724 null,
725 null,
726 Calls.DATE + " DESC"
727 );
728
729 if (cursor.moveToFirst()) {
730 do {
731 final StringBuilder sb=new StringBuilder(50);//NOPMD different strings
732 final int type=cursor.getInt(0);
733 final String from=cursor.getString(1);
734
735 switch(type){
736 case Calls.INCOMING_TYPE:
737 sb.append(context.getString(incoming_call_from, from));
738 break;
739 case Calls.MISSED_TYPE:
740 sb.append(context.getString(missed_call_from, from));
741 break;
742 case Calls.OUTGOING_TYPE:
743 sb.append(context.getString(outgoing_call_to, from));
744 break;
745 }
746
747 if (cursor.getString(2) != null)
748 sb.append('(').append(cursor.getString(2)).append(") ");
749
750 sb.append(context.getString(duration_seconds_starting_at,
751 Long.valueOf(cursor.getLong(3)),
752 new Date(cursor.getLong(4))));
753
754 Utils.sendMessage(context, replyTo, toNonNull(sb.toString()));
755 } while (cursor.moveToNext() && cursor.getPosition() < numCalls);
756 }
757
758 cursor.close();
759 }
760
761 /**
762 * Search for contacts by name/nickname and send matching entries to an Address.
763 *
764 * @param context Context instance
765 * @param replyTo destination Address
766 * @param name name/nickname part to search for
767 */
768 @SuppressLint("StringFormatMatches")
769 public static void contacts(final Context context, final Address replyTo, final String name){
770 final Cursor cursor=context.getContentResolver().query(Uri.withAppendedPath(
771 Contacts.CONTENT_FILTER_URI, name),
772 new String[]{Contacts.DISPLAY_NAME, BaseColumns._ID, Contacts.LOOKUP_KEY},
773 null, null, Contacts.DISPLAY_NAME);
774
775 if(cursor.getCount()==0)
776 Utils.sendMessage(context, replyTo, no_matching_contacts_found);
777
778 while(cursor.moveToNext()){
779 final String[] fields = {
780 CommonDataKinds.Phone.NUMBER,
781 CommonDataKinds.Phone.TYPE,
782 CommonDataKinds.Phone.LABEL,
783 };
784
785 final Cursor inCursor=context.getContentResolver().query(Data.CONTENT_URI,
786 fields,
787 Data.CONTACT_ID+" = ? AND "+Data.MIMETYPE+ " = ?",
788 new String[]{Long.toString(cursor.getLong(1)), CommonDataKinds.Phone.CONTENT_ITEM_TYPE},
789 CommonDataKinds.Phone.LABEL);
790
791 while(inCursor.moveToNext())
792 Utils.sendMessage(context, replyTo, toNonNull(context.getString(contact_info,
793 cursor.getString(0),
794 inCursor.getString(0),
795 phoneNumberType(context, inCursor.getInt(1), inCursor.getString(2)))));
796
797 inCursor.close();
798 }
799
800 cursor.close();
801 }
802
803 /**
804 * Send battery status information to an Address or as a notification
805 *
806 * @param context Context instance
807 * @param replyTo Address to send the information to, if sending to a direct address. Null otherwise.
808 * @param type Notification type, if sending as a notification. Null otherwise.
809 */
810 public static void describeBatteryLevel(final Context context, final @Nullable Address replyTo, final @Nullable MessageType type) {
811 if(replyTo==null&&type==null)
812 return;
813 final Intent intent=context.registerReceiver(null, new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
814 if(intent==null)
815 return;
816 final double level=intent.getIntExtra(BatteryManager.EXTRA_LEVEL, 0);
817 final int scale=intent.getIntExtra(BatteryManager.EXTRA_SCALE, 100);
818 final int plugged=intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, 0);
819 final int status=intent.getIntExtra(BatteryManager.EXTRA_STATUS, BatteryManager.BATTERY_STATUS_UNKNOWN);
820 final int temp=intent.getIntExtra(BatteryManager.EXTRA_TEMPERATURE, 0);
821 final int volt=intent.getIntExtra(BatteryManager.EXTRA_VOLTAGE, 0);
822
823 final StringBuilder sb=new StringBuilder(100);
824 sb.append(context.getString(battery_level, Double.valueOf(level*100/scale)));
825
826 switch(plugged){
827 case 0:
828 sb.append(context.getString(not_plugged_in));
829 break;
830 case BatteryManager.BATTERY_PLUGGED_AC:
831 sb.append(context.getString(plugged_in_ac));
832 break;
833 case BatteryManager.BATTERY_PLUGGED_USB:
834 sb.append(context.getString(plugged_in_usb));
835 break;
836 case BatteryManager.BATTERY_PLUGGED_WIRELESS:
837 sb.append(context.getString(plugged_in_wireless));
838 break;
839 }
840
841 switch(status){
842 case BatteryManager.BATTERY_STATUS_CHARGING:
843 sb.append(context.getString(status_charging));
844 break;
845 case BatteryManager.BATTERY_STATUS_DISCHARGING:
846 sb.append(context.getString(status_discharging));
847 break;
848 case BatteryManager.BATTERY_STATUS_FULL:
849 sb.append(context.getString(status_full));
850 break;
851 case BatteryManager.BATTERY_STATUS_NOT_CHARGING:
852 sb.append(context.getString(status_not_charging));
853 break;
854 case BatteryManager.BATTERY_STATUS_UNKNOWN:
855 sb.append(context.getString(status_unknown));
856 break;
857 }
858
859 sb.append(context.getString(temperature, Integer.valueOf(temp)));
860
861 sb.append(context.getString(voltage, Integer.valueOf(volt)));
862 if(type==null)
863 Utils.sendMessage(context, toNonNull(replyTo), toNonNull(sb.toString()));
864 else
865 Utils.sendMessage(context, type, toNonNull(sb.toString()));
866 }
867
868 /**
869 * Dial a phone number.
870 *
871 * @param context Context instance
872 * @param replyTo reply Address
873 * @param nr phone number to dial
874 */
875 public static void dial(final Context context, final Address replyTo, final String nr){
876 final Intent intent=new Intent(Intent.ACTION_CALL,Uri.parse("tel:"+nr));
877 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
878 final String name=Utils.callerId(context, nr);
879 if(name==null)
880 Utils.sendMessage(context, replyTo, dialing, nr);
881 else
882 Utils.sendMessage(context, replyTo, dialing, nr+" ("+name+")");
883 context.startActivity(intent);
884 }
885
886 /**
887 * Show a dialog with a message and a list of buttons.
888 *
889 * @param context Context instance
890 * @param replyTo reply Address
891 * @param message dialog message
892 * @param buttons dialog buttons
893 */
894 public static void dialog(final Context context, final Address replyTo, final String message, final String[] buttons){
895 final Intent intent=new Intent(context, DialogActivity.class);
896 intent.putExtra(DialogActivity.EXTRA_MESSAGE, message);
897 intent.putExtra(DialogActivity.EXTRA_BUTTONS, buttons);
898 intent.putExtra(DialogActivity.EXTRA_REPLYTO, replyTo.toString());
899 intent.addFlags(
900 Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS|
901 Intent.FLAG_ACTIVITY_NEW_TASK|
902 Intent.FLAG_ACTIVITY_NO_USER_ACTION|
903 Intent.FLAG_FROM_BACKGROUND);
904 Utils.sendMessage(context, toNonNull(replyTo), showing_dialog);
905 context.startActivity(intent);
906 }
907
908 /**
909 * Turns the flashlight on or off.
910 *
911 * @param context Context instance
912 * @param replyTo reply Address
913 * @param on requested flashlight state
914 */
915 public static void flash(final Context context, final Address replyTo, final boolean on){
916 startCamera(context, replyTo);
917 if(camera==null)
918 return;
919 final Camera.Parameters parms=camera.getParameters();
920 if(on){
921 parms.setFlashMode(Camera.Parameters.FLASH_MODE_TORCH);
922 camera.setParameters(parms);
923 } else {
924 parms.setFlashMode(Camera.Parameters.FLASH_MODE_AUTO);
925 camera.setParameters(parms);
926 stopCamera();
927 }
928 }
929
930 /**
931 * Start sending location updates to an Address.
932 *
933 * @param context Context instance
934 * @param replyTo destination Address
935 * @param provider LocationProvider
936 * @param minTime minimum time between two consecutive updates (in ms)
937 * @param minDistance minimum distance between two consecutive updates (in meters)
938 *
939 * @see LocationManager#requestLocationUpdates(String, long, float, LocationListener)
940 */
941 public static void location(final Context context, final Address replyTo, final String provider,final long minTime,final float minDistance){
942 final LocationManager man=(LocationManager) context.getApplicationContext().getSystemService(Context.LOCATION_SERVICE);
943 if(locationListener!=null)
944 nolocation(context, toNonNull(Address.BLACKHOLE));
945 Utils.registerOngoing(context, toNonNull(OngoingEvent.LOCATION));
946 locationListener=new FonBotLocationListener(context, replyTo);
947 man.removeUpdates(locationListener);
948 final Location lastKnownLocation=man.getLastKnownLocation(provider);
949 if(lastKnownLocation!=null){
950 Utils.sendMessage(context, replyTo, last_known_location);
951 locationListener.onLocationChanged(lastKnownLocation);
952 }
953 Utils.sendMessage(context, replyTo, listening_for_location_updates);
954 man.requestLocationUpdates(provider, minTime, minDistance, locationListener);
955 }
956
957 /**
958 * Lock the phone.
959 *
960 * @param context Context instance
961 * @param replyTo reply Address
962 */
963 public static void lock(final Context context, final Address replyTo) {
964 final DevicePolicyManager dpm=(DevicePolicyManager) context.getSystemService(Context.DEVICE_POLICY_SERVICE);
965 dpm.lockNow();
966 Utils.sendMessage(context, replyTo, device_locked);
967 }
968
969 /**
970 * Send a command to a running instance of the music player
971 *
972 * @param context Context instance
973 * @param replyTo reply Address
974 * @param command command to send
975 */
976 public static void musicPlayerCommand(final Context context, final Address replyTo, final String command) {
977 final Intent intent=new Intent("com.android.music.musicservicecommand");
978 intent.putExtra("command", command);
979 context.sendBroadcast(intent);
980 Utils.sendMessage(context, replyTo, command_sent);
981 }
982
983 /**
984 * Send a file to a server.
985 *
986 * @param context Context instance
987 * @param replyTo reply Address
988 * @param filename file to send
989 * @param hostname server hostname
990 * @param port server port
991 */
992 public static void ncfile(final Context context, final Address replyTo, final String filename,final String hostname,final int port){
993 new AsyncTask<Void, Void, Void>() {
994 @Override
995 protected @Nullable Void doInBackground(@Nullable final Void... params) {
996 final FileChannel in;
997 try{
998 in=new FileInputStream(filename).getChannel();
999 } catch (final FileNotFoundException e){
1000 Utils.sendMessage(context, replyTo, file_not_found, filename);
1001 return null;
1002 }
1003 final SocketChannel sock;
1004 try{
1005 sock = SocketChannel.open(new InetSocketAddress(hostname, port));
1006 } catch (final IOException e){
1007 Utils.sendMessage(context, replyTo, toNonNull(context.getString(
1008 cannot_connect_to_host_on_port, hostname, Integer.valueOf(port))));
1009 try {
1010 in.close();
1011 } catch (IOException ex) {
1012 //ignored
1013 }
1014 return null;
1015 }
1016
1017 try{
1018 in.transferTo(0, in.size(), sock);
1019 } catch (final IOException e){
1020 Utils.sendMessage(context, replyTo, toNonNull(context.getString(
1021 io_error, e.getMessage())));
1022 } finally {
1023 try{
1024 in.close();
1025 } catch (IOException e){
1026 //ignored
1027 }
1028 try{
1029 sock.close();
1030 } catch(IOException e){
1031 //ignored
1032 }
1033 }
1034 return null;
1035 }
1036
1037 @Override
1038 protected void onPostExecute(@Nullable final Void result) {
1039 Utils.sendMessage(context, replyTo, file_sent);
1040 }
1041 }.execute();
1042 }
1043
1044 /**
1045 * Stop sending location updates.
1046 *
1047 * @param context Context instance
1048 * @param replyTo reply Address
1049 */
1050 public static void nolocation(final Context context, final Address replyTo){
1051 Utils.unregisterOngoing(context, toNonNull(OngoingEvent.LOCATION));
1052 final LocationManager man=(LocationManager) context.getApplicationContext().getSystemService(Context.LOCATION_SERVICE);
1053 man.removeUpdates(locationListener);
1054 locationListener=null;
1055 Utils.sendMessage(context, replyTo, no_longer_listening_for_location_updates);
1056 }
1057
1058 /**
1059 * Take a photo and send it to a server.
1060 *
1061 * @param context Context instance
1062 * @param replyTo reply Address
1063 * @param hostname server hostname
1064 * @param port server port
1065 */
1066 public static void photo(final Context context, final Address replyTo, final String hostname, final int port){
1067 startCamera(context, replyTo);
1068 if(camera==null)
1069 return;
1070 final Camera.Parameters parms=camera.getParameters();
1071 parms.setJpegQuality(70);
1072 parms.setPictureFormat(ImageFormat.JPEG);
1073 camera.setParameters(parms);
1074
1075 final SurfaceView fakeView=new SurfaceView(context);
1076 try {
1077 camera.setPreviewDisplay(fakeView.getHolder());
1078 } catch (IOException e) {
1079 Utils.sendMessage(context, replyTo, error_setting_preview_display);
1080 return;
1081 }
1082 camera.startPreview();
1083 final Handler handler=new Handler();
1084
1085 new Thread(new Runnable() {
1086 @Override
1087 public void run() {
1088 try {
1089 Thread.sleep(2000);
1090 } catch (InterruptedException e) {
1091 //ignored
1092 }
1093
1094 handler.post(new Runnable() {
1095 @Override
1096 public void run() {
1097 camera.takePicture(null, null, new FonBotPictureCallback(context, replyTo, hostname, port));
1098 }
1099 });
1100 }
1101 }).start();
1102 }
1103
1104 /**
1105 * Send a directory listing to an Address
1106 *
1107 * @param context Context instance
1108 * @param replyTo destination Address
1109 * @param directory directory to list
1110 */
1111 public static void ls(final Context context, final Address replyTo, final String directory) {
1112 final File[] files=new File(directory).listFiles();
1113 if(files==null){
1114 Utils.sendMessage(context, replyTo, string_is_not_a_directory, directory);
1115 return;
1116 }
1117
1118 final StringBuilder sb=new StringBuilder(context.getString(files_in_directory,directory));
1119 for(final File file : files){
1120 sb.append(file.getName());
1121 if(file.isDirectory())
1122 sb.append('/');
1123 sb.append(" ");
1124 }
1125
1126 Utils.sendMessage(context, replyTo, toNonNull(sb.toString()));
1127 }
1128
1129 /**
1130 * Make the phone start ringing if it is not ringing or stop ringing if it is.
1131 *
1132 * @param context Context instance
1133 * @param replyTo reply Address
1134 */
1135 public static void ring(final Context context, final Address replyTo){
1136 setupRingtone(context);
1137 if(ringtone==null){
1138 Utils.sendMessage(context, replyTo, no_ringtone_found);
1139 return;
1140 }
1141 if(ringtone.isPlaying())
1142 stopAlarm(context, replyTo);
1143 else
1144 startAlarm(context, replyTo);
1145 }
1146
1147 /**
1148 * Make the phone start/stop ringing.
1149 *
1150 * @param context Context instance
1151 * @param replyTo reply Address
1152 * @param on true if the phone should start ringing, false otherwise
1153 */
1154 public static void ring(final Context context, final Address replyTo, final boolean on){
1155 setupRingtone(context);
1156 if(ringtone==null){
1157 Utils.sendMessage(context, replyTo, no_ringtone_found);
1158 return;
1159 }
1160 if(on&&!ringtone.isPlaying())
1161 startAlarm(context, replyTo);
1162 else if(ringtone.isPlaying()&&!on)
1163 stopAlarm(context, replyTo);
1164 }
1165
1166 /**
1167 * Send the current ringer mode to an Address
1168 *
1169 * @param context Context instance
1170 * @param replyTo destination Address
1171 */
1172 public static void ringer(final Context context, final Address replyTo){
1173 final AudioManager man=(AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
1174 switch(man.getRingerMode()){
1175 case AudioManager.RINGER_MODE_NORMAL:
1176 Utils.sendMessage(context, replyTo, ringer_mode_normal);
1177 break;
1178 case AudioManager.RINGER_MODE_VIBRATE:
1179 Utils.sendMessage(context, replyTo, ringer_mode_vibrate);
1180 break;
1181 case AudioManager.RINGER_MODE_SILENT:
1182 Utils.sendMessage(context, replyTo, ringer_mode_silent);
1183 break;
1184 default:
1185 Utils.sendMessage(context, replyTo, unknown_ringer_mode);
1186 }
1187 }
1188
1189 /**
1190 * Set the ringer mode.
1191 *
1192 * @param context Context instance
1193 * @param replyTo reply Address
1194 * @param ringerMode requested ringer mode
1195 *
1196 * @see Utils.RingerMode
1197 */
1198 public static void ringer(final Context context, final Address replyTo, final int ringerMode){
1199 final AudioManager man=(AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
1200 man.setRingerMode(ringerMode);
1201 ringer(context, replyTo);
1202 }
1203
1204 /**
1205 * Remove a file or empty directory.
1206 *
1207 * @param context Context instance
1208 * @param replyTo reply Address
1209 * @param filename file/empty directory to delete
1210 */
1211 public static void rm(final Context context, final Address replyTo, final String filename){
1212 if(new File(filename).delete())
1213 Utils.sendMessage(context, replyTo, file_deleted);
1214 else
1215 Utils.sendMessage(context, replyTo, error_while_deleting_file);
1216 }
1217
1218 /**
1219 * Clear the keyguard password.
1220 *
1221 * @param context Context instance
1222 * @param replyTo reply Address
1223 * @throws SecurityException if FonBot does not have device administration permissions
1224 */
1225 public static void setPassword(final Context context, final Address replyTo) throws SecurityException{
1226 final DevicePolicyManager dpm=(DevicePolicyManager) context.getSystemService(Context.DEVICE_POLICY_SERVICE);
1227
1228 dpm.resetPassword("", 0);
1229 Utils.sendMessage(context, replyTo, password_cleared);
1230 }
1231
1232 /**
1233 * Change the keyguard password.
1234 *
1235 * @param context Context instance
1236 * @param replyTo reply Address
1237 * @param password new password
1238 * @throws SecurityException if FonBot does not have device administration permissions
1239 */
1240 public static void setPassword(final Context context, final Address replyTo, final String password) throws SecurityException{
1241 final DevicePolicyManager dpm=(DevicePolicyManager) context.getSystemService(Context.DEVICE_POLICY_SERVICE);
1242
1243 dpm.resetPassword(password, 0);
1244 Utils.sendMessage(context, replyTo, password_set);
1245 }
1246
1247 /**
1248 * Send a text message.
1249 *
1250 * @param context Context instance
1251 * @param replyTo reply Address
1252 * @param destination destination phone number
1253 * @param text text message contents
1254 */
1255 public static void sms(final Context context, final Address replyTo, final String destination, final String text){
1256 final SmsManager manager=SmsManager.getDefault();
1257 final ArrayList<String> messages=manager.divideMessage(text);
1258 if(messages.size() > 1)
1259 Utils.sendMessage(context, replyTo, message_was_split_into_parts, Integer.valueOf(messages.size()));
1260
1261 final ArrayList<PendingIntent> sents=new ArrayList<PendingIntent>(messages.size());
1262 final ArrayList<PendingIntent> delivereds=new ArrayList<PendingIntent>(messages.size());
1263
1264 final String name=Utils.callerId(context, destination);
1265 final String fullDestination;
1266 if(name==null)
1267 fullDestination=destination;
1268 else
1269 fullDestination=destination+" ("+name+")";
1270
1271 for(int i=0;i<messages.size();i++){
1272 final Intent sent=new Intent(context,SmsStatusReceiver.class);
1273 sent.putExtra(SmsStatusReceiver.EXTRA_DESTINATION, fullDestination);
1274 sent.putExtra(SmsStatusReceiver.EXTRA_PART, i+1);
1275 sent.putExtra(SmsStatusReceiver.EXTRA_TOTAL, messages.size());
1276 sent.putExtra(SmsStatusReceiver.EXTRA_REPLY_TO, replyTo.toString());
1277 sent.setAction(SmsStatusReceiver.SENT_ACTION+i);//actions must be unique
1278 sents.add(PendingIntent.getBroadcast(context, 0, sent, PendingIntent.FLAG_UPDATE_CURRENT));
1279
1280 final Intent delivered=new Intent(context, SmsStatusReceiver.class);
1281 delivered.putExtra(SmsStatusReceiver.EXTRA_DESTINATION, fullDestination);
1282 delivered.putExtra(SmsStatusReceiver.EXTRA_PART, i+1);
1283 delivered.putExtra(SmsStatusReceiver.EXTRA_TOTAL, messages.size());
1284 delivered.putExtra(SmsStatusReceiver.EXTRA_REPLY_TO, replyTo.toString());
1285 delivered.setAction(SmsStatusReceiver.DELIVERED_ACTION+i);//actions must be unique
1286 delivereds.add(PendingIntent.getBroadcast(context, 0, delivered, PendingIntent.FLAG_UPDATE_CURRENT));
1287 }
1288
1289 Log.d(Heavy.class.getName(), "Sending sms to "+destination);
1290 manager.sendMultipartTextMessage(destination, null, messages, sents, delivereds);
1291 }
1292
1293 /**
1294 * Send the last SMSes to an Address.
1295 *
1296 * @param context Context instance
1297 * @param replyTo destination Address
1298 * @param numSms how many SMSes to send
1299 */
1300 public static void smslog(final Context context, final Address replyTo, final int numSms) {
1301 final String[] fields = {"type","address", "body", "date"};
1302
1303 final Cursor cursor = context.getContentResolver().query (
1304 Uri.parse("content://sms"),
1305 fields,
1306 null,
1307 null,
1308 "date DESC"
1309 );
1310
1311 if (cursor.moveToFirst()) {
1312 do {
1313 final String fromNumber=cursor.getString(1);
1314 final String from;
1315 final String name=Utils.callerId(context, Utils.toNonNull(fromNumber));
1316 if(name==null)
1317 from=fromNumber;
1318 else
1319 from=fromNumber+" ("+name+')';
1320 final String message=cursor.getString(2).replace("\n", "\n ");
1321 final Date date=new Date(cursor.getLong(3));
1322
1323 if(cursor.getInt(0)==1)
1324 Utils.sendMessage(context, replyTo, incoming_message, from, message, date);
1325 else
1326 Utils.sendMessage(context, replyTo, outgoing_message, from, message, date);
1327 } while (cursor.moveToNext() && cursor.getPosition() < numSms);
1328 }
1329
1330 cursor.close();
1331 }
1332
1333 /** TTS instance, only used by {@link #speak(Context, Address, String)} */
1334 private static TextToSpeech tts;
1335
1336 /**
1337 * Speak a String using the text-to-speech engine.
1338 *
1339 * @param context Context instance
1340 * @param replyTo reply Address
1341 * @param text text to speak
1342 */
1343 public static void speak(final Context context, final Address replyTo, final String text){
1344 tts=new TextToSpeech(context, new OnInitListener() {
1345 @Override
1346 public void onInit(final int status) {
1347 if(status==TextToSpeech.SUCCESS){
1348 Utils.sendMessage(context, replyTo, speaking);
1349 tts.speak(text, TextToSpeech.QUEUE_ADD, null);
1350 } else
1351 Utils.sendMessage(context, replyTo, tts_engine_not_available);
1352 }
1353 });
1354 }
1355
1356 /**
1357 * Show a toast notification with the default duration.
1358 *
1359 * @param context Context instance
1360 * @param replyTo reply Address
1361 * @param text toast text
1362 */
1363 public static void toast(final Context context, final Address replyTo, final String text){
1364 toast(context, replyTo, text, Toast.LENGTH_SHORT);
1365 }
1366
1367 /**
1368 * Show a toast notification.
1369 *
1370 * @param context Context instance
1371 * @param replyTo reply Address
1372 * @param text toast text
1373 * @param duration toast duration
1374 */
1375 public static void toast(final Context context, final Address replyTo, final String text, final int duration){
1376 Toast.makeText(context,text,duration).show();
1377 Utils.sendMessage(context, replyTo, toast_shown);
1378 }
1379
1380 /**
1381 * Make the phone vibrate for a number of milliseconds.
1382 *
1383 * @param context Context instance
1384 * @param replyTo reply Address
1385 * @param ms vibrate duration, in milliseconds
1386 */
1387 public static void vibrate(final Context context, final Address replyTo, final long ms){
1388 final Vibrator v=(Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE);
1389 Utils.sendMessage(context, replyTo, vibrating);
1390 v.vibrate(ms);
1391 }
1392
1393 /**
1394 * View an URI in an appropriate activity.
1395 *
1396 * @param context Context instance
1397 * @param replyTo reply Address
1398 * @param uri URI to view
1399 */
1400 public static void view(final Context context, final Address replyTo, final Uri uri) {
1401 try{
1402 final Intent intent=new Intent(Intent.ACTION_VIEW);
1403 intent.setData(uri);
1404 intent.setFlags(Intent.FLAG_FROM_BACKGROUND|Intent.FLAG_ACTIVITY_NEW_TASK);
1405 context.startActivity(intent);
1406 Utils.sendMessage(context, replyTo, url_opened);
1407 } catch(ActivityNotFoundException e){
1408 Utils.sendMessage(context, replyTo, no_activity_found_for_this_url);
1409 } catch(Exception e){
1410 Utils.sendMessage(context, replyTo, invalid_url);
1411 }
1412 }
1413
1414 /**
1415 * Get the current WiFi state.
1416 *
1417 * @param context Context instance
1418 * @param replyTo reply Address
1419 */
1420 public static void wifi(final Context context, final Address replyTo){
1421 final WifiManager man=(WifiManager) context.getSystemService(Context.WIFI_SERVICE);
1422 if(man.isWifiEnabled())
1423 Utils.sendMessage(context, replyTo, wifi_on);
1424 else
1425 Utils.sendMessage(context, replyTo, wifi_off);
1426 }
1427
1428 /**
1429 * Set the WiFi state.
1430 *
1431 * @param context Context instance
1432 * @param replyTo reply Address
1433 * @param on the requested WiFi state
1434 */
1435 public static void wifi(final Context context, final Address replyTo, final boolean on){
1436 final WifiManager man=(WifiManager) context.getSystemService(Context.WIFI_SERVICE);
1437 man.setWifiEnabled(on);
1438 if(on)
1439 Utils.sendMessage(context, replyTo, enabling_wifi);
1440 else
1441 Utils.sendMessage(context, replyTo, disabling_wifi);
1442 }
1443
1444 /**
1445 * Factory reset the phone, optionally deleting the SD card too.
1446 *
1447 * @param context Context instance
1448 * @param type {@link Utils.WipeType} instance
1449 * @throws SecurityException if FonBot does not have device administration permissions
1450 */
1451 @SuppressLint("InlinedApi")
1452 public static void wipe(final Context context, final WipeType type) throws SecurityException{
1453 final DevicePolicyManager dpm=(DevicePolicyManager) context.getSystemService(Context.DEVICE_POLICY_SERVICE);
1454
1455 switch(type){
1456 case DATA:
1457 dpm.wipeData(0);
1458 break;
1459 case FULL:
1460 dpm.wipeData(DevicePolicyManager.WIPE_EXTERNAL_STORAGE);
1461 break;
1462 }
1463 }
1464
1465 /**
1466 * Disable a Command. The command cannot be used until enabled again with the {@link Utils.Command#ENABLE ENABLE} command.
1467 *
1468 * @param context Context instance
1469 * @param replyTo reply Address
1470 * @param command Command to disable
1471 */
1472 public static void disable(final Context context, final Address replyTo, final Command command){
1473 PreferenceManager.getDefaultSharedPreferences(context).edit()
1474 .putBoolean(command+"disabled", true).commit();
1475 Utils.sendMessage(context, replyTo, command_disabled, command);
1476 }
1477
1478 /**
1479 * Re-enable a disabled Command.
1480 *
1481 * @param context Context instance
1482 * @param replyTo reply Address
1483 * @param command Command to re-enable
1484 */
1485 public static void enable(final Context context, final Address replyTo, final Command command){
1486 PreferenceManager.getDefaultSharedPreferences(context).edit()
1487 .remove(command+"disabled").commit();
1488 Utils.sendMessage(context, replyTo, command_enabled, command);
1489
1490 }
1491
1492 /**
1493 * Check whether a Command is disabled.
1494 *
1495 * @param context Context instance
1496 * @param command Command to check
1497 * @return true if the Command is disabled, false otherwise
1498 */
1499 public static boolean isCommandDisabled(final Context context, final Command command){
1500 return PreferenceManager.getDefaultSharedPreferences(context).getBoolean(command+"disabled", false);
1501 }
1502
1503 /**
1504 * Poll the server for pending commands.
1505 *
1506 * @param context Context instance
1507 * @param replyTo reply Address
1508 */
1509 public static void poll(final Context context, final Address replyTo) {
1510 Utils.sendMessage(context, replyTo, polling_server);
1511 Utils.pollServer(context);
1512 }
1513
1514 /**
1515 * Change the server poll interval.
1516 *
1517 * @param context Context instance
1518 * @param replyTo reply Address
1519 * @param ms server poll interval in milliseconds. If 0, server poll is disabled
1520 */
1521 public static void poll(final Context context, final Address replyTo, final long ms){
1522 final AlarmManager man=(AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
1523 final Intent pollAlarm=new Intent(context, FonBotMainService.class);
1524 pollAlarm.setAction(FonBotMainService.ACTION_TRIGGER_POLL);
1525 final PendingIntent intent=PendingIntent.getService(context, 0, pollAlarm, 0);
1526 if(ms==0){
1527 Utils.unregisterOngoing(context, toNonNull(OngoingEvent.POLL));
1528 man.cancel(intent);
1529 Utils.sendMessage(context, replyTo, polling_stopped);
1530 } else {
1531 Utils.registerOngoing(context, toNonNull(OngoingEvent.POLL));
1532 man.setRepeating(AlarmManager.RTC_WAKEUP, 0, ms, intent);
1533 Utils.sendMessage(context, replyTo, polling_every_milliseconds, Long.valueOf(ms));
1534 }
1535 }
1536
1537 /**
1538 * Get an instance of {@link ITelephony}
1539 *
1540 * @param context Context instance
1541 * @return an instance of {@link ITelephony}
1542 * @throws NoSuchMethodException thrown by reflection
1543 * @throws IllegalArgumentException thrown by reflection
1544 * @throws IllegalAccessException thrown by reflection
1545 * @throws InvocationTargetException thrown by reflection
1546 */
1547 private static ITelephony getITelephony(final Context context) throws NoSuchMethodException, IllegalArgumentException, IllegalAccessException, InvocationTargetException{
1548 final TelephonyManager man=(TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
1549 final Method m=TelephonyManager.class.getDeclaredMethod("getITelephony");
1550 m.setAccessible(true);
1551 return toNonNull((ITelephony) m.invoke(man));
1552 }
1553
1554 /**
1555 * Hang up the phone.
1556 *
1557 * @param context Context instance
1558 * @param replyTo reply Address
1559 */
1560 public static void hangup(final Context context, final Address replyTo){
1561 try{
1562 getITelephony(context).endCall();
1563 } catch(Exception e){
1564 Utils.sendMessage(context, replyTo, exception_while_hanging_up_call,
1565 e.getClass().getName(), e.getMessage());
1566 }
1567 }
1568
1569 /**
1570 * Answer the phone if it is ringing.
1571 *
1572 * @param context Context instance
1573 * @param replyTo reply Address
1574 */
1575 public static void answer(final Context context, final Address replyTo){
1576 try{
1577 getITelephony(context).answerRingingCall();
1578 } catch(Exception e){
1579 Utils.sendMessage(context, replyTo, exception_while_answering_call,
1580 e.getClass().getName(), e.getMessage());
1581 }
1582 }
1583
1584 /**
1585 * Launch a package.
1586 *
1587 * @param context Context instance
1588 * @param replyTo reply Address
1589 * @param pkg name of the package to launch
1590 */
1591 public static void launch(final Context context, final Address replyTo, final String pkg){
1592 final Intent intent=context.getPackageManager().getLaunchIntentForPackage(pkg);
1593 if(intent==null){
1594 Utils.sendMessage(context, replyTo, no_such_package);
1595 return;
1596 }
1597 context.startActivity(intent);
1598 Utils.sendMessage(context, replyTo, app_launched);
1599 }
1600
1601 /**
1602 * Get the mobile data enabled status.
1603 *
1604 * @param context Context instance
1605 * @param replyTo reply Address
1606 */
1607 public static void data(final Context context, final Address replyTo){
1608 try{
1609 final ConnectivityManager man=(ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
1610 final Method m=ConnectivityManager.class.getDeclaredMethod("getMobileDataEnabled");
1611 m.setAccessible(true);
1612 if(((Boolean)m.invoke(man)).booleanValue())
1613 Utils.sendMessage(context, replyTo, data_on);
1614 else
1615 Utils.sendMessage(context, replyTo, data_off);
1616 } catch(Exception e){
1617 Utils.sendMessage(context, replyTo, exception_while_determining_data_state,
1618 e.getClass().getName(), e.getMessage());
1619 }
1620 }
1621
1622 /**
1623 * Set the mobile data enabled status.
1624 *
1625 * @param context Context instance
1626 * @param replyTo reply Address
1627 * @param enable whether to enable mobile data
1628 */
1629 public static void data(final Context context, final Address replyTo, final boolean enable) {
1630 try{
1631 if(enable){
1632 getITelephony(context).enableDataConnectivity();
1633 Utils.sendMessage(context, replyTo, enabling_data);
1634 } else {
1635 getITelephony(context).disableDataConnectivity();
1636 Utils.sendMessage(context, replyTo, disabling_data);
1637 }
1638 } catch(Exception e){
1639 Utils.sendMessage(context, replyTo, exception_while_getting_itelephony,
1640 e.getClass().getName(), e.getMessage());
1641 }
1642 }
1643
1644 /**
1645 * Get the GPS status.
1646 *
1647 * @param context Context instance
1648 * @param replyTo reply Address
1649 */
1650 public static void gps(final Context context, final Address replyTo){
1651 if(Secure.isLocationProviderEnabled(context.getContentResolver(), LocationManager.GPS_PROVIDER))
1652 Utils.sendMessage(context, replyTo, gps_on);
1653 else
1654 Utils.sendMessage(context, replyTo, gps_off);
1655 }
1656
1657 /**
1658 * Set the GPS status.
1659 *
1660 * @param context Context instance
1661 * @param replyTo reply Address
1662 * @param enabled requested GPS status
1663 */
1664 public static void gps(final Context context, final Address replyTo, final boolean enabled) {
1665 Secure.setLocationProviderEnabled(context.getContentResolver(), LocationManager.GPS_PROVIDER, enabled);
1666 if(enabled)
1667 Utils.sendMessage(context, replyTo, enabling_gps);
1668 else
1669 Utils.sendMessage(context, replyTo, disabling_gps);
1670 }
1671
1672 /**
1673 * Get the Google location (aka network location) state.
1674 *
1675 * @param context Context instance
1676 * @param replyTo reply Address
1677 */
1678 public static void glocation(final Context context, final Address replyTo){
1679 if(Secure.isLocationProviderEnabled(context.getContentResolver(), LocationManager.NETWORK_PROVIDER))
1680 Utils.sendMessage(context, replyTo, network_location_on);
1681 else
1682 Utils.sendMessage(context, replyTo, network_location_off);
1683 }
1684
1685 /**
1686 * Set the Google location (aka network location) state.
1687 *
1688 * @param context Context instance
1689 * @param replyTo reply Address
1690 * @param enabled requested Google location state
1691 */
1692 public static void glocation(final Context context, final Address replyTo, final boolean enabled) {
1693 Secure.setLocationProviderEnabled(context.getContentResolver(), LocationManager.NETWORK_PROVIDER, enabled);
1694 if(enabled)
1695 Utils.sendMessage(context, replyTo, enabling_network_location);
1696 else
1697 Utils.sendMessage(context, replyTo, disabling_network_location);
1698 }
1699
1700 /**
1701 * Reboot the phone.
1702 *
1703 * @param context Context instance
1704 * @param replyTo reply Address
1705 * @param reason reboot reason
1706 *
1707 * @see PowerManager#reboot(String)
1708 */
1709 public static void reboot(final Context context, final Address replyTo, final @Nullable String reason) {
1710 final PowerManager pm=(PowerManager) context.getSystemService(Context.POWER_SERVICE);
1711 Utils.sendMessage(context, replyTo, rebooting);
1712 pm.reboot(reason);
1713 }
1714
1715 /**
1716 * Cancel a notification.
1717 *
1718 * @param context Context instance
1719 * @param replyTo reply Address
1720 * @param id notification ID
1721 */
1722 public static void notify(final Context context, final Address replyTo, final int id) {
1723 final NotificationManager man=(NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
1724 man.cancel(id);
1725 Utils.sendMessage(context, replyTo, notification_canceled);
1726 }
1727
1728 /**
1729 * Show a notification.
1730 *
1731 * @param context Context instance
1732 * @param replyTo reply Address
1733 * @param id notification ID
1734 * @param title notificationO title
1735 * @param text notification text
1736 */
1737 public static void notify(final Context context, final Address replyTo, final int id, final String title, final String text) {
1738 final NotificationManager man=(NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
1739 man.notify(id, new NotificationCompat.Builder(context).
1740 setContentTitle(title).
1741 setContentText(text).
1742 setSmallIcon(android.R.drawable.stat_notify_sync_noanim).
1743 build());
1744 Utils.sendMessage(context, replyTo, notification_shown);
1745 }
1746 }
This page took 0.136632 seconds and 4 git commands to generate.