├── .gitignore ├── .idea ├── .name ├── compiler.xml ├── copyright │ └── profiles_settings.xml ├── dictionaries │ └── wangchenlong.xml ├── encodings.xml ├── gradle.xml ├── misc.xml ├── modules.xml └── runConfigurations.xml ├── README.md ├── app ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── me │ │ └── chunyu │ │ └── spike │ │ └── wcl_visualizer_demo │ │ └── ApplicationTest.java │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── me │ │ │ └── chunyu │ │ │ └── spike │ │ │ └── wcl_visualizer_demo │ │ │ ├── MainActivity.java │ │ │ ├── permissions │ │ │ ├── PermissionsActivity.java │ │ │ └── PermissionsChecker.java │ │ │ └── visualizers │ │ │ ├── RendererFactory.java │ │ │ ├── SimpleWaveformRenderer.java │ │ │ ├── WaveformRenderer.java │ │ │ └── WaveformView.java │ └── res │ │ ├── drawable │ │ └── ic_mic_off.xml │ │ ├── layout │ │ ├── activity_main.xml │ │ └── activity_permissions.xml │ │ ├── mipmap-hdpi │ │ └── ic_launcher.png │ │ ├── mipmap-mdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xhdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xxhdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xxxhdpi │ │ └── ic_launcher.png │ │ ├── values-w820dp │ │ └── dimens.xml │ │ └── values │ │ ├── colors.xml │ │ ├── dimens.xml │ │ ├── strings.xml │ │ └── styles.xml │ └── test │ └── java │ └── me │ └── chunyu │ └── spike │ └── wcl_visualizer_demo │ └── ExampleUnitTest.java ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/workspace.xml 5 | /.idea/libraries 6 | .DS_Store 7 | /build 8 | /captures 9 | -------------------------------------------------------------------------------- /.idea/.name: -------------------------------------------------------------------------------- 1 | wcl-visualizer-demo -------------------------------------------------------------------------------- /.idea/compiler.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /.idea/copyright/profiles_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /.idea/dictionaries/wangchenlong.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /.idea/encodings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.idea/gradle.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 22 | 23 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 12 | 13 | 14 | 26 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 53 | 54 | 55 | 56 | 57 | 1.8 58 | 59 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 75 | 76 | 77 | 78 | 79 | 80 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /.idea/runConfigurations.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # wcl-visualizer-demo 2 | 使用Visualizer类绘制音频的波纹形态. 3 | 4 | 示例详细[参考](http://www.jianshu.com/p/e9d2bc36ada5) 5 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | apply plugin: 'me.tatarka.retrolambda' 3 | 4 | android { 5 | compileSdkVersion 23 6 | buildToolsVersion "23.0.2" 7 | 8 | defaultConfig { 9 | applicationId "me.chunyu.spike.wcl_visualizer_demo" 10 | minSdkVersion 14 11 | targetSdkVersion 23 12 | versionCode 1 13 | versionName "1.0" 14 | } 15 | 16 | buildTypes { 17 | release { 18 | minifyEnabled false 19 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 20 | } 21 | } 22 | 23 | compileOptions { 24 | sourceCompatibility JavaVersion.VERSION_1_8 25 | targetCompatibility JavaVersion.VERSION_1_8 26 | } 27 | } 28 | 29 | dependencies { 30 | compile fileTree(dir: 'libs', include: ['*.jar']) 31 | testCompile 'junit:junit:4.12' 32 | compile 'com.android.support:appcompat-v7:23.1.1' 33 | compile 'com.jakewharton:butterknife:7.0.1' 34 | } 35 | -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in /Users/wangchenlong/Installations/android-sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -------------------------------------------------------------------------------- /app/src/androidTest/java/me/chunyu/spike/wcl_visualizer_demo/ApplicationTest.java: -------------------------------------------------------------------------------- 1 | package me.chunyu.spike.wcl_visualizer_demo; 2 | 3 | import android.app.Application; 4 | import android.test.ApplicationTestCase; 5 | 6 | /** 7 | * Testing Fundamentals 8 | */ 9 | public class ApplicationTest extends ApplicationTestCase { 10 | public ApplicationTest() { 11 | super(Application.class); 12 | } 13 | } -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /app/src/main/java/me/chunyu/spike/wcl_visualizer_demo/MainActivity.java: -------------------------------------------------------------------------------- 1 | package me.chunyu.spike.wcl_visualizer_demo; 2 | 3 | import android.Manifest; 4 | import android.content.Intent; 5 | import android.graphics.Color; 6 | import android.media.audiofx.Visualizer; 7 | import android.os.Bundle; 8 | import android.support.v4.content.ContextCompat; 9 | import android.support.v7.app.AppCompatActivity; 10 | 11 | import butterknife.Bind; 12 | import butterknife.ButterKnife; 13 | import me.chunyu.spike.wcl_visualizer_demo.permissions.PermissionsActivity; 14 | import me.chunyu.spike.wcl_visualizer_demo.permissions.PermissionsChecker; 15 | import me.chunyu.spike.wcl_visualizer_demo.visualizers.RendererFactory; 16 | import me.chunyu.spike.wcl_visualizer_demo.visualizers.WaveformView; 17 | 18 | public class MainActivity extends AppCompatActivity { 19 | 20 | private static final int CAPTURE_SIZE = 256; // 获取这些数据, 用于显示 21 | private static final int REQUEST_CODE = 0; 22 | 23 | // 权限 24 | private static final String[] PERMISSIONS = new String[]{ 25 | Manifest.permission.RECORD_AUDIO, 26 | Manifest.permission.MODIFY_AUDIO_SETTINGS 27 | }; 28 | 29 | @Bind(R.id.main_wv_waveform) WaveformView mWvWaveform; // 波纹视图 30 | 31 | private Visualizer mVisualizer; // 音频可视化类 32 | 33 | @Override 34 | protected void onCreate(Bundle savedInstanceState) { 35 | super.onCreate(savedInstanceState); 36 | setContentView(R.layout.activity_main); 37 | ButterKnife.bind(this); 38 | 39 | RendererFactory rendererFactory = new RendererFactory(); 40 | mWvWaveform.setRenderer(rendererFactory.createSimpleWaveformRender(ContextCompat.getColor(this, R.color.colorPrimary), Color.WHITE)); 41 | } 42 | 43 | @Override protected void onResume() { 44 | super.onResume(); 45 | 46 | PermissionsChecker checker = new PermissionsChecker(this); 47 | 48 | if (checker.lakesPermissions(PERMISSIONS)) { 49 | PermissionsActivity.startActivityForResult(this, REQUEST_CODE, PERMISSIONS); 50 | } else { 51 | startVisualiser(); 52 | } 53 | } 54 | 55 | @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { 56 | super.onActivityResult(requestCode, resultCode, data); 57 | if (requestCode == REQUEST_CODE && resultCode == PermissionsActivity.PERMISSIONS_DENIED) { 58 | finish(); 59 | } 60 | } 61 | 62 | // 设置音频线 63 | private void startVisualiser() { 64 | mVisualizer = new Visualizer(0); // 初始化 65 | mVisualizer.setDataCaptureListener(new Visualizer.OnDataCaptureListener() { 66 | @Override 67 | public void onWaveFormDataCapture(Visualizer visualizer, byte[] waveform, int samplingRate) { 68 | if (mWvWaveform != null) { 69 | mWvWaveform.setWaveform(waveform); 70 | } 71 | } 72 | 73 | @Override 74 | public void onFftDataCapture(Visualizer visualizer, byte[] fft, int samplingRate) { 75 | 76 | } 77 | }, Visualizer.getMaxCaptureRate(), true, false); 78 | mVisualizer.setCaptureSize(CAPTURE_SIZE); 79 | mVisualizer.setEnabled(true); 80 | } 81 | 82 | // 释放 83 | @Override protected void onPause() { 84 | if (mVisualizer != null) { 85 | mVisualizer.setEnabled(false); 86 | mVisualizer.release(); 87 | } 88 | super.onPause(); 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /app/src/main/java/me/chunyu/spike/wcl_visualizer_demo/permissions/PermissionsActivity.java: -------------------------------------------------------------------------------- 1 | package me.chunyu.spike.wcl_visualizer_demo.permissions; 2 | 3 | import android.app.Activity; 4 | import android.content.Intent; 5 | import android.content.pm.PackageManager; 6 | import android.net.Uri; 7 | import android.os.Bundle; 8 | import android.provider.Settings; 9 | import android.support.annotation.NonNull; 10 | import android.support.annotation.Nullable; 11 | import android.support.v4.app.ActivityCompat; 12 | import android.support.v7.app.AlertDialog; 13 | import android.support.v7.app.AppCompatActivity; 14 | 15 | import me.chunyu.spike.wcl_visualizer_demo.R; 16 | 17 | /** 18 | * 处理权限的类 19 | *

