package pl.edu.agh.adhoc; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.InetAddress; import java.net.SocketException; import java.net.UnknownHostException; import java.util.Hashtable; import net.osmand.plus.R; import net.osmand.plus.activities.MainMenuActivity; import pl.edu.agh.adhoc.system.Configuration; import pl.edu.agh.adhoc.system.CoreTask; import pl.edu.agh.logic.TrafficDataProvider; import android.app.Application; import android.app.Notification; import android.app.NotificationManager; import android.app.PendingIntent; import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; import android.net.wifi.WifiManager; import android.os.Handler; import android.os.Message; import android.preference.PreferenceManager; import android.util.Log; import android.widget.Toast; public class AdHocModule { public Application application; public static final String MSG_TAG = "AdHoc Wifi"; public static final int DEFAULT_LISTEN_PORT = 2340; public final String DEFAULT_PASSPHRASE = "abcdefghijklm"; public final String DEFAULT_LANNETWORK = "192.168.2.0/24"; public final String DEFAULT_ENCSETUP = "wpa_supplicant"; // StartUp-Check perfomed public boolean startupCheckPerformed = false; // WifiManager private WifiManager wifiManager; // Preferences public SharedPreferences settings = null; public SharedPreferences.Editor preferenceEditor = null; // Notification public NotificationManager notificationManager; private Notification notification; // Intents private PendingIntent mainIntent; // Original States private static boolean origWifiState = false; // Supplicant public CoreTask.WpaSupplicant wpasupplicant = null; // TiWlan.conf public CoreTask.TiWlanConf tiwlan = null; // tether.conf public CoreTask.TetherConfig tethercfg = null; // CoreTask public CoreTask coretask = null; public AdHocBroadcastSocket socket = null; public TrafficDataProvider trafficDataProvider = null; public AdHocModule(Application application) { this.application = application; } public void setTrafficDataProvider(TrafficDataProvider trafficDataProvider) { this.trafficDataProvider = trafficDataProvider; } public void init() { Log.d(MSG_TAG, "Calling init()"); //create CoreTask this.coretask = new CoreTask(); this.coretask.setPath(application.getApplicationContext().getFilesDir().getParent()); Log.d(MSG_TAG, "Current directory is "+application.getApplicationContext().getFilesDir().getParent()); // Check Homedir, or create it this.checkDirs(); // Preferences this.settings = PreferenceManager.getDefaultSharedPreferences(application); // preferenceEditor this.preferenceEditor = settings.edit(); // init wifiManager wifiManager = (WifiManager) application.getSystemService(Context.WIFI_SERVICE); // Supplicant config this.wpasupplicant = this.coretask.new WpaSupplicant(); // tiwlan.conf this.tiwlan = this.coretask.new TiWlanConf(); // tether.cfg this.tethercfg = this.coretask.new TetherConfig(); this.tethercfg.read(); this.notificationManager = (NotificationManager) application.getSystemService(Context.NOTIFICATION_SERVICE); this.notification = new Notification(R.drawable.start_notification, "AdHoc Wifi", System.currentTimeMillis()); this.mainIntent = PendingIntent.getActivity(application, 0, new Intent(application, MainMenuActivity.class), 0); this.socket = new AdHocBroadcastSocket(); } public void finish() { Log.d(MSG_TAG, "Calling finish()"); this.stopAdHoc(); this.notificationManager.cancelAll(); } public void updateConfiguration() { long startStamp = System.currentTimeMillis(); String deviceType = Configuration.getDeviceType(); boolean bluetoothPref = this.settings.getBoolean("bluetoothon", false); boolean wepEnabled = this.settings.getBoolean("encpref", false); String ssid = this.settings.getString("ssidpref", "AndroidTether"); String txpower = this.settings.getString("txpowerpref", "disabled"); String lannetwork = this.settings.getString("lannetworkpref", DEFAULT_LANNETWORK); String wepkey = this.settings.getString("passphrasepref", DEFAULT_PASSPHRASE); String wepsetupMethod = this.settings.getString("encsetuppref", DEFAULT_ENCSETUP); String channel = this.settings.getString("channelpref", "1"); String mac = this.wifiManager.getConnectionInfo().getMacAddress(); String[] macChks = mac.split(":"); byte[] ip = new byte[4]; int i =0; for(String macChk: macChks) { i++; if(i<=2) { continue; } Integer ipChk = Integer.parseInt(macChk, 16); ip[i-3] = ipChk.byteValue(); } ip[0] = 10; InetAddress address; try { address = InetAddress.getByAddress(ip); lannetwork = address.getHostAddress(); } catch (UnknownHostException e) { Log.e(MSG_TAG, "Error while craeting ip"); } // tether.conf this.tethercfg.read(); this.tethercfg.put("device.type", deviceType); this.tethercfg.put("tether.mode", bluetoothPref ? "bt" : "wifi"); this.tethercfg.put("wifi.essid", ssid); this.tethercfg.put("wifi.channel", channel); this.tethercfg.put("ip.network", lannetwork.split("/")[0]); this.tethercfg.put("ip.netmask", "255.0.0.0"); this.tethercfg.put("ip.gateway", lannetwork.split("/")[0]); this.tethercfg.put("wifi.interface", this.coretask.getProp("wifi.interface")); this.tethercfg.put("wifi.txpower", txpower); // wepEncryption if (wepEnabled) { this.tethercfg.put("wifi.encryption", "wep"); this.tethercfg.put("wifi.wepkey", wepkey); // Getting encryption-method if setup-method on auto if (wepsetupMethod.equals("auto")) { wepsetupMethod = Configuration.getEncryptionAutoMethod(deviceType); } // Setting setup-mode this.tethercfg.put("wifi.setup", wepsetupMethod); // Prepare wpa_supplicant-config if wpa_supplicant selected if (wepsetupMethod.equals("wpa_supplicant")) { // Install wpa_supplicant.conf-template if (this.wpasupplicant.exists() == false) { this.installWpaSupplicantConfig(); } // Update wpa_supplicant.conf Hashtable<String,String> values = new Hashtable<String,String>(); values.put("ssid", "\""+this.settings.getString("ssidpref", "TrafficAdHoc")+"\""); values.put("wep_key0", "\""+this.settings.getString("passphrasepref", DEFAULT_PASSPHRASE)+"\""); this.wpasupplicant.write(values); } } else { this.tethercfg.put("wifi.encryption", "disabled"); this.tethercfg.put("wifi.wepkey", ""); // Make sure to remove wpa_supplicant.conf if (this.wpasupplicant.exists()) { this.wpasupplicant.remove(); } } // determine driver wpa_supplicant this.tethercfg.put("wifi.driver", Configuration.getWpaSupplicantDriver(deviceType)); // writing config-file if (this.tethercfg.write() == false) { Log.e(MSG_TAG, "Unable to update tether.conf!"); } /* * TODO * Need to find a better method to identify if the used device is a * HTC Dream aka T-Mobile G1 */ if (deviceType.equals(Configuration.DEVICE_DREAM)) { Hashtable<String,String> values = new Hashtable<String,String>(); values.put("dot11DesiredSSID", this.settings.getString("ssidpref", "TrafficAdHoc")); values.put("dot11DesiredChannel", this.settings.getString("channelpref", "1")); this.tiwlan.write(values); } Log.d(MSG_TAG, "Creation of configuration-files took ==> "+(System.currentTimeMillis()-startStamp)+" milliseconds."); coretask.runRootCommand("cp " + AdHocModule.this.coretask.DATA_FILE_PATH+"/conf/tether.conf /data/data/android.tether/conf"); } // Start/Stop AdHoc public boolean startAdHoc() { // Updating all configs this.updateConfiguration(); this.disableWifi(); // Starting service if (this.coretask.runRootCommand(this.coretask.DATA_FILE_PATH+"/bin/tether start 1")) { AdHocModule.this.copyFile(AdHocModule.this.coretask.DATA_FILE_PATH+"/conf/ad_hoc.pid", "550", R.raw.ad_hoc_pid); String listenAddress = this.tethercfg.get("ip.gateway"); InetAddress address; try { address = InetAddress.getByName(listenAddress); this.socket.open(address, DEFAULT_LISTEN_PORT); } catch (UnknownHostException e) { Log.e(MSG_TAG, "Wrong ad-hoc listen address", e); } catch (SocketException e) { Log.e(MSG_TAG, "ad-hoc broad cast socket error", e); } if(trafficDataProvider != null) { trafficDataProvider.startAdHocServer(); } return true; } return false; } public boolean stopAdHoc() { boolean stopped = this.coretask.runRootCommand(this.coretask.DATA_FILE_PATH+"/bin/tether stop 1"); this.notificationManager.cancelAll(); AdHocModule.this.removeFile(AdHocModule.this.coretask.DATA_FILE_PATH+"/conf/ad_hoc.pid"); if(trafficDataProvider != null) { trafficDataProvider.stopAdHocServer(); } this.socket.close(); this.enableWifi(); return stopped; } public boolean restartAdHoc() { boolean status = this.coretask.runRootCommand(this.coretask.DATA_FILE_PATH+"/bin/tether stop 1"); this.notificationManager.cancelAll(); // Updating all configs this.updateConfiguration(); this.disableWifi(); // Starting service if (status == true) status = this.coretask.runRootCommand(this.coretask.DATA_FILE_PATH+"/bin/tether start 1"); this.showStartNotification(); return status; } public String getNetworkDevice() { return this.coretask.getProp("wifi.interface"); } // gets user preference on whether wakelock should be disabled during tethering public boolean isWakeLockDisabled(){ return this.settings.getBoolean("wakelockpref", true); } // Wifi public void disableWifi() { if (this.wifiManager.isWifiEnabled()) { origWifiState = true; this.wifiManager.setWifiEnabled(false); Log.d(MSG_TAG, "Wifi disabled!"); // Waiting for interface-shutdown try { Thread.sleep(5000); } catch (InterruptedException e) { // nothing } } } public void enableWifi() { if (origWifiState) { // Waiting for interface-restart this.wifiManager.setWifiEnabled(true); try { Thread.sleep(5000); } catch (InterruptedException e) { // nothing } Log.d(MSG_TAG, "Wifi started!"); } } public int getNotificationType() { return Integer.parseInt(this.settings.getString("notificationpref", "2")); } // Notification public void showStartNotification() { notification.flags = Notification.FLAG_ONGOING_EVENT; notification.setLatestEventInfo(application, "AdHoc Wifi", "AdHoc is currently running ...", this.mainIntent); this.notificationManager.notify(-1, this.notification); } public boolean binariesExists() { File file = new File(this.coretask.DATA_FILE_PATH+"/bin/tether"); return file.exists(); } public boolean isProcessRunning() { File pidFile = new File(this.coretask.DATA_FILE_PATH+"/conf/ad_hoc.pid"); return pidFile.exists(); } public void installWpaSupplicantConfig() { this.copyFile(this.coretask.DATA_FILE_PATH+"/conf/wpa_supplicant.conf", "0644", R.raw.wpa_supplicant_conf); } Handler displayMessageHandler = new Handler(){ public void handleMessage(Message msg) { if (msg.obj != null) { AdHocModule.this.displayToastMessage((String)msg.obj); } super.handleMessage(msg); } }; public void renewLibrary() { File libNativeTaskFile = new File(AdHocModule.this.coretask.DATA_FILE_PATH+"/library/libnativetask.so"); if (libNativeTaskFile.exists()){ libNativeTaskFile.renameTo(new File(AdHocModule.this.coretask.DATA_FILE_PATH+"/library/libnativetask.so")); } } public void installFiles() { String message = null; // libnativeTask.so if (message == null) { File libNativeTaskFile = new File(AdHocModule.this.coretask.DATA_FILE_PATH+"/library/libnativetask.so"); if (libNativeTaskFile.exists()) { message = AdHocModule.this.copyFile(AdHocModule.this.coretask.DATA_FILE_PATH+"/library/libnativetask.so", R.raw.libnativetask_so); } else { message = AdHocModule.this.copyFile(AdHocModule.this.coretask.DATA_FILE_PATH+"/library/libnativetask.so", R.raw.libnativetask_so); } } // tether if (message == null) { message = AdHocModule.this.copyFile(AdHocModule.this.coretask.DATA_FILE_PATH+"/bin/tether", "0755", R.raw.tether); } // ifconfig if (message == null) { message = AdHocModule.this.copyFile(AdHocModule.this.coretask.DATA_FILE_PATH+"/bin/ifconfig", "0755", R.raw.ifconfig); } // iwconfig if (message == null) { message = AdHocModule.this.copyFile(AdHocModule.this.coretask.DATA_FILE_PATH+"/bin/iwconfig", "0755", R.raw.iwconfig); } // tiwlan.ini if (message == null) { File dir = new File("/data/data/android.tether/conf"); if(! dir.exists()) { coretask.runRootCommand("/system/bin/mkdir -p /data/data/android.tether/conf"); } AdHocModule.this.copyFile(AdHocModule.this.coretask.DATA_FILE_PATH+"/conf/tiwlan.ini", "0644", R.raw.tiwlan_ini); coretask.runRootCommand("cp " + AdHocModule.this.coretask.DATA_FILE_PATH+"/conf/tiwlan.ini /data/data/android.tether/conf"); } // edify script if (message == null) { AdHocModule.this.copyFile(AdHocModule.this.coretask.DATA_FILE_PATH+"/conf/tether.edify", "0644", R.raw.tether_edify); coretask.runRootCommand("cp " + AdHocModule.this.coretask.DATA_FILE_PATH+"/conf/tether.edify /data/data/android.tether/conf"); } // tether.cfg if (message == null) { AdHocModule.this.copyFile(AdHocModule.this.coretask.DATA_FILE_PATH+"/conf/tether.conf", "0644", R.raw.tether_conf); coretask.runRootCommand("cp " + AdHocModule.this.coretask.DATA_FILE_PATH+"/conf/tether.conf /data/data/android.tether/conf"); } // wpa_supplicant drops privileges, we need to make files readable. AdHocModule.this.coretask.chmod(AdHocModule.this.coretask.DATA_FILE_PATH+"/conf/", "0755"); if (message == null) { message = "Binaries and config-files installed!"; } // Sending message Message msg = new Message(); msg.obj = message; AdHocModule.this.displayMessageHandler.sendMessage(msg); } private String removeFile(String filename) { File outFile = new File(filename); Log.d(MSG_TAG, "Deleting file '"+filename+"' ..."); if(!outFile.delete()) { return "Couldn't delete file - "+filename+"!"; } return null; } private String copyFile(String filename, String permission, int ressource) { String result = this.copyFile(filename, ressource); if (result != null) { return result; } if (this.coretask.chmod(filename, permission) != true) { result = "Can't change file-permission for '"+filename+"'!"; } return result; } private String copyFile(String filename, int ressource) { File outFile = new File(filename); Log.d(MSG_TAG, "Copying file '"+filename+"' ..."); InputStream is = this.application.getResources().openRawResource(ressource); byte buf[] = new byte[1024]; int len; try { OutputStream out = new FileOutputStream(outFile); while((len = is.read(buf))>0) { out.write(buf,0,len); } out.close(); is.close(); } catch (IOException e) { return "Couldn't install file - "+filename+"!"; } return null; } private void checkDirs() { File dir = new File(this.coretask.DATA_FILE_PATH); if (dir.exists() == false) { this.displayToastMessage("Application data-dir does not exist!"); } else { String[] dirs = { "/bin", "/var", "/conf", "/library"}; for (String dirname : dirs) { dir = new File(this.coretask.DATA_FILE_PATH + dirname); if (dir.exists() == false) { if (!dir.mkdir()) { this.displayToastMessage("Couldn't create " + dirname + " directory!"); } } else { Log.d(MSG_TAG, "Directory '"+dir.getAbsolutePath()+"' already exists!"); } } } } // Display Toast-Message public void displayToastMessage(String message) { Toast.makeText(application.getApplicationContext(), message, Toast.LENGTH_LONG).show(); } }