/** Copyright (C) 2013 Louis Teboul (a.k.a Androguide)
*
* admin@pimpmyrom.org || louisteboul@gmail.com
* http://pimpmyrom.org || http://androguide.fr
* 71 quai Clémenceau, 69300 Caluire-et-Cuire, FRANCE.
*
* 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 2 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, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
**/
package com.androguide.honamicontrol.kernel.cpucontrol;
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.honamicontrol.R;
import com.androguide.honamicontrol.helpers.CMDProcessor.CMDProcessor;
import com.androguide.honamicontrol.helpers.CPUHelper;
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 CPUFragment 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 SNAKE_CHARMER_MAX_FREQ = "/sys/kernel/msm_cpufreq_limit/cpufreq_limit";
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 = CPUHelper.readOneLine(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 = CPUHelper.readOneLine(GOVERNOR);
// String currentIo = CPUHelper.getIOScheduler();
String curMaxSpeed = CPUHelper.readOneLine(MAX_FREQ);
String curMinSpeed = CPUHelper.readOneLine(MIN_FREQ);
if (mIsTegra3) {
String curTegraMaxSpeed = CPUHelper.readOneLine(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 = CPUHelper.readOneLine(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 = CPUHelper.readOneLine(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..
for (int i = 0; i < mNumOfCpu; i++) {
CMDProcessor.runSuCommand("busybox echo " + mMaxFreqSetting + " > "
+ MAX_FREQ.replace("cpu0", "cpu" + i));
CMDProcessor.runSuCommand("busybox echo " + mMinFreqSetting + " > "
+ MIN_FREQ.replace("cpu0", "cpu" + i));
}
if (mIsTegra3) {
CMDProcessor.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();
// 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++) {
CMDProcessor.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.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 = CPUHelper.readOneLine(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);
}
}