/* * Copyright (C) 2013 - 2014 Alexander "Evisceration" Martinz * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. * */ package org.namelessrom.devicecontrol.modules.editor; import android.app.Activity; import android.app.AlertDialog; import android.content.DialogInterface; import android.os.Bundle; import android.text.TextUtils; import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; import android.widget.AdapterView; import android.widget.ArrayAdapter; import android.widget.EditText; import android.widget.LinearLayout; import android.widget.ListView; import android.widget.Spinner; import android.widget.TextView; import org.namelessrom.devicecontrol.DeviceConstants; import org.namelessrom.devicecontrol.R; import org.namelessrom.devicecontrol.utils.Scripts; import org.namelessrom.devicecontrol.utils.ShellOutput; import org.namelessrom.devicecontrol.utils.Utils; import java.util.ArrayList; import java.util.Collections; import at.amartinz.execution.BusyBox; import timber.log.Timber; public class BuildPropEditorFragment extends BaseEditorFragment { //============================================================================================== // Fields //============================================================================================== private static final int REMOVE = 100; private static final int SAVE = 200; private ListView mListView; private LinearLayout mLoadingView; private PropAdapter mAdapter = null; private final ArrayList<Prop> mProps = new ArrayList<>(); //============================================================================================== // Overridden Methods //============================================================================================== @Override protected int getFragmentId() { return DeviceConstants.ID_TOOLS_EDITORS_BUILD_PROP; } @Override public void onViewCreated(View view, Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); Utils.getCommandResult(BuildPropEditorFragment.this, -1, "cat /system/build.prop", true); } @Override public View onCreateView(final LayoutInflater inflater, final ViewGroup container, final Bundle savedInstanceState) { super.onCreate(savedInstanceState); setHasOptionsMenu(true); final View view = inflater.inflate(R.layout.tools_prop_list, container, false); mListView = (ListView) view.findViewById(R.id.proplist); mListView.setOnItemClickListener(this); mListView.setFastScrollEnabled(true); mListView.setFastScrollAlwaysVisible(true); mListView.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() { @Override public boolean onItemLongClick(final AdapterView<?> adapterView, final View view , final int i, final long l) { final Prop p = (Prop) adapterView.getItemAtPosition(i); if (p != null && !p.getName().contains("fingerprint")) { makeDialog(R.string.delete_property, getString(R.string.delete_property_message, p.getName()), p); } return true; } }); mLoadingView = (LinearLayout) view.findViewById(R.id.loading); final LinearLayout emptyView = (LinearLayout) view.findViewById(R.id.nofiles); mListView.setEmptyView(emptyView); return view; } @Override protected PropAdapter getAdapter() { return mAdapter; } @Override public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { super.onCreateOptionsMenu(menu, inflater); // remove unused items menu.removeItem(R.id.menu_action_apply); menu.removeItem(R.id.menu_action_toggle); } @Override public boolean onOptionsItemSelected(final MenuItem item) { final int id = item.getItemId(); switch (id) { case R.id.menu_action_add: { editBuildPropDialog(null); return true; } } return false; } @Override public void onItemClick(AdapterView<?> parent, View view, int position, long row) { if (mAdapter == null) { return; } final Prop p = mAdapter.getItem(position); if (p != null) { if (!p.getName().contains("fingerprint")) { editBuildPropDialog(p); } } } @Override public void onShellOutput(final ShellOutput shellOutput) { switch (shellOutput.id) { case SAVE: case REMOVE: Utils.remount("/system", "ro"); Collections.sort(mProps); if (mAdapter != null) { mAdapter.notifyDataSetChanged(); } break; default: Timber.v("onReadPropsCompleted: %s", shellOutput.output); if (isAdded()) { loadBuildProp(shellOutput.output); } else { Timber.w("Not attached!"); } break; } } //============================================================================================== // Methods //============================================================================================== private void loadBuildProp(final String s) { mProps.clear(); final String p[] = s.split("\n"); for (String aP : p) { if (TextUtils.isEmpty(aP) || aP.contains("#") || !aP.contains("=")) { continue; } aP = aP.trim(); if (aP.length() <= 0) { continue; } aP = aP.replace("[", "").replace("]", ""); final String pp[] = aP.split("="); final Prop prop; if (pp.length >= 2) { final StringBuilder sb = new StringBuilder(); for (int i = 2; i < pp.length; i++) { sb.append('=').append(pp[i]); } prop = new Prop(pp[0].trim(), pp[1].trim() + sb.toString()); } else { prop = new Prop(pp[0].trim(), ""); } if (!mProps.contains(prop)) { mProps.add(prop); } } Collections.sort(mProps); mLoadingView.setVisibility(View.GONE); mAdapter = new PropAdapter(getActivity(), mProps); mListView.setAdapter(mAdapter); } //============================================================================================== // Dialogs //============================================================================================== private boolean mSpinnerHelper; private void editBuildPropDialog(final Prop p) { final Activity activity = getActivity(); if (activity == null) { return; } final View editDialog = LayoutInflater.from(getActivity()).inflate(R.layout.dialog_build_prop, null, false); final TextView tvName = (TextView) editDialog.findViewById(R.id.prop_name_tv); final EditText etName = (EditText) editDialog.findViewById(R.id.prop_name); final EditText etValue = (EditText) editDialog.findViewById(R.id.prop_value); final Spinner sp = (Spinner) editDialog.findViewById(R.id.preset_spinner); final LinearLayout lpresets = (LinearLayout) editDialog.findViewById(R.id.prop_presets); final ArrayAdapter<CharSequence> vAdapter = new ArrayAdapter<>(activity, android.R.layout.simple_spinner_item); vAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); vAdapter.clear(); final String title; if (p != null) { title = getString(R.string.edit_property); final String v = p.getVal(); lpresets.setVisibility(View.GONE); if ("0".equals(v) || "1".equals(v)) { vAdapter.add("0"); vAdapter.add("1"); lpresets.setVisibility(View.VISIBLE); sp.setAdapter(vAdapter); } else if ("true".equalsIgnoreCase(v) || "false".equalsIgnoreCase(v)) { vAdapter.add("false"); vAdapter.add("true"); lpresets.setVisibility(View.VISIBLE); sp.setAdapter(vAdapter); } tvName.setText(p.getName()); etName.setText(p.getName()); etName.setVisibility(View.GONE); etValue.setText(p.getVal()); } else { title = getString(R.string.add_property); vAdapter.add(""); vAdapter.add("0"); vAdapter.add("1"); vAdapter.add("true"); vAdapter.add("false"); sp.setAdapter(vAdapter); lpresets.setVisibility(View.VISIBLE); etName.setVisibility(View.VISIBLE); } // fuuuu, stupid spinner bugs mSpinnerHelper = false; sp.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() { @Override public void onItemSelected(AdapterView<?> parentView, View selectedItemView, int position, long id) { if (!mSpinnerHelper) { mSpinnerHelper = true; return; } final Object item = sp.getSelectedItem(); if (item != null) { etValue.setText(item.toString().trim()); } } @Override public void onNothingSelected(AdapterView<?> parentView) { } }); new AlertDialog.Builder(activity) .setTitle(title) .setView(editDialog) .setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { dialog.cancel(); } } ) .setPositiveButton(R.string.save, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { if (etValue.getText() == null) { return; } final String name; final String value; if (p != null) { name = p.getName(); value = etValue.getText().toString().trim(); p.setVal(value); } else { if (etName.getText() == null) { return; } name = etName.getText().toString().trim(); if (name.length() <= 0) { return; } value = etValue.getText().toString().trim(); mProps.add(new Prop(name, value)); } final String addCmd = Scripts.addOrUpdate(name, value); final String cmd = BusyBox.callBusyBoxApplet("mount", "-o rw,remount /system;") + addCmd; Utils.getCommandResult(BuildPropEditorFragment.this, SAVE, cmd); } }).show(); } private void makeDialog(final int title, final String msg, final Prop prop) { final Activity activity = getActivity(); if (activity == null) { return; } new AlertDialog.Builder(activity) .setTitle(title) .setMessage(msg) .setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int id) { dialog.cancel(); } } ) .setPositiveButton(android.R.string.yes, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { Utils.remount("/system", "rw"); final String cmd = Scripts.removeProperty(prop.getName()); Utils.getCommandResult(BuildPropEditorFragment.this, REMOVE, cmd); if (mAdapter != null) { mAdapter.remove(prop); } } }).show(); } }