package com.androguide.apkreator.fragments;
import android.app.Activity;
import android.content.SharedPreferences;
import android.graphics.Color;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.preference.PreferenceManager;
import android.support.v4.app.Fragment;
import android.support.v7.app.ActionBarActivity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemSelectedListener;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.SeekBar;
import android.widget.Spinner;
import android.widget.TextView;
import com.androguide.apkreator.R;
import com.androguide.apkreator.helpers.CMDProcessor.CMDProcessor;
import com.androguide.apkreator.helpers.CPUHelper;
import com.androguide.apkreator.helpers.Helpers;
import com.echo.holographlibrary.Line;
import com.echo.holographlibrary.LineGraph;
import com.echo.holographlibrary.LinePoint;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
public class CPUControl extends Fragment implements
SeekBar.OnSeekBarChangeListener {
private ActionBarActivity fa;
Button Tweaks;
private static SharedPreferences preferences;
public static final String TAG = "CPUSettings";
public static final String CURRENT_CPU = "/sys/devices/system/cpu/cpu0/cpufreq/scaling_cur_freq";
public static final String MAX_FREQ = "/sys/devices/system/cpu/cpu0/cpufreq/scaling_max_freq";
public static final String TEGRA_MAX_FREQ = "/sys/module/cpu_tegra/parameters/cpu_user_cap";
public static final String MIN_FREQ = "/sys/devices/system/cpu/cpu0/cpufreq/scaling_min_freq";
public static final String STEPS = "/sys/devices/system/cpu/cpu0/cpufreq/scaling_available_frequencies";
public static final String GOVERNORS_LIST = "/sys/devices/system/cpu/cpu0/cpufreq/scaling_available_governors";
public static final String GOVERNOR = "/sys/devices/system/cpu/cpu0/cpufreq/scaling_governor";
public static final String IO_SCHEDULER = "/sys/block/mmcblk0/queue/scheduler";
public static final String NUM_OF_CPUS = "/sys/devices/system/cpu/present";
public static final String MAX_CPU = "max_cpu";
public static final String MIN_CPU = "min_cpu";
public static final String GOV_PREF = "gov";
public static final String IO_PREF = "io";
public static final String SOB = "cpu_boot";
private static LineGraph graph;
private static Line line;
private static int currX = 0;
private static int counter = 0;
private static TextView mCurFreq;
private SeekBar mMaxSlider;
private SeekBar mMinSlider;
private Spinner mGovernor;
private Spinner mIo;
private TextView mMaxSpeedText;
private TextView mMinSpeedText;
private String[] availableFrequencies;
private Activity mActivity;
private String mMaxFreqSetting;
private String mMinFreqSetting;
private CurCPUThread mCurCPUThread;
private boolean mIsTegra3 = false;
private int mNumOfCpu = 1;
private View view;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup root,
Bundle savedInstanceState) {
setHasOptionsMenu(true);
fa = (ActionBarActivity) super.getActivity();
mActivity = getActivity();
view = inflater.inflate(R.layout.card_cpu_control, root, false);
preferences = PreferenceManager.getDefaultSharedPreferences(mActivity);
graph = (LineGraph) view.findViewById(R.id.graph);
line = new Line();
LinePoint point = new LinePoint();
point.setX(currX);
point.setY(1);
line.addPoint(point);
line.setColor(Color.parseColor("#FFBB33"));
graph.addLine(line);
graph.setLineToFill(0);
availableFrequencies = new String[0];
String availableFrequenciesLine = Helpers.readOneLineNotRoot(STEPS);
if (availableFrequenciesLine != null) {
availableFrequencies = availableFrequenciesLine.split(" ");
Arrays.sort(availableFrequencies, new Comparator<String>() {
@Override
public int compare(String object1, String object2) {
return Integer.valueOf(object1).compareTo(
Integer.valueOf(object2));
}
});
}
int frequenciesNum = availableFrequencies.length - 1;
String currentGovernor = Helpers.readOneLineNotRoot(GOVERNOR);
String currentIo = CPUHelper.getIOScheduler();
String curMaxSpeed = Helpers.readOneLineNotRoot(MAX_FREQ);
String curMinSpeed = Helpers.readOneLineNotRoot(MIN_FREQ);
if (mIsTegra3) {
String curTegraMaxSpeed = Helpers.readOneLineNotRoot(TEGRA_MAX_FREQ);
int curTegraMax = 0;
try {
curTegraMax = Integer.parseInt(curTegraMaxSpeed);
if (curTegraMax > 0) {
curMaxSpeed = Integer.toString(curTegraMax);
}
} catch (NumberFormatException ex) {
curTegraMax = 0;
}
}
String numOfCpus = Helpers.readOneLineNotRoot(NUM_OF_CPUS);
String[] cpuCount = numOfCpus.split("-");
if (cpuCount.length > 1) {
try {
int cpuStart = Integer.parseInt(cpuCount[0]);
int cpuEnd = Integer.parseInt(cpuCount[1]);
mNumOfCpu = cpuEnd - cpuStart + 1;
if (mNumOfCpu < 0)
mNumOfCpu = 1;
} catch (NumberFormatException ex) {
mNumOfCpu = 1;
}
}
mCurFreq = (TextView) view.findViewById(R.id.currspeed);
mMaxSlider = (SeekBar) view.findViewById(R.id.max_slider);
mMaxSlider.setMax(frequenciesNum);
mMaxSpeedText = (TextView) view.findViewById(R.id.max_speed_text);
mMaxSpeedText.setText(toMHz(curMaxSpeed));
mMaxSlider.setProgress(Arrays.asList(availableFrequencies).indexOf(
curMaxSpeed));
mMaxSlider.setOnSeekBarChangeListener(this);
mMinSlider = (SeekBar) view.findViewById(R.id.min_slider);
mMinSlider.setMax(frequenciesNum);
mMinSpeedText = (TextView) view.findViewById(R.id.min_speed_text);
mMinSpeedText.setText(toMHz(curMinSpeed));
mMinSlider.setProgress(Arrays.asList(availableFrequencies).indexOf(
curMinSpeed));
mMinSlider.setOnSeekBarChangeListener(this);
mGovernor = (Spinner) view.findViewById(R.id.governor);
String[] availableGovernors = Helpers.readOneLineNotRoot(GOVERNORS_LIST)
.split(" ");
ArrayAdapter<CharSequence> governorAdapter = new ArrayAdapter<CharSequence>(
mActivity, android.R.layout.simple_spinner_item);
governorAdapter
.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
for (int i = 0; i < availableGovernors.length; i++) {
governorAdapter.add(availableGovernors[i]);
}
mGovernor.setAdapter(governorAdapter);
mGovernor.setSelection(Arrays.asList(availableGovernors).indexOf(
currentGovernor));
mGovernor.setOnItemSelectedListener(new GovListener());
mIo = (Spinner) view.findViewById(R.id.io);
String[] availableIo = CPUHelper.getAvailableIOSchedulers();
ArrayAdapter<CharSequence> ioAdapter = new ArrayAdapter<CharSequence>(
mActivity, android.R.layout.simple_spinner_item);
ioAdapter
.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
for (int i = 0; i < availableIo.length; i++) {
ioAdapter.add(availableIo[i]);
}
mIo.setAdapter(ioAdapter);
mIo.setSelection(Arrays.asList(availableIo).indexOf(currentIo));
mIo.setOnItemSelectedListener(new IOListener());
return view;
}
@Override
public void onProgressChanged(SeekBar seekBar, int progress,
boolean fromUser) {
if (fromUser) {
switch (seekBar.getId()) {
case R.id.max_slider:
setMaxSpeed(seekBar, progress);
break;
case R.id.min_slider:
setMinSpeed(seekBar, progress);
break;
}
}
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
// we have a break now, write the values..
CMDProcessor cmd = new CMDProcessor();
for (int i = 0; i < mNumOfCpu; i++) {
cmd.runSuCommand("busybox echo " + mMaxFreqSetting + " > "
+ MAX_FREQ.replace("cpu0", "cpu" + i));
cmd.runSuCommand("busybox echo " + mMinFreqSetting + " > "
+ MIN_FREQ.replace("cpu0", "cpu" + i));
}
if (mIsTegra3) {
cmd.runSuCommand("busybox echo " + mMaxFreqSetting + " > "
+ TEGRA_MAX_FREQ);
}
}
public class GovListener implements OnItemSelectedListener {
public void onItemSelected(AdapterView<?> parent, View view, int pos,
long id) {
String selected = parent.getItemAtPosition(pos).toString();
CMDProcessor cmd = new CMDProcessor();
// do this on all cpu's since MSM can have different governors on
// each cpu
// and it doesn't hurt other devices to do it
for (int i = 0; i < mNumOfCpu; i++) {
cmd.runSuCommand("busybox echo " + selected + " > "
+ GOVERNOR.replace("cpu0", "cpu" + i));
}
final SharedPreferences.Editor editor = preferences.edit();
editor.putString(GOV_PREF, selected);
editor.commit();
}
public void onNothingSelected(AdapterView<?> parent) {
}
}
public class IOListener implements OnItemSelectedListener {
public void onItemSelected(AdapterView<?> parent, View view, int pos,
long id) {
String selected = parent.getItemAtPosition(pos).toString();
CMDProcessor cmd = new CMDProcessor();
cmd.runSuCommand("busybox echo " + selected + " > " + IO_SCHEDULER);
final SharedPreferences.Editor editor = preferences.edit();
editor.putString(IO_PREF, selected);
editor.commit();
}
public void onNothingSelected(AdapterView<?> parent) {
}
}
@Override
public void onResume() {
super.onResume();
if (mCurCPUThread == null) {
mCurCPUThread = new CurCPUThread();
mCurCPUThread.start();
}
}
@Override
public void onDestroy() {
super.onDestroy();
if (mCurCPUThread.isAlive()) {
mCurCPUThread.interrupt();
try {
mCurCPUThread.join();
} catch (InterruptedException e) {
}
}
}
public void setMaxSpeed(SeekBar seekBar, int progress) {
String current;
current = availableFrequencies[progress];
int minSliderProgress = mMinSlider.getProgress();
if (progress <= minSliderProgress) {
mMinSlider.setProgress(progress);
mMinSpeedText.setText(toMHz(current));
mMinFreqSetting = current;
}
mMaxSpeedText.setText(toMHz(current));
mMaxFreqSetting = current;
final SharedPreferences.Editor editor = preferences.edit();
editor.putString(MAX_CPU, current);
editor.commit();
}
public void setMinSpeed(SeekBar seekBar, int progress) {
String current;
current = availableFrequencies[progress];
int maxSliderProgress = mMaxSlider.getProgress();
if (progress >= maxSliderProgress) {
mMaxSlider.setProgress(progress);
mMaxSpeedText.setText(toMHz(current));
mMaxFreqSetting = current;
}
mMinSpeedText.setText(toMHz(current));
mMinFreqSetting = current;
final SharedPreferences.Editor editor = preferences.edit();
editor.putString(MIN_CPU, current);
editor.commit();
}
// Convert raw collected values to formatted MhZ
private static String toMHz(String mhzString) {
if (Integer.valueOf(mhzString) != null)
return String.valueOf(Integer.valueOf(mhzString) / 1000) + " MHz";
else
return "NaN";
}
// Read current frequency from /sys in a separate thread
protected class CurCPUThread extends Thread {
private boolean mInterrupt = false;
public void interrupt() {
mInterrupt = true;
}
@Override
public void run() {
try {
while (!mInterrupt) {
sleep(400);
final String curFreq = Helpers.readOneLineNotRoot(CURRENT_CPU);
mCurCPUHandler.sendMessage(mCurCPUHandler.obtainMessage(0,
curFreq));
}
} catch (InterruptedException e) {
return;
}
}
}
// Update real-time current frequency & stats in a separate thread
protected static Handler mCurCPUHandler = new Handler() {
public void handleMessage(Message msg) {
mCurFreq.setText(toMHz((String) msg.obj));
currX += 1;
final int p = Integer.parseInt((String) msg.obj);
new Thread(new Runnable() {
public void run() {
counter++;
addStatPoint(currX, p, line, graph);
ArrayList<LinePoint> array = line.getPoints();
if (line.getSize() > 10)
array.remove(0);
line.setPoints(array);
// Reset the line every 50 updates of the current frequency
// to make-up for the lack of garbage collection in the
// HoloGraph pluggable
if (counter == 50) {
graph.removeAllLines();
line = new Line();
LinePoint point = new LinePoint();
point.setX(currX);
point.setY(1);
line.addPoint(point);
line.setColor(Color.parseColor("#FFBB33"));
graph.addLine(line);
counter = 0;
}
}
}).start();
}
};
// Static method to add new point to the graph
public static void addStatPoint(int X, int Y, Line line, LineGraph graph) {
LinePoint point = new LinePoint();
point.setX(X);
point.setY(Y);
line.addPoint(point);
graph.addLine(line);
}
}