X-Git-Url: http://git.ieval.ro/?a=blobdiff_plain;f=src%2Fro%2Fieval%2Ffonbot%2FHeavy.java;h=f87f3f5457e69aa4ac0357b2a60ebb23a319e1bb;hb=a5259b32f390d9adf8bca1b7a4bbb620bde11479;hp=6e91f2f1fbbd61c173ad4105ffb48cd1189b9909;hpb=2e5049c9c08b1989b4bfbbfbf479d83dbe2b75a9;p=fonbot.git diff --git a/src/ro/ieval/fonbot/Heavy.java b/src/ro/ieval/fonbot/Heavy.java index 6e91f2f..f87f3f5 100644 --- a/src/ro/ieval/fonbot/Heavy.java +++ b/src/ro/ieval/fonbot/Heavy.java @@ -3,15 +3,22 @@ package ro.ieval.fonbot; import static ro.ieval.fonbot.R.string.*; import static ro.ieval.fonbot.Utils.toNonNull; +import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; +import java.io.FileOutputStream; import java.io.FileNotFoundException; +import java.io.InputStream; +import java.io.InputStreamReader; import java.io.IOException; +import java.io.OutputStream; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.net.InetSocketAddress; import java.net.Socket; import java.net.UnknownHostException; +import java.net.URL; +import java.net.URLConnection; import java.nio.channels.FileChannel; import java.nio.channels.SocketChannel; import java.util.ArrayList; @@ -53,6 +60,7 @@ import android.os.BatteryManager; import android.os.Bundle; import android.os.Handler; import android.os.PowerManager; +import android.os.SystemClock; import android.os.Vibrator; import android.preference.PreferenceManager; import android.provider.BaseColumns; @@ -166,7 +174,14 @@ final class Heavy { final Date locationDate=new Date(loc.getTime()); sb.append(" "); sb.append(toNonNull(context.getString(at))); + sb.append(" "); sb.append(locationDate.toString()); + sb.append(". "); + + sb.append("http://openstreetmap.org/?zoom=15&mlat="); + sb.append(loc.getLatitude()); + sb.append("&mlon="); + sb.append(loc.getLongitude()); Utils.sendMessage(toNonNull(context), toNonNull(replyTo), toNonNull(sb.toString())); } @@ -275,11 +290,158 @@ final class Heavy { Utils.sendMessage(toNonNull(context), toNonNull(replyTo), cannot_connect_to_host_on_port, hostname, Integer.valueOf(port)); return null; } - Utils.sendMessage(toNonNull(context), toNonNull(replyTo), photo_sent); + Utils.sendConfirmMessage(toNonNull(context), toNonNull(replyTo), photo_sent); return null; } } + /** + * ExecutableRunnable that uploads a file to a given host and port, netcat-style + * + * @author Marius Gavrilescu + */ + private static final class NcfileExecutableRunnable extends ExecutableRunnable { + private final Context context; + private final Address replyTo; + private final String filename; + private final String hostname; + private final int port; + + /** + * Construct a NcfileExecutableRunnable + * + * @param context Context instance + * @param replyTo reply Address + * @param filename filename to upload + * @param hostname hostname to upload to + * @param port port to upload to + */ + NcfileExecutableRunnable(final Context context, final Address replyTo, final String filename, final String hostname, final int port){ + this.context=context; + this.replyTo=replyTo; + this.filename=filename; + this.hostname=hostname; + this.port=port; + } + + @Override public void run(){ + final FileChannel in; + final SocketChannel sock; + try{ + in=new FileInputStream(filename).getChannel(); + } catch (final FileNotFoundException e){ + Utils.sendMessage(context, replyTo, file_not_found, filename); + return; + } + + try{ + sock = SocketChannel.open(new InetSocketAddress(hostname, port)); + } catch (final IOException e){ + Utils.sendMessage(context, replyTo, cannot_connect_to_host_on_port, hostname, Integer.valueOf(port)); + try { + in.close(); + } catch (IOException ex) { + //ignored + } + return; + } + + try{ + in.transferTo(0, in.size(), sock); + } catch (final IOException e){ + Utils.sendMessage(context, replyTo, io_error, e.getMessage()); + } finally { + try{ + in.close(); + } catch (IOException e){ + //ignored + } + try{ + sock.close(); + } catch(IOException e){ + //ignored + } + } + Utils.sendConfirmMessage(context, replyTo, file_sent); + } + } + + /** + * ExecutableRunnable that downloads a file from a given host and port, netcat-style + * + * @author Marius Gavrilescu + */ + private static final class GetfileExecutableRunnable extends ExecutableRunnable { + private final Context context; + private final Address replyTo; + private final String filename; + private final String hostname; + private final int port; + + /** + * Construct a GetfileExecutableRunnable + * + * @param context Context instance + * @param replyTo reply Address + * @param filename filename to save to + * @param hostname hostname to download from + * @param port port to download from + */ + GetfileExecutableRunnable(final Context context, final Address replyTo, final String filename, final String hostname, final int port){ + this.context=context; + this.replyTo=replyTo; + this.filename=filename; + this.hostname=hostname; + this.port=port; + } + + @Override public void run(){ + final InputStream in; + final FileOutputStream out; + final Socket sock; + try{ + out=new FileOutputStream(filename); + } catch (final IOException e){ + Utils.sendMessage(context, replyTo, error_opening_file, filename, e.getMessage()); + return; + } + + try{ + sock = new Socket(hostname, port); + in = sock.getInputStream(); + } catch (final IOException e){ + Utils.sendMessage(context, replyTo, cannot_connect_to_host_on_port, hostname, Integer.valueOf(port)); + try { + out.close(); + } catch (IOException ex) { + //ignored + } + return; + } + + try{ + byte[] buffer=new byte[1024*1024*2]; + int nread; + while((nread = in.read(buffer)) > 0) + out.write(buffer, 0, nread); + } catch (final IOException e){ + Utils.sendMessage(context, replyTo, io_error, e.getMessage()); + } finally { + try{ + out.close(); + } catch (IOException e){ + //ignored + } + try{ + sock.close(); + } catch(IOException e){ + //ignored + } + } + Utils.sendConfirmMessage(context, replyTo, file_received); + } + } + /** * PictureCallback that sends the picture to a server. * @@ -317,11 +479,47 @@ final class Heavy { return; camera.stopPreview(); stopCamera(); - Utils.sendMessage(toNonNull(context), toNonNull(replyTo), sending_photo); + Utils.sendConfirmMessage(toNonNull(context), toNonNull(replyTo), sending_photo); new SendDataAsyncTask(toNonNull(context), toNonNull(replyTo), toNonNull(hostname), port, data).execute(); } } + /** + * Runnable that takes a screen capture and stores it in a file. + */ + private static final class ScreencapRunnable implements Runnable{ + private final Context context; + private final Address replyTo; + private final String filename; + + ScreencapRunnable(final Context context, final Address replyTo, final String filename){ + this.context=context; + this.replyTo=replyTo; + this.filename=filename; + } + + @Override + public void run(){ + final int exitCode; + try { + exitCode=Runtime.getRuntime().exec(new String[]{ + "su", + "-c", + "screencap -p \"" + filename + "\"" + }).waitFor(); + } catch (final Exception e){ + e.printStackTrace(); + Utils.sendMessage(toNonNull(context), toNonNull(replyTo), screencap_failed); + return; + } + + if(exitCode == 0 && new File(filename).exists()) + Utils.sendConfirmMessage(toNonNull(context), toNonNull(replyTo), screencap_successful); + else + Utils.sendMessage(toNonNull(context), toNonNull(replyTo), screencap_failed); + } + } + /** * Get help for a particular command * @@ -436,6 +634,9 @@ final class Heavy { case SMS: Utils.sendMessage(context, replyTo, sms_help); break; + case SMSQ: + Utils.sendMessage(context, replyTo, smsq_help); + break; case SMSLOG: Utils.sendMessage(context, replyTo, smslog_help); break; @@ -460,11 +661,26 @@ final class Heavy { case REBOOT: Utils.sendMessage(context, replyTo, reboot_help); break; - case SHUTDOWN: - Utils.sendMessage(context, replyTo, shutdown_help); - break; case NOTIFY: Utils.sendMessage(context, replyTo, notify_help); + break; + case SCREENCAP: + Utils.sendMessage(context, replyTo, screencap_help); + break; + case TORCH: + Utils.sendMessage(context, replyTo, torch_help); + break; + case GETFILE: + Utils.sendMessage(context, replyTo, getfile_help); + break; + case SH: + Utils.sendMessage(context, replyTo, sh_help); + break; + case ROOTSH: + Utils.sendMessage(context, replyTo, rootsh_help); + break; + default: + Utils.sendMessage(context, replyTo, command_not_documented); } } @@ -583,7 +799,7 @@ final class Heavy { man.setRingerMode(AudioManager.RINGER_MODE_NORMAL); savedRingVolume=man.getStreamVolume(AudioManager.STREAM_RING); man.setStreamVolume(AudioManager.STREAM_RING, man.getStreamMaxVolume(AudioManager.STREAM_RING), 0); - Utils.sendMessage(context, replyTo, ringing); + Utils.sendConfirmMessage(context, replyTo, ringing); ringtone.play(); } @@ -593,11 +809,15 @@ final class Heavy { * @param context Context instance * @param replyTo reply Address */ - private static void startCamera(final Context context, final Address replyTo){ + private static void startCamera(final Context context, final Address replyTo, final int cameraNumber){ if(camera!=null) return; try{ - camera=Camera.open(); + try{ + camera=Camera.open(cameraNumber); + } catch (Exception ex){ + camera=Camera.open(); + } } catch (Exception e){ Utils.sendMessage(context, replyTo, cannot_grab_camera); } @@ -612,7 +832,7 @@ final class Heavy { private static void stopAlarm(final Context context, final Address replyTo){ Utils.unregisterOngoing(context, toNonNull(OngoingEvent.RING)); final AudioManager man=(AudioManager) context.getSystemService(Context.AUDIO_SERVICE); - Utils.sendMessage(context, replyTo, no_longer_ringing); + Utils.sendConfirmMessage(context, replyTo, no_longer_ringing); ringtone.stop(); man.setStreamVolume(AudioManager.STREAM_RING, savedRingVolume, 0); man.setRingerMode(savedRingerMode); @@ -677,11 +897,11 @@ final class Heavy { if(on) { adapter.enable(); - Utils.sendMessage(context, replyTo, enabling_bluetooth); + Utils.sendConfirmMessage(context, replyTo, enabling_bluetooth); } else { adapter.disable(); - Utils.sendMessage(context, replyTo, disabling_bluetooth); + Utils.sendConfirmMessage(context, replyTo, disabling_bluetooth); } } @@ -696,9 +916,6 @@ final class Heavy { case LOCATION: nolocation(context, toNonNull(Address.BLACKHOLE)); break; - case POLL: - poll(context, toNonNull(Address.BLACKHOLE), 0); - break; case RING: ring(context, toNonNull(Address.BLACKHOLE), false); break; @@ -788,10 +1005,10 @@ final class Heavy { CommonDataKinds.Phone.LABEL); while(inCursor.moveToNext()) - Utils.sendMessage(context, replyTo, toNonNull(context.getString(contact_info, + Utils.sendMessage(context, replyTo, contact_info, cursor.getString(0), inCursor.getString(0), - phoneNumberType(context, inCursor.getInt(1), inCursor.getString(2))))); + phoneNumberType(context, inCursor.getInt(1), inCursor.getString(2))); inCursor.close(); } @@ -876,9 +1093,9 @@ final class Heavy { intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); final String name=Utils.callerId(context, nr); if(name==null) - Utils.sendMessage(context, replyTo, dialing, nr); + Utils.sendConfirmMessage(context, replyTo, dialing, nr); else - Utils.sendMessage(context, replyTo, dialing, nr+" ("+name+")"); + Utils.sendConfirmMessage(context, replyTo, dialing, nr+" ("+name+")"); context.startActivity(intent); } @@ -900,7 +1117,7 @@ final class Heavy { Intent.FLAG_ACTIVITY_NEW_TASK| Intent.FLAG_ACTIVITY_NO_USER_ACTION| Intent.FLAG_FROM_BACKGROUND); - Utils.sendMessage(context, toNonNull(replyTo), showing_dialog); + Utils.sendConfirmMessage(context, toNonNull(replyTo), showing_dialog); context.startActivity(intent); } @@ -912,7 +1129,7 @@ final class Heavy { * @param on requested flashlight state */ public static void flash(final Context context, final Address replyTo, final boolean on){ - startCamera(context, replyTo); + startCamera(context, replyTo, 0); if(camera==null) return; final Camera.Parameters parms=camera.getParameters(); @@ -938,7 +1155,7 @@ final class Heavy { * @see LocationManager#requestLocationUpdates(String, long, float, LocationListener) */ public static void location(final Context context, final Address replyTo, final String provider,final long minTime,final float minDistance){ - final LocationManager man=(LocationManager) context.getSystemService(Context.LOCATION_SERVICE); + final LocationManager man=(LocationManager) context.getApplicationContext().getSystemService(Context.LOCATION_SERVICE); if(locationListener!=null) nolocation(context, toNonNull(Address.BLACKHOLE)); Utils.registerOngoing(context, toNonNull(OngoingEvent.LOCATION)); @@ -949,7 +1166,7 @@ final class Heavy { Utils.sendMessage(context, replyTo, last_known_location); locationListener.onLocationChanged(lastKnownLocation); } - Utils.sendMessage(context, replyTo, listening_for_location_updates); + Utils.sendConfirmMessage(context, replyTo, listening_for_location_updates); man.requestLocationUpdates(provider, minTime, minDistance, locationListener); } @@ -962,7 +1179,7 @@ final class Heavy { public static void lock(final Context context, final Address replyTo) { final DevicePolicyManager dpm=(DevicePolicyManager) context.getSystemService(Context.DEVICE_POLICY_SERVICE); dpm.lockNow(); - Utils.sendMessage(context, replyTo, device_locked); + Utils.sendConfirmMessage(context, replyTo, device_locked); } /** @@ -976,7 +1193,7 @@ final class Heavy { final Intent intent=new Intent("com.android.music.musicservicecommand"); intent.putExtra("command", command); context.sendBroadcast(intent); - Utils.sendMessage(context, replyTo, command_sent); + Utils.sendConfirmMessage(context, replyTo, command_sent); } /** @@ -989,55 +1206,7 @@ final class Heavy { * @param port server port */ public static void ncfile(final Context context, final Address replyTo, final String filename,final String hostname,final int port){ - new AsyncTask() { - @Override - protected @Nullable Void doInBackground(@Nullable final Void... params) { - final FileChannel in; - try{ - in=new FileInputStream(filename).getChannel(); - } catch (final FileNotFoundException e){ - Utils.sendMessage(context, replyTo, file_not_found, filename); - return null; - } - final SocketChannel sock; - try{ - sock = SocketChannel.open(new InetSocketAddress(hostname, port)); - } catch (final IOException e){ - Utils.sendMessage(context, replyTo, toNonNull(context.getString( - cannot_connect_to_host_on_port, hostname, Integer.valueOf(port)))); - try { - in.close(); - } catch (IOException ex) { - //ignored - } - return null; - } - - try{ - in.transferTo(0, in.size(), sock); - } catch (final IOException e){ - Utils.sendMessage(context, replyTo, toNonNull(context.getString( - io_error, e.getMessage()))); - } finally { - try{ - in.close(); - } catch (IOException e){ - //ignored - } - try{ - sock.close(); - } catch(IOException e){ - //ignored - } - } - return null; - } - - @Override - protected void onPostExecute(@Nullable final Void result) { - Utils.sendMessage(context, replyTo, file_sent); - } - }.execute(); + new NcfileExecutableRunnable(context, replyTo, filename, hostname, port).execute(); } /** @@ -1048,10 +1217,10 @@ final class Heavy { */ public static void nolocation(final Context context, final Address replyTo){ Utils.unregisterOngoing(context, toNonNull(OngoingEvent.LOCATION)); - final LocationManager man=(LocationManager) context.getSystemService(Context.LOCATION_SERVICE); + final LocationManager man=(LocationManager) context.getApplicationContext().getSystemService(Context.LOCATION_SERVICE); man.removeUpdates(locationListener); locationListener=null; - Utils.sendMessage(context, replyTo, no_longer_listening_for_location_updates); + Utils.sendConfirmMessage(context, replyTo, no_longer_listening_for_location_updates); } /** @@ -1059,11 +1228,12 @@ final class Heavy { * * @param context Context instance * @param replyTo reply Address + * @param cameraNumber camera to take photo with * @param hostname server hostname * @param port server port */ - public static void photo(final Context context, final Address replyTo, final String hostname, final int port){ - startCamera(context, replyTo); + public static void photo(final Context context, final Address replyTo, final int cameraNumber, final String hostname, final int port){ + startCamera(context, replyTo, cameraNumber); if(camera==null) return; final Camera.Parameters parms=camera.getParameters(); @@ -1084,16 +1254,16 @@ final class Heavy { new Thread(new Runnable() { @Override public void run() { - try { - Thread.sleep(2000); - } catch (InterruptedException e) { - //ignored - } + SystemClock.sleep(2000); handler.post(new Runnable() { @Override public void run() { - camera.takePicture(null, null, new FonBotPictureCallback(context, replyTo, hostname, port)); + try { + camera.takePicture(null, null, new FonBotPictureCallback(context, replyTo, hostname, port)); + } catch(Exception e){ + Utils.sendMessage(context, replyTo, error_while_processing_command, e.getClass().getName(), e.getMessage()); + } } }); } @@ -1209,7 +1379,7 @@ final class Heavy { */ public static void rm(final Context context, final Address replyTo, final String filename){ if(new File(filename).delete()) - Utils.sendMessage(context, replyTo, file_deleted); + Utils.sendConfirmMessage(context, replyTo, file_deleted); else Utils.sendMessage(context, replyTo, error_while_deleting_file); } @@ -1225,7 +1395,7 @@ final class Heavy { final DevicePolicyManager dpm=(DevicePolicyManager) context.getSystemService(Context.DEVICE_POLICY_SERVICE); dpm.resetPassword("", 0); - Utils.sendMessage(context, replyTo, password_cleared); + Utils.sendConfirmMessage(context, replyTo, password_cleared); } /** @@ -1240,7 +1410,7 @@ final class Heavy { final DevicePolicyManager dpm=(DevicePolicyManager) context.getSystemService(Context.DEVICE_POLICY_SERVICE); dpm.resetPassword(password, 0); - Utils.sendMessage(context, replyTo, password_set); + Utils.sendConfirmMessage(context, replyTo, password_set); } /** @@ -1251,11 +1421,11 @@ final class Heavy { * @param destination destination phone number * @param text text message contents */ - public static void sms(final Context context, final Address replyTo, final String destination, final String text){ + public static void sms(final Context context, final Address replyTo, final String destination, final String text, final boolean quiet){ final SmsManager manager=SmsManager.getDefault(); final ArrayList messages=manager.divideMessage(text); if(messages.size() > 1) - Utils.sendMessage(context, replyTo, message_was_split_into_parts, Integer.valueOf(messages.size())); + Utils.sendConfirmMessage(context, replyTo, message_was_split_into_parts, Integer.valueOf(messages.size())); final ArrayList sents=new ArrayList(messages.size()); final ArrayList delivereds=new ArrayList(messages.size()); @@ -1273,7 +1443,7 @@ final class Heavy { sent.putExtra(SmsStatusReceiver.EXTRA_PART, i+1); sent.putExtra(SmsStatusReceiver.EXTRA_TOTAL, messages.size()); sent.putExtra(SmsStatusReceiver.EXTRA_REPLY_TO, replyTo.toString()); - sent.setAction(SmsStatusReceiver.SENT_ACTION+i);//actions must be unique + sent.setAction(SmsStatusReceiver.SENT_ACTION+i+System.currentTimeMillis());//actions must be unique sents.add(PendingIntent.getBroadcast(context, 0, sent, PendingIntent.FLAG_UPDATE_CURRENT)); final Intent delivered=new Intent(context, SmsStatusReceiver.class); @@ -1281,12 +1451,12 @@ final class Heavy { delivered.putExtra(SmsStatusReceiver.EXTRA_PART, i+1); delivered.putExtra(SmsStatusReceiver.EXTRA_TOTAL, messages.size()); delivered.putExtra(SmsStatusReceiver.EXTRA_REPLY_TO, replyTo.toString()); - delivered.setAction(SmsStatusReceiver.DELIVERED_ACTION+i);//actions must be unique + delivered.setAction(SmsStatusReceiver.DELIVERED_ACTION+i+System.currentTimeMillis());//actions must be unique delivereds.add(PendingIntent.getBroadcast(context, 0, delivered, PendingIntent.FLAG_UPDATE_CURRENT)); } Log.d(Heavy.class.getName(), "Sending sms to "+destination); - manager.sendMultipartTextMessage(destination, null, messages, sents, delivereds); + manager.sendMultipartTextMessage(destination, null, messages, sents, quiet ? null : delivereds); } /** @@ -1311,11 +1481,16 @@ final class Heavy { do { final String fromNumber=cursor.getString(1); final String from; - final String name=Utils.callerId(context, Utils.toNonNull(fromNumber)); - if(name==null) - from=fromNumber; - else - from=fromNumber+" ("+name+')'; + if(fromNumber == null) + from = null; + else { + final String name=Utils.callerId(context, Utils.toNonNull(fromNumber)); + if(name==null) + from=fromNumber; + else + from=fromNumber+" ("+name+')'; + } + final String message=cursor.getString(2).replace("\n", "\n "); final Date date=new Date(cursor.getLong(3)); @@ -1344,7 +1519,7 @@ final class Heavy { @Override public void onInit(final int status) { if(status==TextToSpeech.SUCCESS){ - Utils.sendMessage(context, replyTo, speaking); + Utils.sendConfirmMessage(context, replyTo, speaking); tts.speak(text, TextToSpeech.QUEUE_ADD, null); } else Utils.sendMessage(context, replyTo, tts_engine_not_available); @@ -1373,7 +1548,7 @@ final class Heavy { */ public static void toast(final Context context, final Address replyTo, final String text, final int duration){ Toast.makeText(context,text,duration).show(); - Utils.sendMessage(context, replyTo, toast_shown); + Utils.sendConfirmMessage(context, replyTo, toast_shown); } /** @@ -1385,7 +1560,7 @@ final class Heavy { */ public static void vibrate(final Context context, final Address replyTo, final long ms){ final Vibrator v=(Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE); - Utils.sendMessage(context, replyTo, vibrating); + Utils.sendConfirmMessage(context, replyTo, vibrating); v.vibrate(ms); } @@ -1402,7 +1577,7 @@ final class Heavy { intent.setData(uri); intent.setFlags(Intent.FLAG_FROM_BACKGROUND|Intent.FLAG_ACTIVITY_NEW_TASK); context.startActivity(intent); - Utils.sendMessage(context, replyTo, url_opened); + Utils.sendConfirmMessage(context, replyTo, url_opened); } catch(ActivityNotFoundException e){ Utils.sendMessage(context, replyTo, no_activity_found_for_this_url); } catch(Exception e){ @@ -1435,9 +1610,9 @@ final class Heavy { final WifiManager man=(WifiManager) context.getSystemService(Context.WIFI_SERVICE); man.setWifiEnabled(on); if(on) - Utils.sendMessage(context, replyTo, enabling_wifi); + Utils.sendConfirmMessage(context, replyTo, enabling_wifi); else - Utils.sendMessage(context, replyTo, disabling_wifi); + Utils.sendConfirmMessage(context, replyTo, disabling_wifi); } /** @@ -1471,7 +1646,7 @@ final class Heavy { public static void disable(final Context context, final Address replyTo, final Command command){ PreferenceManager.getDefaultSharedPreferences(context).edit() .putBoolean(command+"disabled", true).commit(); - Utils.sendMessage(context, replyTo, command_disabled, command); + Utils.sendConfirmMessage(context, replyTo, command_disabled, command); } /** @@ -1484,7 +1659,7 @@ final class Heavy { public static void enable(final Context context, final Address replyTo, final Command command){ PreferenceManager.getDefaultSharedPreferences(context).edit() .remove(command+"disabled").commit(); - Utils.sendMessage(context, replyTo, command_enabled, command); + Utils.sendConfirmMessage(context, replyTo, command_enabled, command); } @@ -1500,37 +1675,14 @@ final class Heavy { } /** - * Poll the server for pending commands. + * Start long polling if stopped * * @param context Context instance * @param replyTo reply Address */ public static void poll(final Context context, final Address replyTo) { - Utils.sendMessage(context, replyTo, polling_server); - Utils.pollServer(context); - } - - /** - * Change the server poll interval. - * - * @param context Context instance - * @param replyTo reply Address - * @param ms server poll interval in milliseconds. If 0, server poll is disabled - */ - public static void poll(final Context context, final Address replyTo, final long ms){ - final AlarmManager man=(AlarmManager) context.getSystemService(Context.ALARM_SERVICE); - final Intent pollAlarm=new Intent(context, LocalBroadcastReceiver.class); - pollAlarm.setAction(LocalBroadcastReceiver.ACTION_POLL_ALARM); - final PendingIntent intent=PendingIntent.getBroadcast(context, 0, pollAlarm, 0); - if(ms==0){ - Utils.unregisterOngoing(context, toNonNull(OngoingEvent.POLL)); - man.cancel(intent); - Utils.sendMessage(context, replyTo, polling_stopped); - } else { - Utils.registerOngoing(context, toNonNull(OngoingEvent.POLL)); - man.setRepeating(AlarmManager.RTC_WAKEUP, 0, ms, intent); - Utils.sendMessage(context, replyTo, polling_every_milliseconds, Long.valueOf(ms)); - } + Utils.sendConfirmMessage(context, replyTo, starting_long_polling_if_stopped); + context.startService(new Intent(context, FonBotMainService.class)); } /** @@ -1594,7 +1746,7 @@ final class Heavy { return; } context.startActivity(intent); - Utils.sendMessage(context, replyTo, app_launched); + Utils.sendConfirmMessage(context, replyTo, app_launched); } /** @@ -1629,10 +1781,10 @@ final class Heavy { try{ if(enable){ getITelephony(context).enableDataConnectivity(); - Utils.sendMessage(context, replyTo, enabling_data); + Utils.sendConfirmMessage(context, replyTo, enabling_data); } else { getITelephony(context).disableDataConnectivity(); - Utils.sendMessage(context, replyTo, disabling_data); + Utils.sendConfirmMessage(context, replyTo, disabling_data); } } catch(Exception e){ Utils.sendMessage(context, replyTo, exception_while_getting_itelephony, @@ -1663,9 +1815,9 @@ final class Heavy { public static void gps(final Context context, final Address replyTo, final boolean enabled) { Secure.setLocationProviderEnabled(context.getContentResolver(), LocationManager.GPS_PROVIDER, enabled); if(enabled) - Utils.sendMessage(context, replyTo, enabling_gps); + Utils.sendConfirmMessage(context, replyTo, enabling_gps); else - Utils.sendMessage(context, replyTo, disabling_gps); + Utils.sendConfirmMessage(context, replyTo, disabling_gps); } /** @@ -1691,9 +1843,9 @@ final class Heavy { public static void glocation(final Context context, final Address replyTo, final boolean enabled) { Secure.setLocationProviderEnabled(context.getContentResolver(), LocationManager.NETWORK_PROVIDER, enabled); if(enabled) - Utils.sendMessage(context, replyTo, enabling_network_location); + Utils.sendConfirmMessage(context, replyTo, enabling_network_location); else - Utils.sendMessage(context, replyTo, disabling_network_location); + Utils.sendConfirmMessage(context, replyTo, disabling_network_location); } /** @@ -1707,8 +1859,22 @@ final class Heavy { */ public static void reboot(final Context context, final Address replyTo, final @Nullable String reason) { final PowerManager pm=(PowerManager) context.getSystemService(Context.POWER_SERVICE); - Utils.sendMessage(context, replyTo, rebooting); - pm.reboot(reason); + Utils.sendConfirmMessage(context, replyTo, rebooting); + try { + pm.reboot(reason); + } catch (final Exception e){ + e.printStackTrace(); + } + try { + Runtime.getRuntime().exec(new String[]{ + "su", + "-c", + "reboot" + }).waitFor(); + } catch (final Exception e){ + e.printStackTrace(); + } + Utils.sendMessage(toNonNull(context), toNonNull(replyTo), reboot_failed); } /** @@ -1721,7 +1887,7 @@ final class Heavy { public static void notify(final Context context, final Address replyTo, final int id) { final NotificationManager man=(NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE); man.cancel(id); - Utils.sendMessage(context, replyTo, notification_canceled); + Utils.sendConfirmMessage(context, replyTo, notification_canceled); } /** @@ -1740,6 +1906,67 @@ final class Heavy { setContentText(text). setSmallIcon(android.R.drawable.stat_notify_sync_noanim). build()); - Utils.sendMessage(context, replyTo, notification_shown); + Utils.sendConfirmMessage(context, replyTo, notification_shown); + } + + /** + * Take a screen capture. Uses the screencap utility and requires root. + * + * @param context Context instance + * @param replyTo reply Address + * @param filename capture file location + */ + public static void screencap(final Context context, final Address replyTo, final String filename){ + new Thread(new ScreencapRunnable(context, replyTo, filename)).start(); + } + + /** + * Toggle the torch state using the Torch (net.cactii.torch2) app. + * + * @param context Context instance + * @param replyTo reply Address + */ + public static void torch(final Context context, final Address replyTo){ + context.sendBroadcast(new Intent("net.cactii.flash2.TOGGLE_FLASHLIGHT")); + Utils.sendConfirmMessage(context, replyTo, toggling_torch_state); + } + + /** + * Download a file from a given URL to a given filename + * + * @param context Context instance + * @param replyTo reply Address + * @param filename filename to save to + * @param hostname hostname to download from + * @param port port to download from + */ + public static void getfile(final Context context, final Address replyTo, final String filename, final String hostname, final int port){ + new GetfileExecutableRunnable(context, replyTo, filename, hostname, port).execute(); + } + + /** + * Execute a command using a given shell and reply with the output. + * + * @param context Context instance + * @param replyTo reply Address + * @param shell The shell to execute with. Usually sh or su. + * @param command The command to pass to the shell. + */ + public static void execute(final Context context, final Address replyTo, final String shell, final String command) { + try { + final Process proc = Runtime.getRuntime().exec(new String[]{ + shell, + "-c", + command + }); + final BufferedReader br = new BufferedReader (new InputStreamReader(proc.getInputStream())); + String line; + while((line = br.readLine()) != null) + Utils.sendMessage(context, replyTo, line); + proc.waitFor(); + } catch (final Exception e){ + Utils.sendMessage(context, replyTo, error_while_processing_command, e.getClass().getName(), e.getMessage()); + Log.w(Heavy.class.getName(), "Error while processing command", e); + } } }