20 | * Created by wangchenlong on 16/2/11. 21 | */ 22 | public class PermissionsActivity extends AppCompatActivity { 23 | public static final int PERMISSIONS_GRANTED = 0; 24 | public static final int PERMISSIONS_DENIED = 1; 25 | 26 | private static final int PERMISSION_REQUEST_CODE = 0; 27 | private static final String EXTRA_PERMISSIONS = "me.chunyu.clwang.permissions.extra_permissions"; 28 | private static final String PACKAGE_URL_SCHEME = "package:"; 29 | 30 | private PermissionsChecker mChecker; // 检查权限 31 | private boolean mRequiresCheck; // 是否检查 32 | 33 | // 启动当前的Activity 34 | public static void startActivityForResult(Activity activity, int requestCode, String... permissions) { 35 | Intent intent = new Intent(activity, PermissionsActivity.class); 36 | intent.putExtra(EXTRA_PERMISSIONS, permissions); 37 | ActivityCompat.startActivityForResult(activity, intent, requestCode, null); 38 | } 39 | 40 | @Override protected void onCreate(@Nullable Bundle savedInstanceState) { 41 | super.onCreate(savedInstanceState); 42 | 43 | if (getIntent() == null || !getIntent().hasExtra(EXTRA_PERMISSIONS)) { 44 | throw new RuntimeException("当前Activity需要使用静态方法startActivityForResult启动"); 45 | } 46 | 47 | setContentView(R.layout.activity_permissions); 48 | 49 | mChecker = new PermissionsChecker(this); 50 | mRequiresCheck = true; 51 | } 52 | 53 | @Override protected void onResume() { 54 | super.onResume(); 55 | 56 | if (mRequiresCheck) { 57 | String[] permissions = getIntent().getStringArrayExtra(EXTRA_PERMISSIONS); 58 | 59 | if (mChecker.lakesPermissions(permissions)) { 60 | requestPermissions(permissions); 61 | } else { 62 | allPermissionsGranted(); 63 | } 64 | } else { 65 | mRequiresCheck = true; 66 | } 67 | } 68 | 69 | private void requestPermissions(String... permissions) { 70 | ActivityCompat.requestPermissions(this, permissions, PERMISSION_REQUEST_CODE); 71 | } 72 | 73 | private void allPermissionsGranted() { 74 | setResult(PERMISSIONS_GRANTED); 75 | finish(); 76 | } 77 | 78 | // 权限管理的返回 79 | @Override 80 | public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { 81 | if (requestCode == PERMISSION_REQUEST_CODE && hasAllPermissionsGranted(grantResults)) { 82 | mRequiresCheck = true; 83 | allPermissionsGranted(); 84 | } else { 85 | mRequiresCheck = false; 86 | showMissingPermissionDialog(); 87 | } 88 | 89 | } 90 | 91 | // 判断是否拥有所有权限 92 | private boolean hasAllPermissionsGranted(@NonNull int[] grantResults) { 93 | for (int grantResult : grantResults) { 94 | if (grantResult == PackageManager.PERMISSION_DENIED) { 95 | return false; 96 | } 97 | } 98 | return true; 99 | } 100 | 101 | private void showMissingPermissionDialog() { 102 | AlertDialog.Builder builder = new AlertDialog.Builder(PermissionsActivity.this); 103 | builder.setTitle(R.string.help).setMessage(R.string.string_help_text); 104 | builder.setNegativeButton(R.string.quit, ((dialog, which) -> { 105 | setResult(PERMISSIONS_DENIED); 106 | finish(); 107 | })); 108 | builder.setPositiveButton(R.string.settings, (dialog, which) -> { 109 | startAppSettings(); 110 | }); 111 | builder.show(); 112 | } 113 | 114 | private void startAppSettings() { 115 | Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS); 116 | intent.setData(Uri.parse(PACKAGE_URL_SCHEME + getPackageName())); 117 | startActivity(intent); 118 | } 119 | } 120 | 121 | 122 | -------------------------------------------------------------------------------- /app/src/main/java/me/chunyu/spike/wcl_visualizer_demo/permissions/PermissionsChecker.java: -------------------------------------------------------------------------------- 1 | package me.chunyu.spike.wcl_visualizer_demo.permissions; 2 | 3 | import android.content.Context; 4 | import android.content.pm.PackageManager; 5 | import android.support.v4.content.ContextCompat; 6 | 7 | /** 8 | * 权限检测 9 | *

10 | * Created by wangchenlong on 16/2/11. 11 | */ 12 | public class PermissionsChecker { 13 | private final Context mContext; 14 | 15 | public PermissionsChecker(Context context) { 16 | mContext = context.getApplicationContext(); 17 | } 18 | 19 | // 判断是否缺少权限 20 | public boolean lakesPermissions(String... permissions) { 21 | for (String permission : permissions) { 22 | if (lakesPermission(permission)) 23 | return true; 24 | } 25 | return false; 26 | } 27 | 28 | private boolean lakesPermission(String permission) { 29 | return ContextCompat.checkSelfPermission(mContext, permission) == PackageManager.PERMISSION_DENIED; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /app/src/main/java/me/chunyu/spike/wcl_visualizer_demo/visualizers/RendererFactory.java: -------------------------------------------------------------------------------- 1 | package me.chunyu.spike.wcl_visualizer_demo.visualizers; 2 | 3 | import android.support.annotation.ColorInt; 4 | 5 | /** 6 | * 工厂模式 7 | *

8 | * Created by wangchenlong on 16/2/12. 9 | */ 10 | public class RendererFactory { 11 | public WaveformRenderer createSimpleWaveformRender(@ColorInt int foreground, @ColorInt int background) { 12 | return SimpleWaveformRenderer.newInstance(background, foreground); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /app/src/main/java/me/chunyu/spike/wcl_visualizer_demo/visualizers/SimpleWaveformRenderer.java: -------------------------------------------------------------------------------- 1 | package me.chunyu.spike.wcl_visualizer_demo.visualizers; 2 | 3 | import android.graphics.Canvas; 4 | import android.graphics.Paint; 5 | import android.graphics.Path; 6 | import android.support.annotation.ColorInt; 7 | 8 | /** 9 | * 波纹渲染逻辑 10 | *

11 | * Created by wangchenlong on 16/2/12. 12 | */ 13 | public class SimpleWaveformRenderer implements WaveformRenderer { 14 | 15 | private static final int Y_FACTOR = 0xFF; // 2的8次方 = 256 16 | private static final float HALF_FACTOR = 0.5f; 17 | 18 | @ColorInt private final int mBackgroundColor; 19 | private final Paint mForegroundPaint; 20 | private final Path mWaveformPath; 21 | 22 | private SimpleWaveformRenderer(@ColorInt int backgroundColor, Paint foregroundPaint, Path waveformPath) { 23 | mBackgroundColor = backgroundColor; 24 | mForegroundPaint = foregroundPaint; 25 | mWaveformPath = waveformPath; 26 | } 27 | 28 | public static SimpleWaveformRenderer newInstance(@ColorInt int backgroundColor, @ColorInt int foregroundColour) { 29 | Paint paint = new Paint(); 30 | paint.setColor(foregroundColour); 31 | paint.setAntiAlias(true); // 抗锯齿 32 | paint.setStrokeWidth(8.0f); // 设置宽度 33 | paint.setStyle(Paint.Style.STROKE); // 填充 34 | 35 | Path waveformPath = new Path(); 36 | 37 | return new SimpleWaveformRenderer(backgroundColor, paint, waveformPath); 38 | } 39 | 40 | @Override public void render(Canvas canvas, byte[] waveform) { 41 | canvas.drawColor(mBackgroundColor); 42 | float width = canvas.getWidth(); 43 | float height = canvas.getHeight(); 44 | 45 | mWaveformPath.reset(); 46 | 47 | // 没有数据 48 | if (waveform != null) { 49 | // 绘制波形 50 | renderWaveform(waveform, width, height); 51 | } else { 52 | // 绘制直线 53 | renderBlank(width, height); 54 | } 55 | 56 | canvas.drawPath(mWaveformPath, mForegroundPaint); 57 | } 58 | 59 | private void renderWaveform(byte[] waveform, float width, float height) { 60 | float xIncrement = width / (float) (waveform.length); // 水平块数 61 | float yIncrement = height / Y_FACTOR; // 竖直块数 62 | int halfHeight = (int) (height * HALF_FACTOR); // 居中位置 63 | mWaveformPath.moveTo(0, halfHeight); 64 | for (int i = 1; i < waveform.length; ++i) { 65 | float yPosition = waveform[i] > 0 ? 66 | height - (yIncrement * waveform[i]) : -(yIncrement * waveform[i]); 67 | mWaveformPath.lineTo(xIncrement * i, yPosition); 68 | } 69 | mWaveformPath.lineTo(width, halfHeight); // 最后的点, 水平居中 70 | } 71 | 72 | // 居中画一条直线 73 | private void renderBlank(float width, float height) { 74 | int y = (int) (height * HALF_FACTOR); 75 | mWaveformPath.moveTo(0, y); 76 | mWaveformPath.lineTo(width, y); 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /app/src/main/java/me/chunyu/spike/wcl_visualizer_demo/visualizers/WaveformRenderer.java: -------------------------------------------------------------------------------- 1 | package me.chunyu.spike.wcl_visualizer_demo.visualizers; 2 | 3 | import android.graphics.Canvas; 4 | 5 | /** 6 | * 音频波纹渲染接口 7 | *

8 | * Created by wangchenlong on 16/2/11. 9 | */ 10 | public interface WaveformRenderer { 11 | void render(Canvas canvas, byte[] waveform); 12 | } 13 | -------------------------------------------------------------------------------- /app/src/main/java/me/chunyu/spike/wcl_visualizer_demo/visualizers/WaveformView.java: -------------------------------------------------------------------------------- 1 | package me.chunyu.spike.wcl_visualizer_demo.visualizers; 2 | 3 | import android.annotation.TargetApi; 4 | import android.content.Context; 5 | import android.graphics.Canvas; 6 | import android.util.AttributeSet; 7 | import android.view.View; 8 | 9 | import java.util.Arrays; 10 | 11 | /** 12 | * 音频波纹视图 13 | *

14 | * Created by wangchenlong on 16/2/11. 15 | */ 16 | public class WaveformView extends View { 17 | 18 | private WaveformRenderer mRenderer; // 绘制类 19 | private byte[] mWaveform; // 波纹形状 20 | 21 | public WaveformView(Context context) { 22 | super(context); 23 | } 24 | 25 | public WaveformView(Context context, AttributeSet attrs) { 26 | super(context, attrs); 27 | } 28 | 29 | public WaveformView(Context context, AttributeSet attrs, int defStyleAttr) { 30 | super(context, attrs, defStyleAttr); 31 | } 32 | 33 | @TargetApi(21) 34 | public WaveformView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { 35 | super(context, attrs, defStyleAttr, defStyleRes); 36 | } 37 | 38 | public void setRenderer(WaveformRenderer renderer) { 39 | mRenderer = renderer; 40 | } 41 | 42 | public void setWaveform(byte[] waveform) { 43 | mWaveform = Arrays.copyOf(waveform, waveform.length); // 数组复制 44 | invalidate(); // 设置波纹之后, 需要重绘 45 | } 46 | 47 | @Override protected void onDraw(Canvas canvas) { 48 | super.onDraw(canvas); 49 | if (mRenderer != null) { 50 | mRenderer.render(canvas, mWaveform); 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_mic_off.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 13 | 14 | 15 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_permissions.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 16 | 17 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SpikeKing/wcl-visualizer-demo/7bdf5b4e13fbc683ba54075f8dd5dacbff0a6f64/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SpikeKing/wcl-visualizer-demo/7bdf5b4e13fbc683ba54075f8dd5dacbff0a6f64/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SpikeKing/wcl-visualizer-demo/7bdf5b4e13fbc683ba54075f8dd5dacbff0a6f64/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SpikeKing/wcl-visualizer-demo/7bdf5b4e13fbc683ba54075f8dd5dacbff0a6f64/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SpikeKing/wcl-visualizer-demo/7bdf5b4e13fbc683ba54075f8dd5dacbff0a6f64/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/values-w820dp/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 64dp 6 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #FF4081 4 | #FF83FA 5 | #FF1493 6 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/values/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 16dp 4 | 16dp 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | wcl-visualizer-demo 3 | 运行应用需要音频权限.\n\n当提示时请授予这些权限. 4 | 5 | 设置 6 | 帮助 7 | 当前应用缺少必要权限。\n\n请点击\"设置\"-\"权限\"-打开所需权限。\n\n最后点击两次后退按钮,即可返回。 8 | 退出 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 10 | 11 |