package com.aero.control.fragments; import android.app.AlertDialog; import android.app.ProgressDialog; import android.content.Context; import android.content.DialogInterface; import android.content.SharedPreferences; import android.graphics.Point; import android.os.Bundle; import android.preference.Preference; import android.preference.PreferenceCategory; import android.preference.PreferenceManager; import android.preference.PreferenceScreen; import android.util.Log; import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; import android.view.View; import android.widget.EditText; import android.widget.TextView; import android.widget.Toast; import com.aero.control.AeroActivity; import com.aero.control.R; import com.aero.control.helpers.Android.CustomListPreference; import com.aero.control.helpers.Android.CustomPreference; import com.aero.control.helpers.FilePath; import com.aero.control.helpers.PreferenceHandler; import com.aero.control.helpers.Util; import com.github.amlcurran.showcaseview.ShowcaseView; import com.github.amlcurran.showcaseview.targets.Target; import java.io.FileOutputStream; import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.HashSet; /** * Created by Alexander Christ on 16.09.13. * Default Memory Fragment */ public class MemoryFragment extends PlaceHolderFragment implements Preference.OnPreferenceChangeListener { private PreferenceCategory PrefCat; private PreferenceScreen root; private boolean showDialog = true; private CustomPreference mDynFSync, mWriteBackControl, mFsync, mKSMSettings; private CustomPreference mFSTrimToggle, mDalvikSettings, mRandomSettings; private CustomListPreference mIOScheduler, mReadAHead; private String mFileSystem; private MemoryDalvikFragment mMemoryDalvikFragment; private PreferenceHandler mIOSchedulerHandler; private static final String MEMORY_SETTINGS_CATEGORY = "memory_settings"; private static final String IO_SETTINGS_CATEGORY = "io_scheduler_parameter"; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // Load the preferences from an XML resource addPreferencesFromResource(R.layout.memory_fragment); setHasOptionsMenu(true); ArrayList<CharSequence> readaheadValues = new ArrayList<CharSequence>(); String temp; root = this.getPreferenceScreen(); final PreferenceCategory memorySettingsCategory = (PreferenceCategory) findPreference(MEMORY_SETTINGS_CATEGORY); final PreferenceCategory ioSettingsCategory = (PreferenceCategory) findPreference(IO_SETTINGS_CATEGORY); mDynFSync = new CustomPreference(getActivity()); mDynFSync.setName("dynFsync"); mDynFSync.setTitle(R.string.pref_dynamic_fsync); mDynFSync.setSummary(R.string.pref_dynamic_fsync_sum); mDynFSync.setLookUpDefault(FilePath.DYANMIC_FSYNC); mDynFSync.setOrder(15); memorySettingsCategory.addPreference(mDynFSync); if ("1".equals(AeroActivity.shell.getInfo(FilePath.DYANMIC_FSYNC))) { mDynFSync.setClicked(true); mDynFSync.setSummary(R.string.enabled); } else if ("0".equals(AeroActivity.shell.getInfo(FilePath.DYANMIC_FSYNC))) { mDynFSync.setClicked(false); mDynFSync.setSummary(R.string.disabled); } else { if (memorySettingsCategory != null) memorySettingsCategory.removePreference(mDynFSync); } // FSync Toggle; mFsync = new CustomPreference(getActivity()); mFsync.setName("fsync"); mFsync.setTitle(R.string.pref_fsync); mFsync.setSummary(R.string.pref_fsync_sum); mFsync.setLookUpDefault(FilePath.FSYNC); mFsync.setOrder(14); memorySettingsCategory.addPreference(mFsync); temp = AeroActivity.shell.getInfo(FilePath.FSYNC); if ("Y".equals(temp) || "1".equals(temp)) { mFsync.setClicked(true); mFsync.setSummary(R.string.enabled); } else if ("N".equals(temp) || "0".equals(temp)) { mFsync.setClicked(false); mFsync.setSummary(R.string.disabled); } else { if (memorySettingsCategory != null) memorySettingsCategory.removePreference(mFsync); } mKSMSettings = new CustomPreference(getActivity()); mKSMSettings.setName("ksm"); mKSMSettings.setTitle(R.string.pref_ksm); mKSMSettings.setSummary(R.string.pref_ksm_sum); mKSMSettings.setLookUpDefault(FilePath.KSM_SETTINGS); mKSMSettings.setOrder(16); memorySettingsCategory.addPreference(mKSMSettings); temp = AeroActivity.shell.getInfo(FilePath.KSM_SETTINGS); if ("1".equals(temp)) { mKSMSettings.setClicked(true); mKSMSettings.setSummary(R.string.enabled); } else if ("2".equals(temp) || "0".equals(temp)) { mKSMSettings.setClicked(false); mKSMSettings.setSummary(R.string.disabled); } else { if (memorySettingsCategory != null) memorySettingsCategory.removePreference(mKSMSettings); } mWriteBackControl = new CustomPreference(getActivity()); mWriteBackControl.setName("writeback"); mWriteBackControl.setTitle(R.string.pref_dynamic_writeback); mWriteBackControl.setSummary(R.string.pref_dynamic_writeback_sum); mWriteBackControl.setLookUpDefault(FilePath.WRITEBACK); mWriteBackControl.setOrder(20); memorySettingsCategory.addPreference(mWriteBackControl); if ("1".equals(AeroActivity.shell.getInfo(FilePath.WRITEBACK))) { mWriteBackControl.setClicked(true); mWriteBackControl.setSummary(R.string.enabled); } else if ("0".equals(AeroActivity.shell.getInfo(FilePath.WRITEBACK))) { mWriteBackControl.setClicked(false); mWriteBackControl.setSummary(R.string.disabled); } else { if (memorySettingsCategory != null) memorySettingsCategory.removePreference(mWriteBackControl); } for (int i = 1; i <= 32; i++) { readaheadValues.add("" + (128 * i)); } mReadAHead = new CustomListPreference(getActivity()); mReadAHead.setName("read_ahead"); mReadAHead.setOrder(12); mReadAHead.setTitle(R.string.pref_readahead); mReadAHead.setDialogTitle(R.string.pref_readahead_dialog); mReadAHead.setEntries(readaheadValues.toArray(new CharSequence[0])); mReadAHead.setEntryValues(readaheadValues.toArray(new CharSequence[0])); mReadAHead.setValue(AeroActivity.shell.getInfo(FilePath.READAHEAD_PARAMETER)); mReadAHead.setSummary(AeroActivity.shell.getInfo(FilePath.READAHEAD_PARAMETER)); mReadAHead.setOnPreferenceChangeListener(this); memorySettingsCategory.addPreference(mReadAHead); mRandomSettings = (CustomPreference)findPreference("entropy_settings"); mRandomSettings.setOrder(22); mFSTrimToggle = (CustomPreference)findPreference("fstrim_toggle"); mFSTrimToggle.setOrder(25); mFSTrimToggle.setHideOnBoot(true); mDalvikSettings = (CustomPreference)findPreference("dalvik_settings"); mDalvikSettings.setOrder(30); mDalvikSettings.setHideOnBoot(true); mIOScheduler = new CustomListPreference(getActivity()); mIOScheduler.setName("io_scheduler_list"); mIOScheduler.setTitle(R.string.io_scheduler); mIOScheduler.setDialogTitle(R.string.io_scheduler); mIOScheduler.setEntries(AeroActivity.shell.getInfoArray(FilePath.GOV_IO_FILE, 0, 1)); mIOScheduler.setEntryValues(AeroActivity.shell.getInfoArray(FilePath.GOV_IO_FILE, 0, 1)); mIOScheduler.setValue(AeroActivity.shell.getInfoString(AeroActivity.shell.getInfo(FilePath.GOV_IO_FILE))); mIOScheduler.setSummary(AeroActivity.shell.getInfoString(AeroActivity.shell.getInfo(FilePath.GOV_IO_FILE))); mIOScheduler.setDialogIcon(R.drawable.device_drive); mIOScheduler.setOnPreferenceChangeListener(this); ioSettingsCategory.addPreference(mIOScheduler); mIOSchedulerHandler = new PreferenceHandler(getActivity(), ioSettingsCategory, getPreferenceManager()); mIOSchedulerHandler.addInvisiblePreference(); if (showDialog) { Runnable runnable = new Runnable() { @Override public void run() { // Ensure only devices with this special path are checked; final String fileMount[] = AeroActivity.shell.getInfo("/proc/mounts", false); boolean fileMountCheck = false; for (String tmp : fileMount) { if (tmp.contains("/dev/block/mmcblk1p25")) { fileMountCheck = true; break; } } showDialog = false; if (fileMountCheck) { final String fileJournal = AeroActivity.shell.getRootInfo("tune2fs -l", "/dev/block/mmcblk1p25"); final boolean fileSystemCheck = fileJournal.length() != 0 && fileJournal.contains("has_journal"); getActivity().runOnUiThread(new Runnable() { @Override public void run() { if (!fileSystemCheck) { AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); LayoutInflater inflater = getActivity().getLayoutInflater(); // Just reuse aboutScreen, because its Linear and has a TextView View layout = inflater.inflate(R.layout.about_screen, null); TextView aboutText = (TextView) (layout != null ? layout.findViewById(R.id.aboutScreen) : null); builder.setTitle(R.string.has_journal_dialog_header); if (aboutText != null) { aboutText.setText(getText(R.string.has_journal_dialog)); aboutText.setTextSize(13); } builder.setView(layout) .setPositiveButton(R.string.got_it, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int id) { } }); builder.show(); } } }); } } }; Thread checkThread = new Thread(runnable); checkThread.start(); } } @Override public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); // Set up our file; int output = 0; if (AeroActivity.genHelper.doesExist(getActivity().getFilesDir().getAbsolutePath() + "/" + FilePath.FILENAME)) { output = 1; } // Only show showcase once; if (output == 0) DrawFirstStart(R.string.showcase_memory_fragment_trim, R.string.showcase_memory_fragment_trim_sum, FilePath.FILENAME); } // Create our options menu; @Override public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { inflater.inflate(R.menu.memory_menu, menu); super.onCreateOptionsMenu(menu, inflater); } @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case R.id.action_io_settings: loadIOParameter(); break; } return super.onOptionsItemSelected(item); } @Override public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference preference) { CustomPreference cusPref = null; if (preference == mDynFSync) { mDynFSync.setClicked(!mDynFSync.isClicked()); if (mDynFSync.isClicked()) AeroActivity.shell.setRootInfo("1", FilePath.DYANMIC_FSYNC); else AeroActivity.shell.setRootInfo("0", FilePath.DYANMIC_FSYNC); cusPref = (CustomPreference) preference; } else if (preference == mFsync) { mFsync.setClicked(!mFsync.isClicked()); if (mFsync.isClicked()) AeroActivity.shell.setRootInfo("1", FilePath.FSYNC); else AeroActivity.shell.setRootInfo("0", FilePath.FSYNC); cusPref = (CustomPreference) preference; } else if (preference == mKSMSettings) { mKSMSettings.setClicked(!mKSMSettings.isClicked()); if (mKSMSettings.isClicked()) AeroActivity.shell.setRootInfo("1", FilePath.KSM_SETTINGS); else AeroActivity.shell.setRootInfo("0", FilePath.KSM_SETTINGS); cusPref = (CustomPreference) preference; } else if (preference == mWriteBackControl) { mWriteBackControl.setClicked(!mWriteBackControl.isClicked()); if (mWriteBackControl.isClicked()) AeroActivity.shell.setRootInfo("1", FilePath.WRITEBACK); else AeroActivity.shell.setRootInfo("0", FilePath.WRITEBACK); cusPref = (CustomPreference)preference; } else if (preference == mFSTrimToggle) { fsTrimToggleClick(); } else if (preference == mDalvikSettings) { if (mMemoryDalvikFragment == null) mMemoryDalvikFragment = new MemoryDalvikFragment(); AeroActivity.mHandler.postDelayed(new Runnable() { @Override public void run() { getFragmentManager() .beginTransaction() .setCustomAnimations(android.R.animator.fade_in, android.R.animator.fade_out) .replace(R.id.content_frame, mMemoryDalvikFragment) .addToBackStack("Memory") .commit(); } },AeroActivity.genHelper.getDefaultDelay()); } else if (preference == mRandomSettings) { onRandomClick(); } // If its checked, we want to save it; if (cusPref != null) { if (cusPref.isChecked()) { SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(getActivity()); SharedPreferences.Editor editor = sharedPrefs.edit(); String state = cusPref.isClicked() ? "1" : "0"; editor.putString(cusPref.getName(), state).commit(); } } return true; } @Override public boolean onPreferenceChange(Preference preference, Object newValue) { String value = (String) newValue; if (preference == mIOScheduler) { mIOScheduler.setSummary(value); AeroActivity.shell.setRootInfo(value, FilePath.GOV_IO_FILE); // Kill everything with fire; if (PrefCat != null) root.removePreference(PrefCat); } else if (preference == mReadAHead) { AeroActivity.shell.setRootInfo(value, FilePath.READAHEAD_PARAMETER); mReadAHead.setSummary(value); } else { return false; } return true; } private void onRandomClick() { AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); LayoutInflater inflater = getActivity().getLayoutInflater(); // Inflate our layout and build up the UI; View layout = inflater.inflate(R.layout.memory_random, null); TextView txtRandomRead = (TextView) layout.findViewById(R.id.random_read); TextView txtRandomWrite = (TextView) layout.findViewById(R.id.random_write); final EditText editRandomRead = (EditText) layout.findViewById(R.id.random_read_value); final EditText editRandomWrite = (EditText) layout.findViewById(R.id.random_write_value); txtRandomRead.setText(Util.getLastSysValue(FilePath.RANDOM_READ_WAKEUP)); txtRandomWrite.setText(Util.getLastSysValue(FilePath.RANDOM_WRITE_WAKEUP)); editRandomRead.setText(AeroActivity.shell.getFastInfo(FilePath.RANDOM_READ_WAKEUP)); editRandomWrite.setText(AeroActivity.shell.getFastInfo(FilePath.RANDOM_WRITE_WAKEUP)); builder.setIcon(R.drawable.puzzle); // Display the current available entropy as well as the pool size; builder.setTitle(getText(R.string.pref_entropy_settings) + " (" + AeroActivity.shell.getFastInfo(FilePath.RANDOM_POOL_AVAIL) + "/" + AeroActivity.shell.getFastInfo(FilePath.RANDOM_POOL_SIZE) + ")"); builder.setView(layout); builder.setPositiveButton(R.string.save, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { // Build up our commands; String[] cmds = { "echo " + editRandomRead.getText() + " > " + FilePath.RANDOM_READ_WAKEUP, "echo " + editRandomWrite.getText() + " > " + FilePath.RANDOM_WRITE_WAKEUP, }; AeroActivity.shell.setRootInfo(cmds); if (mRandomSettings.isChecked()) { SharedPreferences preference = PreferenceManager.getDefaultSharedPreferences(getActivity().getBaseContext()); // We still want to write it here, since we can disable it later; preference.edit().putStringSet(mRandomSettings.getKey(), new HashSet<String>(Arrays.asList(cmds))).commit(); } } }); builder.setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { // Do nothing } }); builder.show(); } private void fsTrimToggleClick() { // If the library doesn't exist, skip through; if (!(AeroActivity.genHelper.doesExist("/system/xbin/fstrim"))) { Toast.makeText(getActivity(), R.string.pref_fstrim_no_busybox, Toast.LENGTH_SHORT).show(); return; } if (mFileSystem == null) mFileSystem = AeroActivity.shell.getRootInfo("mount", ""); final CharSequence[] system = {" /system ", " /data ", " /cache "}; final ArrayList<String> fs = new ArrayList<String>(); int tmp; int count = 0; String temp; for (CharSequence a : system) { if (mFileSystem.contains(a)) { tmp = mFileSystem.indexOf(a.toString()); temp = mFileSystem.substring(tmp, tmp + a.length() + 4).replace(a, ""); if (temp.equals("ext3") || temp.equals("ext4")) { fs.add(a.toString()); count++; } } } final CharSequence[] fsystem = fs.toArray(new CharSequence[0]); // If the device doesn't support trimable filesystems; if (count == 0) { Toast.makeText(getActivity(), R.string.unavailable, Toast.LENGTH_SHORT).show(); return; } AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); final ProgressDialog update = new ProgressDialog(getActivity()); builder.setTitle(R.string.pref_fstrim); builder.setIcon(R.drawable.file_exe); builder.setItems(fsystem, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int item) { final String b = (String)fsystem[item]; update.setProgressStyle(ProgressDialog.STYLE_SPINNER); update.setCancelable(false); update.setIndeterminate(true); update.setIndeterminateDrawable(getResources().getDrawable(R.drawable.spinner_animation)); update.setMessage(Util.getRandomLoadingText(getActivity())); update.show(); AeroActivity.shell.remountSystem(); Runnable runnable = new Runnable() { @Override public void run() { try { // Set up the root-command; AeroActivity.shell.getRootInfo("fstrim -v", b); // Sleep the current thread and exit dialog; Thread.sleep(2000); } catch (Exception e) { Log.e("Aero", "An error occurred while trimming.", e); } getActivity().runOnUiThread(new Runnable() { @Override public void run() { update.dismiss(); } }); } }; Thread trimThread = new Thread(runnable); if (!trimThread.isAlive()) trimThread.start(); } }).show(); } public void DrawFirstStart(int header, int content, String filename) { try { FileOutputStream fos = getActivity().openFileOutput(filename, Context.MODE_PRIVATE); fos.write("1".getBytes()); fos.close(); } catch (IOException e) { Log.e("Aero", "Could not save file. ", e); } Target homeTarget = new Target() { @Override public Point getPoint() { return new Point(200, 200); } }; new ShowcaseView.Builder(getActivity()) .setContentTitle(header) .setContentText(content) .setTarget(homeTarget) .build(); } private void loadIOParameter() { // First remove our invisible element; mIOSchedulerHandler.removeInvisiblePreference(); try { String completeParamterList[] = AeroActivity.shell.getDirInfo(FilePath.GOV_IO_PARAMETER, true); // If there are already some entries, kill them all (with fire) if (PrefCat != null) root.removePreference(PrefCat); if (completeParamterList.length == 0) { Toast.makeText(getActivity(), R.string.pref_io_scheduler_no_parameter, Toast.LENGTH_LONG).show(); return; } PrefCat = new PreferenceCategory(getActivity()); PrefCat.setTitle(R.string.pref_io_scheduler); root.addPreference(PrefCat); try { Thread.sleep(500); } catch (InterruptedException e) { Log.e("Aero", "Something interrupted the main Thread, try again.", e); } PreferenceHandler h = new PreferenceHandler(getActivity(), PrefCat, getPreferenceManager()); h.genPrefFromDictionary(completeParamterList, FilePath.GOV_IO_PARAMETER); // Probably the wrong place, should be in getDirInfo ? } catch (NullPointerException e) { Toast.makeText(getActivity(), R.string.pref_io_scheduler_no_parameter, Toast.LENGTH_LONG).show(); root.removePreference(PrefCat); Log.e("Aero", "There isn't any folder i can check. Does this governor has parameters?", e); } } }