Module fragment with menu; remove and disable buttons

This commit is contained in:
dvdandroid 2016-08-21 16:08:45 +02:00 committed by topjohnwu
parent f5e53cd60f
commit 31b552ab51
20 changed files with 163 additions and 176 deletions

View File

@ -1 +0,0 @@
MagiskManager

View File

@ -1,22 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="CompilerConfiguration">
<option name="DEFAULT_COMPILER" value="Javac" />
<resourceExtensions />
<wildcardResourcePatterns>
<entry name="!?*.java" />
<entry name="!?*.form" />
<entry name="!?*.class" />
<entry name="!?*.groovy" />
<entry name="!?*.scala" />
<entry name="!?*.flex" />
<entry name="!?*.kt" />
<entry name="!?*.clj" />
</wildcardResourcePatterns>
<annotationProcessing>
<profile default="true" name="Default" enabled="true">
<processorPath useClasspath="true" />
</profile>
</annotationProcessing>
</component>
</project>

View File

@ -1,6 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="Encoding">
<file url="PROJECT" charset="UTF-8" />
</component>
</project>

View File

@ -1,28 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="GradleSettings">
<option name="linkedExternalProjectsSettings">
<GradleProjectSettings>
<option name="distributionType" value="LOCAL" />
<option name="externalProjectPath" value="$PROJECT_DIR$" />
<option name="gradleHome" value="C:\Program Files\Android-Studio\gradle\gradle-2.14.1" />
<option name="modules">
<set>
<option value="$PROJECT_DIR$" />
<option value="$PROJECT_DIR$/app" />
<option value="$PROJECT_DIR$/lib" />
<option value="$PROJECT_DIR$/lib/RootCommands" />
</set>
</option>
<option name="myModules">
<set>
<option value="$PROJECT_DIR$" />
<option value="$PROJECT_DIR$/app" />
<option value="$PROJECT_DIR$/lib" />
<option value="$PROJECT_DIR$/lib/RootCommands" />
</set>
</option>
</GradleProjectSettings>
</option>
</component>
</project>

View File

@ -1,62 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="EntryPointsManager">
<entry_points version="2.0" />
</component>
<component name="NullableNotNullManager">
<option name="myDefaultNullable" value="android.support.annotation.Nullable" />
<option name="myDefaultNotNull" value="android.support.annotation.NonNull" />
<option name="myNullables">
<value>
<list size="4">
<item index="0" class="java.lang.String" itemvalue="org.jetbrains.annotations.Nullable" />
<item index="1" class="java.lang.String" itemvalue="javax.annotation.Nullable" />
<item index="2" class="java.lang.String" itemvalue="edu.umd.cs.findbugs.annotations.Nullable" />
<item index="3" class="java.lang.String" itemvalue="android.support.annotation.Nullable" />
</list>
</value>
</option>
<option name="myNotNulls">
<value>
<list size="4">
<item index="0" class="java.lang.String" itemvalue="org.jetbrains.annotations.NotNull" />
<item index="1" class="java.lang.String" itemvalue="javax.annotation.Nonnull" />
<item index="2" class="java.lang.String" itemvalue="edu.umd.cs.findbugs.annotations.NonNull" />
<item index="3" class="java.lang.String" itemvalue="android.support.annotation.NonNull" />
</list>
</value>
</option>
</component>
<component name="ProjectLevelVcsManager" settingsEditedManually="false">
<OptionsSetting value="true" id="Add" />
<OptionsSetting value="true" id="Remove" />
<OptionsSetting value="true" id="Checkout" />
<OptionsSetting value="true" id="Update" />
<OptionsSetting value="true" id="Status" />
<OptionsSetting value="true" id="Edit" />
<ConfirmationsSetting value="0" id="Add" />
<ConfirmationsSetting value="0" id="Remove" />
</component>
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_7" assert-keyword="true" jdk-15="true" project-jdk-name="1.8" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/build/classes" />
</component>
<component name="ProjectType">
<option name="id" value="Android" />
</component>
<component name="masterDetails">
<states>
<state key="ProjectJDKs.UI">
<settings>
<last-edited>1.8</last-edited>
<splitter-proportions>
<option name="proportions">
<list>
<option value="0.2" />
</list>
</option>
</splitter-proportions>
</settings>
</state>
</states>
</component>
</project>

View File

@ -1,11 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/MagiskManager.iml" filepath="$PROJECT_DIR$/MagiskManager.iml" />
<module fileurl="file://$PROJECT_DIR$/lib/RootCommands/RootCommands.iml" filepath="$PROJECT_DIR$/lib/RootCommands/RootCommands.iml" />
<module fileurl="file://$PROJECT_DIR$/app/app.iml" filepath="$PROJECT_DIR$/app/app.iml" />
<module fileurl="file://$PROJECT_DIR$/lib/lib.iml" filepath="$PROJECT_DIR$/lib/lib.iml" />
</modules>
</component>
</project>

