package com.gokulnc.ums_universal; import android.app.DownloadManager; import android.app.Notification; import android.app.NotificationManager; import android.app.PendingIntent; import android.content.BroadcastReceiver; import android.content.ContentResolver; import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; import android.database.Cursor; import android.net.Uri; import android.provider.MediaStore; import android.support.v7.app.NotificationCompat; import android.util.Log; import android.widget.Toast; import com.stericson.RootShell.execution.Command; import com.stericson.RootShell.execution.Shell; import com.stericson.RootTools.RootTools; import java.util.Date; import static android.content.Context.NOTIFICATION_SERVICE; import static com.gokulnc.ums_universal.Constants.LOG_TAG; public class UsbBroadcastReceiver extends BroadcastReceiver { static SharedPreferences data; private static long lastAccessTime = Long.MAX_VALUE; // public static boolean isNewInstance = true; //These state variables get lost if app is opened & closed, so to read from SharedPref when that happens public static boolean isUMSdisabled = true; static final String usbStateChangeAction = "android.hardware.usb.action.USB_STATE"; static final String intentEnableUMS = "com.gokulnc.ums_universal.ACTION_ENABLE_UMS"; static final String intentDisableUMS = "com.gokulnc.ums_universal.ACTION_DISABLE_UMS"; @Override public void onReceive(Context context, Intent intent) { String action = intent.getAction(); Log.d(LOG_TAG, "Received Broadcast: "+action); if(data==null) data = context.getSharedPreferences(Constants.MyPREFERENCES, Context.MODE_PRIVATE); if(data.getBoolean(Constants.autoStart, false) && !MainActivity.isAppOpen && action.equalsIgnoreCase(usbStateChangeAction)) { if(intent.getBooleanExtra("connected", false)) toggleUMS(true, false, context); else toggleUMS(false, true, context); } else if(action.equalsIgnoreCase(intentEnableUMS)) { if(intent.getBooleanExtra("fromWidget", false) && !data.getBoolean(Constants.widgetEnabled, false)) { data.edit().putBoolean(Constants.widgetEnabled, true).apply(); return; //all this bullshit to ignore the onUpdate() from widget when widget created for first time } toggleUMS(true, false, context); } else if(action.equalsIgnoreCase(intentDisableUMS)) { if(intent.getBooleanExtra("fromWidget", false) && !data.getBoolean(Constants.widgetEnabled, false)) { data.edit().putBoolean(Constants.widgetEnabled, true).apply(); return; } //Notification will not be removed when toggled from Notification boolean removeNotif = intent.getBooleanExtra("removeNotif", true); toggleUMS(false, removeNotif, context); //} else if(action.equalsIgnoreCase("android.intent.action.BOOT_COMPLETED")) { } else if(action.equalsIgnoreCase(DownloadManager.ACTION_DOWNLOAD_COMPLETE)) { Toast.makeText(context, "Download Complete", Toast.LENGTH_SHORT).show(); try { installUpdate(context, intent); } catch (Exception e) { e.printStackTrace(); } } } public void installUpdate(Context context, Intent intent) throws Exception { Intent install = new Intent(Intent.ACTION_VIEW); install.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); install.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); long downloadId = intent.getExtras().getLong(DownloadManager.EXTRA_DOWNLOAD_ID); Log.d(LOG_TAG, "download id: "+downloadId); DownloadManager dlMgr = (DownloadManager) context.getSystemService(Context.DOWNLOAD_SERVICE); /*try { dlMgr.openDownloadedFile(downloadId); } catch (Exception e) { e.printStackTrace(); context.startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(MainActivity.XdaThreadURL))); }*/ //install.setDataAndType(downloadedApk, dlMgr.getMimeTypeForDownloadedFile(downloadId)); //treats apk as a zip, lol Uri downloadedApk = dlMgr.getUriForDownloadedFile(downloadId); install.setDataAndType(getFileUriFromUri(context, downloadedApk) , "application/vnd.android.package-archive"); //MIME-type referred here: http://stackoverflow.com/questions/20065040/download-installing-and-delete-apk-file-on-android-device-programmatically-fro context.startActivity(install); } public static Uri getFileUriFromUri(Context c, Uri uri) { //Reference: http://stackoverflow.com/questions/9194361/how-to-use-android-downloadmanager try { if ("content".equals(uri.getScheme())) { //Android 4.2 and above behavior String[] filePathColumn = {MediaStore.MediaColumns.DATA}; ContentResolver contentResolver = c.getContentResolver(); Cursor cursor = contentResolver.query(uri, filePathColumn, null, null, null); cursor.moveToFirst(); int columnIndex = cursor.getColumnIndex(filePathColumn[0]); String filePath = cursor.getString(columnIndex); cursor.close(); return Uri.parse("file://" + filePath); } else if ("file".equals(uri.getScheme())) { return uri; } } catch (Exception e) { e.printStackTrace(); } return uri; } void openApp(Context context) { Intent i = new Intent(context, MainActivity.class); i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); context.startActivity(i); } boolean toggleUMS(boolean enableUMS, boolean removeNotif, Context context) { if(new Date().getTime()-lastAccessTime > 4500 || lastAccessTime==Long.MAX_VALUE) { //When a mode is toggled, the USB_STATE CHANGE broadcast is sent 2 times (thus firing toggles recursively), which gets built up exponentially. //This dirty hack condition ensures that those toggles are eliminated (by allowing a toggle only once in 4 secs) lastAccessTime = new Date().getTime(); return enableUMS?enableUMS(context):disableUMS(context, removeNotif); } return false; } boolean enableUMS(Context context) { try { String enableCommand = data.getString(Constants.setPermissionCmds, "")+"\n"+data.getString(Constants.enableUMScmds, ""); if(enableCommand.isEmpty()) { Toast.makeText(context, context.getString(R.string.toast_open_app_once), Toast.LENGTH_SHORT).show(); return false; } Shell rootShell = RootTools.getShell(true); Command cmd = new Command(0, "setenforce 0\n"+enableCommand); rootShell.add(cmd); //if(!rootShell.isExecuting) rootShell.close(); } catch (Exception e) { e.printStackTrace(); Toast.makeText(context, context.getString(R.string.error_ums), Toast.LENGTH_SHORT).show(); openApp(context); return false; } Toast.makeText(context, context.getString(R.string.toast_ums_enabled), Toast.LENGTH_SHORT).show(); isUMSdisabled = false; showNotification(context); return true; } boolean disableUMS(Context context, boolean removeNotif) { try { String disableCommand = data.getString(Constants.disableUMScmds, ""); if(disableCommand.isEmpty()) { Toast.makeText(context, context.getString(R.string.toast_open_app_once), Toast.LENGTH_SHORT).show(); return false; } Shell rootShell = RootTools.getShell(true); Command cmd = new Command(0, disableCommand); rootShell.add(cmd); //if(!rootShell.isExecuting) rootShell.close(); } catch (Exception e) { e.printStackTrace(); Toast.makeText(context, context.getString(R.string.error_ums_disable), Toast.LENGTH_SHORT).show(); return false; } Toast.makeText(context, context.getString(R.string.toast_ums_disabled), Toast.LENGTH_SHORT).show(); isUMSdisabled = true; if(removeNotif) removeNotification(context); else showNotification(context); //TODO: if(MainActivity.isAppOpen) MainActivity.updateUSBconfig(); //When toggled from notif return true; } public static void showNotification(Context context) { if(data==null) data = context.getSharedPreferences(Constants.MyPREFERENCES, Context.MODE_PRIVATE); if(data.getBoolean(Constants.NotifsEnable, true) || data.getBoolean(Constants.autoStart, false)&&!MainActivity.isAppOpen) { PendingIntent pi = PendingIntent.getActivity(context, 0, new Intent(context, MainActivity.class), 0); PendingIntent ums_action; if(isUMSdisabled) { ums_action = PendingIntent.getBroadcast(context, 0, new Intent(intentEnableUMS), PendingIntent.FLAG_CANCEL_CURRENT); } else { Intent i = new Intent(intentDisableUMS); i.putExtra("removeNotif", false); ums_action = PendingIntent.getBroadcast(context, 0, i, PendingIntent.FLAG_CANCEL_CURRENT); } NotificationManager notificationManager = (NotificationManager) context.getSystemService(NOTIFICATION_SERVICE); Notification notification = new NotificationCompat.Builder(context) .setTicker(isUMSdisabled ? context.getString(R.string.notif_ums_disabled) : context.getString(R.string.notif_ums_enabled)) .setSmallIcon(android.R.drawable.stat_notify_sdcard_usb) .setContentTitle(isUMSdisabled ? context.getString(R.string.notif_ums_disabled) : context.getString(R.string.notif_ums_enabled)) .setContentText(isUMSdisabled ? context.getString(R.string.notif_ums_disabled_msg):context.getString(R.string.notif_ums_enabled_msg)) .setContentIntent(pi) //.setOngoing(true) .addAction(new android.support.v4.app.NotificationCompat.Action.Builder( R.drawable.empty_icon, isUMSdisabled ? context.getString(R.string.action_enable_ums_short): context.getString(R.string.action_disable_ums_short), ums_action ).build()) .build(); if(notification!=null) notificationManager.notify(0, notification); } } public static void removeNotification(Context context) { NotificationManager notificationManager = (NotificationManager) context.getSystemService(NOTIFICATION_SERVICE); notificationManager.cancelAll(); } }