Initial implementation of auto-mount, WIP
Will manually merge working product into /master
@ -1,11 +1,16 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest package="com.topjohnwu.magisk"
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools">
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
package="com.topjohnwu.magisk">
|
||||
|
||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
||||
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
|
||||
<uses-permission
|
||||
android:name="android.permission.PACKAGE_USAGE_STATS"
|
||||
tools:ignore="ProtectedPermissions" />
|
||||
|
||||
|
||||
<application
|
||||
android:allowBackup="true"
|
||||
@ -26,15 +31,25 @@
|
||||
<activity
|
||||
android:name=".AboutActivity"
|
||||
android:theme="@style/AppTheme.Transparent" />
|
||||
|
||||
<provider
|
||||
android:name="android.support.v4.content.FileProvider"
|
||||
android:authorities="com.topjohnwu.magisk.provider"
|
||||
android:grantUriPermissions="true"
|
||||
android:exported="false">
|
||||
android:exported="false"
|
||||
android:grantUriPermissions="true">
|
||||
<meta-data
|
||||
android:name="android.support.FILE_PROVIDER_PATHS"
|
||||
android:resource="@xml/file_paths" />
|
||||
</provider>
|
||||
<receiver android:name=".AutoStart">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.BOOT_COMPLETED" />
|
||||
</intent-filter>
|
||||
</receiver>
|
||||
|
||||
<service
|
||||
android:name=".MonitorService"
|
||||
android:exported="false" />
|
||||
</application>
|
||||
|
||||
</manifest>
|
154
app/src/main/java/com/topjohnwu/magisk/AutoRootFragment.java
Normal file
@ -0,0 +1,154 @@
|
||||
package com.topjohnwu.magisk;
|
||||
|
||||
import android.app.ProgressDialog;
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Bundle;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.v4.app.ListFragment;
|
||||
import android.util.Log;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ListView;
|
||||
|
||||
import com.topjohnwu.magisk.utils.ApplicationAdapter;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
public class AutoRootFragment extends ListFragment {
|
||||
private PackageManager packageManager = null;
|
||||
private List<ApplicationInfo> applist = null;
|
||||
private ApplicationAdapter listadaptor = null;
|
||||
public ListView listView;
|
||||
public SharedPreferences prefs;
|
||||
private View view;
|
||||
List<String> arrayList;
|
||||
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
||||
view = inflater.inflate(R.layout.auto_root_fragment, container, false);
|
||||
return view;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
|
||||
super.onActivityCreated(savedInstanceState);
|
||||
listView = getListView();
|
||||
packageManager = getActivity().getPackageManager();
|
||||
prefs = PreferenceManager.getDefaultSharedPreferences(getContext());
|
||||
if (!prefs.contains("autoapps")) {
|
||||
SharedPreferences.Editor editor = prefs.edit();
|
||||
Set<String> set = new HashSet<String>();
|
||||
set.add("com.google.android.apps.walletnfcrel");
|
||||
editor.putStringSet("autoapps", set);
|
||||
editor.commit();
|
||||
}
|
||||
new LoadApplications().execute();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
new LoadApplications().execute();
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void onListItemClick(ListView l, View v, int position, long id) {
|
||||
super.onListItemClick(l, v, position, id);
|
||||
ApplicationInfo app = applist.get(position);
|
||||
ToggleApp(app.packageName, position, v);
|
||||
|
||||
}
|
||||
|
||||
private void ToggleApp(String appToCheck, int position, View v) {
|
||||
|
||||
Set<String> set = prefs.getStringSet("autoapps", null);
|
||||
|
||||
arrayList = new ArrayList<>(set);
|
||||
Log.d("Magisk", "Trying to toggle for " + appToCheck + " stringset is " + arrayList.toString());
|
||||
SharedPreferences.Editor editor = prefs.edit();
|
||||
|
||||
if (arrayList.contains(appToCheck)) {
|
||||
Log.d("Magisk", "App is in array, removing");
|
||||
|
||||
for (int i = 0; i < arrayList.size(); i++) {
|
||||
if (appToCheck.equals(arrayList.get(i))) {
|
||||
arrayList.remove(i);
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
arrayList.add(appToCheck);
|
||||
|
||||
}
|
||||
Set<String> set2 = new HashSet<String>(arrayList);
|
||||
Log.d("Magisk", "Committing set, value is: " + set2);
|
||||
editor.putStringSet("autoapps", set2);
|
||||
editor.apply();
|
||||
listadaptor.UpdateRootStatusView(position,v);
|
||||
|
||||
|
||||
}
|
||||
|
||||
private List<ApplicationInfo> checkForLaunchIntent(List<ApplicationInfo> list) {
|
||||
ArrayList<ApplicationInfo> applist = new ArrayList<ApplicationInfo>();
|
||||
for (ApplicationInfo info : list) {
|
||||
try {
|
||||
if (null != packageManager.getLaunchIntentForPackage(info.packageName)) {
|
||||
applist.add(info);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
return applist;
|
||||
}
|
||||
|
||||
private class LoadApplications extends AsyncTask<Void, Void, Void> {
|
||||
private ProgressDialog progress = null;
|
||||
|
||||
@Override
|
||||
protected Void doInBackground(Void... params) {
|
||||
applist = checkForLaunchIntent(packageManager.getInstalledApplications(PackageManager.GET_META_DATA));
|
||||
listadaptor = new ApplicationAdapter(getActivity(),
|
||||
R.layout.app_list_row, applist);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onCancelled() {
|
||||
super.onCancelled();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(Void result) {
|
||||
setListAdapter(listadaptor);
|
||||
progress.dismiss();
|
||||
super.onPostExecute(result);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPreExecute() {
|
||||
progress = ProgressDialog.show(getActivity(), null,
|
||||
"Loading application info...");
|
||||
super.onPreExecute();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onProgressUpdate(Void... values) {
|
||||
super.onProgressUpdate(values);
|
||||
}
|
||||
}
|
||||
}
|
16
app/src/main/java/com/topjohnwu/magisk/AutoStart.java
Normal file
@ -0,0 +1,16 @@
|
||||
package com.topjohnwu.magisk;
|
||||
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.util.Log;
|
||||
|
||||
public class AutoStart extends BroadcastReceiver {
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
Log.d("Magisk", "Received Boot call, attempting to start service");
|
||||
Intent myIntent = new Intent(context, MonitorService.class);
|
||||
context.startService(myIntent);
|
||||
|
||||
}
|
||||
}
|
198
app/src/main/java/com/topjohnwu/magisk/MonitorService.java
Normal file
@ -0,0 +1,198 @@
|
||||
package com.topjohnwu.magisk;
|
||||
|
||||
import android.app.AppOpsManager;
|
||||
import android.app.Fragment;
|
||||
import android.app.NotificationManager;
|
||||
import android.app.PendingIntent;
|
||||
import android.app.Service;
|
||||
import android.app.usage.UsageStats;
|
||||
import android.app.usage.UsageStatsManager;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.os.Build;
|
||||
import android.os.CountDownTimer;
|
||||
import android.os.IBinder;
|
||||
import android.os.Process;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.v4.app.NotificationCompat;
|
||||
import android.util.Log;
|
||||
|
||||
import com.topjohnwu.magisk.utils.Shell;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.SortedMap;
|
||||
import java.util.TreeMap;
|
||||
|
||||
public class MonitorService extends Service
|
||||
|
||||
{
|
||||
|
||||
private static final String TAG = "Magisk";
|
||||
private UsageStatsManager mUsageStatsManager;
|
||||
private SharedPreferences prefs;
|
||||
private Boolean disableroot;
|
||||
private Boolean disablerootprev;
|
||||
public static boolean isRecursionEnable = false;
|
||||
private NotificationManager mNotifyMgr;
|
||||
private CountDownTimer timer = new CountDownTimer(1000, 1000) {
|
||||
|
||||
@Override
|
||||
public void onTick(long millisUntilFinished) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFinish() {
|
||||
CheckProcesses();
|
||||
|
||||
}
|
||||
}.start();
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public IBinder onBind(Intent intent) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int onStartCommand(Intent intent, int flags, int startId) {
|
||||
if (!intent.hasExtra("disable")) {
|
||||
|
||||
|
||||
new Thread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
// DO your work here
|
||||
// get the data
|
||||
timer.start();
|
||||
}
|
||||
}).start();
|
||||
|
||||
|
||||
return START_STICKY;
|
||||
} else return STOP_FOREGROUND_REMOVE;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
Log.d(TAG, "Destroyah!");
|
||||
android.os.Process.killProcess(android.os.Process.myPid());
|
||||
super.onDestroy();
|
||||
}
|
||||
|
||||
private boolean getStats(Set<String> seti) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
boolean inStats = false;
|
||||
UsageStatsManager lUsageStatsManager = (UsageStatsManager) getSystemService(Context.USAGE_STATS_SERVICE);
|
||||
if (seti != null) {
|
||||
ArrayList<String> statList = new ArrayList<>(seti);
|
||||
for (int i = 0; i < statList.size(); i++) {
|
||||
if (isAppForeground(statList.get(i))) {
|
||||
inStats = (isAppForeground(statList.get(i)));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return inStats;
|
||||
|
||||
}
|
||||
Log.d(TAG, "SDK check failed.");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
protected boolean isAppForeground(String packageName) {
|
||||
UsageStatsManager usageStatsManager = (UsageStatsManager) getSystemService(Context.USAGE_STATS_SERVICE);
|
||||
long time = System.currentTimeMillis();
|
||||
|
||||
List<UsageStats> stats = usageStatsManager.queryUsageStats(UsageStatsManager.INTERVAL_DAILY, time - 1000 * 10, time);
|
||||
|
||||
String topPackageName = new String();
|
||||
|
||||
if (stats != null) {
|
||||
SortedMap<Long, UsageStats> mySortedMap = new TreeMap<>();
|
||||
|
||||
for (UsageStats usageStats : stats) {
|
||||
mySortedMap.put(usageStats.getLastTimeUsed(), usageStats);
|
||||
}
|
||||
|
||||
if (mySortedMap != null && !mySortedMap.isEmpty()) {
|
||||
topPackageName = mySortedMap.get(mySortedMap.lastKey()).getPackageName();
|
||||
}
|
||||
}
|
||||
|
||||
return topPackageName.equals(packageName);
|
||||
}
|
||||
|
||||
private void CheckProcesses() {
|
||||
prefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
|
||||
if (prefs.getBoolean("autoRootEnable", false)) {
|
||||
|
||||
Set<String> set = prefs.getStringSet("autoapps", null);
|
||||
|
||||
ArrayList<String> arrayList = null;
|
||||
if (set != null) {
|
||||
disableroot = getStats(set);
|
||||
|
||||
}
|
||||
if (disableroot != disablerootprev) {
|
||||
String rootstatus = (disableroot ? "disabled" : "enabled");
|
||||
Shell.su((disableroot ? "setprop magisk.root 0" : "setprop magisk.root 1"));
|
||||
mNotifyMgr = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
|
||||
NotificationCompat.Builder mBuilder;
|
||||
mNotifyMgr.cancelAll();
|
||||
if (disableroot) {
|
||||
timer.cancel();
|
||||
this.stopSelf();
|
||||
Intent intent = new Intent(this, WelcomeActivity.class);
|
||||
intent.putExtra("relaunch", "relaunch");
|
||||
PendingIntent pendingIntent = PendingIntent.getActivity(
|
||||
this,
|
||||
0,
|
||||
intent,
|
||||
PendingIntent.FLAG_UPDATE_CURRENT);
|
||||
|
||||
mBuilder =
|
||||
new NotificationCompat.Builder(this)
|
||||
.setSmallIcon(disableroot ? R.drawable.ic_stat_notification_autoroot_off : R.drawable.ic_stat_notification_autoroot_on)
|
||||
.setContentIntent(pendingIntent)
|
||||
.setContentTitle("Auto-root status changed")
|
||||
.setContentText("Auto root has been " + rootstatus + "! Tap to re-enable when done.");
|
||||
|
||||
} else {
|
||||
mBuilder =
|
||||
new NotificationCompat.Builder(this)
|
||||
.setAutoCancel(true)
|
||||
.setSmallIcon(disableroot ? R.drawable.ic_stat_notification_autoroot_off : R.drawable.ic_stat_notification_autoroot_on)
|
||||
.setContentTitle("Auto-root status changed")
|
||||
.setContentText("Auto root has been " + rootstatus + "!");
|
||||
}
|
||||
// Builds the notification and issues it.
|
||||
int mNotificationId = 001;
|
||||
mNotifyMgr.notify(mNotificationId, mBuilder.build());
|
||||
|
||||
}
|
||||
disablerootprev = disableroot;
|
||||
|
||||
|
||||
Log.d(TAG, "Check Processes finished, result is " + disableroot + " and settings say we should be " + prefs.getBoolean("autoRootEnable", false));
|
||||
timer.start();
|
||||
}
|
||||
}
|
||||
|
||||
private boolean hasUsagePermission() {
|
||||
AppOpsManager appOps = (AppOpsManager)
|
||||
getSystemService(Context.APP_OPS_SERVICE);
|
||||
int mode = appOps.checkOpNoThrow(AppOpsManager.OPSTR_GET_USAGE_STATS,
|
||||
Process.myUid(), getPackageName());
|
||||
return mode == AppOpsManager.MODE_ALLOWED;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@ -1,8 +1,11 @@
|
||||
package com.topjohnwu.magisk;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.v4.app.Fragment;
|
||||
import android.view.LayoutInflater;
|
||||
@ -25,33 +28,51 @@ import butterknife.ButterKnife;
|
||||
|
||||
public class RootFragment extends Fragment {
|
||||
|
||||
@BindView(R.id.progressBar) ProgressBar progressBar;
|
||||
|
||||
@BindView(R.id.rootSwitchView) View rootToggleView;
|
||||
@BindView(R.id.selinuxSwitchView) View selinuxToggleView;
|
||||
@BindView(R.id.rootStatusView) View rootStatusView;
|
||||
@BindView(R.id.safetynetStatusView) View safetynetStatusView;
|
||||
@BindView(R.id.selinuxStatusView) View selinuxStatusView;
|
||||
|
||||
@BindView(R.id.root_toggle) Switch rootToggle;
|
||||
@BindView(R.id.selinux_toggle) Switch selinuxToggle;
|
||||
|
||||
@BindView(R.id.root_status_container) View rootStatusContainer;
|
||||
@BindView(R.id.root_status_icon) ImageView rootStatusIcon;
|
||||
@BindView(R.id.root_status) TextView rootStatus;
|
||||
|
||||
@BindView(R.id.selinux_status_container) View selinuxStatusContainer;
|
||||
@BindView(R.id.selinux_status_icon) ImageView selinuxStatusIcon;
|
||||
@BindView(R.id.selinux_status) TextView selinuxStatus;
|
||||
|
||||
@BindView(R.id.safety_net_status) TextView safetyNetStatus;
|
||||
@BindView(R.id.safety_net_icon) ImageView safetyNetStatusIcon;
|
||||
|
||||
@BindColor(R.color.red500) int red500;
|
||||
@BindColor(R.color.green500) int green500;
|
||||
@BindColor(R.color.grey500) int grey500;
|
||||
@BindColor(R.color.accent) int accent;
|
||||
|
||||
public SharedPreferences prefs;
|
||||
@BindView(R.id.progressBar)
|
||||
ProgressBar progressBar;
|
||||
@BindView(R.id.rootSwitchView)
|
||||
View rootToggleView;
|
||||
@BindView(R.id.autoRootSwitchView)
|
||||
View autoRootToggleView;
|
||||
@BindView(R.id.selinuxSwitchView)
|
||||
View selinuxToggleView;
|
||||
@BindView(R.id.rootStatusView)
|
||||
View rootStatusView;
|
||||
@BindView(R.id.safetynetStatusView)
|
||||
View safetynetStatusView;
|
||||
@BindView(R.id.selinuxStatusView)
|
||||
View selinuxStatusView;
|
||||
@BindView(R.id.root_toggle)
|
||||
Switch rootToggle;
|
||||
@BindView(R.id.auto_root_toggle)
|
||||
Switch autoRootToggle;
|
||||
@BindView(R.id.selinux_toggle)
|
||||
Switch selinuxToggle;
|
||||
@BindView(R.id.root_status_container)
|
||||
View rootStatusContainer;
|
||||
@BindView(R.id.root_status_icon)
|
||||
ImageView rootStatusIcon;
|
||||
@BindView(R.id.root_status)
|
||||
TextView rootStatus;
|
||||
@BindView(R.id.selinux_status_container)
|
||||
View selinuxStatusContainer;
|
||||
@BindView(R.id.selinux_status_icon)
|
||||
ImageView selinuxStatusIcon;
|
||||
@BindView(R.id.selinux_status)
|
||||
TextView selinuxStatus;
|
||||
@BindView(R.id.safety_net_status)
|
||||
TextView safetyNetStatus;
|
||||
@BindView(R.id.safety_net_icon)
|
||||
ImageView safetyNetStatusIcon;
|
||||
@BindColor(R.color.red500)
|
||||
int red500;
|
||||
@BindColor(R.color.green500)
|
||||
int green500;
|
||||
@BindColor(R.color.grey500)
|
||||
int grey500;
|
||||
@BindColor(R.color.accent)
|
||||
int accent;
|
||||
int statusOK = R.drawable.ic_check_circle;
|
||||
int statusError = R.drawable.ic_error;
|
||||
int statusUnknown = R.drawable.ic_help;
|
||||
@ -63,10 +84,25 @@ public class RootFragment extends Fragment {
|
||||
ButterKnife.bind(this, view);
|
||||
|
||||
new updateUI().execute();
|
||||
prefs = PreferenceManager.getDefaultSharedPreferences(getContext());
|
||||
|
||||
rootToggle.setOnClickListener(toggle -> {
|
||||
Shell.su(((CompoundButton) toggle).isChecked() ? "setprop magisk.root 1" : "setprop magisk.root 0");
|
||||
new Handler().postDelayed(() -> new updateUI().execute(), 1000);
|
||||
if (!((CompoundButton) toggle).isChecked()) {
|
||||
autoRootToggle.setChecked(false);
|
||||
}
|
||||
});
|
||||
|
||||
autoRootToggle.setOnClickListener(toggle -> {
|
||||
SharedPreferences.Editor editor = prefs.edit();
|
||||
editor.putBoolean("autoRootEnable", ((CompoundButton) toggle).isChecked());
|
||||
editor.commit();
|
||||
if (((CompoundButton) toggle).isChecked()) {
|
||||
Intent myIntent = new Intent(getActivity(), MonitorService.class);
|
||||
getActivity().startService(myIntent);
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
selinuxToggle.setOnClickListener(toggle -> {
|
||||
@ -77,7 +113,13 @@ public class RootFragment extends Fragment {
|
||||
return view;
|
||||
}
|
||||
|
||||
private class updateUI extends AsyncTask<Void, Void, Void> {
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
new updateUI().execute();
|
||||
}
|
||||
|
||||
public class updateUI extends AsyncTask<Void, Void, Void> {
|
||||
|
||||
@Override
|
||||
protected Void doInBackground(Void... voids) {
|
||||
@ -98,6 +140,7 @@ public class RootFragment extends Fragment {
|
||||
|
||||
if (Shell.rootAccess()) {
|
||||
rootToggleView.setVisibility(View.VISIBLE);
|
||||
autoRootToggleView.setVisibility(View.VISIBLE);
|
||||
selinuxToggleView.setVisibility(View.VISIBLE);
|
||||
}
|
||||
|
||||
@ -183,7 +226,7 @@ public class RootFragment extends Fragment {
|
||||
rootToggle.setChecked(true);
|
||||
safetyNetStatusIcon.setImageResource(statusError);
|
||||
safetyNetStatus.setText(R.string.root_system_info);
|
||||
|
||||
autoRootToggleView.setVisibility(View.GONE);
|
||||
rootToggleView.setVisibility(View.GONE);
|
||||
selinuxToggleView.setVisibility(View.GONE);
|
||||
break;
|
||||
|
@ -1,11 +1,16 @@
|
||||
package com.topjohnwu.magisk;
|
||||
|
||||
import android.Manifest;
|
||||
import android.app.ActivityManager;
|
||||
import android.app.AppOpsManager;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.provider.Settings;
|
||||
import android.support.annotation.IdRes;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.design.widget.NavigationView;
|
||||
@ -31,9 +36,12 @@ public class WelcomeActivity extends AppCompatActivity implements NavigationView
|
||||
|
||||
private final Handler mDrawerHandler = new Handler();
|
||||
|
||||
@BindView(R.id.toolbar) Toolbar toolbar;
|
||||
@BindView(R.id.drawer_layout) DrawerLayout drawer;
|
||||
@BindView(R.id.nav_view) NavigationView navigationView;
|
||||
@BindView(R.id.toolbar)
|
||||
Toolbar toolbar;
|
||||
@BindView(R.id.drawer_layout)
|
||||
DrawerLayout drawer;
|
||||
@BindView(R.id.nav_view)
|
||||
NavigationView navigationView;
|
||||
|
||||
@IdRes
|
||||
private int mSelectedId = R.id.magisk;
|
||||
@ -43,16 +51,25 @@ public class WelcomeActivity extends AppCompatActivity implements NavigationView
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.activity_welcome);
|
||||
ButterKnife.bind(this);
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);
|
||||
}
|
||||
|
||||
|
||||
// Startups
|
||||
PreferenceManager.setDefaultValues(this, R.xml.defaultpref, false);
|
||||
if (!isMyServiceRunning(MonitorService.class)) {
|
||||
Intent myIntent = new Intent(getApplication(), MonitorService.class);
|
||||
getApplication().startService(myIntent);
|
||||
}
|
||||
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED
|
||||
&& Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
requestPermissions(new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, 0);
|
||||
}
|
||||
if (!hasPermission()) {
|
||||
startActivityForResult(new Intent(Settings.ACTION_USAGE_ACCESS_SETTINGS), 100);
|
||||
}
|
||||
|
||||
new Utils.Initialize(this).execute();
|
||||
new Utils.CheckUpdates(this).execute();
|
||||
new Utils.LoadModules(this).execute();
|
||||
@ -85,6 +102,9 @@ public class WelcomeActivity extends AppCompatActivity implements NavigationView
|
||||
}
|
||||
|
||||
navigationView.setNavigationItemSelectedListener(this);
|
||||
if (getIntent().hasExtra("relaunch")) {
|
||||
navigate(R.id.root);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -114,6 +134,25 @@ public class WelcomeActivity extends AppCompatActivity implements NavigationView
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean hasPermission() {
|
||||
AppOpsManager appOps = (AppOpsManager)
|
||||
getSystemService(Context.APP_OPS_SERVICE);
|
||||
int mode = appOps.checkOpNoThrow(AppOpsManager.OPSTR_GET_USAGE_STATS,
|
||||
android.os.Process.myUid(), getPackageName());
|
||||
return mode == AppOpsManager.MODE_ALLOWED;
|
||||
|
||||
}
|
||||
|
||||
private boolean isMyServiceRunning(Class<?> serviceClass) {
|
||||
ActivityManager manager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
|
||||
for (ActivityManager.RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) {
|
||||
if (serviceClass.getName().equals(service.service.getClassName())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private void navigate(final int itemId) {
|
||||
Fragment navFragment = null;
|
||||
String tag = "";
|
||||
@ -128,6 +167,11 @@ public class WelcomeActivity extends AppCompatActivity implements NavigationView
|
||||
tag = "root";
|
||||
navFragment = new RootFragment();
|
||||
break;
|
||||
case R.id.autoroot:
|
||||
setTitle(R.string.auto_root);
|
||||
tag = "ic_autoroot";
|
||||
navFragment = new AutoRootFragment();
|
||||
break;
|
||||
case R.id.modules:
|
||||
setTitle(R.string.modules);
|
||||
tag = "modules";
|
||||
@ -154,4 +198,6 @@ public class WelcomeActivity extends AppCompatActivity implements NavigationView
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,107 @@
|
||||
package com.topjohnwu.magisk.utils;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ArrayAdapter;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.topjohnwu.magisk.R;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
public class ApplicationAdapter extends ArrayAdapter<ApplicationInfo> {
|
||||
private List<ApplicationInfo> appsList = null;
|
||||
private Context context;
|
||||
private PackageManager packageManager;
|
||||
public ArrayList arrayList;
|
||||
public SharedPreferences prefs;
|
||||
|
||||
public ApplicationAdapter(Context context, int textViewResourceId,
|
||||
List<ApplicationInfo> appsList) {
|
||||
super(context, textViewResourceId, appsList);
|
||||
this.context = context;
|
||||
this.appsList = appsList;
|
||||
packageManager = context.getPackageManager();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCount() {
|
||||
return ((null != appsList) ? appsList.size() : 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ApplicationInfo getItem(int position) {
|
||||
return ((null != appsList) ? appsList.get(position) : null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getItemId(int position) {
|
||||
return position;
|
||||
}
|
||||
|
||||
@Override
|
||||
public View getView(int position, View convertView, ViewGroup parent) {
|
||||
View view = convertView;
|
||||
|
||||
prefs = PreferenceManager.getDefaultSharedPreferences(getContext());
|
||||
if (null == view) {
|
||||
LayoutInflater layoutInflater = (LayoutInflater) context
|
||||
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
|
||||
view = layoutInflater.inflate(R.layout.app_list_row, null);
|
||||
}
|
||||
|
||||
ApplicationInfo applicationInfo = appsList.get(position);
|
||||
if (null != applicationInfo) {
|
||||
TextView appName = (TextView) view.findViewById(R.id.app_name);
|
||||
TextView packageName = (TextView) view.findViewById(R.id.app_paackage);
|
||||
ImageView iconview = (ImageView) view.findViewById(R.id.app_icon);
|
||||
ImageView statusview = (ImageView) view.findViewById(R.id.app_status);
|
||||
appName.setText(applicationInfo.loadLabel(packageManager));
|
||||
packageName.setText(applicationInfo.packageName);
|
||||
iconview.setImageDrawable(applicationInfo.loadIcon(packageManager));
|
||||
if (CheckApp(applicationInfo.packageName)) {
|
||||
statusview.setImageDrawable(this.context.getDrawable(R.drawable.root));
|
||||
} else {
|
||||
statusview.setImageDrawable(null);
|
||||
}
|
||||
}
|
||||
return view;
|
||||
}
|
||||
|
||||
public void UpdateRootStatusView(int position, View convertView) {
|
||||
View view = convertView;
|
||||
if (null == view) {
|
||||
LayoutInflater layoutInflater = (LayoutInflater) context
|
||||
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
|
||||
view = layoutInflater.inflate(R.layout.app_list_row, null);
|
||||
}
|
||||
ApplicationInfo applicationInfo = appsList.get(position);
|
||||
if (null != applicationInfo) {
|
||||
ImageView statusview = (ImageView) view.findViewById(R.id.app_status);
|
||||
if (CheckApp(applicationInfo.packageName)) {
|
||||
statusview.setImageDrawable(this.context.getDrawable(R.drawable.root));
|
||||
} else {
|
||||
statusview.setImageDrawable(null);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private boolean CheckApp(String appToCheck) {
|
||||
Set<String> set = prefs.getStringSet("autoapps", null);
|
||||
arrayList = new ArrayList<>(set);
|
||||
return arrayList.toString().contains(appToCheck);
|
||||
|
||||
}
|
||||
|
||||
|
||||
};
|
After Width: | Height: | Size: 1.0 KiB |
After Width: | Height: | Size: 1.0 KiB |
After Width: | Height: | Size: 1.2 KiB |
After Width: | Height: | Size: 1.0 KiB |
After Width: | Height: | Size: 720 B |
After Width: | Height: | Size: 749 B |
After Width: | Height: | Size: 749 B |
After Width: | Height: | Size: 723 B |
After Width: | Height: | Size: 1.6 KiB |
After Width: | Height: | Size: 1.6 KiB |
After Width: | Height: | Size: 1.4 KiB |
After Width: | Height: | Size: 1.5 KiB |
After Width: | Height: | Size: 2.7 KiB |
After Width: | Height: | Size: 2.9 KiB |
After Width: | Height: | Size: 2.5 KiB |
After Width: | Height: | Size: 2.6 KiB |
After Width: | Height: | Size: 4.3 KiB |
After Width: | Height: | Size: 4.4 KiB |
After Width: | Height: | Size: 3.8 KiB |
After Width: | Height: | Size: 4.0 KiB |
4
app/src/main/res/drawable/ic_autoroot.xml
Normal file
@ -0,0 +1,4 @@
|
||||
<vector android:height="24dp" android:viewportHeight="400.0"
|
||||
android:viewportWidth="400.0" android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<path android:fillAlpha="1.00" android:fillColor="#000000" android:pathData="M200.6,24.2C231.8,24.2 263,33 289.6,49.5C304.7,58.8 318.2,70.7 329.8,84.1C351.5,109.6 365.2,141.7 368.8,175C373.6,217.4 361.5,261.5 335.5,295.5C334.2,297.1 332.8,298.7 331.9,300.7C341.7,310.1 351,320 360.9,329.3C322.7,339.3 284.5,349.6 246.3,359.9C256.4,323.5 266,287 275.7,250.5C262.4,250.5 249.1,250.5 235.8,250.5C228.5,269.8 221.2,289.1 214.1,308.4C205.9,308.6 197.8,308.5 189.6,308.5C188.4,306.7 187.1,304.9 185.9,303C192.4,285.5 199.1,268 205.6,250.5C189.5,250.6 173.4,250.3 157.4,250.6C150.4,270 142.9,289.2 135.8,308.5C129.8,308.5 123.9,308.4 117.9,308.6C130.4,317.8 144,325.6 158.9,330.3C171.9,334.6 185.6,336.6 199.4,336.7C199.4,349.4 199.3,362.1 199.4,374.8C165.8,374.9 132.2,364.5 104.4,345.6C91.7,337 80.3,326.5 70.2,314.9C48.5,289.4 34.8,257.3 31.2,224C26.3,180.4 39.2,134.9 66.8,100.7C67.2,99.9 67.7,99.2 68.1,98.4C58.3,88.9 49,79 39.1,69.7C77.3,59.7 115.6,49.4 153.7,39.1C143.6,75.7 133.8,112.5 124.1,149.3C137.9,149.3 151.7,149.2 165.5,149.3C172.9,130 180.2,110.6 187.3,91.2C195.5,90.8 203.7,91 211.8,91C213,92.8 214.3,94.6 215.5,96.3C209.1,114 202.3,131.6 195.8,149.2C211.8,149.3 227.8,149.2 243.9,149.3C251.2,129.9 258.3,110.3 265.8,90.9C271.5,90.8 277.3,91.6 282.9,90.4C280.2,89.5 278.1,87.7 275.9,86.1C254,70.7 227.4,62.2 200.6,62.3C200.6,49.6 200.7,36.9 200.6,24.2M292.5,100C286.4,116.4 280.2,132.8 274,149.3C280.9,149.2 287.8,149.3 294.7,149.2C296,150.8 297.3,152.4 298.6,153.9C297.1,162.1 295.7,170.3 294.3,178.5C283.9,178.5 273.4,178.5 262.9,178.5C257.5,192.7 252.1,206.9 246.9,221.2C258.7,221.3 270.5,221.1 282.3,221.3C283.5,222.9 284.8,224.4 286.1,225.9C284.9,233.7 283.4,241.4 282.1,249.1C281.6,251 283.6,252.1 284.6,253.3C291.5,259.8 297.7,266.9 304.8,273.1C312.9,262.1 319.6,250.1 324.2,237.3C334.3,208.7 334.2,176.7 323.7,148.3C317,130.1 306.4,113.4 292.5,100M95.2,125.9C86.2,138 79,151.4 74.5,165.8C65.3,194.4 66.4,226.3 77.6,254.2C84.6,271.5 95.1,287.4 108.7,300.1C114.9,283.6 121.3,267.1 127.2,250.5C121.5,250.5 115.8,250.5 110,250.5C108.6,250.4 106.7,251 105.8,249.5C104.5,247.9 102.3,246.3 102.9,244.1C104.2,236.5 105.5,228.9 106.8,221.2C117.4,221.2 128.1,221.4 138.7,221.1C143.9,206.9 149.3,192.7 154.6,178.5C142.9,178.4 131.1,178.6 119.3,178.4C117.6,177.3 116.4,175.3 115,173.8C116.3,165.8 117.9,157.9 119,150C118.3,148.2 116.6,147.1 115.3,145.7C108.6,139.2 102.3,132.1 95.2,125.9M168.8,221.2C184.8,221.2 200.8,221.3 216.8,221.2C222.2,207 227.5,192.8 232.8,178.5C216.8,178.5 200.7,178.5 184.6,178.5C179.4,192.8 174,207 168.8,221.2Z"/>
|
||||
</vector>
|
56
app/src/main/res/layout/app_list_row.xml
Normal file
@ -0,0 +1,56 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content" >
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/app_icon"
|
||||
android:layout_width="50dp"
|
||||
android:layout_height="50dp"
|
||||
android:padding="3dp"
|
||||
android:scaleType="centerCrop" />
|
||||
<RelativeLayout
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/lynn"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent"
|
||||
android:gravity="center_vertical"
|
||||
android:orientation="vertical"
|
||||
android:paddingLeft="5dp"
|
||||
android:paddingRight="50dp">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/app_name"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center_vertical"
|
||||
android:textStyle="bold" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/app_paackage"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center_vertical" />
|
||||
|
||||
<RelativeLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"></RelativeLayout>
|
||||
|
||||
|
||||
</LinearLayout>
|
||||
<ImageView
|
||||
android:id="@+id/app_status"
|
||||
android:layout_width="50dp"
|
||||
android:layout_height="50dp"
|
||||
android:padding="3dp"
|
||||
android:scaleType="centerCrop"
|
||||
android:layout_gravity="right"
|
||||
android:layout_alignParentEnd="true" />
|
||||
|
||||
</RelativeLayout>
|
||||
|
||||
</LinearLayout>
|
10
app/src/main/res/layout/auto_root_fragment.xml
Normal file
@ -0,0 +1,10 @@
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent"
|
||||
android:orientation="vertical" >
|
||||
|
||||
<ListView android:id="@android:id/list"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent"/>
|
||||
|
||||
</LinearLayout>
|
@ -30,4 +30,14 @@
|
||||
android:layout_height="0dp"
|
||||
android:layout_weight="1"/>
|
||||
|
||||
<android.support.design.widget.FloatingActionButton
|
||||
android:id="@+id/fab"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="right"
|
||||
android:layout_margin="16dp"
|
||||
android:clickable="true"
|
||||
android:src="@drawable/ic_add"
|
||||
/>
|
||||
|
||||
</LinearLayout>
|
@ -34,6 +34,24 @@
|
||||
android:text="@string/root_toggle"
|
||||
android:textSize="16sp"/>
|
||||
|
||||
</android.support.v7.widget.CardView>
|
||||
<android.support.v7.widget.CardView
|
||||
android:id="@+id/autoRootSwitchView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:elevation="2dp"
|
||||
android:visibility="gone"
|
||||
app:cardCornerRadius="0dp">
|
||||
|
||||
<Switch
|
||||
android:id="@+id/auto_root_toggle"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="12dp"
|
||||
android:checked="true"
|
||||
android:text="@string/auto_root"
|
||||
android:textSize="16sp"/>
|
||||
|
||||
</android.support.v7.widget.CardView>
|
||||
|
||||
<android.support.v7.widget.CardView
|
||||
|
@ -15,6 +15,11 @@
|
||||
android:icon="@drawable/root"
|
||||
android:title="@string/root"/>
|
||||
|
||||
<item
|
||||
android:id="@+id/autoroot"
|
||||
android:icon="@drawable/ic_autoroot"
|
||||
android:title="@string/auto_root"/>
|
||||
|
||||
<item
|
||||
android:id="@+id/modules"
|
||||
android:icon="@drawable/ic_extension"
|
||||
|
@ -21,6 +21,7 @@
|
||||
|
||||
<!--Root Fragment-->
|
||||
<string name="root_toggle">Root Toggle</string>
|
||||
<string name="auto_root">Auto Root</string>
|
||||
<string name="selinux_toggle">SELinux Toggle</string>
|
||||
|
||||
<string name="root_error">Root Error</string>
|
||||
|
7
app/src/main/res/xml/defaultpref.xml
Normal file
@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<Preference
|
||||
android:key="autoapps"
|
||||
android:defaultValue="com.google.android.apps.walletnfcrel"
|
||||
/>
|
||||
</PreferenceScreen>
|