Add Superuser logging UI
This commit is contained in:
parent
ca9334b2df
commit
cbb32f82eb
@ -55,13 +55,14 @@ dependencies {
|
|||||||
compile 'com.android.support:design:25.1.0'
|
compile 'com.android.support:design:25.1.0'
|
||||||
compile 'com.android.support:support-v4:25.1.0'
|
compile 'com.android.support:support-v4:25.1.0'
|
||||||
compile 'com.android.support:support-v13:25.1.0'
|
compile 'com.android.support:support-v13:25.1.0'
|
||||||
compile 'com.jakewharton:butterknife:8.4.0'
|
compile 'com.jakewharton:butterknife:8.5.1'
|
||||||
compile 'com.google.code.gson:gson:2.8.0'
|
compile 'com.google.code.gson:gson:2.8.0'
|
||||||
compile 'com.github.clans:fab:1.6.4'
|
compile 'com.github.clans:fab:1.6.4'
|
||||||
|
compile 'com.thoughtbot:expandablerecyclerview:1.4'
|
||||||
compile 'com.madgag.spongycastle:core:1.54.0.0'
|
compile 'com.madgag.spongycastle:core:1.54.0.0'
|
||||||
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:9.0.1'
|
compile 'com.google.android.gms:play-services-safetynet:9.0.1'
|
||||||
annotationProcessor 'com.jakewharton:butterknife-compiler:8.4.0'
|
annotationProcessor 'com.jakewharton:butterknife-compiler:8.5.1'
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,6 @@ package com.topjohnwu.magisk;
|
|||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.SharedPreferences;
|
import android.content.SharedPreferences;
|
||||||
import android.preference.PreferenceManager;
|
import android.preference.PreferenceManager;
|
||||||
import android.text.TextUtils;
|
|
||||||
|
|
||||||
import com.topjohnwu.magisk.module.Module;
|
import com.topjohnwu.magisk.module.Module;
|
||||||
import com.topjohnwu.magisk.module.Repo;
|
import com.topjohnwu.magisk.module.Repo;
|
||||||
|
@ -2,17 +2,14 @@ package com.topjohnwu.magisk;
|
|||||||
|
|
||||||
|
|
||||||
import android.app.Fragment;
|
import android.app.Fragment;
|
||||||
import android.app.FragmentManager;
|
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.support.design.widget.TabLayout;
|
import android.support.design.widget.TabLayout;
|
||||||
import android.support.v13.app.FragmentPagerAdapter;
|
|
||||||
import android.support.v4.view.ViewPager;
|
import android.support.v4.view.ViewPager;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import com.topjohnwu.magisk.adapters.TabFragmentAdapter;
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import butterknife.BindView;
|
import butterknife.BindView;
|
||||||
import butterknife.ButterKnife;
|
import butterknife.ButterKnife;
|
||||||
@ -25,7 +22,6 @@ public class LogFragment extends Fragment {
|
|||||||
@BindView(R.id.container) ViewPager viewPager;
|
@BindView(R.id.container) ViewPager viewPager;
|
||||||
@BindView(R.id.tab) TabLayout tab;
|
@BindView(R.id.tab) TabLayout tab;
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
||||||
Bundle savedInstanceState) {
|
Bundle savedInstanceState) {
|
||||||
@ -33,7 +29,7 @@ public class LogFragment extends Fragment {
|
|||||||
View v = inflater.inflate(R.layout.fragment_log, container, false);
|
View v = inflater.inflate(R.layout.fragment_log, container, false);
|
||||||
unbinder = ButterKnife.bind(this, v);
|
unbinder = ButterKnife.bind(this, v);
|
||||||
|
|
||||||
ViewPagerAdapter adapter = new ViewPagerAdapter(getChildFragmentManager());
|
TabFragmentAdapter adapter = new TabFragmentAdapter(getChildFragmentManager());
|
||||||
|
|
||||||
adapter.addTab(new MagiskLogFragment(), getString(R.string.magisk));
|
adapter.addTab(new MagiskLogFragment(), getString(R.string.magisk));
|
||||||
|
|
||||||
@ -54,38 +50,4 @@ public class LogFragment extends Fragment {
|
|||||||
unbinder.unbind();
|
unbinder.unbind();
|
||||||
}
|
}
|
||||||
|
|
||||||
private class ViewPagerAdapter extends FragmentPagerAdapter {
|
|
||||||
|
|
||||||
List<Fragment> fragmentList;
|
|
||||||
List<String> titleList;
|
|
||||||
|
|
||||||
public ViewPagerAdapter(FragmentManager fm) {
|
|
||||||
super(fm);
|
|
||||||
fragmentList = new ArrayList<>();
|
|
||||||
titleList = new ArrayList<>();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Fragment getItem(int position) {
|
|
||||||
return fragmentList.get(position);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getCount() {
|
|
||||||
return fragmentList.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public CharSequence getPageTitle(int position) {
|
|
||||||
return titleList.get(position);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void addTab(Fragment fragment, String title) {
|
|
||||||
fragmentList.add(fragment);
|
|
||||||
titleList.add(title);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -41,6 +41,7 @@ public class MainActivity extends AppCompatActivity
|
|||||||
@BindView(R.id.nav_view) public NavigationView navigationView;
|
@BindView(R.id.nav_view) public NavigationView navigationView;
|
||||||
|
|
||||||
private int mSelectedId = R.id.status;
|
private int mSelectedId = R.id.status;
|
||||||
|
private float toolbarElevation;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onCreate(final Bundle savedInstanceState) {
|
protected void onCreate(final Bundle savedInstanceState) {
|
||||||
@ -74,6 +75,8 @@ public class MainActivity extends AppCompatActivity
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
toolbarElevation = toolbar.getElevation();
|
||||||
|
|
||||||
drawer.addDrawerListener(toggle);
|
drawer.addDrawerListener(toggle);
|
||||||
toggle.syncState();
|
toggle.syncState();
|
||||||
|
|
||||||
@ -158,6 +161,7 @@ public class MainActivity extends AppCompatActivity
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void navigate(int itemId, boolean now) {
|
public void navigate(int itemId, boolean now) {
|
||||||
|
toolbar.setElevation(toolbarElevation);
|
||||||
switch (itemId) {
|
switch (itemId) {
|
||||||
case R.id.status:
|
case R.id.status:
|
||||||
displayFragment(new StatusFragment(), "status", now);
|
displayFragment(new StatusFragment(), "status", now);
|
||||||
@ -179,6 +183,7 @@ public class MainActivity extends AppCompatActivity
|
|||||||
break;
|
break;
|
||||||
case R.id.log:
|
case R.id.log:
|
||||||
displayFragment(new LogFragment(), "log", now);
|
displayFragment(new LogFragment(), "log", now);
|
||||||
|
toolbar.setElevation(0);
|
||||||
break;
|
break;
|
||||||
case R.id.settings:
|
case R.id.settings:
|
||||||
startActivity(new Intent(this, SettingsActivity.class));
|
startActivity(new Intent(this, SettingsActivity.class));
|
||||||
|
@ -35,7 +35,7 @@ public class ModulesFragment extends Fragment implements CallbackHandler.EventLi
|
|||||||
private Unbinder unbinder;
|
private Unbinder unbinder;
|
||||||
@BindView(R.id.swipeRefreshLayout) SwipeRefreshLayout mSwipeRefreshLayout;
|
@BindView(R.id.swipeRefreshLayout) SwipeRefreshLayout mSwipeRefreshLayout;
|
||||||
@BindView(R.id.recyclerView) RecyclerView recyclerView;
|
@BindView(R.id.recyclerView) RecyclerView recyclerView;
|
||||||
@BindView(R.id.empty_rv) TextView emptyTv;
|
@BindView(R.id.empty_rv) TextView emptyRv;
|
||||||
@BindView(R.id.fab) FloatingActionButton fabio;
|
@BindView(R.id.fab) FloatingActionButton fabio;
|
||||||
|
|
||||||
private List<Module> listModules = new ArrayList<>();
|
private List<Module> listModules = new ArrayList<>();
|
||||||
@ -114,10 +114,10 @@ public class ModulesFragment extends Fragment implements CallbackHandler.EventLi
|
|||||||
private void updateUI() {
|
private void updateUI() {
|
||||||
ModuleHelper.getModuleList(listModules);
|
ModuleHelper.getModuleList(listModules);
|
||||||
if (listModules.size() == 0) {
|
if (listModules.size() == 0) {
|
||||||
emptyTv.setVisibility(View.VISIBLE);
|
emptyRv.setVisibility(View.VISIBLE);
|
||||||
recyclerView.setVisibility(View.GONE);
|
recyclerView.setVisibility(View.GONE);
|
||||||
} else {
|
} else {
|
||||||
emptyTv.setVisibility(View.GONE);
|
emptyRv.setVisibility(View.GONE);
|
||||||
recyclerView.setVisibility(View.VISIBLE);
|
recyclerView.setVisibility(View.VISIBLE);
|
||||||
recyclerView.setAdapter(new ModulesAdapter(listModules));
|
recyclerView.setAdapter(new ModulesAdapter(listModules));
|
||||||
}
|
}
|
||||||
|
@ -33,7 +33,7 @@ public class ReposFragment extends Fragment implements CallbackHandler.EventList
|
|||||||
|
|
||||||
private Unbinder unbinder;
|
private Unbinder unbinder;
|
||||||
@BindView(R.id.recyclerView) RecyclerView recyclerView;
|
@BindView(R.id.recyclerView) RecyclerView recyclerView;
|
||||||
@BindView(R.id.empty_rv) TextView emptyTv;
|
@BindView(R.id.empty_rv) TextView emptyRv;
|
||||||
@BindView(R.id.swipeRefreshLayout) SwipeRefreshLayout mSwipeRefreshLayout;
|
@BindView(R.id.swipeRefreshLayout) SwipeRefreshLayout mSwipeRefreshLayout;
|
||||||
|
|
||||||
private List<Repo> mUpdateRepos = new ArrayList<>();
|
private List<Repo> mUpdateRepos = new ArrayList<>();
|
||||||
@ -138,7 +138,7 @@ public class ReposFragment extends Fragment implements CallbackHandler.EventList
|
|||||||
|
|
||||||
private void updateUI() {
|
private void updateUI() {
|
||||||
if (fUpdateRepos.size() + fInstalledRepos.size() + fOthersRepos.size() == 0) {
|
if (fUpdateRepos.size() + fInstalledRepos.size() + fOthersRepos.size() == 0) {
|
||||||
emptyTv.setVisibility(View.VISIBLE);
|
emptyRv.setVisibility(View.VISIBLE);
|
||||||
recyclerView.setVisibility(View.GONE);
|
recyclerView.setVisibility(View.GONE);
|
||||||
} else {
|
} else {
|
||||||
List<SimpleSectionedRecyclerViewAdapter.Section> sections = new ArrayList<>();
|
List<SimpleSectionedRecyclerViewAdapter.Section> sections = new ArrayList<>();
|
||||||
@ -153,7 +153,7 @@ public class ReposFragment extends Fragment implements CallbackHandler.EventList
|
|||||||
}
|
}
|
||||||
SimpleSectionedRecyclerViewAdapter.Section[] array = sections.toArray(new SimpleSectionedRecyclerViewAdapter.Section[sections.size()]);
|
SimpleSectionedRecyclerViewAdapter.Section[] array = sections.toArray(new SimpleSectionedRecyclerViewAdapter.Section[sections.size()]);
|
||||||
mSectionedAdapter.setSections(array);
|
mSectionedAdapter.setSections(array);
|
||||||
emptyTv.setVisibility(View.GONE);
|
emptyRv.setVisibility(View.GONE);
|
||||||
recyclerView.setVisibility(View.VISIBLE);
|
recyclerView.setVisibility(View.VISIBLE);
|
||||||
}
|
}
|
||||||
mSwipeRefreshLayout.setRefreshing(false);
|
mSwipeRefreshLayout.setRefreshing(false);
|
||||||
|
@ -3,7 +3,6 @@ package com.topjohnwu.magisk;
|
|||||||
import android.content.SharedPreferences;
|
import android.content.SharedPreferences;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.preference.CheckBoxPreference;
|
import android.preference.CheckBoxPreference;
|
||||||
import android.preference.ListPreference;
|
|
||||||
import android.preference.Preference;
|
import android.preference.Preference;
|
||||||
import android.preference.PreferenceFragment;
|
import android.preference.PreferenceFragment;
|
||||||
import android.preference.PreferenceManager;
|
import android.preference.PreferenceManager;
|
||||||
|
@ -21,8 +21,6 @@ import com.topjohnwu.magisk.utils.Logger;
|
|||||||
import com.topjohnwu.magisk.utils.Shell;
|
import com.topjohnwu.magisk.utils.Shell;
|
||||||
import com.topjohnwu.magisk.utils.Utils;
|
import com.topjohnwu.magisk.utils.Utils;
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import butterknife.BindColor;
|
import butterknife.BindColor;
|
||||||
import butterknife.BindView;
|
import butterknife.BindView;
|
||||||
import butterknife.ButterKnife;
|
import butterknife.ButterKnife;
|
||||||
|
@ -3,18 +3,54 @@ package com.topjohnwu.magisk;
|
|||||||
|
|
||||||
import android.app.Fragment;
|
import android.app.Fragment;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
import android.support.v7.widget.RecyclerView;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
|
import android.widget.TextView;
|
||||||
|
|
||||||
|
import com.topjohnwu.magisk.adapters.SuLogAdapter;
|
||||||
|
import com.topjohnwu.magisk.superuser.SuLogDatabaseHelper;
|
||||||
|
import com.topjohnwu.magisk.superuser.SuLogEntry;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import butterknife.BindView;
|
||||||
|
import butterknife.ButterKnife;
|
||||||
|
import butterknife.Unbinder;
|
||||||
|
|
||||||
public class SuLogFragment extends Fragment {
|
public class SuLogFragment extends Fragment {
|
||||||
|
|
||||||
|
@BindView(R.id.empty_rv) TextView emptyRv;
|
||||||
|
@BindView(R.id.recyclerView) RecyclerView recyclerView;
|
||||||
|
|
||||||
|
private Unbinder unbinder;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
||||||
Bundle savedInstanceState) {
|
Bundle savedInstanceState) {
|
||||||
// Inflate the layout for this fragment
|
// Inflate the layout for this fragment
|
||||||
return inflater.inflate(R.layout.fragment_su_log, container, false);
|
View v = inflater.inflate(R.layout.fragment_su_log, container, false);
|
||||||
|
unbinder = ButterKnife.bind(this, v);
|
||||||
|
|
||||||
|
SuLogDatabaseHelper dbHelper = new SuLogDatabaseHelper(getActivity());
|
||||||
|
List<SuLogEntry> logs = dbHelper.getLogList();
|
||||||
|
|
||||||
|
if (logs.size() == 0) {
|
||||||
|
emptyRv.setVisibility(View.VISIBLE);
|
||||||
|
recyclerView.setVisibility(View.GONE);
|
||||||
|
} else {
|
||||||
|
recyclerView.setAdapter(new SuLogAdapter(logs).getAdapter());
|
||||||
|
emptyRv.setVisibility(View.GONE);
|
||||||
|
recyclerView.setVisibility(View.VISIBLE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onDestroyView() {
|
||||||
|
super.onDestroyView();
|
||||||
|
unbinder.unbind();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -25,7 +25,7 @@ public class SuperuserFragment extends Fragment {
|
|||||||
|
|
||||||
private Unbinder unbinder;
|
private Unbinder unbinder;
|
||||||
@BindView(R.id.recyclerView) RecyclerView recyclerView;
|
@BindView(R.id.recyclerView) RecyclerView recyclerView;
|
||||||
@BindView(R.id.empty_rv) TextView emptyTv;
|
@BindView(R.id.empty_rv) TextView emptyRv;
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
@Override
|
@Override
|
||||||
@ -38,14 +38,12 @@ public class SuperuserFragment extends Fragment {
|
|||||||
SuDatabaseHelper dbHelper = new SuDatabaseHelper(getActivity());
|
SuDatabaseHelper dbHelper = new SuDatabaseHelper(getActivity());
|
||||||
List<Policy> policyList = dbHelper.getPolicyList(pm);
|
List<Policy> policyList = dbHelper.getPolicyList(pm);
|
||||||
|
|
||||||
PolicyAdapter adapter = new PolicyAdapter(policyList, dbHelper, pm);
|
|
||||||
|
|
||||||
if (policyList.size() == 0) {
|
if (policyList.size() == 0) {
|
||||||
emptyTv.setVisibility(View.VISIBLE);
|
emptyRv.setVisibility(View.VISIBLE);
|
||||||
recyclerView.setVisibility(View.GONE);
|
recyclerView.setVisibility(View.GONE);
|
||||||
} else {
|
} else {
|
||||||
recyclerView.setAdapter(adapter);
|
recyclerView.setAdapter(new PolicyAdapter(policyList, dbHelper, pm));
|
||||||
emptyTv.setVisibility(View.GONE);
|
emptyRv.setVisibility(View.GONE);
|
||||||
recyclerView.setVisibility(View.VISIBLE);
|
recyclerView.setVisibility(View.VISIBLE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -111,6 +111,9 @@ public class PolicyAdapter extends RecyclerView.Adapter<PolicyAdapter.ViewHolder
|
|||||||
holder.notificationSwitch.setChecked(policy.notification);
|
holder.notificationSwitch.setChecked(policy.notification);
|
||||||
holder.loggingSwitch.setChecked(policy.logging);
|
holder.loggingSwitch.setChecked(policy.logging);
|
||||||
|
|
||||||
|
// Hide for now
|
||||||
|
holder.moreInfo.setVisibility(View.GONE);
|
||||||
|
|
||||||
} catch (PackageManager.NameNotFoundException e) {
|
} catch (PackageManager.NameNotFoundException e) {
|
||||||
policyList.remove(position);
|
policyList.remove(position);
|
||||||
dbHelper.deletePolicy(policy.uid);
|
dbHelper.deletePolicy(policy.uid);
|
||||||
|
@ -0,0 +1,238 @@
|
|||||||
|
package com.topjohnwu.magisk.adapters;
|
||||||
|
|
||||||
|
import android.animation.Animator;
|
||||||
|
import android.animation.ValueAnimator;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.support.v7.widget.RecyclerView;
|
||||||
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
import android.view.ViewTreeObserver;
|
||||||
|
import android.view.animation.Animation;
|
||||||
|
import android.view.animation.RotateAnimation;
|
||||||
|
import android.widget.ImageView;
|
||||||
|
import android.widget.LinearLayout;
|
||||||
|
import android.widget.TextView;
|
||||||
|
|
||||||
|
import com.thoughtbot.expandablerecyclerview.ExpandableRecyclerViewAdapter;
|
||||||
|
import com.thoughtbot.expandablerecyclerview.models.ExpandableGroup;
|
||||||
|
import com.thoughtbot.expandablerecyclerview.viewholders.ChildViewHolder;
|
||||||
|
import com.thoughtbot.expandablerecyclerview.viewholders.GroupViewHolder;
|
||||||
|
import com.topjohnwu.magisk.R;
|
||||||
|
import com.topjohnwu.magisk.superuser.SuLogEntry;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import butterknife.BindView;
|
||||||
|
import butterknife.ButterKnife;
|
||||||
|
|
||||||
|
public class SuLogAdapter {
|
||||||
|
|
||||||
|
private ExpandableAdapter adapter;
|
||||||
|
private HashSet<SuLogEntry> expandList = new HashSet<>();
|
||||||
|
|
||||||
|
public SuLogAdapter(List<SuLogEntry> list) {
|
||||||
|
|
||||||
|
// Separate the logs with date
|
||||||
|
LinkedHashMap<String, ArrayList<SuLogEntry>> logEntryMap = new LinkedHashMap<>();
|
||||||
|
ArrayList<SuLogEntry> group;
|
||||||
|
for (SuLogEntry log : list) {
|
||||||
|
String date = log.getDateString();
|
||||||
|
group = logEntryMap.get(date);
|
||||||
|
if (group == null) {
|
||||||
|
group = new ArrayList<>();
|
||||||
|
logEntryMap.put(date, group);
|
||||||
|
}
|
||||||
|
group.add(log);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Then format them into expandable groups
|
||||||
|
ArrayList<LogGroup> logEntryGroups = new ArrayList<>();
|
||||||
|
for (HashMap.Entry<String, ArrayList<SuLogEntry>> entry : logEntryMap.entrySet()) {
|
||||||
|
logEntryGroups.add(new LogGroup(entry.getKey(), entry.getValue()));
|
||||||
|
}
|
||||||
|
adapter = new ExpandableAdapter(logEntryGroups);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public RecyclerView.Adapter getAdapter() {
|
||||||
|
return adapter;
|
||||||
|
}
|
||||||
|
|
||||||
|
private class ExpandableAdapter
|
||||||
|
extends ExpandableRecyclerViewAdapter<LogGroupViewHolder, LogViewHolder> {
|
||||||
|
|
||||||
|
ExpandableAdapter(List<? extends ExpandableGroup> groups) {
|
||||||
|
super(groups);
|
||||||
|
expandableList.expandedGroupIndexes[0] = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public LogGroupViewHolder onCreateGroupViewHolder(ViewGroup parent, int viewType) {
|
||||||
|
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_item_sulog_group, parent, false);
|
||||||
|
return new LogGroupViewHolder(v);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public LogViewHolder onCreateChildViewHolder(ViewGroup parent, int viewType) {
|
||||||
|
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_item_sulog, parent, false);
|
||||||
|
return new LogViewHolder(v);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onBindChildViewHolder(LogViewHolder holder, int flatPosition, ExpandableGroup group, int childIndex) {
|
||||||
|
Context context = holder.itemView.getContext();
|
||||||
|
SuLogEntry logEntry = (SuLogEntry) group.getItems().get(childIndex);
|
||||||
|
holder.setExpanded(expandList.contains(logEntry));
|
||||||
|
holder.itemView.setOnClickListener(view -> {
|
||||||
|
if (holder.mExpanded) {
|
||||||
|
holder.collapse();
|
||||||
|
expandList.remove(logEntry);
|
||||||
|
} else {
|
||||||
|
holder.expand();
|
||||||
|
expandList.add(logEntry);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
holder.appName.setText(logEntry.appName);
|
||||||
|
holder.action.setText(logEntry.action ? context.getString(R.string.grant) : context.getString(R.string.deny, ""));
|
||||||
|
holder.command.setText(logEntry.command);
|
||||||
|
holder.fromPid.setText(String.valueOf(logEntry.fromPid));
|
||||||
|
holder.toUid.setText(String.valueOf(logEntry.toUid));
|
||||||
|
holder.time.setText(logEntry.getTimeString());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onBindGroupViewHolder(LogGroupViewHolder holder, int flatPosition, ExpandableGroup group) {
|
||||||
|
holder.date.setText(group.getTitle());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class LogGroup extends ExpandableGroup<SuLogEntry> {
|
||||||
|
LogGroup(String title, List<SuLogEntry> items) {
|
||||||
|
super(title, items);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static class LogGroupViewHolder extends GroupViewHolder {
|
||||||
|
|
||||||
|
@BindView(R.id.date) TextView date;
|
||||||
|
@BindView(R.id.arrow) ImageView arrow;
|
||||||
|
|
||||||
|
public LogGroupViewHolder(View itemView) {
|
||||||
|
super(itemView);
|
||||||
|
ButterKnife.bind(this, itemView);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void expand() {
|
||||||
|
RotateAnimation rotate =
|
||||||
|
new RotateAnimation(360, 180, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
|
||||||
|
rotate.setDuration(300);
|
||||||
|
rotate.setFillAfter(true);
|
||||||
|
arrow.setAnimation(rotate);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void collapse() {
|
||||||
|
RotateAnimation rotate =
|
||||||
|
new RotateAnimation(180, 360, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
|
||||||
|
rotate.setDuration(300);
|
||||||
|
rotate.setFillAfter(true);
|
||||||
|
arrow.setAnimation(rotate);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static class LogViewHolder extends ChildViewHolder {
|
||||||
|
|
||||||
|
@BindView(R.id.app_name) TextView appName;
|
||||||
|
@BindView(R.id.action) TextView action;
|
||||||
|
@BindView(R.id.time) TextView time;
|
||||||
|
@BindView(R.id.fromPid) TextView fromPid;
|
||||||
|
@BindView(R.id.toUid) TextView toUid;
|
||||||
|
@BindView(R.id.command) TextView command;
|
||||||
|
@BindView(R.id.expand_layout) LinearLayout expandLayout;
|
||||||
|
|
||||||
|
private ValueAnimator mAnimator;
|
||||||
|
private boolean mExpanded = false;
|
||||||
|
private static int expandHeight = 0;
|
||||||
|
|
||||||
|
public LogViewHolder(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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,40 @@
|
|||||||
|
package com.topjohnwu.magisk.adapters;
|
||||||
|
|
||||||
|
import android.app.Fragment;
|
||||||
|
import android.app.FragmentManager;
|
||||||
|
import android.support.v13.app.FragmentPagerAdapter;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class TabFragmentAdapter extends FragmentPagerAdapter {
|
||||||
|
|
||||||
|
private List<Fragment> fragmentList;
|
||||||
|
private List<String> titleList;
|
||||||
|
|
||||||
|
public TabFragmentAdapter(FragmentManager fm) {
|
||||||
|
super(fm);
|
||||||
|
fragmentList = new ArrayList<>();
|
||||||
|
titleList = new ArrayList<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Fragment getItem(int position) {
|
||||||
|
return fragmentList.get(position);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getCount() {
|
||||||
|
return fragmentList.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CharSequence getPageTitle(int position) {
|
||||||
|
return titleList.get(position);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addTab(Fragment fragment, String title) {
|
||||||
|
fragmentList.add(fragment);
|
||||||
|
titleList.add(title);
|
||||||
|
}
|
||||||
|
}
|
@ -2,13 +2,20 @@ package com.topjohnwu.magisk.superuser;
|
|||||||
|
|
||||||
import android.content.ContentValues;
|
import android.content.ContentValues;
|
||||||
import android.database.Cursor;
|
import android.database.Cursor;
|
||||||
|
import android.os.Parcel;
|
||||||
|
import android.os.Parcelable;
|
||||||
|
|
||||||
public class SuLogEntry {
|
import java.text.DateFormat;
|
||||||
|
import java.text.SimpleDateFormat;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.Locale;
|
||||||
|
|
||||||
|
public class SuLogEntry implements Parcelable {
|
||||||
|
|
||||||
public int fromUid, toUid, fromPid;
|
public int fromUid, toUid, fromPid;
|
||||||
public String packageName, appName, command;
|
public String packageName, appName, command;
|
||||||
public boolean action;
|
public boolean action;
|
||||||
public long time;
|
public Date date;
|
||||||
|
|
||||||
public SuLogEntry(Policy policy) {
|
public SuLogEntry(Policy policy) {
|
||||||
fromUid = policy.uid;
|
fromUid = policy.uid;
|
||||||
@ -24,7 +31,7 @@ public class SuLogEntry {
|
|||||||
appName = c.getString(c.getColumnIndex("app_name"));
|
appName = c.getString(c.getColumnIndex("app_name"));
|
||||||
command = c.getString(c.getColumnIndex("command"));
|
command = c.getString(c.getColumnIndex("command"));
|
||||||
action = c.getInt(c.getColumnIndex("action")) != 0;
|
action = c.getInt(c.getColumnIndex("action")) != 0;
|
||||||
time = c.getLong(c.getColumnIndex("until"));
|
date = new Date(c.getLong(c.getColumnIndex("time")) * 1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ContentValues getContentValues() {
|
public ContentValues getContentValues() {
|
||||||
@ -35,8 +42,57 @@ public class SuLogEntry {
|
|||||||
values.put("from_pid", fromPid);
|
values.put("from_pid", fromPid);
|
||||||
values.put("command", command);
|
values.put("command", command);
|
||||||
values.put("to_uid", toUid);
|
values.put("to_uid", toUid);
|
||||||
values.put("action", action);
|
values.put("action", action ? 1 : 0);
|
||||||
values.put("time", time);
|
values.put("time", date.getTime() / 1000);
|
||||||
return values;
|
return values;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getDateString() {
|
||||||
|
return DateFormat.getDateInstance(DateFormat.MEDIUM).format(date);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getTimeString() {
|
||||||
|
return new SimpleDateFormat("h:mm a", Locale.US).format(date);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static final Creator<SuLogEntry> CREATOR = new Creator<SuLogEntry>() {
|
||||||
|
@Override
|
||||||
|
public SuLogEntry createFromParcel(Parcel in) {
|
||||||
|
return new SuLogEntry(in);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SuLogEntry[] newArray(int size) {
|
||||||
|
return new SuLogEntry[size];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
protected SuLogEntry(Parcel in) {
|
||||||
|
fromUid = in.readInt();
|
||||||
|
toUid = in.readInt();
|
||||||
|
fromPid = in.readInt();
|
||||||
|
packageName = in.readString();
|
||||||
|
appName = in.readString();
|
||||||
|
command = in.readString();
|
||||||
|
action = in.readByte() != 0;
|
||||||
|
date = new Date(in.readLong());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int describeContents() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void writeToParcel(Parcel dest, int flags) {
|
||||||
|
dest.writeInt(fromUid);
|
||||||
|
dest.writeInt(toUid);
|
||||||
|
dest.writeInt(fromPid);
|
||||||
|
dest.writeString(packageName);
|
||||||
|
dest.writeString(appName);
|
||||||
|
dest.writeString(command);
|
||||||
|
dest.writeByte((byte) (action ? 1 : 0));
|
||||||
|
dest.writeLong(date.getTime());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,6 +8,8 @@ import android.widget.Toast;
|
|||||||
|
|
||||||
import com.topjohnwu.magisk.R;
|
import com.topjohnwu.magisk.R;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
public class SuReceiver extends BroadcastReceiver {
|
public class SuReceiver extends BroadcastReceiver {
|
||||||
@Override
|
@Override
|
||||||
public void onReceive(Context context, Intent intent) {
|
public void onReceive(Context context, Intent intent) {
|
||||||
@ -32,14 +34,18 @@ public class SuReceiver extends BroadcastReceiver {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SuLogEntry log = new SuLogEntry(policy);
|
||||||
|
|
||||||
if (policy.notification) {
|
if (policy.notification) {
|
||||||
String message;
|
String message;
|
||||||
switch (action) {
|
switch (action) {
|
||||||
case "allow":
|
case "allow":
|
||||||
message = context.getString(R.string.su_allow_toast, policy.appName);
|
message = context.getString(R.string.su_allow_toast, policy.appName);
|
||||||
|
log.action = true;
|
||||||
break;
|
break;
|
||||||
case "deny":
|
case "deny":
|
||||||
message = context.getString(R.string.su_deny_toast, policy.appName);
|
message = context.getString(R.string.su_deny_toast, policy.appName);
|
||||||
|
log.action = false;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
return;
|
return;
|
||||||
@ -53,10 +59,10 @@ public class SuReceiver extends BroadcastReceiver {
|
|||||||
if (pid < 0) return;
|
if (pid < 0) return;
|
||||||
command = intent.getStringExtra("command");
|
command = intent.getStringExtra("command");
|
||||||
if (command == null) return;
|
if (command == null) return;
|
||||||
SuLogEntry log = new SuLogEntry(policy);
|
|
||||||
log.toUid = toUid;
|
log.toUid = toUid;
|
||||||
log.fromPid = pid;
|
log.fromPid = pid;
|
||||||
log.command = command;
|
log.command = command;
|
||||||
|
log.date = new Date();
|
||||||
SuLogDatabaseHelper logDbHelper = new SuLogDatabaseHelper(context);
|
SuLogDatabaseHelper logDbHelper = new SuLogDatabaseHelper(context);
|
||||||
logDbHelper.addLog(log);
|
logDbHelper.addLog(log);
|
||||||
}
|
}
|
||||||
|
@ -16,8 +16,6 @@ import com.topjohnwu.magisk.Global;
|
|||||||
import com.topjohnwu.magisk.R;
|
import com.topjohnwu.magisk.R;
|
||||||
import com.topjohnwu.magisk.receivers.DownloadReceiver;
|
import com.topjohnwu.magisk.receivers.DownloadReceiver;
|
||||||
|
|
||||||
import java.io.ByteArrayInputStream;
|
|
||||||
import java.io.ByteArrayOutputStream;
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
13
app/src/main/res/drawable/ic_arrow.xml
Normal file
13
app/src/main/res/drawable/ic_arrow.xml
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:height="24dp"
|
||||||
|
android:viewportHeight="24"
|
||||||
|
android:viewportWidth="24"
|
||||||
|
android:width="24dp">
|
||||||
|
|
||||||
|
<path
|
||||||
|
android:fillColor="#000000"
|
||||||
|
android:pathData="M7.41 7.84L12 12.42l4.59-4.58L18 9.25l-6 6-6-6z" />
|
||||||
|
<path
|
||||||
|
android:pathData="M0-.75h24v24H0z" />
|
||||||
|
</vector>
|
@ -15,6 +15,7 @@
|
|||||||
android:id="@+id/tab"
|
android:id="@+id/tab"
|
||||||
app:tabPaddingEnd="20dp"
|
app:tabPaddingEnd="20dp"
|
||||||
app:tabPaddingStart="20dp"
|
app:tabPaddingStart="20dp"
|
||||||
|
android:elevation="4dp"
|
||||||
android:visibility="gone">
|
android:visibility="gone">
|
||||||
|
|
||||||
</android.support.design.widget.TabLayout>
|
</android.support.design.widget.TabLayout>
|
||||||
|
145
app/src/main/res/layout/list_item_sulog.xml
Normal file
145
app/src/main/res/layout/list_item_sulog.xml
Normal file
@ -0,0 +1,145 @@
|
|||||||
|
<?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="2dp"
|
||||||
|
android:layout_marginEnd="@dimen/card_horizontal_margin"
|
||||||
|
android:layout_marginStart="@dimen/card_horizontal_margin"
|
||||||
|
android:layout_marginTop="2dp"
|
||||||
|
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:padding="10dp">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/app_name"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:maxLines="1"
|
||||||
|
android:ellipsize="end"
|
||||||
|
android:textAppearance="?android:attr/textAppearanceSmall"
|
||||||
|
android:textColor="?android:attr/textColorPrimary"
|
||||||
|
android:textIsSelectable="false"
|
||||||
|
android:layout_weight="2" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:id="@+id/action"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:textAppearance="?android:attr/textAppearanceSmall"
|
||||||
|
android:textColor="?android:attr/textColorSecondary"
|
||||||
|
android:gravity="center_horizontal" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:id="@+id/time"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:textAppearance="?android:attr/textAppearanceSmall"
|
||||||
|
android:textColor="?android:attr/textColorSecondary"
|
||||||
|
android:gravity="center_horizontal" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/expand_layout"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:paddingTop="5dp"
|
||||||
|
android:paddingBottom="5dp"
|
||||||
|
android:gravity="center"
|
||||||
|
android:layout_gravity="center_horizontal">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:gravity="center_horizontal"
|
||||||
|
android:layout_weight="1">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:text="@string/pid"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:textColor="?android:attr/textColorSecondary"
|
||||||
|
android:textSize="12sp" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:id="@+id/fromPid"
|
||||||
|
android:textColor="?android:attr/textColorSecondary"
|
||||||
|
android:textSize="12sp" />
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:gravity="center_horizontal"
|
||||||
|
android:layout_weight="1">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:text="@string/target_uid"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:textColor="?android:attr/textColorSecondary"
|
||||||
|
android:textSize="12sp" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:id="@+id/toUid"
|
||||||
|
android:textColor="?android:attr/textColorSecondary"
|
||||||
|
android:textSize="12sp" />
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:gravity="center_horizontal"
|
||||||
|
android:layout_weight="2">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:text="@string/command"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:textColor="?android:attr/textColorSecondary"
|
||||||
|
android:textSize="12sp" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:id="@+id/command"
|
||||||
|
android:textColor="?android:attr/textColorSecondary"
|
||||||
|
android:gravity="start"
|
||||||
|
android:textSize="12sp" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
|
||||||
|
</android.support.v7.widget.CardView>
|
||||||
|
|
||||||
|
|
23
app/src/main/res/layout/list_item_sulog_group.xml
Normal file
23
app/src/main/res/layout/list_item_sulog_group.xml
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:padding="5dp">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="25dp"
|
||||||
|
android:src="@drawable/ic_arrow"
|
||||||
|
android:id="@+id/arrow"
|
||||||
|
android:layout_marginEnd="10dp" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:text="2017/1/1"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:id="@+id/date"
|
||||||
|
android:textColor="?android:attr/textColorPrimary"
|
||||||
|
android:textAppearance="?android:attr/textAppearanceSmall"
|
||||||
|
android:gravity="center_vertical" />
|
||||||
|
</LinearLayout>
|
@ -138,7 +138,7 @@
|
|||||||
|
|
||||||
<!--Superuser-->
|
<!--Superuser-->
|
||||||
<string name="su_request_title">Superuser-Anfrage</string>
|
<string name="su_request_title">Superuser-Anfrage</string>
|
||||||
<string name="deny">Gewähren</string>
|
<string name="deny">Gewähren%1$s</string>
|
||||||
<string name="grant">Verweigern%1$s</string>
|
<string name="grant">Verweigern%1$s</string>
|
||||||
<string name="su_warning">Gewährt vollen Zugriff auf das Gerät.\nVerweigere, wenn du dir unsicher bist!</string>
|
<string name="su_warning">Gewährt vollen Zugriff auf das Gerät.\nVerweigere, wenn du dir unsicher bist!</string>
|
||||||
<string name="forever">Dauerhaft</string>
|
<string name="forever">Dauerhaft</string>
|
||||||
|
@ -131,7 +131,7 @@
|
|||||||
|
|
||||||
<!--Superuser-->
|
<!--Superuser-->
|
||||||
<string name="su_request_title">Prośba dostępu Superusera</string>
|
<string name="su_request_title">Prośba dostępu Superusera</string>
|
||||||
<string name="deny">Odmów</string>
|
<string name="deny">Odmów%1$s</string>
|
||||||
<string name="grant">Przyznaj</string>
|
<string name="grant">Przyznaj</string>
|
||||||
<string name="su_warning">Udziela pełnego dostępu do urządzenia.\nOdmów jeśli nie jesteś pewien!</string>
|
<string name="su_warning">Udziela pełnego dostępu do urządzenia.\nOdmów jeśli nie jesteś pewien!</string>
|
||||||
<string name="forever">Zawsze</string>
|
<string name="forever">Zawsze</string>
|
||||||
|
@ -169,7 +169,9 @@
|
|||||||
<string name="su_revoke_title">Revoke?</string>
|
<string name="su_revoke_title">Revoke?</string>
|
||||||
<string name="su_revoke_msg">Confirm to revoke %1$s rights?</string>
|
<string name="su_revoke_msg">Confirm to revoke %1$s rights?</string>
|
||||||
|
|
||||||
<!-- TODO: Remove or change this placeholder text -->
|
<!--Superuser logs-->
|
||||||
<string name="hello_blank_fragment">Hello blank fragment</string>
|
<string name="pid">PID:\u0020</string>
|
||||||
|
<string name="target_uid">Target UID:\u0020</string>
|
||||||
|
<string name="command">Command:\u0020</string>
|
||||||
|
|
||||||
</resources>
|
</resources>
|
||||||
|
Loading…
Reference in New Issue
Block a user