From e6e176c739a7491b98dd513046672e624d888e03 Mon Sep 17 00:00:00 2001 From: Vijay Rawat Date: Sun, 21 Jun 2015 17:11:18 +0530 Subject: [PATCH] Added 2 features for rooted phones : - Clear cache and - Clear data. MLManagerApplication is created to provide single instace of AppPreferences. Earlier multiple instances were being created which is not required. RootUtils added for checking some root related info. Tested on a few rooted and unrooted phones. --- app/src/main/AndroidManifest.xml | 3 +- .../mlmanager/MLManagerApplication.java | 23 ++++++ .../mlmanager/activities/AboutActivity.java | 3 +- .../mlmanager/activities/AppActivity.java | 69 ++++++++++++++-- .../mlmanager/activities/MainActivity.java | 3 +- .../activities/SettingsActivity.java | 3 +- .../mlmanager/adapters/AppAdapter.java | 3 +- .../mlmanager/utils/AppPreferences.java | 11 +++ .../mlmanager/utils/RootUtils.java | 81 +++++++++++++++++++ .../mlmanager/utils/UtilsApp.java | 3 +- .../mlmanager/utils/UtilsDialog.java | 24 +++++- .../javiersantos/mlmanager/utils/UtilsUI.java | 3 +- app/src/main/res/layout/activity_app.xml | 35 +++++++- app/src/main/res/values/strings.xml | 14 +++- 14 files changed, 260 insertions(+), 18 deletions(-) create mode 100644 app/src/main/java/com/javiersantos/mlmanager/MLManagerApplication.java create mode 100644 app/src/main/java/com/javiersantos/mlmanager/utils/RootUtils.java diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 9b976bb..951ea08 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -10,7 +10,8 @@ android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" - android:theme="@style/MLManager" > + android:theme="@style/MLManager" + android:name=".MLManagerApplication"> diff --git a/app/src/main/java/com/javiersantos/mlmanager/MLManagerApplication.java b/app/src/main/java/com/javiersantos/mlmanager/MLManagerApplication.java new file mode 100644 index 0000000..e11b82a --- /dev/null +++ b/app/src/main/java/com/javiersantos/mlmanager/MLManagerApplication.java @@ -0,0 +1,23 @@ +package com.javiersantos.mlmanager; + +import android.app.Application; + +import com.javiersantos.mlmanager.utils.AppPreferences; + +/** + * Created by vijay.rawat01 on 6/21/15. + */ +public class MLManagerApplication extends Application { + + private static AppPreferences sAppPreferences; + + @Override + public void onCreate() { + sAppPreferences = new AppPreferences(this); + super.onCreate(); + } + + public static AppPreferences getAppPreferences() { + return sAppPreferences; + } +} diff --git a/app/src/main/java/com/javiersantos/mlmanager/activities/AboutActivity.java b/app/src/main/java/com/javiersantos/mlmanager/activities/AboutActivity.java index fe33dd3..3992995 100644 --- a/app/src/main/java/com/javiersantos/mlmanager/activities/AboutActivity.java +++ b/app/src/main/java/com/javiersantos/mlmanager/activities/AboutActivity.java @@ -9,6 +9,7 @@ import android.view.WindowManager; import android.widget.TextView; +import com.javiersantos.mlmanager.MLManagerApplication; import com.javiersantos.mlmanager.R; import com.javiersantos.mlmanager.utils.AppPreferences; import com.javiersantos.mlmanager.utils.UtilsApp; @@ -22,7 +23,7 @@ public class AboutActivity extends AppCompatActivity { protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_about); - this.appPreferences = new AppPreferences(getApplicationContext()); + this.appPreferences = MLManagerApplication.getAppPreferences(); setInitialConfiguration(); setScreenElements(); diff --git a/app/src/main/java/com/javiersantos/mlmanager/activities/AppActivity.java b/app/src/main/java/com/javiersantos/mlmanager/activities/AppActivity.java index dcb0cd9..434977a 100644 --- a/app/src/main/java/com/javiersantos/mlmanager/activities/AppActivity.java +++ b/app/src/main/java/com/javiersantos/mlmanager/activities/AppActivity.java @@ -6,6 +6,7 @@ import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; import android.net.Uri; +import android.os.AsyncTask; import android.os.Build; import android.os.Bundle; import android.support.v7.app.AppCompatActivity; @@ -18,10 +19,13 @@ import android.widget.ImageView; import android.widget.TextView; +import com.afollestad.materialdialogs.MaterialDialog; import com.getbase.floatingactionbutton.FloatingActionButton; import com.javiersantos.mlmanager.AppInfo; +import com.javiersantos.mlmanager.MLManagerApplication; import com.javiersantos.mlmanager.R; import com.javiersantos.mlmanager.utils.AppPreferences; +import com.javiersantos.mlmanager.utils.RootUtils; import com.javiersantos.mlmanager.utils.UtilsApp; import com.javiersantos.mlmanager.utils.UtilsDialog; import com.javiersantos.mlmanager.utils.UtilsUI; @@ -45,7 +49,7 @@ protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_app); this.context = this; - this.appPreferences = new AppPreferences(getApplicationContext()); + this.appPreferences = MLManagerApplication.getAppPreferences(); getInitialConfiguration(); setInitialConfiguration(); @@ -90,6 +94,7 @@ private void setScreenElements() { CardView extract = (CardView) findViewById(R.id.extract_card); CardView uninstall = (CardView) findViewById(R.id.uninstall_card); CardView cache = (CardView) findViewById(R.id.cache_card); + CardView clearData = (CardView) findViewById(R.id.clear_data_card); FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab); icon.setImageDrawable(appInfo.getIcon()); @@ -147,14 +152,32 @@ public void onClick(View view) { } }); - /*if (UtilsApp.existCacheFolder(appData)) { + if(RootUtils.isRooted()) { cache.setVisibility(View.VISIBLE); - TextView cache_description = (TextView) findViewById(R.id.cache_description); - cache_description.setText(String.format(getString(R.string.dialog_cache_description), UtilsApp.getCacheFolderSize(appData))); - } else { - cache.setVisibility(View.GONE); - }*/ - cache.setVisibility(View.GONE); + cache.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + MaterialDialog dialog = UtilsDialog.showTitleContentWithProgress(context + , getResources().getString(R.string.dialog_cache_deleting_title) + , getResources().getString(R.string.dialog_cache_deleting_description)); + new DeleteDataInBackground(dialog, appInfo.getData() + "/cache/**" + , getResources().getString(R.string.dialog_cache_success_title) + , getResources().getString(R.string.dialog_cache_success_description, appInfo.getName())).execute(); + } + }); + clearData.setVisibility(View.VISIBLE); + clearData.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + MaterialDialog dialog = UtilsDialog.showTitleContentWithProgress(context + , getResources().getString(R.string.dialog_clear_data_deleting_title) + , getResources().getString(R.string.dialog_clear_data_deleting_description)); + new DeleteDataInBackground(dialog, appInfo.getData() + "/**" + , getResources().getString(R.string.dialog_clear_data_success_title) + , getResources().getString(R.string.dialog_clear_data_success_description, appInfo.getName())).execute(); + } + }); + } // FAB fab.setIcon(R.drawable.ic_send_white); @@ -215,4 +238,34 @@ public boolean onOptionsItemSelected(MenuItem item) { return super.onOptionsItemSelected(item); } + class DeleteDataInBackground extends AsyncTask { + private MaterialDialog dialog; + private String directory; + private String successTitle; + private String successDescription; + + public DeleteDataInBackground(MaterialDialog dialog, String directory, String successTitle, String successDescription) { + this.dialog = dialog; + this.directory = directory; + this.successTitle = successTitle; + this.successDescription = successDescription; + } + + @Override + protected Boolean doInBackground(Void... voids) { + boolean status = RootUtils.removeWithRootPermission(directory); + return status; + } + + @Override + protected void onPostExecute(Boolean status) { + super.onPostExecute(status); + dialog.dismiss(); + if (status) { + UtilsDialog.showTitleContent(context, successTitle, successDescription); + } else { + UtilsDialog.showTitleContent(context, context.getResources().getString(R.string.dialog_cache_and_data_error_title), context.getResources().getString(R.string.dialog_cache_and_data_error_description)); + } + } + } } diff --git a/app/src/main/java/com/javiersantos/mlmanager/activities/MainActivity.java b/app/src/main/java/com/javiersantos/mlmanager/activities/MainActivity.java index 55b0829..04cd712 100644 --- a/app/src/main/java/com/javiersantos/mlmanager/activities/MainActivity.java +++ b/app/src/main/java/com/javiersantos/mlmanager/activities/MainActivity.java @@ -23,6 +23,7 @@ import android.widget.Toast; import com.javiersantos.mlmanager.AppInfo; +import com.javiersantos.mlmanager.MLManagerApplication; import com.javiersantos.mlmanager.R; import com.javiersantos.mlmanager.adapters.AppAdapter; import com.javiersantos.mlmanager.utils.AppPreferences; @@ -77,7 +78,7 @@ public class MainActivity extends AppCompatActivity implements SearchView.OnQuer protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); - this.appPreferences = new AppPreferences(getApplicationContext()); + this.appPreferences = MLManagerApplication.getAppPreferences(); this.context = this; setInitialConfiguration(); diff --git a/app/src/main/java/com/javiersantos/mlmanager/activities/SettingsActivity.java b/app/src/main/java/com/javiersantos/mlmanager/activities/SettingsActivity.java index 85ffa3b..d96c419 100644 --- a/app/src/main/java/com/javiersantos/mlmanager/activities/SettingsActivity.java +++ b/app/src/main/java/com/javiersantos/mlmanager/activities/SettingsActivity.java @@ -16,6 +16,7 @@ import android.view.WindowManager; import android.widget.LinearLayout; +import com.javiersantos.mlmanager.MLManagerApplication; import com.javiersantos.mlmanager.R; import com.javiersantos.mlmanager.utils.AppPreferences; import com.javiersantos.mlmanager.utils.UtilsApp; @@ -42,7 +43,7 @@ public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); addPreferencesFromResource(R.xml.settings); this.context = this; - this.appPreferences = new AppPreferences(getApplicationContext()); + this.appPreferences = MLManagerApplication.getAppPreferences(); prefs = PreferenceManager.getDefaultSharedPreferences(this); prefs.registerOnSharedPreferenceChangeListener(this); diff --git a/app/src/main/java/com/javiersantos/mlmanager/adapters/AppAdapter.java b/app/src/main/java/com/javiersantos/mlmanager/adapters/AppAdapter.java index 5875ea0..9a8d179 100644 --- a/app/src/main/java/com/javiersantos/mlmanager/adapters/AppAdapter.java +++ b/app/src/main/java/com/javiersantos/mlmanager/adapters/AppAdapter.java @@ -16,6 +16,7 @@ import android.widget.TextView; import com.gc.materialdesign.views.ButtonFlat; +import com.javiersantos.mlmanager.MLManagerApplication; import com.javiersantos.mlmanager.activities.AppActivity; import com.javiersantos.mlmanager.AppInfo; import com.javiersantos.mlmanager.R; @@ -40,7 +41,7 @@ public class AppAdapter extends RecyclerView.Adapter i public AppAdapter(List appList, Context context) { this.appList = appList; this.context = context; - this.appPreferences = new AppPreferences(context); + this.appPreferences = MLManagerApplication.getAppPreferences(); } @Override diff --git a/app/src/main/java/com/javiersantos/mlmanager/utils/AppPreferences.java b/app/src/main/java/com/javiersantos/mlmanager/utils/AppPreferences.java index 56a551a..16d0628 100644 --- a/app/src/main/java/com/javiersantos/mlmanager/utils/AppPreferences.java +++ b/app/src/main/java/com/javiersantos/mlmanager/utils/AppPreferences.java @@ -18,6 +18,8 @@ public class AppPreferences { public static final String KeyNavigationBlack = "prefNavigationBlack"; public static final String KeyCustomFilename = "prefCustomFilename"; public static final String KeySortMode = "prefSortMode"; + public static final String KeyIsRooted = "prefIsRooted"; + public static final String KeyIsRootedCheckDone = "prefIsRootedCheckDone"; public AppPreferences(Context context) { this.sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context); @@ -25,6 +27,15 @@ public AppPreferences(Context context) { this.context = context; } + public int getRootStatus() { + return sharedPreferences.getInt(KeyIsRooted, 0); + } + + public void setRootStatus(int rootStatus) { + editor.putInt(KeyStartDelete, rootStatus); + editor.commit(); + } + public Boolean getStartDeletePref() { return sharedPreferences.getBoolean(KeyStartDelete, false); } diff --git a/app/src/main/java/com/javiersantos/mlmanager/utils/RootUtils.java b/app/src/main/java/com/javiersantos/mlmanager/utils/RootUtils.java new file mode 100644 index 0000000..9199647 --- /dev/null +++ b/app/src/main/java/com/javiersantos/mlmanager/utils/RootUtils.java @@ -0,0 +1,81 @@ +package com.javiersantos.mlmanager.utils; + +import android.os.Build; + +import com.javiersantos.mlmanager.MLManagerApplication; + +import java.io.File; + +/** + * Created by vijay.rawat01 on 6/21/15. + */ +public class RootUtils { + + private static final int ROOT_STATUS_NOT_CHECKED = 0; + private static final int ROOT_STATUS_ROOTED = 1; + private static final int ROOT_STATUS_NOT_ROOTED = 2; + + private RootUtils() { + } + + public static boolean isRooted() { + int rootStatus = MLManagerApplication.getAppPreferences().getRootStatus(); + boolean isRooted = false; + if (rootStatus == ROOT_STATUS_NOT_CHECKED) { + isRooted = isRootByBuildTag() || isRootedByFileSU() || isRootedByExecutingCommand(); + MLManagerApplication.getAppPreferences().setRootStatus(isRooted ? ROOT_STATUS_ROOTED : ROOT_STATUS_NOT_ROOTED); + } else if (rootStatus == ROOT_STATUS_ROOTED) { + isRooted = true; + } + return isRooted; + } + + public static boolean isRootByBuildTag() { + String buildTags = Build.TAGS; + return ((buildTags != null && buildTags.contains("test-keys"))); + } + + public static boolean isRootedByFileSU() { + try { + File file = new File("/system/app/Superuser.apk"); + if (file.exists()) { + return true; + } + } catch (Exception e1) { + } + return false; + } + + public static boolean isRootedByExecutingCommand() { + return canExecuteCommand("/system/xbin/which su") + || canExecuteCommand("/system/bin/which su") + || canExecuteCommand("which su"); + } + + public static boolean removeWithRootPermission(String directory) { + boolean status = false; + try { + String[] command = new String[]{"su", "-c", "rm -rf " + directory}; + Process process = Runtime.getRuntime().exec(command); + process.waitFor(); + int i = process.exitValue(); + if (i == 0) { + status = true; + } + } catch (Exception e) { + } + return status; + } + + private static boolean canExecuteCommand(String command) { + boolean isExecuted; + try { + Runtime.getRuntime().exec(command); + isExecuted = true; + } catch (Exception e) { + isExecuted = false; + } + + return isExecuted; + } +} diff --git a/app/src/main/java/com/javiersantos/mlmanager/utils/UtilsApp.java b/app/src/main/java/com/javiersantos/mlmanager/utils/UtilsApp.java index b7f16be..ac4a892 100644 --- a/app/src/main/java/com/javiersantos/mlmanager/utils/UtilsApp.java +++ b/app/src/main/java/com/javiersantos/mlmanager/utils/UtilsApp.java @@ -6,6 +6,7 @@ import android.os.Environment; import com.javiersantos.mlmanager.AppInfo; +import com.javiersantos.mlmanager.MLManagerApplication; import org.apache.commons.io.FileUtils; @@ -21,7 +22,7 @@ public static File getAppFolder() { } public static File copyFile(Context context, AppInfo appInfo) { - appPreferences = new AppPreferences(context); + appPreferences = MLManagerApplication.getAppPreferences(); File initialFile = new File(appInfo.getSource()); File finalFile; diff --git a/app/src/main/java/com/javiersantos/mlmanager/utils/UtilsDialog.java b/app/src/main/java/com/javiersantos/mlmanager/utils/UtilsDialog.java index 35becb5..1cb073d 100644 --- a/app/src/main/java/com/javiersantos/mlmanager/utils/UtilsDialog.java +++ b/app/src/main/java/com/javiersantos/mlmanager/utils/UtilsDialog.java @@ -5,13 +5,14 @@ import com.afollestad.materialdialogs.MaterialDialog; import com.javiersantos.mlmanager.AppInfo; +import com.javiersantos.mlmanager.MLManagerApplication; import com.javiersantos.mlmanager.R; public class UtilsDialog { private static AppPreferences appPreferences; public static MaterialDialog.Builder showSavedDialog(Context context, AppInfo appInfo) { - appPreferences = new AppPreferences(context); + appPreferences = MLManagerApplication.getAppPreferences(); String filename; switch (appPreferences.getCustomFilename()) { @@ -70,4 +71,25 @@ public static MaterialDialog.Builder showIndeterminateProgressDialog(Context con return materialBuilder; } + public static MaterialDialog showTitleContent(Context context, String title, String content) { + MaterialDialog.Builder materialBuilder = new MaterialDialog.Builder(context) + .title(title) + .content(content).positiveText(context.getResources().getString(R.string.button_ok)).cancelable(true).callback(new MaterialDialog.ButtonCallback() { + @Override + public void onPositive(MaterialDialog dialog) { + dialog.dismiss(); + } + }); + return materialBuilder.show(); + } + + public static MaterialDialog showTitleContentWithProgress(Context context, String title, String content) { + MaterialDialog.Builder materialBuilder = new MaterialDialog.Builder(context) + .title(title) + .content(content) + .cancelable(false) + .progress(true, 0); + return materialBuilder.show(); + } + } diff --git a/app/src/main/java/com/javiersantos/mlmanager/utils/UtilsUI.java b/app/src/main/java/com/javiersantos/mlmanager/utils/UtilsUI.java index 6c1514a..bc1867b 100644 --- a/app/src/main/java/com/javiersantos/mlmanager/utils/UtilsUI.java +++ b/app/src/main/java/com/javiersantos/mlmanager/utils/UtilsUI.java @@ -9,6 +9,7 @@ import android.view.View; import android.widget.AdapterView; +import com.javiersantos.mlmanager.MLManagerApplication; import com.javiersantos.mlmanager.activities.AboutActivity; import com.javiersantos.mlmanager.R; import com.javiersantos.mlmanager.activities.SettingsActivity; @@ -40,7 +41,7 @@ public static int darker (int color, double factor) { public static Drawer setNavigationDrawer (Activity activity, final Context context, Toolbar toolbar, final AppAdapter appAdapter, final AppAdapter appSystemAdapter, final RecyclerView recyclerView) { int header; - appPreferences = new AppPreferences(context); + appPreferences = MLManagerApplication.getAppPreferences(); String apps, systemApps; if (getDayOrNight() == 1) { diff --git a/app/src/main/res/layout/activity_app.xml b/app/src/main/res/layout/activity_app.xml index 5d2d248..02a42b6 100644 --- a/app/src/main/res/layout/activity_app.xml +++ b/app/src/main/res/layout/activity_app.xml @@ -190,7 +190,8 @@ android:layout_height="85dp" card_view:cardCornerRadius="2dp" android:foreground="?android:attr/selectableItemBackground" - android:layout_margin="5dp"> + android:layout_margin="5dp" + android:visibility="gone"> + + + + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index c52bb58..3747005 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -31,7 +31,19 @@ Tap to uninstall Uninstall this app right now Tap to remove cache - Remove the cache for this app: %.2f MB + Remove the cache for this app + Cache deleted!! + Cache for %1$s is removed. + Deleting cache files!! + Please wait while cache files are being deleted. + Tap to clear data + Remove all application data for this app + Deleting all files!! + Please wait while all files are being deleted. + Data deleted!! + All data for %1$s is removed. + To delete data your phone must be rooted and root permission should be given. If you have denied access once. Go to SuperUser app to give access to MLManager. + Root required!! Cancel