diff --git a/buildSrc/src/main/groovy/Config.groovy b/buildSrc/src/main/groovy/Config.groovy
index a69b8907c7..9a8d69d659 100644
--- a/buildSrc/src/main/groovy/Config.groovy
+++ b/buildSrc/src/main/groovy/Config.groovy
@@ -34,7 +34,7 @@ class Config {
lib_base : new ModuleConfig(isApply: true , useLocal: true , localPath: "./lib/base"),
lib_common : new ModuleConfig(isApply: true , useLocal: true , localPath: "./lib/common"),
lib_subutil : new ModuleConfig(isApply: true , useLocal: true , localPath: "./lib/subutil"),
- lib_utilcode : new ModuleConfig(isApply: true , useLocal: false, localPath: "./lib/utilcode", remotePath: "com.blankj:utilcodex:$Config.versionName"),
+ lib_utilcode : new ModuleConfig(isApply: true , useLocal: true , localPath: "./lib/utilcode", remotePath: "com.blankj:utilcodex:$Config.versionName"),
lib_utildebug : new ModuleConfig(isApply: true , useLocal: true , localPath: "./lib/utildebug"),
lib_utildebug_no_op : new ModuleConfig(isApply: true , useLocal: true , localPath: "./lib/utildebug-no-op"),
/*Don't delete this line*/
diff --git a/config/publish.gradle b/config/publish.gradle
index 7608215123..17238d23ea 100644
--- a/config/publish.gradle
+++ b/config/publish.gradle
@@ -21,206 +21,206 @@
./gradlew :xxmodule:publish2Remote -> upload to mavenCentral
*/
-apply plugin: 'maven-publish'
-apply plugin: 'signing'
-
-ext.multiPublishMode = true
-
-File localPropertiesFile = project.rootProject.file("local.properties");
-if (!localPropertiesFile.exists()) {
- return
-}
-
-Properties properties = new Properties()
-properties.load(new FileInputStream(localPropertiesFile))
-properties.each { name, value -> ext[name] = value }
-
-afterEvaluate {
- def ext = project.ext
- publishing {
- publications {
- release(MavenPublication) {
- groupId ext.groupId
- artifactId ext.artifactId
- version ext.version
-
- if (isAndroidEnv(project)) {
- if (project.ext.multiPublishMode) {
- artifact("$buildDir/outputs/aar/${project.getName()}-release.aar")
- artifact sourcesJar
- } else {
- from project.components.release
- }
- } else {
- from project.components.java
- }
-
- pom {
- name = ext.artifactId
- description = ext.artifactId
- url = ext.website
-
- licenses {
- license {
- name = 'The Apache Software License, Version 2.0'
- url = 'http://www.apache.org/licenses/LICENSE-2.0.txt'
- }
- }
- developers {
- developer {
- id = ext.ossrhUsername
- name = ext.ossrhUsername
- }
- }
- scm {
- url = ext.website
- connection = ext.website
- developerConnection = ext.website + ".git"
- }
-
- if (project.ext.multiPublishMode) {
- withXml {
- def dependenciesNode = asNode().getAt('dependencies')[0] ?:
- asNode().appendNode('dependencies')
-
- configurations.api.getDependencies().each {
- dep -> addDependency(project, dependenciesNode, dep, "compile")
- }
- configurations.implementation.getDependencies().each {
- dep -> addDependency(project, dependenciesNode, dep, "runtime")
- }
- }
- }
- }
- }
- }
-
- repositories {
- maven {
- // s01 is newest
- def releasesUrl = "https://s01.oss.sonatype.org/content/repositories/releases/"
- def snapshotUrl = "https://s01.oss.sonatype.org/content/repositories/snapshots/"
- url = version.toUpperCase().endsWith('SNAPSHOT') ? snapshotUrl : releasesUrl
-
- credentials {
- username ossrhUsername
- password ossrhPassword
- }
- }
- }
- }
-
- signing {
- sign publishing.publications
- }
-}
-
-private void addDependency(Project project, def dependenciesNode, Dependency dep, String scope) {
- if (dep.group == null || dep.version == null || dep.name == null || dep.name == "unspecified") {
- return
- }
-
- final dependencyNode = dependenciesNode.appendNode('dependency')
- dependencyNode.appendNode('scope', scope)
-
- if (dep.version == 'unspecified') {
- // 检测 module 中的 dependencies 是否有源码依赖
- // 如果是源码依赖,而且没有在 config 中配置 remotePath,
- // 那么发布到仓库,其他地方依赖该库时会找不到源码的那个库
- println "publish -> module(unspecified) <${dep.group}:${dep.name}:${dep.version}>"
- if (project.ext.groupId || project.ext.version) {
- throw new GradleException("The module of <" + dep.name + "> should set groupId & version.")
- }
- // 源码依赖,但配置了 remotePath,让 pom 中写入 remotePath
- println("publish -> module(wrapped) <${project.ext.groupId}:${name}:${project.ext.version}>")
-
- dependencyNode.appendNode('groupId', project.ext.pomGroupID)
- dependencyNode.appendNode('artifactId', dep.name)
- dependencyNode.appendNode('version', project.ext.pomVersion)
- } else {
- dependencyNode.appendNode('groupId', dep.group)
- dependencyNode.appendNode('artifactId', dep.name)
- dependencyNode.appendNode('version', dep.version)
- println("publish -> library <${dep.group}:${dep.name}:${dep.version}>")
- }
-
- if (!dep.transitive) {
- // In case of non transitive dependency,
- // all its dependencies should be force excluded from them POM file
- final exclusionNode = dependencyNode.appendNode('exclusions').appendNode('exclusion')
- exclusionNode.appendNode('groupId', '*')
- exclusionNode.appendNode('artifactId', '*')
- } else if (!dep.properties.excludeRules.empty) {
- // For transitive with exclusions, all exclude rules should be added to the POM file
- final exclusions = dependencyNode.appendNode('exclusions')
- dep.properties.excludeRules.each { ExcludeRule rule ->
- final exclusionNode = exclusions.appendNode('exclusion')
- exclusionNode.appendNode('groupId', rule.group ?: '*')
- exclusionNode.appendNode('artifactId', rule.module ?: '*')
- }
- }
-}
-
-if (isAndroidEnv(project)) {
- // This generates sources.jar
- task sourcesJar(type: Jar) {
- classifier = 'sources'
- from android.sourceSets.main.java.source
- }
-
- task javadoc(type: Javadoc) {
- source = android.sourceSets.main.java.source
- classpath += configurations.compile
- classpath += project.files(android.getBootClasspath().join(File.pathSeparator))
- }
-
- task javadocJar(type: Jar, dependsOn: javadoc) {
- classifier = 'javadoc'
- from javadoc.destinationDir
- }
-} else {
- task sourcesJar(type: Jar, dependsOn: classes) {
- classifier = 'sources'
- from sourceSets.main.allSource
- }
-
- task javadocJar(type: Jar, dependsOn: javadoc) {
- classifier = 'javadoc'
- from javadoc.destinationDir
- }
-}
-
-if (project.hasProperty("kotlin")) {
- // Disable creating javadocs
- project.tasks.withType(Javadoc) {
- enabled = false
- }
-}
-
-javadoc {
- options {
- encoding "UTF-8"
- charSet 'UTF-8'
- author true
- version project.ext.version
- links "http://docs.oracle.com/javase/7/docs/api"
- title "${project.ext.artifactId} ${project.ext.version}"
- }
-}
-
-artifacts {
- archives javadocJar
- archives sourcesJar
-}
-
-static def isAndroidEnv(Project project) {
- return project.getPlugins().hasPlugin('com.android.application') || project.getPlugins().hasPlugin('com.android.library')
-}
-
-task publish2Local(type: GradleBuild) {
- tasks = ['assemble', 'publishReleasePublicationToMavenLocal']
-}
-
-task publish2Remote(type: GradleBuild) {
- tasks = ['assemble', 'publishReleasePublicationToMavenRepository']
-}
\ No newline at end of file
+//apply plugin: 'maven-publish'
+//apply plugin: 'signing'
+//
+//ext.multiPublishMode = true
+//
+//File localPropertiesFile = project.rootProject.file("local.properties");
+//if (!localPropertiesFile.exists()) {
+// return
+//}
+//
+//Properties properties = new Properties()
+//properties.load(new FileInputStream(localPropertiesFile))
+//properties.each { name, value -> ext[name] = value }
+//
+//afterEvaluate {
+// def ext = project.ext
+// publishing {
+// publications {
+// release(MavenPublication) {
+// groupId ext.groupId
+// artifactId ext.artifactId
+// version ext.version
+//
+// if (isAndroidEnv(project)) {
+// if (project.ext.multiPublishMode) {
+// artifact("$buildDir/outputs/aar/${project.getName()}-release.aar")
+// artifact sourcesJar
+// } else {
+// from project.components.release
+// }
+// } else {
+// from project.components.java
+// }
+//
+// pom {
+// name = ext.artifactId
+// description = ext.artifactId
+// url = ext.website
+//
+// licenses {
+// license {
+// name = 'The Apache Software License, Version 2.0'
+// url = 'http://www.apache.org/licenses/LICENSE-2.0.txt'
+// }
+// }
+// developers {
+// developer {
+// id = ext.ossrhUsername
+// name = ext.ossrhUsername
+// }
+// }
+// scm {
+// url = ext.website
+// connection = ext.website
+// developerConnection = ext.website + ".git"
+// }
+//
+// if (project.ext.multiPublishMode) {
+// withXml {
+// def dependenciesNode = asNode().getAt('dependencies')[0] ?:
+// asNode().appendNode('dependencies')
+//
+// configurations.api.getDependencies().each {
+// dep -> addDependency(project, dependenciesNode, dep, "compile")
+// }
+// configurations.implementation.getDependencies().each {
+// dep -> addDependency(project, dependenciesNode, dep, "runtime")
+// }
+// }
+// }
+// }
+// }
+// }
+//
+// repositories {
+// maven {
+// // s01 is newest
+// def releasesUrl = "https://s01.oss.sonatype.org/content/repositories/releases/"
+// def snapshotUrl = "https://s01.oss.sonatype.org/content/repositories/snapshots/"
+// url = version.toUpperCase().endsWith('SNAPSHOT') ? snapshotUrl : releasesUrl
+//
+// credentials {
+// username ossrhUsername
+// password ossrhPassword
+// }
+// }
+// }
+// }
+//
+// signing {
+// sign publishing.publications
+// }
+//}
+//
+//private void addDependency(Project project, def dependenciesNode, Dependency dep, String scope) {
+// if (dep.group == null || dep.version == null || dep.name == null || dep.name == "unspecified") {
+// return
+// }
+//
+// final dependencyNode = dependenciesNode.appendNode('dependency')
+// dependencyNode.appendNode('scope', scope)
+//
+// if (dep.version == 'unspecified') {
+// // 检测 module 中的 dependencies 是否有源码依赖
+// // 如果是源码依赖,而且没有在 config 中配置 remotePath,
+// // 那么发布到仓库,其他地方依赖该库时会找不到源码的那个库
+// println "publish -> module(unspecified) <${dep.group}:${dep.name}:${dep.version}>"
+// if (project.ext.groupId || project.ext.version) {
+// throw new GradleException("The module of <" + dep.name + "> should set groupId & version.")
+// }
+// // 源码依赖,但配置了 remotePath,让 pom 中写入 remotePath
+// println("publish -> module(wrapped) <${project.ext.groupId}:${name}:${project.ext.version}>")
+//
+// dependencyNode.appendNode('groupId', project.ext.pomGroupID)
+// dependencyNode.appendNode('artifactId', dep.name)
+// dependencyNode.appendNode('version', project.ext.pomVersion)
+// } else {
+// dependencyNode.appendNode('groupId', dep.group)
+// dependencyNode.appendNode('artifactId', dep.name)
+// dependencyNode.appendNode('version', dep.version)
+// println("publish -> library <${dep.group}:${dep.name}:${dep.version}>")
+// }
+//
+// if (!dep.transitive) {
+// // In case of non transitive dependency,
+// // all its dependencies should be force excluded from them POM file
+// final exclusionNode = dependencyNode.appendNode('exclusions').appendNode('exclusion')
+// exclusionNode.appendNode('groupId', '*')
+// exclusionNode.appendNode('artifactId', '*')
+// } else if (!dep.properties.excludeRules.empty) {
+// // For transitive with exclusions, all exclude rules should be added to the POM file
+// final exclusions = dependencyNode.appendNode('exclusions')
+// dep.properties.excludeRules.each { ExcludeRule rule ->
+// final exclusionNode = exclusions.appendNode('exclusion')
+// exclusionNode.appendNode('groupId', rule.group ?: '*')
+// exclusionNode.appendNode('artifactId', rule.module ?: '*')
+// }
+// }
+//}
+//
+//if (isAndroidEnv(project)) {
+// // This generates sources.jar
+// task sourcesJar(type: Jar) {
+// classifier = 'sources'
+// from android.sourceSets.main.java.source
+// }
+//
+// task javadoc(type: Javadoc) {
+// source = android.sourceSets.main.java.source
+// classpath += configurations.compile
+// classpath += project.files(android.getBootClasspath().join(File.pathSeparator))
+// }
+//
+// task javadocJar(type: Jar, dependsOn: javadoc) {
+// classifier = 'javadoc'
+// from javadoc.destinationDir
+// }
+//} else {
+// task sourcesJar(type: Jar, dependsOn: classes) {
+// classifier = 'sources'
+// from sourceSets.main.allSource
+// }
+//
+// task javadocJar(type: Jar, dependsOn: javadoc) {
+// classifier = 'javadoc'
+// from javadoc.destinationDir
+// }
+//}
+//
+//if (project.hasProperty("kotlin")) {
+// // Disable creating javadocs
+// project.tasks.withType(Javadoc) {
+// enabled = false
+// }
+//}
+//
+//javadoc {
+// options {
+// encoding "UTF-8"
+// charSet 'UTF-8'
+// author true
+// version project.ext.version
+// links "http://docs.oracle.com/javase/7/docs/api"
+// title "${project.ext.artifactId} ${project.ext.version}"
+// }
+//}
+//
+//artifacts {
+// archives javadocJar
+// archives sourcesJar
+//}
+//
+//static def isAndroidEnv(Project project) {
+// return project.getPlugins().hasPlugin('com.android.application') || project.getPlugins().hasPlugin('com.android.library')
+//}
+//
+//task publish2Local(type: GradleBuild) {
+// tasks = ['assemble', 'publishReleasePublicationToMavenLocal']
+//}
+//
+//task publish2Remote(type: GradleBuild) {
+// tasks = ['assemble', 'publishReleasePublicationToMavenRepository']
+//}
\ No newline at end of file
diff --git a/feature/utilcode/pkg/src/main/AndroidManifest.xml b/feature/utilcode/pkg/src/main/AndroidManifest.xml
index 8da0667a23..94ce260cb3 100644
--- a/feature/utilcode/pkg/src/main/AndroidManifest.xml
+++ b/feature/utilcode/pkg/src/main/AndroidManifest.xml
@@ -275,6 +275,9 @@
android:name=".feature.volume.VolumeActivity"
android:configChanges="orientation|keyboardHidden|screenSize"
android:launchMode="singleTop" />
+
> {
+ return CollectionUtils.newArrayList(
+ startRingItemCLick(
+ "Start Ring 1",
+ "ring"
+ ),
+ volumeItemSeekBar("Adjust Ring 1 Volume", "ring"),
+ rateItemSeekBar("Adjust Ring 1 Rate", "ring"),
+ getLoopSwitch("Set Ring 1 Loop", "ring"),
+ pauseRingItemCLick("Pause Ring 1", "ring"),
+ resumeRingItemCLick("Resume Ring 1", "ring"),
+ stopRingItemCLick("Stop Ring 1", "ring"),
+ startRingItemCLick(
+ "Start Ring 2",
+ "ring2"
+ ),
+ volumeItemSeekBar("Adjust Ring 2 Volume", "ring2"),
+ rateItemSeekBar("Adjust Ring 2 Rate", "ring2"),
+ getLoopSwitch("Set Ring 2 Loop", "ring2"),
+ pauseRingItemCLick("Pause Ring 2", "ring2"),
+ resumeRingItemCLick("Resume Ring 2", "ring2"),
+ stopRingItemCLick("Stop Ring 2", "ring2")
+ )
+ }
+
+ private fun startRingItemCLick(
+ title: CharSequence,
+ resKey: String
+ ): CommonItemClick {
+ return CommonItemClick(title) {
+ SoundUtils.getInstance().stop(resKey)
+ SoundUtils.getInstance().play(resKey)
+ }
+ }
+
+ private fun volumeItemSeekBar(title: CharSequence, resKey: String): CommonItemSeekBar {
+ var curPos = 100
+ return CommonItemSeekBar(
+ title,
+ 100,
+ object : CommonItemSeekBar.ProgressListener() {
+ override fun getCurValue(): Int {
+ return curPos
+ }
+
+ override fun onProgressChanged(
+ seekBar: SeekBar?,
+ progress: Int,
+ fromUser: Boolean
+ ) {
+ curPos = progress
+ SoundUtils.getInstance()
+ .setVolume(resKey, progress / 100f, progress / 100f)
+ }
+ })
+ }
+
+ private fun rateItemSeekBar(title: CharSequence, resKey: String): CommonItemSeekBar {
+ var curPos = 100
+
+ val itemSeekBar = CommonItemSeekBar(
+ title,
+ 50,
+ 200,
+ object : CommonItemSeekBar.ProgressListener() {
+ override fun getCurValue(): Int {
+ return curPos
+ }
+
+ override fun onProgressChanged(
+ seekBar: SeekBar?,
+ progress: Int,
+ fromUser: Boolean
+ ) {
+ curPos = progress
+ SoundUtils.getInstance()
+ .setRate(resKey, progress / 100f)
+ }
+ })
+ itemSeekBar
+ return itemSeekBar
+ }
+
+
+ private fun getLoopSwitch(title: CharSequence, resKey: String): CommonItemSwitch {
+ var isChecked = false
+ return CommonItemSwitch(
+ title,
+ {
+ isChecked
+ },
+ {
+ isChecked = it
+ SoundUtils.getInstance().setLoop(resKey, isChecked)
+ }
+ )
+ }
+
+
+ private fun pauseRingItemCLick(title: CharSequence, resKey: String): CommonItemClick {
+ return CommonItemClick(title) {
+ SoundUtils.getInstance().pause(resKey)
+ }
+ }
+
+ private fun resumeRingItemCLick(title: CharSequence, resKey: String): CommonItemClick {
+ return CommonItemClick(title) {
+ SoundUtils.getInstance().resume(resKey)
+ }
+ }
+
+ private fun stopRingItemCLick(title: CharSequence, resKey: String): CommonItemClick {
+ return CommonItemClick(title) {
+ SoundUtils.getInstance().stop(resKey)
+ }
+ }
+
+ override fun onDestroy() {
+ super.onDestroy()
+ SoundUtils.getInstance().release()
+ }
+}
diff --git a/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/volume/VolumeActivity.kt b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/volume/VolumeActivity.kt
index 26d67dda07..bc1ff3de0a 100644
--- a/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/volume/VolumeActivity.kt
+++ b/feature/utilcode/pkg/src/main/java/com/blankj/utilcode/pkg/feature/volume/VolumeActivity.kt
@@ -3,12 +3,16 @@ package com.blankj.utilcode.pkg.feature.volume
import android.content.Context
import android.content.Intent
import android.media.AudioManager
+import android.os.Bundle
+import android.view.View
import android.widget.SeekBar
import com.blankj.common.activity.CommonActivity
import com.blankj.common.item.CommonItem
+import com.blankj.common.item.CommonItemClick
import com.blankj.common.item.CommonItemSeekBar
import com.blankj.utilcode.pkg.R
import com.blankj.utilcode.util.CollectionUtils
+import com.blankj.utilcode.util.SoundUtils
import com.blankj.utilcode.util.VolumeUtils
/**
@@ -32,30 +36,43 @@ class VolumeActivity : CommonActivity() {
return R.string.demo_volume
}
+
override fun bindItems(): MutableList> {
return CollectionUtils.newArrayList(
- getItemSeekBar("Voice Call", AudioManager.STREAM_VOICE_CALL),
- getItemSeekBar("System", AudioManager.STREAM_SYSTEM),
- getItemSeekBar("Music", AudioManager.STREAM_MUSIC),
- getItemSeekBar("Ring", AudioManager.STREAM_RING),
- getItemSeekBar("Alarm", AudioManager.STREAM_ALARM),
- getItemSeekBar("Notification", AudioManager.STREAM_NOTIFICATION),
- getItemSeekBar("Dtmf", AudioManager.STREAM_DTMF)
+ getItemSeekBar("Voice Call", AudioManager.STREAM_VOICE_CALL),
+ getItemSeekBar("System", AudioManager.STREAM_SYSTEM),
+ getItemSeekBar("Music", AudioManager.STREAM_MUSIC),
+ getItemSeekBar("Ring", AudioManager.STREAM_RING),
+ getItemSeekBar("Alarm", AudioManager.STREAM_ALARM),
+ getItemSeekBar("Notification", AudioManager.STREAM_NOTIFICATION),
+ getItemSeekBar("Dtmf", AudioManager.STREAM_DTMF)
)
}
+ override fun initView(savedInstanceState: Bundle?, contentView: View?) {
+ super.initView(savedInstanceState, contentView)
+ }
+
private fun getItemSeekBar(title: CharSequence, streamType: Int): CommonItemSeekBar {
- return CommonItemSeekBar(title, VolumeUtils.getMaxVolume(streamType), object : CommonItemSeekBar.ProgressListener() {
- override fun getCurValue(): Int {
- return VolumeUtils.getVolume(streamType)
- }
-
- override fun onProgressChanged(seekBar: SeekBar?, progress: Int, fromUser: Boolean) {
- VolumeUtils.setVolume(streamType, progress, AudioManager.FLAG_SHOW_UI)
- }
- })
+ return CommonItemSeekBar(
+ title,
+ VolumeUtils.getMaxVolume(streamType),
+ object : CommonItemSeekBar.ProgressListener() {
+ override fun getCurValue(): Int {
+ return VolumeUtils.getVolume(streamType)
+ }
+
+ override fun onProgressChanged(
+ seekBar: SeekBar?,
+ progress: Int,
+ fromUser: Boolean
+ ) {
+ VolumeUtils.setVolume(streamType, progress, AudioManager.FLAG_SHOW_UI)
+ }
+ })
}
+
override fun onResume() {
super.onResume()
itemsView.updateItems(bindItems())
diff --git a/feature/utilcode/pkg/src/main/res/raw/ring.mp3 b/feature/utilcode/pkg/src/main/res/raw/ring.mp3
new file mode 100644
index 0000000000..6e113b4062
Binary files /dev/null and b/feature/utilcode/pkg/src/main/res/raw/ring.mp3 differ
diff --git a/feature/utilcode/pkg/src/main/res/raw/ring2.mp3 b/feature/utilcode/pkg/src/main/res/raw/ring2.mp3
new file mode 100644
index 0000000000..a7d090fac7
Binary files /dev/null and b/feature/utilcode/pkg/src/main/res/raw/ring2.mp3 differ
diff --git a/feature/utilcode/pkg/src/main/res/values/strings.xml b/feature/utilcode/pkg/src/main/res/values/strings.xml
index ccec698647..a33469ac53 100644
--- a/feature/utilcode/pkg/src/main/res/values/strings.xml
+++ b/feature/utilcode/pkg/src/main/res/values/strings.xml
@@ -43,6 +43,7 @@
TransActivity Demo
VibrateUtils Demo
VolumeUtils Demo
+ SoundUtils Demo
Shared Element
diff --git a/lib/common/src/main/java/com/blankj/common/item/CommonItemSeekBar.java b/lib/common/src/main/java/com/blankj/common/item/CommonItemSeekBar.java
index 14ff005851..1fdb0062cd 100644
--- a/lib/common/src/main/java/com/blankj/common/item/CommonItemSeekBar.java
+++ b/lib/common/src/main/java/com/blankj/common/item/CommonItemSeekBar.java
@@ -1,5 +1,6 @@
package com.blankj.common.item;
+import android.os.Build;
import android.view.MotionEvent;
import android.view.View;
import android.widget.SeekBar;
@@ -22,10 +23,11 @@
*/
public class CommonItemSeekBar extends CommonItem {
- private CharSequence mTitle;
- private CharSequence mContent;
- private int mMaxProgress;
- private int mCurProgress;
+ private CharSequence mTitle;
+ private CharSequence mContent;
+ private int mMinProgress;
+ private int mMaxProgress;
+ private int mCurProgress;
private ProgressListener mProgressListener;
public CommonItemSeekBar(@StringRes int title, int maxProgress, @NonNull ProgressListener listener) {
@@ -41,6 +43,16 @@ public CommonItemSeekBar(@NonNull CharSequence title, int maxProgress, @NonNull
mContent = String.valueOf(mCurProgress);
}
+ public CommonItemSeekBar(@NonNull CharSequence title, int minProgress, int maxProgress, @NonNull ProgressListener listener) {
+ super(R.layout.common_item_title_seekbar);
+ mTitle = title;
+ mMaxProgress = maxProgress;
+ mMinProgress = minProgress;
+ mCurProgress = listener.getCurValue();
+ mProgressListener = listener;
+ mContent = String.valueOf(mCurProgress);
+ }
+
@Override
public void bind(@NonNull ItemViewHolder holder, int position) {
@@ -53,6 +65,9 @@ public void bind(@NonNull ItemViewHolder holder, int position) {
final SeekBar seekBar = holder.findViewById(R.id.commonItemSb);
seekBar.setMax(mMaxProgress);
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
+ seekBar.setMin(mMinProgress);
+ }
seekBar.setProgress(mCurProgress);
holder.itemView.setOnTouchListener(new View.OnTouchListener() {
@Override
diff --git a/lib/utilcode/src/main/java/com/blankj/utilcode/util/SoundUtils.java b/lib/utilcode/src/main/java/com/blankj/utilcode/util/SoundUtils.java
new file mode 100644
index 0000000000..2be99cce0d
--- /dev/null
+++ b/lib/utilcode/src/main/java/com/blankj/utilcode/util/SoundUtils.java
@@ -0,0 +1,410 @@
+package com.blankj.utilcode.util;
+
+import android.content.Context;
+import android.content.res.AssetFileDescriptor;
+import android.media.AudioAttributes;
+import android.media.AudioManager;
+import android.media.MediaPlayer;
+import android.media.SoundPool;
+import android.os.Build;
+import android.os.Bundle;
+import android.text.TextUtils;
+
+import androidx.annotation.RawRes;
+import androidx.annotation.RequiresApi;
+
+import com.blankj.utilcode.R;
+
+import java.io.FileDescriptor;
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Objects;
+
+/**
+ * @author leo
+ * @version 1.0
+ * @className SoundUtils
+ * @description TODO
+ * @date 2022/11/24 15:21
+ **/
+public class SoundUtils {
+
+ private int maxStreams = 5;
+ private int streamType = AudioManager.STREAM_MUSIC;
+ private int contentType = AudioAttributes.CONTENT_TYPE_UNKNOWN;
+ private int flags;
+ private boolean muted;
+ private int capturePolicy = AudioAttributes.ALLOW_CAPTURE_BY_NONE;
+ private int usage;
+
+ private HashMap soundIdMap;
+ private HashMap streamIdMap;
+
+ private static SoundUtils soundUtils;
+
+ private SoundPool soundPool;
+
+ public static SoundUtils getInstance() {
+ synchronized (SoundUtils.class) {
+ if (soundUtils == null) {
+ soundUtils = new Builder()
+ .setStreamType(AudioManager.STREAM_MUSIC)
+ .setMaxStreams(5)
+ .build();
+ }
+ }
+ return soundUtils;
+ }
+
+
+ private SoundUtils() {
+ soundIdMap = new HashMap<>();
+ streamIdMap = new HashMap<>();
+ create();
+ }
+
+
+ private void setMaxStreams(int maxStreams) {
+ this.maxStreams = maxStreams;
+ }
+
+ private void setStreamType(int streamType) {
+ this.streamType = streamType;
+ }
+
+ private void setContentType(int contentType) {
+ this.contentType = contentType;
+ }
+
+ private void setFlags(int flags) {
+ this.flags = flags;
+ }
+
+ private void setHapticChannelsMuted(boolean muted) {
+ this.muted = muted;
+ }
+
+ private void setAllowedCapturePolicy(int capturePolicy) {
+ this.capturePolicy = capturePolicy;
+ }
+
+ private void setUsage(int usage) {
+ this.usage = usage;
+ }
+
+ public static class Builder {
+
+ private int maxStreams = 5;
+ private int streamType = AudioManager.STREAM_MUSIC;
+ private int contentType = AudioAttributes.CONTENT_TYPE_UNKNOWN;
+ private int flags;
+ private boolean muted;
+ private int capturePolicy = AudioAttributes.ALLOW_CAPTURE_BY_NONE;
+ private int usage;
+
+
+ public Builder setMaxStreams(int maxStreams) {
+ this.maxStreams = maxStreams;
+ return this;
+ }
+
+ public Builder setStreamType(int streamType) {
+ this.streamType = streamType;
+ return this;
+ }
+
+ public Builder setContentType(int contentType) {
+ this.contentType = contentType;
+ return this;
+ }
+
+ public Builder setFlags(int flags) {
+ this.flags = flags;
+ return this;
+ }
+
+ public Builder setHapticChannelsMuted(boolean muted) {
+ this.muted = muted;
+ return this;
+ }
+
+ public Builder setAllowedCapturePolicy(int capturePolicy) {
+ this.capturePolicy = capturePolicy;
+ return this;
+ }
+
+ public Builder setUsage(int usage) {
+ this.usage = usage;
+ return this;
+ }
+
+ public SoundUtils build() {
+ SoundUtils soundUtils = new SoundUtils();
+ soundUtils.setFlags(flags);
+ soundUtils.setContentType(contentType);
+ soundUtils.setMaxStreams(maxStreams);
+ soundUtils.setHapticChannelsMuted(muted);
+ soundUtils.setStreamType(streamType);
+ soundUtils.setAllowedCapturePolicy(capturePolicy);
+ soundUtils.setUsage(usage);
+ return soundUtils;
+ }
+ }
+
+ private void create() {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
+ AudioAttributes attributes;
+ if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.Q) {
+ attributes = new AudioAttributes.Builder()
+ .setLegacyStreamType(streamType)
+ .setContentType(contentType)
+ .setFlags(flags)
+ .setHapticChannelsMuted(muted)
+ .setUsage(usage)
+ .setAllowedCapturePolicy(capturePolicy)
+ .build();
+ } else {
+ attributes = new AudioAttributes.Builder()
+ .setLegacyStreamType(streamType)
+ .setContentType(contentType)
+ .setFlags(flags)
+ .setUsage(usage)
+ .build();
+ }
+ soundPool = new SoundPool.Builder()
+ .setMaxStreams(maxStreams)
+ .setAudioAttributes(attributes)
+ .build();
+ } else {
+ soundPool = new SoundPool(maxStreams, streamType, 0);
+ }
+ }
+
+ public void preload(String key, @RawRes int resId) {
+ preload(key, resId, null);
+ }
+
+ public void preload(String key, @RawRes int resId, SoundPool.OnLoadCompleteListener listener) {
+
+ if (soundIdMap.size() > maxStreams) {
+ throw new IllegalArgumentException("u cannot preload raw count > maxStreams...");
+ }
+
+ int soundID = soundPool.load(Utils.getApp(), resId, 1);
+ if (listener != null) {
+ soundPool.setOnLoadCompleteListener(listener);
+ }
+ soundIdMap.put(key, soundID);
+ }
+
+ public void preload(String key, String path) {
+ preload(key, path, null);
+ }
+
+ public void preload(String key, String path, SoundPool.OnLoadCompleteListener listener) {
+
+ if (soundIdMap.size() > maxStreams) {
+ throw new IllegalArgumentException("u cannot preload raw count > maxStreams...");
+ }
+
+ int soundID = soundPool.load(path, 1);
+ if (listener != null) {
+ soundPool.setOnLoadCompleteListener(listener);
+ }
+ soundIdMap.put(key, soundID);
+ }
+
+ public void preload(String key, AssetFileDescriptor afd) {
+ preload(key, afd, null);
+ }
+
+ public void preload(String key, AssetFileDescriptor afd, SoundPool.OnLoadCompleteListener listener) {
+
+ if (soundIdMap.size() > maxStreams) {
+ throw new IllegalArgumentException("u cannot preload raw count > maxStreams...");
+ }
+
+ int soundID = soundPool.load(afd, 1);
+ if (listener != null) {
+ soundPool.setOnLoadCompleteListener(listener);
+ }
+ soundIdMap.put(key, soundID);
+ }
+
+ public void preload(String key, FileDescriptor fd, long offset, long length) {
+ preload(key, fd, offset, length, null);
+ }
+
+ public void preload(String key, FileDescriptor fd, long offset, long length, SoundPool.OnLoadCompleteListener listener) {
+
+ if (soundIdMap.size() > maxStreams) {
+ throw new IllegalArgumentException("u cannot preload raw count > maxStreams...");
+ }
+
+ int soundID = soundPool.load(fd, offset, length, 1);
+ if (listener != null) {
+ soundPool.setOnLoadCompleteListener(listener);
+ }
+ soundIdMap.put(key, soundID);
+ }
+
+
+ public void unload(String key) {
+ Integer soundId = soundIdMap.get(key);
+ if (soundId != null) {
+ soundPool.unload(soundId);
+ }
+ soundIdMap.remove(key);
+ }
+
+
+ /**
+ * @param: key
+ * @param: leftVolume left volume value (range = 0.0 to 1.0)
+ * @param: rightVolume right volume value (range = 0.0 to 1.0)
+ * @param: priority tream priority (0 = lowest priority)
+ * @param: loop loop mode (0 = no loop, -1 = loop forever)
+ * @param: rate playback rate (1.0 = normal playback, range 0.5 to 2.0)
+ * @description: TODO
+ * @return: void
+ * @author: leo
+ * @date: 2022/12/1 9:52
+ */
+ public void play(String key, float leftVolume, float rightVolume, int priority, int loop, float rate) {
+ if (soundPool != null) {
+ Integer resId = soundIdMap.get(key);
+ if (resId != null) {
+ int streamID = soundPool.play(resId, leftVolume, rightVolume, priority, loop, rate);
+ streamIdMap.put(key, streamID);
+ } else {
+ throw new IllegalStateException("i have not find this " + key + " raw!");
+ }
+ }
+ }
+
+ public void play(String key, int priority, int loop, float rate) {
+ play(key, 1, 1, priority, loop, rate);
+ }
+
+ public void play(String key, int loop, float rate) {
+ play(key, 1, 1, 1, loop, rate);
+ }
+
+ public void play(String key) {
+ play(key, 1, 1, 1, 0, 1);
+ }
+
+ public void play(String key, boolean loop) {
+ play(key, loop ? -1 : 0, 1);
+ }
+
+ public void play(String key, float rate) {
+ play(key, 0, rate);
+ }
+
+
+ public void stop(String key) {
+ Integer streamID = streamIdMap.get(key);
+ if (streamID != null) {
+ soundPool.stop(streamID);
+ }
+ }
+
+ public void resume(String key) {
+ Integer streamId = streamIdMap.get(key);
+ if (streamId != null) {
+ soundPool.resume(streamId);
+ }
+ }
+
+ public void pause(String key) {
+ Integer streamId = streamIdMap.get(key);
+ if (streamId != null) {
+ soundPool.pause(streamId);
+ }
+ }
+
+ /**
+ * @param: key
+ * @param: loop loop mode (0 = no loop, -1 = loop forever)
+ * @description: TODO
+ * @return: void
+ * @author: leo
+ * @date: 2022/12/1 10:24
+ */
+ public void setLoop(String key, int loop) {
+ if (soundPool != null) {
+ soundIdMap.get(key);
+ Integer streamId = streamIdMap.get(key);
+ if (streamId != null) {
+ soundPool.pause(streamId);
+ soundPool.setLoop(streamId, loop);
+ soundPool.resume(streamId);
+ }
+ }
+ }
+
+ public void setLoop(String key, boolean loop) {
+ if (loop) {
+ setLoop(key, -1);
+ } else {
+ setLoop(key, 0);
+ }
+ }
+
+ /**
+ * @param: key
+ * @param: leftVolume left volume value (range = 0.0 to 1.0)
+ * @param: rightVolume right volume value (range = 0.0 to 1.0)
+ * @description: TODO
+ * @return: void
+ * @author: leo
+ * @date: 2022/12/1 10:19
+ */
+ public void setVolume(String key, float leftVolume, float rightVolume) {
+ if (soundPool != null) {
+ Integer streamID = streamIdMap.get(key);
+ if (streamID != null) {
+ soundPool.setVolume(streamID, leftVolume, rightVolume);
+ }
+ }
+ }
+
+ /**
+ * @param: key
+ * @param: rate rate – playback rate (1.0 = normal playback, range 0.5 to 2.0)
+ * @description: TODO
+ * @return: void
+ * @author: leo
+ * @date: 2022/12/1 10:26
+ */
+ public void setRate(String key, float rate) {
+ if (soundPool != null) {
+ Integer streamID = streamIdMap.get(key);
+ if (streamID != null) {
+ soundPool.setRate(streamID, rate);
+ }
+ }
+ }
+
+
+ public void release() {
+ Iterator iterator = soundIdMap.keySet().iterator();
+ while (iterator.hasNext()) {
+ String key = iterator.next();
+ stop(key);
+ Integer soundId = soundIdMap.get(key);
+ if (soundId != null) {
+ soundPool.unload(soundId);
+ }
+ iterator.remove();
+ }
+ streamIdMap.clear();
+ if (soundPool != null) {
+ soundPool.release();
+ soundUtils = null;
+ }
+ }
+}
diff --git a/lib/utilcode/src/test/java/com/blankj/utilcode/util/SoundUtilsTest.java b/lib/utilcode/src/test/java/com/blankj/utilcode/util/SoundUtilsTest.java
new file mode 100644
index 0000000000..d79e4f8c4a
--- /dev/null
+++ b/lib/utilcode/src/test/java/com/blankj/utilcode/util/SoundUtilsTest.java
@@ -0,0 +1,46 @@
+package com.blankj.utilcode.util;
+
+import android.media.AudioManager;
+
+import com.blankj.utilcode.R;
+
+import org.junit.Test;
+
+/**
+ * @author leo
+ * @version 1.0
+ * @className SoundUtilsTest
+ * @description TODO
+ * @date 2022/11/30 11:15
+ **/
+public class SoundUtilsTest extends BaseTest {
+
+ @Test
+ public void play() {
+ //前奏
+ SoundUtils soundUtils = new SoundUtils.Builder()
+ .setMaxStreams(8)
+ .setStreamType(AudioManager.STREAM_RING)
+ .build();
+
+
+
+// //1.用法1
+// SoundUtils.getInstance().preload("ring", R.raw.ring);
+// SoundUtils.getInstance().play("ring");
+//
+// //2.用法2
+// soundUtils.preload("ring",R.raw.ring);
+// soundUtils.preload("ringback",R.raw.ring);
+//
+// soundUtils.play("ring");
+//
+//
+// SoundUtils.getInstance().destroy();
+// soundUtils.destroy();
+//
+//
+// SoundUtils.play();
+
+ }
+}