View File

@ -1,12 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="RunConfigurationProducerService">
<option name="ignoredProducers">
<set>
<option value="org.jetbrains.plugins.gradle.execution.test.runner.AllInPackageGradleConfigurationProducer" />
<option value="org.jetbrains.plugins.gradle.execution.test.runner.TestClassGradleConfigurationProducer" />
<option value="org.jetbrains.plugins.gradle.execution.test.runner.TestMethodGradleConfigurationProducer" />
</set>
</option>
</component>
</project>

View File

@ -1,5 +1,7 @@
package com.topjohnwu.magisk.model;
import com.topjohnwu.magisk.ui.utils.Utils;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
@ -8,6 +10,10 @@ public class Module {
private final boolean isValid;
private final boolean isCache;
private File mRemoveFile;
private File mDisableFile;
private File mPropFile;
private String mName;
@ -18,9 +24,11 @@ public class Module {
this.isCache = file.getPath().contains("cache");
this.isValid = new File(file + "/module.prop").exists();
if (isValid) {
mPropFile = new File(file + "/module.prop");
}
if (!isValid) return;
mPropFile = new File(file + "/module.prop");
mRemoveFile = new File(file + "/remove");
mDisableFile = new File(file + "/disable");
}
public boolean isValid() {
@ -43,6 +51,14 @@ public class Module {
return mDescription;
}
public void createRemoveFile() {
Utils.executeCommand("echo \"\" > " + mRemoveFile.getPath());
}
public void createDisableFile() {
Utils.executeCommand("echo \"\" > " + mDisableFile.getPath());
}
public void parse() throws Exception {
BufferedReader reader = new BufferedReader(new FileReader(mPropFile));
String line;

View File

@ -0,0 +1,9 @@
package com.topjohnwu.magisk.rv;
import android.view.View;
public interface ItemClickListener {
void onItemClick(View view, int position);
}

View File

@ -4,6 +4,7 @@ import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import com.topjohnwu.magisk.R;
@ -17,37 +18,34 @@ import butterknife.ButterKnife;
public class ModulesAdapter extends RecyclerView.Adapter<ModulesAdapter.ViewHolder> {
private final List<Module> mList;
private final ItemClickListener mListener;
public ModulesAdapter(List<Module> mList) {
this.mList = mList;
public ModulesAdapter(List<Module> list, ItemClickListener listener) {
this.mList = list;
this.mListener = listener;
}
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.row, parent, false);
/*FIXME
final ViewHolder viewHolder = new ViewHolder(view);
view.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
listener.onItemClick(viewHolder.getAdapterPosition());
}
});*/
return new ViewHolder(view);
}
@Override
public void onBindViewHolder(ViewHolder holder, int position) {
public void onBindViewHolder(final ViewHolder holder, int position) {
Module module = mList.get(position);
holder.title.setText(module.getName());
holder.versionName.setText(module.getVersion());
holder.description.setText(module.getDescription());
//FIXME
//holder.cache.setText("" + module.isCache());
holder.overflowButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
mListener.onItemClick(holder.overflowButton, holder.getAdapterPosition());
}
});
}
@Override
@ -60,7 +58,7 @@ public class ModulesAdapter extends RecyclerView.Adapter<ModulesAdapter.ViewHold
@BindView(R.id.title) TextView title;
@BindView(R.id.version_name) TextView versionName;
@BindView(R.id.description) TextView description;
//@BindView(R.id.cache) TextView cache;
@BindView(R.id.overflow) ImageView overflowButton;
public ViewHolder(View itemView) {
super(itemView);

View File

@ -1,21 +1,27 @@
package com.topjohnwu.magisk.ui;
import android.app.ProgressDialog;
import android.os.AsyncTask;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.design.widget.Snackbar;
import android.support.v7.widget.PopupMenu;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ProgressBar;
import com.topjohnwu.magisk.R;
import com.topjohnwu.magisk.model.Module;
import com.topjohnwu.magisk.rv.ItemClickListener;
import com.topjohnwu.magisk.rv.ModulesAdapter;
import com.topjohnwu.magisk.ui.utils.Utils;
import java.io.File;
import java.io.FileFilter;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
@ -28,31 +34,64 @@ public class ModulesFragment extends android.support.v4.app.Fragment {
private static final String MAGISK_CACHE_PATH = "/cache/magisk";
@BindView(R.id.recyclerView) RecyclerView recyclerView;
@BindView(R.id.progressBar) ProgressBar progressBar;
private List<Module> listModules = new ArrayList<>();
private ItemClickListener moduleActions = new ItemClickListener() {
@Override
public void onItemClick(final View view, final int position) {
PopupMenu popup = new PopupMenu(getContext(), view);
try {
Field[] fields = popup.getClass().getDeclaredFields();
for (Field field : fields) {
if ("mPopup".equals(field.getName())) {
field.setAccessible(true);
Object menuPopupHelper = field.get(popup);
Class<?> classPopupHelper = Class.forName(menuPopupHelper.getClass().getName());
Method setForceIcons = classPopupHelper.getMethod("setForceShowIcon", boolean.class);
setForceIcons.invoke(menuPopupHelper, true);
break;
}
}
} catch (Exception ignored) {
}
popup.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
@Override
public boolean onMenuItemClick(MenuItem item) {
switch (item.getItemId()) {
case R.id.remove:
listModules.get(position).createRemoveFile();
Snackbar.make(view, R.string.remove_file_created, Snackbar.LENGTH_SHORT).show();
break;
case R.id.disable:
listModules.get(position).createDisableFile();
Snackbar.make(view, R.string.disable_file_created, Snackbar.LENGTH_SHORT).show();
break;
}
return false;
}
});
popup.inflate(R.menu.module_popup);
popup.show();
}
};
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.modules_fragment, container, false);
ButterKnife.bind(this, v);
View view = inflater.inflate(R.layout.modules_fragment, container, false);
ButterKnife.bind(this, view);
new CheckFolders().execute();
return v;
return view;
}
private class CheckFolders extends AsyncTask<Void, Integer, Boolean> {
private ProgressDialog progress;
@Override
protected void onPreExecute() {
super.onPreExecute();
progress = ProgressDialog.show(getContext(), null, getString(R.string.loading), true, false);
}
@Override
protected Boolean doInBackground(Void... voids) {
File[] magisk = new File(MAGISK_PATH).listFiles(new FileFilter() {
@ -104,9 +143,9 @@ public class ModulesFragment extends android.support.v4.app.Fragment {
protected void onPostExecute(Boolean result) {
super.onPostExecute(result);
progress.dismiss();
progressBar.setVisibility(View.GONE);
recyclerView.setAdapter(new ModulesAdapter(listModules));
recyclerView.setAdapter(new ModulesAdapter(listModules, moduleActions));
}
}

View 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="#757575"
android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM4,12c0,-4.42 3.58,-8 8,-8 1.85,0 3.55,0.63 4.9,1.69L5.69,16.9C4.63,15.55 4,13.85 4,12zM12,20c-1.85,0 -3.55,-0.63 -4.9,-1.69L18.31,7.1C19.37,8.45 20,10.15 20,12c0,4.42 -3.58,8 -8,8z"/>
</vector>

View 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="#757575"
android:pathData="M6,19c0,1.1 0.9,2 2,2h8c1.1,0 2,-0.9 2,-2V7H6v12zM19,4h-3.5l-1,-1h-5l-1,1H5v2h14V4z"/>
</vector>

View File

@ -0,0 +1,25 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2015 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<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:pathData="M12,8c1.1,0 2,-0.9 2,-2s-0.9,-2 -2,-2c-1.1,0 -2,0.9 -2,2S10.9,8 12,8zM12,10c-1.1,0 -2,0.9 -2,2s0.9,2 2,2c1.1,0 2,-0.9 2,-2S13.1,10 12,10zM12,16c-1.1,0 -2,0.9 -2,2s0.9,2 2,2c1.1,0 2,-0.9 2,-2S13.1,16 12,16z"
android:fillColor="#757575"/>
</vector>

View File

@ -6,6 +6,12 @@
android:layout_marginTop="?attr/actionBarSize"
android:orientation="vertical">
<ProgressBar
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/progressBar"
android:layout_gravity="center"/>
<android.support.v7.widget.RecyclerView
android:id="@+id/recyclerView"
android:layout_width="match_parent"

View File

@ -73,7 +73,7 @@
android:focusable="false"
android:gravity="center"
android:padding="3dp"
android:src="@drawable/root"/>
android:src="@drawable/ic_menu_overflow_material"/>
</LinearLayout>

View File

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="@+id/remove"
android:icon="@drawable/ic_delete"
android:title="@string/remove"/>
<item
android:id="@+id/disable"
android:icon="@drawable/ic_block"
android:title="@string/disable"/>
</menu>

View File

@ -28,4 +28,8 @@
<string name="root">Root</string>
<string name="modules">Modules</string>
<string name="log">Log</string>
<string name="remove">Remove</string>
<string name="disable">Disable</string>
<string name="remove_file_created">Module will be removed at next reboot</string>
<string name="disable_file_created">Module will be disabled at next reboot</string>
</resources>