Add Superuser management UI
This commit is contained in:
parent
3681177be4
commit
67c9e2ead6
@ -59,7 +59,7 @@ dependencies {
|
|||||||
compile 'com.madgag.spongycastle:prov:1.54.0.0'
|
compile 'com.madgag.spongycastle:prov:1.54.0.0'
|
||||||
compile 'com.madgag.spongycastle:pkix:1.54.0.0'
|
compile 'com.madgag.spongycastle:pkix:1.54.0.0'
|
||||||
compile 'com.madgag.spongycastle:pg:1.54.0.0'
|
compile 'com.madgag.spongycastle:pg:1.54.0.0'
|
||||||
compile 'com.google.android.gms:play-services-safetynet:10.0.1'
|
compile 'com.google.android.gms:play-services-safetynet:9.0.1'
|
||||||
compile 'com.android.support:support-v4:25.1.0'
|
compile 'com.android.support:support-v4:25.1.0'
|
||||||
annotationProcessor 'com.jakewharton:butterknife-compiler:8.4.0'
|
annotationProcessor 'com.jakewharton:butterknife-compiler:8.4.0'
|
||||||
}
|
}
|
||||||
|
@ -165,6 +165,9 @@ public class MainActivity extends AppCompatActivity
|
|||||||
case R.id.install:
|
case R.id.install:
|
||||||
displayFragment(new InstallFragment(), "install", now);
|
displayFragment(new InstallFragment(), "install", now);
|
||||||
break;
|
break;
|
||||||
|
case R.id.superuser:
|
||||||
|
displayFragment(new SuperuserFragment(), "superuser", now);
|
||||||
|
break;
|
||||||
case R.id.modules:
|
case R.id.modules:
|
||||||
displayFragment(new ModulesFragment(), "modules", now);
|
displayFragment(new ModulesFragment(), "modules", now);
|
||||||
break;
|
break;
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
package com.topjohnwu.magisk;
|
package com.topjohnwu.magisk;
|
||||||
|
|
||||||
import android.content.Context;
|
|
||||||
import android.content.SharedPreferences;
|
import android.content.SharedPreferences;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.preference.CheckBoxPreference;
|
import android.preference.CheckBoxPreference;
|
||||||
|
@ -0,0 +1,67 @@
|
|||||||
|
package com.topjohnwu.magisk;
|
||||||
|
|
||||||
|
|
||||||
|
import android.app.Fragment;
|
||||||
|
import android.content.pm.PackageManager;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.support.annotation.Nullable;
|
||||||
|
import android.support.v7.widget.RecyclerView;
|
||||||
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
import android.widget.TextView;
|
||||||
|
|
||||||
|
import com.topjohnwu.magisk.adapters.PolicyAdapter;
|
||||||
|
import com.topjohnwu.magisk.superuser.Policy;
|
||||||
|
import com.topjohnwu.magisk.superuser.SuDatabaseHelper;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import butterknife.BindView;
|
||||||
|
import butterknife.ButterKnife;
|
||||||
|
import butterknife.Unbinder;
|
||||||
|
|
||||||
|
public class SuperuserFragment extends Fragment {
|
||||||
|
|
||||||
|
private Unbinder unbinder;
|
||||||
|
@BindView(R.id.recyclerView) RecyclerView recyclerView;
|
||||||
|
@BindView(R.id.empty_rv) TextView emptyTv;
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
@Override
|
||||||
|
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
|
||||||
|
View view = inflater.inflate(R.layout.fragment_superuser, container, false);
|
||||||
|
unbinder = ButterKnife.bind(this, view);
|
||||||
|
|
||||||
|
PackageManager pm = getActivity().getPackageManager();
|
||||||
|
|
||||||
|
SuDatabaseHelper dbHelper = new SuDatabaseHelper(getActivity());
|
||||||
|
List<Policy> policyList = dbHelper.getPolicyList(pm);
|
||||||
|
|
||||||
|
PolicyAdapter adapter = new PolicyAdapter(policyList, dbHelper, pm);
|
||||||
|
|
||||||
|
if (policyList.size() == 0) {
|
||||||
|
emptyTv.setVisibility(View.VISIBLE);
|
||||||
|
recyclerView.setVisibility(View.GONE);
|
||||||
|
} else {
|
||||||
|
recyclerView.setAdapter(adapter);
|
||||||
|
emptyTv.setVisibility(View.GONE);
|
||||||
|
recyclerView.setVisibility(View.VISIBLE);
|
||||||
|
}
|
||||||
|
|
||||||
|
return view;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onStart() {
|
||||||
|
super.onStart();
|
||||||
|
getActivity().setTitle(getString(R.string.superuser));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onDestroyView() {
|
||||||
|
super.onDestroyView();
|
||||||
|
unbinder.unbind();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,200 @@
|
|||||||
|
package com.topjohnwu.magisk.adapters;
|
||||||
|
|
||||||
|
import android.animation.Animator;
|
||||||
|
import android.animation.ValueAnimator;
|
||||||
|
import android.content.pm.PackageManager;
|
||||||
|
import android.support.v7.widget.RecyclerView;
|
||||||
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
import android.view.ViewTreeObserver;
|
||||||
|
import android.widget.ImageView;
|
||||||
|
import android.widget.LinearLayout;
|
||||||
|
import android.widget.Switch;
|
||||||
|
import android.widget.TextView;
|
||||||
|
|
||||||
|
import com.topjohnwu.magisk.R;
|
||||||
|
import com.topjohnwu.magisk.superuser.Policy;
|
||||||
|
import com.topjohnwu.magisk.superuser.SuDatabaseHelper;
|
||||||
|
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import butterknife.BindView;
|
||||||
|
import butterknife.ButterKnife;
|
||||||
|
|
||||||
|
public class PolicyAdapter extends RecyclerView.Adapter<PolicyAdapter.ViewHolder> {
|
||||||
|
|
||||||
|
private List<Policy> policyList;
|
||||||
|
private SuDatabaseHelper dbHelper;
|
||||||
|
private PackageManager pm;
|
||||||
|
private HashSet<Policy> expandList = new HashSet<>();
|
||||||
|
|
||||||
|
public PolicyAdapter(List<Policy> list, SuDatabaseHelper db, PackageManager pm) {
|
||||||
|
policyList = list;
|
||||||
|
dbHelper = db;
|
||||||
|
this.pm = pm;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
|
||||||
|
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_item_policy, parent, false);
|
||||||
|
return new ViewHolder(v);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onBindViewHolder(ViewHolder holder, int position) {
|
||||||
|
try {
|
||||||
|
Policy policy = policyList.get(position);
|
||||||
|
|
||||||
|
holder.setExpanded(expandList.contains(policy));
|
||||||
|
|
||||||
|
holder.itemView.setOnClickListener(view -> {
|
||||||
|
if (holder.mExpanded) {
|
||||||
|
holder.collapse();
|
||||||
|
expandList.remove(policy);
|
||||||
|
} else {
|
||||||
|
holder.expand();
|
||||||
|
expandList.add(policy);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
holder.appName.setText(policy.appName);
|
||||||
|
holder.packageName.setText(policy.packageName);
|
||||||
|
holder.appIcon.setImageDrawable(pm.getPackageInfo(policy.packageName, 0).applicationInfo.loadIcon(pm));
|
||||||
|
holder.masterSwitch.setOnCheckedChangeListener((v, isChecked) -> {
|
||||||
|
if (isChecked && policy.policy == Policy.DENY) {
|
||||||
|
policy.policy = Policy.ALLOW;
|
||||||
|
dbHelper.addPolicy(policy);
|
||||||
|
} else if (!isChecked && policy.policy == Policy.ALLOW) {
|
||||||
|
policy.policy = Policy.DENY;
|
||||||
|
dbHelper.addPolicy(policy);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
holder.notificationSwitch.setOnCheckedChangeListener((v, isChecked) -> {
|
||||||
|
if (isChecked && !policy.notification) {
|
||||||
|
policy.notification = true;
|
||||||
|
dbHelper.addPolicy(policy);
|
||||||
|
} else if (!isChecked && policy.notification) {
|
||||||
|
policy.notification = false;
|
||||||
|
dbHelper.addPolicy(policy);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
holder.loggingSwitch.setOnCheckedChangeListener((v, isChecked) -> {
|
||||||
|
if (isChecked && !policy.logging) {
|
||||||
|
policy.logging = true;
|
||||||
|
dbHelper.addPolicy(policy);
|
||||||
|
} else if (!isChecked && policy.logging) {
|
||||||
|
policy.logging = false;
|
||||||
|
dbHelper.addPolicy(policy);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
holder.masterSwitch.setChecked(policy.policy == Policy.ALLOW);
|
||||||
|
holder.notificationSwitch.setChecked(policy.notification);
|
||||||
|
holder.loggingSwitch.setChecked(policy.logging);
|
||||||
|
|
||||||
|
} catch (PackageManager.NameNotFoundException e) {
|
||||||
|
policyList.remove(position);
|
||||||
|
notifyItemRemoved(position);
|
||||||
|
notifyItemRangeChanged(position, policyList.size());
|
||||||
|
onBindViewHolder(holder, position);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getItemCount() {
|
||||||
|
return policyList.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
static class ViewHolder extends RecyclerView.ViewHolder {
|
||||||
|
|
||||||
|
@BindView(R.id.app_name) TextView appName;
|
||||||
|
@BindView(R.id.package_name) TextView packageName;
|
||||||
|
@BindView(R.id.expand_layout) LinearLayout expandLayout;
|
||||||
|
@BindView(R.id.app_icon) ImageView appIcon;
|
||||||
|
@BindView(R.id.master_switch) Switch masterSwitch;
|
||||||
|
@BindView(R.id.notification_switch) Switch notificationSwitch;
|
||||||
|
@BindView(R.id.logging_switch) Switch loggingSwitch;
|
||||||
|
|
||||||
|
@BindView(R.id.more_info) ImageView moreInfo;
|
||||||
|
|
||||||
|
private ValueAnimator mAnimator;
|
||||||
|
private boolean mExpanded = false;
|
||||||
|
private static int expandHeight = 0;
|
||||||
|
|
||||||
|
ViewHolder(View itemView) {
|
||||||
|
super(itemView);
|
||||||
|
ButterKnife.bind(this, itemView);
|
||||||
|
expandLayout.getViewTreeObserver().addOnPreDrawListener(
|
||||||
|
new ViewTreeObserver.OnPreDrawListener() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onPreDraw() {
|
||||||
|
if (expandHeight == 0) {
|
||||||
|
final int widthSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
|
||||||
|
final int heightSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
|
||||||
|
expandLayout.measure(widthSpec, heightSpec);
|
||||||
|
expandHeight = expandLayout.getMeasuredHeight();
|
||||||
|
}
|
||||||
|
|
||||||
|
expandLayout.getViewTreeObserver().removeOnPreDrawListener(this);
|
||||||
|
expandLayout.setVisibility(View.GONE);
|
||||||
|
mAnimator = slideAnimator(0, expandHeight);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setExpanded(boolean expanded) {
|
||||||
|
mExpanded = expanded;
|
||||||
|
ViewGroup.LayoutParams layoutParams = expandLayout.getLayoutParams();
|
||||||
|
layoutParams.height = expanded ? expandHeight : 0;
|
||||||
|
expandLayout.setLayoutParams(layoutParams);
|
||||||
|
expandLayout.setVisibility(expanded ? View.VISIBLE : View.GONE);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void expand() {
|
||||||
|
expandLayout.setVisibility(View.VISIBLE);
|
||||||
|
mAnimator.start();
|
||||||
|
mExpanded = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void collapse() {
|
||||||
|
if (!mExpanded) return;
|
||||||
|
int finalHeight = expandLayout.getHeight();
|
||||||
|
ValueAnimator mAnimator = slideAnimator(finalHeight, 0);
|
||||||
|
mAnimator.addListener(new Animator.AnimatorListener() {
|
||||||
|
@Override
|
||||||
|
public void onAnimationEnd(Animator animator) {
|
||||||
|
expandLayout.setVisibility(View.GONE);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onAnimationStart(Animator animator) {}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onAnimationCancel(Animator animator) {}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onAnimationRepeat(Animator animator) {}
|
||||||
|
});
|
||||||
|
mAnimator.start();
|
||||||
|
mExpanded = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private ValueAnimator slideAnimator(int start, int end) {
|
||||||
|
|
||||||
|
ValueAnimator animator = ValueAnimator.ofInt(start, end);
|
||||||
|
|
||||||
|
animator.addUpdateListener(valueAnimator -> {
|
||||||
|
int value = (Integer) valueAnimator.getAnimatedValue();
|
||||||
|
ViewGroup.LayoutParams layoutParams = expandLayout.getLayoutParams();
|
||||||
|
layoutParams.height = value;
|
||||||
|
expandLayout.setLayoutParams(layoutParams);
|
||||||
|
});
|
||||||
|
return animator;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@ -7,6 +7,11 @@ import android.database.Cursor;
|
|||||||
|
|
||||||
|
|
||||||
public class Policy {
|
public class Policy {
|
||||||
|
public static final int INTERACTIVE = 0;
|
||||||
|
public static final int DENY = 1;
|
||||||
|
public static final int ALLOW = 2;
|
||||||
|
|
||||||
|
|
||||||
public int uid, policy;
|
public int uid, policy;
|
||||||
public long until;
|
public long until;
|
||||||
public boolean logging, notification;
|
public boolean logging, notification;
|
||||||
|
@ -57,21 +57,22 @@ public class SuDatabaseHelper extends SQLiteOpenHelper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public List<Policy> getPolicyList(PackageManager pm) {
|
public List<Policy> getPolicyList(PackageManager pm) {
|
||||||
|
List<Policy> ret = new ArrayList<>();
|
||||||
SQLiteDatabase db = getWritableDatabase();
|
SQLiteDatabase db = getWritableDatabase();
|
||||||
ArrayList<Policy> ret = new ArrayList<>();
|
|
||||||
Policy policy;
|
Policy policy;
|
||||||
// Clear outdated policies
|
// Clear outdated policies
|
||||||
db.delete(TABLE_NAME, "until > 0 and until < ?", new String[] { String.valueOf(System.currentTimeMillis()) });
|
db.delete(TABLE_NAME, "until > 0 and until < ?", new String[] { String.valueOf(System.currentTimeMillis()) });
|
||||||
try (Cursor c = db.query(TABLE_NAME, null, null, null, null, null, null)) {
|
try (Cursor c = db.query(TABLE_NAME, null, null, null, null, null, "app_name")) {
|
||||||
while (c.moveToNext()) {
|
while (c.moveToNext()) {
|
||||||
policy = new Policy(c);
|
policy = new Policy(c);
|
||||||
// Package is uninstalled
|
// Package is uninstalled
|
||||||
if (pm.getPackagesForUid(policy.uid) == null)
|
if (pm.getPackagesForUid(policy.uid) == null) {
|
||||||
deletePolicy(policy.uid);
|
deletePolicy(policy.uid);
|
||||||
else
|
} else {
|
||||||
ret.add(policy);
|
ret.add(policy);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
db.close();
|
db.close();
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
package com.topjohnwu.magisk.superuser;
|
package com.topjohnwu.magisk.superuser;
|
||||||
|
|
||||||
import android.content.ContentValues;
|
import android.content.ContentValues;
|
||||||
import android.content.DialogInterface;
|
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.pm.PackageInfo;
|
import android.content.pm.PackageInfo;
|
||||||
import android.content.pm.PackageManager;
|
import android.content.pm.PackageManager;
|
||||||
@ -11,10 +10,7 @@ import android.os.AsyncTask;
|
|||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.CountDownTimer;
|
import android.os.CountDownTimer;
|
||||||
import android.support.v7.app.AppCompatActivity;
|
import android.support.v7.app.AppCompatActivity;
|
||||||
import android.view.MotionEvent;
|
|
||||||
import android.view.View;
|
|
||||||
import android.view.Window;
|
import android.view.Window;
|
||||||
import android.widget.AdapterView;
|
|
||||||
import android.widget.ArrayAdapter;
|
import android.widget.ArrayAdapter;
|
||||||
import android.widget.Button;
|
import android.widget.Button;
|
||||||
import android.widget.ImageView;
|
import android.widget.ImageView;
|
||||||
@ -117,7 +113,7 @@ public class SuRequestActivity extends AppCompatActivity {
|
|||||||
policy.packageName = packageName;
|
policy.packageName = packageName;
|
||||||
policy.appName = appName;
|
policy.appName = appName;
|
||||||
policy.until = (timeout == 0) ? 0 : (System.currentTimeMillis() / 1000 + timeout * 60);
|
policy.until = (timeout == 0) ? 0 : (System.currentTimeMillis() / 1000 + timeout * 60);
|
||||||
policy.policy = action ? 2 : 1;
|
policy.policy = action ? Policy.ALLOW : Policy.DENY;
|
||||||
policy.logging = true;
|
policy.logging = true;
|
||||||
policy.notification = true;
|
policy.notification = true;
|
||||||
new SuDatabaseHelper(this).addPolicy(policy);
|
new SuDatabaseHelper(this).addPolicy(policy);
|
||||||
|
@ -8,7 +8,6 @@ import android.database.Cursor;
|
|||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.AsyncTask;
|
import android.os.AsyncTask;
|
||||||
import android.provider.OpenableColumns;
|
import android.provider.OpenableColumns;
|
||||||
import android.util.Log;
|
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
import com.topjohnwu.magisk.Global;
|
import com.topjohnwu.magisk.Global;
|
||||||
|
9
app/src/main/res/drawable/ic_more.xml
Normal file
9
app/src/main/res/drawable/ic_more.xml
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="24dp"
|
||||||
|
android:height="24dp"
|
||||||
|
android:viewportWidth="24.0"
|
||||||
|
android:viewportHeight="24.0">
|
||||||
|
<path
|
||||||
|
android:fillColor="#FF000000"
|
||||||
|
android:pathData="M6,10c-1.1,0 -2,0.9 -2,2s0.9,2 2,2 2,-0.9 2,-2 -0.9,-2 -2,-2zM18,10c-1.1,0 -2,0.9 -2,2s0.9,2 2,2 2,-0.9 2,-2 -0.9,-2 -2,-2zM12,10c-1.1,0 -2,0.9 -2,2s0.9,2 2,2 2,-0.9 2,-2 -0.9,-2 -2,-2z"/>
|
||||||
|
</vector>
|
9
app/src/main/res/drawable/ic_notifications.xml
Normal file
9
app/src/main/res/drawable/ic_notifications.xml
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="24dp"
|
||||||
|
android:height="24dp"
|
||||||
|
android:viewportWidth="24.0"
|
||||||
|
android:viewportHeight="24.0">
|
||||||
|
<path
|
||||||
|
android:fillColor="#FF000000"
|
||||||
|
android:pathData="M7.58,4.08L6.15,2.65C3.75,4.48 2.17,7.3 2.03,10.5h2c0.15,-2.65 1.51,-4.97 3.55,-6.42zM19.97,10.5h2c-0.15,-3.2 -1.73,-6.02 -4.12,-7.85l-1.42,1.43c2.02,1.45 3.39,3.77 3.54,6.42zM18,11c0,-3.07 -1.64,-5.64 -4.5,-6.32L13.5,4c0,-0.83 -0.67,-1.5 -1.5,-1.5s-1.5,0.67 -1.5,1.5v0.68C7.63,5.36 6,7.92 6,11v5l-2,2v1h16v-1l-2,-2v-5zM12,22c0.14,0 0.27,-0.01 0.4,-0.04 0.65,-0.14 1.18,-0.58 1.44,-1.18 0.1,-0.24 0.15,-0.5 0.15,-0.78h-4c0.01,1.1 0.9,2 2.01,2z"/>
|
||||||
|
</vector>
|
7
app/src/main/res/drawable/ic_superuser.xml
Normal file
7
app/src/main/res/drawable/ic_superuser.xml
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:height="24dp"
|
||||||
|
android:width="24dp"
|
||||||
|
android:viewportWidth="24"
|
||||||
|
android:viewportHeight="24">
|
||||||
|
<path android:fillColor="#000" android:pathData="M5.41,21L6.12,17H2.12L2.47,15H6.47L7.53,9H3.53L3.88,7H7.88L8.59,3H10.59L9.88,7H15.88L16.59,3H18.59L17.88,7H21.88L21.53,9H17.53L16.47,15H20.47L20.12,17H16.12L15.41,21H13.41L14.12,17H8.12L7.41,21H5.41M9.53,9L8.47,15H14.47L15.53,9H9.53Z" />
|
||||||
|
</vector>
|
28
app/src/main/res/layout/fragment_superuser.xml
Normal file
28
app/src/main/res/layout/fragment_superuser.xml
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
<LinearLayout
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:layout_marginTop="?attr/actionBarSize"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/empty_rv"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:layout_gravity="center"
|
||||||
|
android:fontFamily="sans-serif-light"
|
||||||
|
android:gravity="center"
|
||||||
|
android:text="@string/no_apps_found"
|
||||||
|
android:textSize="20sp"
|
||||||
|
android:textStyle="italic"
|
||||||
|
android:visibility="gone" />
|
||||||
|
|
||||||
|
<android.support.v7.widget.RecyclerView
|
||||||
|
android:id="@+id/recyclerView"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:dividerHeight="@dimen/card_divider_space"
|
||||||
|
app:layoutManager="android.support.v7.widget.LinearLayoutManager" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
163
app/src/main/res/layout/list_item_policy.xml
Normal file
163
app/src/main/res/layout/list_item_policy.xml
Normal file
@ -0,0 +1,163 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<android.support.v7.widget.CardView
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:card_view="http://schemas.android.com/apk/res-auto"
|
||||||
|
style="?attr/cardStyle"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center"
|
||||||
|
android:layout_marginBottom="@dimen/card_vertical_margin"
|
||||||
|
android:layout_marginEnd="@dimen/card_horizontal_margin"
|
||||||
|
android:layout_marginStart="@dimen/card_horizontal_margin"
|
||||||
|
android:layout_marginTop="@dimen/card_vertical_margin"
|
||||||
|
android:minHeight="?android:attr/listPreferredItemHeight"
|
||||||
|
card_view:cardCornerRadius="@dimen/card_corner_radius"
|
||||||
|
card_view:cardElevation="@dimen/card_elevation">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:id="@+id/info_layout"
|
||||||
|
android:paddingStart="10dp"
|
||||||
|
android:paddingEnd="10dp"
|
||||||
|
android:paddingTop="5dp"
|
||||||
|
android:paddingBottom="5dp">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/app_icon"
|
||||||
|
android:layout_width="50dp"
|
||||||
|
android:layout_height="50dp"
|
||||||
|
android:layout_gravity="center_vertical"
|
||||||
|
android:gravity="end" />
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:layout_gravity="center_vertical"
|
||||||
|
android:layout_marginStart="5dp"
|
||||||
|
android:layout_marginEnd="5dp">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/app_name"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:maxLines="1"
|
||||||
|
android:ellipsize="end"
|
||||||
|
android:textAppearance="?android:attr/textAppearanceMedium"
|
||||||
|
android:textColor="?android:attr/textColorPrimary"
|
||||||
|
android:textIsSelectable="false"/>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/package_name"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:maxLines="1"
|
||||||
|
android:ellipsize="end"
|
||||||
|
android:textAppearance="?android:attr/textAppearanceSmall"
|
||||||
|
android:textColor="@android:color/tertiary_text_dark"
|
||||||
|
android:textIsSelectable="false" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<Switch
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:id="@+id/master_switch"
|
||||||
|
android:layout_weight="0"
|
||||||
|
android:checked="false"
|
||||||
|
android:layout_gravity="center_vertical"
|
||||||
|
android:gravity="center_vertical" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/expand_layout"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center_horizontal"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:paddingStart="10dp"
|
||||||
|
android:paddingEnd="10dp">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:gravity="center"
|
||||||
|
android:paddingTop="10dp"
|
||||||
|
android:paddingBottom="10dp"
|
||||||
|
android:layout_gravity="center">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:src="@drawable/ic_notifications"
|
||||||
|
android:layout_gravity="center_vertical"
|
||||||
|
android:tint="@color/icon_grey"
|
||||||
|
android:layout_marginEnd="10dp" />
|
||||||
|
|
||||||
|
<Switch
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:id="@+id/notification_switch"
|
||||||
|
android:checked="false"
|
||||||
|
android:layout_gravity="center_vertical"
|
||||||
|
android:gravity="center_vertical" />
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:gravity="center"
|
||||||
|
android:paddingTop="10dp"
|
||||||
|
android:paddingBottom="10dp"
|
||||||
|
android:layout_gravity="center">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:src="@drawable/ic_bug_report"
|
||||||
|
android:layout_gravity="center_vertical"
|
||||||
|
android:tint="@color/icon_grey"
|
||||||
|
android:layout_marginEnd="10dp" />
|
||||||
|
|
||||||
|
<Switch
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:id="@+id/logging_switch"
|
||||||
|
android:checked="false"
|
||||||
|
android:layout_gravity="center_vertical"
|
||||||
|
android:gravity="center_vertical" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/more_info"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:background="?android:attr/selectableItemBackground"
|
||||||
|
android:src="@drawable/ic_more"
|
||||||
|
android:tint="@color/icon_grey"
|
||||||
|
android:layout_gravity="center" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
|
||||||
|
</android.support.v7.widget.CardView>
|
||||||
|
|
||||||
|
|
@ -16,6 +16,18 @@
|
|||||||
android:title="@string/install"
|
android:title="@string/install"
|
||||||
android:visible="false"/>
|
android:visible="false"/>
|
||||||
|
|
||||||
|
<item
|
||||||
|
android:id="@+id/superuser"
|
||||||
|
android:icon="@drawable/ic_superuser"
|
||||||
|
android:title="@string/superuser"
|
||||||
|
android:visible="true"/>
|
||||||
|
|
||||||
|
</group>
|
||||||
|
|
||||||
|
<group
|
||||||
|
android:checkableBehavior="single"
|
||||||
|
android:id="@+id/second_group">
|
||||||
|
|
||||||
<item
|
<item
|
||||||
android:id="@+id/modules"
|
android:id="@+id/modules"
|
||||||
android:icon="@drawable/ic_extension"
|
android:icon="@drawable/ic_extension"
|
||||||
@ -30,15 +42,17 @@
|
|||||||
android:id="@+id/magiskhide"
|
android:id="@+id/magiskhide"
|
||||||
android:icon="@drawable/ic_autoroot"
|
android:icon="@drawable/ic_autoroot"
|
||||||
android:title="@string/magiskhide"/>
|
android:title="@string/magiskhide"/>
|
||||||
|
|
||||||
<item
|
<item
|
||||||
android:id="@+id/log"
|
android:id="@+id/log"
|
||||||
android:icon="@drawable/ic_bug_report"
|
android:icon="@drawable/ic_bug_report"
|
||||||
android:title="@string/log"/>
|
android:title="@string/log"/>
|
||||||
|
|
||||||
</group>
|
</group>
|
||||||
|
|
||||||
<group
|
<group
|
||||||
android:checkableBehavior="none"
|
android:checkableBehavior="none"
|
||||||
android:id="@+id/second_group">
|
android:id="@+id/third_group">
|
||||||
|
|
||||||
<item
|
<item
|
||||||
android:id="@+id/settings"
|
android:id="@+id/settings"
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
<string name="magiskhide">Magisk Hide</string>
|
<string name="magiskhide">Magisk Hide</string>
|
||||||
<string name="modules">Modules</string>
|
<string name="modules">Modules</string>
|
||||||
<string name="downloads">Downloads</string>
|
<string name="downloads">Downloads</string>
|
||||||
|
<string name="superuser">Superuser</string>
|
||||||
<string name="log">Log</string>
|
<string name="log">Log</string>
|
||||||
<string name="settings">Settings</string>
|
<string name="settings">Settings</string>
|
||||||
<string name="status">Status</string>
|
<string name="status">Status</string>
|
||||||
@ -156,9 +157,7 @@
|
|||||||
<string name="sixtymin">60 min</string>
|
<string name="sixtymin">60 min</string>
|
||||||
<string name="su_allow_toast">%1$s is granted Superuser permissions</string>
|
<string name="su_allow_toast">%1$s is granted Superuser permissions</string>
|
||||||
<string name="su_deny_toast">%1$s is denied Superuser permissions</string>
|
<string name="su_deny_toast">%1$s is denied Superuser permissions</string>
|
||||||
|
<string name="no_apps_found">No apps found</string>
|
||||||
<!-- TODO: Remove or change this placeholder text -->
|
|
||||||
<string name="hello_blank_fragment">Hello blank fragment</string>
|
|
||||||
|
|
||||||
|
|
||||||
</resources>
|
</resources>
|
||||||
|
Loading…
Reference in New Issue
Block a user