add theme selector dark/light

This commit is contained in:
Alexey Kuznetsov 2016-04-02 15:04:18 +03:00
commit 36a9c467c7
24 changed files with 398 additions and 273 deletions

View file

@ -15,7 +15,5 @@ public class ApplicationTest extends ApplicationTestCase<Application> {
}
public void testFFT() {
short[] buf = RawSamples.generateSound(16000, 4500, 100);
short[] fft = RawSamples.fft(buf, 0, buf.length);
}
}

View file

@ -14,7 +14,7 @@
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme">
android:theme="@style/AppThemeLight">
<service android:name=".services.RecordingService" />
<activity
android:name=".activities.SettingsActivity"
@ -23,7 +23,7 @@
android:name=".activities.MainActivity"
android:configChanges="orientation|keyboardHidden|screenSize"
android:label="@string/title_activity_main"
android:theme="@style/AppTheme.NoActionBar">
android:theme="@style/AppThemeLight.NoActionBar">
<intent-filter>
<action android:name="android.intent.action.MAIN" />

View file

@ -12,6 +12,8 @@ import android.view.MenuInflater;
import android.view.View;
import android.view.ViewGroup;
import com.github.axet.audiorecorder.app.MainApplication;
/**
* A {@link android.preference.PreferenceActivity} which implements and proxies the necessary calls
* to be used with AppCompat.
@ -22,6 +24,7 @@ public abstract class AppCompatPreferenceActivity extends PreferenceActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
setTheme(((MainApplication) getApplication()).getUserTheme());
getDelegate().installViewFactory();
getDelegate().onCreate(savedInstanceState);
super.onCreate(savedInstanceState);

View file

@ -435,6 +435,9 @@ public class MainActivity extends AppCompatActivity implements AbsListView.OnScr
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setTheme(((MainApplication) getApplication()).getMainTheme());
setContentView(R.layout.activity_main);
// ATTENTION: This was auto-generated to implement the App Indexing API.

View file

@ -147,6 +147,9 @@ public class RecordingActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setTheme(((MainApplication) getApplication()).getUserTheme());
setContentView(R.layout.activity_recording);
pitch = (PitchView) findViewById(R.id.recording_pitch);
@ -273,9 +276,7 @@ public class RecordingActivity extends AppCompatActivity {
pitch.clear(cut / samplesUpdate);
for (int i = 0; i < len; i += samplesUpdate) {
double dB = RawSamples.getDB(buf, i, samplesUpdate);
short[] ss = new short[samplesUpdate];
System.arraycopy(buf, i, ss, 0, ss.length);
pitch.add(dB, ss);
pitch.add(dB);
}
updateSamples(samplesTime);
}
@ -615,12 +616,10 @@ public class RecordingActivity extends AppCompatActivity {
for (int i = 0; i < readSize; i += samplesUpdate) {
final double dB = RawSamples.getDB(buffer, i, samplesUpdate);
final short[] ss = new short[samplesUpdate];
System.arraycopy(buffer, i, ss, 0, ss.length);
handle.post(new Runnable() {
@Override
public void run() {
pitch.add(dB, ss);
pitch.add(dB);
}
});
}

View file

@ -6,6 +6,7 @@ import android.annotation.TargetApi;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.content.res.Configuration;
import android.media.Ringtone;
@ -23,6 +24,7 @@ import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.ActionBar;
import android.view.MenuItem;
import android.widget.ListView;
import android.widget.Toast;
import com.github.axet.audiorecorder.R;
@ -41,7 +43,7 @@ import java.util.List;
* href="http://developer.android.com/guide/topics/ui/settings.html">Settings
* API Guide</a> for more information on developing a Settings UI.
*/
public class SettingsActivity extends AppCompatPreferenceActivity {
public class SettingsActivity extends AppCompatPreferenceActivity implements SharedPreferences.OnSharedPreferenceChangeListener {
/**
* A preference value change listener that updates the preference's summary
* to reflect its new value.
@ -120,8 +122,12 @@ public class SettingsActivity extends AppCompatPreferenceActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setupActionBar();
final SharedPreferences shared = PreferenceManager.getDefaultSharedPreferences(this);
shared.registerOnSharedPreferenceChangeListener(this);
getFragmentManager().beginTransaction().replace(android.R.id.content, new GeneralPreferenceFragment()).commit();
}
@ -195,6 +201,23 @@ public class SettingsActivity extends AppCompatPreferenceActivity {
return true;
}
@Override
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
if(key.equals(MainApplication.PREFERENCE_THEME)) {
finish();
startActivity(new Intent(this, SettingsActivity.class));
overridePendingTransition(android.R.anim.fade_in, android.R.anim.fade_out);
}
}
@Override
protected void onDestroy() {
super.onDestroy();
final SharedPreferences shared = PreferenceManager.getDefaultSharedPreferences(this);
shared.unregisterOnSharedPreferenceChangeListener(this);
}
/**
* This fragment shows general preferences only. It is used when the
* activity is showing a two-pane settings UI.
@ -226,6 +249,7 @@ public class SettingsActivity extends AppCompatPreferenceActivity {
}
bindPreferenceSummaryToValue(findPreference(MainApplication.PREFERENCE_RATE));
bindPreferenceSummaryToValue(findPreference(MainApplication.PREFERENCE_THEME));
}
@Override

View file

@ -1,9 +1,14 @@
package com.github.axet.audiorecorder.app;
import android.app.Application;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.res.TypedArray;
import android.preference.PreferenceManager;
import android.util.Log;
import android.util.TypedValue;
import com.github.axet.androidlibrary.widgets.ThemeUtils;
import com.github.axet.audiorecorder.R;
public class MainApplication extends Application {
@ -13,12 +18,37 @@ public class MainApplication extends Application {
public static final String PREFERENCE_SILENT = "silence";
public static final String PREFERENCE_ENCODING = "encoding";
public static final String PREFERENCE_LAST = "last_recording";
public static final String PREFERENCE_THEME = "theme";
@Override
public void onCreate() {
super.onCreate();
PreferenceManager.setDefaultValues(this, R.xml.pref_general, false);
Context context = this;
context.setTheme(getUserTheme());
Log.d("123", "color " + Integer.toHexString(ThemeUtils.getThemeColor(context, android.R.attr.textColorSecondary)));
}
public int getUserTheme() {
final SharedPreferences shared = PreferenceManager.getDefaultSharedPreferences(this);
String theme = shared.getString(MainApplication.PREFERENCE_THEME, "");
if (theme.equals("Theme_Dark")) {
return R.style.AppThemeDark;
} else {
return R.style.AppThemeLight;
}
}
public int getMainTheme() {
final SharedPreferences shared = PreferenceManager.getDefaultSharedPreferences(this);
String theme = shared.getString(MainApplication.PREFERENCE_THEME, "");
if (theme.equals("Theme_Dark")) {
return R.style.AppThemeDark_NoActionBar;
} else {
return R.style.AppThemeLight_NoActionBar;
}
}
static public String formatTime(int tt) {

View file

@ -143,43 +143,7 @@ public class RawSamples {
public static double getDB(double amplitude) {
// https://en.wikipedia.org/wiki/Sound_pressure
return 20.0 * Math.log10(amplitude / 32768d);
}
public static short[] generateSound(int sampleRate, int freqHz, int durationMs) {
int count = sampleRate * durationMs / 1000;
short[] samples = new short[count];
for (int i = 0; i < count; i++) {
short sample = (short) (Math.sin(2 * Math.PI * i / (sampleRate / freqHz)) * 0x7FFF);
samples[i] = sample;
}
return samples;
}
public static short[] fft(short[] buffer, int offset, int len) {
int len2 = (int) Math.pow(2, Math.ceil(Math.log(len) / Math.log(2)));
final double[][] dataRI = new double[][]{
new double[len2], new double[len2]
};
double[] dataR = dataRI[0];
double[] dataI = dataRI[1];
for (int i = 0; i < len; i++) {
dataR[i] = buffer[offset + i];
}
FastFourierTransformer.transformInPlace(dataRI, DftNormalization.STANDARD, TransformType.FORWARD);
short[] data = new short[len2 / 2];
for (int i = 0; i < data.length; i++) {
Complex c = new Complex(dataR[i], dataI[i]);
data[i] = (short) (2.0 / len * c.abs());
}
return data;
return 20.0 * Math.log10(amplitude / 0x7FFF);
}
public void close() {

View file

@ -5,8 +5,11 @@ import android.app.PendingIntent;
import android.app.Service;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.ContextWrapper;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.content.res.Resources;
import android.os.Build;
import android.os.IBinder;
import android.support.annotation.Nullable;
@ -16,6 +19,7 @@ import android.widget.RemoteViews;
import com.github.axet.audiorecorder.R;
import com.github.axet.audiorecorder.activities.RecordingActivity;
import com.github.axet.audiorecorder.app.MainApplication;
/**
* RecordingActivity more likly to be removed from memory when paused then service. Notification button
@ -140,6 +144,19 @@ public class RecordingService extends Service {
view.setOnClickPendingIntent(R.id.notification_pause, pe);
view.setImageViewResource(R.id.notification_pause, !recording ? R.drawable.play : R.drawable.pause);
getBaseContext().setTheme(((MainApplication) getApplication()).getUserTheme());
view.apply(new ContextWrapper(getBaseContext()) {
public Context createPackageContext(String packageName, int flags) throws PackageManager.NameNotFoundException {
return new ContextWrapper(getBaseContext().createPackageContext(packageName, flags)) {
@Override
public Resources.Theme getTheme() {
return getBaseContext().getTheme();
}
};
}
}, null);
NotificationCompat.Builder builder = new NotificationCompat.Builder(this)
.setOngoing(true)
.setContentTitle("Recording")

View file

@ -11,21 +11,13 @@ import android.view.View;
import com.github.axet.audiorecorder.app.RawSamples;
public class FFTBarView extends View {
public class FFTBarView extends FFTView {
public static final String TAG = FFTBarView.class.getSimpleName();
Paint paint;
short[] buffer;
int barCount;
float barWidth;
float barDeli;
int max;
Paint textPaint;
Rect textBounds;
public FFTBarView(Context context) {
this(context, null);
}
@ -41,46 +33,11 @@ public class FFTBarView extends View {
}
void create() {
paint = new Paint();
paint.setColor(0xff0433AE);
paint.setStrokeWidth(dp2px(1));
textBounds = new Rect();
textPaint = new Paint();
textPaint.setColor(Color.GRAY);
textPaint.setAntiAlias(true);
textPaint.setTextSize(20f);
if (isInEditMode()) {
//buffer = simple();
buffer = RawSamples.generateSound(16000, 4000, 100);
buffer = RawSamples.fft(buffer, 0, buffer.length);
}
super.create();
}
public void setBuffer(short[] buf) {
buffer = RawSamples.fft(buf, 0, buf.length);
max = Integer.MIN_VALUE;
for (int i = 0; i < buffer.length; i++) {
max = Math.max(buffer[i], max);
}
}
short[] simple() {
int sampleRate = 1000;
int count = sampleRate;
short[] samples = new short[count];
for (int i = 0; i < count; i++) {
double x = i / (double) sampleRate;
double y = 0;
y += 0.9 * Math.sin(50 * 2 * Math.PI * x);
y += 0.5 * Math.sin(80 * 2 * Math.PI * x);
y += 0.7 * Math.sin(40 * 2 * Math.PI * x);
samples[i] = (short) (y / 2.1 * 0x7fff);
}
return samples;
public void setBuffer(double[] buf) {
super.setBuffer(buf);
}
@Override
@ -113,10 +70,6 @@ public class FFTBarView extends View {
protected void onLayout(boolean changed, int l, int t, int r, int b) {
}
int dp2px(float dp) {
return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, getResources().getDisplayMetrics());
}
@Override
public void onDraw(Canvas canvas) {
if (barCount == 0)
@ -134,7 +87,7 @@ public class FFTBarView extends View {
int offset = i * step;
int end = Math.min(offset + step, buffer.length);
for (int k = offset; k < end; k++) {
short s = buffer[k];
double s = buffer[k];
max = Math.max(max, s);
}
}

View file

@ -13,15 +13,9 @@ import android.view.View;
import com.github.axet.audiorecorder.app.RawSamples;
public class FFTChartView extends View {
public class FFTChartView extends FFTView {
public static final String TAG = FFTChartView.class.getSimpleName();
Paint paint;
short[] buffer;
Paint textPaint;
Rect textBounds;
public FFTChartView(Context context) {
this(context, null);
}
@ -37,42 +31,13 @@ public class FFTChartView extends View {
}
void create() {
paint = new Paint();
paint.setColor(0xff0433AE);
paint.setStrokeWidth(dp2px(1));
textBounds = new Rect();
textPaint = new Paint();
textPaint.setColor(Color.GRAY);
textPaint.setAntiAlias(true);
textPaint.setTextSize(20f);
if (isInEditMode()) {
buffer = simple();
//buffer = RawSamples.generateSound(16000, 4000, 100);
//buffer = RawSamples.fft(buffer, 0, buffer.length);
}
super.create();
}
public void setBuffer(short[] buf) {
buffer = RawSamples.fft(buf, 0, buf.length);
public void setBuffer(double[] buf) {
super.setBuffer(buf);
}
short[] simple() {
int sampleRate = 1000;
int count = sampleRate;
short[] samples = new short[count];
for (int i = 0; i < count; i++) {
double x = i / (double) sampleRate;
double y = 0;
y += 0.9 * Math.sin(50 * 2 * Math.PI * x);
y += 0.5 * Math.sin(80 * 2 * Math.PI * x);
y += 0.7 * Math.sin(40 * 2 * Math.PI * x);
samples[i] = (short) (y / 2.1 * 0x7fff);
}
return samples;
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
@ -83,33 +48,34 @@ public class FFTChartView extends View {
protected void onLayout(boolean changed, int l, int t, int r, int b) {
}
int dp2px(float dp) {
return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, getResources().getDisplayMetrics());
}
@Override
public void onDraw(Canvas canvas) {
int min = Integer.MAX_VALUE;
int max = Integer.MIN_VALUE;
if (buffer == null)
return;
for (int i = 0; i < buffer.length; i++) {
min = Math.min(buffer[i], min);
max = Math.max(buffer[i], max);
}
canvas.drawColor(Color.RED);
int h = getHeight();
if (min < 0) {
h = h / 2;
}
float startX = 0, startY = h;
float step = canvas.getWidth() / (float) buffer.length;
int w = getWidth() - getPaddingLeft() - getPaddingRight();
float step = w / (float) buffer.length;
double min = Integer.MAX_VALUE;
double max = Integer.MIN_VALUE;
for (int i = 0; i < buffer.length; i++) {
double v = buffer[i];
min = Math.min(v, min);
max = Math.max(v, max);
v = (RawSamples.MAXIMUM_DB + v) / RawSamples.MAXIMUM_DB;
float endX = startX;
float endY = h - h * (buffer[i] / (float) 0x7fff);
float endY = (float) (h - h * v);
canvas.drawLine(startX, startY, endX, endY, paint);
@ -122,7 +88,7 @@ public class FFTChartView extends View {
String tMax = "" + max;
textPaint.getTextBounds(tMax, 0, tMax.length(), textBounds);
canvas.drawText("" + max, getWidth() - textBounds.width(), getHeight(), textPaint);
canvas.drawText("" + max, w - textBounds.width(), getHeight(), textPaint);
}
}

View file

@ -0,0 +1,151 @@
package com.github.axet.audiorecorder.widgets;
import android.content.Context;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.View;
import com.github.axet.audiorecorder.app.RawSamples;
import org.apache.commons.math3.complex.Complex;
import org.apache.commons.math3.transform.DftNormalization;
import org.apache.commons.math3.transform.FastFourierTransformer;
import org.apache.commons.math3.transform.TransformType;
public class FFTView extends View {
public static final String TAG = FFTView.class.getSimpleName();
Paint paint;
double[] buffer;
Paint textPaint;
Rect textBounds;
public FFTView(Context context) {
this(context, null);
}
public FFTView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public FFTView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
create();
}
void create() {
paint = new Paint();
paint.setColor(0xff0433AE);
paint.setStrokeWidth(dp2px(1));
textBounds = new Rect();
textPaint = new Paint();
textPaint.setColor(Color.GRAY);
textPaint.setAntiAlias(true);
textPaint.setTextSize(20f);
if (isInEditMode()) {
short[] b = simple();
b = generateSound(16000, 4000, 100);
buffer = fft(b, 0, b.length);
//buffer = RawSamples.generateSound(16000, 4000, 100);
//buffer = RawSamples.fft(buffer, 0, buffer.length);
}
}
public void setBuffer(double[] buf) {
buffer = buf;
}
public static short[] generateSound(int sampleRate, int freqHz, int durationMs) {
int count = sampleRate * durationMs / 1000;
short[] samples = new short[count];
for (int i = 0; i < count; i++) {
short sample = (short) (Math.sin(2 * Math.PI * i / (sampleRate / freqHz)) * 0x7FFF);
samples[i] = sample;
}
return samples;
}
public static double[] asDouble(short[] buffer, int offset, int len) {
double[] dd = new double[len];
for (int i = 0; i < len; i++) {
dd[i] = buffer[offset + i] / (float) 0x7fff;
}
return dd;
}
public static double[] fft(short[] buffer, int offset, int len) {
int len2 = (int) Math.pow(2, Math.ceil(Math.log(len) / Math.log(2)));
final double[][] dataRI = new double[][]{
new double[len2], new double[len2]
};
double[] dataR = dataRI[0];
double[] dataI = dataRI[1];
double powerInput = 0;
for (int i = 0; i < len; i++) {
dataR[i] = buffer[offset + i] / (float) 0x7fff;
powerInput += dataR[i] * dataR[i];
}
powerInput = Math.sqrt(powerInput / len);
FastFourierTransformer.transformInPlace(dataRI, DftNormalization.STANDARD, TransformType.FORWARD);
double[] data = new double[len2 / 2];
data[0] = 10 * Math.log10(Math.pow(new Complex(dataR[0], dataI[0]).abs() / len2, 2));
double powerOutput = 0;
for (int i = 1; i < data.length; i++) {
Complex c = new Complex(dataR[i], dataI[i]);
double p = c.abs();
p = p / len2;
p = p * p;
p = p * 2;
double dB = 10 * Math.log10(p);
powerOutput += p;
data[i] = dB;
}
powerOutput = Math.sqrt(powerOutput);
// if(powerInput != powerOutput) {
// throw new RuntimeException("in " + powerInput + " out " + powerOutput);
// }
return data;
}
public static short[] simple() {
int sampleRate = 1000;
int count = sampleRate;
short[] samples = new short[count];
for (int i = 0; i < count; i++) {
double x = i / (double) count;
double y = 0;
//y += 0.6 * Math.sin(20 * 2 * Math.PI * x);
//y += 0.4 * Math.sin(50 * 2 * Math.PI * x);
//y += 0.2 * Math.sin(80 * 2 * Math.PI * x);
y += Math.sin(100 * 2 * Math.PI * x);
y += Math.sin(200 * 2 * Math.PI * x);
y += Math.sin(300 * 2 * Math.PI * x);
// max = 2.2;
samples[i] = (short) (y / 3 * 0x7fff);
}
return samples;
}
int dp2px(float dp) {
return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, getResources().getDisplayMetrics());
}
}

View file

@ -2,6 +2,7 @@ package com.github.axet.audiorecorder.widgets;
import android.content.Context;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
@ -15,6 +16,9 @@ import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import com.github.axet.androidlibrary.widgets.ThemeUtils;
import com.github.axet.audiorecorder.R;
import com.github.axet.audiorecorder.app.MainApplication;
import com.github.axet.audiorecorder.app.RawSamples;
import java.util.LinkedList;
@ -39,10 +43,7 @@ public class PitchView extends ViewGroup {
// in other words how many milliseconds do we need to show whole pitch.
int pitchTime;
Paint paint;
Paint paintRed;
List<Double> data = new LinkedList<>();
List<short[]> dataSamples = new LinkedList<>();
// how many pitches we can fit on screen
int pitchScreenCount;
@ -56,7 +57,6 @@ public class PitchView extends ViewGroup {
int pitchSize;
PitchGraphView graph;
FFTBarView fft;
PitchCurrentView current;
long time = 0;
@ -77,9 +77,6 @@ public class PitchView extends ViewGroup {
Handler handler;
int pitchColor = 0xff0433AE;
Paint cutColor = new Paint();
public static class HandlerUpdate implements Runnable {
long start;
long updateSpeed;
@ -123,8 +120,11 @@ public class PitchView extends ViewGroup {
}
public class PitchGraphView extends View {
Paint paint;
Paint paintRed;
Paint editPaint;
Paint playPaint;
Paint cutColor;
public PitchGraphView(Context context) {
this(context, null);
@ -137,12 +137,24 @@ public class PitchView extends ViewGroup {
public PitchGraphView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
paint = new Paint();
paint.setColor(getThemeColor(R.attr.colorPrimary));
paint.setStrokeWidth(pitchWidth);
paintRed = new Paint();
paintRed.setColor(Color.RED);
paintRed.setStrokeWidth(pitchWidth);
cutColor = new Paint();
cutColor.setColor(getThemeColor(android.R.attr.textColorHint));
cutColor.setStrokeWidth(pitchWidth);
editPaint = new Paint();
editPaint.setColor(Color.BLACK);
editPaint.setColor(getThemeColor(R.attr.colorPrimaryDark));
editPaint.setStrokeWidth(pitchWidth);
playPaint = new Paint();
playPaint.setColor(Color.BLUE);
playPaint.setColor(getThemeColor(R.attr.colorPrimaryDark));
playPaint.setStrokeWidth(pitchWidth / 2);
}
@ -270,7 +282,7 @@ public class PitchView extends ViewGroup {
textPaint.setTextSize(20f);
paint = new Paint();
paint.setColor(pitchColor);
paint.setColor(getThemeColor(R.attr.colorPrimary));
paint.setStrokeWidth(pitchWidth);
}
@ -309,6 +321,10 @@ public class PitchView extends ViewGroup {
@Override
public void onDraw(Canvas canvas) {
if (data.size() > 0) {
current.update(getEnd());
}
float y = getPaddingTop() + textBounds.height();
int x = getWidth() / 2 - textBounds.width() / 2;
@ -351,15 +367,24 @@ public class PitchView extends ViewGroup {
pitchTime = pitchSize * UPDATE_SPEED;
// bg = getThemeColor(android.R.attr.windowBackground);
cutColor.setColor(0xff0443BE); // getThemeColor(android.R.attr.textColorPrimaryDisableOnly));
graph = new PitchGraphView(getContext());
addView(graph);
fft = new FFTBarView(getContext());
fft.setPadding(0, dp2px(2), 0, 0);
addView(fft);
// fft = new FFTChartView(getContext()) {
// @Override
// public void onDraw(Canvas canvas) {
// if (data.size() > 0) {
// short[] buf = dataSamples.get(getEnd());
// double[] d = FFTView.fft(buf, 0, buf.length);
// //double[] d = asDouble(buf, 0, buf.length);
// fft.setBuffer(d);
// }
//
// super.onDraw(canvas);
// }
// };
// fft.setPadding(0, dp2px(2), 0, 0);
// addView(fft);
current = new PitchCurrentView(getContext());
current.setPadding(0, dp2px(2), 0, 0);
@ -367,23 +392,17 @@ public class PitchView extends ViewGroup {
if (isInEditMode()) {
for (int i = 0; i < 3000; i++) {
data.add(-Math.random() * RawSamples.MAXIMUM_DB);
short[] buf = new short[1600];
dataSamples.add(buf);
data.add(-Math.sin(i) * RawSamples.MAXIMUM_DB);
}
}
paint = new Paint();
paint.setColor(0xff0433AE);
paint.setStrokeWidth(pitchWidth);
paintRed = new Paint();
paintRed.setColor(Color.RED);
paintRed.setStrokeWidth(pitchWidth);
time = System.currentTimeMillis();
}
public int getThemeColor(int id) {
return ThemeUtils.getThemeColor(getContext(), id);
}
public int getMaxPitchCount(int width) {
int pitchScreenCount = width / pitchSize + 1;
@ -405,7 +424,6 @@ public class PitchView extends ViewGroup {
if (data.size() > max) {
int cut = data.size() - max;
data.subList(0, cut).clear();
dataSamples.subList(0, cut).clear();
samples += cut;
int m = data.size() - 1;
@ -417,9 +435,8 @@ public class PitchView extends ViewGroup {
}
}
public void add(double a, short[] ss) {
public void add(double a) {
data.add(a);
dataSamples.add(ss);
}
public void drawCalc() {
@ -472,15 +489,6 @@ public class PitchView extends ViewGroup {
public void draw() {
graph.invalidate();
if (data.size() > 0) {
fft.setBuffer(dataSamples.get(getEnd()));
}
fft.invalidate();
if (data.size() > 0) {
current.update(getEnd());
}
current.invalidate();
}
@ -488,51 +496,35 @@ public class PitchView extends ViewGroup {
return pitchTime;
}
int getThemeColor(int id) {
TypedValue typedValue = new TypedValue();
Context context = getContext();
Resources.Theme theme = context.getTheme();
if (theme.resolveAttribute(id, typedValue, true)) {
if (Build.VERSION.SDK_INT >= 23)
return context.getResources().getColor(typedValue.resourceId, theme);
else
return context.getResources().getColor(typedValue.resourceId);
} else {
return Color.TRANSPARENT;
}
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
current.measure(widthMeasureSpec, heightMeasureSpec);
int ww = getMeasuredWidth() - getPaddingRight() - getPaddingLeft();
int hh = getMeasuredHeight() - getPaddingTop() - getPaddingBottom();
fft.measure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(dp2px(20), MeasureSpec.getMode(widthMeasureSpec)));
current.measure(MeasureSpec.makeMeasureSpec(ww, MeasureSpec.AT_MOST),
MeasureSpec.makeMeasureSpec(hh, MeasureSpec.AT_MOST));
int hh = MeasureSpec.getSize(heightMeasureSpec) - current.getMeasuredHeight() - fft.getMeasuredHeight();
graph.measure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(hh, MeasureSpec.getMode(widthMeasureSpec)));
hh = hh - current.getMeasuredHeight();
graph.measure(MeasureSpec.makeMeasureSpec(ww, MeasureSpec.AT_MOST),
MeasureSpec.makeMeasureSpec(hh, MeasureSpec.AT_MOST));
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
graph.layout(0, 0, graph.getMeasuredWidth(), graph.getMeasuredHeight());
fft.layout(0, graph.getMeasuredHeight(), fft.getMeasuredWidth(),
graph.getMeasuredHeight() + fft.getMeasuredHeight());
current.layout(0, fft.getBottom(), current.getMeasuredWidth(),
fft.getBottom() + current.getMeasuredHeight());
graph.layout(getPaddingLeft(), getPaddingTop(),
getPaddingLeft() + graph.getMeasuredWidth(), getPaddingTop() + graph.getMeasuredHeight());
current.layout(getPaddingLeft(), graph.getBottom(),
getPaddingLeft() + current.getMeasuredWidth(), graph.getBottom() + current.getMeasuredHeight());
}
int dp2px(float dp) {
return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, getResources().getDisplayMetrics());
}
@Override
protected void onDraw(Canvas canvas) {
graph.draw(canvas);
current.draw(canvas);
}
public void stop() {
if (edit != null)
HandlerUpdate.stop(handler, edit);

View file

@ -1,7 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval">
<solid android:color="@color/colorAccent" />
</shape>

View file

@ -10,14 +10,14 @@
<android.support.design.widget.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="@style/AppTheme.AppBarOverlay">
android:theme="@style/AppThemeLight.AppBarOverlay">
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
app:popupTheme="@style/AppTheme.PopupOverlay" />
app:popupTheme="@style/AppThemeLight.PopupOverlay" />
</android.support.design.widget.AppBarLayout>

View file

@ -38,7 +38,8 @@
android:id="@+id/recording_pitch"
android:layout_width="match_parent"
android:layout_height="120dp"
android:layout_centerInParent="true" />
android:layout_centerInParent="true"
android:padding="5dp" />
<FrameLayout
android:layout_width="match_parent"
@ -51,28 +52,24 @@
android:layout_height="wrap_content"
android:paddingBottom="5dp">
<ImageButton
<com.github.axet.androidlibrary.widgets.RoundButton
android:id="@+id/recording_cut"
android:layout_width="40dp"
android:layout_height="40dp"
android:background="@drawable/round"
android:gravity="center"
android:src="@drawable/ic_content_cut_24dp"
android:text="Cancel" />
<ImageButton
<com.github.axet.androidlibrary.widgets.RoundButton
android:id="@+id/recording_play"
android:layout_width="40dp"
android:layout_height="40dp"
android:background="@drawable/round"
android:src="@drawable/play" />
<ImageButton
<com.github.axet.androidlibrary.widgets.RoundButton
android:id="@+id/recording_edit_done"
style="Widget.AppCompat.RoundButton"
android:layout_width="40dp"
android:layout_height="40dp"
android:background="@drawable/round"
android:src="@drawable/ic_close_24dp" />
</com.github.axet.androidlibrary.widgets.EqualLinearLayout>
</FrameLayout>
@ -96,28 +93,24 @@
android:layout_width="match_parent"
android:layout_height="wrap_content">
<ImageButton
<com.github.axet.androidlibrary.widgets.RoundButton
android:id="@+id/recording_cancel"
android:layout_width="40dp"
android:layout_height="40dp"
android:background="@drawable/round"
android:gravity="center"
android:src="@drawable/ic_close_24dp"
android:text="Cancel" />
<ImageButton
<com.github.axet.androidlibrary.widgets.RoundButton
android:id="@+id/recording_pause"
android:layout_width="40dp"
android:layout_height="40dp"
android:background="@drawable/round"
android:src="@drawable/ic_pause_24dp" />
<ImageButton
<com.github.axet.androidlibrary.widgets.RoundButton
android:id="@+id/recording_done"
android:layout_width="40dp"
android:layout_height="40dp"
android:background="@drawable/round"
android:src="@drawable/ic_done" />
</com.github.axet.androidlibrary.widgets.EqualLinearLayout>

View file

@ -3,13 +3,13 @@
android:id="@+id/status_bar_latest_event_content"
android:layout_width="match_parent"
android:layout_height="64dp"
android:background="@android:color/white">
android:background="?android:windowBackground">
<ImageView
android:layout_width="@dimen/notification_large_icon_width"
android:layout_height="@dimen/notification_large_icon_height"
android:src="@drawable/ic_mic_24dp"
android:tint="@android:color/black" />
android:tint="?android:attr/colorForeground" />
<LinearLayout
android:id="@+id/notification_main_column"
@ -30,18 +30,17 @@
<TextView
android:id="@+id/notification_title"
style="@style/AlertDialog.AppCompat"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Audio Recorder"
android:textColor="@android:color/black" />
android:textColor="?android:attr/colorForeground" />
<TextView
android:id="@+id/notification_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Audio Recorder"
android:textColor="@android:color/darker_gray"
android:textColor="?android:attr/textColorHint"
android:textSize="@dimen/notification_subtext_size" />
</LinearLayout>

View file

@ -70,8 +70,8 @@
android:layout_marginBottom="5dp"
android:layout_marginLeft="5dp"
android:layout_marginRight="5dp"
android:background="#dedede"
android:orientation="vertical"
android:background="?attr/secondBackground"
android:padding="5dp">
<LinearLayout
@ -81,6 +81,7 @@
android:orientation="horizontal">
<TextView
android:textColor="?android:textColorSecondary"
android:id="@+id/recording_player_start"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
@ -113,21 +114,21 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/play"
android:tint="@color/colorAccent" />
android:tint="?attr/colorAccent" />
<ImageView
android:id="@+id/recording_player_share"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/share"
android:tint="@color/colorAccent" />
android:tint="?attr/colorAccent" />
<ImageView
android:id="@+id/recording_player_trash"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/trash"
android:tint="@color/colorAccent" />
android:tint="?attr/colorAccent" />
</com.github.axet.androidlibrary.widgets.EqualLinearLayout>
</LinearLayout>
</FrameLayout>

View file

@ -1,6 +1,11 @@
<resources>>
<style name="AppTheme.NoActionBar">
<resources>
<style name="AppThemeLight.NoActionBar">
<item name="windowActionBar">false</item>
<item name="windowNoTitle">true</item>
<item name="android:windowDrawsSystemBarBackgrounds">true</item>
<item name="android:statusBarColor">@android:color/transparent</item>
</style>
<style name="AppThemeDark.NoActionBar">
<item name="windowActionBar">false</item>
<item name="windowNoTitle">true</item>
<item name="android:windowDrawsSystemBarBackgrounds">true</item>

View file

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<attr name="secondBackground" format="color" />
</resources>

View file

@ -2,6 +2,4 @@
<resources>
<color name="colorPrimary">#3F51B5</color>
<color name="colorPrimaryDark">#303F9F</color>
<color name="colorAccent">#FF4081</color>
<color name="button_bg">#606060</color>
</resources>

View file

@ -21,16 +21,26 @@
<item>8000</item>
</string-array>
<string-array name="encodings" >
<string-array name="encodings">
<item>.wav (default)</item>
<item>.m4a</item>
</string-array>
<string-array name="encodings_values" >
<string-array name="encodings_values">
<item>wav</item>
<item>m4a</item>
</string-array>
<string-array name="themes">
<item>Theme White (default)</item>
<item>Theme Dark</item>
</string-array>
<string-array name="themes_values">
<item>Theme_White</item>
<item>Theme_Dark</item>
</string-array>
<string name="title_activity_main">Audio Recorder</string>
<string name="action_settings">Settings</string>

View file

@ -1,20 +1,31 @@
<resources>
<!-- Base application theme. -->
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
<!-- Customize your theme here. -->
<style name="AppThemeLight" parent="Theme.AppCompat.Light.DarkActionBar">
<item name="colorPrimary">@color/colorPrimary</item>
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
<item name="colorAccent">@color/colorAccent</item>
<item name="colorAccent">#FF4081</item>
<item name="secondBackground">#c2c2c2</item>
</style>
<style name="AppTheme.NoActionBar">
<style name="AppThemeLight.NoActionBar">
<item name="windowActionBar">false</item>
<item name="windowNoTitle">true</item>
</style>
<style name="AppTheme.AppBarOverlay" parent="ThemeOverlay.AppCompat.Dark.ActionBar" />
<style name="AppThemeLight.AppBarOverlay" parent="ThemeOverlay.AppCompat.Dark.ActionBar" />
<style name="AppTheme.PopupOverlay" parent="ThemeOverlay.AppCompat.Light" />
<style name="AppThemeLight.PopupOverlay" parent="ThemeOverlay.AppCompat.Light" />
<style name="AppThemeDark" parent="Theme.AppCompat">
<item name="colorPrimary">@color/colorPrimary</item>
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
<item name="colorAccent">#a4a4a4</item>
<item name="secondBackground">#5a595b</item>
</style>
<style name="AppThemeDark.NoActionBar">
<item name="windowActionBar">false</item>
<item name="windowNoTitle">true</item>
</style>
</resources>

View file

@ -1,4 +1,5 @@
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<com.github.axet.androidlibrary.widgets.StoragePathPreference
android:defaultValue="Audio Recorder"
android:key="storage_path"
@ -37,4 +38,14 @@
android:summary="Put phone in 'silence mode' during recording"
android:title="Silence mode" />
<ListPreference
android:defaultValue="Theme_White"
android:entries="@array/themes"
android:entryValues="@array/themes_values"
android:key="theme"
android:negativeButtonText="@null"
android:positiveButtonText="@null"
android:summary="Set application theme (dark / light)"
android:title="Application Theme" />
</PreferenceScreen>