diff --git a/.classpath b/.classpath deleted file mode 100644 index 8531be1069459aade653c6bbe742b2ba35569b31..0000000000000000000000000000000000000000 --- a/.classpath +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - diff --git a/.project b/.project deleted file mode 100644 index e0128a798985feb0364a75413c21890523b2b95c..0000000000000000000000000000000000000000 --- a/.project +++ /dev/null @@ -1,33 +0,0 @@ - - - Eleven - - - - - - com.android.ide.eclipse.adt.ResourceManagerBuilder - - - - - com.android.ide.eclipse.adt.PreCompilerBuilder - - - - - org.eclipse.jdt.core.javabuilder - - - - - com.android.ide.eclipse.adt.ApkBuilder - - - - - - com.android.ide.eclipse.adt.AndroidNature - org.eclipse.jdt.core.javanature - - diff --git a/AndroidManifest-gradle.xml b/AndroidManifest-gradle.xml deleted file mode 100644 index 6cdcc8ae1933bfe43b51b6e139c6f345f661751a..0000000000000000000000000000000000000000 --- a/AndroidManifest-gradle.xml +++ /dev/null @@ -1,201 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/AndroidManifest.xml b/AndroidManifest.xml index bd77e44b669abc0d7fefe5b5f6697c6b8376aa56..4ef373e4105e01cdd33f83daf112a6d9183f941c 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -1,7 +1,7 @@ + @@ -39,13 +44,15 @@ - + - + @@ -205,5 +212,4 @@ android:label="@string/app_name" android:process=":main" /> - diff --git a/assets/licenses.html b/assets/licenses.html deleted file mode 100644 index 53d41288275cc10ccd441e02fbc16953fbaab698..0000000000000000000000000000000000000000 --- a/assets/licenses.html +++ /dev/null @@ -1,89 +0,0 @@ - -

Notices for files:

-
    -
  • ActionBarSherlock
  • -
  • NineOldAndroids.jar
  • -
-
-/*
- * Copyright 2012 Jake Wharton
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
- -

Notices for file:

-
    -
  • AppMsg
  • -
-
-/*
- * Copyright 2012 Evgeny Shishkin
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
- -

Notices for files:

    -
  • DragSortListView
  • -
-
-/*
- * Copyright (C) 2012 Carl Bauer
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
- - -

Notices for file:

    -
  • android-support-v4.jar
  • -
-
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
- diff --git a/build.gradle b/build.gradle index b8ae38f7c4990b9614f3599e02ae87dac9d1bcaf..38e3da75b5c891259bf363a7ff4438ca4958bdb9 100644 --- a/build.gradle +++ b/build.gradle @@ -1,11 +1,11 @@ buildscript { repositories { google() - jcenter() + mavenCentral() } dependencies { - classpath "com.android.tools.build:gradle:3.5.3" + classpath 'com.android.tools.build:gradle:7.0.4' // NOTE: Do not place your application dependencies here; they belong // in the individual module build.gradle files @@ -15,14 +15,14 @@ buildscript { allprojects { repositories { google() - jcenter() + mavenCentral() } } tasks.register("updateGradleWrapper", Wrapper) { // https://docs.gradle.org/current/release-notes.html // https://github.com/gradle/gradle/releases - gradleVersion = '6.1.1' + gradleVersion = '7.0' distributionUrl = "https://services.gradle.org/distributions/gradle-${gradleVersion}-all.zip" } @@ -31,7 +31,7 @@ tasks.register("updateGradleWrapper", Wrapper) { apply plugin: 'com.android.application' android { - compileSdkVersion 29 + compileSdkVersion 31 compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 @@ -41,11 +41,11 @@ android { defaultConfig { applicationId "org.lineageos.eleven" - minSdkVersion 26 - targetSdkVersion 29 + minSdkVersion 28 + targetSdkVersion 30 - versionCode 3 - versionName '3.0' + versionCode 401 + versionName '4.0.1' renderscriptTargetApi 19 renderscriptSupportModeEnabled true @@ -64,14 +64,14 @@ android { applicationIdSuffix ".dev" debuggable true - proguardFiles 'proguard.cfg', 'proguard-debug.cfg' + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard.cfg' minifyEnabled true shrinkResources true zipAlignEnabled true } release { debuggable false - proguardFiles 'proguard.cfg' + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard.cfg' minifyEnabled true shrinkResources true zipAlignEnabled true @@ -108,7 +108,7 @@ android { sourceSets { main { - manifest.srcFile 'AndroidManifest-gradle.xml' + manifest.srcFile 'AndroidManifest.xml' aidl.srcDirs = ['src'] assets.srcDirs = ['assets'] @@ -124,7 +124,7 @@ dependencies { // AndroidX - https://developer.android.com/jetpack/androidx/releases // see https://developer.android.com/jetpack/androidx/releases/appcompat - implementation "androidx.appcompat:appcompat:1.0.2" + implementation "androidx.appcompat:appcompat:1.4.0" // see https://developer.android.com/jetpack/androidx/releases/cardview implementation "androidx.cardview:cardview:1.0.0" @@ -133,14 +133,14 @@ dependencies { implementation "androidx.palette:palette:1.0.0" // see https://developer.android.com/jetpack/androidx/releases/preference - implementation "androidx.preference:preference:1.0.0" + implementation "androidx.preference:preference:1.1.1" // see https://developer.android.com/jetpack/androidx/releases/recyclerview - implementation "androidx.recyclerview:recyclerview:1.0.0" + implementation "androidx.recyclerview:recyclerview:1.2.1" // see https://developer.android.com/jetpack/androidx/releases/constraintlayout - implementation "androidx.constraintlayout:constraintlayout:1.1.3" + implementation "androidx.constraintlayout:constraintlayout:2.1.2" // see https://github.com/material-components/material-components-android/releases - implementation "com.google.android.material:material:1.0.0" + implementation "com.google.android.material:material:1.4.0" } diff --git a/gradle.properties b/gradle.properties new file mode 100644 index 0000000000000000000000000000000000000000..2d8d1e4dd150cb790e1efef522121e30222820d4 --- /dev/null +++ b/gradle.properties @@ -0,0 +1 @@ +android.useAndroidX=true \ No newline at end of file diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index f3d88b1c2faf2fc91d853cd5d4242b5547257070..e708b1c023ec8b20f512888fe07c5bd3ff77bb8f 100644 Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 4e1cc9db6b597a36bc8555c4148024f7ce580e90..2096e9c115203576c8ce387f904e8d8f2cdf4800 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,6 @@ +#Fri Dec 17 16:52:48 CET 2021 distributionBase=GRADLE_USER_HOME +distributionUrl=https\://services.gradle.org/distributions/gradle-7.0.2-bin.zip distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-6.1.1-all.zip -zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME diff --git a/gradlew b/gradlew index 2fe81a7d95e4f9ad2c9b2a046707d36ceb3980b3..4f906e0c811fc9e230eb44819f509cd0627f2600 100755 --- a/gradlew +++ b/gradlew @@ -82,6 +82,7 @@ esac CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + # Determine the Java command to use to start the JVM. if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then @@ -129,6 +130,7 @@ fi if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then APP_HOME=`cygpath --path --mixed "$APP_HOME"` CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + JAVACMD=`cygpath --unix "$JAVACMD"` # We build the pattern for arguments to be converted via cygpath diff --git a/gradlew.bat b/gradlew.bat index 24467a141f791695fc1009c78d913b2c849d1412..ac1b06f93825db68fb0c0b5150917f340eaa5d02 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -29,6 +29,9 @@ if "%DIRNAME%" == "" set DIRNAME=. set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" @@ -37,7 +40,7 @@ if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 -if "%ERRORLEVEL%" == "0" goto init +if "%ERRORLEVEL%" == "0" goto execute echo. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. @@ -51,7 +54,7 @@ goto fail set JAVA_HOME=%JAVA_HOME:"=% set JAVA_EXE=%JAVA_HOME%/bin/java.exe -if exist "%JAVA_EXE%" goto init +if exist "%JAVA_EXE%" goto execute echo. echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% @@ -61,28 +64,14 @@ echo location of your Java installation. goto fail -:init -@rem Get command-line arguments, handling Windows variants - -if not "%OS%" == "Windows_NT" goto win9xME_args - -:win9xME_args -@rem Slurp the command line arguments. -set CMD_LINE_ARGS= -set _SKIP=2 - -:win9xME_args_slurp -if "x%~1" == "x" goto execute - -set CMD_LINE_ARGS=%* - :execute @rem Setup the command line set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + @rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* :end @rem End local scope for the variables with windows NT shell diff --git a/lint-baseline.xml b/lint-baseline.xml new file mode 100644 index 0000000000000000000000000000000000000000..0abe703c4df0de1734eb7e42b3972565ee4109e3 --- /dev/null +++ b/lint-baseline.xml @@ -0,0 +1,12864 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/proguard-debug.cfg b/proguard-debug.cfg deleted file mode 100644 index e9caf6359a57bf16f1e99659ce6fb7b1eb9334bf..0000000000000000000000000000000000000000 --- a/proguard-debug.cfg +++ /dev/null @@ -1 +0,0 @@ --dontobfuscate diff --git a/proguard.cfg b/proguard.cfg index a4d9f4e97d5160f899db3240f73fb301e6505d21..35860bf4c88a242c2ed7238acfc7d2698fc62372 100644 --- a/proguard.cfg +++ b/proguard.cfg @@ -1,56 +1,24 @@ --optimizationpasses 5 --dontusemixedcaseclassnames --dontskipnonpubliclibraryclasses --dontpreverify --verbose --optimizations !code/simplification/arithmetic,!field/*,!class/merging/* - --keep public class * extends android.app.Activity --keep public class * extends android.app.Application --keep public class * extends android.app.Service --keep public class * extends android.content.BroadcastReceiver --keep public class * extends android.content.ContentProvider --keep public class * extends android.app.backup.BackupAgentHelper --keep public class * extends android.preference.Preference --keep public class com.android.vending.licensing.ILicensingService - -#keep all classes that might be used in XML layouts --keep public class * extends android.view.View --keep public class * extends android.app.Fragment --keep public class * extends android.support.v4.Fragment - -#keep all classes --keep public class *{ - public protected *; -} - -#keep all public and protected methods that could be used by java reflection --keepclassmembernames class * { - public protected ; -} - --keepclasseswithmembers class * { - native ; -} - --keepclasseswithmembers class * { - public (android.content.Context, android.util.AttributeSet); -} - --keepclasseswithmembers class * { - public (android.content.Context, android.util.AttributeSet, int); -} - --keepclassmembers enum * { - public static **[] values(); - public static ** valueOf(java.lang.String); -} - --keep class * implements android.os.Parcelable { - public static final android.os.Parcelable$Creator *; -} - --dontwarn **CompatHoneycomb --dontwarn org.htmlcleaner.* --dontwarn org.jaudiotagger.** -#-keep class android.support.v4.** { *; } +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile + +# we are open source +-dontobfuscate diff --git a/res/drawable-hdpi/default_artwork.png b/res/drawable-hdpi/default_artwork.png deleted file mode 100755 index ce6cd651e21d21788a56b4b64c2d6354c7b00fc8..0000000000000000000000000000000000000000 Binary files a/res/drawable-hdpi/default_artwork.png and /dev/null differ diff --git a/res/drawable-hdpi/default_artwork_blur.png b/res/drawable-hdpi/default_artwork_blur.png deleted file mode 100644 index 172705fe2aed38e4cb9c437cef86282da271882e..0000000000000000000000000000000000000000 Binary files a/res/drawable-hdpi/default_artwork_blur.png and /dev/null differ diff --git a/res/drawable-hdpi/ic_album.png b/res/drawable-hdpi/ic_album.png deleted file mode 100644 index c05973308611bd6c3c243070543998eb688a507f..0000000000000000000000000000000000000000 Binary files a/res/drawable-hdpi/ic_album.png and /dev/null differ diff --git a/res/drawable-hdpi/ic_album_lg.png b/res/drawable-hdpi/ic_album_lg.png deleted file mode 100644 index 3d34a6f21034a681ff833445cf5ff388020d07d0..0000000000000000000000000000000000000000 Binary files a/res/drawable-hdpi/ic_album_lg.png and /dev/null differ diff --git a/res/drawable-hdpi/ic_artist.png b/res/drawable-hdpi/ic_artist.png deleted file mode 100644 index 4a84573d461c67d5ec659fffcd2350a40c314859..0000000000000000000000000000000000000000 Binary files a/res/drawable-hdpi/ic_artist.png and /dev/null differ diff --git a/res/drawable-hdpi/ic_artist_lg.png b/res/drawable-hdpi/ic_artist_lg.png deleted file mode 100644 index 39311060cef18656e84cc820cae033965517d41e..0000000000000000000000000000000000000000 Binary files a/res/drawable-hdpi/ic_artist_lg.png and /dev/null differ diff --git a/res/drawable-hdpi/ic_notification.png b/res/drawable-hdpi/ic_notification.png deleted file mode 100644 index 5610f64938a6da9075b03d29caf3eb93d19cdc76..0000000000000000000000000000000000000000 Binary files a/res/drawable-hdpi/ic_notification.png and /dev/null differ diff --git a/res/drawable-hdpi/ic_playlist.png b/res/drawable-hdpi/ic_playlist.png deleted file mode 100644 index d5798de2d4a51b89c8c7bee2460a4ecc27f63c38..0000000000000000000000000000000000000000 Binary files a/res/drawable-hdpi/ic_playlist.png and /dev/null differ diff --git a/res/drawable-hdpi/ic_playlist_lg.png b/res/drawable-hdpi/ic_playlist_lg.png deleted file mode 100644 index 3a4be4979534033f7c567feba49d31e0df4c1793..0000000000000000000000000000000000000000 Binary files a/res/drawable-hdpi/ic_playlist_lg.png and /dev/null differ diff --git a/res/drawable-mdpi/default_artwork.png b/res/drawable-mdpi/default_artwork.png deleted file mode 100755 index 8958ba5ddc5726512a30d2f408a4f6ea18b2f2c4..0000000000000000000000000000000000000000 Binary files a/res/drawable-mdpi/default_artwork.png and /dev/null differ diff --git a/res/drawable-mdpi/default_artwork_blur.png b/res/drawable-mdpi/default_artwork_blur.png deleted file mode 100644 index a44787734739a6b12e6ab8285a735e62cfe56030..0000000000000000000000000000000000000000 Binary files a/res/drawable-mdpi/default_artwork_blur.png and /dev/null differ diff --git a/res/drawable-mdpi/ic_album.png b/res/drawable-mdpi/ic_album.png deleted file mode 100644 index 7ebc0e0fb569d085c203f4dcf7557a84af7592ca..0000000000000000000000000000000000000000 Binary files a/res/drawable-mdpi/ic_album.png and /dev/null differ diff --git a/res/drawable-mdpi/ic_album_lg.png b/res/drawable-mdpi/ic_album_lg.png deleted file mode 100644 index a5c40a3c948a0b9341b4bf6b9eb2a62ef86f5229..0000000000000000000000000000000000000000 Binary files a/res/drawable-mdpi/ic_album_lg.png and /dev/null differ diff --git a/res/drawable-mdpi/ic_artist.png b/res/drawable-mdpi/ic_artist.png deleted file mode 100644 index d1bf6cbe5c4b295b2d24c7e9418aa6f95de9bb8e..0000000000000000000000000000000000000000 Binary files a/res/drawable-mdpi/ic_artist.png and /dev/null differ diff --git a/res/drawable-mdpi/ic_artist_lg.png b/res/drawable-mdpi/ic_artist_lg.png deleted file mode 100644 index 3b8f6cf7d1526847d1d780c89d52890b8bb4a1ec..0000000000000000000000000000000000000000 Binary files a/res/drawable-mdpi/ic_artist_lg.png and /dev/null differ diff --git a/res/drawable-mdpi/ic_notification.png b/res/drawable-mdpi/ic_notification.png deleted file mode 100644 index 9511ea6dc62bd29a516c2960b59657faeea3bb9f..0000000000000000000000000000000000000000 Binary files a/res/drawable-mdpi/ic_notification.png and /dev/null differ diff --git a/res/drawable-mdpi/ic_playlist.png b/res/drawable-mdpi/ic_playlist.png deleted file mode 100644 index 16c2c83b251d09e870c56eb6513b4d94a00d3848..0000000000000000000000000000000000000000 Binary files a/res/drawable-mdpi/ic_playlist.png and /dev/null differ diff --git a/res/drawable-mdpi/ic_playlist_lg.png b/res/drawable-mdpi/ic_playlist_lg.png deleted file mode 100644 index aea793b0a91edc2dcc62c3c497e4a7640f3dde84..0000000000000000000000000000000000000000 Binary files a/res/drawable-mdpi/ic_playlist_lg.png and /dev/null differ diff --git a/res/drawable-xhdpi/default_artwork.png b/res/drawable-xhdpi/default_artwork.png deleted file mode 100755 index d68d94f17db1bc2c891a93c7e68e3334f844b064..0000000000000000000000000000000000000000 Binary files a/res/drawable-xhdpi/default_artwork.png and /dev/null differ diff --git a/res/drawable-xhdpi/default_artwork_blur.png b/res/drawable-xhdpi/default_artwork_blur.png deleted file mode 100644 index b03c39ca2597705e429635af5a74907a2dd65df8..0000000000000000000000000000000000000000 Binary files a/res/drawable-xhdpi/default_artwork_blur.png and /dev/null differ diff --git a/res/drawable-xhdpi/ic_album.png b/res/drawable-xhdpi/ic_album.png deleted file mode 100644 index d7025cf3d69b746171f9d0db9a5488ea8abbb466..0000000000000000000000000000000000000000 Binary files a/res/drawable-xhdpi/ic_album.png and /dev/null differ diff --git a/res/drawable-xhdpi/ic_album_lg.png b/res/drawable-xhdpi/ic_album_lg.png deleted file mode 100644 index 1b50d84fea631c49aa1c578bc72efd22d78f4168..0000000000000000000000000000000000000000 Binary files a/res/drawable-xhdpi/ic_album_lg.png and /dev/null differ diff --git a/res/drawable-xhdpi/ic_artist.png b/res/drawable-xhdpi/ic_artist.png deleted file mode 100644 index 7232871b0db129392e6454bebd5ffdccc9f6702e..0000000000000000000000000000000000000000 Binary files a/res/drawable-xhdpi/ic_artist.png and /dev/null differ diff --git a/res/drawable-xhdpi/ic_artist_lg.png b/res/drawable-xhdpi/ic_artist_lg.png deleted file mode 100644 index 4429a3519021dfa24bad0c25c2fd2b4d159d96e3..0000000000000000000000000000000000000000 Binary files a/res/drawable-xhdpi/ic_artist_lg.png and /dev/null differ diff --git a/res/drawable-xhdpi/ic_notification.png b/res/drawable-xhdpi/ic_notification.png deleted file mode 100644 index 564c5d0de71c3b19a8b29b73327c0514ae037f1e..0000000000000000000000000000000000000000 Binary files a/res/drawable-xhdpi/ic_notification.png and /dev/null differ diff --git a/res/drawable-xhdpi/ic_playlist.png b/res/drawable-xhdpi/ic_playlist.png deleted file mode 100644 index e72ce31206f9f6581905c91591e0a390e359aa44..0000000000000000000000000000000000000000 Binary files a/res/drawable-xhdpi/ic_playlist.png and /dev/null differ diff --git a/res/drawable-xhdpi/ic_playlist_lg.png b/res/drawable-xhdpi/ic_playlist_lg.png deleted file mode 100644 index 4da86c1adaf10537e49a5169055738db0ccbf677..0000000000000000000000000000000000000000 Binary files a/res/drawable-xhdpi/ic_playlist_lg.png and /dev/null differ diff --git a/res/drawable-xxhdpi/default_artwork.png b/res/drawable-xxhdpi/default_artwork.png deleted file mode 100644 index 72b03812a65284a1a81a635ccecbf17d72c590f8..0000000000000000000000000000000000000000 Binary files a/res/drawable-xxhdpi/default_artwork.png and /dev/null differ diff --git a/res/drawable-xxhdpi/default_artwork_blur.png b/res/drawable-xxhdpi/default_artwork_blur.png deleted file mode 100644 index e2693988919e52785196f7f51219574c51adb72d..0000000000000000000000000000000000000000 Binary files a/res/drawable-xxhdpi/default_artwork_blur.png and /dev/null differ diff --git a/res/drawable-xxhdpi/ic_album.png b/res/drawable-xxhdpi/ic_album.png deleted file mode 100644 index 84c5678abeec7fdea4d5c22bb8763a8cfa8191fd..0000000000000000000000000000000000000000 Binary files a/res/drawable-xxhdpi/ic_album.png and /dev/null differ diff --git a/res/drawable-xxhdpi/ic_album_lg.png b/res/drawable-xxhdpi/ic_album_lg.png deleted file mode 100644 index 1b09e9c3084dd07830f238da90222f12364d8483..0000000000000000000000000000000000000000 Binary files a/res/drawable-xxhdpi/ic_album_lg.png and /dev/null differ diff --git a/res/drawable-xxhdpi/ic_artist.png b/res/drawable-xxhdpi/ic_artist.png deleted file mode 100644 index fa94babe9894b5148651d843e2f24e2621f9823b..0000000000000000000000000000000000000000 Binary files a/res/drawable-xxhdpi/ic_artist.png and /dev/null differ diff --git a/res/drawable-xxhdpi/ic_artist_lg.png b/res/drawable-xxhdpi/ic_artist_lg.png deleted file mode 100644 index f232ded16b57d26e4c570e9c1999eb30b95cb462..0000000000000000000000000000000000000000 Binary files a/res/drawable-xxhdpi/ic_artist_lg.png and /dev/null differ diff --git a/res/drawable-xxhdpi/ic_notification.png b/res/drawable-xxhdpi/ic_notification.png deleted file mode 100644 index 1203bc671b5b9a168a7ebe6014f1b22fbcee6a5a..0000000000000000000000000000000000000000 Binary files a/res/drawable-xxhdpi/ic_notification.png and /dev/null differ diff --git a/res/drawable-xxhdpi/ic_playlist.png b/res/drawable-xxhdpi/ic_playlist.png deleted file mode 100644 index ce94de0333ca87079395c9b5df4153c9331d664e..0000000000000000000000000000000000000000 Binary files a/res/drawable-xxhdpi/ic_playlist.png and /dev/null differ diff --git a/res/drawable-xxhdpi/ic_playlist_lg.png b/res/drawable-xxhdpi/ic_playlist_lg.png deleted file mode 100644 index 8c8330925214666c4e103f61e17c645f8cf0c1e9..0000000000000000000000000000000000000000 Binary files a/res/drawable-xxhdpi/ic_playlist_lg.png and /dev/null differ diff --git a/res/drawable/avd_pause_to_play.xml b/res/drawable/avd_pause_to_play.xml new file mode 100644 index 0000000000000000000000000000000000000000..f86d27692ec398027312058315ca7c75c24ce383 --- /dev/null +++ b/res/drawable/avd_pause_to_play.xml @@ -0,0 +1,60 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/res/drawable/avd_play_to_pause.xml b/res/drawable/avd_play_to_pause.xml new file mode 100644 index 0000000000000000000000000000000000000000..c6e110d90833d01c8d0f4d9a354e5c2f185033ec --- /dev/null +++ b/res/drawable/avd_play_to_pause.xml @@ -0,0 +1,60 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/res/values/appmsg_colors.xml b/res/drawable/bg_app_widget.xml similarity index 71% rename from res/values/appmsg_colors.xml rename to res/drawable/bg_app_widget.xml index 5c0fe10d9f3fe6e043f31b64421c40c701c9041d..a5a3a6e4ba17041db4b897f78e3b11f3b4b3db79 100644 --- a/res/values/appmsg_colors.xml +++ b/res/drawable/bg_app_widget.xml @@ -1,5 +1,6 @@ - - - - @color/red - @color/orange - @color/green - - +--> + + + + diff --git a/res/drawable/bottom_shadow.xml b/res/drawable/bg_grid_item.xml similarity index 85% rename from res/drawable/bottom_shadow.xml rename to res/drawable/bg_grid_item.xml index 2122798b750513a023245ffeec53f1365b9f862d..ad3be7aa9b0b8e3e6f8f4fc5599cffe4b6f1a1d0 100644 --- a/res/drawable/bottom_shadow.xml +++ b/res/drawable/bg_grid_item.xml @@ -1,7 +1,6 @@ - - - + + + + + diff --git a/res/drawable/btn_playback_play.xml b/res/drawable/btn_playback_play.xml index 1b6ecd0cc6d9ebf5c5908e2450cdde392b3915df..8c0c5794c7460f68db97daab551ac1cd8dffd718 100644 --- a/res/drawable/btn_playback_play.xml +++ b/res/drawable/btn_playback_play.xml @@ -7,5 +7,5 @@ + android:pathData="M10,8.64L15.27,12L10,15.36V8.64M8,5v14l11,-7L8,5L8,5z" /> diff --git a/res/drawable/btn_notification_collapse.xml b/res/drawable/btn_playback_play_filled.xml similarity index 62% rename from res/drawable/btn_notification_collapse.xml rename to res/drawable/btn_playback_play_filled.xml index 35b2dc7221076d5e3cda9dfe6d2c3674b8b34115..1b6ecd0cc6d9ebf5c5908e2450cdde392b3915df 100644 --- a/res/drawable/btn_notification_collapse.xml +++ b/res/drawable/btn_playback_play_filled.xml @@ -6,8 +6,6 @@ android:viewportHeight="24"> - + android:fillColor="@color/player_control_color" + android:pathData="M8 5v14l11-7z" /> diff --git a/res/drawable/floating_action_button.xml b/res/drawable/btn_playback_play_widget.xml similarity index 61% rename from res/drawable/floating_action_button.xml rename to res/drawable/btn_playback_play_widget.xml index d186128017aa4474527ca5f4ccc5e89e1e6b4240..a28e81e011256e4cba2bdc00199bc06c160c4b72 100644 --- a/res/drawable/floating_action_button.xml +++ b/res/drawable/btn_playback_play_widget.xml @@ -1,6 +1,6 @@ - - - - - - - + + + + + diff --git a/res/drawable/btn_playback_previous.xml b/res/drawable/btn_playback_previous.xml index 34095163fc3dd520b14f053e521a0b3eff08559f..f902d05f3360038d67b2c790dc6c42338f67a544 100644 --- a/res/drawable/btn_playback_previous.xml +++ b/res/drawable/btn_playback_previous.xml @@ -1,11 +1,12 @@ - + android:viewportWidth="24" + android:viewportHeight="24"> + + android:pathData="M6 6h2v12H6zm3.5 6l8.5 6V6l-8.5 6zm6.5 2.14L12.97 12 16 9.86v4.28z" + android:fillType="evenOdd" /> diff --git a/res/drawable/btn_playback_previous_widget.xml b/res/drawable/btn_playback_previous_widget.xml new file mode 100644 index 0000000000000000000000000000000000000000..df45ddf92c76deff58368164fdad35663d80c76b --- /dev/null +++ b/res/drawable/btn_playback_previous_widget.xml @@ -0,0 +1,12 @@ + + + + + diff --git a/res/drawable/btn_playback_repeat_all_widget.xml b/res/drawable/btn_playback_repeat_all_widget.xml new file mode 100644 index 0000000000000000000000000000000000000000..b54de933299bffc8e3a5fa03e0c93069194059ce --- /dev/null +++ b/res/drawable/btn_playback_repeat_all_widget.xml @@ -0,0 +1,11 @@ + + + + + diff --git a/res/drawable/btn_playback_repeat_one_widget.xml b/res/drawable/btn_playback_repeat_one_widget.xml new file mode 100644 index 0000000000000000000000000000000000000000..66f4db53ce63a9ba95876b183cd77c54f1b8aacf --- /dev/null +++ b/res/drawable/btn_playback_repeat_one_widget.xml @@ -0,0 +1,12 @@ + + + + + diff --git a/res/drawable/btn_playback_shuffle_all_widget.xml b/res/drawable/btn_playback_shuffle_all_widget.xml new file mode 100644 index 0000000000000000000000000000000000000000..1d9e0c7d092bddb7389cba2cd9b3db658ff8299f --- /dev/null +++ b/res/drawable/btn_playback_shuffle_all_widget.xml @@ -0,0 +1,13 @@ + + + + + diff --git a/res/drawable/btn_preview_pause.xml b/res/drawable/btn_preview_pause.xml new file mode 100644 index 0000000000000000000000000000000000000000..28da504209c165ea4fb4d21c772fe964297ed182 --- /dev/null +++ b/res/drawable/btn_preview_pause.xml @@ -0,0 +1,11 @@ + + + + + diff --git a/res/drawable/btn_preview_play.xml b/res/drawable/btn_preview_play.xml new file mode 100644 index 0000000000000000000000000000000000000000..0f82d93836687e99dc3be0ab7963fb79a5ef8c59 --- /dev/null +++ b/res/drawable/btn_preview_play.xml @@ -0,0 +1,11 @@ + + + + + diff --git a/res/drawable/now_playing_progress_background.xml b/res/drawable/circular_drawable_collapsed.xml similarity index 79% rename from res/drawable/now_playing_progress_background.xml rename to res/drawable/circular_drawable_collapsed.xml index 2d52ac44073c80819c8f56b6e7d3abc4802d48c0..84f39ba325a3f6c22e19c930d0cbea6fa44b8713 100644 --- a/res/drawable/now_playing_progress_background.xml +++ b/res/drawable/circular_drawable_collapsed.xml @@ -17,9 +17,9 @@ - + diff --git a/res/drawable/default_artwork.xml b/res/drawable/default_artwork.xml new file mode 100644 index 0000000000000000000000000000000000000000..e2c848cb7cc87efaee7c35c1b75ed54c86818a24 --- /dev/null +++ b/res/drawable/default_artwork.xml @@ -0,0 +1,24 @@ + + + + diff --git a/res/drawable/drag_indicator.xml b/res/drawable/drag_indicator.xml index 5ca250129ade1190fbc11a0658211c812da46785..cd1e887cc7472b1fcb01f98f039a557f17945ea3 100644 --- a/res/drawable/drag_indicator.xml +++ b/res/drawable/drag_indicator.xml @@ -5,6 +5,6 @@ android:viewportWidth="24.0" android:viewportHeight="24.0"> + android:fillColor="@color/color_default_icon" + android:pathData="M11.29,8.71L6.7,13.3c-0.39,0.39 -0.39,1.02 0,1.41 0.39,0.39 1.02,0.39 1.41,0L12,10.83l3.88,3.88c0.39,0.39 1.02,0.39 1.41,0 0.39,-0.39 0.39,-1.02 0,-1.41L12.7,8.71c-0.38,-0.39 -1.02,-0.39 -1.41,0z" /> diff --git a/res/drawable/gray_circle.xml b/res/drawable/gray_circle.xml index 20e170be7d0242b348294ad9ef622061a27b5f9b..7e67f71a85b5fc625273b015355a4bc8ad6a797e 100644 --- a/res/drawable/gray_circle.xml +++ b/res/drawable/gray_circle.xml @@ -1,6 +1,7 @@ - - \ No newline at end of file + + diff --git a/res/drawable/gripper.xml b/res/drawable/gripper.xml index e5385f84318f61d4f5e330233be97f9674bad6ad..828173df3a0234a2118ab22c1d4e7c1877481310 100644 --- a/res/drawable/gripper.xml +++ b/res/drawable/gripper.xml @@ -5,6 +5,6 @@ android:viewportWidth="24.0" android:viewportHeight="24.0"> + android:fillColor="@color/color_default_icon" + android:pathData="M11,18c0,1.1 -0.9,2 -2,2s-2,-0.9 -2,-2 0.9,-2 2,-2 2,0.9 2,2zM9,10c-1.1,0 -2,0.9 -2,2s0.9,2 2,2 2,-0.9 2,-2 -0.9,-2 -2,-2zM9,4c-1.1,0 -2,0.9 -2,2s0.9,2 2,2 2,-0.9 2,-2 -0.9,-2 -2,-2zM15,8c1.1,0 2,-0.9 2,-2s-0.9,-2 -2,-2 -2,0.9 -2,2 0.9,2 2,2zM15,10c-1.1,0 -2,0.9 -2,2s0.9,2 2,2 2,-0.9 2,-2 -0.9,-2 -2,-2zM15,16c-1.1,0 -2,0.9 -2,2s0.9,2 2,2 2,-0.9 2,-2 -0.9,-2 -2,-2z" /> diff --git a/res/drawable/gripper_light.xml b/res/drawable/gripper_light.xml index e5385f84318f61d4f5e330233be97f9674bad6ad..828173df3a0234a2118ab22c1d4e7c1877481310 100644 --- a/res/drawable/gripper_light.xml +++ b/res/drawable/gripper_light.xml @@ -5,6 +5,6 @@ android:viewportWidth="24.0" android:viewportHeight="24.0"> + android:fillColor="@color/color_default_icon" + android:pathData="M11,18c0,1.1 -0.9,2 -2,2s-2,-0.9 -2,-2 0.9,-2 2,-2 2,0.9 2,2zM9,10c-1.1,0 -2,0.9 -2,2s0.9,2 2,2 2,-0.9 2,-2 -0.9,-2 -2,-2zM9,4c-1.1,0 -2,0.9 -2,2s0.9,2 2,2 2,-0.9 2,-2 -0.9,-2 -2,-2zM15,8c1.1,0 2,-0.9 2,-2s-0.9,-2 -2,-2 -2,0.9 -2,2 0.9,2 2,2zM15,10c-1.1,0 -2,0.9 -2,2s0.9,2 2,2 2,-0.9 2,-2 -0.9,-2 -2,-2zM15,16c-1.1,0 -2,0.9 -2,2s0.9,2 2,2 2,-0.9 2,-2 -0.9,-2 -2,-2z" /> diff --git a/res/drawable/history_icon.xml b/res/drawable/history_icon.xml deleted file mode 100644 index 39581a6018f64a8c797aaf136507d57d4d688e0b..0000000000000000000000000000000000000000 --- a/res/drawable/history_icon.xml +++ /dev/null @@ -1,15 +0,0 @@ - - - - - diff --git a/res/drawable/ic_action_search.xml b/res/drawable/ic_action_search.xml deleted file mode 100644 index ccdabce156327cd7bd7d6a0222b55c630dc552a4..0000000000000000000000000000000000000000 --- a/res/drawable/ic_action_search.xml +++ /dev/null @@ -1,14 +0,0 @@ - - - - - diff --git a/res/drawable/ic_album.xml b/res/drawable/ic_album.xml new file mode 100644 index 0000000000000000000000000000000000000000..b4fe1d087edbe0c0ad4df8c48526e7ea4ddbe177 --- /dev/null +++ b/res/drawable/ic_album.xml @@ -0,0 +1,25 @@ + + + + diff --git a/res/drawable/ic_arrow_back.xml b/res/drawable/ic_arrow_back.xml new file mode 100644 index 0000000000000000000000000000000000000000..ded8daff8811ded44df025fe5b266be657bf9e72 --- /dev/null +++ b/res/drawable/ic_arrow_back.xml @@ -0,0 +1,10 @@ + + + + diff --git a/res/drawable/ic_artist.xml b/res/drawable/ic_artist.xml new file mode 100644 index 0000000000000000000000000000000000000000..4cce56ebab30d6c914c38f73840892d75254ecf9 --- /dev/null +++ b/res/drawable/ic_artist.xml @@ -0,0 +1,25 @@ + + + + diff --git a/res/drawable/inset_list_divider_no_padding.xml b/res/drawable/ic_notification.xml similarity index 55% rename from res/drawable/inset_list_divider_no_padding.xml rename to res/drawable/ic_notification.xml index 763868f4fb738f5746fd73de86e7c30d27eb80c6..7eb05aa709baeba64f2cbdc51236f4c67ac80bab 100644 --- a/res/drawable/inset_list_divider_no_padding.xml +++ b/res/drawable/ic_notification.xml @@ -1,6 +1,6 @@ - - - - - - - - - \ No newline at end of file + + + diff --git a/res/drawable/ic_playlist.xml b/res/drawable/ic_playlist.xml new file mode 100644 index 0000000000000000000000000000000000000000..fc1288de39ba03238c460d19d2db1e8e6cb632b5 --- /dev/null +++ b/res/drawable/ic_playlist.xml @@ -0,0 +1,25 @@ + + + + diff --git a/res/drawable/menu_button.xml b/res/drawable/menu_button.xml index da1adfc958bc7b9e851a7b479959e73d48fd255a..8a4bd726517a04138956998f7aa4388221646e92 100644 --- a/res/drawable/menu_button.xml +++ b/res/drawable/menu_button.xml @@ -1,14 +1,24 @@ - + - - + android:fillColor="@color/color_default_icon" + android:pathData="M12,8c1.1,0 2,-0.9 2,-2s-0.9,-2 -2,-2 -2,0.9 -2,2 0.9,2 2,2zM12,10c-1.1,0 +-2,0.9 -2,2s0.9,2 2,2 2,-0.9 2,-2 -0.9,-2 -2,-2zM12,16c-1.1,0 -2,0.9 -2,2s0.9,2 2,2 2,-0.9 2,-2 -0.9,-2 -2,-2z" /> diff --git a/res/drawable/menu_button_light.xml b/res/drawable/menu_button_light.xml index da1adfc958bc7b9e851a7b479959e73d48fd255a..8a4bd726517a04138956998f7aa4388221646e92 100644 --- a/res/drawable/menu_button_light.xml +++ b/res/drawable/menu_button_light.xml @@ -1,14 +1,24 @@ - + - - + android:fillColor="@color/color_default_icon" + android:pathData="M12,8c1.1,0 2,-0.9 2,-2s-0.9,-2 -2,-2 -2,0.9 -2,2 0.9,2 2,2zM12,10c-1.1,0 +-2,0.9 -2,2s0.9,2 2,2 2,-0.9 2,-2 -0.9,-2 -2,-2zM12,16c-1.1,0 -2,0.9 -2,2s0.9,2 2,2 2,-0.9 2,-2 -0.9,-2 -2,-2z" /> diff --git a/res/drawable/no_results.xml b/res/drawable/no_results.xml index 1e17a211066476030fbdc83801fd0a8121621e3b..7769d2e84595130600f683a4e62f4bdb8796d044 100644 --- a/res/drawable/no_results.xml +++ b/res/drawable/no_results.xml @@ -8,7 +8,7 @@ diff --git a/res/drawable/now_playing_icon.xml b/res/drawable/now_playing_icon.xml index 89d6cfe8ec5a06d2af6c0de26653f8a47858dcde..d5fe1ea33e9d9b6e43afa77c2ab68141709936ba 100644 --- a/res/drawable/now_playing_icon.xml +++ b/res/drawable/now_playing_icon.xml @@ -6,7 +6,7 @@ android:viewportHeight="24"> diff --git a/res/drawable/playlist_icon.xml b/res/drawable/playlist_icon.xml index 58bd2d126e6f10a48dd8721553eb0e37852475f3..ef871dc3a3fd7cb7f7d1ae8e6e3b5ef26874cc4b 100644 --- a/res/drawable/playlist_icon.xml +++ b/res/drawable/playlist_icon.xml @@ -8,7 +8,6 @@ + android:fillColor="@color/color_default_icon" + android:pathData="M22,6h-5v8.18c-0.31,-0.11 -0.65,-0.18 -1,-0.18c-1.66,0 -3,1.34 -3,3s1.34,3 3,3s3,-1.34 3,-3v-9h3L22,6L22,6zM15,6h-12v2h12L15,6L15,6zM15,10h-12v2h12L15,10L15,10zM11,14h-8v2h8L11,14L11,14zM15,17c0,-0.55 0.45,-1 1,-1c0.55,0 1,0.45 1,1s-0.45,1 -1,1C15.45,18 15,17.55 15,17z" /> diff --git a/res/drawable/recent_icon.xml b/res/drawable/recent_icon.xml index 39581a6018f64a8c797aaf136507d57d4d688e0b..b5503bb545cd3888aac00c4dd84475fdfbda6f2e 100644 --- a/res/drawable/recent_icon.xml +++ b/res/drawable/recent_icon.xml @@ -6,7 +6,7 @@ android:viewportHeight="24"> + android:fillColor="@color/color_default_icon" + android:pathData="M23,12l-2.44,-2.78 0.34,-3.68 -3.61,-0.82 -1.89,-3.18L12,3 8.6,1.54 6.71,4.72l-3.61,0.81 0.34,3.68L1,12l2.44,2.78 -0.34,3.69 3.61,0.82 1.89,3.18L12,21l3.4,1.46 1.89,-3.18 3.61,-0.82 -0.34,-3.68L23,12zM18.49,14.11l0.26,2.79 -2.74,0.62 -1.43,2.41L12,18.82l-2.58,1.11 -1.43,-2.41 -2.74,-0.62 0.26,-2.8L3.66,12l1.85,-2.12 -0.26,-2.78 2.74,-0.61 1.43,-2.41L12,5.18l2.58,-1.11 1.43,2.41 2.74,0.62 -0.26,2.79L20.34,12l-1.85,2.11zM11,15h2v2h-2zM11,7h2v6h-2z" /> diff --git a/res/drawable/right_shadow.xml b/res/drawable/right_shadow.xml deleted file mode 100644 index ef3fc62cf34bb77acb55db7b0d45880ea577f634..0000000000000000000000000000000000000000 --- a/res/drawable/right_shadow.xml +++ /dev/null @@ -1,26 +0,0 @@ - - - - - - - \ No newline at end of file diff --git a/res/drawable/stopwatch_icon_small_grey.xml b/res/drawable/stopwatch_icon_small_grey.xml index d03145fe629d4500b9c4efd548cbb1c9edea0b03..5acf41fc93e2101becc308f8a6cb36819f15794a 100644 --- a/res/drawable/stopwatch_icon_small_grey.xml +++ b/res/drawable/stopwatch_icon_small_grey.xml @@ -8,7 +8,7 @@ + android:fillColor="@color/color_default_icon" + android:pathData="M16.5,3c-1.74,0 -3.41,0.81 -4.5,2.09C10.91,3.81 9.24,3 7.5,3 4.42,3 2,5.42 2,8.5c0,3.78 3.4,6.86 8.55,11.54L12,21.35l1.45,-1.32C18.6,15.36 22,12.28 22,8.5 22,5.42 19.58,3 16.5,3zM12.1,18.55l-0.1,0.1 -0.1,-0.1C7.14,14.24 4,11.39 4,8.5 4,6.5 5.5,5 7.5,5c1.54,0 3.04,0.99 3.57,2.36h1.87C13.46,5.99 14.96,5 16.5,5c2,0 3.5,1.5 3.5,3.5 0,2.89 -3.14,5.74 -7.9,10.05z" /> diff --git a/res/layout/activity_album_detail.xml b/res/layout/activity_album_detail.xml index 9b7c4e6202083111b875191e006e7ffdb601ef43..1c5d1efeb6fc20cef6eb6435fc35674e12cdb5d3 100644 --- a/res/layout/activity_album_detail.xml +++ b/res/layout/activity_album_detail.xml @@ -22,7 +22,6 @@ android:scaleType="centerCrop" /> - + android:layout_alignParentStart="true" /> diff --git a/res/layout/activity_artist_detail.xml b/res/layout/activity_artist_detail.xml index 24a1f068369cffab961dd94459d83d39e6c652be..ab2a0bd354633f7fcc8c543420791779ea15f256 100644 --- a/res/layout/activity_artist_detail.xml +++ b/res/layout/activity_artist_detail.xml @@ -1,17 +1,51 @@ - + android:background="@color/activity_artist_detail_background_color"> - - - - \ No newline at end of file + android:layout_height="wrap_content" + android:orientation="vertical"> + + + + + + + + + + + + + + diff --git a/res/layout/activity_audio_preview.xml b/res/layout/activity_audio_preview.xml index f894488f4b9b9b37b893ea0f87bb10a0034d5840..df487a0041e2e40e2ffc7de4200c5cca9948ac51 100644 --- a/res/layout/activity_audio_preview.xml +++ b/res/layout/activity_audio_preview.xml @@ -1,6 +1,7 @@ - - - - - - \ No newline at end of file diff --git a/res/layout/activity_settings.xml b/res/layout/activity_settings.xml index ac50270df7dab7b4f943dd28f79deb20eca7304b..188e30665aed388247c95ad8794650e7e9e77d77 100644 --- a/res/layout/activity_settings.xml +++ b/res/layout/activity_settings.xml @@ -1,6 +1,6 @@ + android:contentDescription="@null" + android:src="@drawable/default_artwork_blur_2" /> diff --git a/res/layout/app_msg.xml b/res/layout/app_msg.xml deleted file mode 100644 index 8767a0f3b6d220a0ca9335209826ac4ecbd21a94..0000000000000000000000000000000000000000 --- a/res/layout/app_msg.xml +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/res/layout/app_widget_large.xml b/res/layout/app_widget_large.xml index 9bb647b72084e239f7206fca8245d1c279839835..9fc57a1414dd5387ec2b32776b984b1176915158 100644 --- a/res/layout/app_widget_large.xml +++ b/res/layout/app_widget_large.xml @@ -2,6 +2,7 @@ + android:layout_height="wrap_content" + android:background="@drawable/bg_app_widget" + android:columnCount="3" + android:padding="8dp" + android:rowCount="2"> + + + + + + + + + + android:paddingTop="8dp"> - - - - - - - - - - diff --git a/res/layout/app_widget_large_alternate.xml b/res/layout/app_widget_large_alternate.xml index 8bb3504dc7143a34451b9c33c652f11af9e95894..93fce7af60bea9889b3db0bbad5029732a4bcee1 100644 --- a/res/layout/app_widget_large_alternate.xml +++ b/res/layout/app_widget_large_alternate.xml @@ -2,6 +2,7 @@ + android:layout_height="wrap_content" + android:background="@drawable/bg_app_widget" + android:columnCount="3" + android:padding="8dp" + android:rowCount="2"> + android:layout_width="wrap_content" + android:layout_row="0" + android:layout_column="1" + android:layout_columnSpan="2" + android:layout_gravity="start" + android:layout_marginStart="@dimen/notification_info_container_padding_left" + android:gravity="center" + android:orientation="vertical"> - + android:paddingTop="8dp"> + android:src="@drawable/btn_playback_shuffle_all_widget" /> + android:src="@drawable/btn_playback_previous_widget" /> + android:src="@drawable/btn_playback_pause_widget" + android:contentDescription="@string/accessibility_play" /> + android:src="@drawable/btn_playback_next_widget" /> + android:src="@drawable/btn_playback_repeat_all_widget" /> diff --git a/res/layout/app_widget_small.xml b/res/layout/app_widget_small.xml index 97e55a90b91aca1facba9069a76489a63e015b5e..1a94999fffa8487a41627cc04d6fbd8b49ffdefa 100644 --- a/res/layout/app_widget_small.xml +++ b/res/layout/app_widget_small.xml @@ -2,6 +2,7 @@ - + + layout="@layout/play_pause_progress_button_alt" /> diff --git a/res/layout/colorstrip.xml b/res/layout/colorstrip.xml deleted file mode 100644 index 791d054a190fc22b5f130a246327d628803f3b9e..0000000000000000000000000000000000000000 --- a/res/layout/colorstrip.xml +++ /dev/null @@ -1,22 +0,0 @@ - - - \ No newline at end of file diff --git a/res/layout/edit_queue_list_item.xml b/res/layout/edit_queue_list_item.xml index 99f082c1c1facdbc801ba3ec90df5dba530de5d3..0697e9f27de545fddeda80389e22c895979a52af 100644 --- a/res/layout/edit_queue_list_item.xml +++ b/res/layout/edit_queue_list_item.xml @@ -16,7 +16,6 @@ limitations under the License. --> @@ -25,11 +24,9 @@ android:layout_width="@dimen/drag_and_drop_width" android:layout_height="@dimen/drag_and_drop_height" android:layout_centerVertical="true" - android:scaleType="fitXY" android:src="@drawable/gripper_light" /> @@ -25,7 +24,6 @@ android:layout_width="@dimen/drag_and_drop_width" android:layout_height="@dimen/drag_and_drop_height" android:layout_centerVertical="true" - android:scaleType="fitXY" android:src="@drawable/gripper" /> - \ No newline at end of file + diff --git a/res/layout/faux_playlist_header.xml b/res/layout/faux_playlist_header.xml deleted file mode 100644 index 977432fc997e0eaf081fd54ed7fe6f85a79c7f1d..0000000000000000000000000000000000000000 --- a/res/layout/faux_playlist_header.xml +++ /dev/null @@ -1,27 +0,0 @@ - - - - - - - diff --git a/res/layout/list_base.xml b/res/layout/fragment_list.xml similarity index 73% rename from res/layout/list_base.xml rename to res/layout/fragment_list.xml index b9193754010c4d2e6d7cc2d4aa4947b97e1de299..84a0387af0ec69ef96ba11cb810a14c743cc68e5 100644 --- a/res/layout/list_base.xml +++ b/res/layout/fragment_list.xml @@ -1,7 +1,6 @@ - + android:scrollbarStyle="outsideOverlay" + android:scrollbars="vertical" /> diff --git a/res/layout/fragment_music_browser_phone.xml b/res/layout/fragment_music_browser_phone.xml index a508c8b3714213346752f04497e66d8bf3f84c79..2e1de323c747af5d25992433fb52eaaec6ae75d3 100644 --- a/res/layout/fragment_music_browser_phone.xml +++ b/res/layout/fragment_music_browser_phone.xml @@ -2,6 +2,8 @@ - + android:layout_height="match_parent"> - + android:layout_height="@dimen/tpi_height" + android:elevation="@dimen/action_bar_elevation" /> - - - - - - + + diff --git a/res/layout/grid_base.xml b/res/layout/grid_base.xml index b59a0e4bcba408ba020919bce1459c37006b4eb1..e0b2f8bd8d6829f0136465aa79b296baf5df399e 100644 --- a/res/layout/grid_base.xml +++ b/res/layout/grid_base.xml @@ -2,6 +2,7 @@ - + android:scrollbars="vertical" /> diff --git a/res/layout/grid_header.xml b/res/layout/grid_header.xml deleted file mode 100644 index 16a256aaaf59c3bf2bb6d3d487e9f188fc63321c..0000000000000000000000000000000000000000 --- a/res/layout/grid_header.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - \ No newline at end of file diff --git a/res/layout/grid_items_normal.xml b/res/layout/grid_items_normal.xml index a055e65105a4a1efa939ba047e289fdb57781ac5..c4140cb6bf66218f518e0c0fbe43aa68d95c993f 100644 --- a/res/layout/grid_items_normal.xml +++ b/res/layout/grid_items_normal.xml @@ -2,6 +2,7 @@ - - - - - - diff --git a/res/layout/list_item_common.xml b/res/layout/list_item_common.xml index e9543a72333c42dd1bdabc11aa9d03cdf62ce97e..a3d81931840fc7cdb9d4d9a3913fb8d0625c209a 100644 --- a/res/layout/list_item_common.xml +++ b/res/layout/list_item_common.xml @@ -1,19 +1,37 @@ + + - + android:orientation="vertical"> - + android:layout_height="wrap_content" /> + + + android:foreground="?android:selectableItemBackgroundBorderless" + android:src="@drawable/menu_button" /> - \ No newline at end of file + diff --git a/res/layout/list_item_normal.xml b/res/layout/list_item_normal.xml index de538dbc02ca2765df90b08adf35b722daad8a0a..80852a9123f248cdc1dc02697c5b8cbd393202d3 100644 --- a/res/layout/list_item_normal.xml +++ b/res/layout/list_item_normal.xml @@ -2,6 +2,7 @@ - + android:gravity="center_vertical" + android:layout_marginStart="@dimen/list_item_general_margin" + android:paddingTop="@dimen/list_item_padding_top" + android:paddingBottom="@dimen/list_item_padding_bottom"> - - - - - \ No newline at end of file + + diff --git a/res/layout/list_item_queue.xml b/res/layout/list_item_queue.xml index b539a64c8025f805e4ba75ff870848e2c48b5d89..a390ddbd6ccdc4de219c26751781cd1425921358 100644 --- a/res/layout/list_item_queue.xml +++ b/res/layout/list_item_queue.xml @@ -1,5 +1,7 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/res/layout/list_item_simple.xml b/res/layout/list_item_simple.xml deleted file mode 100644 index 756223617040babe210af3e7bc1d6697e60f6d3c..0000000000000000000000000000000000000000 --- a/res/layout/list_item_simple.xml +++ /dev/null @@ -1,78 +0,0 @@ - - - - - - - - - - - - - - - - - - - diff --git a/res/layout/list_item_smart_playlist.xml b/res/layout/list_item_smart_playlist.xml deleted file mode 100644 index badd4a68a3bc7815b52fa7ef5d598d4f35859075..0000000000000000000000000000000000000000 --- a/res/layout/list_item_smart_playlist.xml +++ /dev/null @@ -1,43 +0,0 @@ - - - - - - - - - - \ No newline at end of file diff --git a/res/layout/list_item_top_tracks.xml b/res/layout/list_item_top_tracks.xml index 35d0836f75148a1c63f4b007ff61075255302113..07fed2c051f425a5a3a55bd2450e3bfcec9658da 100644 --- a/res/layout/list_item_top_tracks.xml +++ b/res/layout/list_item_top_tracks.xml @@ -95,7 +95,7 @@ android:id="@+id/popup_menu_button" android:layout_width="@dimen/overflow_width" android:layout_height="@dimen/overflow_height" - android:tint="@color/accent" + android:tint="@color/color_default_icon" android:src="@lineageos.platform:drawable/ic_menu" /> diff --git a/res/layout/list_search_footer.xml b/res/layout/list_search_footer.xml deleted file mode 100644 index 137daa540cd76de18ecd5534284b4124d857bd92..0000000000000000000000000000000000000000 --- a/res/layout/list_search_footer.xml +++ /dev/null @@ -1,43 +0,0 @@ - - - - - - - - - - \ No newline at end of file diff --git a/res/layout/list_search_header.xml b/res/layout/list_search_header.xml deleted file mode 100644 index 5cca5c7048c6711f3253f68f94ed97d75bc459d8..0000000000000000000000000000000000000000 --- a/res/layout/list_search_header.xml +++ /dev/null @@ -1,34 +0,0 @@ - - - - - \ No newline at end of file diff --git a/res/layout/main_playback_controls.xml b/res/layout/main_playback_controls.xml index 8f4b682e178748d161f88d094691711614c391fd..d58a36757afcb2aa907f37c30a210f747914f174 100644 --- a/res/layout/main_playback_controls.xml +++ b/res/layout/main_playback_controls.xml @@ -19,7 +19,6 @@ xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" - android:id="@+id/main_playback_controls_root" android:layout_width="match_parent" android:layout_height="wrap_content" tools:background="@color/blue_dark" diff --git a/res/layout/no_results_message.xml b/res/layout/no_results_message.xml index 1cd68b3249d5210d3b57a4adf2e02691383c874d..654dd2486be7c4e2ff4cb4d8d21589fe30024e10 100644 --- a/res/layout/no_results_message.xml +++ b/res/layout/no_results_message.xml @@ -1,6 +1,7 @@ + + + + + + + + + diff --git a/res/layout/play_pause_progress_button_collapsed.xml b/res/layout/play_pause_progress_button_collapsed.xml index a6da62d21353d3614f5c1580a6a33df920b9addd..f1b6e77305e3d157ba8a4b3889faf4ffaa607cc6 100644 --- a/res/layout/play_pause_progress_button_collapsed.xml +++ b/res/layout/play_pause_progress_button_collapsed.xml @@ -44,8 +44,8 @@ android:indeterminate="false" android:max="100" android:progressTint="@color/color_default_view_on_accent" - android:progressBackgroundTint="@color/color_default_gray1" + android:progressBackgroundTint="@color/accent" android:progress="100" - android:progressDrawable="@drawable/circular_drawable" /> + android:progressDrawable="@drawable/circular_drawable_collapsed" /> diff --git a/res/layout/playlist_detail.xml b/res/layout/playlist_detail.xml index 3f6cbe3d8c545653862700be75032127002a2218..66330ffbb4fef0ef10f5afd2299a2472a1760f79 100644 --- a/res/layout/playlist_detail.xml +++ b/res/layout/playlist_detail.xml @@ -14,15 +14,32 @@ See the License for the specific language governing permissions and limitations under the License. --> - - + - + - + + + + + + + + diff --git a/res/layout/playlist_detail_header.xml b/res/layout/playlist_detail_header.xml index 7cceb7b24e8744ef32bcac59408944a02cfd5cfb..e4a0209f4ed223bfa41626c7567506f0d7da3959 100644 --- a/res/layout/playlist_detail_header.xml +++ b/res/layout/playlist_detail_header.xml @@ -14,6 +14,7 @@ limitations under the License. --> @@ -26,46 +27,32 @@ android:contentDescription="@null" android:scaleType="centerCrop" /> - + android:layout_gravity="center" + android:background="@color/header_shadow_color" + android:gravity="center" + android:orientation="horizontal"> - - - - - - - - - - - + android:layout_marginEnd="16dp" + android:drawablePadding="4dp" + android:textColor="@color/number_of_songs_text_color" + android:textSize="@dimen/text_size_micro" + app:drawableStartCompat="@drawable/playlist_icon" /> + + + diff --git a/res/layout/square_image_view.xml b/res/layout/square_image_view.xml index 0627f33e8892262eb6c772978efb79d4c9cbdfc4..036ed4bfa07f2c0231c3ee59b64195285bee900b 100644 --- a/res/layout/square_image_view.xml +++ b/res/layout/square_image_view.xml @@ -16,7 +16,6 @@ limitations under the License. --> @@ -26,4 +25,4 @@ android:layout_height="match_parent" android:scaleType="centerCrop" /> - \ No newline at end of file + diff --git a/res/menu/album_sort_by.xml b/res/menu/album_sort_by.xml index 3dfbe5ec0342356b042c80aba52fc73b994d3493..582243f8edc3fa9e890df638e6668ef50a65f63b 100644 --- a/res/menu/album_sort_by.xml +++ b/res/menu/album_sort_by.xml @@ -19,7 +19,6 @@ xmlns:android="http://schemas.android.com/apk/res/android" > @@ -42,4 +41,4 @@ - \ No newline at end of file + diff --git a/res/menu/artist_album_sort_by.xml b/res/menu/artist_album_sort_by.xml deleted file mode 100644 index 672348a3a9ab1d39fc853ac954c0d37f5c5c3c59..0000000000000000000000000000000000000000 --- a/res/menu/artist_album_sort_by.xml +++ /dev/null @@ -1,40 +0,0 @@ - - - - - - - - - - - - - - \ No newline at end of file diff --git a/res/menu/artist_song_sort_by.xml b/res/menu/artist_song_sort_by.xml deleted file mode 100644 index 3de99bc7ac4b938ea145aefb3d87672935ee6c37..0000000000000000000000000000000000000000 --- a/res/menu/artist_song_sort_by.xml +++ /dev/null @@ -1,49 +0,0 @@ - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/res/menu/artist_sort_by.xml b/res/menu/artist_sort_by.xml index d9f288f6b63036ae2682d716a2b05c18654b5f84..468320311f7f0b71ba6603ba59b1908e203aca3b 100644 --- a/res/menu/artist_sort_by.xml +++ b/res/menu/artist_sort_by.xml @@ -19,7 +19,6 @@ xmlns:android="http://schemas.android.com/apk/res/android" > @@ -39,4 +38,4 @@ - \ No newline at end of file + diff --git a/res/menu/song_sort_by.xml b/res/menu/song_sort_by.xml index 7ee527ad42750fd93818935b9aaaf33e094635b8..4cd5d4bff76d54d407c85a3f326192ca3332e6a7 100644 --- a/res/menu/song_sort_by.xml +++ b/res/menu/song_sort_by.xml @@ -19,7 +19,6 @@ xmlns:android="http://schemas.android.com/apk/res/android" > @@ -48,4 +47,4 @@ - \ No newline at end of file + diff --git a/res/transition/explode.xml b/res/transition/explode.xml deleted file mode 100644 index ba135b2aff6da33311deb02252579ffa51ebe190..0000000000000000000000000000000000000000 --- a/res/transition/explode.xml +++ /dev/null @@ -1,2 +0,0 @@ - diff --git a/res/values-af/plurals.xml b/res/values-af/plurals.xml index 48ee55571c2bebcdc29060d88de6477ca4fa088c..3240d8765f4abb468e0b7c1014795835a39ff2c9 100644 --- a/res/values-af/plurals.xml +++ b/res/values-af/plurals.xml @@ -16,10 +16,6 @@ limitations under the License. --> - - %d kunstenaar - %d kunstenaars - %d album %d albums @@ -28,10 +24,6 @@ %d lied %d liedere - - %d genre - %d genres - %dh %dh @@ -52,10 +44,6 @@ %d lied bygevoeg tot die waglys. %d liedjies bygevoeg tot die waglys. - - %d lied by gunstelinge gevoeg. - %d liedjies by gunstelinge gevoeg. - %d lied was verwyder. %d liedjies was verwyder. diff --git a/res/values-af/strings.xml b/res/values-af/strings.xml index f659f1f629d59b56fad785a78d5502bb4ef82be1..d82f0bb1524ae9e369105dbd6ee04cf0e8371082 100644 --- a/res/values-af/strings.xml +++ b/res/values-af/strings.xml @@ -18,16 +18,12 @@ --> Musiek - Onlangs Kunstenaars Albums Liedjies Speellys - Genres - Speel tans Speel waglys Albums - Beste Liedjies Alle Liedjies Instellings Skommel @@ -38,16 +34,13 @@ Skommel beste liedjies Skommel onlangs gespeel Skommel laaste bygevoeg - Speel almal Sorteer volgens Verwyder alle items - Verwyder onlangse items Vee waglys uit Stoor wag items na snitlys Klankmenger Voeg by speellys Voeg by waglys - Verwyder vanuit onlangse lys Verwyder vanuit waglys A-Z Z-A @@ -55,8 +48,6 @@ Album Jaar Tydsduur - Datum bygevoeg - Speellys Aantal liedjies Aantal albums Leêrnaam @@ -77,9 +68,7 @@ Hierdie kan nie ongedaan gemaak word nie Dit sal permanent kasgeheue foto inskrywings verwyder Kies foto vanuit Galery - Google soektog Gebruik verstekfoto - Gebruik ou foto Speel Speel volgende Speel album @@ -101,10 +90,7 @@ Herhaal Herhaal almal Herhaal eenkeer - Maak waglys oop - Kyk na musiek \"%s\" gestel as luitoon - Speellys is hernoem Berging Verwyder kasgeheue Verwyder alle kasgeheue foto\'s @@ -117,10 +103,7 @@ Musiek: 4 \u00d7 1 Musiek: 4 \u00d7 2 Musiek: 4 \u00d7 2 (alternatief) - Musiek: onlangs geluister Die equalizer kon nie oopgemaak word nie. - Om musiek van jou rekenaar na jou toestel te kopieer, gebruik \'n USB-kabel. - Liedjies wat jy gemerk het as gunstelinge word hier vertoon. Geen onlangse liedjies Liedjies wat jy onlangs geluister het, sal hier vertoon. Geen liedjies in speellys @@ -151,13 +134,5 @@ 10+ liedjies 5+ albums "Ander" - Wys alle kunstenaars - Wys alle albums - Wys alle liedjies - Wys alle speel waglyste - Alle \"%s\" kunstenaars - Alle \"%s\" albums - Alle \"%s\" liedjies - Alle \"%s\" speellyste %1$s %2$s diff --git a/res/values-ar/plurals.xml b/res/values-ar/plurals.xml index 93c031a8bacf8ff69aded54f57a9dabf18ac0924..647c3571cb7f86c2d6a37b3a952743aaf8018dfe 100644 --- a/res/values-ar/plurals.xml +++ b/res/values-ar/plurals.xml @@ -16,14 +16,6 @@ limitations under the License. --> - - %d فنان - %d فنانين - %d فنانين - %d فنانين - %d فنانين - %d فنانين - %d ألبوم %d ألبومات @@ -40,14 +32,6 @@ %d أغاني %d أغاني - - %d نوع - %d أنواع - %d أنواع - %d أنواع - %d أنواع - %d أنواع - %dس %dس @@ -88,14 +72,6 @@ %d أغاني أُضيفت إلى قائمة الانتظار. %d أغاني أُضيفت إلى قائمة الانتظار. - - %d أغنية أضيفت إلى القائمة المفضلة. - %d أغنيات أضيفت إلى القائمة المفضلة. - %d أغنيات أضيفت إلى القائمة المفضلة. - %d أغنيات أضيفت إلى القائمة المفضلة. - %d أغنيات أضيفت إلى القائمة المفضلة. - %d أغنيات أضيفت إلى القائمة المفضلة. - تم حذف %d أغنية. تم حذف %d أغنيات. diff --git a/res/values-ar/strings.xml b/res/values-ar/strings.xml index 9fe7850efb36f641851cdd5f0ce9a91761036012..4ea887692f73b058ac637b73730dc95eefaa85b4 100644 --- a/res/values-ar/strings.xml +++ b/res/values-ar/strings.xml @@ -18,16 +18,12 @@ --> موسيقى - حديث فنانون ألبومات أغاني قوائم تشغيل - أنواع - قيد التشغيل قائمة انتظار التشغيل ألبومات - الأغاني الأعلى كل الأغاني إعدادات خلْط @@ -38,16 +34,13 @@ خلط الأغاني الأعلى خلط الأغاني التي أذيعت مؤخراً خلط آخر أغاني أضيفت - تشغيل الكل الترتيب حسب مسح القائمة - مسح الأغاني الأخيرة مسح قائمة الانتظار حفظ قائمة الانتظار إلى قائمة التشغيل المعادل إضافة إلى قائمة التشغيل إضافة إلى قائمة الانتظار - إزالة من الأغاني الأخيرة إزالة من قائمة الانتظار من الألف إلى الياء من الياء إلى الألف @@ -55,8 +48,6 @@ ألبوم السنة المدة - تاريخ الإضافة - قائمة الأغاني عدد الأغاني عدد الألبومات اختر الملف @@ -77,9 +68,7 @@ لا يمكن التراجع عن هذا سيؤدي هذا إلى حذف إدخالات الصورة المخزنة مؤقتاً بشكل دائم اختيار صورة من معرض الصور - بحث جوجل استخدام الصورة الافتراضية - استخدام الصور القديمة تشغيل تشغيل التالي تشغيل الألبوم @@ -101,15 +90,13 @@ تكرار تكرار كل تكرار واحدة - فتح قائمة الانتظار - استعراض الموسيقى تعيين \'%s\' كنغمة رنين - تمت إعادة تسميته قائمة التشغيل التخزين حذف ذاكرة التخزين المؤقت إزالة كافة الصور المخزنة مؤقتاً عام إظهار المرئيات مع الموسيقى + خلفية ضبابية عرض كلمات الأغاني للأغاني التي تحتوي على ملف srt هز للتشغيل @@ -117,10 +104,7 @@ موسيقى: 4 \u00d7 1 موسيقى: 4 \u00d7 2 موسيقى: 4 \u00d7 2 (بالتبادل) - الموسيقى: ما استمعت إليه مؤخراً تعذر فتح المعادل. - لنسخ ملفات الموسيقى من الكمبيوتر إلى الجهاز الخاص بك، استخدم كبل USB. - الأغاني التي وضعت عليها علامة المفضلة ستظهر هنا. لا توجد أغاني حديثة. الأغاني التي استمعت إليها مؤخراً ستظهر هنا. لا توجد أغاني في قائمة التشغيل @@ -151,14 +135,6 @@ 10 + أغاني 5 + ألبومات "أخرى" - إظهار جميع الفنانين - إظهار جميع الألبومات - إظهار جميع الأغاني - إظهار جميع قوائم التشغيل - جميع الفنانين \"%s\" - جميع ألبومات \"%s\" - جميع أغاني \"%s\" - جميع قوائم التشغيل \"%s\" %1$s %2$s تشغيل الموسيقى diff --git a/res/values-as/plurals.xml b/res/values-as/plurals.xml index 2108e35d69aec984a5a1961662c0cdcbdcaa01f1..36d3731a75ad326c8f746a68238a7cf8ea06dd5e 100644 --- a/res/values-as/plurals.xml +++ b/res/values-as/plurals.xml @@ -16,10 +16,6 @@ limitations under the License. --> - - %d শিল্পী - %d শিল্পী - %d এলবাম %d এলবামসমূহ @@ -28,10 +24,6 @@ %d গীত %d গীতসমূহ - - %d ৰকম - %d ৰকম - %d গীত প্লে’লিষ্টত যোগ কৰা হৈছে। %d প্লে’লিষ্টত গীতসমূহ যোগ কৰা হৈছে @@ -44,10 +36,6 @@ %d গীত লানি যোগ কৰা হৈছে। %d গীত কিউত যোগ কৰা হৈছে। - - %d গীত প্ৰিয়ত যোগ কৰা হৈছে। - %d গীত প্ৰিয়ত যোগ কৰা হৈছে। - %d গীত বিলোপ কৰা হৈছে। %d গীতসমূহ মচি দিয়া হৈছে diff --git a/res/values-as/strings.xml b/res/values-as/strings.xml index a5b2aa5338872005b517f0319bb28e7ac238c2fc..9c7fd509ede75febbd5308445856a1854c5b0f2e 100644 --- a/res/values-as/strings.xml +++ b/res/values-as/strings.xml @@ -18,16 +18,12 @@ --> মিউজিক - শেহতীয়া চিত্ৰকৰসকল এলবামসমূহ গীতসমূহ প্লেলিষ্টs - শ্ৰেণী - এতিয়া চলি আছে প্লে কিউ এলবামসমূহ - শীৰ্ষ গীত সকলো গীত ছেটিংছ সানমিহলি কৰক @@ -38,16 +34,13 @@ শীৰ্ষ ট্ৰেকবোৰ সানমিহলি কৰক শেহতীয়াকৈ প্লে কৰাবোৰ সানমিহলি কৰক অন্তিম যোগ কৰাবোৰ সানমিহলি কৰক - আটাইবোৰ প্লে’ কৰক সজাই লওঁক তালিকাখন আঁতৰাওঁক - শেহতীয়াবোৰ পৰিষ্কাৰ কৰক কিউ পৰিষ্কাৰ কৰক প্লে-সূচীলৈ কিউ সংৰক্ষণ কৰক ইকুইলাইজাৰ প্লেলিষ্টলৈ যোগ দিয়ক কিউলৈ যোগ কৰক - শেহতীয়াৰ পৰা আঁতৰাওক কিউৰ পৰা আঁতৰাওক A-Z Z-A @@ -55,8 +48,6 @@ এলবাম বছৰ সময়সীমা - তাৰিখ যোগ কৰা হৈছে - ট্ৰেক সূচী গীতৰ সংখ্যা এলবামৰ সংখ্যা ফাইলনাম @@ -77,9 +68,7 @@ এইটো ওভতাব নোৱাৰি ই কেশ্বড প্ৰতিচ্ছবি এণ্ট্ৰিবোৰ স্থায়ীভাবে আঁতৰাব গেলাৰীৰ পৰা ফটো বাচনি কৰক - Google অনুসন্ধান ডিফ\'ল্ট ফটো ব্যৱহাৰ কৰক - পুৰণি ফটো ব্যৱহাৰ কৰক চলাওঁক পৰৱৰ্তীটো প্লে কৰক এলবাম প্লে কৰক @@ -101,10 +90,7 @@ পুনৰাবৃত্তি সকলো পুনৰাবৃত্তি কৰক এটা পুনৰাবৃত্তি কৰক - কিউ খোলক - সংগীত ব্ৰাউজ কৰক \'%s\' ৰিংটোন হিচাপে ছেট কৰা হৈছে - প্লে-সূচী পুনৰ নামাকৰণ কৰা হৈছে ষ্টোৰেজ কেশ্ব বিলোপ কৰক কেশ্বড কৰা সকলো প্ৰতিচ্ছবি আঁতৰাওক @@ -117,10 +103,7 @@ সংগীত: 4 \u00d7 1 সংগীত: 4 \u00d7 2 সংগীত: 4 \u00d7 2 (বিকল্প) - সংগীত: শেহতীয়াকৈ শুনা ইকুইলাইজাৰ খুলিব পৰা নগ\'ল - কম্পিউটাৰৰ পৰা আপোনাৰ ডিভাইচলৈ সংগীত কপি কৰিবলৈ, এডাল USB কেবল ব্যৱহাৰ কৰক - আপুনি প্ৰিয় হিচাপে চিহ্নিত কৰা গীতবোৰ ইয়াত দেখুওৱা হ\'ব। কোনো শেহতীয়া গীত নাই আপুনি শেহতীয়াকৈ শুনা গীতবোৰ ইয়াত প্ৰদৰ্শিত হ\'ব। কোনো গীত প্লে-সূচী নাই @@ -151,13 +134,5 @@ 10+ টা গান 5+ এলবাম ""অন্যান্য"" - সকলো শিল্পী প্ৰদৰ্শন কৰক - সকলো এলবাম প্ৰদৰ্শন কৰক - সকলো গীত প্ৰদৰ্শন কৰক - সকলো প্লে-সূচী প্ৰদৰ্শন কৰক - সকলো \"%s\" শিল্পী - সকলো \"%s\" এলবাম - সকলো \"%s\" গীত - সকলো \"%s\" প্লে-সূচী %1$s %2$s diff --git a/res/values-ast-rES/plurals.xml b/res/values-ast-rES/plurals.xml index c08c32cfa5cd95d6ea8264670aa71a692e252e39..9ef905d5fc6972dccdabe4045f028a90de2d619c 100644 --- a/res/values-ast-rES/plurals.xml +++ b/res/values-ast-rES/plurals.xml @@ -16,48 +16,8 @@ limitations under the License. --> - - %d artista - %d artistes - - - %d álbum - %d álbumes - - - %d canción - %d canciones - - - %d xéneru - %d xéneros - - - %dh - %dh - - %dm - %dm - - - %d canción amestada a la llista. - %d canciones amestaes a la llista. - - - %d canción desaniciada de la llista. - %d canciones desaniciaes de la llista. - - - %d canción amestada a la cola. - %d canciones amestaes a la cola. - - - %d canción amestada a favoritos. - %d canciones amestaes a favoritos. - - - Desanicióse %d canción. - Desaniciáronse %d canciones. + %d m + %d m diff --git a/res/values-ast-rES/strings.xml b/res/values-ast-rES/strings.xml index ad252fc748f0f2bb44ac89f81de0bce74f5ceb04..9f76329c2c90bffea00537403ff020d07a6b06e7 100644 --- a/res/values-ast-rES/strings.xml +++ b/res/values-ast-rES/strings.xml @@ -18,147 +18,24 @@ --> Música - Reciente Artistes Álbumes - Canciones - Llistes de reproducción - Xéneros - Reproduciendo agora - Cola de reproducción Álbumes - Canciones más escuchaes - Toles canciones - Axustes - Al debalu - Too al debalu - Llista de reproducción aleatoria - Álbum al debalu - Artistes al debalu - Canciones más sentíes al debalu - Caberes reproducíes aleatories - Caberes amestaes aleatories - Reproducir too - Ordenar per - Llimpiar llista - Llimpiar reciente - Llimpiar cola - Guardar cola a la llista de reproducción Ecualizador - Amestar a la llista reproducción - Amestar a la cola - Desaniciar de reciente - Desaniciar de la cola A-Z Z-A Artista Álbum Añu Duración - Data amestáu - Llista de pistes - Númberu de canciones - Númberu d\'álbumes - Nome de ficheru - Recientes - Reproducío apocayá - Les canciones más escuchaes - Llista de reproducción nueva - Guardar Encaboxar - Sobrescribir - Llimpiar - Llista %d - Nome de llista - ¿Desaniciar %s? - ¿Llimpiar les más reproducíes? - ¿Llimpiar reproducíos de recién? - ¿Llimpiar caberos amestaos? - Esto nun pue desafacese - Esto desaniciará dafechu toles imáxenes na caché - Esbillar imaxe de la Galería - Gueta de Google - Usar imaxe por defeutu - Usar imaxe previa - Reproducir - Siguiente - Reproducir álbum - Más del artista - Renomar - Desaniciar - Obtener carátula del álbum - Obtener semeya del artista - Quitar de recientes - Usar como timbre - Quitar de la llista - Camudar imaxe - Reproducir - Posar + ¿Quies desaniciar «%s»? + Negóse\'l permisu pa grabar audiu. Concédelu n\'aplicación «Axustes» p\'activar la visualización musical Siguiente - Anterior - Al debalu - Too al debalu - Repitir - Repitilo too - Repitir una - Abrir cola - Restolar pente la música - «%s» afitóse como timbre - Llista renomada - Almacenamientu - Desanciar caché - Desanicia toles imáxenes na caché + Quita toles imáxenes de la caché Xeneral - Amosar visualización musical - Amosar les lletres de les canciones - Pa canciones que tengan un ficheru srt - Xiringar pa reproducir - Xiringa\'l preséu pa reproducir la siguiente canción - Música: 4 \u00d7 1 - Música: 4 \u00d7 2 - Música: 4 \u00d7 2 (alternativu) - Música: Escuchaes recientemente - L\'ecualizador nun pudo abrise. - Pa copiar música del to ordenador al to preséu, usa un cable USB. - Les canciones que marques como favorites van apaecer equí. - Nun hai canciones recientes - Les canciones que sentisti hai poco van apaecer equí. - Nun hai canciones na llista - P\'amestar canciones a esta llista, toca nel menú d\'opciones d\'una canción, álbum o artista y seleiciona \u00ABAmestar a la llista\u00BB. - Nun hai canciones más escuchaes - Les canciones que más escuches van amestase a esta llista. - Nun s\'amestaron canciones recientemente - Les canciones qu\'amestasti\'l postrer mes, van apaecer equí. - Nun s\'alcontró música - Pa copiar música del ordenador al preséu, usa un cable USB. - Nun hai canciones na cola - P\'amestar canciones a la cola, toca nel menú d\'opciones d\'una canción, álbum o artista y seleiciona \u00ABAmestar a la cola\u00BB. - Nun pue reproducise la pista %1$s - Añu desconocíu - Menos de 30 segundos - 30 - 60 segundos - 1 - 2 minutos - 2 - 3 minutos - 3 - 4 minutos - 4 - 5 minutos - 5 - 10 minutos - 10 - 30 minutos - 30 - 60 minutos + Desenfocar el fondu Más de 60 minutos - 1 canción - 2 - 4 canciones - 5 - 9 canciones - 10+ canciones - 5+ álbumes - "Otru" - Amosar tolos artistes - Amosar tolos álbumes - Amosar toles canciones - Amosar toles llistes - Tolos artistes de «%s» - Tolos álbumes de «%s» - Toles canciones de «%s» - Toles llistes de «%s» %1$s %2$s Reproducción de música diff --git a/res/values-az/plurals.xml b/res/values-az/plurals.xml index b095824190bf9cb18a53431c214f62451b309d28..006a73a462790505605418e5b1b713a585f8417f 100644 --- a/res/values-az/plurals.xml +++ b/res/values-az/plurals.xml @@ -16,10 +16,6 @@ limitations under the License. --> - - %d müğənni - %d müğənni - %d albom %d albom @@ -28,10 +24,6 @@ %d mahnı %d mahnı - - %d janr - %d janr - %dsa %dsa @@ -52,10 +44,6 @@ %d mahnı növbəyə əlavə edildi. %d mahnı növbəyə əlavə edildi. - - %d mahnı seçilmişlərə əlavə edildi. - %d mahnı seçilmişlərə əlavə edildi. - %d mahnı silindi. %d mahnı silindi. diff --git a/res/values-az/strings.xml b/res/values-az/strings.xml index 27495bc8c9b593421638893c82559fdb621f0b40..4dda18cdf4c0c2861f85e0fe0f20233fde99c3c9 100644 --- a/res/values-az/strings.xml +++ b/res/values-az/strings.xml @@ -18,16 +18,12 @@ --> Musiqi - Ən son Sənətkarlar Albomlar Mahnılar Oynatma siyahıları - Janrlar - İndi Oynadılan Növbədəkini Oynat Albomlar - Top Mahnılar Bütün Mahnılar Tənzimləmələr Qarışdır @@ -38,16 +34,13 @@ Ən çox dinlənənləri qarışdır Son çalınanları qarışdır Son əlavə edilənləri qarışdır - Hamısını oynat Sıralama: Siyahını təmizlə - Son çalınanları təmizlə Növbədəkini sil Növbəni oynatma siyahısında saxla Ekvalayzer Oynatma siyahısına əlavə et Növbəyə əlavə et - Son çalınanlardan çıxart Növbədən çıxart A-Z Z-A @@ -55,8 +48,6 @@ Albom İl Müddət - Əlavə edilmə tarixi - Musiqi siyahısı Mahnı sayı Albom sayı Fayl adı @@ -77,9 +68,8 @@ Bu əməliyyat geri alına bilməz Bu, gizli yaddaşda olan təsvirləri birdəfəlik siləcək Qalereyadan foto seçin - Google axtarışı İlkin fotodan istifadə et - Köhnə fotodan istifadə et + Səsyazma icazəsi rədd edildi, musiqi vizuallaşdırmanı fəallaşdırmaq üçün Tənzimləmələrdən fəallaşdırın Oynat Sonrakını çal Albomu oynat @@ -101,15 +91,12 @@ Təkrarla Hamısını təkrarla Birini təkrarla - Növbəni aç - Musiqini gözdən keçir \'%s\' zəng səsi kimi tənzimləndi - Siyahı yenidən adlandırıldı Anbar Gizli yaddaşı sil Gizli yaddaşdakı bütün təsvirləri sil Ümumi - Musiqi əyaniləşdiricini göstər + Musiqi vizuallaşdırıcını göstər Bulanıq arxaplan Mahnı sözlərini göstər srt faylı olan mahnılar üçün @@ -118,10 +105,7 @@ Musiqi: 4 \u00d7 1 Musiqi: 4 \u00d7 2 Musiqi: 4 \u00d7 2 (alternativ) - Musiqi: son vaxtlar dinlənən Ekvalayzer açılmadı. - Komputerinizdən cihazınıza musiqi kopyalamaq üçün USB kabeldən istifadə edin. - Seçilmiş kimi işarələdiyiniz mahnılar burada görünəcək. Son çalınan mahnı yoxdur Təzəlikcə dinlədiyiniz mahnılar burada görünəcək. Oynatma siyahısında mahnı yoxdur @@ -152,14 +136,6 @@ 10+ mahnı 5+ albom "Digər" - Bütün sənətkarları göstər - Bütün albomları göstər - Bütün mahnıları göstər - Bütün siyahıları göstər - Bütün \"%s\" sənətkarları - Bütün \"%s\" albomları - Bütün \"%s\" mahnıları - Bütün \"%s\" oynatma siyahıları %1$s %2$s Musiqi oynatma diff --git a/res/values-be/strings.xml b/res/values-be/strings.xml index 098d5401c2798f49fbfac3b0c0c5a37514865355..7d01126d44fd96bfa7ac1ef74f6620b6275fa3a1 100644 --- a/res/values-be/strings.xml +++ b/res/values-be/strings.xml @@ -18,16 +18,12 @@ --> Музыка - Апошнія Выканаўцы Альбомы Трэкi Плэйлісты - Жанры - Зараз грае Чарга прайгравання Альбомы - Топ-трэкі Усе трэкі Налады Перамяшаць @@ -38,16 +34,13 @@ Перамяшаць топ-трэкі Перамяшаць нядаўна прайграныя Перамяшаць апошнія дададзеныя - Граць усё Сартаваць паводле Ачысціць спіс - Ачысціць апошнія Ачысціць чаргу Захаваць у плэйліст Эквалайзер Дадаць у плэйліст Дадаць у чаргу - Выдаліць з апошніх Выдаліць з чаргі Алфавіту Алфавіту ў зваротным парадку @@ -55,8 +48,6 @@ Альбому Году Працягласці - Даце дадання - Трэк-лісту Колькасці трэкаў Колькасці альбомаў Імя файла @@ -77,9 +68,7 @@ Гэта дзеянне немагчыма скасаваць Кэшаваныя выявы будуць выдалены Выбраць з Галерэі - Знайсці ў Google Відарыс па змаўчанні - Зыходная выява\" Прайграць Уключыць наступным Прайграць @@ -101,10 +90,7 @@ Паўтор Паўтор усіх Паўтор трэка - Адчыніць чаргу - Агляд музыкі Трэк %s усталяваны як рынгтон - Плэйліст пераназваны Сховішча Ачысціць кэш Выдаліць усе кэшаваныя выявы @@ -117,10 +103,7 @@ Музыка: 4 \u00d7 1 Музыка: 4 \u00d7 2 Музыка: 4 \u00d7 2 (альтэрнатыўны) - Музыка: нядаўна праслуханыя Эквалайзер не можа быць адчынены. - Каб скапіяваць музыку з ПК, выкарыстайце USB-кабель. - Тут будуць трэкі, якія вы дадалі ў абранае. Няма нядаўніх трэкаў Трэкі, якія вы слухалі нядаўна, будуць знаходзіцца тут. Няма трэкаў у плэйлісце @@ -151,13 +134,5 @@ Больш за 10 трэкаў Больш за 5 альбомаў "Іншыя" - Паказаць усіх выканаўцаў - Паказаць усе альбомы - Паказаць усе трэкі - Паказаць усе плэйлісты - Усе выканаўцы \"%s\" - Усе альбомы \"%s\" - Усе трэкі \"%s\" - Усе плэйлісты \"%s\" %1$s %2$s diff --git a/res/values-bg/plurals.xml b/res/values-bg/plurals.xml index f42c0460b12c33581884b5ac04043d6f8fdc5c76..4c24e099a76e41596038fba2323759b778b6f6cb 100644 --- a/res/values-bg/plurals.xml +++ b/res/values-bg/plurals.xml @@ -16,10 +16,6 @@ limitations under the License. --> - - %d изпълнител - %d изпълнители - %d албум %d албума @@ -28,10 +24,6 @@ %d песен %d песни - - %d жанр - %d жанра - %d ч %d ч @@ -52,10 +44,6 @@ %d песен е добавена към опашката. %d песни са добавени към опашката. - - %d песен е добавена към \"Предпочитани\". - %d песни са добавени към \"Предпочитани\". - %d песен е изтрита. %d песни са изтрити. diff --git a/res/values-bg/strings.xml b/res/values-bg/strings.xml index 1947be2c6179c3ba38cf52aacb31f72eaf8347fd..4d3c636271f5b962c5d353c3c332e718e81a4a40 100644 --- a/res/values-bg/strings.xml +++ b/res/values-bg/strings.xml @@ -18,16 +18,12 @@ --> Музика - Пресни Изпълнители Албуми Песни Списъци за изпълнение - Жанрове - Сега се изпълнява На опашката за възпроизвеждане Албуми - Топ песни Всички песни Настройки Разбъркване @@ -38,16 +34,13 @@ Развъркване на топ песните Разбъркване на скоро слушаните Разбъркване на последно добавените - Възпроизвеждане на всички Сортирай по Изчисти списъка - Изчистване на скорошните Изчистване на опашката за изпълнение Запазване на опашката за изпълнение в списъка за изпълнение Еквалайзер Добави към списък за изпълниние Добавяне към опашката за изпълнение - Премахване от последно изпълнявани Премахване от опашката за изпълнение А-Я Я-А @@ -55,8 +48,6 @@ Албум Година Времетраене - Дата на добавяне - Списък с песни Брой на песните Брой на албумите Име на файла @@ -77,9 +68,7 @@ Това не може да бъде отменено Това завинаги ще изтрие записите в кеша Изберете снимка от Галерия - Търсене в Google Използване снимка по подразбиране - Използвай стара снимка Изпълни Следваща песен Изпълни албум @@ -101,10 +90,7 @@ Повтори Повтори всички Повтори една - Отвори опашка за изпълнение - Прегледайте музиката \"%s\" е зададена, като тон на звънене. - Преименувай списъка за изпълнение Хранилище Изтриване на кеша Премахва всички кеширани изображения @@ -118,10 +104,7 @@ Музика: 4 \u00d7 1 Музика: 4 \u00d7 2 Музика: 4 \u00d7 2 (алтернативен) - Музика: наскоро слушана Еквалайзера не може да бъде отворен. - За да копирате музика от вашия компютър към вашето устройство, използвайте USB кабел. - Песните маркирани като любими ще бъдат показани тук. Няма скорошни песни Песните който сте слушали последно ще се покажат тук. Няма песни в списъка за изпълнение @@ -152,14 +135,6 @@ 10+ песни 5+ албума "Други" - Покажи всички изпълнители - Покажи всички албуми - Покажи всички песни - Покажи всички списъци за изпълнение - Всички изпълнители на \"%s\" - Всички албуми на \"%s\" - Всички песни на \"%s\" - Всички списъци за изпълнение \"%s\" %1$s %2$s Възпроизвеждане на музика diff --git a/res/values-ca/plurals.xml b/res/values-ca/plurals.xml index ebade68fb6482e68b1c0335a2e912ebe9ffc7bd0..d2d34d706216bfe74624efd202bdc0100ced1659 100644 --- a/res/values-ca/plurals.xml +++ b/res/values-ca/plurals.xml @@ -16,10 +16,6 @@ limitations under the License. --> - - %d artista - %d artistes - %d àlbum %d àlbums @@ -28,10 +24,6 @@ %d cançó %d cançons - - %d gènere - %d gèneres - %dh %dh @@ -52,10 +44,6 @@ %d cançó s\'ha afegit a la cua. %d cançons s\'han afegit a la cua. - - %d cançó afegida als preferits. - %d cançons afegides als preferits. - %d cançó s\'ha esborrat. %d cançons s\'han esborrat. diff --git a/res/values-ca/strings.xml b/res/values-ca/strings.xml index 78c36ba336c4d91a87615f822e587eae2c035b40..13632432776a872c5d7630023b387488d70980ad 100644 --- a/res/values-ca/strings.xml +++ b/res/values-ca/strings.xml @@ -18,16 +18,12 @@ --> Música - Recent Artistes Àlbums Cançons Llistes de reproducció - Gèneres - Ara sona Reprodueix cua Àlbums - Cançons més escoltades Totes les cançons Configuració Barreja @@ -38,16 +34,13 @@ Barreja els temes més escoltats Barreja els reproduïts recentment Barreja els darrers afegits - Reprodueix tot Ordena per Neteja la llista - Neteja els recents Neteja la cua Desa-ho en cua a la llista de reproducció Equalitzador Afegeix a la llista de reproducció Afegeix a la cua - Treu dels recents Treu de la cua A-Z Z-A @@ -55,8 +48,6 @@ Àlbum Any Duració - Data d\'addició - Llista de pistes Nombre de cançons Nombre d\'àlbums Nom del fitxer @@ -77,9 +68,8 @@ Això no es podrà desfer Això esborrarà permanentment les imatges de la memòria cau Tria una foto de la galeria - Cerca a Google Utilitza la foto predefinida - Utilitza la foto antiga + S\'ha denegat el permís d\'enregistrament d\'àudio, activeu-lo des de l\'aplicació Configuració per activar la visualització de música Reprodueix Reprodueix el següent Reprodueix àlbum @@ -101,10 +91,7 @@ Repeteix Repeteix tot Repeteix un - Obre la cua - Navega per la música \'%s\' establert com a to de trucada - Llista de reproducció reanomenada Emmagatzematge Esborra memòria cau Treu totes les imatges de la memòria cau @@ -118,10 +105,7 @@ Música: 4 \u00d7 1 Música: 4 \u00d7 2 Música: 4 \u00d7 2 (alternatiu) - Música: recentment escoltada L\'equalitzador no s\'ha pogut obrir. - Per copiar música del teu ordenador al teu dispositiu, utilitza un cable USB. - Les cançons que marquis com a preferides es mostraran aquí. Cap cançó recent Les cançons que has escoltat recentment apareixeran aquí. Sense cançons a la llista de reproducció @@ -152,14 +136,6 @@ 10+ cançons 5+ àlbums "Altres" - Mostra tots els artistes - Mostra tots els àlbums - Mostra totes les cançons - Mostra totes les llistes de reproducció - Tots els artistes de \"%s\" - Tots els àlbums de \"%s\" - Totes les cançons de \"%s\" - Totes les llistes de reproducció de \"%s\" %1$s %2$s Reproducció de música diff --git a/res/values-cs/plurals.xml b/res/values-cs/plurals.xml index b7b26ebde84dd86151f2c5073e793d47a7246e77..34f36f78008f04d66887afb914c14c2412320d67 100644 --- a/res/values-cs/plurals.xml +++ b/res/values-cs/plurals.xml @@ -16,12 +16,6 @@ limitations under the License. --> - - %d umělec - %d umělci - %d umělců - %d umělců - %d album %d alba @@ -34,12 +28,6 @@ %d skladeb %d skladeb - - %d žánr - %d žánry - %d žánrů - %d žánrů - %dh %dh @@ -70,12 +58,6 @@ Do fronty přidáno %d skladeb. Do fronty přidáno %d skladeb. - - Do oblíbených byla přidána %d skladba. - Do oblíbených byly přidány %d skladby. - Do oblíbených bylo přidáno %d skladeb. - Do oblíbených bylo přidáno %d skladeb. - Odstraněna %d skladba. Odstraněny %d skladby. diff --git a/res/values-cs/strings.xml b/res/values-cs/strings.xml index 59cba6ca740b5aa3d4fbc3f307432e06e964fe9c..970a2dce5ce431638b9dee7db8502a80d8167a74 100644 --- a/res/values-cs/strings.xml +++ b/res/values-cs/strings.xml @@ -18,16 +18,12 @@ --> Hudba - Nedávné Umělci Alba Skladby Seznamy skladeb - Žánry - Přehrává se Fronta přehrávání Alba - Nejlepší skladby Všechny skladby Nastavení Náhodně @@ -38,16 +34,13 @@ Náhodně nejlepší skladby Náhodně nedávno přehrávané Náhodně naposledy přidané - Přehrát vše Řadit podle Vyčistit seznam - Vyčistit nedávné Vyčistit frontu Uložit frontu do seznamu skladeb Ekvalizér Přidat do seznamu skladeb Přidat do fronty - Odebrat z nedávných Odebrat z fronty A-Z Z-A @@ -55,8 +48,6 @@ Alba Roku Délky - Data přidání - Seznamu stop Počtu skladeb Počtu alb Jména souboru @@ -77,9 +68,7 @@ Tuto operaci nelze vrátit Tímto trvale odstraníte stáhnuté obrázky Zvolte obrázek z Galerie - Vyhledávání Google Použít výchozí obrázek - Použít starý obrázek Přehrát Přehrát další Přehrát album @@ -101,10 +90,7 @@ Opakovat Opakovat vše Opakovat jednu - Otevřít frontu - Procházet hudbu %s“ nastaveno jako vyzvánění - Seznam skladeb přejmenován Úložiště Smazat cache Odstranit všechny uložené obrázky @@ -118,10 +104,7 @@ Hudba: 4 \u00d7 1 Hudba: 4 \u00d7 2 Hudba: 4 \u00d7 2 (alternativní) - Hudba: nedávno poslouchané Nelze otevřít ekvalizér. - Pro kopírování hudebních souborů z počítače do zařízení použijte USB kabel. - Zde budou zobrazeny všechny skladby označené jako oblíbené. Žádné naposledy přehrávané Zde budou zobrazeny všechny nedávno přehrávané skladby. Žádné skladby v seznamu skladeb @@ -152,14 +135,6 @@ Více jak 10 skladeb Více jak 5 alb "Jiné" - Zobrazit všechny umělce - Zobrazit všechna alba - Zobrazit všechny skladby - Zobrazit všechny seznamy skladeb - Vše od umělce „%s“ - Vše v albu „%s“ - Všechny skladby \"%s\" - Všechny v seznamu skladeb „%s“ %1$s %2$s Přehrávání hudby diff --git a/res/values-cy/plurals.xml b/res/values-cy/plurals.xml index 0a6fa0aa4e696af0ab600e7083f134bfc03d3d21..3d3436501f4f2142956ae00040836b391b2f1ffc 100644 --- a/res/values-cy/plurals.xml +++ b/res/values-cy/plurals.xml @@ -16,14 +16,6 @@ limitations under the License. --> - - %d artistiaid - %d artist - %d artist - %d artist - %d artist - %d artist - %d casgliadau %d casgliad @@ -40,14 +32,6 @@ %d thrac %d trac - - %d genres - %d genre - %d genres - %d genres - %d genres - %d genres - %da %da @@ -88,14 +72,6 @@ %d thrac wedi\'u hychwanegu i\'r ciw. %d trac wedi\'u hychwanegu i\'r ciw. - - %d traciau wedi\'u hychwanegu at ffefrynnau. - %d trac wedi\'i ychwanegu at ffefrynnau. - %d drac wedi\'u hychwanegu at ffefrynnau. - %d thrac wedi\'u hychwanegu at ffefrynnau. - %d thrac wedi\'u hychwanegu at ffefrynnau. - %d trac wedi\'u hychwanegu at ffefrynnau. - %d traciau wedi\'u dileu. %d trac wedi\'i ddileu. diff --git a/res/values-cy/strings.xml b/res/values-cy/strings.xml index 8b520ccfa521e0825265b4c6b6447d59711cb261..fc5351919476ec26da5758e8b262a6727bba9626 100644 --- a/res/values-cy/strings.xml +++ b/res/values-cy/strings.xml @@ -18,16 +18,12 @@ --> Cerddoriaeth - Diweddar Artistiaid Casgliadau Traciau Rhestri caneuon - Genres - Yn Chwarae Nawr Ciw Chwarae Casgliadau - Traciau Poblogaidd Pob Trac Gosodiadau Cymysgu @@ -38,16 +34,13 @@ Cymysgu\'r traciau poblogaidd Cymysgu\'r traciau chwaraewyd diweddar Cymysgu\'r traciau ychwanegwyd diwethaf - Chwarae\'r cwbl Trefnu yn ôl Clirio\'r rhestr - Clirio\'r traciau diweddar Clirio\'r ciw Cadw\'r ciw i\'r rhestr chwarae Cydraddolydd Ychwanegu i\'r rhestr chwarae Ychwanegu i\'r ciw - Tynnu o\'r traciau diweddar Tynnu o\'r ciw A i Y Y i A @@ -55,8 +48,6 @@ Casgliad Blwyddyn Hyd - Dyddiad ychwanegwyd - Rhestr traciau Nifer o draciau Nifer o gasgliadau Enw ffeil @@ -77,9 +68,7 @@ Nid yw\'n bosib dadwneud hyn. Bydd hyn yn dileu delweddau wedi\'u cadw dros dro Dewis lun o\'r oriel - Chwilio Google Defnyddio llun rhagosodedig - Defnyddio hen lun Chwarae Chwarae\'r nesaf Chwarae casgliad @@ -101,10 +90,7 @@ Ailchwarae Ailchwarae\'r cwbl Ailchwarae un - Agor y ciw - Pori traciau Gosodwyd \'%s\' fel y tôn caniad - Ailenwyd y rhestr chwarae Storfa Dileu\'r cof dros dro Dileu pob delwedd wedi\'i chadw dros dro @@ -118,10 +104,7 @@ Cerddoriaeth: 4 \u00d7 1 Cerddoriaeth 4 \u00d7 2 Cerddoriaeth 4 \u00d7 2 (amgen) - Cerddoriaeth: chwaraewyd yn ddiweddar Methwyd ag agor y cydraddolydd. - I gopïo cerddoriaeth o dy gyfrifiadur i dy ddyfais, defnyddia gebl USB. - Bydd traciau rwyt yn eu nodi fel ffefrynnau yn ymddangos yma. Dim traciau diweddar Bydd traciau rwyt wedi gwrando arnynt yn ddiweddar yn ymddangos yma. Does dim traciau yn y rhestr chwarae @@ -152,14 +135,6 @@ 10+ o draciau 5+ casgliad "Arall" - Dangos pob artist - Dangos pob casgliad - Dangos pob trac - Dangos pob rhestr chwarae - Pob artist \"%s\" - Pob \"%s\" casgliad - Pob trac \"%s\" - Pob rhestr chwarae \"%s\" %1$s %2$s Chwarae cerddoriaeth diff --git a/res/values-da/plurals.xml b/res/values-da/plurals.xml index 5d38adf4bb662a42fb48e65de06559ee8bd5690a..a463087b571c197ceecca466a097b1d2de1562f9 100644 --- a/res/values-da/plurals.xml +++ b/res/values-da/plurals.xml @@ -16,10 +16,6 @@ limitations under the License. --> - - %d kunstner - %d kunstnere - %d album %d album @@ -28,10 +24,6 @@ %d sang %d sange - - %d genre - %d genrer - %dt %dt @@ -52,10 +44,6 @@ %d sang føjet til køen. %d sange føjet til køen. - - %d sang føjet til favoritter. - %d sange føjet til favoritter. - %d sang blev slettet. %d sange blev slettet. diff --git a/res/values-da/strings.xml b/res/values-da/strings.xml index c7969159b9f562d8e99fc8c8ab22b28d23c9706b..d2c64784c5a40abc1c6de0bef07ede9f268be1c9 100644 --- a/res/values-da/strings.xml +++ b/res/values-da/strings.xml @@ -18,16 +18,12 @@ --> Musik - Seneste Kunstnere Album Sange Afspilningslister - Genrer - Afspiller Nu Afspilningskø Album - Top Sange Alle Sange Indstillinger Bland @@ -38,16 +34,13 @@ Bland top spor Bland senest afspillede Bland senest tilføjede - Afspil alle Sortér efter Ryd liste - Ryd seneste Ryd kø Gem kø til afspilningsliste Udligner Føj til afspilningsliste Føj til kø - Fjern fra seneste Fjern fra kø A-Å Å-A @@ -55,8 +48,6 @@ Album År Varighed - Dato tilføjet - Sporliste Antal sange Antal album Filnavn @@ -77,9 +68,7 @@ Dette kan ikke fortrydes Dette vil permanent slette de lagrede billedposter Vælg fotografi fra Galleri - Google-søgning Brug standard-fotografi - Brug gammelt fotografi Afspil Afspil næste Afspil album @@ -101,10 +90,7 @@ Gentag Gentag alle Gentag én - Åbn kø - Gennemse musik \'%s\' angivet som ringetone - Afspilningsliste omdøbt Lagerplads Slet lokalt lager Fjern alle lokalt lagrede billeder @@ -117,10 +103,7 @@ Musik: 4 \u00d7 1 Musik: 4 \u00d7 2 Musik: 4 \u00d7 2 (afvekslende) - Musik: senest lyttet til Udligneren kunne ikke åbnes. - Brug et USB-kabel til at kopiere musik, fra din computer til din enhed. - Sange du markerer som favoritter, vil blive vist her. Ingen seneste sange Sange du har lyttet til på det seneste, vil blive vist her. Ingen sange i afspilningsliste @@ -151,13 +134,6 @@ 10+ sange 5+ album "Andre" - Vis alle kunstnere - Vis alle album - Vis alle sange - Vis alle afspilningslister - Alle \"%s\" kunstnere - Alle \"%s\" album - Alle \"%s\" sange - Alle \"%s\" afspilningslister %1$s %2$s + Musikafspilning diff --git a/res/values-de/plurals.xml b/res/values-de/plurals.xml index e8aeea0fd6623ad42d815d18bae60895581150af..cbe208e7b65417661ae77330e8c4df495af15b5d 100644 --- a/res/values-de/plurals.xml +++ b/res/values-de/plurals.xml @@ -16,10 +16,6 @@ limitations under the License. --> - - %d Interpret - %d Interpreten - %d Album %d Alben @@ -28,10 +24,6 @@ %d Titel %d Titel - - %d Genre - %d Genres - %d h %d h @@ -52,10 +44,6 @@ %d Titel wurde zur Warteschlange hinzugefügt. %d Titel wurden zur Warteschlange hinzugefügt. - - %d Titel wurde zu den Favoriten hinzugefügt. - %d Titel wurden zu den Favoriten hinzugefügt. - %d Titel wurde gelöscht. %d Titel wurden gelöscht. diff --git a/res/values-de/strings.xml b/res/values-de/strings.xml index f8a68753d3af1c5cab427f6cd62040b368a75041..484c40fda3ea0413ae9b99b6945a57a7c7ccc0c7 100644 --- a/res/values-de/strings.xml +++ b/res/values-de/strings.xml @@ -17,16 +17,12 @@ limitations under the License. --> Musik - Kürzlich gehört Interpreten Alben Titel Wiedergabelisten - Genres - Aktuelle Wiedergabe Wiedergabe-Warteschlange Alben - Toptitel Alle Titel Einstellungen Zufällige Wiedergabe @@ -37,16 +33,13 @@ Toptitel zufällig wiedergeben Kürzlich gehörte Titel zufällig wiedergeben Zuletzt hinzugefügte Titel zufällig wiedergeben - Alle wiedergeben Sortieren nach Liste löschen - \"Kürzlich gehört\" löschen Warteschlange löschen Warteschlange als Wiedergabeliste speichern Equalizer Zur Wiedergabeliste hinzufügen Zur Warteschlange hinzufügen - Aus \"Kürzlich gehört\" entfernen Aus Warteschlange entfernen A-Z Z-A @@ -54,8 +47,6 @@ Album Jahr Titellänge - Hinzugefügt am - Titelliste Titelanzahl Albenanzahl Dateiname @@ -76,9 +67,8 @@ Dies kann nicht rückgängig gemacht werden Alle zwischengespeicherten Bilder werden hiermit endgültig gelöscht Foto aus Galerie auswählen - Google-Suche Standardfoto verwenden - Altes Foto verwenden + Berechtigung zur Audioaufnahme wurde verweigert. Erlaube sie in den App-Einstellungen, um die Musikvisualisierung zu aktivieren. Wiedergeben Als nächstes wiedergeben Album wiedergeben @@ -102,7 +92,7 @@ Aktuellen Titel wiederholen Warteschlange öffnen Musik durchsuchen - %s“ wurde als Klingelton festgelegt + \"%s\" wurde als Klingelton festgelegt. Wiedergabeliste umbenannt Speicher Cache löschen @@ -113,27 +103,24 @@ Songtexte zeigen Für Titel mit einer SRT-Datei Zum Abspielen schütteln - Schütteln Sie Ihr Gerät, um den nächsten Titel abzuspielen + Schüttel dein Gerät, um den nächsten Titel abzuspielen. Musik: 4 \u00d7 1 Musik: 4 \u00d7 2 Musik: 4 \u00d7 2 (alternativ) - Musik: Kürzlich abgespielt Der Equalizer konnte nicht geöffnet werden. - Verwenden Sie ein USB-Kabel, um Musik von Ihrem Computer auf Ihr Gerät zu kopieren. - Als Favorit markierte Titel werden hier angezeigt. Keine kürzlich gespielten Titel Zuletzt gehörte Titel werden hier angezeigt. Keine Titel in der Wiedergabeliste - Tippen Sie im Optionsmenü auf einen Titel, Künstler oder ein Album und wählen Sie \"Zur Wiedergabeliste hinzufügen\", um den jeweiligen Eintrag zu dieser Liste hinzuzufügen. + Tippe im Optionsmenü auf einen Titel, Künstler oder ein Album und wähle \"Zur Wiedergabeliste hinzufügen\", um den jeweiligen Eintrag zu dieser Liste hinzuzufügen. Keine Toptitel Meistgespielte Titel werden dieser Liste hinzugefügt. Keine kürzlich hinzugefügten Titel Hier werden Titel angezeigt, die innerhalb des letzten Monats hinzugefügt wurden. Keine Musik gefunden - Verwenden Sie ein USB-Kabel, um Musik von Ihrem Computer auf das Gerät zu kopieren. + Verwende ein USB-Kabel, um Musik von deinem Computer auf dein Gerät zu kopieren. Keine Titel in der Warteschlange - Um Titel zur Warteschlange hinzuzufügen, wählen Sie im Optionsmenü eines Titels, Albums oder Interpreten \"Zur Warteschlange hinzufügen\". - Der Titel %1$s konnte nicht abgespielt werden + Um Titel zur Warteschlange hinzuzufügen, wähle im Optionsmenü eines Titels, Albums oder Interpreten \"Zur Warteschlange hinzufügen\". + Der Titel \"%1$s\" konnte nicht abgespielt werden. Unbekanntes Jahr Weniger als 30 Sekunden 30–60 Sekunden @@ -151,14 +138,6 @@ Mehr als 10 Titel Mehr als 5 Alben "Anderes" - Alle Interpreten anzeigen - Alle Alben anzeigen - Alle Titel anzeigen - Alle Wiedergabelisten anzeigen - Alle \"%s\" Interpreten - Alle \"%s\" Alben - Alle \"%s\" Titel - Alle \"%s\" Wiedergabelisten %1$s %2$s Musikwiedergabe \ No newline at end of file diff --git a/res/values-el/plurals.xml b/res/values-el/plurals.xml index fa1bfe7f9c4fb812ed5b2c8961227bb77e3dfa85..b951e3068a3193edfd21d7f8e24921c698b76a03 100644 --- a/res/values-el/plurals.xml +++ b/res/values-el/plurals.xml @@ -16,10 +16,6 @@ limitations under the License. --> - - %d καλλιτέχνης - %d καλλιτέχνες - %d άλμπουμ %d άλμπουμ @@ -28,10 +24,6 @@ %d τραγούδι %d τραγούδια - - %d είδος - %d είδη - %dω %dω @@ -52,10 +44,6 @@ %d τραγούδι προστέθηκε στην ουρά. %d τραγούδια προστέθηκαν στην ουρά. - - %d τραγούδι προστέθηκε στα αγαπημένα. - %d τραγούδια προστέθηκαν στα αγαπημένα. - %d τραγούδι διεγράφη. %d τραγούδια διαγράφηκαν. diff --git a/res/values-el/strings.xml b/res/values-el/strings.xml index 6c38a1b949ad015b2e5fdd71b7a2f98beb7576f5..0853bafaa37cde75c086aa7a991f0c79fe559038 100644 --- a/res/values-el/strings.xml +++ b/res/values-el/strings.xml @@ -18,16 +18,12 @@ --> Μουσική - Πρόσφατα Καλλιτέχνες Άλμπουμ Τραγούδια Λίστες αναπαραγωγής - Είδη - Παίζει Τώρα Ουρά αναπαραγωγής Άλμπουμ - Κορυφαία τραγούδια Όλα τα τραγούδια Ρυθμίσεις Τυχαία αναπαραγωγή @@ -38,16 +34,13 @@ Τυχαία αναπαραγωγή κορυφαίων κομματιών Τυχαία αναπαραγωγή προσφάτων Τυχαία αναπαραγωγή τελευταίων αφίξεων - Αναπαραγωγή όλων Ταξινόμηση κατά Εκκαθάριση λίστας - Εκκαθάριση προσφάτων Εκκαθάριση ουράς Αποθήκευση ουράς σε λίστα αναπαραγωγής Ισοσταθμιστής Προσθήκη στη λίστα αναπαραγωγής Προσθήκη στην ουρά - Κατάργηση από τα πρόσφατα Κατάργηση από την ουρά Α-Ω Ω-Α @@ -55,8 +48,6 @@ Άλμπουμ Έτος Διάρκεια - Ημερομηνία προσθήκης - Λίστα κομματιών Αριθμός τραγουδιών Αριθμός άλμπουμ Όνομα αρχείου @@ -77,9 +68,8 @@ Αυτό δεν μπορεί να αναιρεθεί Αυτό θα διαγράψει μόνιμα τις προσωρινά αποθηκευμένες εικόνες Επιλέξτε φωτογραφία από τη Συλλογή - Αναζήτηση Google Χρήση προεπιλεγμένης φωτογραφίας - Χρήση παλιάς φωτογραφίας + Δεν δόθηκε άδεια εγγραφής ήχου, ενεργοποιήστε την από την εφαρμογή Ρυθμίσεις για να ενεργοποιήσετε την οπτικοποίηση μουσικής Αναπαραγωγή Αναπαραγωγή επόμενου Αναπαραγωγή άλμπουμ @@ -101,10 +91,7 @@ Επανάληψη Επανάληψη όλων Επανάληψη ενός - Άνοιγμα ουράς - Περιήγηση μουσικής \'%s\' ορίστηκε ως ήχος κλήσης - Η λίστα αναπαραγωγής μετονομάστηκε Αποθ. χώρος Διαγράφη προσωρινής μνήμης Κατάργηση όλων των προσωρινά αποθηκευμένων εικόνων @@ -118,10 +105,7 @@ Μουσική: 4 \u00d7 1 Μουσική: 4 \u00d7 2 Μουσική: 4 \u00d7 2 (εναλλακτικό) - Μουσική: ακούστηκαν πρόσφατα Δεν ήταν δυνατό το άνοιγμα του ισοσταθμιστή. - Για να αντιγράψετε μουσική από τον υπολογιστή στη συσκευή σας, χρησιμοποιήστε ένα καλώδιο USB. - Τραγούδια που έχετε επιλέξει ως αγαπημένα θα εμφανίζονται εδώ. Δεν υπάρχουν πρόσφατα τραγούδια Τραγούδια που ακούσατε πρόσφατα θα εμφανίζονται εδώ. Δεν υπάρχουν τραγούδια στη λίστα αναπαραγωγής @@ -152,14 +136,6 @@ 10+ τραγούδια 5+ άλμπουμ "Άλλα" - Εμφάνιση όλων των καλλιτεχνών - Εμφάνιση όλων των άλμπουμ - Εμφάνιση όλων των τραγουδιών - Εμφάνιση όλων των λιστών αναπαραγωγής - Όλοι οι καλλιτέχνες \"%s\" - Όλα τα άλμπουμ \"%s\" - Όλα τα τραγούδια \"%s\" - Όλες οι λίστες αναπαραγωγής \"%s\" %1$s %2$s Αναπαραγωγή μουσικής diff --git a/res/values-en-rAU/plurals.xml b/res/values-en-rAU/plurals.xml index bc7efdf8cac0be63cda0cee0b80e9433f997d0b9..fcb250b6f7da472bba7905afe327e4153fe8ae54 100644 --- a/res/values-en-rAU/plurals.xml +++ b/res/values-en-rAU/plurals.xml @@ -16,10 +16,6 @@ limitations under the License. --> - - %d artist - %d artists - %d album %d albums @@ -28,10 +24,6 @@ %d song %d songs - - %d genre - %d genres - %dh %dh @@ -52,10 +44,6 @@ %d song added to the queue. %d songs added to the queue. - - %d song added to favourites. - %d songs added to favourites. - %d song was deleted. %d songs were deleted. diff --git a/res/values-en-rAU/strings.xml b/res/values-en-rAU/strings.xml index 488ffb5935c8ad6975d02d042a7f76e2d99780b5..6c43d6e0a199808b7ca04d08bc6c3ead89b7f7a5 100644 --- a/res/values-en-rAU/strings.xml +++ b/res/values-en-rAU/strings.xml @@ -18,16 +18,12 @@ --> Music - Recent Artists Albums Songs Playlists - Genres - Now Playing Play Queue Albums - Top Songs All Songs Settings Shuffle @@ -38,16 +34,13 @@ Shuffle top tracks Shuffle recently played Shuffle last added - Play all Sort by Clear list - Clear recent Clear queue Save queue to playlist Equaliser Add to playlist Add to queue - Remove from recent Remove from queue A-Z Z-A @@ -55,8 +48,6 @@ Album Year Duration - Date added - Track list Number of songs Number of albums Filename @@ -77,9 +68,8 @@ This cannot be undone This will permanently delete the cached image entries Choose photo from Gallery - Google search Use default photo - Use old photo + Audio recording permission was denied, enable it from Settings app to enable music visualization Play Play next Play album @@ -101,10 +91,7 @@ Repeat Repeat all Repeat one - Open queue - Browse music \'%s\' set as ringtone - Playlist renamed Storage Delete cache Remove all cached images @@ -118,10 +105,7 @@ Music: 4 \u00d7 1 Music: 4 \u00d7 2 Music: 4 \u00d7 2 (alternate) - Music: recently listened The equaliser could not be opened. - To copy music from your computer to your device, use a USB cable. - Songs you mark as favourites will be shown here. No recent songs Songs you have listened to recently will show up here. No songs in playlist @@ -152,14 +136,6 @@ 10+ songs 5+ albums "Other" - Show all artists - Show all albums - Show all songs - Show all playlists - All \"%s\" artists - All \"%s\" albums - All \"%s\" songs - All \"%s\" playlists %1$s %2$s Music playback diff --git a/res/values-en-rCA/plurals.xml b/res/values-en-rCA/plurals.xml index 30766d2185cba37fc8aab3cd004f117d2ed74721..4d680436c32ca8b805cb199f99a50095e6cab2e6 100644 --- a/res/values-en-rCA/plurals.xml +++ b/res/values-en-rCA/plurals.xml @@ -16,10 +16,6 @@ limitations under the License. --> - - %d artist - %d artists - %d album %d albums @@ -28,10 +24,6 @@ %d song %d songs - - %d genre - %d genres - %dh %dh @@ -52,10 +44,6 @@ %d song added to the queue. %d song added to the queue. - - %d song added to favourites. - %d songs added to favourites. - %d song was deleted. %d songs were deleted. diff --git a/res/values-en-rCA/strings.xml b/res/values-en-rCA/strings.xml index 0be0a5c9bcd6953b29aa6ad1cb82aa7016a0244b..f378875864721e0da8d11450563cf685a941550a 100644 --- a/res/values-en-rCA/strings.xml +++ b/res/values-en-rCA/strings.xml @@ -18,16 +18,12 @@ --> Music - Recent Artists Albums Songs Playlists - Genres - Now Playing Play Queue Albums - Top Songs All Songs Settings Shuffle @@ -38,16 +34,13 @@ Shuffle top tracks Shuffle recently played Shuffle last added - Play all Sort by Clear list - Clear recent Clear queue Save queue to playlist Equalizer Add to playlist Add to queue - Remove from recent Remove from queue A-Z Z-A @@ -55,8 +48,6 @@ Album Year Duration - Date added - Track list Number of songs Number of albums Filename @@ -77,9 +68,8 @@ This cannot be undone This will permanently delete the cached image entries Choose photo from Gallery - Google search Use default photo - Use old photo + Audio recording permission was denied, enable it from Settings app to enable music visualization Play Play next Play album @@ -101,10 +91,7 @@ Repeat Repeat all Repeat one - Open queue - Browse music \'%s\' set as ringtone - Playlist renamed Storage Delete cache Remove all cached images @@ -118,10 +105,7 @@ Music: 4 \u00d7 1 Music: 4 \u00d7 2 Music: 4 \u00d7 2 (alternate) - Music: recently listened The equalizer could not be opened. - To copy music from your computer to your device, use a USB cable. - Songs you mark as favourites will be shown here. No recent songs Songs you have listened to recently will show up here. No songs in playlist @@ -152,14 +136,6 @@ 10+ songs 5+ albums "Other" - Show all artists - Show all albums - Show all songs - Show all playlists - All \"%s\" artists - All \"%s\" albums - All \"%s\" songs - All \"%s\" playlists %1$s %2$s Music playback diff --git a/res/values-en-rGB/plurals.xml b/res/values-en-rGB/plurals.xml index bc7efdf8cac0be63cda0cee0b80e9433f997d0b9..fcb250b6f7da472bba7905afe327e4153fe8ae54 100644 --- a/res/values-en-rGB/plurals.xml +++ b/res/values-en-rGB/plurals.xml @@ -16,10 +16,6 @@ limitations under the License. --> - - %d artist - %d artists - %d album %d albums @@ -28,10 +24,6 @@ %d song %d songs - - %d genre - %d genres - %dh %dh @@ -52,10 +44,6 @@ %d song added to the queue. %d songs added to the queue. - - %d song added to favourites. - %d songs added to favourites. - %d song was deleted. %d songs were deleted. diff --git a/res/values-en-rGB/strings.xml b/res/values-en-rGB/strings.xml index c360595f5d13af4fffe6c045f324fb4d3e519eda..d7a5d8e7795c4279593dd50a049d3c9d2f3930f2 100644 --- a/res/values-en-rGB/strings.xml +++ b/res/values-en-rGB/strings.xml @@ -18,16 +18,12 @@ --> Music - Recent Artists Albums Songs Playlists - Genres - Now Playing Play Queue Albums - Top Songs All Songs Settings Shuffle @@ -38,16 +34,13 @@ Shuffle top tracks Shuffle recently played Shuffle last added - Play all Sort by Clear list - Clear recent Clear queue Save queue to playlist Equaliser Add to playlist Add to queue - Remove from recent Remove from queue A-Z Z-A @@ -55,8 +48,6 @@ Album Year Duration - Date added - Track list Number of songs Number of albums Filename @@ -77,9 +68,8 @@ This cannot be undone This will permanently delete the cached image entries Choose photo from Gallery - Google search Use default photo - Use old photo + Audio recording permission was denied, enable it from Settings app to enable music visualisation Play Play next Play album @@ -101,10 +91,7 @@ Repeat Repeat all Repeat one - Open queue - Browse music \'%s\' set as ringtone - Playlist renamed Storage Delete cache Remove all cached images @@ -118,10 +105,7 @@ Music: 4 \u00d7 1 Music: 4 \u00d7 2 Music: 4 \u00d7 2 (alternate) - Music: recently listened The equaliser could not be opened. - To copy music from your computer to your device, use a USB cable. - Songs you mark as favourites will be shown here. No recent songs Songs you have listened to recently will show up here. No songs in playlist @@ -152,14 +136,6 @@ 10+ songs 5+ albums "Other" - Show all artists - Show all albums - Show all songs - Show all playlists - All \"%s\" artists - All \"%s\" albums - All \"%s\" songs - All \"%s\" playlists %1$s %2$s Music playback diff --git a/res/values-en-rIN/plurals.xml b/res/values-en-rIN/plurals.xml index 52a75545dc69981ca40626c05e2f1a05f6a1a631..fcb250b6f7da472bba7905afe327e4153fe8ae54 100644 --- a/res/values-en-rIN/plurals.xml +++ b/res/values-en-rIN/plurals.xml @@ -16,10 +16,6 @@ limitations under the License. --> - - %d artist - %d artists - %d album %d albums @@ -28,10 +24,6 @@ %d song %d songs - - %d genre - %d genres - %dh %dh @@ -52,10 +44,6 @@ %d song added to the queue. %d songs added to the queue. - - %d song added to favorites. - %d songs added to favorites. - %d song was deleted. %d songs were deleted. diff --git a/res/values-en-rIN/strings.xml b/res/values-en-rIN/strings.xml index e7d846af01cfe09a4a8dab1e170ced551fec96e4..a24cb2efda3c9298eea7af4b6d867ddf28748f0d 100644 --- a/res/values-en-rIN/strings.xml +++ b/res/values-en-rIN/strings.xml @@ -18,16 +18,12 @@ --> Music - Recent Artists Albums Songs Playlists - Genres - Now Playing Play Queue Albums - Top Songs All Songs Settings Shuffle @@ -38,16 +34,13 @@ Shuffle top tracks Shuffle recently played Shuffle last added - Play all Sort by Clear list - Clear recent Clear queue Save queue to playlist Equalizer Add to playlist Add to queue - Remove from recent Remove from queue A-Z Z-A @@ -55,8 +48,6 @@ Album Year Duration - Date added - Track list Number of songs Number of albums Filename @@ -77,9 +68,8 @@ This cannot be undone This will permanently delete the cached image entries Choose photo from Gallery - Google search Use default photo - Use old photo + Audio recording permission was denied, enable it from Settings app to enable music visualisation Play Play next Play album @@ -101,10 +91,7 @@ Repeat Repeat all Repeat one - Open queue - Browse music \'%s\' set as ringtone - Playlist renamed Storage Delete cache Remove all cached images @@ -118,10 +105,7 @@ Music: 4 \u00d7 1 Music: 4 \u00d7 2 Music: 4 \u00d7 2 (alternate) - Music: recently listened The equalizer could not be opened. - To copy music from your computer to your device, use a USB cable. - Songs you mark as favorites will be shown here. No recent songs Songs you have listened to recently will show up here. No songs in playlist @@ -152,14 +136,6 @@ 10+ songs 5+ albums "Other" - Show all artists - Show all albums - Show all songs - Show all playlists - All \"%s\" artists - All \"%s\" albums - All \"%s\" songs - All \"%s\" playlists %1$s %2$s Music playback diff --git a/res/values-es-rUS/plurals.xml b/res/values-es-rUS/plurals.xml index e097f4a101bc0384ae382c793f6172f8684c60c0..6dbf248c99a2ef14c77de03a518a2603a1a47797 100644 --- a/res/values-es-rUS/plurals.xml +++ b/res/values-es-rUS/plurals.xml @@ -16,10 +16,6 @@ limitations under the License. --> - - %d artista - %d artistas - %d álbum %d álbumes @@ -28,10 +24,6 @@ %d canción %d canciones - - %d género - %d géneros - %dh %dh @@ -52,10 +44,6 @@ %d canción añadida a la cola. %d canciones añadidas a la cola. - - %d canción añadida a favoritos. - %d canciones añadidas a favoritos. - %d canción fue eliminada. %d canciones fueron eliminadas. diff --git a/res/values-es-rUS/strings.xml b/res/values-es-rUS/strings.xml index b333d58fe0c946b77a9a683642fead53937dc86d..4d219586286525f391f5a7ae9b64eedc1ae0b071 100644 --- a/res/values-es-rUS/strings.xml +++ b/res/values-es-rUS/strings.xml @@ -18,16 +18,12 @@ --> Música - Reciente Artistas Álbumes Canciones Listas de reproducción - Géneros - Reproduciendo ahora Cola de reproducción Álbumes - Canciones más escuchadas Todas las canciones Ajustes Orden aleatorio @@ -38,16 +34,13 @@ Reproducir las más escuchadas aleatoriamente Seleccionar las reproducidas recientemente Seleccionar las últimas añadidas - Reproducir todo Ordenar por Borrar lista - Borrar recientes Borrar cola Guardar cola en la lista de reproducción Ecualizador Añadir a la lista Añadir a la cola - Quitar de recientes Quitar de la cola A-Z Z-A @@ -55,8 +48,6 @@ Álbum Año Duración - Fecha - Número de pista Número de canciones Número de álbumes Nombre de archivo @@ -77,9 +68,7 @@ Esta operación no se puede deshacer Esta operación borrará todas las imágenes almacenadas en caché Elegir imagen de la galería - Buscar en Google Usar imagen predefinida - Usar imagen previa Reproducir Siguiente Reproducir álbum @@ -101,10 +90,7 @@ Repetir Repetir todas Repetir una - Abrir cola - Buscar música Se estableció «%s » como tono de llamada - Lista renombrada Almacenamiento Borrar caché Quitar todas las imágenes almacenadas @@ -117,10 +103,7 @@ Música: 4 \u00d7 1 Música: 4 \u00d7 2 Música: 4 \u00d7 2 (alternativo) - Música: Escuchada recientemente No se pudo abrir el ecualizador. - Para copiar música del ordenador al dispositivo, utiliza un cable USB. - Las canciones marcadas como favoritas aparecerán aquí. Sin canciones recientes Las canciones que hayas escuchado recientemente aparecerán aquí. Sin canciones en la lista de reproducción @@ -151,14 +134,6 @@ Más de 10 canciones Más de 5 álbumes "Otros" - Mostrar todos los artistas - Mostrar todos los álbumes - Mostrar todas las canciones - Mostrar todas las listas de reproducción - Todos los artistas «%s» - Todos los álbumes «%s» - Todas las canciones «%s» - Todas las listas de reproducción «%s» %1$s %2$s Reproducción de música diff --git a/res/values-es/plurals.xml b/res/values-es/plurals.xml index e097f4a101bc0384ae382c793f6172f8684c60c0..6dbf248c99a2ef14c77de03a518a2603a1a47797 100644 --- a/res/values-es/plurals.xml +++ b/res/values-es/plurals.xml @@ -16,10 +16,6 @@ limitations under the License. --> - - %d artista - %d artistas - %d álbum %d álbumes @@ -28,10 +24,6 @@ %d canción %d canciones - - %d género - %d géneros - %dh %dh @@ -52,10 +44,6 @@ %d canción añadida a la cola. %d canciones añadidas a la cola. - - %d canción añadida a favoritos. - %d canciones añadidas a favoritos. - %d canción fue eliminada. %d canciones fueron eliminadas. diff --git a/res/values-es/strings.xml b/res/values-es/strings.xml index 755cbf959f5eff33db2303b5711257735923f6cd..2a9a95c08f1275f7d55c33f027e03b0bc03b7b7d 100644 --- a/res/values-es/strings.xml +++ b/res/values-es/strings.xml @@ -18,16 +18,12 @@ --> Música - Reciente Artistas Álbumes Canciones Listas de reproducción - Géneros - Reproduciendo ahora Cola de reproducción Álbumes - Canciones más escuchadas Todas las canciones Ajustes Mezclar @@ -38,16 +34,13 @@ Mezclar las más escuchadas Mezclar reproducidas recientemente Mezclar las últimas añadidas - Reproducir todas Ordenar por Borrar lista - Borrar recientes Borrar cola Guardar cola en la lista de reproducción Ecualizador Añadir a la lista de reproducción Añadir a la cola - Quitar de recientes Quitar de la cola A-Z Z-A @@ -55,8 +48,6 @@ Álbum Año Duración - Fecha añadido - Número de pista Número de canciones Número de álbumes Nombre del archivo @@ -77,9 +68,7 @@ Esta operación no se puede deshacer Esta operación eliminará permanentemente todas las imágenes almacenadas en caché Elegir imagen de la Galería - Buscar en Google Usar imagen por defecto - Usar imagen previa Reproducir Siguiente Reproducir álbum @@ -101,15 +90,13 @@ Repetir Repetir todo Repetir una - Abrir cola - Navegar por la música «%s» establecido como timbre de llamada - Lista con nombre nuevo Almacenamiento Limpiar caché Eliminar todas las imágenes almacenadas General Mostrar visualización musical + Desenfocar el fondo Mostrar las letras de las canciones Para canciones que tienen un archivo srt Agitar para reproducir @@ -117,10 +104,7 @@ Música: 4 \u00d7 1 Música: 4 \u00d7 2 Música: 4 \u00d7 2 (alternativo) - Música: Escuchado recientemente El ecualizador no se ha podido abrir. - Para copiar música del ordenador al dispositivo, utiliza un cable USB. - Las canciones que marques como favoritas aparecerán aquí. No hay canciones recientes Las canciones que hayas escuchado recientemente aparecerán aquí. No hay canciones en la lista de reproducción @@ -151,13 +135,5 @@ 10+ canciones 5+ álbumes "Otro" - Mostrar todos los artistas - Mostrar todos los álbumes - Mostrar todas las canciones - Mostrar todas las listas de reproducción - Todos los artistas «%s» - Todos los álbumes «%s» - Todas las canciones «%s» - Todas las listas «%s» %1$s %2$s diff --git a/res/values-et/plurals.xml b/res/values-et/plurals.xml index c258fda1459d77656881ab68596538a689ab1519..73925e4cb260e0baf7df93e7844440a5a488805e 100644 --- a/res/values-et/plurals.xml +++ b/res/values-et/plurals.xml @@ -16,10 +16,6 @@ limitations under the License. --> - - %d esitaja - %d esitajad - %d album %d albumit @@ -28,10 +24,6 @@ %d lugu %d lugu - - %d žanr - %d žanri - %dh %dh @@ -52,10 +44,6 @@ %d lugu lisatud esitlusjärjekorda. %d lugu lisatud esitlusjärjekorda. - - %d lugu lisatud lemmikutesse. - %d lugu lisatud lemmikutesse. - %d lugu kustutatud. %d lugu kustutatud. diff --git a/res/values-et/strings.xml b/res/values-et/strings.xml index e4393d8a939a658457c66460d4ee137b43d2a307..9419d1ac9d64364eb2a8aafec9a0ab1fee3b309a 100644 --- a/res/values-et/strings.xml +++ b/res/values-et/strings.xml @@ -18,16 +18,12 @@ --> Muusika - Hiljutised Esitajad Albumid Laulud Esitusloendid - Žanrid - Nüüd esitamisel Esitlusjärjekord Albumid - Top laulud Kõik laulud Seaded Juhuesitus @@ -38,16 +34,13 @@ Juhuesita top muusikapala Juhuesita viimati esitatud Juhuesita viimati lisatud - Esita kõik Sorteeri Tühjenda loend - Kustuta hiljutised Kustuta järjekord Salvesta esitlusjärjekord esitlusloendisse Ekvalaiser Lisa esitusloendisse Lisa järjekorda - Eemalda hiljutistest Eemalda järjekorrast A-Z Z-A @@ -55,8 +48,6 @@ Album Aasta Kestus - Lisamise kuupäev - Lugude nimekiri Laulude arv Albumite arv Faili nimi @@ -77,9 +68,7 @@ Seda ei saa tagasi võtta See toiming kustutab puhverdatud pildid alatiseks Vali foto galeriist - Google\'i otsing Kasuta vaikimisi pilti - Kasuta vana pilti Esita Esita järgmine Esita album @@ -101,10 +90,7 @@ Korda Korda kõiki Korda ühte - Ava järjekord - Sirvi muusikat \'%s\' sea telefoni helinaks - Esitusloend ümbernimetatud Mälu Kustuta vahemälu Eemalda kõik puhverdatud pildid @@ -118,10 +104,7 @@ Muusika: 4 \u00d7 1 Muusika: 4 \u00d7 2 Muusika: 4 \u00d7 2 (alternatiiv) - Muusika: hiljuti kuulatud Ekvalaiserit ei saanud avada. - Et kopeerida muusikat arvutist seadmesse, kasuta USB-kaablit. - Lemmikuteks märgitud laulud kuvatakse siin. Puuduvad hiljutised laulud Hiljuti kuulatud laulud kuvatakse siin. Esitlusloendis puuduvad laulud @@ -152,14 +135,6 @@ 10+ laulu 5+ Albumit "Muud" - Kuva kõik esitajad - Kuva kõik albumid - Kuva kõik laulud - Kuva kõik esitusloendid - Kõik \"%s\" esitajad - Kõik \"%s\" albumid - Kõik \"%s\" laulud - Kõik \"%s\" esitusloendid %1$s %2$s Muusika taasesitus diff --git a/res/values-eu/plurals.xml b/res/values-eu/plurals.xml index dee954ab0542642971402ae54ebe0c27a4c36a69..b479ca233fda91cc0d08fc9c9f424c5728604da4 100644 --- a/res/values-eu/plurals.xml +++ b/res/values-eu/plurals.xml @@ -16,10 +16,6 @@ limitations under the License. --> - - Artista %d - %d artista - Album %d %d album @@ -28,10 +24,6 @@ Abesti %d %d abesti - - Genero %d - %d genero - %do %do @@ -52,10 +44,6 @@ Abesti %d gehitu da ilarara. %d abesti gehitu dira ilarara. - - Abesti %d gehitu da gogokoetara. - %d abesti bat gehitu dira gogokoetara. - Abesti %d ezabatu da. %d abesti ezabatu dira. diff --git a/res/values-eu/strings.xml b/res/values-eu/strings.xml index 291ac425a2f3d26517765078862c2c2644919d83..78ee76e885bd32e0cc76ffdd5ff4438158e079b3 100644 --- a/res/values-eu/strings.xml +++ b/res/values-eu/strings.xml @@ -18,16 +18,12 @@ --> Musika - Azkenak Artistak Albumak Abestiak Zerrendak - Generoak - Orain erreproduzitzen Erreproduzitu ilara Albumak - Gehien entzundako abestiak Abesti guztiak Ezarpenak Nahastu @@ -38,16 +34,13 @@ Nahastu gehien entzundakoak Nahastu berriki entzundakoak Nahastu berriki gehitutakoak - Erreproduzitu guztiak Ordenatu honela Garbitu zerrenda - Garbitu azkenak Garbitu ilara Gorde ilara erreprodukzio-zerrenda gisa Ekualizadorea Gehitu erreprodukzio zerrendara Gehitu ilarara - Kendu azkenetatik Kendu Ilaratik A-Z Z-A @@ -55,8 +48,6 @@ Albuma Urtea Iraupena - Gehitze data - Pista zerrenda Abesti kopurua Album kopurua Fitxategi izena @@ -77,9 +68,7 @@ Hau ezin da desegin Honek cachean gordetako irudi guztiak behin betiko ezabatuko ditu Hautatu galeriako argazkia - Google bilaketa Erabili argazki lehenetsia - Erabili aurreko irudia Erreproduzitu Erreproduzitu hurrengoa Erreproduzitu albuma @@ -101,10 +90,7 @@ Errepikatu Errepikatu guztiak Errepikatu bat - Ireki ilara - Arakatu musika \'%s\' dei doinu bezala ezarri da - Erreprodukzio zerrendaren izena aldatu da Biltegiratzea Ezabatu cachea Ezabatu cachean gordetako irudi guztiak @@ -117,10 +103,7 @@ Musika: 4 \u00d7 1 Musika: 4 \u00d7 2 Musika: 4 \u00d7 2 (txandakatu) - Musika: berriki entzundakoak Ezin izan da ekualizadorea ireki. - Musika ordenagailutik gailura kopiatzeko erabili USB kablea. - Gogoko gisa markatutako abestiak hemen agertuko dira. Ez dago berriki entzundako abestirik Berriki entzun dituzun abestiak hemen agertuko dira. Ez dago abestirik erreprodukzio-zerrendan @@ -151,14 +134,6 @@ 10+ abesti 5+ album "Beste batzuk" - Erakutsi artista guztiak - Erakutsi album guztiak - Erakutsi abesti guztiak - Erakutsi erreprodukzio-zerrenda guztiak - \"%s\" artista guztiak - \"%s\" album guztiak - \"%s\" abesti guztiak - \"%s\" erreprodukzio-zerrenda guztiak %1$s %2$s Musika erreprodukzioa diff --git a/res/values-fa/plurals.xml b/res/values-fa/plurals.xml index 6cc9ae71a836ccc8b0da7b7a9d5305c0650399e4..5b82b7d8f996fc9addff97199da65bc74c30cda8 100644 --- a/res/values-fa/plurals.xml +++ b/res/values-fa/plurals.xml @@ -16,10 +16,6 @@ limitations under the License. --> - - %d هنرمند - %d هنرمند - %d آلبوم %d آلبوم @@ -28,10 +24,6 @@ %d آهنگ %d آهنگ - - %d سبک - %d سبک - %dساعت %dساعت @@ -52,10 +44,6 @@ %d آهنگ به صف پخش اضافه شد. %d آهنگ به صف پخش اضافه شد. - - %d آهنگ به علاقه‌مندی‌ها اضافه شد. - %d آهنگ به علاقه‌مندی‌ها اضافه شد. - %d آهنگ حذف شد. %d آهنگ حذف شد. diff --git a/res/values-fa/strings.xml b/res/values-fa/strings.xml index 5afbdf94dfc472e3cff213682ac0f2c5528e166f..64d7f104ec3f873e1910e7a9545e72ba2ce30f17 100644 --- a/res/values-fa/strings.xml +++ b/res/values-fa/strings.xml @@ -18,16 +18,12 @@ --> موسیقی - اخیر هنرمندان آلبوم‌ها آهنگ‌ها لیست‌های پخش - ژانرها - درحال پخش صف پخش آلبوم‌ها - آهنگ‌های عالی تمام آهنگ‌ها تنظیمات تصادفی @@ -38,16 +34,13 @@ آهنگ‌های عالی تصادفی اخیرا پخش‌شده تصادفی آخرین افزوده‌شده تصادفی - پخش همه مرتب‌سازی براساس پاک کردن لیست - پاک کردن لیست اخیر پاک کردن صف ذخیره صف در لیست پخش اکولایزر افزودن به لیست پخش افزودن به صف - حذف از لیست اخیر حذف از صف A-Z Z-A @@ -55,8 +48,6 @@ آلبوم سال مدت زمان - تاریخ اضافه شدن - لیست آهنگ تعداد آهنگ‌ها تعداد آلبوم‌ها نام فایل @@ -77,9 +68,7 @@ این کار برگشت‌پذیر نیست این کار تصاویر ذخیره شده را برای همیشه حذف می‌کند انتخاب عکس از گالری - جستجوی گوگل استفاده از عکس پیش‌فرض - استفاده از عکس قبلی پخش پخش بعدی پخش آلبوم @@ -101,10 +90,7 @@ تکرار تکرار همه تکرار یکی - باز کردن صف - مرور موسیقی \'%s\' به‌عنوان صدای زنگ تنظیم شد - نام لیست پخش تغییر کرد ذخیره‌سازی حذف حافظه نهان حذف همه تصاویر ذخیره شده @@ -117,10 +103,7 @@ موسیقی: ۴ \u00d7 ۱ موسیقی: ۴ \u00d7 ۲ موسیقی: ۴ \u00d7 ۲ (جایگزین) - موسیقی: شنیده‎شده اخیر اکولایزر باز نمی‌شود. - برای کپی موسیقی از کامپیوتر به دستگاهتان، از یک کابل USB استفاده کنید. - آهنگ‌هایی علامت‌گذاری‌شده به عنوان موردعلاقه در اینجا نشان داده می‌شوند. آهنگ اخیری وجود ندارد آهنگ‌های تازه شنیده شده در اینجا نمایش داده خواهند شد. هیچ آهنگی در لیست پخش نیست @@ -151,13 +134,5 @@ +۱۰ آهنگ +۵ آلبوم "دیگر" - نمایش همه هنرمندان - نمایش همه آلبوم‌ها - نمایش همه آهنگ‌ها - نمایش همه لیست‌های پخش - تمام «%s» هنرمند - تمام «%s» آلبوم - تمام «%s» آهنگ - تمام «%s» لیست پخش %1$s %2$s diff --git a/res/values-fi/plurals.xml b/res/values-fi/plurals.xml index c3c5b0f985e475e74a141e9b2b3c5c5600265857..3acc7882990d49f47413044a9d73e9ea3aacdac6 100644 --- a/res/values-fi/plurals.xml +++ b/res/values-fi/plurals.xml @@ -16,10 +16,6 @@ limitations under the License. --> - - %d esittäjä - %d esittäjää - %d albumi %d albumia @@ -28,10 +24,6 @@ %d kappale %d kappaletta - - %d tyylilaji - %d tyylilajia - %dt %dt @@ -52,10 +44,6 @@ %d kappale lisätty jonoon. %d kappaletta lisätty jonoon. - - %d kappale lisätty suosikkeihin. - %d kappaletta lisätty suosikkeihin. - %d kappale poistettiin. %d kappaletta poistettiin. diff --git a/res/values-fi/strings.xml b/res/values-fi/strings.xml index e6031e459eae5b6ca59c409afc664f634ec4461f..d4b1c1b2ae7a39e15ffa2c7264e759fa40019716 100644 --- a/res/values-fi/strings.xml +++ b/res/values-fi/strings.xml @@ -18,16 +18,12 @@ --> Musiikki - Äskettäin kuunnellut Esittäjät Albumit Kappaleet Soittolistat - Tyylilajit - Nyt soi Toistojono Albumi - Suosituimmat kappaleet Kaikki kappaleet Asetukset Sekoita @@ -38,16 +34,13 @@ Sekoita suosituimmat kappaleet Sekoita äskettäin kuunnellut Sekoita viimeksi lisätyt - Toista kaikki Lajittelujärjestys Tyhjennä lista - Tyhjennä äskettäin kuunnellut Tyhjennä jono Tallenna jono soittolistalle Taajuuskorjain Lisää soittolistalle Lisää jonoon - Poista äskettäin kuunnelluista Poista jonosta A-Ö Ö-A @@ -55,8 +48,6 @@ Albumi Vuosi Pituus - Lisäyspäivämäärä - Kappalelista Kappaleiden määrä Albumeiden määrä Tiedostonimi @@ -77,9 +68,7 @@ Tätä ei voi perua Kaikki välimuistissa olevat kuvat poistetaan pysyvästi Valitse valokuva galleriasta - Google-haku Käytä oletusvalokuvaa - Käytä vanhaa valokuvaa Toista Toista seuraava Toista albumi @@ -101,10 +90,7 @@ Uudelleentoisto Uudelleentoista kaikki Uudelleentoista yksi - Avaa jono - Selaa musiikkia \'%s\' asetettu soittoääneksi - Soittolista nimetty uudelleen Tallennustila Poista välimuisti Poista kaikki välimuistissa olevat kuvat @@ -118,10 +104,7 @@ Musiikki: 4 \u00d7 1 Musiikki: 4 \u00d7 2 Musiikki: 4 \u00d7 2 (vaihtoehtoinen) - Musiikki: äskettäin kuunneltu Taajuuskorjainta ei voitu avata. - Kopioi musiikkia tietokoneelta laitteeseen käyttämällä USB-kaapelia. - Suosikeiksi merkitsemäsi kappaleet näkyvät tässä. Ei äskettäin kuunneltuja Kuuntelemasi albumit näkyvät tässä. Ei kappaleita soittolistalla @@ -152,14 +135,6 @@ Yli 10 kappaletta Yli 5 albumia "Muut" - Näytä kaikki esittäjät - Näytä kaikki albumit - Näytä kaikki kappaleet - Näytä kaikki soittolistat - Kaikki \"%s\" esittäjää - Kaikki \"%s\" albumia - Kaikki \"%s\" kappaletta - Kaikki \"%s\" soittolistaa %1$s %2$s Musiikin toisto diff --git a/res/values-fr/plurals.xml b/res/values-fr/plurals.xml index c4a3ba291170d01193bf0a5b2051100127f316e2..ada559855a7dd1ecc832f34c8b27daa7add02e08 100644 --- a/res/values-fr/plurals.xml +++ b/res/values-fr/plurals.xml @@ -16,10 +16,6 @@ limitations under the License. --> - - %d artiste - %d artistes - %d album %d albums @@ -28,10 +24,6 @@ %d titre %d titres - - %d genre - %d genres - %dh %dh @@ -52,10 +44,6 @@ %d titre ajouté à la file d\'attente. %d titres ajoutés à la file d\'attente. - - %d titre ajouté aux favoris. - %d titres ajoutés aux favoris. - %d titre a été supprimé. %d titres ont été supprimés. diff --git a/res/values-fr/strings.xml b/res/values-fr/strings.xml index 5424e8806f8dcf66ce8463b85d7b818fdf7c1af9..8c2506efbd5f4c2122ca783591b41d34472ccd73 100644 --- a/res/values-fr/strings.xml +++ b/res/values-fr/strings.xml @@ -18,16 +18,12 @@ --> Musique - Récents Artistes Albums Titres Listes de lecture - Genres - Lecture en cours Lire la file d\'attente Albums - Titres populaires Tous les titres Paramètres Lecture aléatoire @@ -38,16 +34,13 @@ Lecture aléatoire des titres les plus populaires Lecture aléatoire des titres récemment joués Lecture aléatoire des derniers titres ajoutés - Tout lire Trier par Effacer la liste - Effacer les récents Effacer la liste d\'attente Enregistrer la file d\'attente dans la liste de lecture Égaliseur Ajouter à liste de lecture Ajouter à la file d\'attente - Supprimer des récents Supprimer de la file d\'attente A-Z Z-A @@ -55,8 +48,6 @@ Album Année Durée - Date d\'ajout - Liste des pistes Nombre de titres Nombre d\'albums Nom de fichier @@ -77,9 +68,7 @@ Cette action ne peut pas être annulée Cette action supprimera définitivement le cache des images Choisir une photo de la Galerie - Recherche Google Utiliser la photo par défaut - Utiliser l\'ancienne photo Lire Lire le suivant Lire l\'album @@ -101,10 +90,7 @@ Répéter Tout répéter Répéter un - Ouvrir la file d\'attente - Parcourir la musique \'%s\' défini comme sonnerie - Liste de lecture renommée Stockage Supprimer le cache Supprimer toutes les images du cache @@ -118,10 +104,7 @@ Musique : 4 \u00d7 1 Musique : 4 \u00d7 2 Musique : 4 \u00d7 2 (alterné) - Musique : récemment écouté L\'égaliseur ne peut pas être ouvert. - Utilisez un câble USB pour copier de la musique depuis votre ordinateur vers votre appareil. - Vos titres favoris seront affichés ici. Aucun titre récent Les titres écoutés récemment seront affichés ici. Aucun titre dans la liste de lecture @@ -152,14 +135,6 @@ Plus de 10 titres Plus de 5 albums "Autres" - Afficher tous les artistes - Afficher tous les albums - Afficher tous les titres - Afficher toutes les listes de lecture - Tous les artistes \"%s\" - Tous les albums \"%s\" - Tous les titres \"%s\" - Toutes les listes de lecture \"%s\" %1$s %2$s Lecture de musique diff --git a/res/values-fy-rNL/plurals.xml b/res/values-fy-rNL/plurals.xml index a41b2b68445c23c40432eea4666711c82cb7073c..925e0f12a9789eb5560d6fc38cfb8a2ffcde578c 100644 --- a/res/values-fy-rNL/plurals.xml +++ b/res/values-fy-rNL/plurals.xml @@ -16,10 +16,6 @@ limitations under the License. --> - - %d artyst - %d artysten - %d album %d albums @@ -28,10 +24,6 @@ %d nûmer %d nûmers - - %d sjenre - %d sjenres - %do %do @@ -52,10 +44,6 @@ %d nûmer tafoege oan wachtrige. %d nûmers tafoege oan wachtrige. - - %d nûmer tafoege oan favoriten. - %d nûmers tafoege oan favoriten. - %d nûmer fuortsmiten. %d nûmers fuortsmiten. diff --git a/res/values-fy-rNL/strings.xml b/res/values-fy-rNL/strings.xml index 750332df53ad9c23e1208309ba3aa6a8b16144f3..3e6039c6046c2078375be054aef94a99fd138e1c 100644 --- a/res/values-fy-rNL/strings.xml +++ b/res/values-fy-rNL/strings.xml @@ -18,16 +18,12 @@ --> Muzyk - Resint Artysten Albums Nûmers Ofspyllisten - Sjenres - Spilet no Wachtrige Albums - Bêste nûmers Alle nûmers Ynstellingen Mjokselje @@ -38,16 +34,13 @@ Bêste nûmers mjokselje Resinte nrs. mjokselje Lêst tafoege mjokselje - Alles ôfspylje Sortearje op List wiskje - Resinte items wiskje Wachtrige wiskje Wachtrige bewarje as ôfspyllist Equalizer Tafoegje oan ôfspyllist Tafoegje oan wachtrige - Fuortsmite út resint Fuortsmite út wachtrige A-Z Z-A @@ -55,8 +48,6 @@ Album Jier Doer - Datum tafoege - Tracklist Oantal nûmers Oantal albums Bestânsnamme @@ -77,9 +68,7 @@ Dit kin net ûngedien makke wurde Hjirmei wurde alle bewarre ôfbyldingen permanint fuortsmiten Selektearje foto út Galerij - Sykje mei Google Standertfoto brûke - Alde foto brûke Ofspylje Folgjende ôfspylje Album ôfspylje @@ -101,10 +90,7 @@ Werhelje Alles werhelje Ien werhelje - Wachtrige iepenje - Muzyk ferkenne \'%s\' ynsteld as beltoan - Namme ôfspyllist wizige Unthâld Buffer wiskje Alle buffere ôfbyldingen fuortsmite @@ -118,10 +104,7 @@ Muzyk: 4 \u00d7 1 Muzyk: 4 \u00d7 2 Muzyk: 4 \u00d7 2 (alternatyf) - Muzyk: resint belústere Kin equalizer net iepenje. - Om muzyk fan jo kompjûter te kopiearjen nei jo apparaat, kinne jo in USB-kabel brûke. - Jo favorite nûmers wurde hjir toand. Gjin resinte nûmers Nûmers dêr\'t jo resint nei lústere hawwe wurde hjir toand. Gjin nûmers yn ôfspyllist @@ -152,14 +135,6 @@ 10+ nûmers 5+ albums "Oare" - Alle artysten toane - Alle albums toane - Alle nûmers toane - Alle ôfspyllisten toane - Alle ‘%s’ artysten - Alle ‘%s’ albums - Alle ‘%s’ nûmers - Alle ‘%s’ ôfspyllisten %1$s %2$s Ofspyljen fan muzyk diff --git a/res/values-gd/plurals.xml b/res/values-gd/plurals.xml index 5b69aa9fa6176fef37c8faa8ad86e7cf9baa3ece..470048f16514f889b91b95df48ba1643b5850b95 100644 --- a/res/values-gd/plurals.xml +++ b/res/values-gd/plurals.xml @@ -16,12 +16,6 @@ limitations under the License. --> - - %d neach-ciùil - %d neach-ciùil - %d luchd-ciùil - %d neach-ciùil - %d albam %d albam @@ -34,12 +28,6 @@ %d òrain %d òran - - %d ghnè - %d ghnè - %d gnèithean - %d gnè - %du %du @@ -70,12 +58,6 @@ Chaidh %d òrain a chur ris a’ chiutha. Chaidh %d òran a chur ris a’ chiutha. - - Chaidh %d òran a chur ris na h-annsachdan. - Chaidh %d òran a chur ris na h-annsachdan. - Chaidh %d òrain a chur ris na h-annsachdan. - Chaidh %d òran a chur ris na h-annsachdan. - Chaidh %d òran a sguabadh às. Chaidh %d òran a sguabadh às. diff --git a/res/values-gd/strings.xml b/res/values-gd/strings.xml index eae2572056c1428f7463475853c27fb7019987a2..c22275ef3173dcd22045fec165f57e1a3bbaa1c3 100644 --- a/res/values-gd/strings.xml +++ b/res/values-gd/strings.xml @@ -15,18 +15,16 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ---> +--> + Ceòl O chionn goirid Luchd-ciùil Albaman Òrain Liostaichean-cluich - Gnèithean - ’Ga chluich an-dràsta Cluich an ciutha Albaman - Brod nan òran A h-uile òran Roghainnean Air thuaiream @@ -36,7 +34,7 @@ Cuir an neach-ciùil air thuaiream Cuir brod nan òran air thuaiream Cuir na chaidh a chluich o chionn goirid air thuaiream - Cuir an fheadhainn a chuir thu ris o chionn goirid air thuaiream + Cuir na chuir thu ris mu dheireadh air thuaiream Cluich na h-uile Seòrsaich a-rèir Falamhaich an liosta @@ -54,12 +52,10 @@ Albam Bliadhna Faid - Cuin a chaidh a chur ris - Liosta nan traca Co mheud òran Co mheud albam Ainm an fhaidhle - Fear mu dheireadh a chuir thu ris + Na chuir thu ris mu dheireadh Air a chluich o chionn goirid Brod nan traca agam Liosta-chluich ùr @@ -71,14 +67,13 @@ Ainm na liosta-chluich A bheil thu airson %s a sguabadh às? A bheil thu airson brod nan traca fhalamhachadh? - A bheil thu airson na chluich thu o chionn goirid fhalamhachadh\? - A bheil thu airson am fear mu dheireadh a chuir thu ris fhalamhachadh? + Am falamhaich thu na chluich thu o chionn goirid? + A bheil thu airson na chuir thu ris mu dheireadh fhalamhachadh? Chan urrainn dhut seo a neo-dhèanamh Sguabaidh seo às na dealbhan gu buan a chaidh a chur san tasgadan Tagh dealbh on ghailearaidh - Lorg Google - Cleachd an dealbh tùsail - Cleachd seann-dealbh + Cleachd an dealbh bunaiteach + Chaidh cead clàradh fuaime a dhiùltadh, cuir an comas e o aplacaid nan “Roghainnean” airson fir-chlis a’ chiùil a chur an comas Cluich Cluich an ath-fhear Cluich an t-albam @@ -100,15 +95,13 @@ Ath-chluich Ath-chluich na h-uile Ath-chluich aonan - Fosgail an ciutha - Rùraich an ceòl - Suidhich “%s” mar sheirm - Chaidh ainm ùr a thoirt air an liosta-chluich + Chaidh “%s” a shuidheachadh mar sheirm Stòras Sguab an tasgadan às Thoir air falbh gach dealbh san tasgadan Coitcheann Seall fir-chlis a’ chiùil + Cuir sgleò air a’ chùlaibh Seall faclan nan òran Airson òrain aig a bheil faidhle srt Crath airson cluich @@ -131,10 +124,10 @@ Cha deach ceòl a lorg Cleachd càball USB airson lethbhreac dhen cheòl air a’ choimpiutair agad a chur air an uidheam agad. Chan eil òran sam bith sa chiutha - Airson òrain a chur ris a’ chiutha chluich, thoir gnogag air clàr-taice nan roghainnean aig òran, albam no neach-ciùil agus tagh “Cuir ris a’ chiutha chluich”. + Airson òrain a chur ris a’ chiutha chluich, thoir gnogag air clàr-taice nan roghainnean aig òran, albam no neach-ciùil agus tagh “Cuir ris a’ chiutha”. Cha ghabh an traca %1$s a chluich Bliadhna neo-aithnichte - Nas lugha na 30 diog + Nas giorra na 30 diog Eadar 30 is 60 diog Eadar mionaid is 2 mhionaid Eadar 2 is 3 mionaidean @@ -150,14 +143,6 @@ Barrachd air 10 òrain Barrachd air 5 albaman "Eile" - Seall a h-uile neach-ciùil - Seall a h-uile albam - Seall a h-uile òran - Seall a h-uile liosta-chluich - A h-uile neach-ciùil “%s” - A h-uile albam “%s” - A h-uile òran “%s” - A h-uile liosta-chluich “%s” %1$s %2$s Cluiche ciùil - \ No newline at end of file + diff --git a/res/values-gl/plurals.xml b/res/values-gl/plurals.xml index e519da91be0a1e30cb1f8bf45dec977c1bd1c77c..2bf3a614d5e5352140fd35daeec67e354292185a 100644 --- a/res/values-gl/plurals.xml +++ b/res/values-gl/plurals.xml @@ -16,10 +16,6 @@ limitations under the License. --> - - %d artista - %d artistas - %d álbum %d álbums @@ -28,10 +24,6 @@ %d canción %d canciones - - %d genero - %d generos - %dh %dh @@ -52,10 +44,6 @@ %d canción añadida á cola de reproducción. %d cancións añadidas á cola de reproducción. - - %d canción añadida a favoritos. - %d cancións añadidas a favoritos. - %d canción foi eliminada. %d cancións foron eliminadas. diff --git a/res/values-gl/strings.xml b/res/values-gl/strings.xml index ac8e2be46f03ec9ace5ed809cff78e1767b766e0..eb12f0b3888cab02248b0e89a0a217569fc43757 100644 --- a/res/values-gl/strings.xml +++ b/res/values-gl/strings.xml @@ -18,16 +18,12 @@ --> Música - Recente Artistas Álbums Cancións Listas de reprodución - Xéneros - Reproducindo Reproducir cola Álbums - Cancións máis escoitadas Todas as cancións Configuración Ao chou @@ -38,16 +34,13 @@ Barallar cancións máis escoitadas Barallar cancións escoitadas ultimamente Barallar as últimas engadidas - Reproducir todo Ordenar por Limpar a lista - Limpar recentes Limpar cola Gardar a cola na lista de reprodución Ecualizador Engadir á lista Engadir á cola - Eliminar de recentes Eliminar da cola A-Z Z-A @@ -55,8 +48,6 @@ Álbum Ano Duración - Data de adición - Lista de pistas Número de cancións Número de álbums Nome do ficheiro @@ -77,9 +68,7 @@ Isto non se pode desfacer Isto eliminará permanentemente as imaxes gardadas na caché Escoller imaxe da Galería - Buscar en Google Utilizar foto predeterminada - Utilizar foto antiga Reproducir Reproducir a seguinte Reproducir o álbum @@ -101,10 +90,7 @@ Repetir Repetir todo Repetir unha - Abrir cola - Explorar música Estabelecer \'%s\' como ton de chamada - Renomeouse a lista de reprodución Almacenamento Eliminar a caché Retirar todas as imaxes da caché @@ -118,10 +104,7 @@ Música: 4 \u00d7 1 Música: 4 \u00d7 2 Música: 4 \u00d7 2 (alternativo) - Música: escoitadas recentemente Non foi posíbel abrir o ecualizador. - Para copiar a música do seu computador ao seu dispositivo, empregue un cable USB. - Aquí aparecerán as cancións que marque como favoritas. Sen cancións recentes Aquí aparecerán as cancións que teña escoitado ultimamente. Sen cancións na lista de reprodución @@ -152,14 +135,6 @@ 10+ cancións 5+ álbums "Outro" - Amosar todos os artistas - Amosar todos os álbums - Amosar todas as cancións - Amosar todas as listas de reprodución - Todos os artistas \"%s\" - Todos os álbums \"%s\" - Todas as cancións \"%s\" - Todas as listas de reprodución \"%s\" %1$s %2$s Reproducir música diff --git a/res/values-gu/plurals.xml b/res/values-gu/plurals.xml index 9c168006ccf9661034f09c55ec58108bce11bbc2..9eede3478c6ed729b6e6bb88b2ee65b5da9be74e 100644 --- a/res/values-gu/plurals.xml +++ b/res/values-gu/plurals.xml @@ -16,10 +16,6 @@ limitations under the License. --> - - %d આર્ટિસ્ટ - %d આર્ટિસ્ટો - %d આલ્બમ %d આલ્બમ્સ @@ -28,10 +24,6 @@ %d ગીત %d ગીતો - - %d ઝાનર - %d ઝાનરો - %d કલાક %d કલાક @@ -52,10 +44,6 @@ %d હરોળમાં ગીત ઉમેરાયું. %d હરોળમાં ગીતો ઉમેર્યા. - - %d ફેવરિટમાં ગીત ઉમેરાણું. - %d ફેવરિટમાં ગીતો ઉમેરાણાં. - %d ગીત રદ કરવામાં આવ્યું. %d ગીતો હટાવવામાં આવ્યાં હતાં. diff --git a/res/values-gu/strings.xml b/res/values-gu/strings.xml index fcea3fb87a5ea242b392b6fde70356fb43d12a76..2af7fd71830ba5b83d1e009233a9a50d6342f502 100644 --- a/res/values-gu/strings.xml +++ b/res/values-gu/strings.xml @@ -18,16 +18,12 @@ --> સંગીત - તાજેતરનું કલાકારો આલબ્મ્સ ગીતો પ્લેસૂચિઓ - ઝૉનરાં - હાલ પ્લે થાય છે હરોળ પ્લે કરો આલબ્મ્સ - ટોપ ગીતો તમામ ગીતો સેટિંગ્સ પીસો @@ -38,16 +34,13 @@ ટોપ ટ્રૅક્સ શફલ કરો તાજેતર પ્લે કરેલ શફલ કરો છેલ્લું ઉમેરેલ શફલ કરો - તમામ પ્લે કરો ના દ્વારા ગોઠવો સૂચિ સાફ કરો - તાજેતરના સાફ કરો હરોળ સાફ કરો હરોળને પ્લેલિસ્ટમાં સેવ કરો ઇક્વીલાઇઝર પ્લેસૂચિ ઉમેરો હરોળમાં ઍડ કરો - રિસન્ટમાંથી કાઢી નાંખો હરોળમાંથી કાઢી નાંખો A-Z Z-A @@ -55,8 +48,6 @@ આલ્બમ વર્ષ અવધિ - તારીખ ઉમેરી - ટ્રૅક સૂચી ગીતોની સંખ્યા આલ્બમની સંખ્યા ફાઇલનું નામ @@ -77,9 +68,7 @@ આ ક્રિયા પૂર્વવત થઈ શકે નહીં. આનાથી કૅશ કરેલ ઇમેજ એન્ટ્રીઓ કાયમી ભૂંસાઇ જશે ગૅલેરીમાંથી ફોટા પસંદ કરો - ગૂગલ સર્ચ ડિફૉલ્ટ ફોટો વાપરો - જૂનો ફોટો વાપરો ચલાવો આગામી પ્લે કરો આલ્બમ પ્લે કરો @@ -101,10 +90,7 @@ પુનરાવર્તન તમામ પુનરાવર્તિત કરો એક પુનરાવર્તિત કરો - હરોળ ખોલો - મ્યુઝિક બ્રાઉઝ કરો \'%s\' રિંગટોન તરીકે સેટ કરો - પ્લેલિસ્ટનું પુન:નામકરણ કર્યું સ્ટોરેજ કૅશ રદ કરો તમામ કૅશ ઇમેજ કાઢી નાંખો @@ -117,10 +103,7 @@ મ્યુઝિક: 4 \u00d7 1 મ્યુઝિક: 4 \u00d7 2 મ્યુઝિક: 4 \u00d7 2 (વૈકલ્પિક) - મ્યુઝિક: તાજેતરમાં સાંભળેલ ઇક્વલાઇઝર ખોલી શકાયું નહીં. - તમારા કમ્પ્યુટરમાંથી તમારા ડિવાઇસ પર મ્યુઝિક કૉપિ કરવા USB કેબલનો ઉપયોગ કરો. - ફેવરિટ તરીકે તમે અંકિત કરેલ ગીતો અહીં દર્શાવવામાં આવશે. કોઇ તાજેતરનાં ગીતો નહીં તમે તાજેતરમાં સાંભળેલ ગીતો અહીં દેખાશે. પ્લેલિસ્ટમાં કોઇ ગીતો નહીં @@ -151,13 +134,5 @@ 10+ ગીતો 5+ આલ્બોમો ""અન્ય"" - તમામ આર્ટિસ્ટો દર્શાવો - તમામ આલ્બમો દર્શાવો - તમામ ગીતો દર્શાવો - તમામ પ્લેલિસ્ટો દર્શાવો - તમામ \"%s\" આર્ટિસ્ટો - તમામ \"%s\" આલ્બમો - તમામ \"%s\" ગીતો - તમામ \"%s\" પ્લેલિસ્ટો %1$s %2$s diff --git a/res/values-hi/plurals.xml b/res/values-hi/plurals.xml index 8c9d0631b8e298badb6b2cc521a90dd5d3ed9790..6b6cc41fed43a095e38fbda1f47f1df79a6256d0 100644 --- a/res/values-hi/plurals.xml +++ b/res/values-hi/plurals.xml @@ -16,10 +16,6 @@ limitations under the License. --> - - %d कलाकार - %d कलाकार - %d एल्बम %d एल्बम @@ -28,10 +24,6 @@ %d गाना %d गाने - - %d शैली - %d शैलियाँ - %dघं %dघं @@ -52,10 +44,6 @@ %d गाना कतार में जोड़ा गया। %d गाने कतार में जोड़े गए। - - %d गाना पसंदों में जोड़ा गया। - %d गाने पसंदों में जोड़े गए। - %d गाना हटाया गया। %dगाने हटाए गए। diff --git a/res/values-hi/strings.xml b/res/values-hi/strings.xml index 59a7e2cdf9d7fbf1b6e34c9b78129b718d668ee2..f11339270fb6e1ddfadca6ab43273cf86d89201e 100644 --- a/res/values-hi/strings.xml +++ b/res/values-hi/strings.xml @@ -18,16 +18,12 @@ --> संगील - हाल के कलाकार एल्बम गाने प्लेसूचियाँ - शैलियाँ - इस समय बज रहा है प्ले कतार एल्बम - शीर्ष गाने सब गाने सेटिंग शफ़ल करें @@ -38,16 +34,13 @@ शीर्ष ट्रैकों को शफ़ल करें हाल के प्ले किए को शफ़ल करें अंतिम बार जोड़े गए को शफ़ल करें - सबको बजाएँ इसके अनुसार छाँटें सूची को साफ़ करें - हाल को साफ़ करें कतार को साफ़ करें कतार को प्लेसूची में सहेजें तुल्यकारक प्लेसूची में जोड़ें कतार में जोड़ें - हाल से हटाएँ कतार से हटाएँ अ-ह ह-अ @@ -55,8 +48,6 @@ एल्बम वर्ष अवधि - जोड़ने की तिथि - ट्रैक सूची गानों की गिनती एल्बमों की संख्या फ़ाइल का नाम @@ -77,9 +68,7 @@ इसे पलटा नहीं जा सकेगा यह कैश की गई छवि प्रविष्टियों को हमेशा के लिए मिटा देगा गैलरी से फ़ोटो चुनें - गूगल खोज डिफ़ॉल्ट फ़ोटो का उपयोग करें - पुरानी फ़ोटो का उपयोग करें बजाएँ अगला बजाएँ एल्बम को चलाएँ @@ -101,10 +90,7 @@ दुहराएँ सबको दुहराएँ एक को दुहराएँ - कतार खोलें - संगीत को ब्राउज़ करें \'%s\' को रिंगटोन के रूप में सेट करें - प्लेसूची को नया नाम दिया गया भंडारण कैश को हटाएँ कैश की गई सभी छवियों को निकालें @@ -117,10 +103,7 @@ संगीत: 4 \u00d7 1 संगीत: 4 \u00d7 2 संगीत: 4 \u00d7 2 (एक को छोड़कर एक) - संगीत: हाल में सुना गया तुल्यकारक को खोला नहीं जा सका। - अपने कंप्यूटर से अपने उपकरण में संगीत को कॉपी करने के लिए यूएसबी केबल का उपयोग करें। - आप जिन गानों को पसंदीदा के रूप में चिह्नित करेंगे, वे यहाँ दिखाई देंगे। हाल वाले के गाने नहीं हैं आपने हाल में जो गाने सुने हैं, वे यहाँ दिखाई देंगे। प्लेसूची में कोई गाने नहीं हैं @@ -151,13 +134,5 @@ 10+ गाने 5+ गाने "अन्य" - सब कलाकारों को दिखाएँ - सब एल्बम दिखाएँ - सब गाने दिखाएँ - सब प्लेसूचियाँ दिखाएँ - सभी \"%s\" कलाकार - सभी \"%s\" एल्बम - सभी \"%s\" गाने - सभी \"%s\" प्लेसूचियाँ %1$s %2$s diff --git a/res/values-hr/plurals.xml b/res/values-hr/plurals.xml index eb018bca4b3c42b1d1bc147eecab4d5384a23a79..dbdbc0850594b8e01084c28da49ac567c75fcccb 100644 --- a/res/values-hr/plurals.xml +++ b/res/values-hr/plurals.xml @@ -16,11 +16,6 @@ limitations under the License. --> - - %d autor - %d autora - %d autora - %d album %d albuma @@ -31,11 +26,6 @@ %d pjesme %d pjesama - - %d žanr - %d žanra - %d žanra - %dh %dh @@ -61,11 +51,6 @@ %d pjesme dodane u red. %d pjesama dodano u red. - - %d pjesma dodana u favorite. - %d pjesme dodane u favorite. - %d pjesama dodano u favorite. - %d pjesma je izbrisana. %d pjesme su izbrisane. diff --git a/res/values-hr/strings.xml b/res/values-hr/strings.xml index b8b28b3c1de259b238f2600e02224c610dd79b73..b93caafce14238afb130b374cf6adca37afd0084 100644 --- a/res/values-hr/strings.xml +++ b/res/values-hr/strings.xml @@ -18,16 +18,12 @@ --> Glazba - Nedavno Umjetnici Albumi Pjesme Playliste - Žanrovi - Sada svira Za reprodukciju Albumi - Top pjesme Sve pjesme Postavke Miješaj @@ -38,16 +34,13 @@ Miješanje najizvođenijih pjesama Miješaj nedavno svirane Miješaj zadnje dodane - Sviraj sve Sortiraj po Očisti popis - Očisti nedavno Očisti red Spremi red čekanja u playlistu Ekvalizer Dodaj u playlistu Dodaj u red - Ukloni iz nedavnih Ukloni iz reda A-Z Z-A @@ -55,8 +48,6 @@ Album Godina Dužina - Dodano datuma - Popis pjesama Broj pjesama Broj albuma Naziv datoteke @@ -77,9 +68,7 @@ Ovo se ne može poništiti Ovo će trajno izbrisati podatke spremljenih slika Odaberi sliku iz galerije - Google pretraga Koristi zadanu sliku - Koristi staru sliku Sviraj Sviraj sljedeću Reproduciraj album @@ -101,10 +90,7 @@ Ponovi Ponovi sve Ponovi jedan - Otvori red - Pretraži glazbu \'%s\' postavljeno kao zvuk zvona - Playlista preimenovana Pohrana Obriši predmemoriju Obriši sve cachirane slike @@ -117,10 +103,7 @@ Glazba: 4 \u00d7 1 Glazba: 4 \u00d7 2 Glazba: 4 \u00d7 2 (rezervna) - Glazba: nedavno slušano Ekvalizer se ne može otvoriti. - Za kopiranje glazbe s računala na uređaj, koristite USB kabel. - Pjesme koje označite kao favorite biti će prikazane ovdje. Nema nedavnih pjesama Pjesme koje ste slušali će se pojaviti ovdje. Nema pjesama u popisu za reproduciranje @@ -151,13 +134,5 @@ 10 + pjesama 5 + albuma "Ostalo" - Pokaži sve autore - Pokaži sve albume - Pokaži sve pjesme - Pokaži sve popise - Sve \"%s\" umjetnika - Svi \"%s\" albuma - Sve \"%s\" pjesme - Svi \"%s\" popisi za reproduciranje %1$s %2$s diff --git a/res/values-hu/plurals.xml b/res/values-hu/plurals.xml index ff3c2ce644b455c7bec619df00c481bb3a3775f4..e1a10633b60e3949cdb59cf417520af924ff6250 100644 --- a/res/values-hu/plurals.xml +++ b/res/values-hu/plurals.xml @@ -16,10 +16,6 @@ limitations under the License. --> - - %d előadó - %d előadó - %d album %d album @@ -28,10 +24,6 @@ %d dal %d dal - - %d műfaj - %d műfaj - %dó %dó @@ -52,10 +44,6 @@ %d dal hozzáadva a lejátszási sorhoz. %d dal hozzáadva a lejátszási sorhoz. - - %d dal hozzáadva a kedvencekhez. - %d dal hozzáadva a kedvencekhez. - %d dal törölve. %d dal törölve. diff --git a/res/values-hu/strings.xml b/res/values-hu/strings.xml index 54745cebb6e97b6035f2cf7e5f9105b44f809932..0842a2262e3ec9fd7f093be8d4cf3b37426245eb 100644 --- a/res/values-hu/strings.xml +++ b/res/values-hu/strings.xml @@ -18,16 +18,12 @@ --> Zene - Előzmények Előadók Albumok Dalok Lejátszási listák - Műfajok - Most hallható Lejátszási sor lejátszása Albumok - Legtöbbet hallgatottak Összes zeneszám Beállítások Véletlenszerű @@ -38,16 +34,13 @@ Véletlen kedvenc számok Véletlen nemrég játszott Véletlen utoljára hozzáadott - Összes lejátszása Rendezés Lista törlése - Előzmények törlése Lejátszási sor törlése Várólista lista mentése Hangszínszabályzó Hozzáadás a lejátszási lista Hozzáadás a lejátszási sorhoz - Törlés az előzményekből Törlés a lejátszási sorból A-Z Z-A @@ -55,8 +48,6 @@ Album Év Hossz - Hozzáadás dátuma - Dalok listája Dalok száma Albumok száma Fájlnév @@ -77,9 +68,8 @@ Ezt nem lehet visszavonni Ezzel végleg törli a gyorsítótárazott képeket Kép kiválasztása a Galériából - Google keresés Alapértelmezett kép használata - Régi kép használata + Nincs jogosultság az audiófelvételhez, engedélyezze a Beállitásokban, hogy használhassa a zenei vizualizációt. Lejátszás Következő lejátszása Album lejátszása @@ -101,10 +91,7 @@ Ismétlés Összes ismétlése Egy dal ismétlése - Lejátszási sor megnyitása - Zene böngészése \"%s\" beállítva csengőhangként - Lejátszási lista átnevezve Tárhely Gyorsítótár ürítése Minden gyorsítótárazott kép eltávolítása @@ -118,10 +105,7 @@ Zene: 4 \u00d7 1 Zene: 4 \u00d7 2 Zene: 4 \u00d7 2 (alternatív) - Zene: nemrégiben hallgatott A hangszínszabályzót nem lehet megnyitni. - Számítógépről történő zene másoláshoz használjon USB kábelt. - Itt a kedvencként megjelölt dalok fognak megjelenni. Nincsenek előzmények Itt a nemrégiben hallgatott zenéi fognak megjelenni. Nincs dal a lejátszási listán @@ -152,14 +136,6 @@ 10+ dal 5+ album "Egyéb" - Összes előadó megjelenítése - Összes album megjelenítése - Összes dal megjelenítése - Összes lejátszási lista megjelenítése - Összes \"%s\" előadó - Összes \"%s\" album - Összes \"%s\" dal - Összes \"%s\" lejátszási lista %1$s %2$s Zenelejátszás diff --git a/res/values-in/plurals.xml b/res/values-in/plurals.xml index ecd97a01738ee86d22147c21a08dc1be162b8198..498f2b26a3335fb3a27668088ec2f50a01a55d45 100644 --- a/res/values-in/plurals.xml +++ b/res/values-in/plurals.xml @@ -16,18 +16,12 @@ limitations under the License. --> - - %d artis - %d album %d lagu - - %d genre - %dj @@ -43,9 +37,6 @@ %d lagu telah ditambahkan ke antrean. - - %d lagu telah ditambahkan ke favorit. - %d lagu telah dihapus. diff --git a/res/values-in/strings.xml b/res/values-in/strings.xml index 97267a54dcb6c73c37ea6bf0c493c95b8c0fffed..cc098eafdedb69b426fb4067c3b8ad0a83f5445f 100644 --- a/res/values-in/strings.xml +++ b/res/values-in/strings.xml @@ -18,16 +18,12 @@ --> Musik - Terbaru Artis Album Lagu Daftar Putar - Aliran - Sedang diputar Putar daftar antrean Album - Lagu Top Semua Lagu Pengaturan Acak @@ -38,16 +34,13 @@ Putar acak lagu teratas Putar acak yang terakhir diputar Putar acak terakhir ditambahkan - Putar semua Urut berdasarkan Hapus daftar - Hapus yang terbaru Bersihkan antrean Simpan antrean ke daftar putar Equalizer Tambahkan ke daftar putar Tambahkan ke antrean - Hapus dari yang terakhir Hapus dari antrean A-Z Z-A @@ -55,8 +48,6 @@ Album Tahun Durasi - Tanggal ditambahkan - Daftar lagu Jumlah lagu Jumlah album Nama berkas @@ -77,9 +68,7 @@ Ini tidak dapat diurungkan Ini akan menghapus cache gambar secara permanen Pilih foto dari Galeri - Pencarian Google Gunakan foto bawaan - Gunakan foto lama Putar Putar selanjutnya Putar album @@ -101,10 +90,7 @@ Ulang Ulangi semua Ulangi sekali - Buka antrean - Telusuri musik \'%s\' dijadikan sebagai nada dering - Nama daftar putar diganti Penyimpanan Hapus cache Hapus semua cache gambar @@ -117,10 +103,7 @@ Musik: 4 \u00d7 1 Musik: 4 \u00d7 2 Musik: 4 \u00d7 2 (alternatif) - Musik: baru saja didengarkan Equalizer tidak dapat dibuka. - Untuk menyalin musik dari komputer ke perangkat Anda, gunakan kabel USB. - Lagu-lagu yang anda tandai sebagai favorit akan ditampilkan di sini. Tidak ada lagu terbaru Lagu yang Anda dengarkan baru-baru ini akan muncul di sini. Tidak ada lagu dalam daftar putar @@ -151,14 +134,6 @@ 10+ lagu 5+ album "Lain-lain" - Tampilkan semua artis - Tampilkan semua album - Tampilkan semua lagu - Tampilkan semua daftar putar - Semua \"%s\" artis - Semua \"%s\" album - Semua \"%s\" lagu - Semua \"%s\" daftar putar %1$s %2$s Pemutaran musik diff --git a/res/values-is/strings.xml b/res/values-is/strings.xml index dd65aca9cdca33150bef12decaa21c2f91824cf4..5b11a6d39038b7c09724c8570f9efb14feaf4e86 100644 --- a/res/values-is/strings.xml +++ b/res/values-is/strings.xml @@ -28,8 +28,4 @@ Til að bæta lögum í spilunarbiðröðina þína, ýttu þá á valmyndina á lagi, hljómplötu eða flytjanda og veldu \"Bæta í biðröð\". Get ekki spilað lagið %1$s 5+ hljómplötur - Birta alla flytjendur - Birta allar hljómplötur - Allir \"%s\" flytjendur - Allar \"%s\" hljómplötur diff --git a/res/values-it/plurals.xml b/res/values-it/plurals.xml index a7bb2babdda1402d6ede297fe340892a8c75ad48..fe1cd4d2229310c6189fc725399e796c418b61f8 100644 --- a/res/values-it/plurals.xml +++ b/res/values-it/plurals.xml @@ -16,10 +16,6 @@ limitations under the License. --> - - %d artista - %d artisti - %d album %d album @@ -28,10 +24,6 @@ %d canzone %d canzoni - - %d genere - %d generi - %dh %dh @@ -52,10 +44,6 @@ %d canzone aggiunta alla coda. %d canzoni aggiunte alla coda. - - %d canzone aggiunta ai preferiti. - %d canzoni aggiunte ai preferiti. - %d canzone eliminata. %d canzoni eliminate. diff --git a/res/values-it/strings.xml b/res/values-it/strings.xml index 8407b4ad85185648f7d4fc27194984c27cb95b47..f31253457ee0ef39836f72df24b75d17adc1a7d1 100644 --- a/res/values-it/strings.xml +++ b/res/values-it/strings.xml @@ -17,16 +17,12 @@ limitations under the License. --> Musica - Recente Artisti Album Canzoni Playlist - Generi - In riproduzione Coda di riproduzione Album - Canzoni preferite Tutte le canzoni Impostazioni Riproduzione casuale @@ -37,16 +33,13 @@ Riproduzione casuale delle canzoni più ascoltate Riproduzione casuale delle canzoni più recenti Riproduzione casuale nuove canzoni - Riproduci tutto Ordina per Elimina lista - Elimina recenti Elimina coda Salva coda su playlist Equalizzatore Aggiungi alla playlist Aggiungi alla coda - Rimuovi da recenti Rimuovi dalla coda A-Z Z-A @@ -54,8 +47,6 @@ Album Anno Durata - Data aggiunta - Elenco brani Numero canzoni Numero album Nome file @@ -76,9 +67,8 @@ Quest\'azione non può essere annullata Le immagini memorizzate nella cache verranno eliminate permanentemente Scegli foto dalla galleria - Ricerca Google Usa foto predefinita - Usa foto vecchia + L\'accesso al microfono è stato negato, abilitalo dall\'app Impostazioni per attivare il visualizzatore musicale Riproduci Riproduci dopo Riproduci album @@ -100,10 +90,7 @@ Ripeti Ripeti tutto Ripeti singolo - Apri coda - Sfoglia musica \'%s\' impostata come suoneria - Playlist rinominata Archivio Cancella cache Rimuovi immagini memorizzate in cache @@ -117,10 +104,7 @@ Musica: 4 \u00d7 1 Musica: 4 \u00d7 2 Musica: 4 \u00d7 2 (alternativo) - Musica: ascoltati recentemente L\'equalizzazione non può essere aperto. - Per copiare musica dal tuo computer al tuo dispositivo, utilizza un cavo USB. - Le canzoni segnate come preferite saranno mostrate qui. Nessuna canzone recente Le canzoni che hai ascoltato recentemente saranno mostrate qui. Nessuna canzone nella playlist @@ -151,14 +135,6 @@ 10+ canzoni 5+ album "Altro" - Visualizza tutti gli artisti - Visualizza tutti gli album - Visualizza tutte le canzoni - Visualizza tutte le playlist - Tutti gli artisti \"%s\" - Tutti gli album \"%s\" - Tutte le canzoni \"%s\" - Tutte le playlist \"%s\" %1$s %2$s Riproduzione musicale \ No newline at end of file diff --git a/res/values-iw/plurals.xml b/res/values-iw/plurals.xml index 07b2349363a095e08ab164c8d1e8027c08763c17..7d85f9cd58a45411231064375120bb51d7ceeb4a 100644 --- a/res/values-iw/plurals.xml +++ b/res/values-iw/plurals.xml @@ -16,12 +16,6 @@ limitations under the License. --> - - אמן %d - %d אמנים - %d אמנים - %d אמנים - אלבום %d %d אלבומים @@ -34,12 +28,6 @@ %d שירים %d שירים - - ז\'אנר %d - %d ז\'אנרים - %d ז\'אנרים - %d ז\'אנרים - ש\' %d %d ש\' @@ -70,12 +58,6 @@ %d שירים נוספו לתור ההשמעה. %d שירים נוספו לתור ההשמעה. - - שיר %d נוסף למועדפים. - %d שירים נוספו למועדפים. - %d שירים נוספו למועדפים. - %d שירים נוספו למועדפים. - שיר %d נמחק. %d שירים נמחקו. diff --git a/res/values-iw/strings.xml b/res/values-iw/strings.xml index f1ed21c40395406cc8c0cbdffdda39f0f7ec4c43..217193a69a82d074919cd92091be8a18e3d35a4f 100644 --- a/res/values-iw/strings.xml +++ b/res/values-iw/strings.xml @@ -18,16 +18,12 @@ --> מוזיקה - אחרונים אמנים אלבומים שירים רשימות השמעה - ז\'אנרים - מנגן כעת תור השמעה אלבומים - שירים מובילים כל השירים הגדרות ערבב @@ -38,16 +34,13 @@ ערבב רצועות מובילות ערבב שירים שהושמעו לאחרונה ערבב שירים שנוספו לאחרונה - נגן הכל מיין לפי נקה רשימה - נקה רשימת אחרונים נקה את התור שמור את התור לרשימת השמעה אקולייזר הוסף לרשימת השמעה הוסף לתור - הסר מרשימת האחרונים הסר מהתור א-ת / A-Z ת-א / Z-A @@ -55,8 +48,6 @@ אלבום שנה משך - תאריך הוספה - רשימת רצועות מספר שירים מספר אלבומים שם קובץ @@ -77,9 +68,7 @@ פעולה זו אינה ניתנת לביטול פעולה זו תמחק לתמיד את התמונות שבמטמון בחר תמונה מהגלריה - חיפוש Google השתמש בתמונת ברירת מחדל - השתמש בתמונה ישנה נגן נגן את הבא נגן אלבום @@ -101,10 +90,7 @@ חזור חזור על הכול חזור על נוכחי - פתח את תור ההשמעה - הצג מוזיקה \"%s\" נקבע כרינגטון - שונה שם רשימת ההשמעה אחסון מחק מטמון מסיר את כל התמונות שבמטמון @@ -117,10 +103,7 @@ מוזיקה: 4 \u00d7 1 מוזיקה: 4 \u00d7 2 מוזיקה: 4 \u00d7 2 (חלופי) - מוזיקה: הושמעו לאחרונה האקולייזר לא הצליח להיפתח. - כדי להעתיק מוזיקה מהמחשב למכשיר השתמש בכבל USB. - שירים שסומנו כמועדפים יוצגו כאן. אין שירים אחרונים שירים שהאזנת להם לאחרונה יופיעו כאן. אין שירים ברשימת ההשמעה @@ -151,14 +134,6 @@ 10+ שירים 5+ אלבומים "אחר" - הצג את כל האמנים - הצג את כל האלבומים - הצג את כל השירים - הצג את כל רשימות ההשמעה - כל \"%s\" האמנים - כל \"%s\" האלבומים - כל \"%s\" השירים - כל \"%s\" רשימות ההשמעה %1$s %2$s נגינת שמע diff --git a/res/values-ja/plurals.xml b/res/values-ja/plurals.xml index 23981525c23ed3759b5ae1fce56e3b0558fde3bc..c58b69a0e28cbe9e78e53efdff36918114cda80e 100644 --- a/res/values-ja/plurals.xml +++ b/res/values-ja/plurals.xml @@ -16,18 +16,12 @@ limitations under the License. --> - - %d人のアーティスト - %d枚のアルバム %d - - %d個のジャンル - %d時間 @@ -43,9 +37,6 @@ %d曲をキューに追加しました。 - - %d曲をお気に入りに追加しました。 - %d曲を削除しました。 diff --git a/res/values-ja/strings.xml b/res/values-ja/strings.xml index 22a22e320819f53e555cc86306bf63a26e110971..1a8bb4a6ab99144b2300230eda83f4fa7fe500cc 100644 --- a/res/values-ja/strings.xml +++ b/res/values-ja/strings.xml @@ -18,16 +18,12 @@ --> 音楽 - 最近の曲 アーティスト アルバム プレイリスト - ジャンル - 再生中  再生キュー アルバム - トップ曲 すべての曲 設定 シャッフル @@ -38,16 +34,13 @@ トップトラックでシャッフル 最近再生した曲でシャッフル 最近追加した曲でシャッフル - すべて再生 並べ替え リストを消去 - 最近の曲を消去 キューを消去 プレイリストにキューを保存 イコライザー プレイリストに追加 キューに追加 - 最近の曲から削除 キューから削除 昇順 降順 @@ -55,8 +48,6 @@ アルバム 再生時間 - 追加日 - トラックリスト 曲数 アルバム数 ファイル名 @@ -77,9 +68,8 @@ この操作は元に戻せません キャッシュされた画像エントリーを完全に削除します ギャラリーから写真を選択 - Google検索 デフォルトの写真を使用 - 以前の写真を使用 + 音声録音の許可が拒否されました。音楽ビジュアライザーを有効にするには設定アプリから許可を有効化して下さい。 再生 次に再生 アルバムを再生 @@ -101,15 +91,13 @@ リピート すべてリピート 1曲リピート - キューを開く - 音楽を参照 [%s]を着信音として設定しました - プレイリスト名を変更しました ストレージ キャッシュを削除 すべてのキャッシュされた画像を削除する 全般 音楽の視覚エフェクトを表示 + 背景のぼかし 歌詞を表示 srtファイルがある曲向け シェイクで再生 @@ -117,10 +105,7 @@ 音楽: 4 \u00d7 1 音楽: 4 \u00d7 2 音楽: 4 \u00d7 2(別バージョン) - 音楽: 最近聴いた曲 イコライザーを開けませんでした。 - パソコンから端末に音楽をコピーするには、USBケーブルを使用してください。 - お気に入りに追加した曲がここに表示されます。 最近の曲はありません 最近聴いた曲がここに表示されます。 プレイリストに曲がありません @@ -151,14 +136,6 @@ 10曲以上 5枚以上 "その他" - すべてのアーティストを表示 - すべてのアルバムを表示 - すべての曲を表示 - すべてのプレイリストを表示 - 「%s」を含むすべてのアーティスト - [%s]を含むすべてのアルバム - [%s]を含むすべての曲 - [%s]を含むすべてのプレイリスト %1$s%2$s 音楽の再生 diff --git a/res/values-ka/strings.xml b/res/values-ka/strings.xml index 471a12ddb0ecc7113c5432710078813a8088d133..694f1b3a03f10bd96fca40bd549eee0db0281cf4 100644 --- a/res/values-ka/strings.xml +++ b/res/values-ka/strings.xml @@ -21,5 +21,4 @@ მუსიკა: 4 \u00d7 1 მუსიკა: 4 \u00d7 2 მუსიკა: 4 \u00d7 2 (alternativ) - მუსიკა: ბოლოს მოსმენილი diff --git a/res/values-kn/plurals.xml b/res/values-kn/plurals.xml index 224b343f987bfb8291433068493afb3f786555ae..b1f60b5920f41bf3b09783f8af3714d56cf2d607 100644 --- a/res/values-kn/plurals.xml +++ b/res/values-kn/plurals.xml @@ -16,10 +16,6 @@ limitations under the License. --> - - %d ಕಲಾವಿದ - %d ಕಲಾವಿದರು - %d ಆಲ್ಬಂ %d ಆಲ್ಬಂಗಳು @@ -28,10 +24,6 @@ %d ಹಾಡು %d ಹಾಡುಗಳು - - %d ಶೈಲಿ - %d ಶೈಲಿಗಳು - %d %d @@ -52,10 +44,6 @@ %d ಹಾಡನ್ನು ಸರದಿಗೆ ಸೇರಿಸಲಾಗಿದೆ. %d ಹಾಡುಗಳನ್ನು ಸರದಿಗೆ ಸೇರಿಸಲಾಗಿದೆ. - - %d ಹಾಡನ್ನು ಫೇವರಿಟ್ಸ್ ಗೆ ಸೇರಿಸಲಾಗಿದೆ. - %d ಹಾಡುಗಳನ್ನು ಫೇವರಿಟ್ಸ್ ಗೆ ಸೇರಿಸಲಾಗಿದೆ. - %d ಹಾಡನ್ನು ಅಳಿಸಲಾಗಿದೆ. %d ಹಾಡುಗಳನ್ನು ಅಳಿಸಲಾಗಿದೆ. diff --git a/res/values-kn/strings.xml b/res/values-kn/strings.xml index 333b0f2fd76b59dddc687b63eff34da74f7b4ceb..3ef2c66b302eddf413c7b343a8a6259776bb0821 100644 --- a/res/values-kn/strings.xml +++ b/res/values-kn/strings.xml @@ -18,15 +18,11 @@ --> ಸಂಗೀತ - ಇತ್ತೀಚಿನ ಕಲಾವಿದರು ಹಾಡುಗಳು ಪ್ಲೇಪಟ್ಟಿಗಳು - ಪ್ರಕಾರಗಳು - ಈಗ ಪ್ಲೇ ಆಗುತ್ತಿರುವ ಪ್ಲೇ ಸರದಿ ಆಲ್ಬಂಗಳು - ಟಾಪ್ ಹಾಡುಗಳು ಎಲ್ಲಾ ಹಾಡುಗಳು ಸೆಟ್ಟಿಂಗ್ಸ್ ಷಫಲ್ @@ -37,16 +33,13 @@ ಟಾಪ್ ಟ್ರ್ಯಾಕ್‍ಗಳನ್ನು ಷಫಲ್ ಮಾಡಿ ಇತ್ತೀಚೆಗೆ ಪ್ಲೇ ಮಾಡಿದ್ದನ್ನು ಷಫಲ್ ಮಾಡಿ ಕೊನೆಯದಾಗಿ ಸೇರಿಸಿದನ್ನು ಷಫಲ್ ಮಾಡಿ - ಎಲ್ಲವನ್ನು ಪ್ಲೇ ಮಾಡಿ ಇದರಿಂದ ಶೋಧಿಸಿ ಪಟ್ಟಿ ತೆರವುಗೊಳಿಸಿ - ಇತ್ತೀಚಿನವನ್ನು ತೆರವುಗೊಳಿಸಿ ಸರದಿಯನ್ನು ತೆರವುಗೊಳಿಸಿ ಸರದಿಯನ್ನು ಪ್ಲೇಪಟ್ಟಿಗೆ ಉಳಿಸಿ ಸಮಕಾರಕ ಪ್ಲೇಪಟ್ಟಿಗೆ ಸೇರಿಸಿ ಸರದಿಗೆ ಸೇರಿಸಿ - ಇತ್ತೀಚಿನವುಗಳಿಂದ ತೆಗೆ ಸರದಿಯಿಂದ ತೆಗೆ ಅ-ಅಃ ಅಃ-ಅ @@ -54,8 +47,6 @@ ಆಲ್ಬಂ ವರ್ಷ ಕಾಲಾವಧಿ - ಸೇರಿಸಿದ ದಿನಾಂಕ - ಟ್ರ್ಯಾಕ್ ಪಟ್ಟಿ ಹಾಡುಗಳ ಸಂಖ್ಯೆ ಆಲ್ಬಂಗಳ ಸಂಖ್ಯೆ ಕಡತದ ಹೆಸರು @@ -76,9 +67,7 @@ ಇದನ್ನು ಹಿಂತಿರುಗಿಸಲಾಗುವುದಿಲ್ಲ ಇದು ನಗದುಮಾಡಿರುವ ಚಿತ್ರ ನಮೂದುಗಳನ್ನು ಶಾಶ್ವತವಾಗಿ ಅಳಿಸಿಹಾಕುತ್ತದೆ ಗ್ಯಾಲರಿಯಿಂದ ಫೋಟೋ ಆರಿಸಿ - ಗೂಗಲ್ ಸರ್ಚ್ ಡೀಫಾಲ್ಟ್ ಫೋಟೋವನ್ನು ಉಪಯೋಗಿಸಿ - ಹಳೆಯ ಫೋಟೋ ಉಪಯೋಗಿಸಿ ಪ್ಲೇ ನಂತರ ಪ್ಲೇಮಾಡು ಆಲ್ಬಂ ಪ್ಲೇ ಮಾಡು @@ -100,10 +89,7 @@ ಪುನರಾವರ್ತಿಸು ಎಲ್ಲವನ್ನು ಪುನರಾವರ್ತಿಸು ಒಂದನ್ನು ಪುನರಾವರ್ತಿಸು - ಸರದಿಯನ್ನು ತೆರೆ - ಸಂಗೀತವನ್ನು ಬ್ರೌಸ್ ಮಾಡಿ \'%s\' ರಿಂಗ್‍ಟೋನ್ ಆಗಿ ಹೊಂದಿಸಲಾಗಿದೆ - ಪ್ಲೇಪಟ್ಟಿ ಮರುಹೆಸರಿಸಲಾಗಿದೆ ಸಂಗ್ರಹಣೆ ನಗದನ್ನು ಅಳಿಸು ಎಲ್ಲಾ ನಗದು ಮಾಡಿದ ಚಿತ್ರಗಳನ್ನು ತೆಗೆ @@ -116,10 +102,7 @@ ಸಂಗೀತ: 4 \u00d7 1 ಸಂಗೀತ: 4 \u00d7 2 ಸಂಗೀತ: 4 \u00d7 2 (ಪರ್ಯಾಯ) - ಸಂಗೀತ: ಇತ್ತೀಚೆಗೆ ಆಲಿಸಿದ ಸಮಾನಕಾರಕವನ್ನು ತೆರೆಯಲಾಗುವುದಿಲ್ಲ. - ನಿಮ್ಮ ಸಂಗೀತವನ್ನು ನಿಮ್ಮ ಕಂಪ್ಯೂಟರ್‍‍ನಿಂದ ನಿಮ್ಮ ಸಾಧನಕ್ಕೆ ನಕಲಿಸಲು, ಯು‍ಎಸ್‍ಬಿ ಕೇಬಲ್ ಉಪಯೋಗಿಸಿ. - ನೀವು ಫೇವರಿಟ್ಸ್ ಎಂದು ಗುರುತಿಸಿದ ಹಾಡುಗಳನ್ನು ಇಲ್ಲಿ ಪ್ರದರ್ಶಿಸಲಾಗುತ್ತದೆ. ಯಾವುದೇ ಇತ್ತೀಚಿನ ಹಾಡುಗಳಿಲ್ಲ ನೀವು ಇತ್ತೀಚೆಗೆ ಆಲಿಸಿದ ಹಾಡುಗಳು ಇಲ್ಲಿ ಕಾಣಿಸುತ್ತದೆ. ಪ್ಲೇಪಟ್ಟಿಯಲ್ಲಿ ಯಾವುದೇ ಹಾಡುಗಳಿಲ್ಲ @@ -150,14 +133,6 @@ 10+ ಹಾಡುಗಳು 5+ ಆಲ್ಬಂಗಳು "ಇತರೆ" - ಎಲ್ಲಾ ಕಲಾವಿದರನ್ನು ಪ್ರದರ್ಶಿಸು - ಎಲ್ಲಾ ಆಲ್ಬಂಗಳನ್ನು ಪ್ರದರ್ಶಿಸು - ಎಲ್ಲಾ ಹಾಡುಗಳನ್ನು ಪ್ರದರ್ಶಿಸು - ಎಲ್ಲಾ ಪ್ಲೇಪಟ್ಟಿಗಳನ್ನು ಪ್ರದರ್ಶಿಸು - ಎಲ್ಲಾ \"%s\" ಕಲಾವಿದರು - ಎಲ್ಲಾ \"%s\" ಆಲ್ಬಂಗಳು - ಎಲ್ಲಾ \"%s\" ಹಾಡುಗಳು - ಎಲ್ಲಾ \"%s\" ಪ್ಲೇಪಟ್ಟಿಗಳು %1$s %2$s ಸಂಗೀತ ಪುನರಾಡಿಸು diff --git a/res/values-ko/plurals.xml b/res/values-ko/plurals.xml index ed665c981df6529509ae524aed9d9b79789411db..8b09c69abb8399cac160483a60443d7bf2a77209 100644 --- a/res/values-ko/plurals.xml +++ b/res/values-ko/plurals.xml @@ -16,18 +16,12 @@ limitations under the License. --> - - %d명의 아티스트 - %d개의 앨범 %d곡의 음악 - - %d개의 장르 - %d시간 @@ -43,9 +37,6 @@ %d곡의 음악이 대기열에 추가되었습니다. - - %d곡의 음악이 즐겨찾기에 추가되었습니다. - %d곡의 음악이 삭제되었습니다. diff --git a/res/values-ko/strings.xml b/res/values-ko/strings.xml index 0d10ab54c148222bb790b69e9eaca33895e2bdc6..c088cda297ba2a971095f9f5944bbcf422ed7ab3 100644 --- a/res/values-ko/strings.xml +++ b/res/values-ko/strings.xml @@ -18,16 +18,12 @@ --> 음악 - 최근 아티스트 앨범 음악 재생목록 - 장르 - 재생 중 재생 대기열 앨범 - 자주 듣는 곡들 모든 노래 설정 셔플 @@ -38,16 +34,13 @@ 자주 듣는 곡들 셔플 최근 재생 셔플 최근 추가 셔플 - 모두 재생 정렬 목록 비우기 - 최근 목록 비우기 대기열 비우기 큐를 재생 목록으로 저장 이퀄라이저 재생목록에 추가 대기열에 추가 - 최근 재생 목록에서 제거 대기열에서 제거 오름차순 내림차순 @@ -55,8 +48,6 @@ 앨범 연도 길이 - 추가된 날짜 - 트랙 목록 음악 수 앨범 수 파일명 @@ -77,9 +68,8 @@ 이 작업은 되돌릴 수 없습니다 임시 저장된 이미지들이 영구적으로 제거됩니다 갤러리에서 사진 선택 - Google 검색 기본 사진 사용 - 이전 사진 사용 + 오디오 녹음 권한이 거부되어 있습니다. 음악 시각화를 사용하려면 설정 앱에서 권한을 허용해 주세요. 재생 다음 곡 재생 앨범 재생 @@ -101,10 +91,7 @@ 반복 모두 반복 한 곡 반복 - 대기열 열기 - 음악 탐색 \'%s\'이(가) 벨소리로 지정되었습니다 - 재생목록의 이름이 변경되었습니다 저장소 캐시 제거 임시 저장된 모든 이미지 제거 @@ -118,10 +105,7 @@ 음악: 4 \u00d7 1 음악: 4 \u00d7 2 음악: 4 \u00d7 2 (다른 배치) - 음악: 최근에 들은 곡 이퀄라이저를 열 수 없습니다. - 컴퓨터에서 기기로 음악을 복사하려면 USB 케이블을 사용하십시오. - 즐겨찾기에 추가한 음악들이 여기에 표시됩니다. 최근에 재생된 곡 없음 최근에 들은 음악들이 여기에 표시됩니다. 재생목록에 음악 없음 @@ -131,7 +115,7 @@ 최근에 추가된 곡 없음 지난 한 달 동안 추가된 음악들이 여기에 표시됩니다. 음악 없음 - 컴퓨터에서 기기로 음악을 복사하려면 USB 케이블을 사용하십시오. + 컴퓨터에서 기기로 음악을 복사하려면 USB 케이블을 사용하세요. 대기열에 노래 없음 노래를 재생 대기열에 추가하려면 노래, 앨범, 또는 아티스트의 옵션 메뉴를 탭하여 연 뒤 \"대기열에 추가\"를 선택하십시오. %1$s 트랙을 재생할 수 없음 @@ -152,14 +136,6 @@ 10곡 이상의 음악 5개 이상의 앨범 "기타" - 모든 아티스트 보기 - 모든 앨범 보기 - 모든 음악 보기 - 모든 재생목록 보기 - 모든 \"%s\" 아티스트 - 모든 \"%s\" 앨범 - 모든 \"%s\" 음악 - 모든 \"%s\" 재생목록 %1$s %2$s 음악 재생 diff --git a/res/values-ku/strings.xml b/res/values-ku/strings.xml index aab780e17f84fb98d5975191bb3411e64b45348b..a9d625ce73fbe72e8d89d66167dd52a825e19814 100644 --- a/res/values-ku/strings.xml +++ b/res/values-ku/strings.xml @@ -18,16 +18,12 @@ --> مۆسیقا - تازه‌کان هونەرمەند ئەلبوم گۆرانییەکان لیستی لێدان - چه‌شنه‌کان - لێدانی ئێستا لێدانی ڕیزکراو ئەلبوم - گۆرانیەکانی لوتکە هەموو گۆرانیەکان ڕێکخستن ڕیزکراو @@ -38,16 +34,13 @@ تراکی لوتکەی ڕیزکراو لێدراوی تازەی ڕیزکراو ڕیزکردنەوەی تازا زیادکراو - لێدانی هه‌مووی ڕیزکردن به‌پێی پاکردنەوەی خشتەکە - پاککردنه‌وه‌ی تازه‌کان پاککردنه‌وه‌ی ڕیزه‌کان پاشەکەوتکردنی ریزی ڕێزکراو بۆ لێدان یه‌کسانکه‌ری ده‌نگ زیادکردن بۆ لێدراوه‌کان زیادکردن بۆ ڕیزکراوه‌کان - سڕینه‌وه‌ له‌ تازه‌کان سڕینه‌وه‌ له‌ ڕیزه‌کان A-Z Z-A @@ -55,8 +48,6 @@ ئه‌لبوم ساڵ ماوه‌ - ڕۆژی زیادکردنی - لیستی تراکه‌کان ژماره‌ی گۆرانییه‌کان ژماره‌ی ئه‌لبومه‌کان ناوی په‌ڕگه‌ @@ -73,9 +64,7 @@ ئه‌مه‌ دواتر ناتوانی بیگه‌ڕێنیته‌وه‌ ئه‌مه‌ واته‌ سڕینه‌وه‌ی هه‌موو وێنه‌ خه‌زنکراوه‌کان به‌ گشتی هه‌ڵبژاردنی وینه‌یه‌ک له‌ گه‌له‌ری - گه‌ڕانی گۆگڵ به‌کارهێنانی وێنه‌ی سه‌ره‌تایی - به‌کارهێنانی وێنه‌ی کۆن لێدان لێدانی داهاتوو زیاتر له‌لایه‌ن هونه‌رمه‌نده‌وه‌ @@ -96,14 +85,10 @@ دووباره‌کردنه‌وه‌ی هه‌مووی دووباره‌کردنه‌وه‌ی یه‌کدانه‌ \'%s\' خستنه‌ سه‌ر زه‌نگ - ناوی لیستی لێدان گۆڕا بیرگەی سڕینه‌وه‌ی حه‌شارگه‌ سڕینه‌وه‌ی هه‌موو وێنه‌ حه‌شارگه‌کان - ئه‌پۆڵۆ:تازه‌ترین که‌ گوێلێگیراون یه‌کسانکه‌ری ده‌نگ ناکرێته‌وه‌. - بۆ له‌به‌رگرتنه‌وه‌ی گۆرانی له‌ کۆمپیوته‌ر بۆ ئامێره‌که‌ت ، کێبڵی USB به‌کاربهێنه‌. - ئه‌و گۆرانیانه‌ی په‌سه‌ندن له‌لات لێره‌ نیشان ده‌درێن. ئه‌و ئه‌لبومانه‌ی که‌ گوێت لێگرتوون لێره‌ نیشان ئه‌درێن ، گۆرانی لێبده‌. ئه‌و گۆرانیانه‌ی که‌ زیادکراون له‌ مانگی پێشوو لێره‌ نیشان ئه‌درێن. diff --git a/res/values-lt/strings.xml b/res/values-lt/strings.xml index 828acf9fc4723bae069ae33bd5be27d9469614aa..f1ab521a15e1d3d3aa6a31fc7e1a820c796fb91a 100644 --- a/res/values-lt/strings.xml +++ b/res/values-lt/strings.xml @@ -18,16 +18,12 @@ --> Muzika - Nauja Atlikėjai Albumai Dainos Grojaraščiai - Žanrai - Dabar leidžiama Paleisti eilėje Albumai - Top dainos Visos dainos Nustatymai Maišyti @@ -38,16 +34,13 @@ Maišyti top takelius Maišyti naujausiai leistas Maišyti neseniai pridėtas - Paleisti viską Rūšiuoti pagal Išvalyti sąrašą - Išvalyti naujausias Išvalyti eilę Išsaugoti eilę į grojaraštį Vienodintuvas Pridėti į grojaraštį Pridėti į eilę - Pašalinti iš naujausių Pašalinti iš eilės A - Z Z - A @@ -55,8 +48,6 @@ Albumą Metus Trukmę - Pridėjimo datą - Takelių sąrašą Dainų skaičių Albumų skaičių Failo pavadinimą @@ -77,9 +68,7 @@ Tai negali būti atšaukta Visam laikui bus ištrinti talpyklos vaizdo įrašai Pasirinkite nuotrauką iš galerijos - „Google“ paieška Naudoti numatytąją nuotrauką - Naudoti seną nuotrauką Paleisti Paleisti kitą Paleisti albumą @@ -101,10 +90,7 @@ Pakartoti Pakartoti visus Pakartoti vieną - Atidaryti eilę - Naršyti muziką %s“ nustatytas kaip skambėjimo tonas - Grojaraštis pervardytas Saugykla Ištrinti talpyklą Pašalinti visus talpyklos vaizdus @@ -117,10 +103,7 @@ Muzika: 4 \u00d7 1 Muzika: 4 \u00d7 2 Muzika: 4 \u00d7 2 (pakaitinis) - Muzika: naujausiai klausyta Nepavyko atidaryti vienodintuvo. - Kad kopijuotumėte muziką iš kompiuterio į savo įrenginį, naudokite USB kabelį. - Dainas, kurias pažymite kaip mėgstamas bus rodomos čia. Nėra naujausių dainų Naujausiai klausytos dainos bus rodomos čia. Nėra dainų grojaraštyje @@ -151,13 +134,5 @@ 10+ dainų 5+ albumai "Kita" - Rodyti visus atlikėjus - Rodyti visus albumus - Rodyti visas dainas - Rodyti visus grojaraščius - Visi \"%s\" atlikėjai - Visi \"%s\" albumai - Visos \"%s\" dainos - Visi \"%s\" grojaraščiai %1$s %2$s diff --git a/res/values-lu/plurals.xml b/res/values-lu/plurals.xml new file mode 100644 index 0000000000000000000000000000000000000000..a8f1476a1d55a88b7e55eda50427f4f2984ec483 --- /dev/null +++ b/res/values-lu/plurals.xml @@ -0,0 +1,51 @@ + + + + + %d Album + %d Alben + + + %d Lidd + %d Lidder + + + %d St. + %d St. + + + %d Min. + %d Min. + + + %d Lidd an d\'Ofspilllëscht dobäigesat. + %d Lidder an d\'Ofspilllëscht dobäigesat. + + + %d Lidd vun der Ofspilllëscht geläscht. + %d Lidder vun der Ofspilllëscht geläscht. + + + %d Lidd an d\'Ofspilllëscht dobäigesat. + %d Lidder an d\'Ofspilllëscht dobäigesat. + + + %d Lidd gouf geläscht. + %d Lidder goufe geläscht. + + diff --git a/res/values-lu/strings.xml b/res/values-lu/strings.xml new file mode 100644 index 0000000000000000000000000000000000000000..1278492603b2dbf441423d0c20866603c180333b --- /dev/null +++ b/res/values-lu/strings.xml @@ -0,0 +1,138 @@ + + + + Musek + Interpreten + Alben + Musekstécker + Ofspilllëschten + Waardeschlaang ofspillen + Alben + All d\'Lidder + Astellungen + Mëschen + All zoufälleg ofspillen + Ofspilllëscht mëschen + Album mëschen + Interpret mëschen + Top-Lidder mëschen + \"VIru kuerzem ofgespillt\" mëschen + \"Fir d\'lescht dobäigesat\" mëschen + Zortéieren no + Lëscht eidel maachen + Waardeschlaang eidel maachen + Waardeschläif an eng Ofspilllëscht späicheren + Equalizer + An d\'Ofspilllëscht setzen + Un d\'Waardeschlaang hänken + Aus der Waardeschlaang läschen + A-Z + Z-A + Interpret + Album + Joer + Dauer + Unzuel u Museksstécker + Unzuel vun Alben + Fichiersnumm + Fir d\'lescht dobäigesat + Viru kuerzem ofgespillt + Meng Top-Lidder + Nei Ofspilllëscht + Späicheren + Ofbriechen + Iwwerschreiwen + Eidel maachen + Ofspilllëscht %d + Numm vun der Ofspilllëscht + %s läschen? + Top-Lidder eidel maachen? + Rezent ofgespillt eidel maachen? + \"Fir d\'lescht dobäigesat\" eidel maachen? + Dat kann net réckgängeg gemaach ginn + Heiduerch ginn all d\'tëschegespäichert Biller definitiv geläscht + Foto aus der Galerie auswielen + Standardfoto benotzen + Ofspillen + Als nächst ofspillen + Album ofspillen + Méi vun dësem Interpret + Ëmbenennen + Läschen + Album-Cover eroflueden + Interpretebild eroflueden + Aus der \"Viru kuerzem gelauschtert\"-Lëscht läschen + Als Schelltoun benotzen + Aus der Ofspilllëscht läschen + Bild änneren + Ofspillen + Paus + Weider + Zréck + Mëschen + All mëschen + Widderhuelen + All widderhuelen + Eent widderhuelen + \'%s\' als Schelltoun setzen + Späicher + Tëschespäicher läschen + All d\'tëschegespäichert Biller läschen + Allgemeng + Musekvisualiséierung uweisen + Liddertexter uweisen + Fir Lidder déi en \"srt\"-Fichier hunn + Rësele fir opzespillen + Apparat rësele fir dat nächst Lidd ofzespillen + Musek: 4 \u00d7 1 + Musek: 4 \u00d7 2 + Musek: 4 \u00d7 2 (alternativ) + Den Equalizer konnt net opgemaach ginn. + Keng rezent Lidder + Lidder, déi s du viru kuerzem gelauschtert hues, ginn hei ugewisen. + Keng Lidder an der Ofspilllëscht + Fir Lidder an dës Ofspilllëscht ze setzen, dréck den Optiounsmenü op engem Lidd, Album oder Interpret, a wiel \"An d\'Ofspilllëscht setzen\" aus. + Keng Top-Lidder + D\'Lidder, déi s du am meeschte lauschters, ginn hei ugewisen. + Keng Lidder an der lescht dobäigesat + Lidder, déi s du de leschte Mount gelauschtert hues, ginn hei ugewisen. + Keng Musek fonnt + Benotz en USB-Kabel fir Musek vun dengem Computer op den Apparat z\'iwwerdroen. + Keng Lidder an der Waardeschlaang + Fir Lidder an d\'Waardeschlaang ze setzen, dréck den Optiounsmenü bei engem Lidd, Album oder Interpret, a wiel \"An d\'Waardeschlaang setzen\" aus. + Lidd %1$s kann net ofgespillt ginn + Onbekannt Joer + Manner wéi 30 Sekonnen + 30-60 Sekonnen + 1-2 Minutten + 2-3 Minutten + 3-4 Minutten + 4-5 Minutten + 5-10 Minutten + 10-30 Minutten + 30-60 Minutten + Méi wéi 60 Minutten + 1 Lidd + 2-4 Lidder + 5-9 Lidder + 10 oder méi Lidder + 5 oder méi Alben + "Aner" + %1$s %2$s + diff --git a/res/values-lv/plurals.xml b/res/values-lv/plurals.xml index 3461ceeeb07149588d1df369cfe342a0f62a109c..2d3c0827944d7d4bda819e638e147ba5155eb09e 100644 --- a/res/values-lv/plurals.xml +++ b/res/values-lv/plurals.xml @@ -16,11 +16,6 @@ limitations under the License. --> - - %d izpildītājs - %d izpildītājs - %d izpildītāji - %d albums %d albums @@ -31,11 +26,6 @@ %d dziesma %d dziesmas - - %d žanrs - %d žanrs - %d žanri - %dh %dh @@ -61,11 +51,6 @@ %d dziesma pievienota rindai. %d dziesmas pievienotas rindai. - - %d dziesma pievienota favorītiem. - %d dziesma pievienota favorītiem. - %d dziesmas pievienotas favorītiem. - %d dziesma izdzēsta. %d dziesma izdzēsta. diff --git a/res/values-lv/strings.xml b/res/values-lv/strings.xml index b62a9245e522ac611305ae02078cb77343030d35..6091190ca742df81a520b91f365a7047ef470b47 100644 --- a/res/values-lv/strings.xml +++ b/res/values-lv/strings.xml @@ -18,16 +18,12 @@ --> Mūzika - Nesenie Izpildītāji Albumi Dziesmas Atskaņošanas saraksti - Žanri - Šobrīd atskaņo Atskaņošanas rinda Albumi - Labākās dziesmas Visas dziesmas Iestatījumi Jaukt @@ -38,15 +34,12 @@ Jaukt labākās dziesmas Jaukt nesen atskaņoto Jaukt nesen pievienoto - Atskaņot visu Kārtot pēc Notīrīt sarakstu - Notīrīt nesenos Notīrīt rindu Ekvalaizers Pievienot atskaņošanas sarakstam Pievienot rindai - Izņemt no nesenajiem Izņemt no rindas A-Z Z-A @@ -54,8 +47,6 @@ Albums Gads Ilgums - Pievienošanas datums - Dziesmu saraksts Dziesmu skaits Albumu skaits Faila nosaukums @@ -76,9 +67,7 @@ To nevar atsaukt Kešoto attēlu ieraksti tiks dzēsti neatgriezeniski Izvēlēties foto no galerijas - Google meklēšana Izmantot noklusēto foto - Izmantot agrāko foto Atskaņot Atskaņot nākamo Vairāk no izpildītāja @@ -99,10 +88,7 @@ Atkārtot Atkārtot visu Atkārtot vienu - Atvērt rindu - Pārlūkot mūziku \'%s\' ir uzstadīts kā zvana signāls - Atskaņošanas saraksts ir pārsaukts Krātuve Dzēst kešatmiņu Dzēst visas kešotās bildes @@ -113,10 +99,7 @@ Mūzika: 4 \u00d7 1 Mūzika: 4 \u00d7 2 Mūzika: 4 \u00d7 2 (alternatīvā) - Mūzika: nesen klaustītie Ekvalaizeru nevar atvērt. - Lai kopētu mūziku no datora uz šo iekārtu, izmantojiet USB kabeli. - Izlasei pievienotās dziesmas tiks parādītas šeit. Nav neseno dziesmu Nesen klausītās dziesmas tiks parādītas šeit. Atskaņošanas sarakstā nav dziesmu @@ -147,13 +130,5 @@ 10 + dziesmas 5 + albumi "Cits" - Parādīt visus māksliniekus - Parādīt visus albumus - Rādīt visas dziesmas - Parādīt visus atskaņošanas sarakstus - Visi \"%s\" mākslinieki - Visi \"%s\" albumi - Visas \"%s\" dziesmas - Visi \"%s\" atskaņošanas saraksti %1$s %2$s diff --git a/res/values-ml/plurals.xml b/res/values-ml/plurals.xml index 3eaba46691515fb6edcb172fb7eb7d6a39fee3eb..161081a86af7740225c35ab315109b3b819fe4a4 100644 --- a/res/values-ml/plurals.xml +++ b/res/values-ml/plurals.xml @@ -16,10 +16,6 @@ limitations under the License. --> - - %d കലാകാരന് - %d കലാകാരന്മാർ - %d ആൽബം %d ആൽബങ്ങളും @@ -28,10 +24,6 @@ %d പാട്ട് %d പാട്ടുകൾ - - %dസംഗീത തരം - %dസംഗീത തരങ്ങൾ - %d %d @@ -52,10 +44,6 @@ %d ഗാനം ക്യൂ ചേർത്തു. %d പാട്ടുകൾ ക്യൂ ചേർത്തു. - - %d പാട്ട് പ്രിയപ്പെട്ടവലേക്ക് ചേർത്തു. - %d പാട്ടുകൾ പ്രിയപ്പെട്ടവലേക്ക് ചേർത്തു. - %d പാട്ട് ഡിലീറ്റ് ചെയ്തു. %d പാട്ടുകൾ ഇല്ലാതാക്കി. diff --git a/res/values-ml/strings.xml b/res/values-ml/strings.xml index e7dce4dc04a7cd5eab7fce33a7d9ba3e0803cd98..3e455d02086932451c15e255f61fc0cc15892a6e 100644 --- a/res/values-ml/strings.xml +++ b/res/values-ml/strings.xml @@ -18,16 +18,12 @@ --> സംഗീതം - അടുത്തിടെയുള്ളത് ആർട്ടിസ്റ്റുകൾ ആൽബങ്ങൾ ഗാനങ്ങൾ പ്ലേലിസ്റ്റുകൾ - വിഭാഗങ്ങൾ - ഇപ്പോൾ പ്ലേ ചെയ്യുന്നു ക്യൂ പ്ലേ ചെയ്യുന്നു ആൽബങ്ങൾ - മുന്‍നിര ഗാനങ്ങൾ ഗാനങ്ങൾ എല്ലാം ക്രമീകരണം ഷഫിൾ ചെയ്യുക @@ -38,16 +34,13 @@ മുനിര ട്രാക്കുകൾ ഷഫിൾ ചെയ്യുക സമീപകാലത്ത് പ്ലേ ചെയ്തത് ഷഫിൾ ചെയ്യുക അവസാനം ചേർത്തത് ഷഫിൾ ചെയ്യുക - എല്ലാം പ്ലേ ചെയ്യുക ഇതുപ്രകാരം അടുക്കുക ലിസ്റ്റ് മായ്‌ക്കുക - സമീപകാലത്തുള്ളത് മായ്ക്കുക ക്യൂ മായ്ക്കുക പ്ലേലിസ്റ്റിലേക്ക് ക്യൂ സംരക്ഷിക്കുക ഇക്വലൈസർ പ്ലേലിസ്റ്റിൽ ചേർക്കുക ക്യൂവിൽ ചേർക്കുക - സമീപകാലത്തുള്ളവയില്‍ നിന്ന് നീക്കം ചെയ്യുക ക്യൂവിൽ നിന്ന് നീക്കം ചെയ്യുക A-Z Z-A @@ -55,8 +48,6 @@ ആൽബം വര്‍ഷം ദൈർഘ്യം - ചേർത്ത തീയതി - ട്രാക്ക് ലിസ്റ്റ് ഗാനങ്ങളുടെ എണ്ണം ആൽബങ്ങളും എണ്ണം ഫയല്‍നാമം @@ -77,9 +68,7 @@ ഇത് പൂര്‍വ്വസ്ഥിതിയിലാക്കാന്‍ കഴിയില്ല ഈ കാഷെ ചെയ്ത ഇമേജ് എൻട്രികൾ ശാശ്വതമായി ഇല്ലാതാക്കുന്നതാണ് ഗാലറിയിൽ നിന്നും ഫോട്ടോ തിരഞ്ഞെടുക്കുക - ഗൂഗിള്‍ തിരയല്‍ ഡിഫോള്‍ട്ട് ഫോട്ടോ ഉപയോഗിക്കുക - പഴയ ഫോട്ടോ ഉപയോഗിക്കുക പ്ലേ ചെയ്യുക അടുത്തത് പ്ലേ ചെയ്യുക ആൽബം പ്ലേ ചെയ്യുക @@ -101,10 +90,7 @@ ആവർത്തിക്കുക എല്ലാം ആവർത്തിക്കുക ഒരിക്കല്‍ ആവർത്തിക്കുക - ക്യൂ തുറക്കുക - സംഗീതം ബ്രൗസ് ചെയ്യുക \'%s\' റിംഗ്ടോൺ ആയി സജ്ജമാക്കി - പ്ലേലിസ്റ്റിന്റെ പേര് മാറ്റി സംഭരണം കാഷെ ഇല്ലാതാക്കുക കാഷെ ചെയ്ത ചിത്രങ്ങൾ എല്ലാം നീക്കം ചെയ്യുക @@ -117,10 +103,7 @@ സംഗീതം: 4 \u00d7 1 സംഗീതം: 4 \u00d7 2 സംഗീതം: 4 \u00d7 2 (ഇതരമാര്‍ഗ്ഗം) - സംഗീതം: സമീപകാലത്ത് കേട്ടത് ഈക്വലൈസര്‍ തുറക്കാൻ കഴിഞ്ഞില്ല. - നിങ്ങളുടെ കമ്പ്യൂട്ടറിൽ നിന്ന് നിങ്ങളുടെ ഉപകരണത്തിലേക്ക് സംഗീതം പകർത്തുന്നതിന്, ഒരു USB കേബിൾ ഉപയോഗിക്കുക. - പ്രിയപ്പെട്ടവയായി നിങ്ങള്‍ അടയാളപ്പെടുത്തുക ഗാനങ്ങൾ ഇവിടെ കാണിക്കുന്നതാണ്. സമീപകാലത്തുള്ള ഗാനങ്ങൾ ഇല്ല നിങ്ങൾ അടുത്തിടെ കേട്ട ഗാനങ്ങൾ ഇവിടെ കാണിക്കുന്നതാണ്. പ്ലേലിസ്റ്റില്‍ ഗാനങ്ങൾ ഇല്ല @@ -151,13 +134,5 @@ 10+ ഗാനങ്ങൾ 5+ ആൽബങ്ങൾ ""മറ്റുള്ളവ"" - എല്ലാ ആര്‍ട്ടിസ്റ്റുകളെയും കാണിക്കുക - എല്ലാ ആൽബങ്ങളും കാണിക്കുക - എല്ലാ ഗാനങ്ങളും കാണിക്കുക - എല്ലാ പ്ലേലിസ്റ്റുകളും കാണിക്കുക - \"%s\" ആര്‍ട്ടിസ്റ്റുകള്‍ എല്ലാം - \"%s\" ആൽബങ്ങൾ എല്ലാം - \"%s\" പാട്ടുകൾ എല്ലാം - \"%s\" പ്ലേലിസ്റ്റുകൾ എല്ലാം %1$s %2$s diff --git a/res/values-mr/plurals.xml b/res/values-mr/plurals.xml index da45d536b63737982966ffa5e7e9948de0b329e1..fa79feda51bddb801b6ef8d31af361d73ae87afb 100644 --- a/res/values-mr/plurals.xml +++ b/res/values-mr/plurals.xml @@ -16,10 +16,6 @@ limitations under the License. --> - - %d कलाकार - %d कलाकार - %d अल्बम %d अल्बम्स @@ -28,10 +24,6 @@ %d गाणे %d गाणी - - %d जेनर - %d जेनर्स - %dता %dता @@ -52,10 +44,6 @@ %d गाणे रांगेत जोडले. %d गाणी रांगेत जोडली. - - %d गाणे मनपसंतमध्ये जोडले. - %d गाणी मनपसंतमध्ये जोडली. - %d गाणे हटवले गेले. %d गाणी हटवली गेली. diff --git a/res/values-mr/strings.xml b/res/values-mr/strings.xml index e9545caed4568fbf259ef281fa7090857cefdd1f..42a8d0ac912673f77b6b6a43d05f48392425cbdd 100644 --- a/res/values-mr/strings.xml +++ b/res/values-mr/strings.xml @@ -18,16 +18,12 @@ --> संगीत - अलीकडील कलाकार अल्बम्स गाणी प्लेलिस्ट - जेनेर्स - आता प्ले करत आहे प्ले रांग अल्बम्स - सर्वोच्च गाणी सर्व गाणी सेटिंग्ज शफल @@ -38,16 +34,13 @@ सर्वोच्च ट्रॅक्स शफल करा अलीकडेच प्ले केलेले शफल करा शेवटचे जोडलेले शफल करा - सर्व प्ले करा नुसार क्रमवारी लावा सूची साफ करा - अलीकडील साफ करा रांग साफ करा रांग प्लेलिस्टमध्ये जतन करा संतुलक प्लेलिस्टमध्ये जोडा रांगेत जोडा - अलीकडील मधून काढा रांगेतून काढा A-Z Z-A @@ -55,8 +48,6 @@ अल्बम वर्ष कालावधी - तारीख जोडली - ट्रॅक यादी गाण्यांची संख्या अल्बम्सची संख्या फाइलनाव @@ -77,9 +68,7 @@ हे पुनर्स्थापित करता येत नाही यामुळे कॅशे केलेल्या प्रतिमा प्रविष्ठी कायमस्वरूपी हटवल्या जातील गॅलरीमधून फोटो निवडा - Google शोध डिफॉल्ट फोटो वापरा - जुना फोटो वापरा प्ले करा पुढील प्ले करा अल्बम प्ले करा @@ -101,10 +90,7 @@ पुनरावृत्ती सर्व पुनरावृत्ती करा एक पुनरावृत्ती करा - रांग उघडा - संगीत ब्राउझ करा \'%s\' रींग टोन म्हणून सेट करा - प्लेलिस्ट पुनर्नामित केली संचयन कॅशे हटवा सर्व कॅशे केलेल्या प्रतिमा काढा @@ -117,10 +103,7 @@ संगीत: 4 \u00d7 1 संगीत: 4 \u00d7 2 संगीत: 4 \u00d7 2 (पर्यायी) - संगीत: अलीकडेच ऐकलेले इक्वेलायझर उघडता आला नाही. - तुमच्या कॉम्प्युटरवरून तुमच्या डिव्हाइसला कॉपी करण्यासाठी, एक USB केबल वापरा. - तुम्ही मनपसंत म्हणून खूण केलेली गाणी इथे दाखवली जातील. हल्लीची गाणी नाहीत तुम्ही अलीकडेच ऐकलेली गाणी इथे दाखवली जातील. प्लेलिस्टमध्ये गाणी नाहीत @@ -151,13 +134,5 @@ 10+ गाणी 5+ अल्बम्स ""इतर"" - सर्व कलाकार दर्शवा - सर्व अल्बम्स दर्शवा - सर्व गाणी दर्शवा - सर्व प्लेलिस्ट दर्शवा - सर्व \"%s\" कलाकार - सर्व \"%s\" अल्बम्स - सर्व \"%s\" गाणी - सर्व \"%s\" प्लेलिस्ट %1$s %2$s diff --git a/res/values-nb/plurals.xml b/res/values-nb/plurals.xml index b5d9e920e71a9aa879915b77c0643e8a619af7aa..1748b7d6b29bc6a51f352ec04cca4c9460ddaa69 100644 --- a/res/values-nb/plurals.xml +++ b/res/values-nb/plurals.xml @@ -16,10 +16,6 @@ limitations under the License. --> - - %d artist - %d artister - %d album %d albumer @@ -28,10 +24,6 @@ %d sang %d sanger - - %d sjanger - %d sjangre - %dt %dt @@ -52,10 +44,6 @@ %d sang lagt til i avspillingskø. %d sanger lagt til i avspillingskø. - - %d sang lagt til i favoritter. - %d sanger lagt til i favoritter. - %d sang ble slettet. %d sanger ble slettet. diff --git a/res/values-nb/strings.xml b/res/values-nb/strings.xml index dd0124a2f1f5c5cb1dfc3bc0096b25685f0dad8d..f1c31b7520fa9a58dce7e74eb2ab932f7960e408 100644 --- a/res/values-nb/strings.xml +++ b/res/values-nb/strings.xml @@ -18,16 +18,12 @@ --> Musikk - Siste Artister Albumer Sanger Spillelister - Sjangrer - Nå spilles Avspillingskø Albumer - Topp sanger Alle sanger Innstillinger Shuffle @@ -38,16 +34,13 @@ Shuffle topp sanger Shuffle nylig spilte Shuffle sist lagt til - Spill alle Sorter etter Tøm liste - Slett siste Slett kø Lagre kø til spillelisten Equalizer Legg til i spilleliste Legg til i køen - Fjern fra siste Fjern fra køen A-Z Z-A @@ -55,8 +48,6 @@ Album År Varighet - Dato lagt til - Sporliste Antall sanger Antall album Filnavn @@ -77,9 +68,7 @@ Dette kan ikke omgjøres Dette vil permanent slette allehurtigbufferbilder Velg foto fra Galleri - Google søk Bruk standard bilde - Bruk gammelt bilde Spill av Spill neste Spill album @@ -101,10 +90,7 @@ Gjenta Gjenta alle Gjenta én - Åpne kø - Bla gjennom musikken \'%s\' Sett som ringetone - Spillelisten fikk et nytt navn Lagring Slett hurtigbuffer Slett alle mellomlagrede bilder @@ -117,10 +103,7 @@ Musikk: 4 \u00d7 1 Musikk: 4 \u00d7 2 Musikk: 4 \u00d7 2 (alternativ) - Musikk: nylig hørte Equalizeren kan ikke åpnes. - For å kopiere musikk fra en datamaskin til enheten, bruk en USB kabel. - Sanger du markerer som favoritter vil bli vist her. Ingen nye sanger Sanger du har lyttet til sist vises her. Ingen sanger i spillelisten @@ -151,13 +134,5 @@ 10 + sanger 5 + album "Andre" - Vis alle artister - Vis alle album - Vis alle sanger - Vis alle spillelister - Alle \"%s\" artister - Alle \"%s\" albumer - Alle \"%s\" sanger - Alle \"%s\" spillelister %1$s %2$s diff --git a/res/values-nl/plurals.xml b/res/values-nl/plurals.xml index e3a267b5452dda36597790c54c8c6ef1da4973fb..4cb8757e6e8403a45d4baf396630ed9cedd5a61f 100644 --- a/res/values-nl/plurals.xml +++ b/res/values-nl/plurals.xml @@ -16,10 +16,6 @@ limitations under the License. --> - - %d artiest - %d artiesten - %d album %d albums @@ -28,10 +24,6 @@ %d nummer %d nummers - - %d genre - %d genres - %du %du @@ -52,10 +44,6 @@ %d nummer toegevoegd aan wachtrij. %d nummers toegevoegd aan wachtrij. - - %d nummer toegevoegd aan favorieten. - %d nummers toegevoegd aan favorieten. - %d nummer verwijderd. %d nummers verwijderd. diff --git a/res/values-nl/strings.xml b/res/values-nl/strings.xml index 3961421b29f4273cce2f86fd3ae9798338c3d0dd..3082d8f2fd987929fe1965f1a23bea5341c0ea1d 100644 --- a/res/values-nl/strings.xml +++ b/res/values-nl/strings.xml @@ -17,16 +17,12 @@ limitations under the License. --> Muziek - Recent Artiesten Albums Nummers Afspeellijsten - Genres - Nu afspelen Wachtrij Albums - Beste nummers Alle nummers Instellingen Shuffle @@ -37,16 +33,13 @@ Shuffle beste nummers Shuffle recente nummers Shuffle laatst toegevoegd - Alles afspelen Sorteren op Lijst wissen - Recente items wissen Wachtrij wissen Wachtrij opslaan als afspeellijst Equalizer Toevoegen aan afspeellijst Toevoegen aan wachtrij - Verwijderen uit recente Verwijderen uit wachtrij A-Z Z-A @@ -54,8 +47,6 @@ Album Jaar Duur - Datum toegevoegd - Tracklist Aantal nummers Aantal albums Bestandsnaam @@ -76,9 +67,8 @@ Dit kan niet ongedaan worden gemaakt Hiermee worden alle opgeslagen afbeeldingen permanent verwijderd Afbeelding selecteren uit Galerij - Google Zoeken Standaardafbeelding - Oude afbeelding + toestemming VOOR Audio-opname is geweigerd; schakel deze in vanuit Instellingen om muziek-visualisatie in te schakelen Afspelen Volgende afspelen Album afspelen @@ -100,10 +90,7 @@ Herhalen Alles herhalen Eén herhalen - Wachtrij openen - Muziek verkennen \'%s\' ingesteld als beltoon - Naam afspeellijst gewijzigd Opslag Cache wissen Opgeslagen afbeeldingen verwijderen @@ -116,10 +103,7 @@ Muziek: 4 \u00d7 1 Muziek: 4 \u00d7 2 Muziek: 4 \u00d7 2 (alternatief) - Muziek: recent beluisterd Kan equalizer niet openen. - Om muziek van uw computer te kopiëren naar uw apparaat, kunt u een USB-kabel gebruiken. - Uw favoriete nummers worden hier getoond. Geen recente nummers Nummers waar u recent naar hebt geluisterd worden hier getoond. Geen nummers in afspeellijst @@ -150,15 +134,7 @@ 10+ nummers 5+ albums "Overig" - Alle artiesten tonen - Alle albums tonen - Alle nummers tonen - Alle afspeellijsten tonen - Alle \"%s\" artiesten - Alle \"%s\" albums - Alle \"%s\" nummers - Alle \"%s\" afspeellijsten %1$s %2$s Muziek afspelen Achtergrond vervagen - \ No newline at end of file + diff --git a/res/values-or/plurals.xml b/res/values-or/plurals.xml index cafd3431aab512ddde793f61d6c47ef922221caf..565b7027950667cc4808de17f38730a54bc6a846 100644 --- a/res/values-or/plurals.xml +++ b/res/values-or/plurals.xml @@ -16,10 +16,6 @@ limitations under the License. --> - - %d କଳାକାର - %d କଳାକାର - %d ଆଲ୍‍ବମ୍‍ %d ଆଲ୍‍ବମ୍‍ @@ -28,10 +24,6 @@ %d ସଙ୍ଗୀତ %d ସଙ୍ଗୀତ - - %d ଜେନେରେ - %d ଜେନେରେ - %dଘଣ୍ଟା %dh @@ -52,10 +44,6 @@ %d ଗୀତ ଧାଡିରେ ଯୋଗ କରାଯାଇଛି। %d ଗୀତ ଧାଡିରେ ଯୋଗ କରାଯାଇଛି। - - %d ଗୀତ ପସନ୍ଦିଦା େ ଯୋଗ କରାଯାଇଛି। - %d ଗୀତ ପସନ୍ଦିତାସମୂହରେ ଯୋଗ କରାଯାଇଛି। - %d ଗୀତ ବିଲୋପିତ ହୋଇଛି। %d ଗୀତ ବିଲୋପିତ ହୋଇଛି। diff --git a/res/values-or/strings.xml b/res/values-or/strings.xml index c416835ee9e73c0e79d44b75971d42ec2398e83b..2a40aa2a996f9ffd3f54959e043ff7849b424d0a 100644 --- a/res/values-or/strings.xml +++ b/res/values-or/strings.xml @@ -18,16 +18,12 @@ --> ସଙ୍ଗୀତ - ସାମ୍ପ୍ରତିକ କଳାକାରଗଣ ଆଲବମଗୁଡିକ ସଙ୍ଗୀତଗୁଡିକ ଚାଳନାତାଲିକା‌ଗୁଡିକ - ଜେନେରେସ୍‍ - ବର୍ତ୍ତମାନ ଚାଳନ କରନ୍ତୁ ପ୍ଲେ ଧାଡି ଆଲବମଗୁଡିକ - ଶ୍ରେଷ୍ଠ ଗୀତଗୁଡିକ ସମସ୍ତ ସଂଗୀତ ସେଟିଂସ୍ ସଫଲ୍ @@ -38,16 +34,13 @@ ଶୀ‍ର୍ଷ ଟ୍ରାକ୍‍ ସ୍ଥାନ ବଦଳ କରନ୍ତୁ ସମ୍ପ୍ରତି ପ୍ଲେ ସ୍ଥାନ ବଦଳ କରନ୍ତୁ ଶେଷରେ ଯାହା ଯୋଗ ହୋଇଛି ତାହା ସ୍ଥାନ ବଦଳ କରନ୍ତୁ - ସମସ୍ତ ଚାଳନ କରନ୍ତୁ ଦ୍ଵାରା ସର୍ଟ୍ ତାଲିକା ଖାଲି କରନ୍ତୁ - ସମ୍ପ୍ରତି ଖାଲି କରନ୍ତୁ ଧାଡି ଖାଲି କରନ୍ତୁ ଚାଳନତାଲିକାରେ ଧାଡି ସଂରକ୍ଷଣ କରନ୍ତୁ ସମାନକାରୀ ଚାଳନତାଲିକାରେ ଯୋଡନ୍ତୁ ଧାଡି ଯୋଗ କରନ୍ତୁ - ସମ୍ପ୍ରତିରୁ ଅପସାରଣ କରନ୍ତୁ ଧାଡିରୁ ଅପସାରଣ କରନ୍ତୁ A-Z Z-A @@ -55,8 +48,6 @@ ଆଲ୍‍ବମ୍‍ ବ‍ର୍ଷ ଅବଧି - ତାରିଖ ଯୋଗ କରାଯାଇଛି - ଟ୍ରାକ୍‍ ତାଲିକା ଗୀତ ସଂଖ୍ୟା ଆଲ୍‍ବମ୍‍ ସଂଖ୍ୟା ଫାଇଲ୍‌ ନାମ @@ -77,9 +68,7 @@ ଏହା ଅନ୍‍ଡନ୍‍ ହୋଇପାରିବ ନାହିଁ ଏହା କ୍ୟାଚ୍‍ରେ ଥିବା ଚିତ୍ର ପ୍ରବେଶ ‍ସ୍ଥାୟୀ ଭାବେ ବିଲୋପ କରିଦେବ ଗ୍ୟାଲେରୀରୁ ଫଟୋ ପରିବର୍ତ୍ତନ କରନ୍ତୁ - Google ସନ୍ଧାନ ଡିଫଲ୍ଟ ଫଟୋ ବ୍ୟବହାର କରନ୍ତୁ - ପୁରୁଣା ଫଟୋ ବ୍ୟବହାର କରନ୍ତୁ ଚଳାଅ ପରବର୍ତ୍ତୀ ପ୍ଲେ କରନ୍ତୁ ଆଲ୍‍ବମ୍‍ ପ୍ଲେ କରନ୍ତୁ @@ -101,10 +90,7 @@ ପୁନରାବୃତ୍ତି ସମସ୍ତ ପୁନରାବୃତ୍ତି ଏକ ପୁନରାବୃତ୍ତି - ଧାଡି ଖୋଲନ୍ତୁ - ଗୀତ ବ୍ରାଉଜ୍‍ କରନ୍ତୁ \'%s\' ରିଙ୍ଗ୍‍ଟୋନ୍‍ ଭାବେ ସେଟ୍‍ କରନ୍ତୁ - ପ୍ଲେତାଲିକା ପୁନଃନାମ ହୋଇଛି। ଷ୍ଟୋରେଜ୍ କ୍ୟାସେ ବିଲୋପ କରନ୍ତୁ ସମସ୍ତ କ୍ୟାସେର ଚିତ୍ର ଅପସାରଣ କରନ୍ତୁ @@ -117,10 +103,7 @@ ସଙ୍ଗୀତ: 4 \u00d7 1 ସଙ୍ଗୀତ: 4 \u00d7 2 ସଙ୍ଗୀତ: 4 \u00d7 2 (ବିକଳ୍ପ) - ସଙ୍ଗୀତ: ସମ୍ପ୍ରତି ଶୁଣାଯାଇଥିବା ଇକ୍ୱାଲାଇଜର୍‍ ଖୋଲାଯାଇପାରିବ ନାହିଁ। - ସଙ୍ଗୀତ ଆପଣଙ୍କ କମ୍ପ୍ୟୁଟରରୁ ଆପଣଙ୍କ ଡିଭାଇସ୍‍କୁ କପି କରିବା ପାଇଁ, ଏକ USB ତାର ବ୍ୟବହାର କରନ୍ତୁ। - ଆପଣ ପସନ୍ଦିତାସମୂହ ଚିହ୍ନିତ କରିଥିବା ଗୀତଗୁଡିକ ଏଠାରେ ଦେଖାଯିବ। କୌଣସି ସମ୍ପ୍ରତି ଗୀତ ନାହିଁ ସମ୍ପ୍ରତି ଆପଣ ଶୁଣୁଥିବା ଗୀତଗୁଡିକ ଏଠାରେ ପ୍ରଦର୍ଶନ କରିବା। ଚାଳନତାଲିକାରେ କିଛି ଗୀତ ନାହିଁ @@ -151,13 +134,5 @@ 10+ ଗୀତ 5+ ଆଲ୍‍ବମ୍‍ ""ଅନ୍ୟାନ୍ୟ"" - ସମସ୍ତ କଳାକାର ଦେଖାନ୍ତୁ - ସମସ୍ତ ଆଲ୍‍ବମ୍‍ ଦେଖାନ୍ତୁ - ସମସ୍ତ ଗୀତ ଦେଖାନ୍ତୁ - ସମସ୍ତ ପ୍ଲେତାଲିକା ପ୍ରଦର୍ଶନ କରନ୍ତୁ - ସମ୍ସ୍ତ \"%s\" କଳାକାର - ସମ୍ସ୍ତ \"%s\" ଆଲ୍‍ବମ୍‍ - ସମ୍ସ୍ତ \"%s\" ଗୀତ - ସମ୍ସ୍ତ \"%s\" ପ୍ଲେତାଲିକା %1$s %2$s diff --git a/res/values-pl/plurals.xml b/res/values-pl/plurals.xml index ecf05afdbecfc8ce1c50f4912c42fdba67917234..dde360065d4bb9034c21f9c1b786eab0b03a8771 100644 --- a/res/values-pl/plurals.xml +++ b/res/values-pl/plurals.xml @@ -16,12 +16,6 @@ limitations under the License. --> - - %d wykonawca - %d wykonawców - %d wykonawców - %d wykonawców - %d album %d albumy @@ -34,12 +28,6 @@ %d utworów %d utworów - - %d gatunek - %d gatunki - %d gatunków - %d gatunków - %dh %dh @@ -70,12 +58,6 @@ %d utworów dodanych do kolejki. %d utworów dodanych do kolejki. - - %d utwór dodany do ulubionych. - %d utwory dodane do ulubionych. - %d utworów dodanych do ulubionych. - %d utworów dodano do ulubionych. - %d utwór został usunięty. %d utwory zostały usunięte. diff --git a/res/values-pl/strings.xml b/res/values-pl/strings.xml index 3a4980c3e7f35eb48034fdbf5a9d02b16768cbc3..5ed7887ed7fab86e6d436fab8b54d36d94d62fc5 100644 --- a/res/values-pl/strings.xml +++ b/res/values-pl/strings.xml @@ -18,16 +18,12 @@ --> Muzyka - Ostatnio słuchane Wykonawcy Albumy Utwory Playlisty - Gatunki - Teraz odtwarzane Kolejka odtwarzania Albumy - Najlepiej oceniane utwory Wszystkie utwory Ustawienia Losowo @@ -38,16 +34,13 @@ Losuj najlepiej oceniane utwory Losuj ostatnio słuchane Losuj ostatnio dodane - Odtwórz wszystko Sortuj wg Wyczyść listę - Wyczyść ostatnio słuchane Wyczyść kolejkę Zapisz kolejkę odtwarzania jako listę odtwarzania Equalizer Dodaj do playlisty Dodaj do kolejki - Usuń z ostatnio słuchanych Usuń z kolejki A-Z Z-A @@ -55,8 +48,6 @@ Album Rok Czas trwania - Data dodania - Lista utworów Liczba utworów Liczba albumów Nazwa pliku @@ -77,9 +68,7 @@ Operacja nie może zostać cofnięta Grafiki z pamięci podręcznej zostaną trwale usunięte Użyj zdjęcia z galerii - Wyszukiwarka Google Użyj domyślnego zdjęcia - Użyj starego zdjęcia Odtwórz Odtwórz następny Odtwórz album @@ -101,10 +90,7 @@ Powtarzaj Powtarzaj wszystkie Powtarzaj bieżący - Otwórz kolejkę - Przeglądaj muzykę \"%s\" ustawiono jako dzwonek - Zmieniono nazwę playlisty Pamięć Wyczyść pamięć podręczną Usuń wszystkie zapisane grafiki @@ -117,10 +103,7 @@ Muzyka: 4 \u00d7 1 Muzyka: 4 \u00d7 2 Muzyka: 4×2 (alternatywny) - Muzyka: Ostatnio słuchane Equalizer nie może zostać uruchomiony. - Aby skopiować muzykę z komputera do urządzenia, użyj kabla USB. - Tutaj pojawią się utwory oznaczone jako ulubione. Brak ostatnio słuchanych utworów Ostatnio przesłuchane albumy pojawią się tutaj. Zobaczysz je po odtworzeniu kilku utworów. Brak utworów na playliście @@ -151,14 +134,6 @@ 10+ piosenek 5+ Albumów "Inny" - Pokaż wszystkich artystów - Pokaż wszystkie albumy - Pokaż wszystkie utwory - Pokaż wszystkie playlisty - Wszyscy artyści \"%s\" - Wszystkie albumy \"%s\" - Wszystkie piosenki \"%s\" - Wszystkie playlisty \"%s\" %1$s %2$s Odtwarzanie muzyki diff --git a/res/values-pt-rBR/plurals.xml b/res/values-pt-rBR/plurals.xml index 5aa2b747145525383dd2147b9041648f27c6622d..f933a9cf1c0d0871791dc9b53eaeda7a98bef7ae 100644 --- a/res/values-pt-rBR/plurals.xml +++ b/res/values-pt-rBR/plurals.xml @@ -16,10 +16,6 @@ limitations under the License. --> - - %d artista - %d artistas - %d álbum %d álbuns @@ -28,10 +24,6 @@ %d música %d músicas - - %d gênero - %d gêneros - %dh %dh @@ -52,10 +44,6 @@ %d música adicionada à fila. %d músicas adicionadas à fila. - - %d música adicionada aos favoritos. - %d músicas adicionadas aos favoritos. - %d música foi apagada. %d músicas foram apagadas. diff --git a/res/values-pt-rBR/strings.xml b/res/values-pt-rBR/strings.xml index 49312af2e38f78e4faeb837b1a5c4aad6aee64b8..9e94bc44accd32a94b518f0d961ec357aa0057e6 100644 --- a/res/values-pt-rBR/strings.xml +++ b/res/values-pt-rBR/strings.xml @@ -18,16 +18,12 @@ --> Música - Recente Artistas Álbuns Músicas Listas de reprodução - Gêneros - Tocando Fila de reprodução Álbuns - Mais tocadas Todas as músicas Configurações Aleatório @@ -38,16 +34,13 @@ Aleatório nas mais tocadas Aleatório nas tocadas recentemente Aleatório nas últimas adicionadas - Tocar todas Ordenar por Limpar lista - Limpar recentes Limpar fila Salvar fila como lista de reprodução Equalizador Adicionar à lista de reprodução Adicionar à fila - Remover das recentes Remover da fila A-Z Z-A @@ -55,8 +48,6 @@ Álbum Ano Duração - Data adicionada - Lista de faixas Número de músicas Número de álbuns Nome do arquivo @@ -77,9 +68,7 @@ Não pode ser desfeito Isso vai apagar permanentemente o cache de imagens Escolher foto da Galeria - Pesquisa no Google Usar foto padrão - Usar foto antiga Tocar Tocar seguinte Tocar o álbum @@ -101,10 +90,7 @@ Repetir Repetir todas Repetir uma - Abrir fila - Buscar nas músicas \'%s\' foi definido como toque de celular - Lista de reprodução renomeada Armazenamento Apagar cache Remover todas as imagens em cache @@ -118,10 +104,7 @@ Música: 4 \u00d7 1 Música: 4 \u00d7 2 Música: 4 \u00d7 2 (alternativa) - Música: ouvidas recentemente O equalizador não pôde ser aberto. - Para copiar músicas do seu computador para seu dispositivo, use um cabo USB. - As músicas marcadas como favoritas serão exibidas aqui. Não há músicas recentes Músicas ouvidas recentemente serão mostradas aqui. Não há músicas na lista de reprodução @@ -152,14 +135,6 @@ 10 ou mais músicas Mais de 5 álbuns "Outro" - Mostrar todos os artistas - Mostrar todos os álbuns - Mostrar todas as músicas - Mostrar todas as listas de reprodução - Todos os artistas com \"%s\" - Todos os álbuns com \"%s\" - Todas as músicas com \"%s\" - Todas as listas de reprodução com \"%s\" %1$s %2$s Reprodução de música diff --git a/res/values-pt-rPT/plurals.xml b/res/values-pt-rPT/plurals.xml index b9d9c00324a86ae67197c86cf09dd1a45e3167f1..38d505775550915e0dfc64959589b198b14a2aef 100644 --- a/res/values-pt-rPT/plurals.xml +++ b/res/values-pt-rPT/plurals.xml @@ -16,10 +16,6 @@ limitations under the License. --> - - %d artista - %d artistas - %d álbum %d álbuns @@ -28,10 +24,6 @@ %d música %d músicas - - %d género - %d géneros - %dh %dh @@ -52,10 +44,6 @@ %d música adicionada à fila. %d músicas adicionadas à fila. - - %d música adicionada aos favoritos. - %d músicas adicionadas aos favoritos. - %d música foi apagada. %d músicas foram apagadas. diff --git a/res/values-pt-rPT/strings.xml b/res/values-pt-rPT/strings.xml index 1bf3b9184d61b1c8a7d85f936afb3347fa4a4883..92122332ef3f0bdd085b26d0ac80621c5c9b931e 100644 --- a/res/values-pt-rPT/strings.xml +++ b/res/values-pt-rPT/strings.xml @@ -18,16 +18,12 @@ --> Música - Recente Artistas Álbuns Músicas Listas de reprodução - Géneros - A tocar agora Fila de reprodução Álbuns - Top de Músicas Todas as músicas Definições Reproduzir aleatoriamente @@ -38,16 +34,13 @@ Reproduzir Top de músicas aleatoriamente Reproduzir tocadas recentemente aleatoriamente Reproduzir últimas adicionadas aleatoriamente - Reproduzir todas Ordenar por Limpar lista - Limpar recentes Limpar fila Guardar a fila na lista de reprodução Equalizador Adicionar à lista de reprodução Adicionar à fila - Remover das recentes Remover da fila A-Z Z-A @@ -55,8 +48,6 @@ Álbum Ano Duração - Data adicionada - Lista de músicas Número de músicas Número de álbuns Nome do ficheiro @@ -77,9 +68,7 @@ Não pode ser desfeito Isto vai remover permanentemente as imagens em cache Escolher foto da Galeria - Pesquisa no Google Usar foto padrão - Usar foto antiga Reproduzir Reproduzir próxima Reproduzir o álbum @@ -101,10 +90,7 @@ Repetir Repetir todas Repetir uma - Abrir fila - Navegar músicas \'%s\' definida como toque - Mudado o nome da lista de reprodução Armazenamento Apagar cache Eliminar todas as imagens em cache @@ -118,10 +104,7 @@ Música: 4 \u00d7 1 Música: 4 \u00d7 2 Música: 4 \u00d7 2 (alternativo) - Música: recentemente ouvida O equalizador não pôde ser aberto. - Para copiar a música do seu computador para o seu dispositivo, utilize um cabo USB. - Vão ser mostradas aqui as músicas que você marcou como favoritas. Não há músicas recentes Músicas que ouviu recentemente vão ser mostradas aqui. Não há músicas na lista de reprodução @@ -152,14 +135,6 @@ Mais de 10 músicas Mais de 5 álbuns "Outro" - Mostrar todos os artistas - Mostrar todos os álbuns - Mostrar todas as músicas - Mostrar todas as listas de reprodução - Todos os artistas \"%s\" - Todos os álbuns \"%s\" - Todas as músicas \"%s\" - Todas as listas de reprodução \"%s\" %1$s %2$s Reproduzir música diff --git a/res/values-ro/plurals.xml b/res/values-ro/plurals.xml index 4f657dd49d6511759105c1f8b2de9413875d653b..5d1787e318b4e795ac7bd78b57b959e8a23d1ebf 100644 --- a/res/values-ro/plurals.xml +++ b/res/values-ro/plurals.xml @@ -16,11 +16,6 @@ limitations under the License. --> - - %d artist - %d artiști - %d artiști - %d album %d albume @@ -31,11 +26,6 @@ %d melodii %d melodii - - %d gen - %d genuri - %d genuri - %do %do @@ -61,11 +51,6 @@ %d melodii adăugate la coadă. %d melodii adăugate la coadă. - - %d melodie adăugată la Favorite. - %d melodii adăugate la Favorite. - %d melodii adăugate la Favorite. - %d melodie a fost ștearsă. %d melodii au fost șterse. diff --git a/res/values-ro/strings.xml b/res/values-ro/strings.xml index c11b2bce40efd448032bbc4e9a950d05c7a9a518..398f4169ea72aef261fd05de3db8f9a02751aacf 100644 --- a/res/values-ro/strings.xml +++ b/res/values-ro/strings.xml @@ -18,16 +18,12 @@ --> Muzică - Recent Artiști Albume Melodii Liste de redare - Genuri - Rulează acum Coadă de redare Albume - Melodii de top Toate melodiile Setări Amestecare @@ -38,16 +34,13 @@ Amestecă melodiile de top Amestecă melodiile redate recent Amestecă ultimele adăugate - Redă tot Sortare după Curăță lista - Curăță recent Curăță coada Salvați lista pentru redare Egalizator Adaugă la lista de redare Adaugă la coadă - Elimină din recente Elimină din coadă A-Z Z-A @@ -55,8 +48,6 @@ Album An Durată - Data adăugării - Lista de melodii Numărul de melodii Numărul de albume Nume fișier @@ -77,9 +68,8 @@ Această acțiune nu poate fi anulată Aceasta va șterge permanent imaginile păstrate în cache Alege poza din Galerie - Căutare pe Google Utilizare foto implicită - Utilizare foto veche + Permisiunea de înregistrare audio a fost refuzată, activați-o din aplicația Setări pentru a activa vizualizarea muzicii Redare Redă următoarea Redă album @@ -101,10 +91,7 @@ Repetă Repetă toate Repetă una - Deschide coada - Răsfoire muzică \'%s\' este ton de apel - Listă de redare redenumită Stocare Șterge cache-ul Elimină toate imaginile din cache @@ -118,10 +105,7 @@ Muzică: 4 \u00d7 1 Muzică: 4 \u00d7 2 Muzică: 4 \u00d7 2 (alternativ) - Muzică: recent ascultate Egalizatorul nu a putut fi deschis. - Pentru a copia muzică de pe calculator în dispozitivul dvs, folosiți un cablu USB. - Melodiile marcate de dvs ca favorite vor fi afișate aici. Nicio melodie recentă Melodiile redate recent vor fi afișate aici. Nicio melodie în lista de redare @@ -152,14 +136,6 @@ 10+ melodii 5+ albume "Altele" - Arată toți artiștii - Arată toate albumele - Arată toate melodiile - Arată toate listele de redare - Toți \"%s\" artiștii - Toate \"%s\" albumele - Toate \"%s\" melodiile - Toate \"%s\" listele de redare %1$s %2$s Redare muzică diff --git a/res/values-ru/plurals.xml b/res/values-ru/plurals.xml index c662695321c0700c9296dc128ea29519d3c7c295..7ed406e419de3b49b38eddab22992f8ea05f0a66 100644 --- a/res/values-ru/plurals.xml +++ b/res/values-ru/plurals.xml @@ -16,12 +16,6 @@ limitations under the License. --> - - %d исполнитель - %d исполнителя - %d исполнителей - %d исполнителей - %d альбом %d альбома @@ -34,12 +28,6 @@ %d треков %d треков - - %d жанр - %d жанра - %d жанров - %d жанров - %d ч. %d ч. @@ -70,12 +58,6 @@ %d треков добавлены в очередь. %d треков добавлены в очередь. - - %d трек добавлен в избранное. - %d трека добавлены в избранное. - %d треков добавлены в избранное. - %d треков добавлены в избранное. - %d трек удален. %d трека удалены. diff --git a/res/values-ru/strings.xml b/res/values-ru/strings.xml index c8c31ed6dbe6ada91a09b19c62ca502cd88042ab..ddaaad096e35bde56c6a2b4335122ce977aa13fb 100644 --- a/res/values-ru/strings.xml +++ b/res/values-ru/strings.xml @@ -17,16 +17,12 @@ limitations under the License. --> Музыка - Недавние Исполнители Альбомы Треки Плейлисты - Жанры - Сейчас играет Очередь воспроизведения Альбомы - Топ-треки Все треки Настройки Перемешать @@ -37,16 +33,13 @@ Перемешать топ-треки Перемешать недавно воспроизведенные Перемешать последние добавленные - Воспроизвести все Сортировать по Очистить список - Очистить недавние Очистить очередь Сохранить в плейлист Эквалайзер Добавить в плейлист Добавить в очередь - Удалить из недавних Удалить из очереди Алфавиту Алфавиту в обр. порядке @@ -54,8 +47,6 @@ Альбому Году Длительности - Дате добавления - Трек-листу Количеству треков Количеству альбомов Имени файла @@ -76,9 +67,8 @@ Это действие невозможно отменить Это приведет к окончательному удалению записей кэшированных изображений Выбрать из Галереи - Найти в Google Изображение по умолчанию - Исходное изображение + Разрешение на запись звука было отклонено, включите его в настройках устройства, чтобы активировать визуализацию музыки Воспроизвести Воспр. следующим Воспр. альбом @@ -100,10 +90,7 @@ Повтор Повтор всех Повтор трека - Открыть очередь - Обзор музыки Трек «%s» установлен как рингтон - Плейлист переименован Хранилище Очистить кэш Удалить все кэшированные изображения @@ -117,10 +104,7 @@ Музыка: 4 \u00d7 1 Музыка: 4 \u00d7 2 Музыка: 4 \u00d7 2 (альтернативный) - Музыка: недавно прослушанные Не удалось открыть эквалайзер. - Чтобы скопировать музыку с ПК, используйте USB-кабель. - Здесь будут треки, которые вы добавили в избранное. Нет недавних треков Здесь появятся треки, которые вы недавно слушали. Нет треков в плейлисте @@ -151,14 +135,6 @@ Более 10 треков Более 5 альбомов "Другие" - Показать всех исполнителей - Показать все альбомы - Показать все треки - Показать все плейлисты - Все исполнители «%s» - Все альбомы «%s» - Все треки «%s» - Все плейлисты «%s» %1$s %2$s Воспроизведение музыки \ No newline at end of file diff --git a/res/values-sk/plurals.xml b/res/values-sk/plurals.xml index cc5fd6f0e93201097013c3f93d851cb7ea3c4f7f..dfb97413b0f7f5f0e8236527f41f5114104f9dae 100644 --- a/res/values-sk/plurals.xml +++ b/res/values-sk/plurals.xml @@ -16,12 +16,6 @@ limitations under the License. --> - - %d interpret - %d interpreti - %d interpretov - %d interpretov - %d album %d albumy @@ -34,12 +28,6 @@ %d skladieb %d skladieb - - %d žáner - %d žánry - %d žánrov - %d žánrov - %dh %dh @@ -70,12 +58,6 @@ %d skladieb bolo pridaných do poradia. %d skladieb bolo pridaných do poradia. - - %d skladba bola pridaná do obľúbených. - %d skladby boli pridané do obľúbených. - %d skladieb bolo pridaných do obľúbených. - %d skladieb bolo pridaných do obľúbených. - %d skladba bola vymazaná. %d skladby boli vymazané. diff --git a/res/values-sk/strings.xml b/res/values-sk/strings.xml index 9e4ebaf03a9af22fa861698673c8bcd3ba26b120..10101fc8a6e908579534be46237dfe27ad4cf48a 100644 --- a/res/values-sk/strings.xml +++ b/res/values-sk/strings.xml @@ -18,16 +18,12 @@ --> Hudba - Nedávne Interpreti Albumy Skladby Zoznamy skladieb - Žánre - Práve sa prehráva Prehrať poradie Albumy - Najlepšie skladby Všetky skladby Nastavenia Prehrať náhodne @@ -38,16 +34,13 @@ Prehrať najlepšie stopy náhodne Prehrať nedávno prehrávané náhodne Prehrať naposledy pridané náhodne - Prehrať všetky Zoradiť podľa Vyčistiť zoznam - Vyčistiť nedávne Vyčistiť poradie Uložiť poradie do zoznamu skladieb Ekvalizér Pridať do zoznamu skladieb Pridať do poradia - Odstrániť z nedávnych Odstrániť z poradia A-Z Z-A @@ -55,8 +48,6 @@ Albumu Roku Dĺžky - Dátumu pridania - Zoznamu stôp Počtu skladieb Počtu albumov Názvu súboru @@ -77,9 +68,7 @@ Táto akcia sa nedá vrátiť späť Týmto natrvalo odstránite obrázky vo vyrovnávacej pamäti Vybrať fotografiu z Galérie - Vyhľadať pomocou Google Použiť predvolenú fotografiu - Použiť pôvodnú fotografiu Prehrať Prehrať ďalšiu Prehrať album @@ -101,10 +90,7 @@ Opakovať Opakovať všetky Opakovať jednu - Otvoriť poradie - Prehľadávať hudbu Skladba \'%s\' bola nastavená ako vyzváňanie - Zoznam skladieb bol premenovaný Úložisko Vymazať vyrovnávaciu pamäť Odstráni všetky obrázky vo vyrovnávacej pamäti @@ -118,10 +104,7 @@ Hudba: 4 \u00d7 1 Hudba: 4 \u00d7 2 Hudba: 4 \u00d7 2 (alternatívna) - Hudba: nedávno počúvané Nedá sa otvoriť ekvalizér. - Na kopírovanie hudby z vášho počítača do vášho zariadenia použite USB kábel. - Tu budú zobrazené skladby, ktoré ste označili ako obľúbené. Žiadne nedávne skladby Tu budú zobrazené skladby, ktoré ste nedávno počúvali. Žiadne skladby v zozname skladieb @@ -152,14 +135,6 @@ Viac ako 10 skladieb Viac ako 5 albumov "Iné" - Zobraziť všetkých interpretov - Zobraziť všetky albumy - Zobraziť všetky skladby - Zobraziť všetky zoznamy skladieb - Všetko od interpreta \"%s\" - Všetko v albume \"%s\" - Všetky skladby \"%s\" - Všetky v zozname skladieb \"%s\" %1$s %2$s Prehrávanie zvuku diff --git a/res/values-sl/plurals.xml b/res/values-sl/plurals.xml index 388817ec4ada8ba9e3084c3d9f487e8496ebf07a..3ed035d451c12e99d5844a4ccd0d7cd8188ee329 100644 --- a/res/values-sl/plurals.xml +++ b/res/values-sl/plurals.xml @@ -16,12 +16,6 @@ limitations under the License. --> - - %d izvajalec - %d izvajalca - %d izvajalci - %d izvajalcev - %d album %d albuma @@ -34,12 +28,6 @@ %d skladbe %d skladb - - %d žanr - %d žanra - %d žanri - %d žanrov - %d ura %d uri @@ -70,12 +58,6 @@ %d skladbe dodane v čakalno vrsto. %d skladb dodanih v čakalno vrsto. - - %d skladba dodana k priljubljenim. - %d skladbi dodani k priljubljenim. - %d skladbe dodane k priljubljenim. - %d skladb dodanih k priljubljenim. - %d skladba je bila izbrisana. %d skladbi sta bili izbrisani. diff --git a/res/values-sl/strings.xml b/res/values-sl/strings.xml index 85ec81c2358275ea8f4791c04249ea4b4f71a716..d1e3495fadc71814ddeae9ce67ad4f575b36ddea 100644 --- a/res/values-sl/strings.xml +++ b/res/values-sl/strings.xml @@ -18,16 +18,12 @@ --> Glasba - Nedavno Izvajalci Albumi Skladbe Seznami predvajanja - Zvrsti - Trenutno se predvaja Predvajaj čakalno vrsto Albumi - Največkrat predvajane Vse skladbe Nastavitve Premešaj @@ -38,16 +34,13 @@ Premešaj največkrat predvajane Premešaj nedavno predvajane Premešaj nazadnje dodane - Predvajaj vse Razvrsti po Počisti seznam - Počisti nedavne Počisti čakalno vrsto Shrani čakalno vrsto na seznam predvajanja Izenačevalnik Dodaj na seznam predvajanja Dodaj v čakalno vrsto - Odstrani iz nedavnih Odstrani iz čakalne vrste A-Ž Ž-A @@ -55,8 +48,6 @@ Album Leto Trajanje - Datum dodajanja - Seznam skladb številu skladb številu albumov Ime datoteke @@ -77,9 +68,8 @@ Tega ni mogoče razveljaviti To bo trajno izbrisalo vnose predpomnjenih slik Izberite fotografijo iz galerije - Iskanje Google Uporabi privzeto fotografijo - Uporabi staro fotografijo + Dovoljenje za snemanje zvoka je bilo zavrnjeno, omogočite ga iz aplikacijie Nastavitve, da omogočite vizualizatorja glasbe Predvajaj Predvajaj naslednjo Predvajaj album @@ -101,10 +91,7 @@ Ponovi Ponovi vse Ponovi eno - Odpri čakalno vrsto - Prebrskaj glasbo %s nastavljena kot melodijo zvonjenja - Seznam predvajanja preimenovan Shranjevanje Izbriši predpomnilnik Odstrani vse predpomnjene slike @@ -118,10 +105,7 @@ Glasba: 4 \u00d7 1 Glasba: 4 \u00d7 2 Glasba: 4 \u00d7 2 (nadomestno) - Glasba: nedavno poslušano Izenačevalnika ni mogoče odpreti. - Za kopiranje glasbe iz vašega računalnika na vašo napravo uporabite kabel USB. - Skladbe, ki jih označite kot priljubljene, bodo prikazane tukaj. Ni nedavnih skladb Skladbe, ki ste jih nedavno poslušali, bodo prikazane tukaj. Na seznamu predvajanja ni skladb @@ -152,14 +136,6 @@ 10 in več skladb 5 in več albumov "Ostalo" - Prikaži vse izvajalce - Prikaži vse albume - Prikaži vse skladbe - Prikaži vse sezname predvajanja - Vseh \"%s\" izvajalcev - Vseh \"%s\" albumov - Vseh \"%s\" skladb - Vseh \"%s\" seznamov predvajanja %1$s %2$s Predvajanje glasbe diff --git a/res/values-sq/plurals.xml b/res/values-sq/plurals.xml index 5058e008a72a61f01c92861aa998d9b64f1dfd6f..8f1354b990f957b30cee5f9856aedf520ed62ea1 100644 --- a/res/values-sq/plurals.xml +++ b/res/values-sq/plurals.xml @@ -16,10 +16,6 @@ limitations under the License. --> - - %d artist - %d artistë - %d album %d albume @@ -28,10 +24,6 @@ %d këngë %d këngë - - %d zhanër - %d zhanre - %dh %dh @@ -52,10 +44,6 @@ %d këngë u shtua në radhë. %d këngë u shtuan në radhë. - - %d këngë u shtua në listën e këngëve të preferuara. - %d këngë u shtuan në listën e këngëve të preferuara. - %d këngë u fshi. %d këngë u fshinë. diff --git a/res/values-sq/strings.xml b/res/values-sq/strings.xml index 83a6792aa53132d26541d640e91675c98b3ed9c0..dbc8417d4424d3b5fbac5bc00698f253a5b6f362 100644 --- a/res/values-sq/strings.xml +++ b/res/values-sq/strings.xml @@ -18,17 +18,28 @@ --> Muzika - Së fundmi Artistët Albumet Këngët Listat e Këngëve - Zhanret + Luaj Radhën Albumet Të gjitha këngët - Luaji të gjitha + Cilësimet + Përziej + Përziej të gjithë + Përzie listën e luajtjes + Përzie albumin + Përzie artistin + Përzieni pjesët kryesore + Përzie të luajturat kohët e fundit + Përzie të shtuarat kohët e fundit Rendit sipas Hiqe listën + Pastro radhën + Ruaj radhën te lista e luajtjes + Barazues + Shto te lista e luajtjes Shto në radhë Hiq nga radha A-ZH @@ -41,6 +52,8 @@ Numri i albumeve Emri i skedarit Shtuar së fundmi + Luajtur kohët e fundit + Gjurmët e mia kryesore Listë e re Ruaj Anullo @@ -49,27 +62,49 @@ Lista %d Emri i listës së këngëve Dëshiron ta fshish %s? + Pastro të luajturat së fundmi? Zgjidh një foto nga Galeria - Kërkimi në Google Përdor foton e paracaktuar - Përdor foto të vjetër + Leja për regjistrimin e audios u refuzua, aktivizoje atë nga aplikacioni \"Cilësimet\" për të aktivizuar vizualizimin e muzikës Luaj + Luaj tjetër + Luaj Albumin + Më shumë nga artisti Riemërto Fshi + Merr artin e albumit + Merr imazhin e artistit + Hiqe nga më të fundit + Vendose si zile + Hiqeni nga lista e luajtjes Ndërro imazhin + Luaj Vë në pauzë Tjetra E mëparshmja + Përziej + Përziej të gjithë Përsërit Përsëriti të gjitha - Lista u riemërtua + Përsërit një Memoria + Fshij cache Hiqi të gjitha imazhet e ruajtura + Të përgjithshme + Trego vizualizimin e muzikës Zbeh sfondin + Trego tekstin e këngës + Për këngët që kanë një skedar srt + Shkunde për të luajtur + Shkundni pajisjen tuaj për të luajtur këngën tjetër Muzika: 4\u00d7 1 Muzika: 4\u00d7 2 Muzika: 4 \u00d7 2 (alternative) - Muzika: dëgjuar së fundmi + Barazuesi nuk mund të hapej. + Nuk ka këngë të fundit + Këngët që keni dëgjuar kohët e fundit do të shfaqen këtu. + Nuk ka këngë në listën e luajtjes + Për të shtuar këngë në këtë listë luajtje, prekni menynë e opsioneve në një këngë, album ose artist dhe zgjidhni \"Shto në listën e luajtjes\". Viti i panjohur Më pak se 30 sekonda 30 - 60 sekonda @@ -86,14 +121,6 @@ 5 - 9 këngë 10+ këngë 5+ albume - Trego të gjithë artistët - Trego të gjithë albumet - Trego të gjitha këngët - Trego të gjitha listat e këngëve - Të gjithë artistët \"%s\" - Të gjithë albumet \"%s\" - Të gjitha këngët \"%s\" - Të gjitha listat e këngëve \"%s\" %1$s %2$s Luaj muzikë diff --git a/res/values-sr/plurals.xml b/res/values-sr/plurals.xml index 81f66de21f15641e3cd0c6afd1f3c7399166fc9e..e7e0cb2a836bd589e36db82a5670a56910813d62 100644 --- a/res/values-sr/plurals.xml +++ b/res/values-sr/plurals.xml @@ -16,11 +16,6 @@ limitations under the License. --> - - %d уметник - %d уметника - %d уметника - %d албум %d албума @@ -31,11 +26,6 @@ %d песме %d песама - - %d жанр - %d жанра - %d жанрова - %dч %dч @@ -61,11 +51,6 @@ %d песме додате у ред. %d песама додато у ред. - - %d песма додата у омиљене. - %d песме додате у омиљене. - %d песама додато у омиљене. - %d песма је избрисана. %d песме су избрисане. diff --git a/res/values-sr/strings.xml b/res/values-sr/strings.xml index 113a6d937dc04b24a984d5cf349c73717d89a09e..e18cde2b7bd804d6b83a38a0737bd5e5a5dd94cb 100644 --- a/res/values-sr/strings.xml +++ b/res/values-sr/strings.xml @@ -18,16 +18,12 @@ --> Музика - Недавне Извођачи Албуми Песме Плејлисте - Жанрови - Тренутно се слуша Пусти редом Албуми - Најбоље песме Све песме Подешавања Насумично @@ -38,16 +34,13 @@ Насумично најбоље песме Насумично недавно пуштано Насумично последње додато - Пусти све Сортирај по Избриши листу - Избриши недавне Избриши редослед Сачувај редослед као плејлисту Еквилајзер Додај на плејлисту Додај у редослед - Уклони из недавних Уклони из редоследа A-Z Z-A @@ -55,8 +48,6 @@ Албум Година Трајање - Датум додавања - Листа песама Број песама Број албума Име фајла @@ -77,9 +68,7 @@ Ова акција не може бити поништена Ова акција ће трајно уклонити кеширане слике Изабери слику из галерије - Google претрага Користи подразумевану слику - Користи стару слику Пусти Пусти следећу Пусти албум @@ -101,10 +90,7 @@ Понови Понови све Понови једну - Отвори редослед - Тражи музику \'%s\' постављено као тон звона - Плејлиста преименована Складиште Избриши кеш Уклони све кеширане слике @@ -117,10 +103,7 @@ Музика: 4 \u00d7 1 Музика: 4 \u00d7 2 Музика: 4 \u00d7 2 (алтернативно) - Музика: недавно слушано Еквилајзер не може бити отворен. - Да копираш музику са рачунара на твој уређај, користи USB кабал. - Песме које означиш као омиљене ће бити приказане овде. Нема недавних песама Песме које си недавно слушао ће бити приказане овде. Нема песама у плејлисти @@ -151,14 +134,6 @@ 10+ песама 5+ албума "Друго" - Прикажи све уметнике - Прикажи све албуме - Прикажи све песме - Прикажи све плејлисте - Сви \"%s\" уметници - Сви \"%s\" албуми - Све \"%s\" песме - Све \"%s\" плејлисте %1$s %2$s Пуштање музике diff --git a/res/values-sv/plurals.xml b/res/values-sv/plurals.xml index 7699d66b04792527ebb874522e33ea77f1ae8cc4..2d32810ae818b9c8eaf95415a71015ac5ba990c5 100644 --- a/res/values-sv/plurals.xml +++ b/res/values-sv/plurals.xml @@ -16,10 +16,6 @@ limitations under the License. --> - - %d artist - %d artister - %d album %d album @@ -28,10 +24,6 @@ %d låt %d låtar - - %d genre - %d genrer - %dt %dt @@ -52,10 +44,6 @@ %d låt lades till kön. %d låtar lades till kön. - - %d låt lades till Favoriter. - %d låtar lades till Favoriter. - %d låt togs bort. %d låtar togs bort. diff --git a/res/values-sv/strings.xml b/res/values-sv/strings.xml index 64765fca62bdd974248df2349bb149859e49d140..6bd9a720e4dd9000731f4d43b8ef6186e0208f99 100644 --- a/res/values-sv/strings.xml +++ b/res/values-sv/strings.xml @@ -18,16 +18,12 @@ --> Musik - Nya Artister Album Låtar Spellistor - Genrer - Nu spelas Spelkö Album - Bästa låtarna Alla låtar Inställningar Blanda @@ -38,16 +34,13 @@ Slumpa bland topplistan Slumpa senaste spelade Slumpa senaste tillagda låtar - Spela alla Sortera efter Töm lista - Rensa Nya Rensa kö Spara kö till spellistan Equalizer Lägg till spellista Lägg till kö - Ta bort från Nya Ta bort från kö A-Ö Ö-A @@ -55,8 +48,6 @@ Album År Längd - Tillagd - Låtlista Antal låtar Antal album Filnamn @@ -77,9 +68,7 @@ Detta kan inte ångras Detta kommer ta bort cachade bilder permanent Välj foto från Galleri - Sök på Google Använd standardfoto - Använd gammalt foto Spela Spela nästa Spela album @@ -101,10 +90,7 @@ Upprepa Upprepa alla Upprepa en - Öppna kölista - Bläddra bland musik \'%s\' välj som ringsignal - Spellistan omdöpt Lagring Ta bort cache Ta bort alla cachade bilder @@ -117,10 +103,7 @@ Musik: 4 \u00d7 1 Musik: 4 \u00d7 2 Musik: 4 \u00d7 2 (alternativ) - Musik: nyligen lyssnat Equalizern kunde inte öppnas. - Använd en USB-kabel för att kopiera musik från din dator till din enhet. - Låtar som du markerar som Favoriter kommer att synas här. Inga senaste låtar Låtar du lyssnat på nyligen kommer visas här. Inga låtar i spellistan @@ -151,13 +134,5 @@ Fler än 10 låtar Fler än 5 album "Annan" - Visa alla artister - Visa alla album - Visa alla låtar - Visa alla spellistor - Alla \"%s\" artister - Alla \"%s\" album - Alla \"%s\" låtar - Alla \"%s\" spellistor %1$s %2$s diff --git a/res/values-sw600dp/dimens.xml b/res/values-sw600dp/dimens.xml deleted file mode 100644 index c6900a6c8f6071a1acc548b77d2a740501b52c3b..0000000000000000000000000000000000000000 --- a/res/values-sw600dp/dimens.xml +++ /dev/null @@ -1,22 +0,0 @@ - - - - - - 164.0dip - - \ No newline at end of file diff --git a/res/values-ta/plurals.xml b/res/values-ta/plurals.xml index 867cb5ce02e6414a84a13c1f488c28f1bdf1e9ea..b2c632c233e3aeb8b3aeeed8f05f8b8d8658494c 100644 --- a/res/values-ta/plurals.xml +++ b/res/values-ta/plurals.xml @@ -16,10 +16,6 @@ limitations under the License. --> - - %d கலைஞர் - %d கலைஞர்கள் - %d ஆல்பம் %d ஆல்பங்கள் @@ -28,10 +24,6 @@ %d பாடல் %d பாடல்கள் - - %d வகை - %d வகைகள் - %d பாடல் இசைப்பட்டியலில் சேர்க்கப்பட்டது. %d பாடல்கள் இசைப்பட்டியலில் சேர்க்கப்பட்டன. @@ -44,10 +36,6 @@ %d பாடல் சாரையில் சேர்க்கப்பட்டது. %d பாடல்கள் சாரையில் சேர்க்கப்பட்டன. - - %d பாடல் விருப்பங்களில் சேர்க்கப்பட்டது. - %d பாடல்கள் விருப்பங்களில் சேர்க்கப்பட்டன. - %d பாடல் நீக்கப்பட்டது. %d பாடல்கள் நீக்கப்பட்டன. diff --git a/res/values-ta/strings.xml b/res/values-ta/strings.xml index d759a71ca6fde452fd35225835eecb5843cf810e..afb44dd8ef8154e2bb77b7cae18855e3b7cc647f 100644 --- a/res/values-ta/strings.xml +++ b/res/values-ta/strings.xml @@ -18,16 +18,12 @@ --> இசை - சமீபத்தியவை கலைஞர்கள் ஆல்பங்கள் பாடல்கள் இசைப்பட்டியல்கள் - வகைகள் - இப்போது இயங்குகிறது இயக்க சாரை ஆல்பங்கள் - முதன்மையான பாடல்கள் அனைத்து பாடல்கள் அமைப்புகள் குலை @@ -38,16 +34,13 @@ குலை முதன்மையான தடங்கள் குலை சமீபத்திய்ல் இயக்கியதை குலை கடைசியாக சேர்த்ததை - அனைத்தையும் இயக்கு இதன்படி வரிசைப்படுத்து பட்டியலை அழி - சமீபத்தியதை அழி சாரை அழி சாரை இசைப்பட்டியலில் சேமி ஈக்வலைசர் இசைப்பட்டியலுக்குச் சேர் சாரையுடன் சேர் - சமீபத்தியதில் இருந்து நீக்கு சாரையில் இருந்து நீக்கு A-Z Z-A @@ -55,8 +48,6 @@ ஆல்பம் ஆண்டு கால அளவு - சேர்க்கப்பட்ட தேதி - தட பட்டியல் பாடல்களின் எண்ணிக்கை ஆல்பங்களின் எண்ணிக்கை கோப்புப்பெயர் @@ -77,9 +68,7 @@ இதை செயல்நீக்க முடியாது இது நிரந்தரமாக தேக்கிய பட உள்ளீடுகளை நீக்கிவிடும் கேலரியிலிருந்து படத்தைத் தேர்வுசெய்க - Google தேடல் இயல்புநிலை புகைப்படத்தை பயன்படுத்தவும் - பழைய புகைப்படத்தை பயன்படுத்தவும் இயக்கு அடுத்ததை இயக்கு ஆல்பத்தை இயக்கு @@ -101,10 +90,7 @@ மீண்டும் அனைத்தையும் மீண்டும் இயக்கு ஒன்றை மீண்டும் இயக்கு - சாரையை திற - இசையை உலாவு \'%s\' ஐ ரிங்டோனாக அமை - இசைப்பட்டியல் மறுபெயரிடப்பட்டது சேமிப்பிடம் தேக்கத்தை நீக்கு தேக்கப்பட்ட படங்கள் அனைத்தையும் நீக்கு @@ -117,10 +103,7 @@ இசை: 4 \u00d7 1 இசை: 4 \u00d7 2 இசை: 4 \u00d7 2 (மாற்று) - இசை:சமீபத்தில் கேட்டது சமமாக்கியை திறக்க முடியவில்லை. - உங்கள் கணினியில் இருந்து உங்கள் கருவிக்கு இசையை நகலெடுக்க, ஒரு USB கம்பி இழையை பயன்படுத்தவும் - நீங்கள் விருப்பமானது என்று குறிப்பிடும் பாடல்கள் இங்கே காட்டப்படும். சமீபத்திய பாடல்கள் இல்லை நீங்கள் சமீபத்தில் கேட்ட பாடல்கள் இங்கே காட்டப்படும். இசைப்பட்டியலில் பாடல்கள் இல்லை. @@ -151,13 +134,5 @@ 10+ பாடல்கள் 5+ ஆல்பம்கள் ""மற்றவை"" - அனைத்து கலைஞர்களையும் காண்பி - அனைத்து ஆல்பங்களையும் காண்பி - அனைத்து பாடல்களையும் காண்பி - அனைத்து இசைப்பட்டியல்களையும் காண்பி - அனைத்து \”%s\" கலைஞர்கள் - அனைத்து \”%s\" ஆல்பங்கள் - அனைத்து \”%s\" பாடல்கள் - அனைத்து \”%s\" இசைப்பட்டியல்கள் %1$s %2$s diff --git a/res/values-te/plurals.xml b/res/values-te/plurals.xml index 005008ca45bda3715be77edb366c28d376c03c34..eaa0748a177c0cf085e40ae89055581076b6dfaa 100644 --- a/res/values-te/plurals.xml +++ b/res/values-te/plurals.xml @@ -16,10 +16,6 @@ limitations under the License. --> - - %d కళాకారుడు - %d కళాకారులు - %d ఆల్బమ్ %d ఆల్బములు @@ -28,10 +24,6 @@ %d పాట %d పాటలు - - %d శైలి - %d శైలులు - %dh %d @@ -52,10 +44,6 @@ %d పాట నిరీక్షణ క్రమానికి జోడించబడింది. %d పాటలు నిరీక్షణ క్రమానికి జోడించబడ్డాయి. - - %d పాట ఇష్టమైన వాటి జాబితాకు జోడించబడింది. - %d పాటలు ఇష్టమైన వాటి జాబితాకు జోడించబడ్డాయి. - %d పాట తొలగించబడింది. %d పాటలు తొలగించబడ్డాయి. diff --git a/res/values-te/strings.xml b/res/values-te/strings.xml index fce50db2e3f3ded2007e8a26f70cc4fb92a54ead..3074eae89b80d4b40fc036a8ced4b32e4fa77e64 100644 --- a/res/values-te/strings.xml +++ b/res/values-te/strings.xml @@ -18,16 +18,12 @@ --> సంగీతం - ఇటీవలివి ఆర్టిస్టులు ఆల్బమ్‌లు పాటలు ప్లేజాబితాలు - శైలులు - ఇప్పుడు ప్లే చేయబడుతున్నది ప్లే నిరీక్షణ క్రమం ఆల్బమ్‌లు - ఉత్తమ పాటలు అన్ని పాటలు సెట్టింగ్‌లు మార్చు @@ -38,16 +34,13 @@ ఉత్తమ పాటలను కలగాపులగం చేయుము ఇటీవల ప్లే చేయబడిన వాటిని కలగాపులగం చేయుము ఆఖరిన జోడించబడిన వాటిని కలగాపులగం చేయుము - అన్నీ ప్లే చేయండి దీనిద్వారా క్రమబద్ధీకరణ జాబితాను క్లియర్ చేయి - ఇటీవలి వాటిని క్లియర్ చేయుము నిరీక్షణ క్రమాన్ని క్లియర్ చేయుము నిరీక్షణ క్రమాన్ని ప్లేజాబితాకు సేవ్ చేయుము ఈక్వలైజర్ ప్లేజాబితాకు చేర్చు నిరీక్షణ క్రమానికి జోడించుము - ఇటీవలి వాటి నుండి తొలగించుము నిరీక్షణ క్రమం నుండి తొలిగించుము A-Z Z-A @@ -55,8 +48,6 @@ ఆల్బమ్ సంవత్సరం వ్యవధి - చేర్చబడిన తేదీ - ట్రాక్ జాబితా పాటల సంఖ్య ఆల్బముల సంఖ్య ఫైల్ పేరు @@ -77,9 +68,7 @@ ఈ చర్యని రద్దు చేయడం సాధ్యపడదు ఇది శాశ్వతంగా క్యాష్ చేసిన చిత్రాల ఎంట్రీలను తొలిగిస్తుంది గ్యాలరీ నుండి ఫోటోను ఎంచుకోండి - Google శోధన స్వయంసిద్ధ ఫోటోను ఉపయోగించుము - పాత ఫోటోను ఉపయోగించుము ప్లే చేయి తరువాతి దానిని ప్లే చేయుము ఆల్బమును ప్లే చేయుము @@ -101,10 +90,7 @@ పునరావృతం చేయండి అన్నింటినీ పునరావృతం చేయుము ఒకదానిని పునరావృతం చేయుము - నిరీక్షణ క్రమాన్ని తెరువుము - సంగీతాన్ని బ్రౌజ్ చేయుము \'%s\' న్ని రింగ్‌టోనుగా సెట్ చేయుము - ప్లేజాబితా పేరు మార్చబడింది నిల్వ కాషును తొలిగించుము కాష్ చేయబడిన అన్ని చిత్రాలను తొలిగించుము @@ -117,10 +103,7 @@ సంగీతం: 4 \u00d7 1 సంగీతం: 4 \u00d7 2 సంగీతం: 4 \u00d7 2 (ప్రత్యామ్నాయ) - సంగీతం: ఇటీవల విన్నవి ఈక్వలైజరును తెరవడం సాధ్యపడలేదు. - మీ కంప్యూటర్ నుండి మీ యొక్క పరికరానికి సంగీతాన్ని కాపీ చేసేందుకు, USB కేబులును ఉపయోగించండి. - మీరు ఇష్టమైనవిగా గుర్తించిన పాటలు ఇక్కడ చూపించబడతాయి. ఇటీవలి పాటలు ఏమీ లేవు మీరు ఇటీవల విన్న పాటలు ఇక్కడ చూపించబడతాయి. ప్లేజాబితాలో పాటలు లేవు @@ -151,13 +134,5 @@ 10+ పాటలు 5+ ఆల్బములు ""ఇతర"" - అందరు కళాకారులను చూపుము - అన్ని ఆల్బములను చూపుము - అన్ని పాటలను చూపుము - అన్ని ప్లేజాబితాలను చూపుము - అందరు \"%s\" కళాకారులు - అన్ని \"%s\" ఆల్బములు - అన్ని \"%s\" పాటలు - అన్ని \"%s\" ప్లేజాబితాలు %1$s %2$s diff --git a/res/values-th/plurals.xml b/res/values-th/plurals.xml index e307291f732fed05e9b7c9c689d76faf5d297867..e34dd6cb2f2a0be4218a5fc63181f52bdcdd35a3 100644 --- a/res/values-th/plurals.xml +++ b/res/values-th/plurals.xml @@ -16,18 +16,12 @@ limitations under the License. --> - - %d ศิลปิน - %d อัลบั้ม %d เพลง - - %d ประเภท - %dชม. @@ -43,9 +37,6 @@ %d เพลงถูกเพิ่มเข้าในคิว - - %d เพลงถูกเพิ่มในรายการโปรด - %d เพลงถูกลบ diff --git a/res/values-th/strings.xml b/res/values-th/strings.xml index 1b242adb6914f83fe8883b077c3c61c658b4c943..d950bbdd8185ea923dde2b5354b351945f742dfd 100644 --- a/res/values-th/strings.xml +++ b/res/values-th/strings.xml @@ -18,16 +18,12 @@ --> เพลง - ล่าสุด ศิลปิน อัลบั้ม เพลง รายการเพลง - ประเภท - กำลังเล่น คิวเล่น อัลบั้ม - เพลงยอดนิยม เพลงทั้งหมด การตั้งค่า สลับ @@ -38,16 +34,13 @@ สลับแทรคยอดนิยม สลับเพลงที่เล่นล่าสุด สลับเพิ่มล่าสุด - เล่นทั้งหมด เรียงโดย ล้างรายการ - ล้างรายการล่าสุด ล้างคิว บันทึกคิวไปยังรายการที่จะเล่น Equalizer เพิ่มไปยังรายการเพลง เพิ่มไปยังคิว - นำออกจากรายการล่าสุด ลบออกจากคิว A-Z Z-A @@ -55,8 +48,6 @@ อัลบั้ม ปี ระยะเวลา - วันที่เพิ่ม - รายการแทร็ค จำนวนเพลง จำนวนอัลบั้ม ชื่อไฟล์ @@ -77,9 +68,7 @@ การกระทำนี้ไม่สามารถยกเลิกได้ การกระทำนี้จะลบรูปภาพที่แคชอย่างถาวร เลือกรูปจากแกลเลอรี - ค้นหาด้วย Google เลือกรูปเริ่มต้น - ใช้รูปเก่า เล่น เล่นรายการถัดไป เล่นอัลบั้ม @@ -101,10 +90,7 @@ ซ้ำ เล่นซ้ำทั้งหมด ซ้ำหนึ่งครั้ง - เปิดคิว - เรียกดูเพลง \'%s\' ตั้งเป็นเสียงเรียกเข้า - เปลี่ยนชื่อรายการเพลง แหล่งเก็บข้อมูล ล้างแคช ลบรูปที่แคชทั้งหมดออก @@ -118,10 +104,7 @@ เพลง: 4 \u00d7 1 เพลง: 4 \u00d7 2 เพลง: 4 \u00d7 2 (สลับ) - เพลง: ที่ฟังเมื่อเร็ว ๆ นี้ ไม่สามารถเปิด equalizer ได้ - ในการคัดลอกเพลงจากคอมพิวเตอร์ไปยังอุปกรณ์ ให้ใช้สาย USB - เพลงที่ทำเป็นรายการโปรดจะแสดงที่นี่ ไม่มีเพลงล่าสุด เพลงที่ฟังล่าสุดจะแสดงที่นี่ ไม่มีเพลงในรายการที่เล่น @@ -152,14 +135,6 @@ 10+ เพลง 5+ อัลบั้ม "อื่น ๆ" - แสดงศิลปินทั้งหมด - แสดงอัลบั้มทั้งหมด - แสดงเพลงทั้งหมด - แสดงรายการที่เล่นทั้งหมด - ศิลปิน \"%s\" ทั้งหมด - อัลบั้ม \"%s\" ทั้งหมด - เพลง \"%s\" ทั้งหมด - รายการเพลง \"%s\" ทั้งหมด %1$s %2$s เล่นเพลง diff --git a/res/values-tr/plurals.xml b/res/values-tr/plurals.xml index 14e632507768cbd177fcc513c3e06c30a43fc9e7..a5b698ff574ae0b052b1c60dbdb9cacb81edcdd1 100644 --- a/res/values-tr/plurals.xml +++ b/res/values-tr/plurals.xml @@ -16,10 +16,6 @@ limitations under the License. --> - - %d sanatçı - %d sanatçı - %d albüm %d albüm @@ -28,10 +24,6 @@ %d şarkı %d şarkı - - %d tür - %d tür - %dsa %dsa @@ -52,10 +44,6 @@ %d şarkı kuyruğa eklendi. %d şarkı kuyruğa eklendi. - - %d şarkı favorilere eklendi. - %d şarkı favorilere eklendi. - %d şarkı silindi. %d şarkı silindi. diff --git a/res/values-tr/strings.xml b/res/values-tr/strings.xml index 8413a7a72ab1ea6310bcf2970da738a1f8a51759..c3f01a8184b8e7bcab1d27727e2934aad6f64380 100644 --- a/res/values-tr/strings.xml +++ b/res/values-tr/strings.xml @@ -18,16 +18,12 @@ --> Müzik - Son çalınanlar Sanatçılar Albümler Şarkılar Çalma listeleri - Türler - Şimdi Çalınıyor Kuyruğu Çal Albümler - Üst Şarkılar Tüm Şarkılar Ayarlar Karıştır @@ -38,16 +34,13 @@ En çok dinlenenleri karıştır Son çalınanları karıştır Son eklenenleri karıştır - Tümünü çal Sıralama ölçütü: Listeyi temizle - Sonkileri temizle Kuyruğu sil Kuyruğu çalma listesine kaydet Ekolayzer Çalma listesine ekle Kuyruğa ekle - Sonkilerden kaldır Kuyruktan çıkar A-Z Z-A @@ -55,8 +48,6 @@ Albüm Yıl Süre - Eklenme tarihi - Parça listesi Şarkı sayısı Albüm sayısı Dosya adı @@ -77,9 +68,8 @@ Bu işlem geri alınamaz Bu, önbelleğe alınmış resimleri kalıcı olarak silecek Galeriden fotoğraf seç - Google arama Varsayılan fotoğrafı kullan - Eski fotoğrafı kullan + Ses kayıt izni reddedildi, Müzik görselleştirmeyi Ayarlar uygulamasından açınız Çal Sonrakini çal Albümü oynat @@ -101,10 +91,7 @@ Tekrarla Tümünü tekrarla Birini tekrarla - Kuyruğu aç - Müziğe gözat \'%s\' zil sesi olarak ayarlandı - Çalma listesi yeniden adlandırıldı Depolama Önbelleği sil Ön belleğe alınmış tüm resimleri sil @@ -118,10 +105,7 @@ Müzik: 4 \u00d7 1 Müzik: 4 \u00d7 2 Müzik: 4 \u00d7 2 (değiştir) - Müzik: son zamanlarda dinlenen Ekolayzer açılamadı. - Bilgisayarınızdan cihazınıza müzik kopyalamak için USB kablo kullanın. - Favori işaretlediğiniz şarkılar burada gözükecek. Son çalınan şarkı yok Son zamanlarda dinlediğiniz şarkılar burada gösterilecek. Çalma listesinde şarkı yok @@ -152,14 +136,6 @@ 10+ şarkı 5+ albüm "Diğer" - Tüm sanatçıları göster - Tüm albümleri göster - Tüm şarkıları göster - Tüm listeleri göster - Tüm \"%s\" sanatçıları - Tüm \"%s\" albümleri - Tüm \"%s\" şarkıları - Tüm \"%s\" çalma listeleri %1$s %2$s Müzik çalma diff --git a/res/values-ug/strings.xml b/res/values-ug/strings.xml index b841eb42cb9e1cb70b905f56dc3529a55d48f4aa..ff0d40d3cf6f237a92c767c0f01143b29e3a4621 100644 --- a/res/values-ug/strings.xml +++ b/res/values-ug/strings.xml @@ -18,16 +18,12 @@ --> نەغمە - يېقىنقى سەنئەتكار ئالبۇم ناخشا چالىدىغان تىزىم - ئېقىم - چېلىۋاتىدۇ چالىدىغان ئۆچىرەت ئالبۇم - مودا ناخشىلار ھەممە ناخشا تەڭشەكلەر تەرتىپسىز @@ -38,16 +34,13 @@ تەرتىپسىز مودا ناخشىلار تەرتىپسىز يېقىندا قويۇلغان تەرتىپسىز يېقىندا قوشۇلغان - ھەممىنى قويۇش تەرتىپى تىزىملىكنى تازىلاش - يېقىنقىنى تازىلاش ئۆچىرەتنى تازىلاش سەپنى قويۇش تىزىملىكىگە قوشۇش تەڭشىگۈچ چالىدىغان تىزىمغا قوش ئۆچرەتكە قوشۇش - يېقىنقىدىن چىقىرىۋېتىش ئۆچرەتتىن چىقىرىۋېتىش A-Z Z-A @@ -55,8 +48,6 @@ ئالبۇم يىل داۋاملىشىش ۋاقتى - قوشقان ۋاقىت - ناخشا تىزىمى ناخشا سانى ناخشا توپلىمى سانى ھۆججەت ئىسمى @@ -77,9 +68,7 @@ بۇنىڭدىن يېنىۋالغىلى بولمايدۇ بۇ مەشغۇلات غەملەنگەن سۈرەت تۈرلىرىنى مەڭگۈلۈك ئۆچۈرۈۋېتىدۇ رەسىم يىغقۇچتىن سۈرەت تاللاڭ - Google ئىزدەش كۆڭۈلدىكى سۈرەتنى ئىشلەت - كونا سۈرەتنى ئىشلىتىش قويۇش كېيىنكىنى چال پىلاستىنكىنى قويۇش @@ -101,10 +90,7 @@ قايتىلاش ھەممىنى قايتىلاش بىرنى قايتىلاش - سەپنى ئېچىش - مۇزىكا كۆرۈش %s نى قوڭغۇراق ئاۋازىغا تەڭشە - چالىدىغان تىزىم ئاتى ئۆزگەرتىلدى ساقلىغۇچ غەملەكنى تازىلاش غەملەنگەن ھەممە سۈرەتلەرنى چىقىرىۋەت @@ -117,10 +103,7 @@ مۇزىكا: 4 \u00d7 1 مۇزىكا: 4 \u00d7 2 مۇزىكا: 4 \u00d7 2 (نۆۋەتلىشىدۇ) - يېقىندا قويۇلغان مۇزىكا تەڭشىگۈچنى ئاچالمىدى. - سىز USB سىمى ئارقىلىق نەغمىنى كومپيۇتېرىڭىزدىن ئۈسكۈنىگە كۆچۈرۈڭ. - سىز يىغقۇچقا قوشقان ناخشا بۇ جايدا كۆرۈنىدۇ. يېقىنقى مۇزىكا يوق بۇ يەردە سىز يېقىندا قويغان مۇزىكىلار كۆرۈنىدۇ. تىزىملىكتە مۇزىكا يوقكەن @@ -151,13 +134,5 @@ 10+ نەغمە ناخشا 5+ پىلاستىنكا "باشقا" - بارلىق ئارتىسنى كۆرسىتىش - بارلىق پىلاستىنكىنى كۆرسىتىش - بارلىق ناخشىنى كۆرسىتىش - بارلىق قويۇش تىزىملىكىنى كۆرسىتىش - بارلىق \"%s\" ئارتىس - بارلىق \"%s\" پىلاستىنكا - بارلىق \"%s\" ناخشا - بارلىق \"%s\" قويۇش تېزىملىكى - %1$d سائەت %2$d مىنۇت + %1$s سائەت %2$s مىنۇت diff --git a/res/values-uk/strings.xml b/res/values-uk/strings.xml index cc58660cb6c0a3a34ffe977995e241410d3aed6a..9890fc78f8e900a974f339624a73fc429008ed2b 100644 --- a/res/values-uk/strings.xml +++ b/res/values-uk/strings.xml @@ -18,16 +18,12 @@ --> Музика - Нещодавні Виконавці Альбоми Композиції Списки відтворення - Жанри - Зараз грає Відтворити чергу Альбоми - Топ-композиції Всі композиції Налаштування Перемішати @@ -38,16 +34,13 @@ Перемішати топ-композицій Перемішати нещодавно відтворені Перемішати останні додані - Відтворити усе Сортувати за Очистити список - Очистити нещодавні Очистити чергу Зберегти чергу до списку відтворення Еквалайзер Додати до списку відтворення Додати до черги - Видалити з нещодавніх Видалити з черги А-Я Я-А @@ -55,8 +48,6 @@ Альбом Рік Тривалість - Дата додавання - Трек-лист Кількість пісень Кількість альбомів Назва файлу @@ -77,9 +68,7 @@ Цю дію не можна відмінити Це призведе до остаточного видалення записів кешованих зображень Вибрати фото з галереї - Пошук Google Використовувати типове фото - Використовувати старе фото Грати Грати наступну Відтворити альбом @@ -101,10 +90,7 @@ Повторення Повторити все Повторити одну - Відкрити чергу - Огляд музики «%s» встановити як мелодію дзвінка - Список відтворення перейменовано Сховище Видалити кеш Видалити всі кешовані зображення @@ -117,10 +103,7 @@ Музика: 4 \u00d7 1 Музика: 4 \u00d7 2 Музика: 4 \u00d7 2 (альтернативний) - Музика: нещодавно прослухані Неможливо відкрити еквалайзер. - Використовуйте USB-кабель для копіювання музики з комп’ютера. - Тут відображатимуться улюблені пісні. Немає останніх композицій Пісні, які ви слухали нещодавно, з\'являться тут. Немає пісень у списку відтворення @@ -151,13 +134,5 @@ 10 + пісні 5 + альбоми "Інші" - Показати всіх виконавців - Показати всі альбоми - Показати всі композиції - Показати всі списки відтворення - Всі \"%s\" виконавців - Всі \"%s\" альбомів - Всі \"%s\" пісень - Усі \"%s\" списків відтворення %1$s %2$s diff --git a/res/values-vi/plurals.xml b/res/values-vi/plurals.xml index 055931832849a1c1e574624a25080fccc10ecde5..889eef9a0f039864c53dcd7af68a9270b6609f45 100644 --- a/res/values-vi/plurals.xml +++ b/res/values-vi/plurals.xml @@ -16,18 +16,12 @@ limitations under the License. --> - - %d nghệ sĩ - %d album %d bài hát - - %d thể loại - %dgiờ @@ -43,9 +37,6 @@ %d bài hát đã thêm vào hàng đợi. - - %d bài hát đã thêm vào yêu thích. - %d bài hát đã bị xóa. diff --git a/res/values-vi/strings.xml b/res/values-vi/strings.xml index b50c81316b4995e4fc85c0401b2ccbd99512cf8c..23b5386fc768df35ba45b0052e7bd3bb404e6901 100644 --- a/res/values-vi/strings.xml +++ b/res/values-vi/strings.xml @@ -18,16 +18,12 @@ --> Nhạc - Gần đây Nghệ sĩ Album Bài hát Danh sách phát - Thể loại - Đang phát Phát danh sách chờ Album - Bài hát thường nghe Tất cả bài hát Cài đặt Phát ngẫu nhiên @@ -38,16 +34,13 @@ Phát ngẫu nhiên bài hát thường nghe Phát ngẫu nhiên những bài hát nghe gần đây Phát ngẫu nhiên những bài hát vừa thêm - Phát tất cả Xếp theo Xoá danh sách - Xoá danh sách nghe gần đây Xoá danh sách chờ Lưu hàng chờ vào danh sách phát Bộ chỉnh âm Thêm vào danh sách phát Thêm vào danh sách chờ - Xoá khỏi danh sách nghe gần đây Xoá khỏi danh sách chờ A-Z Z-A @@ -55,8 +48,6 @@ Album Năm Thời lượng - Ngày thêm - Danh sách bài hát Số của bài hát Số của album Tên tập tin @@ -77,9 +68,7 @@ Không thể hoàn tác điều này Điều này sẽ xoá vĩnh viễn các mục nhập ảnh đã lưu trong bộ nhớ đệm Chọn ảnh từ Bộ sưu tập - Tìm bằng Google Dùng ảnh mặc định - Dùng ảnh cũ Phát Phát tiếp theo Phát album @@ -101,10 +90,7 @@ Lặp lại Lặp lại tất cả Lặp lại một bài hát - Mở danh sách chờ - Duyệt nhạc \'%s\' được đặt làm nhạc chuông - Đã đổi tên danh sách phát Lưu trữ Xoá bộ nhớ đệm Xoá tất cả ảnh đã có trong bộ nhớ đệm @@ -117,10 +103,7 @@ Nghe nhạc: 4 \u00d7 1 Nghe nhạc: 4 \u00d7 2 Nghe nhạc: 4 \u00d7 2 (kiểu khác) - Nghe nhạc: đã nghe gần đây Không thể mở bộ chỉnh âm. - Để chép nhạc từ máy tính sang thiết bị, hãy dùng cáp USB. - Bài hát bạn đã đánh dấu là yêu thích sẽ hiện tại đây. Không có bài hát nào nghe gần đây Bài hát bạn đã nghe gần đây sẽ hiện tại đây. Không có bài hát nào trong danh sách phát @@ -151,14 +134,6 @@ 10 bài hát trở lên 5 album trở lên "Khác" - Hiện tất cả nghệ sĩ - Hiện tất cả album - Hiện tất cả bài hát - Hiện tất cả danh sách phát - Tất cả về nghệ sĩ \"%s\" - Tất cả về album \"%s\" - Tất cả về bài hát \"%s\" - Tất cả về danh sách phát \"%s\" %1$s %2$s Điều khiển nhạc diff --git a/res/values-zh-rCN/plurals.xml b/res/values-zh-rCN/plurals.xml index 1bfbc03ff7a1d77ee8e7b7b50c1587a6ebed9b04..7aec9babee4c162b663a471978d46e46e83f5e7e 100644 --- a/res/values-zh-rCN/plurals.xml +++ b/res/values-zh-rCN/plurals.xml @@ -16,18 +16,12 @@ limitations under the License. --> - - %d 位艺术家 - %d 张专辑 %d 首歌曲 - - %d 种类型 - %d 小时 @@ -43,9 +37,6 @@ %d 首歌曲已添加到队列。 - - 已添加 %d 首歌曲到收藏夹。 - 已删除 %d 首歌曲。 diff --git a/res/values-zh-rCN/strings.xml b/res/values-zh-rCN/strings.xml index 49c0daba1149714d89cc15d9324d853a1e946105..80231a5174e799bbac1f18b65d6e8f2a75bfed3a 100644 --- a/res/values-zh-rCN/strings.xml +++ b/res/values-zh-rCN/strings.xml @@ -18,16 +18,12 @@ --> 音乐 - 最近播放 艺术家 专辑 歌曲 播放列表 - 类型 - 正在播放 播放队列 专辑 - 热门歌曲 所有歌曲 设置 随机播放 @@ -38,16 +34,13 @@ 随机最热门歌曲 随机最近播放的歌曲 随机最后添加的歌曲 - 全部播放 排序方式 清除列表 - 清除最近播放列表 清除队列 保存队列到播放列表 均衡器 添加到播放列表 添加到队列 - 从最近播放列表移除 从队列移除 A-Z Z-A @@ -55,8 +48,6 @@ 专辑 发行年份 长度 - 日期已添加 - 曲目列表 歌曲数量 专辑数量 文件名 @@ -77,9 +68,8 @@ 此操作不能被撤消 这将永久删除缓存的图像 从图库中选择照片 - Google 搜索 使用默认照片 - 使用旧照片 + 录音权限被拒绝,从设置中启用它以启用音乐可视化 播放 播放下一首 播放专辑 @@ -101,10 +91,7 @@ 重复 全部重复 单曲重复 - 打开队列 - 浏览音乐 设置“%s”为铃声 - 播放列表已被重命名 存储 清除缓存 清除所有缓存的图像 @@ -118,10 +105,7 @@ 音乐:4 \u00d7 1 音乐:4 \u00d7 1 音乐:4 \u00d7 2 (交替) - 最近听过的音乐 无法打开均衡器。 - 请使用 USB 数据线把音乐从您的计算机复制到您的设备中。 - 您标记为收藏的歌曲将在这里显示。 没有最近的歌曲 这里会显示您最近听过的歌曲。 播放列表中没有歌曲 @@ -152,14 +136,6 @@ 10+ 首歌曲 5+ 张专辑 "其他" - 显示所有艺术家 - 显示所有专辑 - 显示所有歌曲 - 显示所有播放列表 - 所有的 \"%s\" 艺术家 - 所有的 \"%s\" 专辑 - 所有的 \"%s\" 歌曲 - 所有的 \"%s\" 播放列表 %1$s %2$s 音乐播放 diff --git a/res/values-zh-rHK/plurals.xml b/res/values-zh-rHK/plurals.xml index da4ef6f435a269499912bcdad42868275c640d60..9d89c1f0054ab586416fd0b87c45cc7c0aff9d80 100644 --- a/res/values-zh-rHK/plurals.xml +++ b/res/values-zh-rHK/plurals.xml @@ -16,9 +16,6 @@ limitations under the License. --> - - %d 種內容類型 - %d 小時 @@ -34,9 +31,6 @@ %d 首歌曲已新增至佇列。 - - %d 首歌曲已新增至最愛。 - %d 首歌曲已刪除。 diff --git a/res/values-zh-rHK/strings.xml b/res/values-zh-rHK/strings.xml index c8efcd6f6ae982d409addc9e996c91c0a9443970..5e4ec8beb01dd2e489942e1ffe4777090df9504f 100644 --- a/res/values-zh-rHK/strings.xml +++ b/res/values-zh-rHK/strings.xml @@ -17,13 +17,9 @@ limitations under the License. --> - 最近播放 歌曲 播放清單 - 內容類型 - 正在播放 播放佇列 - 熱門歌曲 所有歌曲 設定 隨機播放 @@ -34,15 +30,12 @@ 隨機播放熱門歌曲 隨機播放最近播放過的歌曲 隨機播放最近新增的歌曲 - 播放所有歌曲 排序依據 清除清單 - 清除最近播放 清除佇列 等化器 新增至播放清單 新增至佇列 - 從最近播放中移除 從佇列中移除 A-Z Z-A @@ -50,8 +43,6 @@ 專輯 年份 持續時間 - 已加入日期 - 曲目清單 歌曲數量 檔案名稱 最後新增 @@ -70,9 +61,7 @@ 此操作無法復原 這將永久刪除快取圖像項 從圖片庫中選擇相片 - Google 搜尋 使用預設相片 - 使用舊圖片 播放 播放下一首 播放專輯 @@ -93,9 +82,6 @@ 重複播放 全部重複播放 單曲重複播放 - 打開佇列 - 瀏覽音樂 - 已重新命名播放清單 儲存空間 刪除快取 移除所有快取圖像 @@ -108,10 +94,7 @@ 音樂:4 \u00d7 1 音樂:4 \u00d7 2 音樂:4 \u00d7 2(交替) - 音樂:最近聽過 無法打開等化器。 - 使用 USB 連接線將音樂從電腦複製至裝置。 - 您標記為最愛的歌曲將在這裏顯示。 無最近播放的歌曲 您最近聽過的歌曲將在這裏顯示。 播放清單中沒有歌曲 @@ -142,13 +125,5 @@ 10 首以上歌曲 5 張以上專輯 "其他" - 顯示所有演出者 - 顯示所有專輯 - 顯示所有歌曲 - 顯示所有播放清單 - 所有「%s」演出者 - 所有「%s」專輯 - 所有「%s」歌曲 - 所有「%s」播放清單 %1$s %2$s diff --git a/res/values-zh-rTW/plurals.xml b/res/values-zh-rTW/plurals.xml index 0e1e6f403189b69077005657d117c7c2ee7580ef..2751d6509a9850ed7911d9536a8179ea26a7a366 100644 --- a/res/values-zh-rTW/plurals.xml +++ b/res/values-zh-rTW/plurals.xml @@ -16,18 +16,12 @@ limitations under the License. --> - - %d 位演出者 - %d 張專輯 %d 首樂曲 - - %d 種類型 - %d 小時 @@ -43,9 +37,6 @@ 已新增 %d 首樂曲至佇列。 - - 已新增 %d 首樂曲至最愛。 - 已刪除 %d 首樂曲。 diff --git a/res/values-zh-rTW/strings.xml b/res/values-zh-rTW/strings.xml index 37a4b22c997d067b5d51eb0487843655e946da9c..f40b94fbccecac8acd55ee1f00c09bdb7016e256 100644 --- a/res/values-zh-rTW/strings.xml +++ b/res/values-zh-rTW/strings.xml @@ -18,16 +18,12 @@ --> 音樂 - 最近播放 演出者 專輯 樂曲 播放清單 - 類型 - 現正播放 播放佇列 專輯 - 熱門樂曲 所有樂曲 設定 隨機播放 @@ -38,16 +34,13 @@ 隨機播放熱門樂曲 隨機最近播放樂曲 隨機播放最近新增樂曲 - 全部播放 排序方式 清除清單 - 清除最近 清除佇列 將佇列儲存至播放清單 等化器 新增至播放清單 新增至佇列 - 從最近播放清單移除 從佇列移除 遞增排序 遞減排序 @@ -55,8 +48,6 @@ 專輯 年份 長度 - 新增日期 - 曲目清單 樂曲數量 專輯數量 檔案名稱 @@ -77,9 +68,7 @@ 這將無法復原 這將永久刪除已快取的影像 從相簿選擇相片 - Google 搜尋 使用預設相片 - 使用舊的相片 播放 播放下一首 播放專輯 @@ -101,15 +90,13 @@ 循環 全部循環 單曲循環 - 開啟佇列 - 瀏覽音樂 將「%s」設為鈴聲 - 已重新命名播放清單 儲存 清除快取 移除所有已快取的影像 一般 顯示音樂視覺效果 + 模糊背景 顯示歌詞 有 srt 檔的樂曲 搖動播放 @@ -117,10 +104,7 @@ 音樂:4 \u00d7 1 音樂:4 \u00d7 2 音樂:4 \u00d7 2 (備用) - 音樂:最近聽過的 無法開啟等化器。 - 請透過 USB 傳輸線從電腦複製音樂到您的裝置。 - 您標示為最愛的樂曲將會顯示在這裡。 沒有最近播放的樂曲 最近聽過的樂曲將會顯示在這裡。 播放清單中沒有樂曲 @@ -151,14 +135,6 @@ 超過 10 首樂曲 超過 5 張專輯 "其他" - 顯示所有演出者 - 顯示所有專輯 - 顯示所有樂曲 - 顯示所有播放清單 - 所有含「%s」的演出者 - 所有含「%s」 的專輯 - 所有含 「%s」的樂曲 - 所有含「%s」的播放清單 %1$s %2$s 音樂播放 diff --git a/res/values/attrs.xml b/res/values/attrs.xml index 126c35d4c4cbce6bc2b25fc3ab91b44a3bd45ad0..585d4686a61a2d04348efa66121ae31918f38305 100644 --- a/res/values/attrs.xml +++ b/res/values/attrs.xml @@ -34,4 +34,14 @@ + + + + + + + + + + diff --git a/res/values/cm_colors.xml b/res/values/cm_colors.xml index 523932718ae346a6de8c1535e9de7388ce958940..a2a110f87376eb0a1219c1736577b02f2043ae26 100644 --- a/res/values/cm_colors.xml +++ b/res/values/cm_colors.xml @@ -15,6 +15,9 @@ limitations under the License. --> + + #323c46 + @color/purple @color/blue diff --git a/res/values/colors.xml b/res/values/colors.xml index d6c53c7f448a07f94429aa6c746ba663c28d034f..0cf0ed6ae024c8609f51478a19cdd92487036293 100644 --- a/res/values/colors.xml +++ b/res/values/colors.xml @@ -1,12 +1,13 @@ - @color/accent + @color/color_default_icon - #333333 - #fafafa + #000000 + #ffffff @color/color_default_gray1 @color/color_default_gray2 #9C27B0 @@ -60,19 +62,22 @@ #00796B @color/color_default_blue2 + + @color/primary_text + @color/primary_text + @color/background_color @color/primary_text @color/secondary_text - @android:color/transparent + #00000000 @color/primary_dark @color/primary_text - @color/secondary_text @color/accent @color/primary_text @@ -81,12 +86,15 @@ @color/primary_text @color/secondary_text - @color/accent + @color/color_default_icon @color/color_default_gray1 @color/foreground_color + + @color/primary_text + @color/background_color @color/primary_text @@ -110,7 +118,8 @@ @color/color_default_view_on_accent - @color/accent + @color/color_default_icon + @color/accent @color/color_default_view_on_accent diff --git a/res/values/dimens.xml b/res/values/dimens.xml index 4a8a22f45b3e0679ea08fce8a6f3b6c5289d532c..61f043fb34d20ec523e09f4c654406bc2424e528 100644 --- a/res/values/dimens.xml +++ b/res/values/dimens.xml @@ -1,7 +1,7 @@ 16.0dp @@ -35,37 +33,21 @@ 14.0dip - 4.0dip 16.0dip - 24.0dip - 30.0dip 12.0dip 12.0dip 16.0sp - 18.0sp @dimen/text_size_small @dimen/text_size_micro 15.0dip - - 8dp - - 8dp - - 8dp - 8dp - - 128dp - - 8dp 8dp 8dp - 44dip + 56dip 70.0dip - 60.0dip 50.0dip 50.0dip 26.0dip @@ -74,42 +56,19 @@ 50.0dip - 56.0dip - 12.0dip - 12.0dip - 30.0dip - 30.0dip 5.0dip 35.0dip 16.0dip 22.0dip - 64.0dip - 64.0dip 8.0dip - 4.0dip - 8.0dip - 48.0dip - 48.0dip - 128.0dip - 12.0dip - 48.0dip - 10.0dip - 8.0dip - 8.0dip - - - 10.0dip - - 45.0dip - 5.0dip - 16.0dip + 10dp + 240.0dip - 190.0dip 40.0dip @@ -118,55 +77,22 @@ 18.0dip 100.0dip 100.0dip - 26.0dip - 30.0dip - 83.0dip - 26.0dip - - - 36.0dip - 15.0dip - 14sp - 3.0dip @dimen/text_size_micro - 86.0dip - 1.0dip - 8.0dip - - 250.0dip - 128.0dip - 180.0dip - 110.0dip - 80.0dip - 250.0dip - 40.0dip - 8.0dip - 8.0dip - 48.0dip - 8.0dip - 48.0dip - 70.0dip - 70.0dip - 0.0dip - 4.0dip - - - 5.0dip - - - 2.0dip + 250dp + 110dp + 80dp + 80dp + 80dp + 8dp - 20.0dip + 24.0dip 50.0dip - - 8.0dip - 25.0dip 20.0dip @@ -176,12 +102,7 @@ 56.0dip 30.0dip 38.0dip - 48.0dip 48.0dip - 5.0dip - 10.0dip - 16.0dp - 8.0dp 48dp @@ -216,8 +137,6 @@ 12sp 10sp - - 2dp - 8dp - 4dp + 36dp + 112dp diff --git a/res/values/fractions.xml b/res/values/fractions.xml deleted file mode 100644 index 8daab114b3f622a1e46631809a835ec46a147dad..0000000000000000000000000000000000000000 --- a/res/values/fractions.xml +++ /dev/null @@ -1,21 +0,0 @@ - - - - - 75.0% - 42.0% - - diff --git a/res/values/plurals.xml b/res/values/plurals.xml index 9c0123fde28675a77ea194be618ab68aff4f2472..0b706fb5a8882cd7ab33f6f01eb3316d17bf6173 100644 --- a/res/values/plurals.xml +++ b/res/values/plurals.xml @@ -17,10 +17,6 @@ --> - - %d artist - %d artists - @@ -36,10 +32,6 @@ - - %d genre - %d genres - @@ -70,10 +62,6 @@ - - %d song added to favorites. - %d songs added to favorites. - diff --git a/res/values/strings.xml b/res/values/strings.xml index 04be24d41a0808bbd13026f9d1a4890605992175..589125362204c5495593a1ec5abb89d6a410be63 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -21,18 +21,14 @@ Music - Recent Artists Albums Songs Playlists - Genres - Now Playing Play Queue Albums - Top Songs All Songs @@ -45,10 +41,8 @@ Shuffle top tracks Shuffle recently played Shuffle last added - Play all Sort by Clear list - Clear recent Clear queue Save queue to playlist Equalizer @@ -56,7 +50,6 @@ Add to playlist Add to queue - Remove from recent Remove from queue @@ -66,8 +59,6 @@ Album Year Duration - Date added - Track list Number of songs Number of albums Filename @@ -92,9 +83,8 @@ This cannot be undone This will permanently delete the cached image entries Choose photo from Gallery - Google search Use default photo - Use old photo + Audio recording permission was denied, enable it from Settings app to enable music visualization Play @@ -120,12 +110,9 @@ Repeat Repeat all Repeat one - Open queue - Browse music \'%s\' set as ringtone - Playlist renamed Storage @@ -143,13 +130,9 @@ Music: 4 \u00d7 1 Music: 4 \u00d7 2 Music: 4 \u00d7 2 (alternate) - Music: recently listened - - The equalizer could not be opened. - To copy music from your computer to your device, use a USB cable. - Songs you mark as favorites will be shown here. No recent songs Songs you have listened to recently will show up here. No songs in playlist @@ -186,16 +169,6 @@ "Other" - Show all artists - Show all albums - Show all songs - Show all playlists - - All \"%s\" artists - All \"%s\" albums - All \"%s\" songs - All \"%s\" playlists - %1$s %2$s Music playback diff --git a/res/values/styles.xml b/res/values/styles.xml index 565ea349bcb548674cf0dbebfae6af1f6e816ce0..637cc9c0cd7a3869cac9b6e489c349eb06196929 100644 --- a/res/values/styles.xml +++ b/res/values/styles.xml @@ -1,7 +1,7 @@ - + @@ -38,7 +39,7 @@ false false true - @lineageos.platform:drawable/ic_back + @drawable/ic_arrow_back @color/primary_dark @color/primary_dark @color/primary_dark @@ -52,13 +53,19 @@ @color/accent - + + @@ -74,7 +81,7 @@ - - - - - - + + + + diff --git a/src/org/lineageos/eleven/BuildConstants.java b/src/org/lineageos/eleven/BuildConstants.java index 9e730ce4cdaf1fc7152755000327b36f5cba3559..0c749481ed48f82d56b1dc0bd546cb9af3ae6cd3 100644 --- a/src/org/lineageos/eleven/BuildConstants.java +++ b/src/org/lineageos/eleven/BuildConstants.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2019 The LineageOS Project + * Copyright (C) 2019-2021 The LineageOS Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -13,7 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package org.lineageos.eleven; public class BuildConstants { diff --git a/src/org/lineageos/eleven/Config.java b/src/org/lineageos/eleven/Config.java index 5f1077b698f20712379f8a9edce2840d4bda99c8..0da4fff1dbcd660d3fc3900b65543ca8f39a80e7 100644 --- a/src/org/lineageos/eleven/Config.java +++ b/src/org/lineageos/eleven/Config.java @@ -1,7 +1,7 @@ /* * Copyright (C) 2012 Andrew Neal * Copyright (C) 2014 The CyanogenMod Project - * Copyright (C) 2020 The LineageOS Project + * Copyright (C) 2020-2021 The LineageOS Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -15,7 +15,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package org.lineageos.eleven; /** @@ -25,10 +24,6 @@ package org.lineageos.eleven; */ public final class Config { - /* This class is never initiated. */ - public Config() { - } - /** * Used to distinguish album art from artist images */ @@ -56,7 +51,9 @@ public final class Config { */ public static final String ALBUM_YEAR = "album_year"; - /** number of songs in a album or track list */ + /** + * number of songs in a album or track list + */ public static final String SONG_COUNT = "song_count"; /** @@ -64,28 +61,18 @@ public final class Config { */ public static final String MIME_TYPE = "mime_type"; - /** - * Play from search intent - */ - public static final String PLAY_FROM_SEARCH = "android.media.action.MEDIA_PLAY_FROM_SEARCH"; - /** * The smart playlist type */ public static final String SMART_PLAYLIST_TYPE = "smart_playlist_type"; - /** - * Number of search results to show at the top level search - */ - public static final int SEARCH_NUM_RESULTS_TO_GET = 3; - - public static enum SmartPlaylistType { + public enum SmartPlaylistType { LastAdded(-1, R.string.playlist_last_added), RecentlyPlayed(-2, R.string.playlist_recently_played), TopTracks(-3, R.string.playlist_top_tracks); - public long mId; - public int mTitleId; + public final long mId; + public final int mTitleId; SmartPlaylistType(long id, int titleId) { mId = id; @@ -107,7 +94,7 @@ public final class Config { * This helps identify where an id has come from. Mainly used to determine when a user * clicks a song where that song came from (artist/album/playlist) */ - public static enum IdType { + public enum IdType { NA(0), Artist(1), Album(2), diff --git a/src/org/lineageos/eleven/ElevenApplication.java b/src/org/lineageos/eleven/ElevenApplication.java index 5830cf57e83387c1765fe7e427d2ab2cd981629a..036ae55d766de9ae0fe6b38375b1cdcad6750ccd 100644 --- a/src/org/lineageos/eleven/ElevenApplication.java +++ b/src/org/lineageos/eleven/ElevenApplication.java @@ -1,7 +1,7 @@ /* * Copyright (C) 2012 Andrew Neal * Copyright (C) 2014 The CyanogenMod Project - * Copyright (C) 2019 The LineageOS Project + * Copyright (C) 2019-2021 The LineageOS Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -15,11 +15,12 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package org.lineageos.eleven; import android.app.Application; import android.os.StrictMode; +import android.os.StrictMode.ThreadPolicy; +import android.os.StrictMode.VmPolicy; import org.lineageos.eleven.cache.ImageCache; @@ -40,11 +41,11 @@ public class ElevenApplication extends Application { } private void enableStrictMode() { - final StrictMode.ThreadPolicy.Builder threadPolicyBuilder = new StrictMode.ThreadPolicy.Builder() + final ThreadPolicy.Builder threadPolicyBuilder = new ThreadPolicy.Builder() .detectAll() .penaltyLog() .penaltyFlashScreen(); - final StrictMode.VmPolicy.Builder vmPolicyBuilder = new StrictMode.VmPolicy.Builder() + final VmPolicy.Builder vmPolicyBuilder = new VmPolicy.Builder() .detectAll() .penaltyLog(); diff --git a/src/org/lineageos/eleven/MediaButtonIntentReceiver.java b/src/org/lineageos/eleven/MediaButtonIntentReceiver.java index 90cabc0122ee3c24fbf0a0b8e706bc8e5ee48d01..e7ecbaad595da352506a979d9790b769bda91443 100644 --- a/src/org/lineageos/eleven/MediaButtonIntentReceiver.java +++ b/src/org/lineageos/eleven/MediaButtonIntentReceiver.java @@ -1,43 +1,47 @@ /* - * Copyright (C) 2007 The Android Open Source Project Licensed under the Apache - * License, Version 2.0 (the "License"); you may not use this file except in - * compliance with the License. You may obtain a copy of the License at - * http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law - * or agreed to in writing, software distributed under the License is - * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the specific language - * governing permissions and limitations under the License. + * Copyright (C) 2007 The Android Open Source Project + * Copyright (C) 2021 The LineageOS Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ - package org.lineageos.eleven; import android.content.Context; import android.content.Intent; -import android.media.AudioManager; import android.util.Log; import android.util.SparseArray; import android.view.KeyEvent; import androidx.legacy.content.WakefulBroadcastReceiver; +@SuppressWarnings("deprecation") public class MediaButtonIntentReceiver extends WakefulBroadcastReceiver { private static final boolean DEBUG = false; private static final String TAG = "MediaButtonIntentReceiver"; private static final SparseArray KEY_CODE_MAPPING = new SparseArray<>(7); + static { KEY_CODE_MAPPING.put(KeyEvent.KEYCODE_HEADSETHOOK, MusicPlaybackService.CMDHEADSETHOOK); KEY_CODE_MAPPING.put(KeyEvent.KEYCODE_MEDIA_STOP, MusicPlaybackService.CMDSTOP); - KEY_CODE_MAPPING.put(KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE, MusicPlaybackService.CMDTOGGLEPAUSE); + KEY_CODE_MAPPING.put(KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE, + MusicPlaybackService.CMDTOGGLEPAUSE); KEY_CODE_MAPPING.put(KeyEvent.KEYCODE_MEDIA_NEXT, MusicPlaybackService.CMDNEXT); KEY_CODE_MAPPING.put(KeyEvent.KEYCODE_MEDIA_PREVIOUS, MusicPlaybackService.CMDPREVIOUS); KEY_CODE_MAPPING.put(KeyEvent.KEYCODE_MEDIA_PAUSE, MusicPlaybackService.CMDPAUSE); KEY_CODE_MAPPING.put(KeyEvent.KEYCODE_MEDIA_PLAY, MusicPlaybackService.CMDPLAY); } - /** - * {@inheritDoc} - */ @Override public void onReceive(final Context context, final Intent intent) { if (DEBUG) Log.v(TAG, "Received intent: " + intent); diff --git a/src/org/lineageos/eleven/MusicPlaybackService.java b/src/org/lineageos/eleven/MusicPlaybackService.java index 22481e4e2516fc3d50a34d2eddaa28fd4546d742..2355d0a01daf9830ce39d404050df7943708c4b4 100644 --- a/src/org/lineageos/eleven/MusicPlaybackService.java +++ b/src/org/lineageos/eleven/MusicPlaybackService.java @@ -1,7 +1,7 @@ /* * Copyright (C) 2012 Andrew Neal * Copyright (C) 2014-2016 The CyanogenMod Project - * Copyright (C) 2018-2020 The LineageOS Project + * Copyright (C) 2018-2021 The LineageOS Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -15,10 +15,10 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package org.lineageos.eleven; import android.Manifest.permission; +import android.annotation.SuppressLint; import android.app.AlarmManager; import android.app.Notification; import android.app.NotificationChannel; @@ -79,11 +79,11 @@ import org.lineageos.eleven.provider.MusicPlaybackState; import org.lineageos.eleven.provider.RecentStore; import org.lineageos.eleven.provider.SongPlayCount; import org.lineageos.eleven.service.MusicPlaybackTrack; -import org.lineageos.eleven.utils.colors.BitmapWithColors; import org.lineageos.eleven.utils.Lists; import org.lineageos.eleven.utils.PreferenceUtils; import org.lineageos.eleven.utils.ShakeDetector; import org.lineageos.eleven.utils.SrtManager; +import org.lineageos.eleven.utils.colors.BitmapWithColors; import java.io.File; import java.io.IOException; @@ -97,7 +97,7 @@ import java.util.Random; import java.util.TreeSet; /** - * A backbround {@link Service} used to keep music playing between activities + * A background {@link Service} used to keep music playing between activities * and when the user moves Eleven into the background. */ public class MusicPlaybackService extends Service @@ -105,99 +105,106 @@ public class MusicPlaybackService extends Service private static final String TAG = "MusicPlaybackService"; private static final boolean D = false; + private static final String PKG_NAME = BuildConstants.PACKAGE_NAME; + /** * Indicates that the music has paused or resumed */ - public static final String PLAYSTATE_CHANGED = BuildConstants.PACKAGE_NAME + ".playstatechanged"; + public static final String PLAYSTATE_CHANGED = PKG_NAME + ".playstatechanged"; /** * Indicates that music playback position within * a title was changed */ - public static final String POSITION_CHANGED = BuildConstants.PACKAGE_NAME + ".positionchanged"; + public static final String POSITION_CHANGED = PKG_NAME + ".positionchanged"; /** * Indicates the meta data has changed in some way, like a track change */ - public static final String META_CHANGED = BuildConstants.PACKAGE_NAME + ".metachanged"; + public static final String META_CHANGED = PKG_NAME + ".metachanged"; /** * Indicates the queue has been updated */ - public static final String QUEUE_CHANGED = BuildConstants.PACKAGE_NAME + ".queuechanged"; + public static final String QUEUE_CHANGED = PKG_NAME + ".queuechanged"; + + /** + * Indicates a queue item has been moved + */ + public static final String QUEUE_MOVED = BuildConstants.PACKAGE_NAME + ".queuemoved"; /** * Indicates the queue has been updated */ - public static final String PLAYLIST_CHANGED = BuildConstants.PACKAGE_NAME + ".playlistchanged"; + public static final String PLAYLIST_CHANGED = PKG_NAME + ".playlistchanged"; /** * Indicates the repeat mode changed */ - public static final String REPEATMODE_CHANGED = BuildConstants.PACKAGE_NAME + ".repeatmodechanged"; + public static final String REPEATMODE_CHANGED = PKG_NAME + ".repeatmodechanged"; /** * Indicates the shuffle mode changed */ - public static final String SHUFFLEMODE_CHANGED = BuildConstants.PACKAGE_NAME + ".shufflemodechanged"; + public static final String SHUFFLEMODE_CHANGED = PKG_NAME + ".shufflemodechanged"; /** * Indicates the track fails to play */ - public static final String TRACK_ERROR = BuildConstants.PACKAGE_NAME + ".trackerror"; + public static final String TRACK_ERROR = PKG_NAME + ".trackerror"; /** * For backwards compatibility reasons, also provide sticky * broadcasts under the music package */ - public static final String ELEVEN_PACKAGE_NAME = BuildConstants.PACKAGE_NAME; + public static final String ELEVEN_PACKAGE_NAME = PKG_NAME; public static final String MUSIC_PACKAGE_NAME = "com.android.music"; /** * Called to indicate a general service commmand. Used in * {@link MediaButtonIntentReceiver} */ - public static final String SERVICECMD = BuildConstants.PACKAGE_NAME + ".musicservicecommand"; + public static final String SERVICECMD = PKG_NAME + ".musicservicecommand"; /** * Called to go toggle between pausing and playing the music */ - public static final String TOGGLEPAUSE_ACTION = BuildConstants.PACKAGE_NAME + ".togglepause"; + public static final String TOGGLEPAUSE_ACTION = PKG_NAME + ".togglepause"; /** * Called to go to pause the playback */ - public static final String PAUSE_ACTION = BuildConstants.PACKAGE_NAME + ".pause"; + public static final String PAUSE_ACTION = PKG_NAME + ".pause"; /** * Called to go to stop the playback */ - public static final String STOP_ACTION = BuildConstants.PACKAGE_NAME + ".stop"; + public static final String STOP_ACTION = PKG_NAME + ".stop"; /** * Called to go to the previous track or the beginning of the track if partway through the track */ - public static final String PREVIOUS_ACTION = BuildConstants.PACKAGE_NAME + ".previous"; + public static final String PREVIOUS_ACTION = PKG_NAME + ".previous"; /** * Called to go to the previous track regardless of how far in the current track the playback is */ - public static final String PREVIOUS_FORCE_ACTION = BuildConstants.PACKAGE_NAME + ".previous.force"; + public static final String PREVIOUS_FORCE_ACTION = PKG_NAME + ".previous.force"; /** * Called to go to the next track */ - public static final String NEXT_ACTION = BuildConstants.PACKAGE_NAME + ".next"; + public static final String NEXT_ACTION = PKG_NAME + ".next"; /** * Called to change the repeat mode */ - public static final String REPEAT_ACTION = BuildConstants.PACKAGE_NAME + ".repeat"; + public static final String REPEAT_ACTION = PKG_NAME + ".repeat"; /** * Called to change the shuffle mode */ - public static final String SHUFFLE_ACTION = BuildConstants.PACKAGE_NAME + ".shuffle"; + public static final String SHUFFLE_ACTION = PKG_NAME + ".shuffle"; public static final String FROM_MEDIA_BUTTON = "frommediabutton"; @@ -207,12 +214,12 @@ public class MusicPlaybackService extends Service * Used to easily notify a list that it should refresh. i.e. A playlist * changes */ - public static final String REFRESH = BuildConstants.PACKAGE_NAME + ".refresh"; + public static final String REFRESH = PKG_NAME + ".refresh"; /** * Used by the alarm intent to shutdown the service after being idle */ - private static final String SHUTDOWN = BuildConstants.PACKAGE_NAME + ".shutdown"; + private static final String SHUTDOWN = PKG_NAME + ".shutdown"; /** * Called to notify of a timed text @@ -349,7 +356,7 @@ public class MusicPlaybackService extends Service /** * The columns used to retrieve any info from the current track */ - private static final String[] PROJECTION = new String[] { + private static final String[] PROJECTION = new String[]{ BaseColumns._ID, MediaStore.Audio.Media.ARTIST, MediaStore.Audio.Media.ALBUM, MediaStore.Audio.Media.TITLE, MediaStore.Audio.Media.DATA, MediaStore.Audio.Media.MIME_TYPE, MediaStore.Audio.Media.ALBUM_ID, @@ -359,7 +366,7 @@ public class MusicPlaybackService extends Service /** * The columns used to retrieve any info from the current album */ - private static final String[] ALBUM_PROJECTION = new String[] { + private static final String[] ALBUM_PROJECTION = new String[]{ MediaStore.Audio.Albums.ALBUM, MediaStore.Audio.Albums.ARTIST, MediaStore.Audio.Albums.LAST_YEAR }; @@ -543,9 +550,6 @@ public class MusicPlaybackService extends Service private PowerManager.WakeLock mHeadsetHookWakeLock; - /** - * {@inheritDoc} - */ @Override public IBinder onBind(final Intent intent) { if (D) Log.d(TAG, "Service bound, intent = " + intent); @@ -553,9 +557,6 @@ public class MusicPlaybackService extends Service return mBinder; } - /** - * {@inheritDoc} - */ @Override public boolean onUnbind(final Intent intent) { if (D) Log.d(TAG, "Service unbound"); @@ -581,17 +582,11 @@ public class MusicPlaybackService extends Service return true; } - /** - * {@inheritDoc} - */ @Override public void onRebind(final Intent intent) { mIsBound = true; } - /** - * {@inheritDoc} - */ @Override public void onCreate() { if (D) Log.d(TAG, "Creating service"); @@ -680,7 +675,8 @@ public class MusicPlaybackService extends Service shutdownIntent.setAction(SHUTDOWN); mAlarmManager = getSystemService(AlarmManager.class); - mShutdownIntent = PendingIntent.getService(this, 0, shutdownIntent, 0); + mShutdownIntent = PendingIntent.getService(this, 0, shutdownIntent, + PendingIntent.FLAG_IMMUTABLE); // Bring the queue back reloadQueue(); @@ -704,32 +700,39 @@ public class MusicPlaybackService extends Service public void onPause() { pause(false); } + @Override public void onPlay() { play(); } + @Override public void onSeekTo(long pos) { seek(pos); } + @Override public void onSkipToNext() { gotoNext(true); } + @Override public void onSkipToPrevious() { prev(false); } + @Override public void onStop() { pause(false); seek(0); releaseServiceUiAndStop(); } + @Override public void onSkipToQueueItem(long id) { setQueuePosition((int) id); } + @Override public boolean onMediaButtonEvent(@NonNull Intent mediaButtonIntent) { if (Intent.ACTION_MEDIA_BUTTON.equals(mediaButtonIntent.getAction())) { @@ -747,13 +750,10 @@ public class MusicPlaybackService extends Service PendingIntent pi = PendingIntent.getBroadcast(this, 0, new Intent(this, MediaButtonIntentReceiver.class), - PendingIntent.FLAG_UPDATE_CURRENT); + PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE); mSession.setMediaButtonReceiver(pi); } - /** - * {@inheritDoc} - */ @Override public void onDestroy() { if (D) Log.d(TAG, "Destroying service"); @@ -801,9 +801,6 @@ public class MusicPlaybackService extends Service stopShakeDetector(true); } - /** - * {@inheritDoc} - */ @Override public int onStartCommand(final Intent intent, final int flags, final int startId) { if (D) Log.d(TAG, "Got new intent " + intent + ", startId = " + startId); @@ -971,9 +968,6 @@ public class MusicPlaybackService extends Service if (mUnmountReceiver == null) { mUnmountReceiver = new BroadcastReceiver() { - /** - * {@inheritDoc} - */ @Override public void onReceive(final Context context, final Intent intent) { final String action = intent.getAction(); @@ -1042,7 +1036,7 @@ public class MusicPlaybackService extends Service * to the next file after the range. * * @param first The first file to be removed - * @param last The last file to be removed + * @param last The last file to be removed * @return the number of tracks deleted */ private int removeTracksInternal(int first, int last) { @@ -1115,7 +1109,7 @@ public class MusicPlaybackService extends Service /** * Adds a list to the playlist * - * @param list The list to add + * @param list The list to add * @param position The position to place the tracks */ private void addToPlayList(final long[] list, int position, long sourceId, IdType sourceType) { @@ -1179,7 +1173,7 @@ public class MusicPlaybackService extends Service } private Cursor openCursorAndGoToFirst(Uri uri, String[] projection, - String selection, String[] selectionArgs) { + String selection, String[] selectionArgs) { Cursor c = getContentResolver().query(uri, projection, selection, selectionArgs, null, null); if (c == null) { @@ -1190,7 +1184,7 @@ public class MusicPlaybackService extends Service return null; } return c; - } + } private synchronized void closeCursor() { if (mCursor != null) { @@ -1216,7 +1210,7 @@ public class MusicPlaybackService extends Service * playback * * @param openNext True to prepare the next track for playback, false - * otherwise. + * otherwise. */ private void openCurrentAndMaybeNext(final boolean openNext) { synchronized (this) { @@ -1233,7 +1227,7 @@ public class MusicPlaybackService extends Service while (true) { if (mCursor != null && openFile(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI + "/" - + mCursor.getLong(IDCOLIDX))) { + + mCursor.getLong(IDCOLIDX))) { break; } @@ -1279,7 +1273,7 @@ public class MusicPlaybackService extends Service /** * @param force True to force the player onto the track next, false - * otherwise. + * otherwise. * @return The next position to play. */ private int getNextPosition(final boolean force) { @@ -1289,10 +1283,7 @@ public class MusicPlaybackService extends Service } // if we're not forced to go to the next track and we are only playing the current track if (!force && mRepeatMode == REPEAT_CURRENT) { - if (mPlayPos < 0) { - return 0; - } - return mPlayPos; + return Math.max(mPlayPos, 0); } else if (mShuffleMode == SHUFFLE_NORMAL) { final int numTracks = mPlaylist.size(); @@ -1338,7 +1329,7 @@ public class MusicPlaybackService extends Service // return no more tracks if (minNumPlays > 0 && numTracksWithMinNumPlays == numTracks && mRepeatMode != REPEAT_ALL && !force) { - return -1; + return -1; } // else pick a track from the least number of played tracks @@ -1354,7 +1345,9 @@ public class MusicPlaybackService extends Service } // Unexpected to land here - if (D) Log.e(TAG, "Getting the next position resulted did not get a result when it should have"); + if (D) + Log.e(TAG, "Getting the next position resulted did not get a result " + + "when it should have"); return -1; } else if (mShuffleMode == SHUFFLE_AUTO) { doAutoShuffleUpdate(); @@ -1382,6 +1375,7 @@ public class MusicPlaybackService extends Service /** * Sets the next track to be played + * * @param position the target position we want */ private void setNextTrack(int position) { @@ -1399,12 +1393,12 @@ public class MusicPlaybackService extends Service * Creates a shuffled playlist used for party mode */ private boolean makeAutoShuffleList() { - Cursor cursor = null; - try { - cursor = getContentResolver().query(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, - new String[] { - MediaStore.Audio.Media._ID - }, MediaStore.Audio.Media.IS_MUSIC + "=1", null, null); + try (Cursor cursor = getContentResolver().query( + MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, + new String[]{MediaStore.Audio.Media._ID}, + MediaStore.Audio.Media.IS_MUSIC + "= 1", + null, + null)) { if (cursor == null || cursor.getCount() == 0) { return false; } @@ -1416,11 +1410,7 @@ public class MusicPlaybackService extends Service } mAutoShuffleList = list; return true; - } catch (final RuntimeException e) { - } finally { - if (cursor != null) { - cursor.close(); - } + } catch (final RuntimeException ignored) { } return false; } @@ -1505,30 +1495,26 @@ public class MusicPlaybackService extends Service musicIntent.setAction(what.replace(ELEVEN_PACKAGE_NAME, MUSIC_PACKAGE_NAME)); sendStickyBroadcast(musicIntent); - switch (what) { - case META_CHANGED: - // Add the track to the recently played list. - mRecentsCache.addSongId(getAudioId()); + if (META_CHANGED.equals(what)) { + // Add the track to the recently played list. + mRecentsCache.addSongId(getAudioId()); - mSongPlayCountCache.bumpSongCount(getAudioId()); - break; - case QUEUE_CHANGED: - saveQueue(true); - if (isPlaying()) { - // if we are in shuffle mode and our next track is still valid, - // try to re-use the track - // We need to reimplement the queue to prevent hacky solutions like this - if (mNextPlayPos >= 0 && mNextPlayPos < mPlaylist.size() - && getShuffleMode() != SHUFFLE_NONE) { - setNextTrack(mNextPlayPos); - } else { - setNextTrack(); - } + mSongPlayCountCache.bumpSongCount(getAudioId()); + } else if (QUEUE_CHANGED.equals(what) || QUEUE_MOVED.equals(what)) { + saveQueue(true); + if (isPlaying()) { + // if we are in shuffle mode and our next track is still valid, + // try to re-use the track + // We need to reimplement the queue to prevent hacky solutions like this + if (mNextPlayPos >= 0 && mNextPlayPos < mPlaylist.size() + && getShuffleMode() != SHUFFLE_NONE) { + setNextTrack(mNextPlayPos); + } else { + setNextTrack(); } - break; - default: - saveQueue(false); - break; + } + } else { + saveQueue(false); } if (what.equals(PLAYSTATE_CHANGED) || what.equals(META_CHANGED)) { @@ -1551,6 +1537,7 @@ public class MusicPlaybackService extends Service PlaybackState.ACTION_PLAY_FROM_MEDIA_ID | PlaybackState.ACTION_PAUSE | PlaybackState.ACTION_SKIP_TO_NEXT | + PlaybackState.ACTION_SEEK_TO | PlaybackState.ACTION_SKIP_TO_PREVIOUS | PlaybackState.ACTION_STOP; @@ -1559,7 +1546,8 @@ public class MusicPlaybackService extends Service .setActions(playBackStateActions) .setActiveQueueItemId(getAudioId()) .setState(playState, position(), 1.0f).build()); - } else if (what.equals(META_CHANGED) || what.equals(QUEUE_CHANGED)) { + } else if (what.equals(META_CHANGED) || what.equals(QUEUE_CHANGED) + || QUEUE_MOVED.equals(what)) { Bitmap albumArt = getAlbumArt(false).getBitmap(); if (albumArt != null) { // RemoteControlClient wants to recycle the bitmaps thrown at it, so we need @@ -1583,7 +1571,7 @@ public class MusicPlaybackService extends Service .putBitmap(MediaMetadata.METADATA_KEY_ALBUM_ART, albumArt) .build()); - if (what.equals(QUEUE_CHANGED)) { + if (what.equals(QUEUE_CHANGED) || what.equals(QUEUE_MOVED)) { updateMediaSessionQueue(); } @@ -1620,7 +1608,8 @@ public class MusicPlaybackService extends Service Intent nowPlayingIntent = new Intent(ACTION_AUDIO_PLAYER) .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - PendingIntent clickIntent = PendingIntent.getActivity(this, 0, nowPlayingIntent, 0); + PendingIntent clickIntent = PendingIntent.getActivity(this, 0, nowPlayingIntent, + PendingIntent.FLAG_IMMUTABLE); BitmapWithColors artwork = getAlbumArt(false); if (mNotificationPostTime == 0) { @@ -1664,7 +1653,6 @@ public class MusicPlaybackService extends Service .setContentText(text) .setColor(artwork.getVibrantColor()) .setWhen(mNotificationPostTime) - .setShowWhen(false) .setStyle(style) .setVisibility(Notification.VISIBILITY_PUBLIC) .addAction(prevAction) @@ -1678,7 +1666,7 @@ public class MusicPlaybackService extends Service Intent intent = new Intent(action); intent.setComponent(serviceName); - return PendingIntent.getService(this, 0, intent, 0); + return PendingIntent.getService(this, 0, intent, PendingIntent.FLAG_IMMUTABLE); } /** @@ -1740,13 +1728,13 @@ public class MusicPlaybackService extends Service return; } - final long seekpos = mPreferences.getLong("seekpos", 0); - seek(seekpos >= 0 && seekpos < duration() ? seekpos : 0); + final long seekPos = mPreferences.getLong("seekpos", 0); + seek(seekPos >= 0 && seekPos < duration() ? seekPos : 0); if (D) { Log.d(TAG, "restored queue, currently at position " + position() + "/" + duration() - + " (requested " + seekpos + ")"); + + " (requested " + seekPos + ")"); } int repmode = mPreferences.getInt("repeatmode", REPEAT_NONE); @@ -1789,27 +1777,27 @@ public class MusicPlaybackService extends Service boolean shouldAddToPlaylist = true; // should try adding audio info to playlist long id = -1; try { - id = Long.valueOf(uri.getLastPathSegment()); + id = Long.parseLong(uri.getLastPathSegment()); } catch (NumberFormatException ex) { // Ignore } if (id != -1 && path.startsWith( - MediaStore.Audio.Media.EXTERNAL_CONTENT_URI.toString())) { + MediaStore.Audio.Media.EXTERNAL_CONTENT_URI.toString())) { updateCursor(uri); } else if (id != -1 && path.startsWith( - MediaStore.Files.getContentUri("external").toString())) { + MediaStore.Files.getContentUri("external").toString())) { updateCursor(id); - // handle downloaded media files - } else if ( path.startsWith("content://downloads/") ) { + // handle downloaded media files + } else if (path.startsWith("content://downloads/")) { // extract MediaProvider(MP) uri , if available // Downloads.Impl.COLUMN_MEDIAPROVIDER_URI String mpUri = getValueForDownloadedFile(this, uri, "mediaprovider_uri"); if (D) Log.i(TAG, "Downloaded file's MP uri : " + mpUri); - if ( !TextUtils.isEmpty(mpUri) ) { + if (!TextUtils.isEmpty(mpUri)) { // if mpUri is valid, play that URI instead if (openFile(mpUri)) { // notify impending change in track @@ -1834,7 +1822,7 @@ public class MusicPlaybackService extends Service if (mCursor != null && shouldAddToPlaylist) { mPlaylist.clear(); mPlaylist.add(new MusicPlaybackTrack( - mCursor.getLong(IDCOLIDX), -1, IdType.NA, -1)); + mCursor.getLong(IDCOLIDX), -1, IdType.NA, -1)); // propagate the change in playlist state notifyChange(QUEUE_CHANGED); mPlayPos = 0; @@ -1867,7 +1855,7 @@ public class MusicPlaybackService extends Service Columns for a pseudo cursor we are creating for downloaded songs Modeled after mCursor to be able to respond to respond to the same queries as it */ - private static final String[] PROJECTION_MATRIX = new String[] { + private static final String[] PROJECTION_MATRIX = new String[]{ "_id", MediaStore.Audio.Media.ARTIST, MediaStore.Audio.Media.ALBUM, MediaStore.Audio.Media.TITLE, MediaStore.Audio.Media.DATA, MediaStore.Audio.Media.MIME_TYPE, MediaStore.Audio.Media.ALBUM_ID, @@ -1876,6 +1864,7 @@ public class MusicPlaybackService extends Service /** * Creates a pseudo cursor for downloaded audio files with minimal info + * * @param uri the uri of the downloaded file */ private void updateCursorForDownloadedFile(Uri uri) { @@ -1883,9 +1872,9 @@ public class MusicPlaybackService extends Service closeCursor(); // clear mCursor MatrixCursor cursor = new MatrixCursor(PROJECTION_MATRIX); // get title of the downloaded file ; Downloads.Impl.COLUMN_TITLE - String title = getValueForDownloadedFile(this, uri, "title" ); + String title = getValueForDownloadedFile(this, uri, "title"); // populating the cursor with bare minimum info - cursor.addRow(new Object[] { + cursor.addRow(new Object[]{ null, null, null, @@ -1902,17 +1891,14 @@ public class MusicPlaybackService extends Service /** * Query the DownloadProvider to get the value in the specified column - * @param context + * * @param uri the uri of the downloaded file - * @param column - * @return */ private String getValueForDownloadedFile(Context context, Uri uri, String column) { - final String[] projection = { - column - }; - try (Cursor cursor = context.getContentResolver().query(uri, projection, null, null, null)) { + final String[] projection = {column}; + try (Cursor cursor = context.getContentResolver().query(uri, projection, null, null, + null)) { if (cursor != null && cursor.moveToFirst()) { return cursor.getString(0); } @@ -1983,15 +1969,15 @@ public class MusicPlaybackService extends Service /** * Removes a song from the playlist at the specified position. * - * @param id The song id to be removed + * @param id The song id to be removed * @param position The position of the song in the playlist * @return true if successful */ public boolean removeTrackAtPosition(final long id, final int position) { synchronized (this) { - if ( position >=0 && + if (position >= 0 && position < mPlaylist.size() && - mPlaylist.get(position).mId == id ) { + mPlaylist.get(position).mId == id) { return removeTracks(position, position) > 0; } @@ -2005,7 +1991,7 @@ public class MusicPlaybackService extends Service * to the next file after the range. * * @param first The first file to be removed - * @param last The last file to be removed + * @param last The last file to be removed * @return the number of tracks deleted */ public int removeTracks(final int first, final int last) { @@ -2115,7 +2101,7 @@ public class MusicPlaybackService extends Service if (mCursor == null || mPlayPos < 0 || mPlayPos >= mPlaylist.size()) { return null; } - String[] genreProjection = { MediaStore.Audio.Genres.NAME }; + String[] genreProjection = {MediaStore.Audio.Genres.NAME}; Uri genreUri = MediaStore.Audio.Genres.getContentUriForAudioId("external", (int) mPlaylist.get(mPlayPos).mId); Cursor genreCursor = getContentResolver().query(genreUri, genreProjection, @@ -2124,7 +2110,7 @@ public class MusicPlaybackService extends Service try { if (genreCursor.moveToFirst()) { return genreCursor.getString( - genreCursor.getColumnIndexOrThrow(MediaStore.Audio.Genres.NAME)); + genreCursor.getColumnIndexOrThrow(MediaStore.Audio.Genres.NAME)); } } finally { genreCursor.close(); @@ -2211,6 +2197,7 @@ public class MusicPlaybackService extends Service /** * Gets the music track from the queue at the specified index + * * @param index position * @return music track or null */ @@ -2342,7 +2329,7 @@ public class MusicPlaybackService extends Service /** * Gets the track id at a given position in the queue - * @param position + * * @return track id in the queue position */ public long getQueueItemAtPosition(int position) { @@ -2373,7 +2360,8 @@ public class MusicPlaybackService extends Service /** * Helper function to wrap the logic around mIsSupposedToBePlaying for consistentcy - * @param value to set mIsSupposedToBePlaying to + * + * @param value to set mIsSupposedToBePlaying to * @param notify whether we want to fire PLAYSTATE_CHANGED event */ private void setIsSupposedToBePlaying(boolean value, boolean notify) { @@ -2409,7 +2397,7 @@ public class MusicPlaybackService extends Service /** * Opens a list for playback * - * @param list The list of tracks to open + * @param list The list of tracks to open * @param position The position to start playback at */ public void open(final long[] list, final int position, long sourceId, IdType sourceType) { @@ -2463,6 +2451,7 @@ public class MusicPlaybackService extends Service /** * Resumes or starts playback. + * * @param createNewNextTrack True if you want to figure out the next track, false * if you want to re-use the existing next track (used for going back) */ @@ -2708,7 +2697,7 @@ public class MusicPlaybackService extends Service mPlayPos++; } } - notifyChange(QUEUE_CHANGED); + notifyChange(QUEUE_MOVED); } } @@ -2779,7 +2768,7 @@ public class MusicPlaybackService extends Service /** * Queues a new list for playback * - * @param list The list to queue + * @param list The list to queue * @param action The action to take */ public void enqueue(final long[] list, final int action, long sourceId, IdType sourceType) { @@ -2847,9 +2836,8 @@ public class MusicPlaybackService extends Service return mCachedBitmapWithColors[targetIndex]; } - // otherwise get the artwork (or defaultartwork if none found) - final BitmapWithColors bitmap = mImageFetcher.getArtwork(albumName, - albumId, artistName, smallBitmap); + // otherwise get the artwork (or default artwork if none found) + final BitmapWithColors bitmap = mImageFetcher.getArtwork(albumName, albumId, smallBitmap); // if the key is different, clear the bitmaps first if (!key.equals(mCachedKey)) { @@ -2887,7 +2875,7 @@ public class MusicPlaybackService extends Service if (enabled) { if (mShakeDetector == null) { mShakeDetector = new ShakeDetector(() -> { - if (D) Log.d(TAG,"Shake detected"); + if (D) Log.d(TAG, "Shake detected"); gotoNext(true); }); } @@ -2895,8 +2883,7 @@ public class MusicPlaybackService extends Service if (isPlaying()) { startShakeDetector(); } - } - else { + } else { stopShakeDetector(true); } } @@ -2917,7 +2904,7 @@ public class MusicPlaybackService extends Service if (mShakeDetector != null) { mShakeDetector.stop(); } - if(destroyShakeDetector){ + if (destroyShakeDetector) { mShakeDetector = null; if (D) { Log.d(TAG, "ShakeToPlay destroyed!!!"); @@ -2926,20 +2913,17 @@ public class MusicPlaybackService extends Service } private final BroadcastReceiver mIntentReceiver = new BroadcastReceiver() { - /** - * {@inheritDoc} - */ @Override public void onReceive(final Context context, final Intent intent) { final String command = intent.getStringExtra(CMDNAME); - if (AppWidgetSmall.CMDAPPWIDGETUPDATE.equals(command)) { + if (AppWidgetSmall.APP_WIDGET_UPDATE.equals(command)) { final int[] small = intent.getIntArrayExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS); mAppWidgetSmall.performUpdate(MusicPlaybackService.this, small); - } else if (AppWidgetLarge.CMDAPPWIDGETUPDATE.equals(command)) { + } else if (AppWidgetLarge.APP_WIDGET_UPDATE.equals(command)) { final int[] large = intent.getIntArrayExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS); mAppWidgetLarge.performUpdate(MusicPlaybackService.this, large); - } else if (AppWidgetLargeAlternate.CMDAPPWIDGETUPDATE.equals(command)) { + } else if (AppWidgetLargeAlternate.APP_WIDGET_UPDATE.equals(command)) { final int[] largeAlt = intent .getIntArrayExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS); mAppWidgetLargeAlternate.performUpdate(MusicPlaybackService.this, largeAlt); @@ -2989,18 +2973,15 @@ public class MusicPlaybackService extends Service * Constructor of MusicPlayerHandler * * @param service The service to use. - * @param looper The thread to run on. + * @param looper The thread to run on. */ public MusicPlayerHandler(final MusicPlaybackService service, final Looper looper) { super(looper); mService = new WeakReference<>(service); } - /** - * {@inheritDoc} - */ @Override - public void handleMessage(final Message msg) { + public void handleMessage(@NonNull final Message msg) { final MusicPlaybackService service = mService.get(); if (service == null) { return; @@ -3028,7 +3009,7 @@ public class MusicPlaybackService extends Service break; case SERVER_DIED: if (service.isPlaying()) { - final TrackErrorInfo info = (TrackErrorInfo)msg.obj; + final TrackErrorInfo info = (TrackErrorInfo) msg.obj; service.sendErrorMessage(info.mTrackName); // since the service isPlaying(), we only need to remove the offending @@ -3064,7 +3045,8 @@ public class MusicPlaybackService extends Service long eventTime = (Long) msg.obj; mHeadsetHookClickCounter = Math.min(mHeadsetHookClickCounter + 1, 3); - if (D) Log.d(TAG, "Got headset click, count = " + mHeadsetHookClickCounter); + if (D) + Log.d(TAG, "Got headset click, count = " + mHeadsetHookClickCounter); removeMessages(HEADSET_HOOK_MULTI_CLICK_TIMEOUT); if (mHeadsetHookClickCounter == 3) { @@ -3078,9 +3060,15 @@ public class MusicPlaybackService extends Service case HEADSET_HOOK_MULTI_CLICK_TIMEOUT: if (D) Log.d(TAG, "Handling headset click"); switch (mHeadsetHookClickCounter) { - case 1: service.togglePlayPause(); break; - case 2: service.gotoNext(true); break; - case 3: service.prev(false); break; + case 1: + service.togglePlayPause(); + break; + case 2: + service.gotoNext(true); + break; + case 3: + service.prev(false); + break; } mHeadsetHookClickCounter = 0; service.mHeadsetHookWakeLock.release(); @@ -3184,7 +3172,7 @@ public class MusicPlaybackService extends Service /** * @param path The path of the file, or the http/rtsp URL of the stream - * you want to play + * you want to play */ public void setDataSource(final String path) { mIsInitialized = setDataSourceImpl(mCurrentMediaPlayer, path); @@ -3219,7 +3207,7 @@ public class MusicPlaybackService extends Service filePath = uri.getPath(); } - if (!TextUtils.isEmpty(filePath)) { + if (filePath != null && !TextUtils.isEmpty(filePath)) { final int lastIndex = filePath.lastIndexOf('.'); if (lastIndex != -1) { String newPath = filePath.substring(0, lastIndex) + ".srt"; @@ -3232,10 +3220,10 @@ public class MusicPlaybackService extends Service /** * @param player The {@link MediaPlayer} to use - * @param path The path of the file, or the http/rtsp URL of the stream - * you want to play + * @param path The path of the file, or the http/rtsp URL of the stream + * you want to play * @return True if the player has been prepared and is - * ready to play, false otherwise + * ready to play, false otherwise */ private boolean setDataSourceImpl(final MediaPlayer player, final String path) { try { @@ -3261,7 +3249,7 @@ public class MusicPlaybackService extends Service * Set the MediaPlayer to start when this MediaPlayer finishes playback. * * @param path The path of the file, or the http/rtsp URL of the stream - * you want to play + * you want to play */ public void setNextDataSource(final String path) { mNextMediaPath = null; @@ -3369,7 +3357,7 @@ public class MusicPlaybackService extends Service * @return The offset in milliseconds from the start to seek to */ public long seek(final long whereto) { - mCurrentMediaPlayer.seekTo((int)whereto); + mCurrentMediaPlayer.seekTo((int) whereto); mSrtManager.seekTo(whereto); return whereto; } @@ -3392,9 +3380,6 @@ public class MusicPlaybackService extends Service return mCurrentMediaPlayer.getAudioSessionId(); } - /** - * {@inheritDoc} - */ @Override public boolean onError(final MediaPlayer mp, final int what, final int extra) { Log.w(TAG, "Music Server Error what: " + what + " extra: " + extra); @@ -3416,9 +3401,6 @@ public class MusicPlaybackService extends Service return false; } - /** - * {@inheritDoc} - */ @Override public void onCompletion(final MediaPlayer mp) { if (mp == mCurrentMediaPlayer && mNextMediaPlayer != null) { @@ -3434,6 +3416,7 @@ public class MusicPlaybackService extends Service } } + @SuppressWarnings("unused") private static final class ServiceStub extends IElevenService.Stub { private final WeakReference mService; @@ -3442,368 +3425,233 @@ public class MusicPlaybackService extends Service mService = new WeakReference<>(service); } - /** - * {@inheritDoc} - */ @Override public void openFile(final String path) { mService.get().openFile(path); } - /** - * {@inheritDoc} - */ @Override public void open(final long[] list, final int position, long sourceId, int sourceType) { mService.get().open(list, position, sourceId, IdType.getTypeById(sourceType)); } - /** - * {@inheritDoc} - */ @Override public void stop() { mService.get().stop(); } - /** - * {@inheritDoc} - */ @Override public void pause() { mService.get().pause(false); } - /** - * {@inheritDoc} - */ @Override public void play() { mService.get().play(); } - /** - * {@inheritDoc} - */ @Override public void prev(boolean forcePrevious) { mService.get().prev(forcePrevious); } - /** - * {@inheritDoc} - */ @Override public void next() { mService.get().gotoNext(true); } - /** - * {@inheritDoc} - */ @Override public void enqueue(final long[] list, final int action, long sourceId, int sourceType) { mService.get().enqueue(list, action, sourceId, IdType.getTypeById(sourceType)); } - /** - * {@inheritDoc} - */ @Override public void setQueuePosition(final int index) { mService.get().setQueuePosition(index); } - /** - * {@inheritDoc} - */ @Override public void setShuffleMode(final int shufflemode) { mService.get().setShuffleMode(shufflemode); } - /** - * {@inheritDoc} - */ @Override public void setRepeatMode(final int repeatmode) { mService.get().setRepeatMode(repeatmode); } - /** - * {@inheritDoc} - */ @Override public void moveQueueItem(final int from, final int to) { mService.get().moveQueueItem(from, to); } - /** - * {@inheritDoc} - */ @Override public void refresh() { mService.get().refresh(); } - /** - * {@inheritDoc} - */ @Override public void playlistChanged() { mService.get().playlistChanged(); } - /** - * {@inheritDoc} - */ @Override public boolean isPlaying() { return mService.get().isPlaying(); } - /** - * {@inheritDoc} - */ @Override public long[] getQueue() { return mService.get().getQueue(); } - /** - * {@inheritDoc} - */ @Override public long getQueueItemAtPosition(int position) { return mService.get().getQueueItemAtPosition(position); } - /** - * {@inheritDoc} - */ @Override public int getQueueSize() { return mService.get().getQueueSize(); } - /** - * {@inheritDoc} - */ @Override public int getQueueHistoryPosition(int position) { return mService.get().getQueueHistoryPosition(position); } - /** - * {@inheritDoc} - */ @Override public int getQueueHistorySize() { return mService.get().getQueueHistorySize(); } - /** - * {@inheritDoc} - */ @Override public int[] getQueueHistoryList() { return mService.get().getQueueHistoryList(); } - /** - * {@inheritDoc} - */ @Override public long duration() { return mService.get().duration(); } - /** - * {@inheritDoc} - */ @Override public long position() { return mService.get().position(); } - /** - * {@inheritDoc} - */ @Override public long seek(final long position) { return mService.get().seek(position); } - /** - * {@inheritDoc} - */ @Override public void seekRelative(final long deltaInMs) { mService.get().seekRelative(deltaInMs); } - /** - * {@inheritDoc} - */ @Override public long getAudioId() { return mService.get().getAudioId(); } - /** - * {@inheritDoc} - */ @Override public MusicPlaybackTrack getCurrentTrack() { return mService.get().getCurrentTrack(); } - /** - * {@inheritDoc} - */ @Override public MusicPlaybackTrack getTrack(int index) { return mService.get().getTrack(index); } - /** - * {@inheritDoc} - */ @Override public long getNextAudioId() { return mService.get().getNextAudioId(); } - /** - * {@inheritDoc} - */ @Override public long getPreviousAudioId() { return mService.get().getPreviousAudioId(); } - /** - * {@inheritDoc} - */ @Override public long getArtistId() { return mService.get().getArtistId(); } - /** - * {@inheritDoc} - */ @Override public long getAlbumId() { return mService.get().getAlbumId(); } - /** - * {@inheritDoc} - */ @Override public String getArtistName() { return mService.get().getArtistName(); } - /** - * {@inheritDoc} - */ @Override public String getTrackName() { return mService.get().getTrackName(); } - /** - * {@inheritDoc} - */ @Override public String getAlbumName() { return mService.get().getAlbumName(); } - /** - * {@inheritDoc} - */ @Override public String getPath() { return mService.get().getPath(); } - /** - * {@inheritDoc} - */ @Override public int getQueuePosition() { return mService.get().getQueuePosition(); } - /** - * {@inheritDoc} - */ @Override public int getShuffleMode() { return mService.get().getShuffleMode(); } - /** - * {@inheritDoc} - */ @Override public int getRepeatMode() { return mService.get().getRepeatMode(); } - /** - * {@inheritDoc} - */ @Override public int removeTracks(final int first, final int last) { return mService.get().removeTracks(first, last); } - /** - * {@inheritDoc} - */ @Override public int removeTrack(final long id) { return mService.get().removeTrack(id); } - /** - * {@inheritDoc} - */ @Override public boolean removeTrackAtPosition(final long id, final int position) { return mService.get().removeTrackAtPosition(id, position); } - /** - * {@inheritDoc} - */ @Override public int getMediaMountedCount() { return mService.get().getMediaMountedCount(); } - /** - * {@inheritDoc} - */ @Override public int getAudioSessionId() { return mService.get().getAudioSessionId(); } - /** - * {@inheritDoc} - */ @Override public void setShakeToPlayEnabled(boolean enabled) { mService.get().setShakeToPlayEnabled(enabled); } - } + @SuppressLint("StaticFieldLeak") private class QueueUpdateTask extends AsyncTask> { private final long[] mQueue; @@ -3829,7 +3677,7 @@ public class MusicPlaybackService extends Service Cursor c = getContentResolver().query( MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, - new String[] { AudioColumns._ID, AudioColumns.TITLE, AudioColumns.ARTIST }, + new String[]{AudioColumns._ID, AudioColumns.TITLE, AudioColumns.ARTIST}, selection.toString(), null, null); if (c == null) { return null; diff --git a/src/org/lineageos/eleven/MusicStateListener.java b/src/org/lineageos/eleven/MusicStateListener.java index 0ffa9759f30cea7ab3775087feeb4e28e5bbd5b7..65ca45aab80c0a664cd2d694a1e2fca1e73c629a 100644 --- a/src/org/lineageos/eleven/MusicStateListener.java +++ b/src/org/lineageos/eleven/MusicStateListener.java @@ -1,18 +1,19 @@ /* -* Copyright (C) 2014 The CyanogenMod Project -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ + * Copyright (C) 2014 The CyanogenMod Project + * Copyright (C) 2021 The LineageOS Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package org.lineageos.eleven; /** @@ -23,16 +24,15 @@ public interface MusicStateListener { /** * Called when {@link MusicPlaybackService#REFRESH} is invoked */ - public void restartLoader(); + void restartLoader(); /** * Called when {@link MusicPlaybackService#PLAYLIST_CHANGED} is invoked */ - public void onPlaylistChanged(); + void onPlaylistChanged(); /** * Called when {@link MusicPlaybackService#META_CHANGED} is invoked */ - public void onMetaChanged(); - + void onMetaChanged(); } diff --git a/src/org/lineageos/eleven/adapters/AlbumAdapter.java b/src/org/lineageos/eleven/adapters/AlbumAdapter.java index 010f57cbea9c2ba098f050875b96e2603cb637be..090d23e5023a96b972780fa1fab2f8b3b4f6b2b3 100644 --- a/src/org/lineageos/eleven/adapters/AlbumAdapter.java +++ b/src/org/lineageos/eleven/adapters/AlbumAdapter.java @@ -1,27 +1,31 @@ /* * Copyright (C) 2012 Andrew Neal * Copyright (C) 2014 The CyanogenMod Project - * Licensed under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law - * or agreed to in writing, software distributed under the License is - * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the specific language - * governing permissions and limitations under the License. + * Copyright (C) 2021 The LineageOS Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ - package org.lineageos.eleven.adapters; -import android.app.Activity; import android.content.Context; import android.view.LayoutInflater; -import android.view.View; import android.view.ViewGroup; import android.widget.ArrayAdapter; -import android.widget.BaseAdapter; -import org.lineageos.eleven.R; +import androidx.annotation.NonNull; +import androidx.fragment.app.FragmentActivity; +import androidx.recyclerview.widget.RecyclerView; + import org.lineageos.eleven.cache.ImageFetcher; import org.lineageos.eleven.model.Album; import org.lineageos.eleven.ui.MusicHolder; @@ -31,14 +35,15 @@ import org.lineageos.eleven.widgets.IPopupMenuCallback; import java.util.Collections; import java.util.List; +import java.util.function.Consumer; /** * This {@link ArrayAdapter} is used to display all of the albums on a user's - * device for {@link RecentsFragment} and {@link AlbumsFragment}. + * device. * * @author Andrew Neal (andrewdneal@gmail.com) */ -public class AlbumAdapter extends BaseAdapter implements IPopupMenuCallback { +public class AlbumAdapter extends RecyclerView.Adapter implements IPopupMenuCallback { /** * The resource Id of the layout to inflate */ @@ -60,105 +65,66 @@ public class AlbumAdapter extends BaseAdapter implements IPopupMenuCallback { */ private IPopupMenuCallback.IListener mListener; - /** number of columns of containing grid view, - * used to determine which views to pad */ - private int mColumns; - private int mPadding; - - private Context mContext; + private final Context mContext; + private final Consumer mOnItemClickedListener; /** * Constructor of AlbumAdapter * - * @param context The {@link Context} to use. + * @param context The {@link Context} to use. * @param layoutId The resource Id of the view to inflate. - * @param style Determines which layout to use and therefore which items to - * load. */ - public AlbumAdapter(final Activity context, final int layoutId) { + public AlbumAdapter(final FragmentActivity context, final int layoutId, + final Consumer onItemClickedListener) { mContext = context; // Get the layout Id mLayoutId = layoutId; // Initialize the cache & image fetcher mImageFetcher = ElevenUtils.getImageFetcher(context); - mPadding = context.getResources().getDimensionPixelSize(R.dimen.list_item_general_margin); + mOnItemClickedListener = onItemClickedListener; } - /** - * {@inheritDoc} - */ + @NonNull @Override - public View getView(final int position, View convertView, final ViewGroup parent) { - // Recycle ViewHolder's items - MusicHolder holder; - if (convertView == null) { - convertView = LayoutInflater.from(mContext).inflate(mLayoutId, parent, false); - holder = new MusicHolder(convertView); - convertView.setTag(holder); - // set the pop up menu listener - holder.mPopupMenuButton.get().setPopupMenuClickedListener(mListener); - } else { - holder = (MusicHolder)convertView.getTag(); - } + public MusicHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { + return new MusicHolder(LayoutInflater.from(mContext).inflate(mLayoutId, parent, false)); + } + + @Override + public int getItemCount() { + return mAlbums.size(); + } - adjustPadding(position, convertView); + public Album getItem(int pos) { + return mAlbums.get(pos); + } + @Override + public void onBindViewHolder(@NonNull MusicHolder holder, int position) { // Retrieve the data holder final DataHolder dataHolder = mData[position]; + // set the pop up menu listener + holder.mPopupMenuButton.get().setPopupMenuClickedListener(mListener); // Sets the position each time because of recycling holder.mPopupMenuButton.get().setPosition(position); // Set each album name (line one) - holder.mLineOne.get().setText(dataHolder.mLineOne); + holder.mLineOne.get().setText(dataHolder.lineOne); // Set the artist name (line two) - holder.mLineTwo.get().setText(dataHolder.mLineTwo); + holder.mLineTwo.get().setText(dataHolder.lineTwo); + // Set click listener + holder.itemView.setOnClickListener(v -> mOnItemClickedListener.accept(getItem(position))); // Asynchronously load the album images into the adapter mImageFetcher.loadAlbumImage( - dataHolder.mLineTwo, dataHolder.mLineOne, - dataHolder.mItemId, holder.mImage.get()); - - return convertView; - } - - private void adjustPadding(final int position, View convertView) { - if (position < mColumns) { - // first row - convertView.setPadding(0, mPadding, 0, 0); - return; - } - int count = getCount(); - int footers = count % mColumns; - if (footers == 0) { footers = mColumns; } - if (position >= (count-footers)) { - // last row - convertView.setPadding(0, 0, 0, mPadding); - } else { - // middle rows - convertView.setPadding(0, 0 ,0, 0); - } - } - - /** - * {@inheritDoc} - */ - @Override - public boolean hasStableIds() { - return true; + dataHolder.lineTwo, dataHolder.lineOne, + dataHolder.itemId, holder.mImage.get()); } @Override - public int getCount() { - return mAlbums.size(); + public long getItemId(int pos) { + return pos; } - @Override - public Album getItem(int pos) { - return mAlbums.get(pos); - } - - @Override - public long getItemId(int pos) { return pos; } - /** * Method used to cache the data used to populate the list or grid. The idea * is to cache everything before {@code #getView(int, View, ViewGroup)} is @@ -169,44 +135,42 @@ public class AlbumAdapter extends BaseAdapter implements IPopupMenuCallback { int i = 0; for (Album album : mAlbums) { mData[i] = new DataHolder(); - mData[i].mItemId = album.mAlbumId; - mData[i].mLineOne = album.mAlbumName; - mData[i].mLineTwo = album.mArtistName; + mData[i].itemId = album.mAlbumId; + mData[i].lineOne = album.mAlbumName; + mData[i].lineTwo = album.mArtistName; i++; } } public void setData(List albums) { + int oldSize = mAlbums == null ? 0 : mAlbums.size(); + int newSize = albums.size(); + mAlbums = albums; buildCache(); - notifyDataSetChanged(); - } - public void setNumColumns(int columns) { - mColumns = columns; - } - - public void unload() { - setData(Collections.emptyList()); - } - - /** - * @param pause True to temporarily pause the disk cache, false otherwise. - */ - public void setPauseDiskCache(final boolean pause) { - if (mImageFetcher != null) { - mImageFetcher.setPauseDiskCache(pause); + if (oldSize == 0) { + notifyItemRangeInserted(0, newSize); + } else { + int diff = oldSize - newSize; + if (diff > 0) { + // Items were removed + notifyItemRangeChanged(0, newSize); + notifyItemRangeRemoved(newSize, diff); + } else if (diff < 0) { + // Items were added + notifyItemRangeChanged(0, oldSize); + notifyItemRangeInserted(oldSize, diff * -1); + } else { + notifyItemChanged(0, oldSize); + } } } - /** - * @param album The key used to find the cached album to remove - */ - public void removeFromCache(final Album album) { - if (mImageFetcher != null) { - mImageFetcher.removeFromCache( - ImageFetcher.generateAlbumCacheKey(album.mAlbumName, album.mArtistName)); - } + public void unload() { + int size = mAlbums.size(); + mAlbums.clear(); + notifyItemRangeRemoved(0, size); } /** @@ -216,25 +180,8 @@ public class AlbumAdapter extends BaseAdapter implements IPopupMenuCallback { mImageFetcher.flush(); } - /** - * Gets the item position for a given id - * @param id identifies the object - * @return the position if found, -1 otherwise - */ - public int getItemPosition(long id) { - int i = 0; - for (Album album : mAlbums) { - if (album.mAlbumId == id) { - return i; - } - i++; - } - - return -1; - } - @Override public void setPopupMenuClickedListener(IPopupMenuCallback.IListener listener) { mListener = listener; } -} \ No newline at end of file +} diff --git a/src/org/lineageos/eleven/adapters/AlbumArtPagerAdapter.java b/src/org/lineageos/eleven/adapters/AlbumArtPagerAdapter.java index 117a6ff3188cb958edd6a1503e9b3225bd8bd7d3..23cb0b00009d07478c8081747e5b765b091cf287 100644 --- a/src/org/lineageos/eleven/adapters/AlbumArtPagerAdapter.java +++ b/src/org/lineageos/eleven/adapters/AlbumArtPagerAdapter.java @@ -1,21 +1,22 @@ /* -* Copyright (C) 2014 The CyanogenMod Project -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ - + * Copyright (C) 2014 The CyanogenMod Project + * Copyright (C) 2018-2021 The LineageOS Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package org.lineageos.eleven.adapters; +import android.annotation.SuppressLint; import android.content.Context; import android.os.AsyncTask; import android.os.Bundle; @@ -24,6 +25,8 @@ import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import androidx.fragment.app.Fragment; import androidx.fragment.app.FragmentManager; import androidx.fragment.app.FragmentStatePagerAdapter; @@ -31,13 +34,12 @@ import androidx.fragment.app.FragmentStatePagerAdapter; import org.lineageos.eleven.BuildConstants; import org.lineageos.eleven.MusicPlaybackService; import org.lineageos.eleven.R; -import org.lineageos.eleven.cache.ICacheListener; -import org.lineageos.eleven.cache.ImageCache; import org.lineageos.eleven.model.AlbumArtistDetails; import org.lineageos.eleven.utils.ElevenUtils; import org.lineageos.eleven.utils.MusicUtils; import org.lineageos.eleven.widgets.SquareImageView; +import java.lang.ref.WeakReference; import java.util.Iterator; import java.util.LinkedList; @@ -45,17 +47,19 @@ import java.util.LinkedList; * A {@link androidx.fragment.app.FragmentStatePagerAdapter} class for swiping between album art */ public class AlbumArtPagerAdapter extends FragmentStatePagerAdapter { - private static boolean DEBUG = false; + private static final boolean DEBUG = false; private static final String TAG = AlbumArtPagerAdapter.class.getSimpleName(); public static final long NO_TRACK_ID = -1; private static final int MAX_ALBUM_ARTIST_SIZE = 10; // This helps with flickering and jumping and reloading the same tracks - private final static LinkedList sCacheAlbumArtistDetails = new LinkedList<>(); + private final static LinkedList sCacheAlbumArtistDetails = + new LinkedList<>(); /** * Adds the album artist details to the cache + * * @param details the AlbumArtistDetails to add */ public static void addAlbumArtistDetails(AlbumArtistDetails details) { @@ -70,11 +74,13 @@ public class AlbumArtPagerAdapter extends FragmentStatePagerAdapter { /** * Gets the album artist details for the audio track. If it exists, it re-inserts the item * to the end of the queue so it is considered the 'freshest' and stays longer + * * @param audioId the audio track to look for * @return the details of the album artist */ public static AlbumArtistDetails getAlbumArtistDetails(long audioId) { - for (Iterator i = sCacheAlbumArtistDetails.descendingIterator(); i.hasNext();) { + for (Iterator i = sCacheAlbumArtistDetails.descendingIterator(); + i.hasNext(); ) { final AlbumArtistDetails entry = i.next(); if (entry.mAudioId == audioId) { // remove it from the stack to re-add to the top @@ -91,10 +97,11 @@ public class AlbumArtPagerAdapter extends FragmentStatePagerAdapter { private int mPlaylistLen = 0; public AlbumArtPagerAdapter(FragmentManager fm) { - super(fm); + super(fm, FragmentStatePagerAdapter.BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT); } @Override + @NonNull public Fragment getItem(final int position) { long trackID = getTrackId(position); return AlbumArtFragment.newInstance(trackID); @@ -112,6 +119,7 @@ public class AlbumArtPagerAdapter extends FragmentStatePagerAdapter { /** * Gets the track id for the item at position + * * @param position position of the item of the queue * @return track id of the item at position or NO_TRACK_ID if unknown */ @@ -153,11 +161,10 @@ public class AlbumArtPagerAdapter extends FragmentStatePagerAdapter { * The fragments to be displayed inside this adapter. This wraps the album art * and handles loading the album art for a given audio id */ - public static class AlbumArtFragment extends Fragment implements ICacheListener { + public static class AlbumArtFragment extends Fragment { private static final String ID = BuildConstants.PACKAGE_NAME + ".adapters.AlbumArtPagerAdapter.AlbumArtFragment.ID"; - private View mRootView; private AlbumArtistLoader mTask; private SquareImageView mImageView; private long mAudioId = NO_TRACK_ID; @@ -174,21 +181,22 @@ public class AlbumArtPagerAdapter extends FragmentStatePagerAdapter { public void onCreate(final Bundle savedInstanceState) { super.onCreate(savedInstanceState); - mAudioId = getArguments().getLong(ID, NO_TRACK_ID); - ImageCache.getInstance(getActivity()).addCacheListener(this); + final Bundle args = getArguments(); + mAudioId = args == null ? NO_TRACK_ID : args.getLong(ID, NO_TRACK_ID); } @Override - public View onCreateView(final LayoutInflater inflater, final ViewGroup container, final Bundle savedInstanceState) { - mRootView = inflater.inflate(R.layout.album_art_fragment, null); - return mRootView; + @SuppressLint("InflateParams") + public View onCreateView(final LayoutInflater inflater, final ViewGroup container, + final Bundle savedInstanceState) { + View rootView = inflater.inflate(R.layout.album_art_fragment, null); + mImageView = rootView.findViewById(R.id.audio_player_album_art); + return rootView; } @Override public void onDestroy() { super.onDestroy(); - - ImageCache.getInstance(getActivity()).removeCacheListener(this); } @Override @@ -203,9 +211,8 @@ public class AlbumArtPagerAdapter extends FragmentStatePagerAdapter { } @Override - public void onActivityCreated(final Bundle savedInstanceState) { - super.onActivityCreated(savedInstanceState); - mImageView = (SquareImageView)mRootView.findViewById(R.id.audio_player_album_art); + public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); loadImageAsync(); } @@ -230,13 +237,14 @@ public class AlbumArtPagerAdapter extends FragmentStatePagerAdapter { } mTask = new AlbumArtistLoader(this, getActivity()); - ElevenUtils.execute(false, mTask, mAudioId); + ElevenUtils.execute(mTask, mAudioId); } } /** * Loads the image asynchronously + * * @param details details of the image to load */ private void loadImageAsync(AlbumArtistDetails details) { @@ -248,29 +256,24 @@ public class AlbumArtPagerAdapter extends FragmentStatePagerAdapter { mImageView ); } - - @Override - public void onCacheUnpaused() { - loadImageAsync(); - } } /** * This looks up the album and artist details for a track */ private static class AlbumArtistLoader extends AsyncTask { - private Context mContext; - private AlbumArtFragment mFragment; + private final WeakReference mContext; + private final AlbumArtFragment mFragment; public AlbumArtistLoader(final AlbumArtFragment albumArtFragment, final Context context) { - mContext = context; + mContext = new WeakReference<>(context); mFragment = albumArtFragment; } @Override protected AlbumArtistDetails doInBackground(final Long... params) { long id = params[0]; - return MusicUtils.getAlbumArtDetails(mContext, id); + return MusicUtils.getAlbumArtDetails(mContext.get(), id); } @Override diff --git a/src/org/lineageos/eleven/adapters/AlbumDetailSongAdapter.java b/src/org/lineageos/eleven/adapters/AlbumDetailSongAdapter.java index 20efebccd7130bd7d2780f9e6f40debc0f65cbc0..585ae27ac6a2c88488d2ff06b1c9dde519feaf5b 100644 --- a/src/org/lineageos/eleven/adapters/AlbumDetailSongAdapter.java +++ b/src/org/lineageos/eleven/adapters/AlbumDetailSongAdapter.java @@ -1,77 +1,61 @@ /* -* Copyright (C) 2014 The CyanogenMod Project -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ + * Copyright (C) 2014 The CyanogenMod Project + * Copyright (C) 2021 The LineageOS Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package org.lineageos.eleven.adapters; -import android.app.Activity; import android.content.Context; -import android.os.Bundle; import android.view.View; import android.widget.TextView; -import androidx.loader.content.Loader; +import androidx.fragment.app.FragmentActivity; import org.lineageos.eleven.Config; import org.lineageos.eleven.R; import org.lineageos.eleven.cache.ImageFetcher; -import org.lineageos.eleven.loaders.AlbumSongLoader; import org.lineageos.eleven.model.Song; -import org.lineageos.eleven.ui.fragments.AlbumDetailFragment; import org.lineageos.eleven.utils.MusicUtils; -import java.util.List; +public class AlbumDetailSongAdapter extends DetailSongAdapter { -public abstract class AlbumDetailSongAdapter extends DetailSongAdapter { - private AlbumDetailFragment mFragment; - - public AlbumDetailSongAdapter(Activity activity, AlbumDetailFragment fragment) { + public AlbumDetailSongAdapter(FragmentActivity activity) { super(activity); - mFragment = fragment; } - protected int rowLayoutId() { return R.layout.album_detail_song; } + @Override + protected int rowLayoutId() { + return R.layout.album_detail_song; + } + @Override protected Config.IdType getSourceType() { return Config.IdType.Album; } - @Override // LoaderCallbacks - public Loader> onCreateLoader(int id, Bundle args) { - onLoading(); - setSourceId(args.getLong(Config.ID)); - return new AlbumSongLoader(mActivity, getSourceId()); - } - - @Override // LoaderCallbacks - public void onLoadFinished(Loader> loader, List songs) { - super.onLoadFinished(loader, songs); - mFragment.update(songs); - } - protected Holder newHolder(View root, ImageFetcher fetcher) { - return new AlbumHolder(root, fetcher, mActivity); + return new AlbumHolder(root, fetcher, mContext); } private static class AlbumHolder extends Holder { - TextView duration; - Context context; + final TextView duration; + final Context context; protected AlbumHolder(View root, ImageFetcher fetcher, Context context) { super(root, fetcher); this.context = context; - duration = (TextView)root.findViewById(R.id.duration); + duration = root.findViewById(R.id.duration); } protected void update(Song song) { @@ -79,4 +63,4 @@ public abstract class AlbumDetailSongAdapter extends DetailSongAdapter { duration.setText(MusicUtils.makeShortTimeString(context, song.mDuration)); } } -} \ No newline at end of file +} diff --git a/src/org/lineageos/eleven/adapters/ArtistAdapter.java b/src/org/lineageos/eleven/adapters/ArtistAdapter.java index 59827b3297324f54c1a3d9df3b31270dc1f19d37..2b40c6c9a5dafd207e8f29eceb8c50531de8cc7d 100644 --- a/src/org/lineageos/eleven/adapters/ArtistAdapter.java +++ b/src/org/lineageos/eleven/adapters/ArtistAdapter.java @@ -1,50 +1,50 @@ /* * Copyright (C) 2012 Andrew Neal * Copyright (C) 2014 The CyanogenMod Project - * Licensed under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law - * or agreed to in writing, software distributed under the License is - * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the specific language - * governing permissions and limitations under the License. + * Copyright (C) 2021 The LineageOS Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ - package org.lineageos.eleven.adapters; -import android.app.Activity; import android.content.Context; import android.view.LayoutInflater; -import android.view.View; import android.view.ViewGroup; import android.widget.ArrayAdapter; +import androidx.annotation.NonNull; +import androidx.fragment.app.FragmentActivity; +import androidx.recyclerview.widget.RecyclerView; + import org.lineageos.eleven.R; import org.lineageos.eleven.cache.ImageFetcher; import org.lineageos.eleven.model.Artist; -import org.lineageos.eleven.sectionadapter.SectionAdapter.BasicAdapter; import org.lineageos.eleven.ui.MusicHolder; -import org.lineageos.eleven.ui.MusicHolder.DataHolder; import org.lineageos.eleven.utils.ElevenUtils; import org.lineageos.eleven.utils.MusicUtils; import org.lineageos.eleven.widgets.IPopupMenuCallback; +import java.util.ArrayList; +import java.util.List; +import java.util.function.Consumer; + /** * This {@link ArrayAdapter} is used to display all of the artists on a user's - * device for {@link ArtistFragment}. + * device * * @author Andrew Neal (andrewdneal@gmail.com) */ -/** - * @author Andrew Neal (andrewdneal@gmail.com) - */ -public class ArtistAdapter extends ArrayAdapter implements BasicAdapter, IPopupMenuCallback { - - /** - * Number of views (ImageView and TextView) - */ - private static final int VIEW_TYPE_COUNT = 2; +public class ArtistAdapter extends RecyclerView.Adapter implements IPopupMenuCallback { /** * The resource Id of the layout to inflate @@ -56,137 +56,77 @@ public class ArtistAdapter extends ArrayAdapter implements BasicAdapter, */ private final ImageFetcher mImageFetcher; - /** - * Semi-transparent overlay - */ - private final int mOverlay; - /** * Used to cache the artist info */ - private DataHolder[] mData; + private List mArtists; /** * Used to listen to the pop up menu callbacks */ private IListener mListener; + private final Context mContext; + private final Consumer mOnItemClickListener; + /** * Constructor of ArtistAdapter * - * @param context The {@link Context} to use. + * @param context The {@link Context} to use. * @param layoutId The resource Id of the view to inflate. */ - public ArtistAdapter(final Activity context, final int layoutId) { - super(context, 0); + public ArtistAdapter(final FragmentActivity context, final int layoutId, + final Consumer onItemClickListener) { + mContext = context; // Get the layout Id mLayoutId = layoutId; // Initialize the cache & image fetcher mImageFetcher = ElevenUtils.getImageFetcher(context); - // Cache the transparent overlay - mOverlay = context.getResources().getColor(R.color.list_item_background); + mOnItemClickListener = onItemClickListener; + mArtists = new ArrayList<>(0); } - /** - * {@inheritDoc} - */ + @NonNull @Override - public View getView(final int position, View convertView, final ViewGroup parent) { - // Recycle ViewHolder's items - MusicHolder holder; - if (convertView == null) { - convertView = LayoutInflater.from(getContext()).inflate(mLayoutId, parent, false); - holder = new MusicHolder(convertView); - convertView.setTag(holder); - - // set the pop up menu listener - holder.mPopupMenuButton.get().setPopupMenuClickedListener(mListener); - } else { - holder = (MusicHolder)convertView.getTag(); - } - - // Retrieve the data holder - final DataHolder dataHolder = mData[position]; + public MusicHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { + return new MusicHolder(LayoutInflater.from(parent.getContext()) + .inflate(mLayoutId, parent, false)); + } + @Override + public void onBindViewHolder(@NonNull MusicHolder holder, int position) { + Artist artist = getItem(position); + String albumNumber = MusicUtils.makeLabel(mContext, + R.plurals.Nalbums, artist.mAlbumNumber); + String songNumber = MusicUtils.makeLabel(mContext, + R.plurals.Nsongs, artist.mSongNumber); + + holder.itemView.setOnClickListener(v -> mOnItemClickListener.accept(position)); + // set the pop up menu listener + holder.mPopupMenuButton.get().setPopupMenuClickedListener(mListener); // Set each artist name (line one) - holder.mLineOne.get().setText(dataHolder.mLineOne); + holder.mLineOne.get().setText(artist.mArtistName); // Set the number of albums (line two) - holder.mLineTwo.get().setText(dataHolder.mLineTwo); + holder.mLineTwo.get().setText(MusicUtils.makeCombinedString(mContext, + albumNumber, songNumber)); // Asynchronously load the artist image into the adapter - mImageFetcher.loadArtistImage(dataHolder.mLineOne, holder.mImage.get()); + mImageFetcher.loadArtistImage(artist.mArtistName, holder.mImage.get()); // because of recycling, we need to set the position each time holder.mPopupMenuButton.get().setPosition(position); - - return convertView; } - /** - * {@inheritDoc} - */ - @Override - public boolean hasStableIds() { - return true; - } - - /** - * {@inheritDoc} - */ @Override - public int getViewTypeCount() { - return VIEW_TYPE_COUNT; - } - - /** - * Method used to cache the data used to populate the list or grid. The idea - * is to cache everything before {@code #getView(int, View, ViewGroup)} is - * called. - */ - public void buildCache() { - mData = new DataHolder[getCount()]; - for (int i = 0; i < getCount(); i++) { - // Build the artist - final Artist artist = getItem(i); - - // Build the data holder - mData[i] = new DataHolder(); - // Artist Id - mData[i].mItemId = artist.mArtistId; - // Artist names (line one) - mData[i].mLineOne = artist.mArtistName; - - String albumNumber = MusicUtils.makeLabel(getContext(), - R.plurals.Nalbums, artist.mAlbumNumber); - String songNumber = MusicUtils.makeLabel(getContext(), - R.plurals.Nsongs, artist.mSongNumber); - - mData[i].mLineTwo = MusicUtils.makeCombinedString(getContext(), albumNumber, songNumber); - } + public int getItemCount() { + return mArtists.size(); } /** * Method that unloads and clears the items in the adapter */ public void unload() { - clear(); - mData = null; - } - - /** - * @param pause True to temporarily pause the disk cache, false otherwise. - */ - public void setPauseDiskCache(final boolean pause) { - if (mImageFetcher != null) { - mImageFetcher.setPauseDiskCache(pause); - } - } - - /** - * @param artist The key used to find the cached artist to remove - */ - public void removeFromCache(final Artist artist) { - if (mImageFetcher != null) { - mImageFetcher.removeFromCache(artist.mArtistName); - } + int size = mArtists.size(); + mArtists.clear(); + notifyItemRangeRemoved(0, size); } /** @@ -196,24 +136,36 @@ public class ArtistAdapter extends ArrayAdapter implements BasicAdapter, mImageFetcher.flush(); } - /** - * Gets the item position for a given id - * @param id identifies the object - * @return the position if found, -1 otherwise - */ @Override - public int getItemPosition(long id) { - for (int i = 0; i < getCount(); i++) { - if (getItem(i).mArtistId == id) { - return i; - } - } + public void setPopupMenuClickedListener(IListener listener) { + mListener = listener; + } - return -1; + public Artist getItem(int position) { + return mArtists.get(position); } - @Override - public void setPopupMenuClickedListener(IListener listener) { - mListener = listener; + public void setData(List artists) { + int oldSize = mArtists == null ? 0 : mArtists.size(); + int newSize = artists.size(); + + mArtists = artists; + + if (oldSize == 0) { + notifyItemRangeInserted(0, newSize); + } else { + int diff = oldSize - newSize; + if (diff > 0) { + // Items were removed + notifyItemRangeChanged(0, newSize); + notifyItemRangeRemoved(newSize, diff); + } else if (diff < 0) { + // Items were added + notifyItemRangeChanged(0, oldSize); + notifyItemRangeInserted(oldSize, diff * -1); + } else { + notifyItemChanged(0, oldSize); + } + } } } diff --git a/src/org/lineageos/eleven/adapters/ArtistDetailAlbumAdapter.java b/src/org/lineageos/eleven/adapters/ArtistDetailAlbumAdapter.java index b73912a226124e01729431c3061e7be0b5699804..3eca0172a6345c24405e959f1fc82a9f1d226def 100644 --- a/src/org/lineageos/eleven/adapters/ArtistDetailAlbumAdapter.java +++ b/src/org/lineageos/eleven/adapters/ArtistDetailAlbumAdapter.java @@ -1,36 +1,35 @@ /* -* Copyright (C) 2014 The CyanogenMod Project -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ + * Copyright (C) 2014 The CyanogenMod Project + * Copyright (C) 2021 The LineageOS Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package org.lineageos.eleven.adapters; import android.app.Activity; -import android.os.Bundle; +import android.text.TextUtils; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.ImageView; import android.widget.TextView; -import androidx.loader.app.LoaderManager; -import androidx.loader.content.Loader; +import androidx.annotation.NonNull; +import androidx.fragment.app.FragmentActivity; import androidx.recyclerview.widget.RecyclerView; -import org.lineageos.eleven.Config; import org.lineageos.eleven.R; import org.lineageos.eleven.cache.ImageFetcher; -import org.lineageos.eleven.loaders.AlbumLoader; import org.lineageos.eleven.model.Album; import org.lineageos.eleven.utils.ElevenUtils; import org.lineageos.eleven.utils.NavUtils; @@ -41,70 +40,94 @@ import java.util.Collections; import java.util.List; public class ArtistDetailAlbumAdapter -extends RecyclerView.Adapter -implements LoaderManager.LoaderCallbacks>, IPopupMenuCallback { + extends RecyclerView.Adapter + implements IPopupMenuCallback { private static final int TYPE_FIRST = 1; private static final int TYPE_MIDDLE = 2; private static final int TYPE_LAST = 3; - private final Activity mActivity; + /** + * Image cache and image fetcher. + */ private final ImageFetcher mImageFetcher; - private final LayoutInflater mInflater; - private List mAlbums = Collections.emptyList(); + + /** + * Used to listen to the pop up menu callbacks + */ private IListener mListener; - private int mListMargin; - public ArtistDetailAlbumAdapter(final Activity activity) { + /** + * Used to cache the album info. + */ + private List mAlbums = Collections.emptyList(); + + private final Activity mActivity; + + private final int mListMargin; + + /** + * Constructor of ArtistDetailAlbumAdapter + * + * @param activity The {@link FragmentActivity} to use. + */ + public ArtistDetailAlbumAdapter(final FragmentActivity activity) { mActivity = activity; mImageFetcher = ElevenUtils.getImageFetcher(activity); - mInflater = LayoutInflater.from(activity); mListMargin = activity.getResources(). - getDimensionPixelSize(R.dimen.list_item_general_margin); + getDimensionPixelSize(R.dimen.list_item_general_margin); } @Override public int getItemViewType(int position) { // use view types to distinguish first and last elements // so they can be given special treatment for layout - if(position == 0) { return TYPE_FIRST; } - else if(position == getItemCount()-1) { return TYPE_LAST; } - else return TYPE_MIDDLE; + if (position == 0) { + return TYPE_FIRST; + } else if (position == getItemCount() - 1) { + return TYPE_LAST; + } else return TYPE_MIDDLE; } @Override - public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { - View v = mInflater.inflate(R.layout.artist_detail_album, parent, false); + @NonNull + public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { + View v = LayoutInflater.from(parent.getContext()) + .inflate(R.layout.artist_detail_album, parent, false); // add extra margin to the first and last elements - ViewGroup.MarginLayoutParams params = (ViewGroup.MarginLayoutParams)v.getLayoutParams(); - if (viewType == TYPE_FIRST) { params.leftMargin = mListMargin; } - else if(viewType == TYPE_LAST) { params.rightMargin = mListMargin; } + ViewGroup.MarginLayoutParams params = (ViewGroup.MarginLayoutParams) v.getLayoutParams(); + if (viewType == TYPE_FIRST) { + params.leftMargin = mListMargin; + } else if (viewType == TYPE_LAST) { + params.rightMargin = mListMargin; + } return new ViewHolder(v); } @Override - public void onBindViewHolder(ViewHolder holder, int position) { + public void onBindViewHolder(@NonNull ViewHolder holder, int position) { Album a = mAlbums.get(position); - holder.title.setText(a.mAlbumName); - holder.year.setText(a.mYear); + StringBuilder sb = new StringBuilder(); + sb.append(a.mAlbumName); + if (!TextUtils.isEmpty(a.mYear)) { + sb.append('\n').append(a.mYear); + } + holder.description.setText(sb.toString()); mImageFetcher.loadAlbumImage( - a.mArtistName, a.mAlbumName, a.mAlbumId, holder.art); - holder.popupbutton.setPopupMenuClickedListener(mListener); - holder.popupbutton.setPosition(position); + a.mArtistName, a.mAlbumName, a.mAlbumId, holder.art); + holder.popupButton.setPopupMenuClickedListener(mListener); + holder.popupButton.setPosition(position); addAction(holder.itemView, a); } private void addAction(View view, final Album album) { - view.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - NavUtils.openAlbumProfile( - mActivity, album.mAlbumName, album.mArtistName, album.mAlbumId); - } - }); + view.setOnClickListener(v -> NavUtils.openAlbumProfile( + mActivity, album.mAlbumName, album.mArtistName, album.mAlbumId)); } @Override - public int getItemCount() { return mAlbums.size(); } + public int getItemCount() { + return mAlbums.size(); + } public Album getItem(int position) { return mAlbums.get(position); @@ -116,35 +139,47 @@ implements LoaderManager.LoaderCallbacks>, IPopupMenuCallback { } public static class ViewHolder extends RecyclerView.ViewHolder { - public ImageView art; - public TextView title; - public TextView year; - public PopupMenuButton popupbutton; + public final ImageView art; + public final TextView description; + public final PopupMenuButton popupButton; + public ViewHolder(View root) { super(root); - art = (ImageView)root.findViewById(R.id.album_art); - title = (TextView)root.findViewById(R.id.title); - year = (TextView)root.findViewById(R.id.year); - popupbutton = (PopupMenuButton)root.findViewById(R.id.overflow); + art = root.findViewById(R.id.image); + description = root.findViewById(R.id.description); + popupButton = root.findViewById(R.id.popup_menu_button); } } - @Override // LoaderCallbacks - public Loader> onCreateLoader(int id, Bundle args) { - return new AlbumLoader(mActivity, args.getLong(Config.ID)); - } + public void setData(List albums) { + int oldSize = mAlbums == null ? 0 : mAlbums.size(); + int newSize = albums.size(); - @Override // LoaderCallbacks - public void onLoadFinished(Loader> loader, List albums) { - if (albums.isEmpty()) { return; } mAlbums = albums; - notifyDataSetChanged(); + + if (oldSize == 0) { + notifyItemRangeInserted(0, newSize); + } else { + int diff = oldSize - newSize; + if (diff > 0) { + // Items were removed + notifyItemRangeChanged(0, newSize); + notifyItemRangeRemoved(newSize, diff); + } else if (diff < 0) { + // Items were added + notifyItemRangeChanged(0, oldSize); + notifyItemRangeInserted(oldSize, diff * -1); + } + } } - @Override // LoaderCallbacks - public void onLoaderReset(Loader> loader) { - mAlbums = Collections.emptyList(); - notifyDataSetChanged(); + /** + * Method that unloads and clears the items in the adapter + */ + public void unload() { + int size = mAlbums.size(); + mAlbums.clear(); mImageFetcher.flush(); + notifyItemRangeRemoved(0, size); } -} \ No newline at end of file +} diff --git a/src/org/lineageos/eleven/adapters/ArtistDetailSongAdapter.java b/src/org/lineageos/eleven/adapters/ArtistDetailSongAdapter.java index b7599dc4a33ede9883ca5d77367054b9f14c0356..ae36a67e8f083fb2953c51d22e93555db34a98cd 100644 --- a/src/org/lineageos/eleven/adapters/ArtistDetailSongAdapter.java +++ b/src/org/lineageos/eleven/adapters/ArtistDetailSongAdapter.java @@ -1,68 +1,60 @@ /* -* Copyright (C) 2014 The CyanogenMod Project -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ + * Copyright (C) 2014 The CyanogenMod Project + * Copyright (C) 2021 The LineageOS Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package org.lineageos.eleven.adapters; -import android.app.Activity; -import android.os.Bundle; -import android.provider.MediaStore; import android.view.View; import android.widget.ImageView; import android.widget.TextView; -import androidx.loader.content.Loader; +import androidx.fragment.app.FragmentActivity; import org.lineageos.eleven.Config; import org.lineageos.eleven.R; import org.lineageos.eleven.cache.ImageFetcher; -import org.lineageos.eleven.loaders.SongLoader; import org.lineageos.eleven.model.Song; -import java.util.List; - -public abstract class ArtistDetailSongAdapter extends DetailSongAdapter { - public ArtistDetailSongAdapter(Activity activity) { +public class ArtistDetailSongAdapter extends DetailSongAdapter { + public ArtistDetailSongAdapter(FragmentActivity activity) { super(activity); } - protected int rowLayoutId() { return R.layout.artist_detail_song; } + @Override + protected int rowLayoutId() { + return R.layout.artist_detail_song; + } + @Override protected Config.IdType getSourceType() { return Config.IdType.Artist; } - @Override // LoaderCallbacks - public Loader> onCreateLoader(int id, Bundle args) { - onLoading(); - setSourceId(args.getLong(Config.ID)); - final String selection = MediaStore.Audio.AudioColumns.ARTIST_ID + "=" + getSourceId(); - return new SongLoader(mActivity, selection); - } - + @Override protected Holder newHolder(View root, ImageFetcher fetcher) { return new ArtistHolder(root, fetcher); } private static class ArtistHolder extends Holder { - ImageView art; - TextView album; + final ImageView art; + final TextView album; protected ArtistHolder(View root, ImageFetcher fetcher) { super(root, fetcher); - art = (ImageView)root.findViewById(R.id.album_art); - album = (TextView)root.findViewById(R.id.album); + art = root.findViewById(R.id.album_art); + album = root.findViewById(R.id.album); } protected void update(Song song) { @@ -74,4 +66,4 @@ public abstract class ArtistDetailSongAdapter extends DetailSongAdapter { } } } -} \ No newline at end of file +} diff --git a/src/org/lineageos/eleven/adapters/DetailSongAdapter.java b/src/org/lineageos/eleven/adapters/DetailSongAdapter.java index 80771b652b585687eca4c03d179eb7e1dcaa1143..3e908de956b06da5d5d7d7bbbc0c986d5fc35385 100644 --- a/src/org/lineageos/eleven/adapters/DetailSongAdapter.java +++ b/src/org/lineageos/eleven/adapters/DetailSongAdapter.java @@ -1,17 +1,31 @@ +/* + * Copyright (C) 2014 The CyanogenMod Project + * Copyright (C) 2021 The LineageOS Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package org.lineageos.eleven.adapters; -import android.app.Activity; +import android.content.Context; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; -import android.widget.AdapterView; -import android.widget.AdapterView.OnItemClickListener; -import android.widget.BaseAdapter; import android.widget.ImageView; import android.widget.TextView; -import androidx.loader.app.LoaderManager; -import androidx.loader.content.Loader; +import androidx.annotation.NonNull; +import androidx.fragment.app.FragmentActivity; +import androidx.recyclerview.widget.RecyclerView; import org.lineageos.eleven.Config; import org.lineageos.eleven.R; @@ -26,54 +40,106 @@ import org.lineageos.eleven.widgets.PopupMenuButton; import java.util.Collections; import java.util.List; -public abstract class DetailSongAdapter extends BaseAdapter implements - LoaderManager.LoaderCallbacks>, OnItemClickListener, IPopupMenuCallback { - protected final Activity mActivity; +public abstract class DetailSongAdapter extends RecyclerView.Adapter + implements IPopupMenuCallback { + + public static final int NOTHING_PLAYING = -1; + + /** + * Image cache and image fetcher. + */ private final ImageFetcher mImageFetcher; - private final LayoutInflater mInflater; - private List mSongs = Collections.emptyList(); - private IListener mListener; + + /** + * Source id. + */ private long mSourceId = -1; + + /** + * Used to listen to the pop up menu callbacks + */ + private IListener mListener; + + /** + * Current music track. + */ private MusicPlaybackTrack mCurrentlyPlayingTrack; - public DetailSongAdapter(final Activity activity) { - mActivity = activity; - mImageFetcher = ElevenUtils.getImageFetcher(activity); - mInflater = LayoutInflater.from(activity); + /** + * Used to cache the song info. + */ + private List mSongs = Collections.emptyList(); + + protected final Context mContext; + + /** + * Constructor of DetailSongAdapter + * + * @param context The {@link Context} to use. + */ + public DetailSongAdapter(final FragmentActivity context) { + mContext = context; + mImageFetcher = ElevenUtils.getImageFetcher(context); } @Override - public int getCount() { return mSongs.size(); } + public int getItemCount() { + return mSongs.size(); + } - @Override - public Song getItem(int pos) { return mSongs.get(pos); } + public Song getItem(int pos) { + return mSongs.get(pos); + } @Override - public long getItemId(int pos) { return pos; } + public long getItemId(int pos) { + return pos; + } + + protected long getSourceId() { + return mSourceId; + } - protected long getSourceId() { return mSourceId; } - protected void setSourceId(long id) { mSourceId = id; } + public void setSourceId(long id) { + mSourceId = id; + } public void setCurrentlyPlayingTrack(MusicPlaybackTrack currentTrack) { - if (mCurrentlyPlayingTrack == null || !mCurrentlyPlayingTrack.equals(currentTrack)) { - mCurrentlyPlayingTrack = currentTrack; - notifyDataSetChanged(); + if (mCurrentlyPlayingTrack != null && mCurrentlyPlayingTrack.equals(currentTrack)) { + return; + } + + long previousPlayingId = mCurrentlyPlayingTrack == null + ? NOTHING_PLAYING : mCurrentlyPlayingTrack.mId; + mCurrentlyPlayingTrack = currentTrack; + + int toBeUpdated = (currentTrack == null || currentTrack.mId == NOTHING_PLAYING) + ? 1 : 2; + int updated = 0; + + for (int i = 0; i < mSongs.size() && updated < toBeUpdated; i++) { + long id = mSongs.get(i).mSongId; + if ((currentTrack != null && id == currentTrack.mId) || id == previousPlayingId) { + notifyItemChanged(i); + updated++; + } } } + @NonNull @Override - public View getView(int pos, View convertView, ViewGroup parent) { - if(convertView == null) { - convertView = mInflater.inflate(rowLayoutId(), parent, false); - convertView.setTag(newHolder(convertView, mImageFetcher)); - } + public Holder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { + return newHolder(LayoutInflater.from(parent.getContext()) + .inflate(rowLayoutId(), parent, false), mImageFetcher); + } - Holder holder = (Holder)convertView.getTag(); - Song song = getItem(pos); + @Override + public void onBindViewHolder(@NonNull Holder holder, int position) { + Song song = getItem(position); holder.update(song); holder.popupMenuButton.setPopupMenuClickedListener(mListener); - holder.popupMenuButton.setPosition(pos); + holder.popupMenuButton.setPosition(position); if (mCurrentlyPlayingTrack != null && mCurrentlyPlayingTrack.mSourceId == getSourceId() @@ -83,48 +149,60 @@ public abstract class DetailSongAdapter extends BaseAdapter implements } else { holder.playIcon.setVisibility(View.GONE); } - - return convertView; + holder.itemView.setOnClickListener(v -> onItemClick(position)); } protected abstract int rowLayoutId(); - protected abstract void onLoading(); - protected abstract void onNoResults(); + protected abstract Config.IdType getSourceType(); - @Override // OnItemClickListener - public void onItemClick(AdapterView parent, View view, int pos, long id) { + private void onItemClick(int id) { // id is in this case the index in the underlying collection, // which is what we are interested in here -- so use as position - int position = (int)id; // ignore clicks on the header - if(id < 0) { return; } + if (id < 0) { + return; + } // play clicked song and enqueue the rest of the songs in the Adapter - int songCount = getCount(); + int songCount = getItemCount(); long[] toPlay = new long[songCount]; // add all songs to list - for(int i = 0; i < songCount; i++) { + for (int i = 0; i < songCount; i++) { toPlay[i] = getItem(i).mSongId; } // specify the song position to start playing - MusicUtils.playAll(mActivity, toPlay, position, getSourceId(), getSourceType(), false); + MusicUtils.playAll(toPlay, id, getSourceId(), getSourceType(), false); } - @Override // LoaderCallbacks - public void onLoadFinished(Loader> loader, List songs) { - if (songs.isEmpty()) { - onNoResults(); - return; - } + public void setData(List songs) { + int oldSize = mSongs == null ? 0 : mSongs.size(); + int newSize = songs.size(); + mSongs = songs; - notifyDataSetChanged(); + + if (oldSize == 0) { + notifyItemRangeInserted(0, newSize); + } else { + int diff = oldSize - newSize; + if (diff > 0) { + // Items were removed + notifyItemRangeChanged(0, newSize); + notifyItemRangeRemoved(newSize, diff); + } else if (diff < 0) { + // Items were added + notifyItemRangeChanged(0, oldSize); + notifyItemRangeInserted(oldSize, diff * -1); + } + } } - @Override // LoaderCallbacks - public void onLoaderReset(Loader> loader) { - mSongs = Collections.emptyList(); - notifyDataSetChanged(); - mImageFetcher.flush(); + /** + * Method that unloads and clears the items in the adapter + */ + public void unload() { + int size = mSongs.size(); + mSongs.clear(); + notifyItemRangeRemoved(0, size); } @Override @@ -134,19 +212,20 @@ public abstract class DetailSongAdapter extends BaseAdapter implements protected abstract Holder newHolder(View root, ImageFetcher fetcher); - protected static abstract class Holder { - protected ImageFetcher fetcher; - protected TextView title; - protected PopupMenuButton popupMenuButton; - protected ImageView playIcon; + protected static abstract class Holder extends RecyclerView.ViewHolder { + protected final ImageFetcher fetcher; + protected final TextView title; + protected final PopupMenuButton popupMenuButton; + protected final ImageView playIcon; protected Holder(View root, ImageFetcher fetcher) { + super(root); this.fetcher = fetcher; - title = (TextView)root.findViewById(R.id.title); - popupMenuButton = (PopupMenuButton)root.findViewById(R.id.overflow); - playIcon = (ImageView)root.findViewById(R.id.now_playing); + title = root.findViewById(R.id.title); + popupMenuButton = root.findViewById(R.id.overflow); + playIcon = root.findViewById(R.id.now_playing); } protected abstract void update(Song song); } -} \ No newline at end of file +} diff --git a/src/org/lineageos/eleven/adapters/PagerAdapter.java b/src/org/lineageos/eleven/adapters/PagerAdapter.java index d4e909262c14beca2e94423497c5672134121341..0bf7746aec352ab185c1e6857a041132001c5e3a 100644 --- a/src/org/lineageos/eleven/adapters/PagerAdapter.java +++ b/src/org/lineageos/eleven/adapters/PagerAdapter.java @@ -1,14 +1,19 @@ /* * Copyright (C) 2012 Andrew Neal * Copyright (C) 2014 The CyanogenMod Project - * Licensed under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law - * or agreed to in writing, software distributed under the License is - * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the specific language - * governing permissions and limitations under the License. + * Copyright (C) 2021 The LineageOS Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package org.lineageos.eleven.adapters; @@ -18,7 +23,9 @@ import android.os.Bundle; import android.util.SparseArray; import android.view.ViewGroup; +import androidx.annotation.NonNull; import androidx.fragment.app.Fragment; +import androidx.fragment.app.FragmentFactory; import androidx.fragment.app.FragmentManager; import androidx.fragment.app.FragmentPagerAdapter; @@ -45,15 +52,13 @@ public class PagerAdapter extends FragmentPagerAdapter { private final Context mContext; - private int mCurrentPage; - /** * Constructor of PagerAdatper * * @param fragmentManager The supporting fragment manager */ public PagerAdapter(final Context context, final FragmentManager fragmentManager) { - super(fragmentManager); + super(fragmentManager, FragmentPagerAdapter.BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT); mContext = context; } @@ -62,7 +67,7 @@ public class PagerAdapter extends FragmentPagerAdapter { * internally instantiate) * * @param className The full qualified name of fragment class. - * @param params The instantiate params. + * @param params The instantiate params. */ @SuppressWarnings("synthetic-access") public void add(final Class className, final Bundle params) { @@ -90,12 +95,10 @@ public class PagerAdapter extends FragmentPagerAdapter { return getItem(position); } - /** - * {@inheritDoc} - */ + @NonNull @Override - public Object instantiateItem(final ViewGroup container, final int position) { - final Fragment mFragment = (Fragment)super.instantiateItem(container, position); + public Object instantiateItem(@NonNull final ViewGroup container, final int position) { + final Fragment mFragment = (Fragment) super.instantiateItem(container, position); final WeakReference mWeakFragment = mFragmentArray.get(position); if (mWeakFragment != null) { mWeakFragment.clear(); @@ -104,22 +107,24 @@ public class PagerAdapter extends FragmentPagerAdapter { return mFragment; } - /** - * {@inheritDoc} - */ + @NonNull @Override public Fragment getItem(final int position) { final Holder mCurrentHolder = mHolderList.get(position); - final Fragment mFragment = Fragment.instantiate(mContext, - mCurrentHolder.mClassName, mCurrentHolder.mParams); - return mFragment; + final Class fragmentClass = FragmentFactory.loadFragmentClass( + mContext.getClassLoader(), mCurrentHolder.mClassName); + try { + final Fragment fragment = fragmentClass.newInstance(); + fragment.setArguments(mCurrentHolder.mParams); + return fragment; + } catch (InstantiationException | IllegalAccessException e) { + throw new RuntimeException(e); + } } - /** - * {@inheritDoc} - */ @Override - public void destroyItem(final ViewGroup container, final int position, final Object object) { + public void destroyItem(@NonNull final ViewGroup container, final int position, + @NonNull final Object object) { super.destroyItem(container, position, object); final WeakReference mWeakFragment = mFragmentArray.get(position); if (mWeakFragment != null) { @@ -127,41 +132,17 @@ public class PagerAdapter extends FragmentPagerAdapter { } } - /** - * {@inheritDoc} - */ @Override public int getCount() { return mHolderList.size(); } - /** - * {@inheritDoc} - */ @Override public CharSequence getPageTitle(final int position) { return mContext.getResources().getStringArray(R.array.page_titles)[position] .toUpperCase(Locale.getDefault()); } - /** - * Method that returns the current page position. - * - * @return int The current page. - */ - public int getCurrentPage() { - return mCurrentPage; - } - - /** - * Method that sets the current page position. - * - * @param currentPage The current page. - */ - protected void setCurrentPage(final int currentPage) { - mCurrentPage = currentPage; - } - /** * An enumeration of all the main fragments supported. */ @@ -183,14 +164,14 @@ public class PagerAdapter extends FragmentPagerAdapter { */ PLAYLIST(PlaylistFragment.class); - private Class mFragmentClass; + private final Class mFragmentClass; /** * Constructor of MusicFragments * * @param fragmentClass The fragment class */ - private MusicFragments(final Class fragmentClass) { + MusicFragments(final Class fragmentClass) { mFragmentClass = fragmentClass; } diff --git a/src/org/lineageos/eleven/adapters/PlaylistAdapter.java b/src/org/lineageos/eleven/adapters/PlaylistAdapter.java index 364c3e70a349996cd263aabd9e354439c0780a31..f7e38e1b7361c5e8bb1ed1195cf4a03a57776f97 100644 --- a/src/org/lineageos/eleven/adapters/PlaylistAdapter.java +++ b/src/org/lineageos/eleven/adapters/PlaylistAdapter.java @@ -1,16 +1,20 @@ /* * Copyright (C) 2012 Andrew Neal * Copyright (C) 2014 The CyanogenMod Project - * Licensed under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law - * or agreed to in writing, software distributed under the License is - * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the specific language - * governing permissions and limitations under the License. + * Copyright (C) 2021 The LineageOS Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ - package org.lineageos.eleven.adapters; import android.content.Context; @@ -19,6 +23,10 @@ import android.view.View; import android.view.ViewGroup; import android.widget.ArrayAdapter; +import androidx.annotation.NonNull; +import androidx.fragment.app.FragmentActivity; +import androidx.recyclerview.widget.RecyclerView; + import org.lineageos.eleven.Config.SmartPlaylistType; import org.lineageos.eleven.R; import org.lineageos.eleven.cache.ImageFetcher; @@ -29,18 +37,23 @@ import org.lineageos.eleven.ui.fragments.PlaylistFragment; import org.lineageos.eleven.utils.MusicUtils; import org.lineageos.eleven.widgets.IPopupMenuCallback; +import java.util.ArrayList; +import java.util.List; +import java.util.function.Consumer; + /** * This {@link ArrayAdapter} is used to display all of the playlists on a user's * device for {@link PlaylistFragment}. * * @author Andrew Neal (andrewdneal@gmail.com) */ -public class PlaylistAdapter extends ArrayAdapter implements IPopupMenuCallback { +public class PlaylistAdapter extends RecyclerView.Adapter implements + IPopupMenuCallback { /** - * Smart playlists and normal playlists + * Used to identify the view type */ - private static final int VIEW_TYPE_COUNT = 2; + private static final int USER_PLAYLIST_VIEW_TYPE = 0; /** * Used to identify the view type @@ -51,62 +64,62 @@ public class PlaylistAdapter extends ArrayAdapter implements IPopupMen * Used to cache the playlist info */ private DataHolder[] mData; + private final List mPlaylists; /** * Used to listen to the pop up menu callbacks */ protected IListener mListener; + /** + * Used to listen to item clicks. + */ + private final Consumer mOnItemClickListener; + + private final Context mContext; + /** * Constructor of PlaylistAdapter * - * @param context The {@link Context} to use. + * @param activity The {@link FragmentActivity} to use. */ - public PlaylistAdapter(final Context context) { - super(context, 0); + public PlaylistAdapter(final FragmentActivity activity, + final Consumer onItemClickListener) { + mContext = activity; + mOnItemClickListener = onItemClickListener; + mPlaylists = new ArrayList<>(); } - /** - * {@inheritDoc} - */ + @NonNull @Override - public View getView(final int position, View convertView, final ViewGroup parent) { - // Recycle ViewHolder's items - MusicHolder holder; - if (convertView == null) { - int layoutId = R.layout.list_item_normal; - - if (getItemViewType(position) == SMART_PLAYLIST_VIEW_TYPE) { - layoutId = R.layout.list_item_smart_playlist; - } - - convertView = LayoutInflater.from(getContext()).inflate(layoutId, parent, false); - holder = new MusicHolder(convertView); - convertView.setTag(holder); - - // set the pop up menu listener - holder.mPopupMenuButton.get().setPopupMenuClickedListener(mListener); - } else { - holder = (MusicHolder)convertView.getTag(); - } + public MusicHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { + return new MusicHolder(LayoutInflater.from(parent.getContext()) + .inflate(R.layout.list_item_normal, parent, false)); + } + @Override + public void onBindViewHolder(@NonNull MusicHolder holder, int position) { // Retrieve the data holder final DataHolder dataHolder = mData[position]; + // set the pop up menu listener + holder.mPopupMenuButton.get().setPopupMenuClickedListener(mListener); // because of recycling, we need to set the position each time holder.mPopupMenuButton.get().setPosition(position); // Set each playlist name (line one) - holder.mLineOne.get().setText(dataHolder.mLineOne); + holder.mLineOne.get().setText(dataHolder.lineOne); - if (dataHolder.mLineTwo == null) { + if (dataHolder.lineTwo == null) { holder.mLineTwo.get().setVisibility(View.GONE); } else { holder.mLineTwo.get().setVisibility(View.VISIBLE); - holder.mLineTwo.get().setText(dataHolder.mLineTwo); + holder.mLineTwo.get().setText(dataHolder.lineTwo); } - SmartPlaylistType type = SmartPlaylistType.getTypeById(dataHolder.mItemId); + holder.itemView.setOnClickListener(v -> mOnItemClickListener.accept(position)); + + SmartPlaylistType type = SmartPlaylistType.getTypeById(dataHolder.itemId); if (type != null) { // Set the image resource based on the icon switch (type) { @@ -123,41 +136,32 @@ public class PlaylistAdapter extends ArrayAdapter implements IPopupMen } } else { // load the image - ImageFetcher.getInstance(getContext()).loadPlaylistCoverArtImage( - dataHolder.mItemId, holder.mImage.get()); + ImageFetcher.getInstance(mContext).loadPlaylistCoverArtImage( + dataHolder.itemId, holder.mImage.get()); } - - - - return convertView; } - /** - * {@inheritDoc} - */ @Override - public boolean hasStableIds() { - return true; + public int getItemViewType(int position) { + if (getItem(position).isSmartPlaylist()) { + return SMART_PLAYLIST_VIEW_TYPE; + } else { + return USER_PLAYLIST_VIEW_TYPE; + } } - /** - * {@inheritDoc} - */ @Override - public int getViewTypeCount() { - return VIEW_TYPE_COUNT; + public int getItemCount() { + return mPlaylists.size(); } - /** - * {@inheritDoc} - */ - @Override - public int getItemViewType(int position) { - if (getItem(position).isSmartPlaylist()) { - return SMART_PLAYLIST_VIEW_TYPE; - } + public Playlist getItem(int position) { + return mPlaylists.get(position); + } - return 0; + public void add(Playlist playlist) { + mPlaylists.add(playlist); + notifyItemInserted(mPlaylists.size() - 1); } /** @@ -166,20 +170,20 @@ public class PlaylistAdapter extends ArrayAdapter implements IPopupMen * called. */ public void buildCache() { - mData = new DataHolder[getCount()]; - for (int i = 0; i < getCount(); i++) { + mData = new DataHolder[mPlaylists.size()]; + for (int i = 0; i < mPlaylists.size(); i++) { // Build the artist final Playlist playlist = getItem(i); // Build the data holder mData[i] = new DataHolder(); // Playlist Id - mData[i].mItemId = playlist.mPlaylistId; + mData[i].itemId = playlist.mPlaylistId; // Playlist names (line one) - mData[i].mLineOne = playlist.mPlaylistName; + mData[i].lineOne = playlist.mPlaylistName; // # of songs if (playlist.mSongCount >= 0) { - mData[i].mLineTwo = MusicUtils.makeLabel(getContext(), + mData[i].lineTwo = MusicUtils.makeLabel(mContext, R.plurals.Nsongs, playlist.mSongCount); } } @@ -189,8 +193,10 @@ public class PlaylistAdapter extends ArrayAdapter implements IPopupMen * Method that unloads and clears the items in the adapter */ public void unload() { - clear(); + int size = mPlaylists.size(); + mPlaylists.clear(); mData = null; + notifyItemRangeRemoved(0, size); } @Override diff --git a/src/org/lineageos/eleven/adapters/ProfileSongAdapter.java b/src/org/lineageos/eleven/adapters/ProfileSongAdapter.java index 086b664df0ec46e7ed8a2f1104877eb7c0de6fea..490b2d85b7d80be05b863d76686282f44e5ff440 100644 --- a/src/org/lineageos/eleven/adapters/ProfileSongAdapter.java +++ b/src/org/lineageos/eleven/adapters/ProfileSongAdapter.java @@ -1,28 +1,44 @@ /* * Copyright (C) 2012 Andrew Neal * Copyright (C) 2014 The CyanogenMod Project - * Licensed under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law - * or agreed to in writing, software distributed under the License is - * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the specific language - * governing permissions and limitations under the License. + * Copyright (C) 2021 The LineageOS Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ - package org.lineageos.eleven.adapters; -import android.app.Activity; +import android.content.Context; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.ArrayAdapter; +import androidx.annotation.NonNull; +import androidx.fragment.app.FragmentActivity; +import androidx.recyclerview.widget.RecyclerView; + import org.lineageos.eleven.Config; +import org.lineageos.eleven.cache.ImageFetcher; import org.lineageos.eleven.model.Song; +import org.lineageos.eleven.service.MusicPlaybackTrack; +import org.lineageos.eleven.ui.MusicHolder; +import org.lineageos.eleven.utils.ElevenUtils; +import org.lineageos.eleven.utils.MusicUtils; +import org.lineageos.eleven.widgets.IPopupMenuCallback; -import java.util.Collection; +import java.util.ArrayList; +import java.util.List; +import java.util.function.Consumer; /** * This {@link ArrayAdapter} is used to display the songs for a particular playlist @@ -30,108 +46,205 @@ import java.util.Collection; * * @author Andrew Neal (andrewdneal@gmail.com) */ -public class ProfileSongAdapter extends SongAdapter { +public class ProfileSongAdapter extends RecyclerView.Adapter implements + IPopupMenuCallback { + + private static final int NOTHING_PLAYING = -1; + /** - * Instead of having random +1 and -1 sprinkled around, this variable will show what is really - * related to the header + * The resource Id of the layout to inflate */ - public static final int NUM_HEADERS = 1; + private final int mLayoutId; /** - * Fake header layout Id + * Image cache and image fetcher */ - private final int mHeaderId; + private final ImageFetcher mImageFetcher; /** - * Constructor of ProfileSongAdapter - * - * @param activity The {@link Activity} to use - * @param layoutId The resource Id of the view to inflate. + * Used to cache the song info */ - public ProfileSongAdapter(final long playlistId, final Activity activity, final int layoutId, - final int headerId) { - super(activity, layoutId, playlistId, Config.IdType.Playlist); - // Cache the header - mHeaderId = headerId; - } + private List mSongs; /** - * {@inheritDoc} + * Used to listen to the pop up menu callbacks */ - @Override - public View getView(final int position, View convertView, final ViewGroup parent) { + private IPopupMenuCallback.IListener mListener; - // Return a faux header at position 0 - if (position == 0) { - if (convertView == null) { - convertView = LayoutInflater.from(getContext()).inflate(mHeaderId, parent, false); - } + /** + * Current music track + */ + private MusicPlaybackTrack mCurrentlyPlayingTrack; - return convertView; - } + /** + * Source id and type + */ + private final long mSourceId; + private final Config.IdType mSourceType = Config.IdType.Playlist; + + private final Context mContext; + private final Consumer mOnItemClickListener; - return super.getView(position, convertView, parent); + /** + * Constructor of ProfileSongAdapter + * + * @param context The {@link FragmentActivity} to use + * @param layoutId The resource Id of the view to inflate. + */ + public ProfileSongAdapter(final long playlistId, final FragmentActivity context, + final int layoutId, final Consumer onItemClickListener) { + mContext = context; + // Get the layout Id + mLayoutId = layoutId; + // Initialize the cache & image fetcher + mImageFetcher = ElevenUtils.getImageFetcher(context); + // set the source id and type + mSourceId = playlistId; + mOnItemClickListener = onItemClickListener; + mSongs = new ArrayList<>(0); } /** - * {@inheritDoc} + * Determines whether the song at the position should show the currently playing indicator + * + * @param song the song in question + * @return true if we want to show the indicator */ - protected boolean showNowPlayingIndicator(final Song song, final int position) { - return super.showNowPlayingIndicator(song, position) - && mCurrentlyPlayingTrack.mSourcePosition == position - NUM_HEADERS; + protected boolean showNowPlayingIndicator(final Song song) { + return mCurrentlyPlayingTrack != null + && mCurrentlyPlayingTrack.mSourceId == mSourceId + && mCurrentlyPlayingTrack.mSourceType == mSourceType + && mCurrentlyPlayingTrack.mId == song.mSongId; + } + + @NonNull + @Override + public MusicHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { + return new MusicHolder(LayoutInflater.from(parent.getContext()) + .inflate(mLayoutId, parent, false)); } @Override - public boolean isEnabled(int position) { - if (position == 0) { - return false; + public void onBindViewHolder(@NonNull MusicHolder holder, int position) { + // Retrieve the data holder + Song item = getItem(position); + + holder.itemView.setOnClickListener(v -> mOnItemClickListener.accept(position)); + + holder.mPopupMenuButton.get().setPopupMenuClickedListener(mListener); + // Sets the position each time because of recycling + holder.mPopupMenuButton.get().setPosition(position); + // Set each song name (line one) + holder.mLineOne.get().setText(item.mSongName); + // Set the album name (line two) + holder.mLineTwo.get().setText(MusicUtils.makeCombinedString(mContext, item.mArtistName, + item.mAlbumName)); + + // Asynchronously load the artist image into the adapter + if (item.mAlbumId >= 0) { + mImageFetcher.loadAlbumImage(item.mArtistName, item.mAlbumName, item.mAlbumId, + holder.mImage.get()); } - return super.isEnabled(position); + View nowPlayingIndicator = holder.mNowPlayingIndicator.get(); + if (nowPlayingIndicator != null) { + if (showNowPlayingIndicator(item)) { + nowPlayingIndicator.setVisibility(View.VISIBLE); + } else { + nowPlayingIndicator.setVisibility(View.GONE); + } + } + } + + @Override + public int getItemCount() { + return mSongs.size(); } /** - * {@inheritDoc} + * Method that unloads and clears the items in the adapter */ + public void unload() { + int size = mSongs.size(); + mSongs.clear(); + notifyItemRangeRemoved(0, size); + } + @Override - public int getViewTypeCount() { - return super.getViewTypeCount() + NUM_HEADERS; + public void setPopupMenuClickedListener(IPopupMenuCallback.IListener listener) { + mListener = listener; } /** - * {@inheritDoc} + * Sets the currently playing track for the adapter to know when to show indicators + * + * @param currentTrack the currently playing track */ - @Override - public int getItemViewType(final int position) { - if (position == 0) { - // since our view type count adds 1 to the super class, we can return viewtypecount - 1 - return getViewTypeCount() - 1; + public void setCurrentlyPlayingTrack(MusicPlaybackTrack currentTrack) { + if (mCurrentlyPlayingTrack != null && mCurrentlyPlayingTrack.equals(currentTrack)) { + return; + } + + long previousPlayingId = mCurrentlyPlayingTrack == null + ? NOTHING_PLAYING : mCurrentlyPlayingTrack.mId; + mCurrentlyPlayingTrack = currentTrack; + + int toBeUpdated = (currentTrack == null || currentTrack.mId == NOTHING_PLAYING) + ? 1 : 2; + int updated = 0; + + for (int i = 0; i < mSongs.size() && updated < toBeUpdated; i++) { + long id = mSongs.get(i).mSongId; + if ((currentTrack != null && id == currentTrack.mId) || id == previousPlayingId) { + notifyItemChanged(i); + updated++; + } } - return super.getItemViewType(position); } - @Override - public void addAll(Collection collection) { - // insert a header if one is needed - insertHeader(); - super.addAll(collection); + public Song getItem(int position) { + return mSongs.get(position); } - @Override - public void addAll(Song... items) { - // insert a header if one is needed - insertHeader(); - super.addAll(items); + public void setData(List songs) { + int oldSize = mSongs == null ? 0 : mSongs.size(); + int newSize = songs.size(); + + mSongs = songs; + + if (oldSize == 0) { + notifyItemRangeInserted(0, newSize); + } else { + int diff = oldSize - newSize; + if (diff > 0) { + // Items were removed + notifyItemRangeChanged(0, newSize); + notifyItemRangeRemoved(newSize, diff); + } else if (diff < 0) { + // Items were added + notifyItemRangeChanged(0, oldSize); + notifyItemRangeInserted(oldSize, diff * -1); + } else { + notifyItemChanged(0, oldSize); + } + } } - /** - * Make sure we insert our header when we add items - */ - private void insertHeader() { - if (getCount() == 0) { - // add a dummy entry to the underlying adapter. This is needed otherwise the - // underlying adapter could crash because getCount() doesn't match up - add(new Song(-1, null, null, null, -1, -1, -1)); + public void remove(Song song) { + final int index = mSongs.indexOf(song); + if (index >= 0) { + mSongs.remove(index); + notifyItemRemoved(index); + } + } + + public void move(int startPosition, int endPosition) { + if (startPosition == endPosition) { + return; } + + Song moving = mSongs.remove(startPosition); + mSongs.add(endPosition, moving); + notifyItemMoved(startPosition, endPosition); } } diff --git a/src/org/lineageos/eleven/adapters/QueueSongAdapter.java b/src/org/lineageos/eleven/adapters/QueueSongAdapter.java new file mode 100644 index 0000000000000000000000000000000000000000..756755145f0c28f6db4d4f420dad2f26ac44fc47 --- /dev/null +++ b/src/org/lineageos/eleven/adapters/QueueSongAdapter.java @@ -0,0 +1,252 @@ +/* + * Copyright (C) 2021 The LineageOS Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.lineageos.eleven.adapters; + +import android.content.Context; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; + +import androidx.annotation.NonNull; +import androidx.fragment.app.FragmentActivity; +import androidx.recyclerview.widget.RecyclerView; + +import org.lineageos.eleven.Config; +import org.lineageos.eleven.cache.ImageFetcher; +import org.lineageos.eleven.model.Song; +import org.lineageos.eleven.service.MusicPlaybackTrack; +import org.lineageos.eleven.ui.MusicHolder; +import org.lineageos.eleven.ui.fragments.QueueFragment; +import org.lineageos.eleven.utils.ElevenUtils; +import org.lineageos.eleven.utils.MusicUtils; +import org.lineageos.eleven.widgets.IPopupMenuCallback; +import org.lineageos.eleven.widgets.PlayPauseButtonContainer; + +import java.util.ArrayList; +import java.util.List; +import java.util.function.Consumer; + +/** + * This {@link RecyclerView.Adapter} is used to show the queue in + * {@link QueueFragment}. + */ +public class QueueSongAdapter extends RecyclerView.Adapter implements + IPopupMenuCallback { + + public static final int NOTHING_PLAYING = -1; + + /** + * The resource Id of the layout to inflate + */ + private final int mLayoutId; + + /** + * Image cache and image fetcher + */ + private final ImageFetcher mImageFetcher; + + /** + * Current music track + */ + private MusicPlaybackTrack mCurrentlyPlayingTrack; + + private List mSongs; + + /** + * Used to listen to the pop up menu callbacks + */ + private IPopupMenuCallback.IListener mListener; + + /** + * Source id and type + */ + protected final long mSourceId; + protected final Config.IdType mSourceType; + + private final Context mContext; + private final Consumer mOnItemClickListener; + + /** + * Constructor of SongAdapter + * + * @param context The {@link Context} to use. + * @param layoutId The resource Id of the view to inflate. + * @param sourceId The source id that the adapter is created from + * @param sourceType The source type that the adapter is created from + */ + public QueueSongAdapter(final FragmentActivity context, final int layoutId, final long sourceId, + final Config.IdType sourceType, + final Consumer onItemClickListener) { + mContext = context; + // Get the layout Id + mLayoutId = layoutId; + // Initialize the cache & image fetcher + mImageFetcher = ElevenUtils.getImageFetcher(context); + // set the source id and type + mSourceId = sourceId; + mSourceType = sourceType; + mOnItemClickListener = onItemClickListener; + mSongs = new ArrayList<>(); + } + + /** + * Determines whether the song at the position should show the currently playing indicator + * + * @param song the song in question + * @return true if we want to show the indicator + */ + protected boolean showNowPlayingIndicator(final Song song) { + return mCurrentlyPlayingTrack != null + && mCurrentlyPlayingTrack.mSourceId == mSourceId + && mCurrentlyPlayingTrack.mSourceType == mSourceType + && mCurrentlyPlayingTrack.mId == song.mSongId; + } + + @NonNull + @Override + public MusicHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { + return new MusicHolder(LayoutInflater.from(parent.getContext()) + .inflate(mLayoutId, parent, false)); + } + + @Override + public void onBindViewHolder(@NonNull MusicHolder holder, int position) { + // Retrieve the data holder + Song item = getItem(position); + + holder.mPopupMenuButton.get().setPopupMenuClickedListener(mListener); + // Sets the position each time because of recycling + holder.mPopupMenuButton.get().setPosition(position); + // Set each song name (line one) + holder.mLineOne.get().setText(item.mSongName); + // Set the album name (line two) + holder.mLineTwo.get().setText(MusicUtils.makeCombinedString(mContext, item.mArtistName, + item.mAlbumName)); + + holder.itemView.setOnClickListener(v -> mOnItemClickListener.accept(position)); + + // Asynchronously load the artist image into the adapter + if (item.mAlbumId >= 0) { + mImageFetcher.loadAlbumImage(item.mArtistName, item.mAlbumName, item.mAlbumId, + holder.mImage.get()); + } + + // padding doesn't apply to included layouts, so we need + // to wrap it in a container and show/hide with the container + PlayPauseButtonContainer buttonContainer = holder.mPlayPauseProgressButton.get(); + if (buttonContainer != null) { + View playPauseContainer = holder.mPlayPauseProgressContainer.get(); + + if (showNowPlayingIndicator(item)) { + // make it visible + buttonContainer.enableAndShow(); + playPauseContainer.setVisibility(View.VISIBLE); + } else { + // hide it + buttonContainer.disableAndHide(); + playPauseContainer.setVisibility(View.GONE); + } + } + } + + @Override + public int getItemCount() { + return mSongs.size(); + } + + /** + * Method that unloads and clears the items in the adapter + */ + public void unload() { + int size = mSongs.size(); + mSongs.clear(); + notifyItemRangeRemoved(0, size); + } + + /** + * Sets the currently playing track for the adapter to know when to show indicators + * + * @param currentTrack the currently playing track + */ + public void setCurrentlyPlayingTrack(MusicPlaybackTrack currentTrack) { + if (mCurrentlyPlayingTrack != null && mCurrentlyPlayingTrack.equals(currentTrack)) { + return; + } + + long previousPlayingId = mCurrentlyPlayingTrack == null + ? NOTHING_PLAYING : mCurrentlyPlayingTrack.mId; + mCurrentlyPlayingTrack = currentTrack; + + int toBeUpdated = (currentTrack == null || currentTrack.mId == NOTHING_PLAYING) + ? 1 : 2; + int updated = 0; + + for (int i = 0; i < mSongs.size() && updated < toBeUpdated; i++) { + long id = mSongs.get(i).mSongId; + if ((currentTrack != null && id == currentTrack.mId) || id == previousPlayingId) { + notifyItemChanged(i); + updated++; + } + } + } + + @Override + public void setPopupMenuClickedListener(IListener listener) { + mListener = listener; + } + + public Song getItem(int position) { + return mSongs.get(position); + } + + public void setData(List song) { + int oldSize = mSongs == null ? 0 : mSongs.size(); + int newSize = song.size(); + + mSongs = song; + if (oldSize == 0) { + notifyItemRangeInserted(0, newSize); + } else { + int diff = oldSize - newSize; + if (diff > 0) { + // Items were removed + notifyItemRangeChanged(0, newSize); + notifyItemRangeRemoved(newSize, diff); + } else if (diff < 0) { + // Items were added + notifyItemRangeChanged(0, oldSize); + notifyItemRangeInserted(oldSize, diff * -1); + } else { + notifyItemChanged(0, oldSize); + } + } + } + + public void remove(int position) { + mSongs.remove(position); + notifyItemRemoved(position); + } + + public void move(int startPosition, int endPosition) { + if (startPosition == endPosition) { + return; + } + + Song moving = mSongs.remove(startPosition); + mSongs.add(endPosition, moving); + notifyItemMoved(startPosition, endPosition); + } +} diff --git a/src/org/lineageos/eleven/adapters/SongAdapter.java b/src/org/lineageos/eleven/adapters/SongAdapter.java deleted file mode 100644 index 85eecdb59cb4e60b7bd9a11c09fcd35f7ce2717a..0000000000000000000000000000000000000000 --- a/src/org/lineageos/eleven/adapters/SongAdapter.java +++ /dev/null @@ -1,331 +0,0 @@ -/* - * Copyright (C) 2012 Andrew Neal - * Copyright (C) 2014 The CyanogenMod Project - * Copyright (C) 2019 The LineageOS Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.lineageos.eleven.adapters; - -import android.app.Activity; -import android.content.Context; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.ArrayAdapter; - -import org.lineageos.eleven.Config; -import org.lineageos.eleven.cache.ImageFetcher; -import org.lineageos.eleven.model.Artist; -import org.lineageos.eleven.model.Song; -import org.lineageos.eleven.sectionadapter.SectionAdapter; -import org.lineageos.eleven.service.MusicPlaybackTrack; -import org.lineageos.eleven.ui.MusicHolder; -import org.lineageos.eleven.ui.MusicHolder.DataHolder; -import org.lineageos.eleven.ui.fragments.QueueFragment; -import org.lineageos.eleven.ui.fragments.SongFragment; -import org.lineageos.eleven.utils.ElevenUtils; -import org.lineageos.eleven.utils.MusicUtils; -import org.lineageos.eleven.widgets.IPopupMenuCallback; -import org.lineageos.eleven.widgets.PlayPauseButtonContainer; - -/** - * This {@link ArrayAdapter} is used to display all of the songs on a user's - * device for {@link SongFragment}. It is also used to show the queue in - * {@link QueueFragment}. - * - * @author Andrew Neal (andrewdneal@gmail.com) - */ -public class SongAdapter extends ArrayAdapter - implements SectionAdapter.BasicAdapter, IPopupMenuCallback { - - public static final int NOTHING_PLAYING = -1; - - /** - * Number of views (TextView) - */ - private static final int VIEW_TYPE_COUNT = 1; - - /** - * The resource Id of the layout to inflate - */ - private final int mLayoutId; - - /** - * Image cache and image fetcher - */ - private final ImageFetcher mImageFetcher; - - /** - * The index of the item that is currently playing - */ - private long mCurrentQueuePosition = NOTHING_PLAYING; - - /** - * Used to cache the song info - */ - private DataHolder[] mData; - - /** - * Used to listen to the pop up menu callbacks - */ - private IPopupMenuCallback.IListener mListener; - - /** - * Current music track - */ - protected MusicPlaybackTrack mCurrentlyPlayingTrack; - - /** - * Source id and type - */ - protected long mSourceId; - protected Config.IdType mSourceType; - - /** - * Constructor of SongAdapter - * - * @param context The {@link Context} to use. - * @param layoutId The resource Id of the view to inflate. - * @param sourceId The source id that the adapter is created from - * @param sourceType The source type that the adapter is created from - */ - public SongAdapter(final Activity context, final int layoutId, final long sourceId, - final Config.IdType sourceType) { - super(context, 0); - // Get the layout Id - mLayoutId = layoutId; - // Initialize the cache & image fetcher - mImageFetcher = ElevenUtils.getImageFetcher(context); - // set the source id and type - mSourceId = sourceId; - mSourceType = sourceType; - } - - /** - * {@inheritDoc} - */ - @Override - public View getView(final int position, View convertView, final ViewGroup parent) { - // Recycle ViewHolder's items - MusicHolder holder; - if (convertView == null) { - convertView = LayoutInflater.from(getContext()).inflate(mLayoutId, parent, false); - holder = new MusicHolder(convertView); - convertView.setTag(holder); - - holder.mPopupMenuButton.get().setPopupMenuClickedListener(mListener); - } else { - holder = (MusicHolder)convertView.getTag(); - } - - // Retrieve the data holder - final DataHolder dataHolder = mData[position]; - - // Sets the position each time because of recycling - holder.mPopupMenuButton.get().setPosition(position); - // Set each song name (line one) - holder.mLineOne.get().setText(dataHolder.mLineOne); - // Set the album name (line two) - holder.mLineTwo.get().setText(dataHolder.mLineTwo); - - // Asynchronously load the artist image into the adapter - Song item = getItem(position); - if (item.mAlbumId >= 0) { - mImageFetcher.loadAlbumImage(item.mArtistName, item.mAlbumName, item.mAlbumId, - holder.mImage.get()); - } - - // padding doesn't apply to included layouts, so we need - // to wrap it in a container and show/hide with the container - PlayPauseButtonContainer playPauseButtonContainer = holder.mPlayPauseProgressButton.get(); - if (playPauseButtonContainer != null) { - View playPauseContainer = holder.mPlayPauseProgressContainer.get(); - - if (mCurrentQueuePosition == position) { - // make it visible - playPauseButtonContainer.enableAndShow(); - playPauseContainer.setVisibility(View.VISIBLE); - } else { - // hide it - playPauseButtonContainer.disableAndHide(); - playPauseContainer.setVisibility(View.GONE); - } - } - - View nowPlayingIndicator = holder.mNowPlayingIndicator.get(); - if (nowPlayingIndicator != null) { - if (showNowPlayingIndicator(item, position)) { - nowPlayingIndicator.setVisibility(View.VISIBLE); - } else { - nowPlayingIndicator.setVisibility(View.GONE); - } - } - - return convertView; - } - - /** - * Determines whether the song at the position should show the currently playing indicator - * @param song the song in question - * @param position the position of the song - * @return true if we want to show the indicator - */ - protected boolean showNowPlayingIndicator(final Song song, final int position) { - if (mCurrentlyPlayingTrack != null - && mCurrentlyPlayingTrack.mSourceId == mSourceId - && mCurrentlyPlayingTrack.mSourceType == mSourceType - && mCurrentlyPlayingTrack.mId == song.mSongId) { - return true; - } - - return false; - } - - /** - * {@inheritDoc} - */ - @Override - public boolean hasStableIds() { - return true; - } - - /** - * {@inheritDoc} - */ - @Override - public int getViewTypeCount() { - return VIEW_TYPE_COUNT; - } - - /** - * Method used to cache the data used to populate the list or grid. The idea - * is to cache everything before {@code #getView(int, View, ViewGroup)} is - * called. - */ - public void buildCache() { - mData = new DataHolder[getCount()]; - for (int i = 0; i < getCount(); i++) { - // Build the song - final Song song = getItem(i); - - // skip special placeholders - if (song.mSongId == -1) { - continue; - } - - // Build the data holder - mData[i] = new DataHolder(); - // Song Id - mData[i].mItemId = song.mSongId; - // Song names (line one) - mData[i].mLineOne = song.mSongName; - // Song duration (line one, right) - mData[i].mLineOneRight = MusicUtils.makeShortTimeString(getContext(), song.mDuration); - - // Artist Name | Album Name (line two) - mData[i].mLineTwo = MusicUtils.makeCombinedString(getContext(), song.mArtistName, - song.mAlbumName); - } - } - - /** - * @param pause True to temporarily pause the disk cache, false otherwise. - */ - public void setPauseDiskCache(final boolean pause) { - if (mImageFetcher != null) { - mImageFetcher.setPauseDiskCache(pause); - } - } - - /** - * @param artist The key used to find the cached artist to remove - */ - public void removeFromCache(final Artist artist) { - if (mImageFetcher != null) { - mImageFetcher.removeFromCache(artist.mArtistName); - } - } - - /** - * Method that unloads and clears the items in the adapter - */ - public void unload() { - clear(); - mData = null; - } - - /** - * Do nothing. - */ - public void flush() { - } - - /** - * Gets the item position for a given id - * @param id identifies the object - * @return the position if found, -1 otherwise - */ - @Override - public int getItemPosition(long id) { - for (int i = 0; i < getCount(); i++) { - if (getItem(i).mSongId == id) { - return i; - } - } - - return -1; - } - - public void setCurrentQueuePosition(long queuePosition) { - if (mCurrentQueuePosition != queuePosition) { - mCurrentQueuePosition = queuePosition; - - notifyDataSetChanged(); - } - } - - @Override - public void setPopupMenuClickedListener(IListener listener) { - mListener = listener; - } - - /** - * Sets the currently playing track for the adapter to know when to show indicators - * @param currentTrack the currently playing track - * @return true if the current track is different - */ - public boolean setCurrentlyPlayingTrack(MusicPlaybackTrack currentTrack) { - if (mCurrentlyPlayingTrack == null || !mCurrentlyPlayingTrack.equals(currentTrack)) { - mCurrentlyPlayingTrack = currentTrack; - - notifyDataSetChanged(); - return true; - } - - return false; - } - - /** - * @return Gets the list of song ids from the adapter - */ - public long[] getSongIds() { - long[] ret = new long[getCount()]; - for (int i = 0; i < getCount(); i++) { - ret[i] = getItem(i).mSongId; - } - - return ret; - } -} diff --git a/src/org/lineageos/eleven/adapters/SongListAdapter.java b/src/org/lineageos/eleven/adapters/SongListAdapter.java new file mode 100644 index 0000000000000000000000000000000000000000..92d24f060f2c36002463f5f26e42f6c8be3d6671 --- /dev/null +++ b/src/org/lineageos/eleven/adapters/SongListAdapter.java @@ -0,0 +1,285 @@ +/* + * Copyright (C) 2021 The LineageOS Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.lineageos.eleven.adapters; + +import android.content.Context; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; + +import androidx.annotation.NonNull; +import androidx.fragment.app.FragmentActivity; +import androidx.recyclerview.widget.RecyclerView; + +import org.lineageos.eleven.Config; +import org.lineageos.eleven.cache.ImageFetcher; +import org.lineageos.eleven.model.Song; +import org.lineageos.eleven.service.MusicPlaybackTrack; +import org.lineageos.eleven.ui.MusicHolder; +import org.lineageos.eleven.ui.MusicHolder.DataHolder; +import org.lineageos.eleven.ui.fragments.SongFragment; +import org.lineageos.eleven.utils.ElevenUtils; +import org.lineageos.eleven.utils.MusicUtils; +import org.lineageos.eleven.widgets.IPopupMenuCallback; + +import java.util.ArrayList; +import java.util.List; +import java.util.function.Consumer; + +/** + * This {@link RecyclerView.Adapter} is used to display all of the songs on a user's + * device for {@link SongFragment}. + */ +public class SongListAdapter extends RecyclerView.Adapter implements + IPopupMenuCallback { + + public static final int NOTHING_PLAYING = -1; + + /** + * The resource Id of the layout to inflate + */ + private final int mLayoutId; + + /** + * Image cache and image fetcher + */ + private final ImageFetcher mImageFetcher; + + /** + * Used to cache the song info + */ + private DataHolder[] mData; + private List mSongs; + + /** + * Used to listen to the pop up menu callbacks + */ + private IListener mListener; + + /** + * Current music track + */ + private MusicPlaybackTrack mCurrentlyPlayingTrack; + + /** + * Source id and type + */ + private final long mSourceId; + private final Config.IdType mSourceType; + + private final Context mContext; + private final Consumer mOnItemClickListener; + + /** + * Constructor of SongAdapter + * + * @param context The {@link Context} to use. + * @param layoutId The resource Id of the view to inflate. + * @param sourceId The source id that the adapter is created from + * @param sourceType The source type that the adapter is created from + */ + public SongListAdapter(final FragmentActivity context, final int layoutId, final long sourceId, + final Config.IdType sourceType, + final Consumer onItemClickListener) { + mContext = context; + // Get the layout Id + mLayoutId = layoutId; + // Initialize the cache & image fetcher + mImageFetcher = ElevenUtils.getImageFetcher(context); + // set the source id and type + mSourceId = sourceId; + mSourceType = sourceType; + mOnItemClickListener = onItemClickListener; + mSongs = new ArrayList<>(0); + } + + /** + * Determines whether the song at the position should show the currently playing indicator + * + * @param song the song in question + * @param position the position of the song + * @return true if we want to show the indicator + */ + protected boolean showNowPlayingIndicator(final Song song, final int position) { + return mCurrentlyPlayingTrack != null + && mCurrentlyPlayingTrack.mSourceId == mSourceId + && mCurrentlyPlayingTrack.mSourceType == mSourceType + && mCurrentlyPlayingTrack.mId == song.mSongId; + } + + @NonNull + @Override + public MusicHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { + return new MusicHolder(LayoutInflater.from(parent.getContext()) + .inflate(mLayoutId, parent, false)); + } + + @Override + public void onBindViewHolder(@NonNull MusicHolder holder, int position) { + // Retrieve the data holder + final DataHolder dataHolder = mData[position]; + + holder.itemView.setOnClickListener(v -> mOnItemClickListener.accept(position)); + + holder.mPopupMenuButton.get().setPopupMenuClickedListener(mListener); + // Sets the position each time because of recycling + holder.mPopupMenuButton.get().setPosition(position); + // Set each song name (line one) + holder.mLineOne.get().setText(dataHolder.lineOne); + // Set the album name (line two) + holder.mLineTwo.get().setText(dataHolder.lineTwo); + + // Asynchronously load the artist image into the adapter + Song item = getItem(position); + if (item.mAlbumId >= 0) { + mImageFetcher.loadAlbumImage(item.mArtistName, item.mAlbumName, item.mAlbumId, + holder.mImage.get()); + } + + View nowPlayingIndicator = holder.mNowPlayingIndicator.get(); + if (nowPlayingIndicator != null) { + if (showNowPlayingIndicator(item, position)) { + nowPlayingIndicator.setVisibility(View.VISIBLE); + } else { + nowPlayingIndicator.setVisibility(View.GONE); + } + } + + customizeBind(holder, position); + } + + @Override + public int getItemCount() { + return mSongs.size(); + } + + protected void customizeBind(@NonNull MusicHolder holder, int position) { + } + + /** + * Method used to cache the data used to populate the list or grid. The idea + * is to cache everything before {@code #getView(int, View, ViewGroup)} is + * called. + */ + public void buildCache() { + mData = new DataHolder[getItemCount()]; + for (int i = 0; i < getItemCount(); i++) { + // Build the song + final Song song = getItem(i); + + // skip special placeholders + if (song.mSongId == -1) { + continue; + } + + // Build the data holder + mData[i] = new DataHolder(); + // Song Id + mData[i].itemId = song.mSongId; + // Song names + mData[i].lineOne = song.mSongName; + // Song duration + mData[i].lineOneRight = MusicUtils.makeShortTimeString(mContext, song.mDuration); + + // Artist Name | Album Name + mData[i].lineTwo = MusicUtils.makeCombinedString(mContext, song.mArtistName, + song.mAlbumName); + } + } + + /** + * Method that unloads and clears the items in the adapter + */ + public void unload() { + int size = mSongs.size(); + mSongs.clear(); + mData = null; + notifyItemRangeRemoved(0, size); + } + + @Override + public void setPopupMenuClickedListener(IListener listener) { + mListener = listener; + } + + /** + * Sets the currently playing track for the adapter to know when to show indicators + * + * @param currentTrack the currently playing track + */ + public void setCurrentlyPlayingTrack(MusicPlaybackTrack currentTrack) { + if (mCurrentlyPlayingTrack != null && mCurrentlyPlayingTrack.equals(currentTrack)) { + return; + } + + long previousPlayingId = mCurrentlyPlayingTrack == null + ? NOTHING_PLAYING : mCurrentlyPlayingTrack.mId; + mCurrentlyPlayingTrack = currentTrack; + + int toBeUpdated = (currentTrack == null || currentTrack.mId == NOTHING_PLAYING) + ? 1 : 2; + int updated = 0; + + for (int i = 0; i < mSongs.size() && updated < toBeUpdated; i++) { + long id = mSongs.get(i).mSongId; + if ((currentTrack != null && id == currentTrack.mId) || id == previousPlayingId) { + notifyItemChanged(i); + updated++; + } + } + } + + /** + * @return Gets the list of song ids from the adapter + */ + public long[] getSongIds() { + long[] ret = new long[mSongs.size()]; + for (int i = 0; i < mSongs.size(); i++) { + ret[i] = getItem(i).mSongId; + } + + return ret; + } + + public Song getItem(int position) { + return mSongs.get(position); + } + + public void setData(List songs) { + int oldSize = mSongs == null ? 0 : mSongs.size(); + int newSize = songs.size(); + + mSongs = songs; + buildCache(); + + if (oldSize == 0) { + notifyItemRangeInserted(0, newSize); + } else { + int diff = oldSize - newSize; + if (diff > 0) { + // Items were removed + notifyItemRangeChanged(0, newSize); + notifyItemRangeRemoved(newSize, diff); + } else if (diff < 0) { + // Items were added + notifyItemRangeChanged(0, oldSize); + notifyItemRangeInserted(oldSize, diff * -1); + } else { + notifyItemChanged(0, oldSize); + } + } + } +} diff --git a/src/org/lineageos/eleven/adapters/SummarySearchAdapter.java b/src/org/lineageos/eleven/adapters/SummarySearchAdapter.java deleted file mode 100644 index 85e9e1f746daab78217814adcfdd59683799fd1b..0000000000000000000000000000000000000000 --- a/src/org/lineageos/eleven/adapters/SummarySearchAdapter.java +++ /dev/null @@ -1,221 +0,0 @@ -/* -* Copyright (C) 2014 The CyanogenMod Project -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ -package org.lineageos.eleven.adapters; - -import android.app.Activity; -import android.text.TextUtils; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.ArrayAdapter; -import android.widget.TextView; - -import org.lineageos.eleven.R; -import org.lineageos.eleven.cache.ImageFetcher; -import org.lineageos.eleven.format.PrefixHighlighter; -import org.lineageos.eleven.model.SearchResult; -import org.lineageos.eleven.sectionadapter.SectionAdapter; -import org.lineageos.eleven.ui.MusicHolder; -import org.lineageos.eleven.utils.ElevenUtils; -import org.lineageos.eleven.utils.MusicUtils; -import org.lineageos.eleven.widgets.IPopupMenuCallback; - -import java.util.Locale; - -/** - * Used to populate the list view with the search results. - */ -public final class SummarySearchAdapter extends ArrayAdapter - implements SectionAdapter.BasicAdapter, IPopupMenuCallback { - - /** - * Image cache and image fetcher - */ - private final ImageFetcher mImageFetcher; - - /** - * Highlights the query - */ - private final PrefixHighlighter mHighlighter; - - /** - * The prefix that's highlighted - */ - private char[] mPrefix; - - /** - * Used to listen to the pop up menu callbacks - */ - private IListener mListener; - - /** - * Constructor for SearchAdapter - * - * @param context The {@link Activity} to use. - */ - public SummarySearchAdapter(final Activity context) { - super(context, 0); - // Initialize the cache & image fetcher - mImageFetcher = ElevenUtils.getImageFetcher(context); - // Create the prefix highlighter - mHighlighter = new PrefixHighlighter(context); - } - - /** - * {@inheritDoc} - */ - @Override - public View getView(final int position, View convertView, final ViewGroup parent) { - /* Recycle ViewHolder's items */ - MusicHolder holder; - - if (convertView == null) { - convertView = LayoutInflater.from(getContext()).inflate( - R.layout.list_item_normal, parent, false); - holder = new MusicHolder(convertView); - convertView.setTag(holder); - // set the pop up menu listener - holder.mPopupMenuButton.get().setPopupMenuClickedListener(mListener); - } else { - holder = (MusicHolder)convertView.getTag(); - } - - // Sets the position each time because of recycling - holder.mPopupMenuButton.get().setPosition(position); - - final SearchResult item = getItem(position); - - switch (item.mType) { - case Artist: - // Asynchronously load the artist image into the adapter - mImageFetcher.loadArtistImage(item.mArtist, holder.mImage.get()); - - setText(holder.mLineOne.get(), item.mArtist); - - String songCount = MusicUtils.makeLabel(getContext(), R.plurals.Nsongs, item.mSongCount); - String albumCount = MusicUtils.makeLabel(getContext(), R.plurals.Nalbums, item.mAlbumCount); - // Album Name | Artist Name (line two) - holder.mLineTwo.get().setText(MusicUtils.makeCombinedString(getContext(), songCount, albumCount)); - break; - case Album: - // Asynchronously load the album images into the adapter - mImageFetcher.loadAlbumImage(item.mArtist, item.mAlbum, - item.mId, holder.mImage.get()); - - setText(holder.mLineOne.get(), item.mAlbum); - setText(holder.mLineTwo.get(), item.mArtist); - break; - case Song: - // Asynchronously load the album images into the adapter - mImageFetcher.loadAlbumImage(item.mArtist, item.mAlbum, - item.mAlbumId, holder.mImage.get()); - - setText(holder.mLineOne.get(), item.mTitle); - setText(holder.mLineTwo.get(), - MusicUtils.makeCombinedString(getContext(), item.mArtist, item.mAlbum)); - break; - case Playlist: - // Asynchronously load the playlist images into the adapter - ImageFetcher.getInstance(getContext()).loadPlaylistCoverArtImage( - item.mId, holder.mImage.get()); - - setText(holder.mLineOne.get(), item.mTitle); - String songs = MusicUtils.makeLabel(getContext(), R.plurals.Nsongs, item.mSongCount); - holder.mLineTwo.get().setText(songs); - break; - } - - return convertView; - } - - /** - * Sets the text onto the textview with highlighting if a prefix is defined - * @param textView - * @param text - */ - private void setText(final TextView textView, final String text) { - if (mPrefix == null) { - textView.setText(text); - } else { - mHighlighter.setText(textView, text, mPrefix); - } - } - - /** - * {@inheritDoc} - */ - @Override - public boolean hasStableIds() { - return true; - } - - /** - * @param pause True to temporarily pause the disk cache, false - * otherwise. - */ - public void setPauseDiskCache(final boolean pause) { - if (mImageFetcher != null) { - mImageFetcher.setPauseDiskCache(pause); - } - } - - /** - * @param prefix The query to filter. - */ - public void setPrefix(final CharSequence prefix) { - if (!TextUtils.isEmpty(prefix)) { - mPrefix = prefix.toString().toUpperCase(Locale.getDefault()).toCharArray(); - } else { - mPrefix = null; - } - } - - @Override - public void unload() { - clear(); - } - - @Override - public void buildCache() { - - } - - @Override - public void flush() { - mImageFetcher.flush(); - } - - /** - * Gets the item position for a given id - * @param id identifies the object - * @return the position if found, -1 otherwise - */ - @Override - public int getItemPosition(long id) { - for (int i = 0; i < getCount(); i++) { - if (getItem(i).mId == id) { - return i; - } - } - - return -1; - } - - @Override - public void setPopupMenuClickedListener(IListener listener) { - mListener = listener; - } -} \ No newline at end of file diff --git a/src/org/lineageos/eleven/appwidgets/AppWidgetBase.java b/src/org/lineageos/eleven/appwidgets/AppWidgetBase.java index e6ab4ce2af2630d7860ff9ba3dcd3f3f380d3308..57d130f517a5fdf35a0c9f4a9e9a75ccd8ab10c8 100644 --- a/src/org/lineageos/eleven/appwidgets/AppWidgetBase.java +++ b/src/org/lineageos/eleven/appwidgets/AppWidgetBase.java @@ -1,16 +1,20 @@ /* * Copyright (C) 2012 Andrew Neal * Copyright (C) 2014 The CyanogenMod Project - * Licensed under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law - * or agreed to in writing, software distributed under the License is - * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the specific language - * governing permissions and limitations under the License. + * Copyright (C) 2021 The LineageOS Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ - package org.lineageos.eleven.appwidgets; import android.app.PendingIntent; @@ -22,10 +26,9 @@ import android.content.Intent; public abstract class AppWidgetBase extends AppWidgetProvider { protected PendingIntent buildPendingIntent(Context context, final String action, - final ComponentName serviceName) { + final ComponentName serviceName) { Intent intent = new Intent(action); intent.setComponent(serviceName); - return PendingIntent.getService(context, 0, intent, 0); + return PendingIntent.getService(context, 0, intent, PendingIntent.FLAG_IMMUTABLE); } - } diff --git a/src/org/lineageos/eleven/appwidgets/AppWidgetLarge.java b/src/org/lineageos/eleven/appwidgets/AppWidgetLarge.java index e25e0bf98e90a33088f332268cc832a363aa267e..2cb27ac93d47f780c5dafd9a977b5fd35b17b81e 100644 --- a/src/org/lineageos/eleven/appwidgets/AppWidgetLarge.java +++ b/src/org/lineageos/eleven/appwidgets/AppWidgetLarge.java @@ -1,16 +1,20 @@ /* * Copyright (C) 2012 Andrew Neal * Copyright (C) 2014 The CyanogenMod Project - * Licensed under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law - * or agreed to in writing, software distributed under the License is - * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the specific language - * governing permissions and limitations under the License. + * Copyright (C) 2021 The LineageOS Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ - package org.lineageos.eleven.appwidgets; import android.annotation.SuppressLint; @@ -34,7 +38,7 @@ import org.lineageos.eleven.ui.activities.HomeActivity; @SuppressLint("NewApi") public class AppWidgetLarge extends AppWidgetBase { - public static final String CMDAPPWIDGETUPDATE = "app_widget_large_update"; + public static final String APP_WIDGET_UPDATE = "app_widget_large_update"; private static AppWidgetLarge mInstance; @@ -45,15 +49,12 @@ public class AppWidgetLarge extends AppWidgetBase { return mInstance; } - /** - * {@inheritDoc} - */ @Override public void onUpdate(final Context context, final AppWidgetManager appWidgetManager, - final int[] appWidgetIds) { + final int[] appWidgetIds) { defaultAppWidget(context, appWidgetIds); final Intent updateIntent = new Intent(MusicPlaybackService.SERVICECMD); - updateIntent.putExtra(MusicPlaybackService.CMDNAME, AppWidgetLarge.CMDAPPWIDGETUPDATE); + updateIntent.putExtra(MusicPlaybackService.CMDNAME, AppWidgetLarge.APP_WIDGET_UPDATE); updateIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, appWidgetIds); updateIntent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY); context.sendBroadcast(updateIntent); @@ -70,7 +71,8 @@ public class AppWidgetLarge extends AppWidgetBase { pushUpdate(context, appWidgetIds, appWidgetViews); } - private void pushUpdate(final Context context, final int[] appWidgetIds, final RemoteViews views) { + private void pushUpdate(final Context context, final int[] appWidgetIds, + final RemoteViews views) { final AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context); if (appWidgetIds != null) { appWidgetManager.updateAppWidget(appWidgetIds, views); @@ -125,12 +127,12 @@ public class AppWidgetLarge extends AppWidgetBase { final boolean isPlaying = service.isPlaying(); if (isPlaying) { appWidgetView.setImageViewResource(R.id.app_widget_large_play, - R.drawable.btn_playback_pause); + R.drawable.btn_playback_pause_widget); appWidgetView.setContentDescription(R.id.app_widget_large_play, service.getString(R.string.accessibility_pause)); } else { appWidgetView.setImageViewResource(R.id.app_widget_large_play, - R.drawable.btn_playback_play); + R.drawable.btn_playback_play_widget); appWidgetView.setContentDescription(R.id.app_widget_large_play, service.getString(R.string.accessibility_play)); } @@ -143,8 +145,7 @@ public class AppWidgetLarge extends AppWidgetBase { } /** - * Link up various button actions using {@link PendingIntents}. - * + * Link up various button actions using {@link PendingIntent}s. */ private void linkButtons(final Context context, final RemoteViews views) { Intent action; @@ -155,21 +156,22 @@ public class AppWidgetLarge extends AppWidgetBase { // Home action = new Intent(context, HomeActivity.class); action.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP); - pendingIntent = PendingIntent.getActivity(context, 0, action, 0); + pendingIntent = PendingIntent.getActivity(context, 0, action, PendingIntent.FLAG_IMMUTABLE); views.setOnClickPendingIntent(R.id.app_widget_large_info_container, pendingIntent); views.setOnClickPendingIntent(R.id.app_widget_large_image, pendingIntent); // Previous track - pendingIntent = buildPendingIntent(context, MusicPlaybackService.PREVIOUS_ACTION, serviceName); + pendingIntent = buildPendingIntent(context, MusicPlaybackService.PREVIOUS_ACTION, + serviceName); views.setOnClickPendingIntent(R.id.app_widget_large_previous, pendingIntent); // Play and pause - pendingIntent = buildPendingIntent(context, MusicPlaybackService.TOGGLEPAUSE_ACTION, serviceName); + pendingIntent = buildPendingIntent(context, MusicPlaybackService.TOGGLEPAUSE_ACTION, + serviceName); views.setOnClickPendingIntent(R.id.app_widget_large_play, pendingIntent); // Next track pendingIntent = buildPendingIntent(context, MusicPlaybackService.NEXT_ACTION, serviceName); views.setOnClickPendingIntent(R.id.app_widget_large_next, pendingIntent); } - } diff --git a/src/org/lineageos/eleven/appwidgets/AppWidgetLargeAlternate.java b/src/org/lineageos/eleven/appwidgets/AppWidgetLargeAlternate.java index 2ed47d7e0e2ebb92961542e2e85ec497f8cc7deb..04909659710549f2e94142436ff55e9a044a4186 100644 --- a/src/org/lineageos/eleven/appwidgets/AppWidgetLargeAlternate.java +++ b/src/org/lineageos/eleven/appwidgets/AppWidgetLargeAlternate.java @@ -1,16 +1,20 @@ /* * Copyright (C) 2012 Andrew Neal * Copyright (C) 2014 The CyanogenMod Project - * Licensed under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law - * or agreed to in writing, software distributed under the License is - * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the specific language - * governing permissions and limitations under the License. + * Copyright (C) 2021 The LineageOS Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ - package org.lineageos.eleven.appwidgets; import android.annotation.SuppressLint; @@ -36,7 +40,7 @@ import org.lineageos.eleven.widgets.ShuffleButton; @SuppressLint("NewApi") public class AppWidgetLargeAlternate extends AppWidgetBase { - public static final String CMDAPPWIDGETUPDATE = "app_widget_large_alternate_update"; + public static final String APP_WIDGET_UPDATE = "app_widget_large_alternate_update"; private static AppWidgetLargeAlternate mInstance; @@ -47,16 +51,13 @@ public class AppWidgetLargeAlternate extends AppWidgetBase { return mInstance; } - /** - * {@inheritDoc} - */ @Override public void onUpdate(final Context context, final AppWidgetManager appWidgetManager, - final int[] appWidgetIds) { + final int[] appWidgetIds) { defaultAppWidget(context, appWidgetIds); final Intent updateIntent = new Intent(MusicPlaybackService.SERVICECMD); updateIntent.putExtra(MusicPlaybackService.CMDNAME, - AppWidgetLargeAlternate.CMDAPPWIDGETUPDATE); + AppWidgetLargeAlternate.APP_WIDGET_UPDATE); updateIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, appWidgetIds); updateIntent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY); context.sendBroadcast(updateIntent); @@ -73,7 +74,8 @@ public class AppWidgetLargeAlternate extends AppWidgetBase { pushUpdate(context, appWidgetIds, appWidgetViews); } - private void pushUpdate(final Context context, final int[] appWidgetIds, final RemoteViews views) { + private void pushUpdate(final Context context, final int[] appWidgetIds, + final RemoteViews views) { final AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context); if (appWidgetIds != null) { appWidgetManager.updateAppWidget(appWidgetIds, views); @@ -130,12 +132,12 @@ public class AppWidgetLargeAlternate extends AppWidgetBase { final boolean isPlaying = service.isPlaying(); if (isPlaying) { appWidgetView.setImageViewResource(R.id.app_widget_large_alternate_play, - R.drawable.btn_playback_pause); + R.drawable.btn_playback_pause_widget); appWidgetView.setContentDescription(R.id.app_widget_large_alternate_play, service.getString(R.string.accessibility_pause)); } else { appWidgetView.setImageViewResource(R.id.app_widget_large_alternate_play, - R.drawable.btn_playback_play); + R.drawable.btn_playback_play_widget); appWidgetView.setContentDescription(R.id.app_widget_large_alternate_play, service.getString(R.string.accessibility_play)); } @@ -144,21 +146,21 @@ public class AppWidgetLargeAlternate extends AppWidgetBase { switch (service.getRepeatMode()) { case MusicPlaybackService.REPEAT_ALL: appWidgetView.setImageViewResource(R.id.app_widget_large_alternate_repeat, - R.drawable.btn_playback_repeat_all); + R.drawable.btn_playback_repeat_all_widget); appWidgetView.setInt(R.id.app_widget_large_alternate_repeat, "setAlpha", - (int)(RepeatButton.ACTIVE_ALPHA * 255)); + (int) (RepeatButton.ACTIVE_ALPHA * 255)); break; case MusicPlaybackService.REPEAT_CURRENT: appWidgetView.setImageViewResource(R.id.app_widget_large_alternate_repeat, - R.drawable.btn_playback_repeat_one); + R.drawable.btn_playback_repeat_one_widget); appWidgetView.setInt(R.id.app_widget_large_alternate_repeat, "setAlpha", - (int)(RepeatButton.ACTIVE_ALPHA * 255)); + (int) (RepeatButton.ACTIVE_ALPHA * 255)); break; default: appWidgetView.setImageViewResource(R.id.app_widget_large_alternate_repeat, - R.drawable.btn_playback_repeat_all); + R.drawable.btn_playback_repeat_all_widget); appWidgetView.setInt(R.id.app_widget_large_alternate_repeat, "setAlpha", - (int)(RepeatButton.INACTIVE_ALPHA * 255)); + (int) (RepeatButton.INACTIVE_ALPHA * 255)); break; } @@ -166,17 +168,17 @@ public class AppWidgetLargeAlternate extends AppWidgetBase { switch (service.getShuffleMode()) { case MusicPlaybackService.SHUFFLE_NONE: appWidgetView.setImageViewResource(R.id.app_widget_large_alternate_shuffle, - R.drawable.btn_playback_shuffle_all); + R.drawable.btn_playback_shuffle_all_widget); appWidgetView.setInt(R.id.app_widget_large_alternate_shuffle, "setAlpha", - (int)(ShuffleButton.INACTIVE_ALPHA * 255)); + (int) (ShuffleButton.INACTIVE_ALPHA * 255)); break; case MusicPlaybackService.SHUFFLE_AUTO: case MusicPlaybackService.SHUFFLE_NORMAL: default: appWidgetView.setImageViewResource(R.id.app_widget_large_alternate_shuffle, - R.drawable.btn_playback_shuffle_all); + R.drawable.btn_playback_shuffle_all_widget); appWidgetView.setInt(R.id.app_widget_large_alternate_shuffle, "setAlpha", - (int)(ShuffleButton.ACTIVE_ALPHA * 255)); + (int) (ShuffleButton.ACTIVE_ALPHA * 255)); break; } @@ -188,8 +190,7 @@ public class AppWidgetLargeAlternate extends AppWidgetBase { } /** - * Link up various button actions using {@link PendingIntents}. - * + * Link up various button actions using {@link PendingIntent}s. */ private void linkButtons(final Context context, final RemoteViews views) { Intent action; @@ -200,21 +201,24 @@ public class AppWidgetLargeAlternate extends AppWidgetBase { // Home action = new Intent(context, HomeActivity.class); action.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP); - pendingIntent = PendingIntent.getActivity(context, 0, action, 0); + pendingIntent = PendingIntent.getActivity(context, 0, action, PendingIntent.FLAG_IMMUTABLE); views.setOnClickPendingIntent(R.id.app_widget_large_alternate_info_container, pendingIntent); views.setOnClickPendingIntent(R.id.app_widget_large_alternate_image, pendingIntent); // Shuffle modes - pendingIntent = buildPendingIntent(context, MusicPlaybackService.SHUFFLE_ACTION, serviceName); + pendingIntent = buildPendingIntent(context, MusicPlaybackService.SHUFFLE_ACTION, + serviceName); views.setOnClickPendingIntent(R.id.app_widget_large_alternate_shuffle, pendingIntent); // Previous track - pendingIntent = buildPendingIntent(context, MusicPlaybackService.PREVIOUS_ACTION, serviceName); + pendingIntent = buildPendingIntent(context, MusicPlaybackService.PREVIOUS_ACTION, + serviceName); views.setOnClickPendingIntent(R.id.app_widget_large_alternate_previous, pendingIntent); // Play and pause - pendingIntent = buildPendingIntent(context, MusicPlaybackService.TOGGLEPAUSE_ACTION, serviceName); + pendingIntent = buildPendingIntent(context, MusicPlaybackService.TOGGLEPAUSE_ACTION, + serviceName); views.setOnClickPendingIntent(R.id.app_widget_large_alternate_play, pendingIntent); // Next track @@ -222,8 +226,8 @@ public class AppWidgetLargeAlternate extends AppWidgetBase { views.setOnClickPendingIntent(R.id.app_widget_large_alternate_next, pendingIntent); // Repeat modes - pendingIntent = buildPendingIntent(context, MusicPlaybackService.REPEAT_ACTION, serviceName); + pendingIntent = buildPendingIntent(context, MusicPlaybackService.REPEAT_ACTION, + serviceName); views.setOnClickPendingIntent(R.id.app_widget_large_alternate_repeat, pendingIntent); } - } diff --git a/src/org/lineageos/eleven/appwidgets/AppWidgetSmall.java b/src/org/lineageos/eleven/appwidgets/AppWidgetSmall.java index 9c10f25bbd7027f426beb3248417cf23acd7126d..34344d548ce0807c316d697a78578765eae5f123 100644 --- a/src/org/lineageos/eleven/appwidgets/AppWidgetSmall.java +++ b/src/org/lineageos/eleven/appwidgets/AppWidgetSmall.java @@ -1,16 +1,20 @@ /* * Copyright (C) 2012 Andrew Neal * Copyright (C) 2014 The CyanogenMod Project - * Licensed under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law - * or agreed to in writing, software distributed under the License is - * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the specific language - * governing permissions and limitations under the License. + * Copyright (C) 2021 The LineageOS Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ - package org.lineageos.eleven.appwidgets; import android.annotation.SuppressLint; @@ -21,7 +25,6 @@ import android.content.Context; import android.content.Intent; import android.graphics.Bitmap; import android.text.TextUtils; -import android.view.View; import android.widget.RemoteViews; import org.lineageos.eleven.MusicPlaybackService; @@ -29,14 +32,14 @@ import org.lineageos.eleven.R; import org.lineageos.eleven.ui.activities.HomeActivity; /** - * 4x1 App-Widget + * Square App-Widget * * @author Andrew Neal (andrewdneal@gmail.com) */ @SuppressLint("NewApi") public class AppWidgetSmall extends AppWidgetBase { - public static final String CMDAPPWIDGETUPDATE = "app_widget_small_update"; + public static final String APP_WIDGET_UPDATE = "app_widget_small_update"; private static AppWidgetSmall mInstance; @@ -47,15 +50,12 @@ public class AppWidgetSmall extends AppWidgetBase { return mInstance; } - /** - * {@inheritDoc} - */ @Override public void onUpdate(final Context context, final AppWidgetManager appWidgetManager, final int[] appWidgetIds) { defaultAppWidget(context, appWidgetIds); final Intent updateIntent = new Intent(MusicPlaybackService.SERVICECMD); - updateIntent.putExtra(MusicPlaybackService.CMDNAME, AppWidgetSmall.CMDAPPWIDGETUPDATE); + updateIntent.putExtra(MusicPlaybackService.CMDNAME, AppWidgetSmall.APP_WIDGET_UPDATE); updateIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, appWidgetIds); updateIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY); context.sendBroadcast(updateIntent); @@ -68,12 +68,12 @@ public class AppWidgetSmall extends AppWidgetBase { private void defaultAppWidget(final Context context, final int[] appWidgetIds) { final RemoteViews appWidgetViews = new RemoteViews(context.getPackageName(), R.layout.app_widget_small); - appWidgetViews.setViewVisibility(R.id.app_widget_small_info_container, View.INVISIBLE); linkButtons(context, appWidgetViews); pushUpdate(context, appWidgetIds, appWidgetViews); } - private void pushUpdate(final Context context, final int[] appWidgetIds, final RemoteViews views) { + private void pushUpdate(final Context context, final int[] appWidgetIds, + final RemoteViews views) { final AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context); if (appWidgetIds != null) { appWidgetManager.updateAppWidget(appWidgetIds, views); @@ -114,16 +114,15 @@ public class AppWidgetSmall extends AppWidgetBase { R.layout.app_widget_small); final CharSequence trackName = service.getTrackName(); + final CharSequence albumName = service.getAlbumName(); final CharSequence artistName = service.getArtistName(); final Bitmap bitmap = service.getAlbumArt(true).getBitmap(); // Set the titles and artwork - if (TextUtils.isEmpty(trackName) && TextUtils.isEmpty(artistName)) { - appWidgetView.setViewVisibility(R.id.app_widget_small_info_container, View.INVISIBLE); - } else { - appWidgetView.setViewVisibility(R.id.app_widget_small_info_container, View.VISIBLE); + if (!TextUtils.isEmpty(trackName) || !TextUtils.isEmpty(artistName)) { appWidgetView.setTextViewText(R.id.app_widget_small_line_one, trackName); - appWidgetView.setTextViewText(R.id.app_widget_small_line_two, artistName); + appWidgetView.setTextViewText(R.id.app_widget_small_line_two, albumName); + appWidgetView.setTextViewText(R.id.app_widget_small_line_three, artistName); } appWidgetView.setImageViewBitmap(R.id.app_widget_small_image, bitmap); @@ -131,12 +130,12 @@ public class AppWidgetSmall extends AppWidgetBase { final boolean isPlaying = service.isPlaying(); if (isPlaying) { appWidgetView.setImageViewResource(R.id.app_widget_small_play, - R.drawable.btn_playback_pause); + R.drawable.btn_playback_pause_widget); appWidgetView.setContentDescription(R.id.app_widget_small_play, service.getString(R.string.accessibility_pause)); } else { appWidgetView.setImageViewResource(R.id.app_widget_small_play, - R.drawable.btn_playback_play); + R.drawable.btn_playback_play_widget); appWidgetView.setContentDescription(R.id.app_widget_small_play, service.getString(R.string.accessibility_play)); } @@ -149,7 +148,7 @@ public class AppWidgetSmall extends AppWidgetBase { } /** - * Link up various button actions using {@link PendingIntents}. + * Link up various button actions using {@link PendingIntent}s. * */ private void linkButtons(final Context context, final RemoteViews views) { @@ -161,21 +160,13 @@ public class AppWidgetSmall extends AppWidgetBase { // Home action = new Intent(context, HomeActivity.class); action.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP); - pendingIntent = PendingIntent.getActivity(context, 0, action, 0); + pendingIntent = PendingIntent.getActivity(context, 0, action, PendingIntent.FLAG_IMMUTABLE); views.setOnClickPendingIntent(R.id.app_widget_small_info_container, pendingIntent); views.setOnClickPendingIntent(R.id.app_widget_small_image, pendingIntent); - // Previous track - pendingIntent = buildPendingIntent(context, MusicPlaybackService.PREVIOUS_ACTION, serviceName); - views.setOnClickPendingIntent(R.id.app_widget_small_previous, pendingIntent); - // Play and pause - pendingIntent = buildPendingIntent(context, MusicPlaybackService.TOGGLEPAUSE_ACTION, serviceName); + pendingIntent = buildPendingIntent(context, MusicPlaybackService.TOGGLEPAUSE_ACTION, + serviceName); views.setOnClickPendingIntent(R.id.app_widget_small_play, pendingIntent); - - // Next track - pendingIntent = buildPendingIntent(context, MusicPlaybackService.NEXT_ACTION, serviceName); - views.setOnClickPendingIntent(R.id.app_widget_small_next, pendingIntent); } - } diff --git a/src/org/lineageos/eleven/cache/BitmapWorkerTask.java b/src/org/lineageos/eleven/cache/BitmapWorkerTask.java index bf8cbaa1d9aab9ef6e10d1b5d5a74b15443f01ee..c2fb173826890b159b6a5076f51f832992295804 100644 --- a/src/org/lineageos/eleven/cache/BitmapWorkerTask.java +++ b/src/org/lineageos/eleven/cache/BitmapWorkerTask.java @@ -1,18 +1,19 @@ /* -* Copyright (C) 2014 The CyanogenMod Project -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ + * Copyright (C) 2014 The CyanogenMod Project + * Copyright (C) 2021 The LineageOS Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package org.lineageos.eleven.cache; import android.content.Context; @@ -53,18 +54,19 @@ public abstract class BitmapWorkerTask protected final Resources mResources; - protected boolean mScaleImgToView; + protected final boolean mScaleImgToView; /** * The key used to store cached entries */ - public String mKey; + public final String mKey; /** * Constructor of BitmapWorkerTask - * @param key used for caching the image - * @param imageView The {@link ImageView} to use. - * @param imageType The type of image URL to fetch for. + * + * @param key used for caching the image + * @param imageView The {@link ImageView} to use. + * @param imageType The type of image URL to fetch for. * @param fromDrawable what drawable to transition from */ public BitmapWorkerTask(final String key, final ImageView imageView, final ImageType imageType, @@ -74,14 +76,16 @@ public abstract class BitmapWorkerTask /** * Constructor of BitmapWorkerTask - * @param key used for caching the image - * @param imageView The {@link ImageView} to use. - * @param imageType The type of image URL to fetch for. - * @param fromDrawable what drawable to transition from + * + * @param key used for caching the image + * @param imageView The {@link ImageView} to use. + * @param imageType The type of image URL to fetch for. + * @param fromDrawable what drawable to transition from * @param scaleImgToView flag to scale the bitmap to the image view bounds */ - public BitmapWorkerTask(final String key, final ImageView imageView, final ImageType imageType, - final Drawable fromDrawable, final Context context, final boolean scaleImgToView) { + public BitmapWorkerTask(final String key, final ImageView imageView, + final ImageType imageType, final Drawable fromDrawable, + final Context context, final boolean scaleImgToView) { mKey = key; mContext = context; @@ -105,7 +109,8 @@ public abstract class BitmapWorkerTask protected ImageView getAttachedImageView() { final ImageView imageView = mImageReference.get(); if (imageView != null) { - final BitmapWorkerTask bitmapWorkerTask = ImageWorker.getBitmapWorkerTask(imageView); + final BitmapWorkerTask bitmapWorkerTask = + ImageWorker.getBitmapWorkerTask(imageView); if (this == bitmapWorkerTask) { return imageView; } @@ -116,34 +121,37 @@ public abstract class BitmapWorkerTask /** * Gets the bitmap given the input params + * * @param params artistName, albumName, albumId * @return Bitmap */ protected Bitmap getBitmapInBackground(final String... params) { return ImageWorker.getBitmapInBackground(mContext, mImageCache, mKey, - params[1], params[0], Long.valueOf(params[2]), mImageType); + Long.parseLong(params[2]), mImageType); } /** * Creates a transition drawable with default parameters + * * @param bitmap the bitmap to transition to * @return the transition drawable */ protected TransitionDrawable createImageTransitionDrawable(final Bitmap bitmap) { - return createImageTransitionDrawable(bitmap, ImageWorker.FADE_IN_TIME, false, false); + return createImageTransitionDrawable(bitmap, ImageWorker.FADE_IN_TIME, false); } /** * Creates a transition drawable - * @param bitmap to transition to + * + * @param bitmap to transition to * @param fadeTime the time to fade in ms - * @param dither setting - * @param force force create a transition even if bitmap == null (fade to transparent) + * @param force force create a transition even if bitmap == null (fade to transparent) * @return the transition drawable */ protected TransitionDrawable createImageTransitionDrawable(final Bitmap bitmap, - final int fadeTime, final boolean dither, final boolean force) { + final int fadeTime, + final boolean force) { return ImageWorker.createImageTransitionDrawable(mResources, mFromDrawable, bitmap, - fadeTime, dither, force); + fadeTime, force); } } diff --git a/src/org/lineageos/eleven/cache/BlurBitmapWorkerTask.java b/src/org/lineageos/eleven/cache/BlurBitmapWorkerTask.java index 72ed72899ccd3df9092cf1513ebff3a2d3e38341..d3bda2a280409fcf387f9b8734e61807e32b0bf0 100644 --- a/src/org/lineageos/eleven/cache/BlurBitmapWorkerTask.java +++ b/src/org/lineageos/eleven/cache/BlurBitmapWorkerTask.java @@ -1,18 +1,19 @@ /* -* Copyright (C) 2014 The CyanogenMod Project -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ + * Copyright (C) 2014 The CyanogenMod Project + * Copyright (C) 2021 The LineageOS Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package org.lineageos.eleven.cache; import android.content.Context; @@ -35,12 +36,13 @@ import java.lang.ref.WeakReference; * This will download the image (if needed) and create a blur and set the scrim as well on the * BlurScrimImage */ -public class BlurBitmapWorkerTask extends BitmapWorkerTask { +public class BlurBitmapWorkerTask extends BitmapWorkerTask { private static final String TAG = BlurBitmapWorkerTask.class.getSimpleName(); // if the image is too small, the blur will look bad post scale up so we use the min size - // to scale up before bluring + // to scale up before blurring private static final int MIN_BITMAP_SIZE = 500; // number of times to run the blur private static final int NUM_BLUR_RUNS = 8; @@ -61,21 +63,25 @@ public class BlurBitmapWorkerTask extends BitmapWorkerTaskBlurBitmapWorkerTask - * @param key used for caching the image + * + * @param key used for caching the image * @param albumScrimImage The {@link AlbumScrimImage} to use. - * @param imageType The type of image URL to fetch for. - * @param fromDrawable what drawable to transition from + * @param imageType The type of image URL to fetch for. + * @param fromDrawable what drawable to transition from */ public BlurBitmapWorkerTask(final String key, final AlbumScrimImage albumScrimImage, final ImageType imageType, final Drawable fromDrawable, - final Context context, final RenderScript renderScript) { + final Context context) { super(key, albumScrimImage.getImageView(), imageType, fromDrawable, context); mBlurScrimImage = new WeakReference<>(albumScrimImage); - mRenderScript = renderScript; + + if (sRenderScript == null) { + sRenderScript = RenderScript.create(mContext); + } // use the existing image as the drawable and if it doesn't exist fallback to transparent mFromDrawable = albumScrimImage.getImageView().getDrawable(); @@ -84,9 +90,6 @@ public class BlurBitmapWorkerTask extends BitmapWorkerTask bitmapWorkerTask = + ImageWorker.getBitmapWorkerTask(blurImage); if (this == bitmapWorkerTask) { return blurImage.getImageView(); } diff --git a/src/org/lineageos/eleven/cache/ICacheListener.java b/src/org/lineageos/eleven/cache/ICacheListener.java deleted file mode 100644 index fcc9de6c474c6abd19d1955a0d4fc7a7c8421a90..0000000000000000000000000000000000000000 --- a/src/org/lineageos/eleven/cache/ICacheListener.java +++ /dev/null @@ -1,20 +0,0 @@ -/* -* Copyright (C) 2014 The CyanogenMod Project -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ -package org.lineageos.eleven.cache; - -public interface ICacheListener { - void onCacheUnpaused(); -} diff --git a/src/org/lineageos/eleven/cache/ImageCache.java b/src/org/lineageos/eleven/cache/ImageCache.java index 23d6eb63b5f295cbb7915c9f2ae97b6404a6c704..c530f3afa9e7ca3dbdf4c2f02edbbc8e5cc3d002 100644 --- a/src/org/lineageos/eleven/cache/ImageCache.java +++ b/src/org/lineageos/eleven/cache/ImageCache.java @@ -1,7 +1,7 @@ /* * Copyright (C) 2012 Andrew Neal * Copyright (C) 2014 The CyanogenMod Project - * Copyright (C) 2018-2020 The LineageOS Project + * Copyright (C) 2018-2021 The LineageOS Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -15,13 +15,11 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package org.lineageos.eleven.cache; +import android.annotation.SuppressLint; import android.app.Activity; import android.app.ActivityManager; -import android.app.Fragment; -import android.app.FragmentManager; import android.content.ComponentCallbacks2; import android.content.ContentUris; import android.content.Context; @@ -32,11 +30,13 @@ import android.graphics.BitmapFactory; import android.net.Uri; import android.os.AsyncTask; import android.os.Bundle; -import android.os.Environment; -import android.os.Looper; import android.os.ParcelFileDescriptor; import android.util.Log; +import androidx.fragment.app.Fragment; +import androidx.fragment.app.FragmentActivity; +import androidx.fragment.app.FragmentManager; + import org.lineageos.eleven.cache.disklrucache.DiskLruCache; import org.lineageos.eleven.utils.ElevenUtils; import org.lineageos.eleven.utils.IoUtils; @@ -51,6 +51,8 @@ import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.util.HashSet; +import androidx.annotation.NonNull; + /** * This class holds the memory and disk bitmap caches. */ @@ -65,12 +67,12 @@ public final class ImageCache { /** * Default memory cache size as a percent of device memory class */ - private static final float MEM_CACHE_DIVIDER = 0.25f; + private static final float MEM_CACHE_DIVIDER = 0.50f; /** - * Default disk cache size 10MB + * Default disk cache size 50MB */ - private static final int DISK_CACHE_SIZE = 1024 * 1024 * 10; + private static final int DISK_CACHE_SIZE = 50 * 1024 * 1024; /** * Compression settings when writing images to disk cache @@ -97,19 +99,8 @@ public final class ImageCache { */ private DiskLruCache mDiskCache; - /** - * listeners to the cache state - */ - private HashSet mListeners = new HashSet<>(); - private static ImageCache sInstance; - /** - * Used to temporarily pause the disk cache while scrolling - */ - public boolean mPauseDiskAccess = false; - private final Object mPauseLock = new Object(); - static { mArtworkUri = Uri.parse("content://media/external/audio/albumart"); } @@ -129,7 +120,7 @@ public final class ImageCache { * @param context The {@link Context} to use * @return A new instance of this class. */ - public final static ImageCache getInstance(final Context context) { + public static ImageCache getInstance(final Context context) { if (sInstance == null) { sInstance = new ImageCache(context.getApplicationContext()); } @@ -139,11 +130,10 @@ public final class ImageCache { /** * Initialize the cache, providing all parameters. * - * @param context The {@link Context} to use - * @param cacheParams The cache parameters to initialize the cache + * @param context The {@link Context} to use */ private void init(final Context context) { - ElevenUtils.execute(false, new AsyncTask() { + ElevenUtils.execute(new AsyncTask() { @Override protected Void doInBackground(final Void... unused) { @@ -151,7 +141,7 @@ public final class ImageCache { initDiskCache(context); return null; } - }, (Void[])null); + }, (Void[]) null); // Set up the memory cache initLruCache(context); } @@ -168,16 +158,14 @@ public final class ImageCache { // Set up disk cache if (mDiskCache == null || mDiskCache.isClosed()) { File diskCacheDir = getDiskCacheDir(context, TAG); - if (diskCacheDir != null) { - if (!diskCacheDir.exists()) { - diskCacheDir.mkdirs(); - } - if (getUsableSpace(diskCacheDir) > DISK_CACHE_SIZE) { - try { - mDiskCache = DiskLruCache.open(diskCacheDir, 1, 1, DISK_CACHE_SIZE); - } catch (final IOException e) { - diskCacheDir = null; - } + if (!diskCacheDir.exists()) { + //noinspection ResultOfMethodCallIgnored + diskCacheDir.mkdirs(); + } + if (getUsableSpace(diskCacheDir) > DISK_CACHE_SIZE) { + try { + mDiskCache = DiskLruCache.open(diskCacheDir, 1, 1, DISK_CACHE_SIZE); + } catch (final IOException ignored) { } } } @@ -212,7 +200,7 @@ public final class ImageCache { } @Override - public void onConfigurationChanged(final Configuration newConfig) { + public void onConfigurationChanged(@NonNull final Configuration newConfig) { // Nothing to do } }); @@ -223,18 +211,18 @@ public final class ImageCache { * , if not found a new one is created using the supplied params and saved * to a {@link RetainFragment} * - * @param activity The calling {@link FragmentActivity} + * @param activity The calling {@link Activity} * @return An existing retained ImageCache object or a new one if one did - * not exist + * not exist */ - public static ImageCache findOrCreateCache(final Activity activity) { + public static ImageCache findOrCreateCache(final FragmentActivity activity) { // Search for, or create an instance of the non-UI RetainFragment final RetainFragment retainFragment = findOrCreateRetainFragment( - activity.getFragmentManager()); + activity.getSupportFragmentManager()); // See if we already have an ImageCache stored in RetainFragment - ImageCache cache = (ImageCache)retainFragment.getObject(); + ImageCache cache = (ImageCache) retainFragment.getObject(); // No existing ImageCache, create one and store it in RetainFragment if (cache == null) { @@ -250,11 +238,11 @@ public final class ImageCache { * * @param fm The {@link FragmentManager} to use * @return The existing instance of the {@link Fragment} or the new instance - * if just created + * if just created */ public static RetainFragment findOrCreateRetainFragment(final FragmentManager fm) { // Check to see if we have retained the worker fragment - RetainFragment retainFragment = (RetainFragment)fm.findFragmentByTag(TAG); + RetainFragment retainFragment = (RetainFragment) fm.findFragmentByTag(TAG); // If not retained, we need to create and add it if (retainFragment == null) { @@ -267,7 +255,7 @@ public final class ImageCache { /** * Adds a new image to the memory and disk caches * - * @param data The key used to store the image + * @param data The key used to store the image * @param bitmap The {@link Bitmap} to cache */ public void addBitmapToCache(final String data, final Bitmap bitmap) { @@ -277,8 +265,8 @@ public final class ImageCache { /** * Adds a new image to the memory and disk caches * - * @param data The key used to store the image - * @param bitmap The {@link Bitmap} to cache + * @param data The key used to store the image + * @param bitmap The {@link Bitmap} to cache * @param replace force a replace even if the bitmap exists in the cache */ public void addBitmapToCache(final String data, final Bitmap bitmap, final boolean replace) { @@ -310,8 +298,6 @@ public final class ImageCache { } } } catch (final IOException e) { - Log.e(TAG, "addBitmapToCache", e); - } catch (final IllegalStateException e) { // if the user clears the cache while we have an async task going we could try // writing to the disk cache while it isn't ready. Catching here will silently // fail instead @@ -325,7 +311,7 @@ public final class ImageCache { /** * Called to add a new image to the memory cache * - * @param data The key identifier + * @param data The key identifier * @param bitmap The {@link Bitmap} to cache */ public void addBitmapToMemCache(final String data, final Bitmap bitmap) { @@ -335,8 +321,8 @@ public final class ImageCache { /** * Called to add a new image to the memory cache * - * @param data The key identifier - * @param bitmap The {@link Bitmap} to cache + * @param data The key identifier + * @param bitmap The {@link Bitmap} to cache * @param replace whether to force a replace if it already exists */ public void addBitmapToMemCache(final String data, final Bitmap bitmap, final boolean replace) { @@ -356,16 +342,7 @@ public final class ImageCache { * @return The {@link Bitmap} if found in cache, null otherwise */ public final Bitmap getBitmapFromMemCache(final String data) { - if (data == null) { - return null; - } - if (mLruCache != null) { - final Bitmap lruBitmap = mLruCache.get(data); - if (lruBitmap != null) { - return lruBitmap; - } - } - return null; + return (data == null || mLruCache == null) ? null : mLruCache.get(data); } /** @@ -385,7 +362,6 @@ public final class ImageCache { return getBitmapFromMemCache(data); } - waitUntilUnpaused(); final String key = hashKeyForDisk(data); if (mDiskCache != null) { InputStream inputStream = null; @@ -436,8 +412,8 @@ public final class ImageCache { * calling {@code #getArtworkFromFile(Context, String)} again * * @param context The {@link Context} to use - * @param data The name of the album art - * @param id The ID of the album to find artwork for + * @param data The name of the album art + * @param id The ID of the album to find artwork for * @return The artwork for an album */ public final Bitmap getCachedArtwork(final Context context, final String data, final long id) { @@ -459,7 +435,7 @@ public final class ImageCache { * Used to fetch the artwork for an album locally from the user's device * * @param context The {@link Context} to use - * @param albumID The ID of the album to find artwork for + * @param albumId The ID of the album to find artwork for * @return The artwork for an album */ public final Bitmap getArtworkFromFile(final Context context, final long albumId) { @@ -467,7 +443,6 @@ public final class ImageCache { return null; } Bitmap artwork = null; - waitUntilUnpaused(); ParcelFileDescriptor parcelFileDescriptor = null; try { @@ -478,7 +453,7 @@ public final class ImageCache { artwork = BitmapFactory.decodeFileDescriptor(fileDescriptor); } } catch (final IllegalStateException e) { - // Log.e(TAG, "IllegalStateExcetpion - getArtworkFromFile - ", e); + // Log.e(TAG, "IllegalStateException - getArtworkFromFile - ", e); } catch (final FileNotFoundException e) { // Log.e(TAG, "FileNotFoundException - getArtworkFromFile - ", e); } catch (final OutOfMemoryError evict) { @@ -495,7 +470,7 @@ public final class ImageCache { * cache first */ public void flush() { - ElevenUtils.execute(false, new AsyncTask() { + ElevenUtils.execute(new AsyncTask() { @Override protected Void doInBackground(final Void... unused) { @@ -517,7 +492,7 @@ public final class ImageCache { * Clears the disk and memory caches */ public void clearCaches() { - ElevenUtils.execute(false, new AsyncTask() { + ElevenUtils.execute(new AsyncTask() { @Override protected Void doInBackground(final Void... unused) { @@ -543,7 +518,7 @@ public final class ImageCache { * thread. */ public void close() { - ElevenUtils.execute(false, new AsyncTask() { + ElevenUtils.execute(new AsyncTask() { @Override protected Void doInBackground(final Void... unused) { @@ -596,82 +571,22 @@ public final class ImageCache { flush(); } - /** - * Used to temporarily pause the disk cache while the user is scrolling to - * improve scrolling. - * - * @param pause True to temporarily pause the disk cache, false otherwise. - */ - public void setPauseDiskCache(final boolean pause) { - synchronized (mPauseLock) { - if (mPauseDiskAccess != pause) { - mPauseDiskAccess = pause; - if (!pause) { - mPauseLock.notify(); - - for (ICacheListener listener : mListeners) { - listener.onCacheUnpaused(); - } - } - } - } - } - - private void waitUntilUnpaused() { - synchronized (mPauseLock) { - if (Looper.myLooper() != Looper.getMainLooper()) { - while (mPauseDiskAccess) { - try { - mPauseLock.wait(); - } catch (InterruptedException e) { - // ignored, we'll start waiting again - } - } - } - } - } - - /** - * @return True if the user is scrolling, false otherwise. - */ - public boolean isDiskCachePaused() { - return mPauseDiskAccess; - } - - public void addCacheListener(ICacheListener listener) { - mListeners.add(listener); - } - - public void removeCacheListener(ICacheListener listener) { - mListeners.remove(listener); - } - /** * Get a usable cache directory (external if available, internal otherwise) * - * @param context The {@link Context} to use + * @param context The {@link Context} to use * @param uniqueName A unique directory name to append to the cache - * directory + * directory * @return The cache directory */ public static File getDiskCacheDir(final Context context, final String uniqueName) { // getExternalCacheDir(context) returns null if external storage is not ready final String cachePath = getExternalCacheDir(context) != null - ? getExternalCacheDir(context).getPath() - : context.getCacheDir().getPath(); + ? getExternalCacheDir(context).getPath() + : context.getCacheDir().getPath(); return new File(cachePath, uniqueName); } - /** - * Check if external storage is built-in or removable - * - * @return True if external storage is removable (like an SD card), false - * otherwise - */ - public static boolean isExternalStorageRemovable() { - return Environment.isExternalStorageRemovable(); - } - /** * Get the external app cache directory * @@ -688,6 +603,7 @@ public final class ImageCache { * @param path The path to check * @return The space available in bytes */ + @SuppressLint("UsableSpace") public static long getUsableSpace(final File path) { return path.getUsableSpace(); } @@ -715,7 +631,7 @@ public final class ImageCache { * * @param bytes The bytes to convert. * @return A {@link String} converted from the bytes of a hashable key used - * to store a filename on the disk, to hex digits. + * to store a filename on the disk, to hex digits. */ private static String bytesToHexString(final byte[] bytes) { final StringBuilder builder = new StringBuilder(); diff --git a/src/org/lineageos/eleven/cache/ImageFetcher.java b/src/org/lineageos/eleven/cache/ImageFetcher.java index 4f54a8f1442bcdb98fcf4852fd0b9511b3e09047..ff4abe5620d57036353a1bd7b064c36aced8c762 100644 --- a/src/org/lineageos/eleven/cache/ImageFetcher.java +++ b/src/org/lineageos/eleven/cache/ImageFetcher.java @@ -1,7 +1,7 @@ /* * Copyright (C) 2012 Andrew Neal * Copyright (C) 2014 The CyanogenMod Project - * Copyright (C) 2019 The LineageOS Project + * Copyright (C) 2019-2021 The LineageOS Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -15,7 +15,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package org.lineageos.eleven.cache; import android.content.ContentResolver; @@ -23,14 +22,14 @@ import android.content.Context; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.net.Uri; -import android.util.Log; import android.widget.ImageView; + import org.lineageos.eleven.Config; import org.lineageos.eleven.MusicPlaybackService; import org.lineageos.eleven.cache.PlaylistWorkerTask.PlaylistWorkerType; +import org.lineageos.eleven.utils.MusicUtils; import org.lineageos.eleven.utils.PreferenceUtils; import org.lineageos.eleven.utils.colors.BitmapWithColors; -import org.lineageos.eleven.utils.MusicUtils; import org.lineageos.eleven.utils.colors.ColorExtractor; import org.lineageos.eleven.widgets.AlbumScrimImage; import org.lineageos.eleven.widgets.LetterTileDrawable; @@ -66,7 +65,7 @@ public class ImageFetcher extends ImageWorker { * @param context The {@link Context} to use * @return A new instance of this class. */ - public static final ImageFetcher getInstance(final Context context) { + public static ImageFetcher getInstance(final Context context) { if (sInstance == null) { sInstance = new ImageFetcher(context.getApplicationContext()); } @@ -79,8 +78,9 @@ public class ImageFetcher extends ImageWorker { /** * Loads a playlist's most played song's artist image + * * @param playlistId id of the playlist - * @param imageView imageview to load into + * @param imageView imageview to load into */ public void loadPlaylistArtistImage(final long playlistId, final ImageView imageView) { loadPlaylistImage(playlistId, PlaylistWorkerType.Artist, imageView); @@ -88,8 +88,9 @@ public class ImageFetcher extends ImageWorker { /** * Loads a playlist's most played songs into a combined image, or show 1 if not enough images + * * @param playlistId id of the playlist - * @param imageView imageview to load into + * @param imageView imageview to load into */ public void loadPlaylistCoverArtImage(final long playlistId, final ImageView imageView) { loadPlaylistImage(playlistId, PlaylistWorkerType.CoverArt, imageView); @@ -100,21 +101,20 @@ public class ImageFetcher extends ImageWorker { */ public void loadAlbumImage(final String artistName, final String albumName, final long albumId, final ImageView imageView) { - loadImage(generateAlbumCacheKey(albumName, artistName), artistName, albumName, albumId, imageView, - ImageType.ALBUM); + loadImage(generateAlbumCacheKey(albumName, artistName), artistName, albumName, albumId, + imageView, ImageType.ALBUM); } /** * Used to fetch the current artwork. */ public void loadCurrentArtwork(final ImageView imageView) { - loadImage(getCurrentCacheKey(), - MusicUtils.getArtistName(), MusicUtils.getAlbumName(), MusicUtils.getCurrentAlbumId(), - imageView, ImageType.ALBUM); + loadImage(getCurrentCacheKey(), MusicUtils.getArtistName(), MusicUtils.getAlbumName(), + MusicUtils.getCurrentAlbumId(), imageView, ImageType.ALBUM); } public void updateScrimImage(final AlbumScrimImage image, - final ColorExtractor.Callback callback) { + final ColorExtractor.Callback callback) { if (mUseBlur) { loadCurrentBlurredArtwork(image); } else { @@ -126,9 +126,8 @@ public class ImageFetcher extends ImageWorker { * Used to fetch the current artwork blurred. */ private void loadCurrentBlurredArtwork(final AlbumScrimImage image) { - loadBlurImage(getCurrentCacheKey(), - MusicUtils.getArtistName(), MusicUtils.getAlbumName(), MusicUtils.getCurrentAlbumId(), - image, ImageType.ALBUM); + loadBlurImage(getCurrentCacheKey(), MusicUtils.getArtistName(), MusicUtils.getAlbumName(), + MusicUtils.getCurrentAlbumId(), image); } private void loadCurrentGradientArtwork(final ColorExtractor.Callback callback) { @@ -154,27 +153,11 @@ public class ImageFetcher extends ImageWorker { /** * Used to fetch artist images. It also scales the image to fit the image view, if necessary. */ - public void loadArtistImage(final String key, final ImageView imageView, boolean scaleImgToView) { + public void loadArtistImage(final String key, final ImageView imageView, + boolean scaleImgToView) { loadImage(key, key, null, -1, imageView, ImageType.ARTIST, scaleImgToView); } - /** - * Used to fetch the current artist image. - */ - public void loadCurrentArtistImage(final ImageView imageView) { - loadImage(MusicUtils.getArtistName(), MusicUtils.getArtistName(), null, -1, imageView, - ImageType.ARTIST); - } - - /** - * @param pause True to temporarily pause the disk cache, false otherwise. - */ - public void setPauseDiskCache(final boolean pause) { - if (mImageCache != null) { - mImageCache.setPauseDiskCache(pause); - } - } - /** * Clears the disk and memory caches */ @@ -187,18 +170,6 @@ public class ImageFetcher extends ImageWorker { sKeys.clear(); } - public void addCacheListener(ICacheListener listener) { - if (mImageCache != null) { - mImageCache.addCacheListener(listener); - } - } - - public void removeCacheListener(ICacheListener listener) { - if (mImageCache != null) { - mImageCache.removeCacheListener(listener); - } - } - /** * @param key The key used to find the image to remove */ @@ -214,13 +185,11 @@ public class ImageFetcher extends ImageWorker { * * @param albumName The name of the current album * @param albumId The ID of the current album - * @param artistName The album artist in case we should have to download - * missing artwork * @param smallArtwork Get the small version of the default artwork if no artwork exists * @return The album art as an {@link Bitmap} */ public BitmapWithColors getArtwork(final String albumName, final long albumId, - final String artistName, boolean smallArtwork) { + boolean smallArtwork) { final String key = String.valueOf(albumId); final Bitmap artwork = getArtworkBitmap(albumName, albumId); if (artwork != null) { @@ -252,7 +221,6 @@ public class ImageFetcher extends ImageWorker { * * @param albumName The album name the cache key needs to be generated. * @param artistName The artist name the cache key needs to be generated. - * @return */ public static String generateAlbumCacheKey(final String albumName, final String artistName) { if (albumName == null || artistName == null) { @@ -266,8 +234,8 @@ public class ImageFetcher extends ImageWorker { * * @param selectedImage Uri of the Image to decode * @return A {@link Bitmap} sampled down from the original with the same - * aspect ratio and dimensions that are equal to or greater than the - * requested width and height + * aspect ratio and dimensions that are equal to or greater than the + * requested width and height */ public static Bitmap decodeSampledBitmapFromUri(ContentResolver cr, final Uri selectedImage) { // First decode with inJustDecodeBounds=true to check dimensions @@ -312,14 +280,14 @@ public class ImageFetcher extends ImageWorker { * decoding but results in a larger bitmap which isn't as useful for caching * purposes. * - * @param options An options object with out* params already populated (run - * through a decode* method with inJustDecodeBounds==true - * @param reqWidth The requested width of the resulting bitmap + * @param options An options object with out* params already populated (run + * through a decode* method with inJustDecodeBounds==true + * @param reqWidth The requested width of the resulting bitmap * @param reqHeight The requested height of the resulting bitmap * @return The value to be used for inSampleSize */ - public static final int calculateInSampleSize(final BitmapFactory.Options options, - final int reqWidth, final int reqHeight) { + public static int calculateInSampleSize(final BitmapFactory.Options options, + final int reqWidth, final int reqHeight) { /* Raw height and width of image */ final int height = options.outHeight; final int width = options.outWidth; @@ -327,9 +295,9 @@ public class ImageFetcher extends ImageWorker { if (height > reqHeight || width > reqWidth) { if (width > height) { - inSampleSize = Math.round((float)height / (float)reqHeight); + inSampleSize = Math.round((float) height / (float) reqHeight); } else { - inSampleSize = Math.round((float)width / (float)reqWidth); + inSampleSize = Math.round((float) width / (float) reqWidth); } // This offers some additional logic in case the image has a strange diff --git a/src/org/lineageos/eleven/cache/ImageWorker.java b/src/org/lineageos/eleven/cache/ImageWorker.java index 7ce4417e7f8d3b7e91e4910a0d5a16904b2b5240..277aeb4a434ba663ad4b7945418fb6fcea3a5557 100644 --- a/src/org/lineageos/eleven/cache/ImageWorker.java +++ b/src/org/lineageos/eleven/cache/ImageWorker.java @@ -1,7 +1,7 @@ /* * Copyright (C) 2012 Andrew Neal * Copyright (C) 2014 The CyanogenMod Project - * Copyright (C) 2019 The LineageOS Project + * Copyright (C) 2019-2021 The LineageOS Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -15,7 +15,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package org.lineageos.eleven.cache; import android.content.Context; @@ -26,14 +25,13 @@ import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.Drawable; import android.graphics.drawable.TransitionDrawable; -import android.renderscript.RenderScript; import android.view.View; import android.widget.ImageView; +import org.lineageos.eleven.cache.PlaylistWorkerTask.PlaylistWorkerType; import org.lineageos.eleven.provider.PlaylistArtworkStore; import org.lineageos.eleven.utils.ElevenUtils; import org.lineageos.eleven.utils.ImageUtils; -import org.lineageos.eleven.cache.PlaylistWorkerTask.PlaylistWorkerType; import org.lineageos.eleven.widgets.AlbumScrimImage; import org.lineageos.eleven.widgets.LetterTileDrawable; @@ -51,16 +49,11 @@ import java.util.concurrent.RejectedExecutionException; */ public abstract class ImageWorker { - /** - * Render script - */ - public static RenderScript sRenderScript = null; - /** * Tracks which images we've tried to download and prevents it from trying again * In the future we might want to throw this into a db */ - public static Set sKeys = Collections.synchronizedSet(new HashSet()); + public static final Set sKeys = Collections.synchronizedSet(new HashSet<>()); /** * Default transition drawable fade time @@ -72,11 +65,6 @@ public abstract class ImageWorker { */ public static final int FADE_IN_TIME_SLOW = 1000; - /** - * The resources to use - */ - private final Resources mResources; - /** * First layer of the transition drawable */ @@ -85,7 +73,7 @@ public abstract class ImageWorker { /** * The Context to use */ - protected Context mContext; + protected final Context mContext; /** * Disk and memory caches @@ -100,11 +88,6 @@ public abstract class ImageWorker { protected ImageWorker(final Context context) { mContext = context.getApplicationContext(); - if (sRenderScript == null) { - sRenderScript = RenderScript.create(mContext); - } - - mResources = mContext.getResources(); // Create the transparent layer for the transition drawable mTransparentDrawable = new ColorDrawable(Color.TRANSPARENT); } @@ -155,7 +138,7 @@ public abstract class ImageWorker { * @return A new drawable of the default artwork */ public Drawable getNewDrawable(ImageType imageType, String name, - String identifier) { + String identifier) { LetterTileDrawable letterTileDrawable = new LetterTileDrawable(mContext); letterTileDrawable.setTileDetails(name, identifier, imageType); letterTileDrawable.setIsCircular(false); @@ -163,8 +146,8 @@ public abstract class ImageWorker { } public static Bitmap getBitmapInBackground(final Context context, final ImageCache imageCache, - final String key, final String albumName, final String artistName, - final long albumId, final ImageType imageType) { + final String key, final long albumId, + final ImageType imageType) { // The result Bitmap bitmap = null; @@ -180,7 +163,7 @@ public abstract class ImageWorker { } // Finally, add the new image to the cache - if (bitmap != null && key != null && imageCache != null) { + if (bitmap != null) { imageCache.addBitmapToCache(key, bitmap); } @@ -192,6 +175,7 @@ public abstract class ImageWorker { /** * Parses the drawable for instances of TransitionDrawable and breaks them open until it finds * a drawable that isn't a transition drawable + * * @param drawable to parse * @return the target drawable that isn't a TransitionDrawable */ @@ -211,17 +195,19 @@ public abstract class ImageWorker { /** * Creates a transition drawable to Bitmap with params - * @param resources Android Resources! + * + * @param resources Android Resources! * @param fromDrawable the drawable to transition from - * @param bitmap the bitmap to transition to - * @param fadeTime the fade time in MS to fade in - * @param dither setting - * @param force force create a transition even if bitmap == null (fade to transparent) + * @param bitmap the bitmap to transition to + * @param fadeTime the fade time in MS to fade in + * @param force force create a transition even if bitmap == null (fade to transparent) * @return the drawable if created, null otherwise */ public static TransitionDrawable createImageTransitionDrawable(final Resources resources, - final Drawable fromDrawable, final Bitmap bitmap, final int fadeTime, - final boolean dither, final boolean force) { + final Drawable fromDrawable, + final Bitmap bitmap, + final int fadeTime, + final boolean force) { if (bitmap != null || force) { final Drawable[] arrayDrawable = new Drawable[2]; arrayDrawable[0] = getTopDrawable(fromDrawable); @@ -231,7 +217,6 @@ public abstract class ImageWorker { if (bitmap != null) { layerTwo = new BitmapDrawable(resources, bitmap); layerTwo.setFilterBitmap(false); - layerTwo.setDither(dither); } else { // if no bitmap (forced) then transition to transparent layerTwo = new ColorDrawable(Color.TRANSPARENT); @@ -279,12 +264,13 @@ public abstract class ImageWorker { /** * This will create the palette transition from the original color to the new one + * * @param scrimImage the container to change the color for - * @param color the color to transition to + * @param color the color to transition to * @return the transition to run */ public static TransitionDrawable createPaletteTransition(AlbumScrimImage scrimImage, - int color) { + int color) { final Drawable[] arrayDrawable = new Drawable[2]; arrayDrawable[0] = getTopDrawable(scrimImage.getBackground()); @@ -303,13 +289,14 @@ public abstract class ImageWorker { /** * Cancels and clears out any pending bitmap worker tasks on this image view + * * @param image ImageView/BlurScrimImage to check */ - public static final void cancelWork(final View image) { + public static void cancelWork(final View image) { Object tag = image.getTag(); - if (tag != null && tag instanceof AsyncTaskContainer) { - AsyncTaskContainer asyncTaskContainer = (AsyncTaskContainer)tag; - BitmapWorkerTask bitmapWorkerTask = asyncTaskContainer.getBitmapWorkerTask(); + if (tag instanceof AsyncTaskContainer) { + AsyncTaskContainer asyncTaskContainer = (AsyncTaskContainer) tag; + BitmapWorkerTask bitmapWorkerTask = asyncTaskContainer.getBitmapWorkerTask(); if (bitmapWorkerTask != null) { bitmapWorkerTask.cancel(false); } @@ -323,7 +310,7 @@ public abstract class ImageWorker { * Returns false if the existing async task is loading the same key value * Returns true otherwise and also cancels the async task if one exists */ - public static final boolean executePotentialWork(final String key, final View view) { + public static boolean executePotentialWork(final String key, final View view) { final AsyncTaskContainer asyncTaskContainer = getAsyncTaskContainer(view); if (asyncTaskContainer != null) { // we are trying to reload the same image, return false to indicate no work is needed @@ -346,7 +333,7 @@ public abstract class ImageWorker { * @return Retrieve the AsyncTaskContainer assigned to the {@link View}. null if there is no * such task. */ - public static final AsyncTaskContainer getAsyncTaskContainer(final View view) { + public static AsyncTaskContainer getAsyncTaskContainer(final View view) { if (view != null) { if (view.getTag() instanceof AsyncTaskContainer) { return (AsyncTaskContainer) view.getTag(); @@ -363,9 +350,10 @@ public abstract class ImageWorker { * * @param view Any {@link View} that either is or contains an ImageView. * @return Retrieve the currently active work task (if any) associated with - * this {@link View}. null if there is no such task. + * this {@link View}. null if there is no such task. */ - public static final BitmapWorkerTask getBitmapWorkerTask(final View view) { + @SuppressWarnings("rawtypes") + public static BitmapWorkerTask getBitmapWorkerTask(final View view) { AsyncTaskContainer asyncTask = getAsyncTaskContainer(view); if (asyncTask != null) { return asyncTask.getBitmapWorkerTask(); @@ -383,15 +371,15 @@ public abstract class ImageWorker { */ public static final class AsyncTaskContainer { - private final WeakReference mBitmapWorkerTaskReference; + private final WeakReference> mBitmapWorkerTaskReference; // keep a copy of the key in case the worker task mBitmapWorkerTaskReference is released // after completion - private String mKey; + private final String mKey; /** * Constructor of AsyncDrawable */ - public AsyncTaskContainer(final BitmapWorkerTask bitmapWorkerTask) { + public AsyncTaskContainer(final BitmapWorkerTask bitmapWorkerTask) { mBitmapWorkerTaskReference = new WeakReference<>(bitmapWorkerTask); mKey = bitmapWorkerTask.mKey; } @@ -399,7 +387,7 @@ public abstract class ImageWorker { /** * @return The {@link BitmapWorkerTask} associated with this drawable */ - public BitmapWorkerTask getBitmapWorkerTask() { + public BitmapWorkerTask getBitmapWorkerTask() { return mBitmapWorkerTaskReference.get(); } @@ -410,16 +398,17 @@ public abstract class ImageWorker { /** * Loads the default image into the image view given the image type + * * @param imageView The {@link ImageView} * @param imageType The type of image */ public void loadDefaultImage(final ImageView imageView, final ImageType imageType, - final String name, final String identifier) { + final String name, final String identifier) { if (imageView != null) { // if an existing letter drawable exists, re-use it Drawable existingDrawable = imageView.getDrawable(); - if (existingDrawable != null && existingDrawable instanceof LetterTileDrawable) { - ((LetterTileDrawable)existingDrawable).setTileDetails(name, identifier, imageType); + if (existingDrawable instanceof LetterTileDrawable) { + ((LetterTileDrawable) existingDrawable).setTileDetails(name, identifier, imageType); } else { imageView.setImageDrawable(getNewDrawable(imageType, name, identifier)); @@ -430,16 +419,17 @@ public abstract class ImageWorker { /** * Called to fetch the artist or album art. * - * @param key The unique identifier for the image. + * @param key The unique identifier for the image. * @param artistName The artist name for the Last.fm API. - * @param albumName The album name for the Last.fm API. - * @param albumId The album art index, to check for missing artwork. - * @param imageView The {@link ImageView} used to set the cached - * {@link Bitmap}. - * @param imageType The type of image URL to fetch for. + * @param albumName The album name for the Last.fm API. + * @param albumId The album art index, to check for missing artwork. + * @param imageView The {@link ImageView} used to set the cached + * {@link Bitmap}. + * @param imageType The type of image URL to fetch for. */ - protected void loadImage(final String key, final String artistName, final String albumName, - final long albumId, final ImageView imageView, final ImageType imageType) { + protected void loadImage(final String key, final String artistName, + final String albumName, final long albumId, + final ImageView imageView, final ImageType imageType) { loadImage(key, artistName, albumName, albumId, imageView, imageType, false); } @@ -447,13 +437,13 @@ public abstract class ImageWorker { /** * Called to fetch the artist or album art. * - * @param key The unique identifier for the image. - * @param artistName The artist name for the Last.fm API. - * @param albumName The album name for the Last.fm API. - * @param albumId The album art index, to check for missing artwork. - * @param imageView The {@link ImageView} used to set the cached - * {@link Bitmap}. - * @param imageType The type of image URL to fetch for. + * @param key The unique identifier for the image. + * @param artistName The artist name for the Last.fm API. + * @param albumName The album name for the Last.fm API. + * @param albumId The album art index, to check for missing artwork. + * @param imageView The {@link ImageView} used to set the cached + * {@link Bitmap}. + * @param imageType The type of image URL to fetch for. * @param scaleImgToView config option to scale the image to the image view's dimensions */ protected void loadImage(final String key, final String artistName, final String albumName, @@ -486,8 +476,7 @@ public abstract class ImageWorker { loadDefaultImage(imageView, imageType, null, key); } - if (executePotentialWork(key, imageView) - && imageView != null && !mImageCache.isDiskCachePaused()) { + if (executePotentialWork(key, imageView)) { Drawable fromDrawable = imageView.getDrawable(); if (fromDrawable == null) { fromDrawable = mTransparentDrawable; @@ -495,12 +484,13 @@ public abstract class ImageWorker { // Otherwise run the worker task final SimpleBitmapWorkerTask bitmapWorkerTask = new SimpleBitmapWorkerTask(key, - imageView, imageType, fromDrawable, mContext, scaleImgToView); + imageView, imageType, fromDrawable, mContext, scaleImgToView); - final AsyncTaskContainer asyncTaskContainer = new AsyncTaskContainer(bitmapWorkerTask); + final AsyncTaskContainer asyncTaskContainer = + new AsyncTaskContainer(bitmapWorkerTask); imageView.setTag(asyncTaskContainer); try { - ElevenUtils.execute(false, bitmapWorkerTask, + ElevenUtils.execute(bitmapWorkerTask, artistName, albumName, String.valueOf(albumId)); } catch (RejectedExecutionException e) { // Executor has exhausted queue space @@ -512,9 +502,10 @@ public abstract class ImageWorker { /** * Called to fetch a playlist's top artist or cover art + * * @param playlistId playlist identifier - * @param type of work to get (Artist or CoverArt) - * @param imageView to set the image to + * @param type of work to get (Artist or CoverArt) + * @param imageView to set the image to */ public void loadPlaylistImage(final long playlistId, final PlaylistWorkerType type, final ImageView imageView) { @@ -545,7 +536,7 @@ public abstract class ImageWorker { // even though we may have found the image in the cache, we want to check if the playlist // has been updated, or it's been too long since the last update and change the image // accordingly - if (executePotentialWork(key, imageView) && !mImageCache.isDiskCachePaused()) { + if (executePotentialWork(key, imageView)) { // since a playlist's image can change based on changes to the playlist // set the from drawable to be the existing image (if it exists) instead of transparent // and fade from there @@ -555,12 +546,12 @@ public abstract class ImageWorker { } // Otherwise run the worker task - final PlaylistWorkerTask bitmapWorkerTask = new PlaylistWorkerTask(key, playlistId, type, - lruBitmap != null, imageView, fromDrawable, mContext); + final PlaylistWorkerTask bitmapWorkerTask = new PlaylistWorkerTask(key, playlistId, + type, lruBitmap != null, imageView, fromDrawable, mContext); final AsyncTaskContainer asyncTaskContainer = new AsyncTaskContainer(bitmapWorkerTask); imageView.setTag(asyncTaskContainer); try { - ElevenUtils.execute(false, bitmapWorkerTask); + ElevenUtils.execute(bitmapWorkerTask); } catch (RejectedExecutionException e) { // Executor has exhausted queue space } @@ -569,30 +560,28 @@ public abstract class ImageWorker { /** * Called to fetch the blurred artist or album art. - * - * @param key The unique identifier for the image. - * @param artistName The artist name for the Last.fm API. - * @param albumName The album name for the Last.fm API. - * @param albumId The album art index, to check for missing artwork. - * @param albumScrimImage The {@link AlbumScrimImage} used to set the cached - * {@link Bitmap}. - * @param imageType The type of image URL to fetch for. + * @param key The unique identifier for the image. + * @param artistName The artist name for the Last.fm API. + * @param albumName The album name for the Last.fm API. + * @param albumId The album art index, to check for missing artwork. + * @param albumScrimImage The {@link AlbumScrimImage} used to set the cached {@link Bitmap}. */ protected void loadBlurImage(final String key, final String artistName, final String albumName, - final long albumId, final AlbumScrimImage albumScrimImage, final ImageType imageType) { + final long albumId, final AlbumScrimImage albumScrimImage) { if (key == null || mImageCache == null || albumScrimImage == null) { return; } - if (executePotentialWork(key, albumScrimImage) && !mImageCache.isDiskCachePaused()) { + if (executePotentialWork(key, albumScrimImage)) { // Otherwise run the worker task final BlurBitmapWorkerTask blurWorkerTask = new BlurBitmapWorkerTask(key, - albumScrimImage, imageType, mTransparentDrawable, mContext, sRenderScript); + albumScrimImage, ImageType.ALBUM, mTransparentDrawable, mContext); final AsyncTaskContainer asyncTaskContainer = new AsyncTaskContainer(blurWorkerTask); albumScrimImage.setTag(asyncTaskContainer); try { - ElevenUtils.execute(false, blurWorkerTask, artistName, albumName, String.valueOf(albumId)); + ElevenUtils.execute(blurWorkerTask, artistName, albumName, + String.valueOf(albumId)); } catch (RejectedExecutionException e) { // Executor has exhausted queue space, show default artwork albumScrimImage.transitionToDefaultState(); @@ -604,6 +593,8 @@ public abstract class ImageWorker { * Used to define what type of image URL to fetch for, artist or album. */ public enum ImageType { - ARTIST, ALBUM, PLAYLIST; + ARTIST, + ALBUM, + PLAYLIST } } diff --git a/src/org/lineageos/eleven/cache/LruCache.java b/src/org/lineageos/eleven/cache/LruCache.java index c81dad1d0cdd7fbd1390357b39e22bd60781b1f2..ee8ca274361203c8f6766db0db5c38954d6c8728 100644 --- a/src/org/lineageos/eleven/cache/LruCache.java +++ b/src/org/lineageos/eleven/cache/LruCache.java @@ -1,14 +1,19 @@ /* - * Copyright (C) 2011 The Android Open Source Project Licensed under the Apache - * License, Version 2.0 (the "License"); you may not use this file except in - * compliance with the License. You may obtain a copy of the License at - * http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law - * or agreed to in writing, software distributed under the License is - * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the specific language - * governing permissions and limitations under the License. + * Copyright (C) 2011 The Android Open Source Project + * Copyright (C) 2021 The LineageOS Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ - package org.lineageos.eleven.cache; // NOTE: upstream of this class is android.util.LruCache, changes below @@ -32,24 +37,20 @@ public class LruCache { private final int maxSize; - /** Size of this cache in units. Not necessarily the number of elements. */ + /** + * Size of this cache in units. Not necessarily the number of elements. + */ private int size; - private int putCount; - - private int createCount; - - private int evictionCount; - private int hitCount; private int missCount; /** * @param maxSize for caches that do not override {@link #sizeOf}, this is - * the maximum number of entries in the cache. For all other - * caches, this is the maximum sum of the sizes of the entries in - * this cache. + * the maximum number of entries in the cache. For all other + * caches, this is the maximum sum of the sizes of the entries in + * this cache. */ public LruCache(final int maxSize) { if (maxSize <= 0) { @@ -80,37 +81,7 @@ public class LruCache { this.missCount++; } - /* - * Attempt to create a value. This may take a long time, and the map may - * be different when create() returns. If a conflicting value was added - * to the map while create() was working, we leave that value in the map - * and release the created value. - */ - - final V createdValue = create(key); - if (createdValue == null) { - return null; - } - - synchronized (this) { - this.createCount++; - mapValue = map.put(key, createdValue); - - if (mapValue != null) { - /* There was a conflict so undo that last put */ - this.map.put(key, mapValue); - } else { - this.size += safeSizeOf(key, createdValue); - } - } - - if (mapValue != null) { - entryRemoved(false, key, createdValue, mapValue); - return mapValue; - } else { - trimToSize(maxSize); - return createdValue; - } + return null; } /** @@ -119,6 +90,7 @@ public class LruCache { * * @return the previous value mapped by {@code key}. */ + @SuppressWarnings("UnusedReturnValue") public final V put(final K key, final V value) { if (key == null || value == null) { throw new NullPointerException("key == null || value == null"); @@ -126,7 +98,6 @@ public class LruCache { V previous; synchronized (this) { - this.putCount++; this.size += safeSizeOf(key, value); previous = this.map.put(key, value); if (previous != null) { @@ -134,17 +105,13 @@ public class LruCache { } } - if (previous != null) { - entryRemoved(false, key, previous, value); - } - trimToSize(maxSize); return previous; } /** * @param maxSize the maximum size of the cache before returning. May be -1 - * to evict even 0-sized elements. + * to evict even 0-sized elements. */ public void trimToSize(final int maxSize) { while (true) { @@ -165,10 +132,7 @@ public class LruCache { value = toEvict.getValue(); this.map.remove(key); this.size -= safeSizeOf(key, value); - this.evictionCount++; } - - entryRemoved(true, key, value, null); } } @@ -177,6 +141,7 @@ public class LruCache { * * @return the previous value mapped by {@code key}. */ + @SuppressWarnings("UnusedReturnValue") public final V remove(final K key) { if (key == null) { throw new NullPointerException("key == null"); @@ -190,50 +155,9 @@ public class LruCache { } } - if (previous != null) { - entryRemoved(false, key, previous, null); - } - return previous; } - /** - * Called for entries that have been evicted or removed. This method is - * invoked when a value is evicted to make space, removed by a call to - * {@link #remove}, or replaced by a call to {@link #put}. The default - * implementation does nothing. - *

- * The method is called without synchronization: other threads may access - * the cache while this method is executing. - * - * @param evicted true if the entry is being removed to make space, false if - * the removal was caused by a {@link #put} or {@link #remove}. - * @param newValue the new value for {@code key}, if it exists. If non-null, - * this removal was caused by a {@link #put}. Otherwise it was - * caused by an eviction or a {@link #remove}. - */ - protected void entryRemoved(final boolean evicted, final K key, final V oldValue, - final V newValue) { - } - - /** - * Called after a cache miss to compute a value for the corresponding key. - * Returns the computed value or null if no value can be computed. The - * default implementation returns null. - *

- * The method is called without synchronization: other threads may access - * the cache while this method is executing. - *

- * If a value for {@code key} exists in the cache when this method returns, - * the created value will be released with {@link #entryRemoved} and - * discarded. This can occur when multiple threads request the same key at - * the same time (causing multiple values to be created), or when one thread - * calls {@link #put} while another is creating a value for the same key. - */ - protected V create(final K key) { - return null; - } - private int safeSizeOf(final K key, final V value) { final int result = sizeOf(key, value); if (result < 0) { @@ -254,7 +178,7 @@ public class LruCache { } /** - * Clear the cache, calling {@link #entryRemoved} on each removed entry. + * Clear the cache, calling {@link #trimToSize} on each removed entry. */ public final void evictAll() { trimToSize(-1); // -1 will evict 0-sized elements @@ -269,59 +193,6 @@ public class LruCache { return this.size; } - /** - * For caches that do not override {@link #sizeOf}, this returns the maximum - * number of entries in the cache. For all other caches, this returns the - * maximum sum of the sizes of the entries in this cache. - */ - public synchronized final int maxSize() { - return this.maxSize; - } - - /** - * Returns the number of times {@link #get} returned a value. - */ - public synchronized final int hitCount() { - return this.hitCount; - } - - /** - * Returns the number of times {@link #get} returned null or required a new - * value to be created. - */ - public synchronized final int missCount() { - return this.missCount; - } - - /** - * Returns the number of times {@link #create(Object)} returned a value. - */ - public synchronized final int createCount() { - return this.createCount; - } - - /** - * Returns the number of times {@link #put} was called. - */ - public synchronized final int putCount() { - return this.putCount; - } - - /** - * Returns the number of values that have been evicted. - */ - public synchronized final int evictionCount() { - return this.evictionCount; - } - - /** - * Returns a copy of the current contents of the cache, ordered from least - * recently accessed to most recently accessed. - */ - public synchronized final Map snapshot() { - return new LinkedHashMap<>(this.map); - } - @SuppressLint("DefaultLocale") @Override public synchronized final String toString() { diff --git a/src/org/lineageos/eleven/cache/PlaylistWorkerTask.java b/src/org/lineageos/eleven/cache/PlaylistWorkerTask.java index c962d45476d5229c71b9720b28ed1d6fc99ebbcf..d797ffaa52ffba42caeeb2e2f5ed05df5572c58a 100644 --- a/src/org/lineageos/eleven/cache/PlaylistWorkerTask.java +++ b/src/org/lineageos/eleven/cache/PlaylistWorkerTask.java @@ -1,18 +1,19 @@ /* -* Copyright (C) 2014 The CyanogenMod Project -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ + * Copyright (C) 2014 The CyanogenMod Project + * Copyright (C) 2021 The LineageOS Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package org.lineageos.eleven.cache; import android.content.Context; @@ -69,9 +70,10 @@ public class PlaylistWorkerTask extends BitmapWorkerTask keys = new HashSet<>(sortedCursor.getCount()); @@ -297,7 +295,7 @@ public class PlaylistWorkerTask extends BitmapWorkerTaskBitmapWorkerTask * - * @param key the key of the image to store to - * @param imageView The {@link ImageView} to use. - * @param imageType The type of image URL to fetch for. - * @param fromDrawable what drawable to transition from - */ - public SimpleBitmapWorkerTask(final String key, final ImageView imageView, final ImageType imageType, - final Drawable fromDrawable, final Context context) { - super(key, imageView, imageType, fromDrawable, context); - } - - /** - * Constructor of BitmapWorkerTask - * - * @param key the key of the image to store to - * @param imageView The {@link ImageView} to use. - * @param imageType The type of image URL to fetch for. - * @param fromDrawable what drawable to transition from + * @param key the key of the image to store to + * @param imageView The {@link ImageView} to use. + * @param imageType The type of image URL to fetch for. + * @param fromDrawable what drawable to transition from * @param scaleImgToView flag to scale the bitmap to the image view bounds */ - public SimpleBitmapWorkerTask(final String key, final ImageView imageView, final ImageType imageType, - final Drawable fromDrawable, final Context context, final boolean scaleImgToView) { + public SimpleBitmapWorkerTask(final String key, final ImageView imageView, + final ImageType imageType, final Drawable fromDrawable, + final Context context, final boolean scaleImgToView) { super(key, imageView, imageType, fromDrawable, context, scaleImgToView); } - /** - * {@inheritDoc} - */ @Override protected TransitionDrawable doInBackground(final String... params) { if (isCancelled()) { @@ -66,16 +53,14 @@ public class SimpleBitmapWorkerTask extends BitmapWorkerTask lruEntries = - new LinkedHashMap(0, 0.75f, true); - private int redundantOpCount; - - /** - * To differentiate between old and current snapshots, each entry is given - * a sequence number each time an edit is committed. A snapshot is stale if - * its sequence number is not equal to its entry's sequence number. - */ - private long nextSequenceNumber = 0; - - /** This cache uses a single background thread to evict entries. */ - final ThreadPoolExecutor executorService = - new ThreadPoolExecutor(0, 1, 60L, TimeUnit.SECONDS, new LinkedBlockingQueue()); - private final Callable cleanupCallable = new Callable() { - public Void call() throws Exception { - synchronized (DiskLruCache.this) { - if (journalWriter == null) { - return null; // Closed. - } - trimToSize(); - if (journalRebuildRequired()) { - rebuildJournal(); - redundantOpCount = 0; + private final File directory; + private final File journalFile; + private final File journalFileTmp; + private final File journalFileBackup; + private final int appVersion; + private long maxSize; + private final int valueCount; + private long size = 0; + private Writer journalWriter; + private final LinkedHashMap lruEntries = + new LinkedHashMap<>(0, 0.75f, true); + private int redundantOpCount; + + /** + * To differentiate between old and current snapshots, each entry is given + * a sequence number each time an edit is committed. A snapshot is stale if + * its sequence number is not equal to its entry's sequence number. + */ + private long nextSequenceNumber = 0; + + /** + * This cache uses a single background thread to evict entries. + */ + final ThreadPoolExecutor executorService = + new ThreadPoolExecutor(0, 1, 60L, TimeUnit.SECONDS, new LinkedBlockingQueue<>()); + private final Callable cleanupCallable = new Callable() { + public Void call() throws Exception { + synchronized (DiskLruCache.this) { + if (journalWriter == null) { + return null; // Closed. + } + trimToSize(); + if (journalRebuildRequired()) { + rebuildJournal(); + redundantOpCount = 0; + } + } + return null; } - } - return null; - } - }; - - private DiskLruCache(File directory, int appVersion, int valueCount, long maxSize) { - this.directory = directory; - this.appVersion = appVersion; - this.journalFile = new File(directory, JOURNAL_FILE); - this.journalFileTmp = new File(directory, JOURNAL_FILE_TEMP); - this.journalFileBackup = new File(directory, JOURNAL_FILE_BACKUP); - this.valueCount = valueCount; - this.maxSize = maxSize; - } - - /** - * Opens the cache in {@code directory}, creating a cache if none exists - * there. - * - * @param directory a writable directory - * @param valueCount the number of values per cache entry. Must be positive. - * @param maxSize the maximum number of bytes this cache should use to store - * @throws IOException if reading or writing the cache directory fails - */ - public static DiskLruCache open(File directory, int appVersion, int valueCount, long maxSize) - throws IOException { - if (maxSize <= 0) { - throw new IllegalArgumentException("maxSize <= 0"); - } - if (valueCount <= 0) { - throw new IllegalArgumentException("valueCount <= 0"); - } + }; - // If a bkp file exists, use it instead. - File backupFile = new File(directory, JOURNAL_FILE_BACKUP); - if (backupFile.exists()) { - File journalFile = new File(directory, JOURNAL_FILE); - // If journal file also exists just delete backup file. - if (journalFile.exists()) { - backupFile.delete(); - } else { - renameTo(backupFile, journalFile, false); - } + private DiskLruCache(File directory, int appVersion, int valueCount, long maxSize) { + this.directory = directory; + this.appVersion = appVersion; + this.journalFile = new File(directory, JOURNAL_FILE); + this.journalFileTmp = new File(directory, JOURNAL_FILE_TEMP); + this.journalFileBackup = new File(directory, JOURNAL_FILE_BACKUP); + this.valueCount = valueCount; + this.maxSize = maxSize; } - // Prefer to pick up where we left off. - DiskLruCache cache = new DiskLruCache(directory, appVersion, valueCount, maxSize); - if (cache.journalFile.exists()) { - try { - cache.readJournal(); - cache.processJournal(); + /** + * Opens the cache in {@code directory}, creating a cache if none exists + * there. + * + * @param directory a writable directory + * @param valueCount the number of values per cache entry. Must be positive. + * @param maxSize the maximum number of bytes this cache should use to store + * @throws IOException if reading or writing the cache directory fails + */ + public static DiskLruCache open(File directory, int appVersion, int valueCount, long maxSize) + throws IOException { + if (maxSize <= 0) { + throw new IllegalArgumentException("maxSize <= 0"); + } + if (valueCount <= 0) { + throw new IllegalArgumentException("valueCount <= 0"); + } + + // If a bkp file exists, use it instead. + File backupFile = new File(directory, JOURNAL_FILE_BACKUP); + if (backupFile.exists()) { + File journalFile = new File(directory, JOURNAL_FILE); + // If journal file also exists just delete backup file. + if (journalFile.exists()) { + //noinspection ResultOfMethodCallIgnored + backupFile.delete(); + } else { + renameTo(backupFile, journalFile, false); + } + } + + // Prefer to pick up where we left off. + DiskLruCache cache = new DiskLruCache(directory, appVersion, valueCount, maxSize); + if (cache.journalFile.exists()) { + try { + cache.readJournal(); + cache.processJournal(); + return cache; + } catch (IOException journalIsCorrupt) { + System.out + .println("DiskLruCache " + + directory + + " is corrupt: " + + journalIsCorrupt.getMessage() + + ", removing"); + cache.delete(); + } + } + + // Create a new empty cache. + //noinspection ResultOfMethodCallIgnored + directory.mkdirs(); + cache = new DiskLruCache(directory, appVersion, valueCount, maxSize); + cache.rebuildJournal(); return cache; - } catch (IOException journalIsCorrupt) { - System.out - .println("DiskLruCache " - + directory - + " is corrupt: " - + journalIsCorrupt.getMessage() - + ", removing"); - cache.delete(); - } } - // Create a new empty cache. - directory.mkdirs(); - cache = new DiskLruCache(directory, appVersion, valueCount, maxSize); - cache.rebuildJournal(); - return cache; - } - - private void readJournal() throws IOException { - StrictLineReader reader = new StrictLineReader(new FileInputStream(journalFile), Util.US_ASCII); - try { - String magic = reader.readLine(); - String version = reader.readLine(); - String appVersionString = reader.readLine(); - String valueCountString = reader.readLine(); - String blank = reader.readLine(); - if (!MAGIC.equals(magic) - || !VERSION_1.equals(version) - || !Integer.toString(appVersion).equals(appVersionString) - || !Integer.toString(valueCount).equals(valueCountString) - || !"".equals(blank)) { - throw new IOException("unexpected journal header: [" + magic + ", " + version + ", " - + valueCountString + ", " + blank + "]"); - } - - int lineCount = 0; - while (true) { + private void readJournal() throws IOException { + StrictLineReader reader = new StrictLineReader(new FileInputStream(journalFile), + Util.US_ASCII); try { - readJournalLine(reader.readLine()); - lineCount++; - } catch (EOFException endOfJournal) { - break; - } - } - redundantOpCount = lineCount - lruEntries.size(); - - // If we ended on a truncated line, rebuild the journal before appending to it. - if (reader.hasUnterminatedLine()) { - rebuildJournal(); - } else { - journalWriter = new BufferedWriter(new OutputStreamWriter( - new FileOutputStream(journalFile, true), Util.US_ASCII)); - } - } finally { - Util.closeQuietly(reader); - } - } - - private void readJournalLine(String line) throws IOException { - int firstSpace = line.indexOf(' '); - if (firstSpace == -1) { - throw new IOException("unexpected journal line: " + line); + String magic = reader.readLine(); + String version = reader.readLine(); + String appVersionString = reader.readLine(); + String valueCountString = reader.readLine(); + String blank = reader.readLine(); + if (!MAGIC.equals(magic) + || !VERSION_1.equals(version) + || !Integer.toString(appVersion).equals(appVersionString) + || !Integer.toString(valueCount).equals(valueCountString) + || !"".equals(blank)) { + throw new IOException("unexpected journal header: [" + magic + ", " + version + ", " + + valueCountString + ", " + blank + "]"); + } + + int lineCount = 0; + while (true) { + try { + readJournalLine(reader.readLine()); + lineCount++; + } catch (EOFException endOfJournal) { + break; + } + } + redundantOpCount = lineCount - lruEntries.size(); + + // If we ended on a truncated line, rebuild the journal before appending to it. + if (reader.hasUnterminatedLine()) { + rebuildJournal(); + } else { + journalWriter = new BufferedWriter(new OutputStreamWriter( + new FileOutputStream(journalFile, true), Util.US_ASCII)); + } + } finally { + Util.closeQuietly(reader); + } } - int keyBegin = firstSpace + 1; - int secondSpace = line.indexOf(' ', keyBegin); - final String key; - if (secondSpace == -1) { - key = line.substring(keyBegin); - if (firstSpace == REMOVE.length() && line.startsWith(REMOVE)) { - lruEntries.remove(key); - return; - } - } else { - key = line.substring(keyBegin, secondSpace); - } + private void readJournalLine(String line) throws IOException { + int firstSpace = line.indexOf(' '); + if (firstSpace == -1) { + throw new IOException("unexpected journal line: " + line); + } - Entry entry = lruEntries.get(key); - if (entry == null) { - entry = new Entry(key); - lruEntries.put(key, entry); - } + int keyBegin = firstSpace + 1; + int secondSpace = line.indexOf(' ', keyBegin); + final String key; + if (secondSpace == -1) { + key = line.substring(keyBegin); + if (firstSpace == REMOVE.length() && line.startsWith(REMOVE)) { + lruEntries.remove(key); + return; + } + } else { + key = line.substring(keyBegin, secondSpace); + } - if (secondSpace != -1 && firstSpace == CLEAN.length() && line.startsWith(CLEAN)) { - String[] parts = line.substring(secondSpace + 1).split(" "); - entry.readable = true; - entry.currentEditor = null; - entry.setLengths(parts); - } else if (secondSpace == -1 && firstSpace == DIRTY.length() && line.startsWith(DIRTY)) { - entry.currentEditor = new Editor(entry); - } else if (secondSpace == -1 && firstSpace == READ.length() && line.startsWith(READ)) { - // This work was already done by calling lruEntries.get(). - } else { - throw new IOException("unexpected journal line: " + line); - } - } - - /** - * Computes the initial size and collects garbage as a part of opening the - * cache. Dirty entries are assumed to be inconsistent and will be deleted. - */ - private void processJournal() throws IOException { - deleteIfExists(journalFileTmp); - for (Iterator i = lruEntries.values().iterator(); i.hasNext(); ) { - Entry entry = i.next(); - if (entry.currentEditor == null) { - for (int t = 0; t < valueCount; t++) { - size += entry.lengths[t]; - } - } else { - entry.currentEditor = null; - for (int t = 0; t < valueCount; t++) { - deleteIfExists(entry.getCleanFile(t)); - deleteIfExists(entry.getDirtyFile(t)); + Entry entry = lruEntries.get(key); + if (entry == null) { + entry = new Entry(key); + lruEntries.put(key, entry); } - i.remove(); - } - } - } - - /** - * Creates a new journal that omits redundant information. This replaces the - * current journal if it exists. - */ - private synchronized void rebuildJournal() throws IOException { - if (journalWriter != null) { - journalWriter.close(); - } - Writer writer = new BufferedWriter( - new OutputStreamWriter(new FileOutputStream(journalFileTmp), Util.US_ASCII)); - try { - writer.write(MAGIC); - writer.write("\n"); - writer.write(VERSION_1); - writer.write("\n"); - writer.write(Integer.toString(appVersion)); - writer.write("\n"); - writer.write(Integer.toString(valueCount)); - writer.write("\n"); - writer.write("\n"); - - for (Entry entry : lruEntries.values()) { - if (entry.currentEditor != null) { - writer.write(DIRTY + ' ' + entry.key + '\n'); + if (secondSpace != -1 && firstSpace == CLEAN.length() && line.startsWith(CLEAN)) { + String[] parts = line.substring(secondSpace + 1).split(" "); + entry.readable = true; + entry.currentEditor = null; + entry.setLengths(parts); + } else if (secondSpace == -1 && firstSpace == DIRTY.length() && line.startsWith(DIRTY)) { + entry.currentEditor = new Editor(entry); + } else if (secondSpace == -1 && firstSpace == READ.length() && line.startsWith(READ)) { + // This work was already done by calling lruEntries.get(). } else { - writer.write(CLEAN + ' ' + entry.key + entry.getLengths() + '\n'); + throw new IOException("unexpected journal line: " + line); } - } - } finally { - writer.close(); } - if (journalFile.exists()) { - renameTo(journalFile, journalFileBackup, true); + /** + * Computes the initial size and collects garbage as a part of opening the + * cache. Dirty entries are assumed to be inconsistent and will be deleted. + */ + private void processJournal() throws IOException { + deleteIfExists(journalFileTmp); + for (Iterator i = lruEntries.values().iterator(); i.hasNext(); ) { + Entry entry = i.next(); + if (entry.currentEditor == null) { + for (int t = 0; t < valueCount; t++) { + size += entry.lengths[t]; + } + } else { + entry.currentEditor = null; + for (int t = 0; t < valueCount; t++) { + deleteIfExists(entry.getCleanFile(t)); + deleteIfExists(entry.getDirtyFile(t)); + } + i.remove(); + } + } } - renameTo(journalFileTmp, journalFile, false); - journalFileBackup.delete(); - journalWriter = new BufferedWriter( - new OutputStreamWriter(new FileOutputStream(journalFile, true), Util.US_ASCII)); - } + /** + * Creates a new journal that omits redundant information. This replaces the + * current journal if it exists. + */ + private synchronized void rebuildJournal() throws IOException { + if (journalWriter != null) { + journalWriter.close(); + } - private static void deleteIfExists(File file) throws IOException { - if (file.exists() && !file.delete()) { - throw new IOException(); - } - } + try (Writer writer = new BufferedWriter( + new OutputStreamWriter(new FileOutputStream(journalFileTmp), Util.US_ASCII))) { + writer.write(MAGIC); + writer.write("\n"); + writer.write(VERSION_1); + writer.write("\n"); + writer.write(Integer.toString(appVersion)); + writer.write("\n"); + writer.write(Integer.toString(valueCount)); + writer.write("\n"); + writer.write("\n"); + + for (Entry entry : lruEntries.values()) { + if (entry.currentEditor != null) { + writer.write(DIRTY + ' ' + entry.key + '\n'); + } else { + writer.write(CLEAN + ' ' + entry.key + entry.getLengths() + '\n'); + } + } + } - private static void renameTo(File from, File to, boolean deleteDestination) throws IOException { - if (deleteDestination) { - deleteIfExists(to); - } - if (!from.renameTo(to)) { - throw new IOException(); - } - } - - /** - * Returns a snapshot of the entry named {@code key}, or null if it doesn't - * exist is not currently readable. If a value is returned, it is moved to - * the head of the LRU queue. - */ - public synchronized Snapshot get(String key) throws IOException { - checkNotClosed(); - validateKey(key); - Entry entry = lruEntries.get(key); - if (entry == null) { - return null; - } + if (journalFile.exists()) { + renameTo(journalFile, journalFileBackup, true); + } + renameTo(journalFileTmp, journalFile, false); + //noinspection ResultOfMethodCallIgnored + journalFileBackup.delete(); - if (!entry.readable) { - return null; + journalWriter = new BufferedWriter( + new OutputStreamWriter(new FileOutputStream(journalFile, true), Util.US_ASCII)); } - // Open all streams eagerly to guarantee that we see a single published - // snapshot. If we opened streams lazily then the streams could come - // from different edits. - InputStream[] ins = new InputStream[valueCount]; - try { - for (int i = 0; i < valueCount; i++) { - ins[i] = new FileInputStream(entry.getCleanFile(i)); - } - } catch (FileNotFoundException e) { - // A file must have been deleted manually! - for (int i = 0; i < valueCount; i++) { - if (ins[i] != null) { - Util.closeQuietly(ins[i]); - } else { - break; + private static void deleteIfExists(File file) throws IOException { + if (file.exists() && !file.delete()) { + throw new IOException(); } - } - return null; } - redundantOpCount++; - journalWriter.append(READ + ' ' + key + '\n'); - if (journalRebuildRequired()) { - executorService.submit(cleanupCallable); + private static void renameTo(File from, File to, boolean deleteDestination) throws IOException { + if (deleteDestination) { + deleteIfExists(to); + } + if (!from.renameTo(to)) { + throw new IOException(); + } } - return new Snapshot(key, entry.sequenceNumber, ins, entry.lengths); - } - - /** - * Returns an editor for the entry named {@code key}, or null if another - * edit is in progress. - */ - public Editor edit(String key) throws IOException { - return edit(key, ANY_SEQUENCE_NUMBER); - } - - private synchronized Editor edit(String key, long expectedSequenceNumber) throws IOException { - checkNotClosed(); - validateKey(key); - Entry entry = lruEntries.get(key); - if (expectedSequenceNumber != ANY_SEQUENCE_NUMBER && (entry == null - || entry.sequenceNumber != expectedSequenceNumber)) { - return null; // Snapshot is stale. - } - if (entry == null) { - entry = new Entry(key); - lruEntries.put(key, entry); - } else if (entry.currentEditor != null) { - return null; // Another edit is in progress. - } + /** + * Returns a snapshot of the entry named {@code key}, or null if it doesn't + * exist is not currently readable. If a value is returned, it is moved to + * the head of the LRU queue. + */ + public synchronized Snapshot get(String key) throws IOException { + checkNotClosed(); + validateKey(key); + Entry entry = lruEntries.get(key); + if (entry == null) { + return null; + } - Editor editor = new Editor(entry); - entry.currentEditor = editor; - - // Flush the journal before creating files to prevent file leaks. - journalWriter.write(DIRTY + ' ' + key + '\n'); - journalWriter.flush(); - return editor; - } - - /** Returns the directory where this cache stores its data. */ - public File getDirectory() { - return directory; - } - - /** - * Returns the maximum number of bytes that this cache should use to store - * its data. - */ - public synchronized long getMaxSize() { - return maxSize; - } - - /** - * Changes the maximum number of bytes the cache can store and queues a job - * to trim the existing store, if necessary. - */ - public synchronized void setMaxSize(long maxSize) { - this.maxSize = maxSize; - executorService.submit(cleanupCallable); - } - - /** - * Returns the number of bytes currently being used to store the values in - * this cache. This may be greater than the max size if a background - * deletion is pending. - */ - public synchronized long size() { - return size; - } - - private synchronized void completeEdit(Editor editor, boolean success) throws IOException { - Entry entry = editor.entry; - if (entry.currentEditor != editor) { - throw new IllegalStateException(); - } + if (!entry.readable) { + return null; + } - // If this edit is creating the entry for the first time, every index must have a value. - if (success && !entry.readable) { - for (int i = 0; i < valueCount; i++) { - if (!editor.written[i]) { - editor.abort(); - throw new IllegalStateException("Newly created entry didn't create value for index " + i); + // Open all streams eagerly to guarantee that we see a single published + // snapshot. If we opened streams lazily then the streams could come + // from different edits. + InputStream[] ins = new InputStream[valueCount]; + try { + for (int i = 0; i < valueCount; i++) { + ins[i] = new FileInputStream(entry.getCleanFile(i)); + } + } catch (FileNotFoundException e) { + // A file must have been deleted manually! + for (int i = 0; i < valueCount; i++) { + if (ins[i] != null) { + Util.closeQuietly(ins[i]); + } else { + break; + } + } + return null; } - if (!entry.getDirtyFile(i).exists()) { - editor.abort(); - return; + + redundantOpCount++; + journalWriter.append(READ + ' ').append(key).append(String.valueOf('\n')); + if (journalRebuildRequired()) { + executorService.submit(cleanupCallable); } - } - } - for (int i = 0; i < valueCount; i++) { - File dirty = entry.getDirtyFile(i); - if (success) { - if (dirty.exists()) { - File clean = entry.getCleanFile(i); - dirty.renameTo(clean); - long oldLength = entry.lengths[i]; - long newLength = clean.length(); - entry.lengths[i] = newLength; - size = size - oldLength + newLength; - } - } else { - deleteIfExists(dirty); - } + return new Snapshot(ins); } - redundantOpCount++; - entry.currentEditor = null; - if (entry.readable | success) { - entry.readable = true; - journalWriter.write(CLEAN + ' ' + entry.key + entry.getLengths() + '\n'); - if (success) { - entry.sequenceNumber = nextSequenceNumber++; - } - } else { - lruEntries.remove(entry.key); - journalWriter.write(REMOVE + ' ' + entry.key + '\n'); + /** + * Returns an editor for the entry named {@code key}, or null if another + * edit is in progress. + */ + public Editor edit(String key) throws IOException { + return edit(key, ANY_SEQUENCE_NUMBER); } - journalWriter.flush(); - if (size > maxSize || journalRebuildRequired()) { - executorService.submit(cleanupCallable); - } - } - - /** - * We only rebuild the journal when it will halve the size of the journal - * and eliminate at least 2000 ops. - */ - private boolean journalRebuildRequired() { - final int redundantOpCompactThreshold = 2000; - return redundantOpCount >= redundantOpCompactThreshold // - && redundantOpCount >= lruEntries.size(); - } - - /** - * Drops the entry for {@code key} if it exists and can be removed. Entries - * actively being edited cannot be removed. - * - * @return true if an entry was removed. - */ - public synchronized boolean remove(String key) throws IOException { - checkNotClosed(); - validateKey(key); - Entry entry = lruEntries.get(key); - if (entry == null || entry.currentEditor != null) { - return false; - } + private synchronized Editor edit(String key, long expectedSequenceNumber) throws IOException { + checkNotClosed(); + validateKey(key); + Entry entry = lruEntries.get(key); + if (expectedSequenceNumber != ANY_SEQUENCE_NUMBER && (entry == null + || entry.sequenceNumber != expectedSequenceNumber)) { + return null; // Snapshot is stale. + } + if (entry == null) { + entry = new Entry(key); + lruEntries.put(key, entry); + } else if (entry.currentEditor != null) { + return null; // Another edit is in progress. + } - for (int i = 0; i < valueCount; i++) { - File file = entry.getCleanFile(i); - if (file.exists() && !file.delete()) { - throw new IOException("failed to delete " + file); - } - size -= entry.lengths[i]; - entry.lengths[i] = 0; + Editor editor = new Editor(entry); + entry.currentEditor = editor; + + // Flush the journal before creating files to prevent file leaks. + journalWriter.write(DIRTY + ' ' + key + '\n'); + journalWriter.flush(); + return editor; } - redundantOpCount++; - journalWriter.append(REMOVE + ' ' + key + '\n'); - lruEntries.remove(key); + private synchronized void completeEdit(Editor editor, boolean success) throws IOException { + Entry entry = editor.entry; + if (entry.currentEditor != editor) { + throw new IllegalStateException(); + } - if (journalRebuildRequired()) { - executorService.submit(cleanupCallable); - } + // If this edit is creating the entry for the first time, every index must have a value. + if (success && !entry.readable) { + for (int i = 0; i < valueCount; i++) { + if (!editor.written[i]) { + editor.abort(); + throw new IllegalStateException("Newly created entry didn't create value for index " + i); + } + if (!entry.getDirtyFile(i).exists()) { + editor.abort(); + return; + } + } + } - return true; - } + for (int i = 0; i < valueCount; i++) { + File dirty = entry.getDirtyFile(i); + if (success) { + if (dirty.exists()) { + File clean = entry.getCleanFile(i); + dirty.renameTo(clean); + long oldLength = entry.lengths[i]; + long newLength = clean.length(); + entry.lengths[i] = newLength; + size = size - oldLength + newLength; + } + } else { + deleteIfExists(dirty); + } + } - /** Returns true if this cache has been closed. */ - public synchronized boolean isClosed() { - return journalWriter == null; - } + redundantOpCount++; + entry.currentEditor = null; + if (entry.readable | success) { + entry.readable = true; + journalWriter.write(CLEAN + ' ' + entry.key + entry.getLengths() + '\n'); + if (success) { + entry.sequenceNumber = nextSequenceNumber++; + } + } else { + lruEntries.remove(entry.key); + journalWriter.write(REMOVE + ' ' + entry.key + '\n'); + } + journalWriter.flush(); - private void checkNotClosed() { - if (journalWriter == null) { - throw new IllegalStateException("cache is closed"); - } - } - - /** Force buffered operations to the filesystem. */ - public synchronized void flush() throws IOException { - checkNotClosed(); - trimToSize(); - journalWriter.flush(); - } - - /** Closes this cache. Stored values will remain on the filesystem. */ - public synchronized void close() throws IOException { - if (journalWriter == null) { - return; // Already closed. - } - for (Entry entry : new ArrayList(lruEntries.values())) { - if (entry.currentEditor != null) { - entry.currentEditor.abort(); - } - } - trimToSize(); - journalWriter.close(); - journalWriter = null; - } - - private void trimToSize() throws IOException { - while (size > maxSize) { - Map.Entry toEvict = lruEntries.entrySet().iterator().next(); - remove(toEvict.getKey()); - } - } - - /** - * Closes the cache and deletes all of its stored values. This will delete - * all files in the cache directory including files that weren't created by - * the cache. - */ - public void delete() throws IOException { - close(); - Util.deleteContents(directory); - } - - private void validateKey(String key) { - Matcher matcher = LEGAL_KEY_PATTERN.matcher(key); - if (!matcher.matches()) { - throw new IllegalArgumentException("keys must match regex " - + STRING_KEY_PATTERN + ": \"" + key + "\""); - } - } - - private static String inputStreamToString(InputStream in) throws IOException { - return Util.readFully(new InputStreamReader(in, Util.UTF_8)); - } - - /** A snapshot of the values for an entry. */ - public final class Snapshot implements Closeable { - private final String key; - private final long sequenceNumber; - private final InputStream[] ins; - private final long[] lengths; - - private Snapshot(String key, long sequenceNumber, InputStream[] ins, long[] lengths) { - this.key = key; - this.sequenceNumber = sequenceNumber; - this.ins = ins; - this.lengths = lengths; + if (size > maxSize || journalRebuildRequired()) { + executorService.submit(cleanupCallable); + } } /** - * Returns an editor for this snapshot's entry, or null if either the - * entry has changed since this snapshot was created or if another edit - * is in progress. + * We only rebuild the journal when it will halve the size of the journal + * and eliminate at least 2000 ops. */ - public Editor edit() throws IOException { - return DiskLruCache.this.edit(key, sequenceNumber); + private boolean journalRebuildRequired() { + final int redundantOpCompactThreshold = 2000; + return redundantOpCount >= redundantOpCompactThreshold // + && redundantOpCount >= lruEntries.size(); } - /** Returns the unbuffered stream with the value for {@code index}. */ - public InputStream getInputStream(int index) { - return ins[index]; - } + /** + * Drops the entry for {@code key} if it exists and can be removed. Entries + * actively being edited cannot be removed. + * + * @return true if an entry was removed. + */ + @SuppressWarnings("UnusedReturnValue") + public synchronized boolean remove(String key) throws IOException { + checkNotClosed(); + validateKey(key); + Entry entry = lruEntries.get(key); + if (entry == null || entry.currentEditor != null) { + return false; + } - /** Returns the string value for {@code index}. */ - public String getString(int index) throws IOException { - return inputStreamToString(getInputStream(index)); - } + for (int i = 0; i < valueCount; i++) { + File file = entry.getCleanFile(i); + if (file.exists() && !file.delete()) { + throw new IOException("failed to delete " + file); + } + size -= entry.lengths[i]; + entry.lengths[i] = 0; + } - /** Returns the byte length of the value for {@code index}. */ - public long getLength(int index) { - return lengths[index]; - } + redundantOpCount++; + journalWriter.append(REMOVE + ' ').append(key).append(String.valueOf('\n')); + lruEntries.remove(key); - public void close() { - for (InputStream in : ins) { - Util.closeQuietly(in); - } - } - } + if (journalRebuildRequired()) { + executorService.submit(cleanupCallable); + } - private static final OutputStream NULL_OUTPUT_STREAM = new OutputStream() { - @Override - public void write(int b) throws IOException { - // Eat all writes silently. Nom nom. - } - }; - - /** Edits the values for an entry. */ - public final class Editor { - private final Entry entry; - private final boolean[] written; - private boolean hasErrors; - private boolean committed; - - private Editor(Entry entry) { - this.entry = entry; - this.written = (entry.readable) ? null : new boolean[valueCount]; + return true; } /** - * Returns an unbuffered input stream to read the last committed value, - * or null if no value has been committed. + * Returns true if this cache has been closed. */ - public InputStream newInputStream(int index) throws IOException { - synchronized (DiskLruCache.this) { - if (entry.currentEditor != this) { - throw new IllegalStateException(); - } - if (!entry.readable) { - return null; - } - try { - return new FileInputStream(entry.getCleanFile(index)); - } catch (FileNotFoundException e) { - return null; + public synchronized boolean isClosed() { + return journalWriter == null; + } + + private void checkNotClosed() { + if (journalWriter == null) { + throw new IllegalStateException("cache is closed"); } - } } /** - * Returns the last committed value as a string, or null if no value - * has been committed. + * Force buffered operations to the filesystem. */ - public String getString(int index) throws IOException { - InputStream in = newInputStream(index); - return in != null ? inputStreamToString(in) : null; + public synchronized void flush() throws IOException { + checkNotClosed(); + trimToSize(); + journalWriter.flush(); } /** - * Returns a new unbuffered output stream to write the value at - * {@code index}. If the underlying output stream encounters errors - * when writing to the filesystem, this edit will be aborted when - * {@link #commit} is called. The returned output stream does not throw - * IOExceptions. + * Closes this cache. Stored values will remain on the filesystem. */ - public OutputStream newOutputStream(int index) throws IOException { - if (index < 0 || index >= valueCount) { - throw new IllegalArgumentException("Expected index " + index + " to " - + "be greater than 0 and less than the maximum value count " - + "of " + valueCount); - } - synchronized (DiskLruCache.this) { - if (entry.currentEditor != this) { - throw new IllegalStateException(); + public synchronized void close() throws IOException { + if (journalWriter == null) { + return; // Already closed. } - if (!entry.readable) { - written[index] = true; + for (Entry entry : new ArrayList<>(lruEntries.values())) { + if (entry.currentEditor != null) { + entry.currentEditor.abort(); + } } - File dirtyFile = entry.getDirtyFile(index); - FileOutputStream outputStream; - try { - outputStream = new FileOutputStream(dirtyFile); - } catch (FileNotFoundException e) { - // Attempt to recreate the cache directory. - directory.mkdirs(); - try { - outputStream = new FileOutputStream(dirtyFile); - } catch (FileNotFoundException e2) { - // We are unable to recover. Silently eat the writes. - return NULL_OUTPUT_STREAM; - } - } - return new FaultHidingOutputStream(outputStream); - } + trimToSize(); + journalWriter.close(); + journalWriter = null; } - /** Sets the value at {@code index} to {@code value}. */ - public void set(int index, String value) throws IOException { - Writer writer = null; - try { - writer = new OutputStreamWriter(newOutputStream(index), Util.UTF_8); - writer.write(value); - } finally { - Util.closeQuietly(writer); - } + private void trimToSize() throws IOException { + while (size > maxSize) { + Map.Entry toEvict = lruEntries.entrySet().iterator().next(); + remove(toEvict.getKey()); + } } /** - * Commits this edit so it is visible to readers. This releases the - * edit lock so another edit may be started on the same key. + * Closes the cache and deletes all of its stored values. This will delete + * all files in the cache directory including files that weren't created by + * the cache. */ - public void commit() throws IOException { - if (hasErrors) { - completeEdit(this, false); - remove(entry.key); // The previous entry is stale. - } else { - completeEdit(this, true); - } - committed = true; + public void delete() throws IOException { + close(); + Util.deleteContents(directory); + } + + private void validateKey(String key) { + Matcher matcher = LEGAL_KEY_PATTERN.matcher(key); + if (!matcher.matches()) { + throw new IllegalArgumentException("keys must match regex " + + STRING_KEY_PATTERN + ": \"" + key + "\""); + } } /** - * Aborts this edit. This releases the edit lock so another edit may be - * started on the same key. + * A snapshot of the values for an entry. */ - public void abort() throws IOException { - completeEdit(this, false); - } + public static final class Snapshot implements Closeable { + private final InputStream[] ins; - public void abortUnlessCommitted() { - if (!committed) { - try { - abort(); - } catch (IOException ignored) { + private Snapshot(InputStream[] ins) { + this.ins = ins; + } + + /** + * Returns the unbuffered stream with the value for {@code index}. + */ + public InputStream getInputStream(int index) { + return ins[index]; + } + + public void close() { + for (InputStream in : ins) { + Util.closeQuietly(in); + } } - } } - private class FaultHidingOutputStream extends FilterOutputStream { - private FaultHidingOutputStream(OutputStream out) { - super(out); - } + private static final OutputStream NULL_OUTPUT_STREAM = new OutputStream() { + @Override + public void write(int b) { + // Eat all writes silently. Nom nom. + } + }; - @Override public void write(int oneByte) { - try { - out.write(oneByte); - } catch (IOException e) { - hasErrors = true; + /** + * Edits the values for an entry. + */ + public final class Editor { + private final Entry entry; + private final boolean[] written; + private boolean hasErrors; + + private Editor(Entry entry) { + this.entry = entry; + this.written = (entry.readable) ? null : new boolean[valueCount]; } - } - @Override public void write(byte[] buffer, int offset, int length) { - try { - out.write(buffer, offset, length); - } catch (IOException e) { - hasErrors = true; + /** + * Returns a new unbuffered output stream to write the value at + * {@code index}. If the underlying output stream encounters errors + * when writing to the filesystem, this edit will be aborted when + * {@link #commit} is called. The returned output stream does not throw + * IOExceptions. + */ + public OutputStream newOutputStream(int index) { + if (index < 0 || index >= valueCount) { + throw new IllegalArgumentException("Expected index " + index + " to " + + "be greater than 0 and less than the maximum value count " + + "of " + valueCount); + } + synchronized (DiskLruCache.this) { + if (entry.currentEditor != this) { + throw new IllegalStateException(); + } + if (!entry.readable) { + written[index] = true; + } + File dirtyFile = entry.getDirtyFile(index); + FileOutputStream outputStream; + try { + outputStream = new FileOutputStream(dirtyFile); + } catch (FileNotFoundException e) { + // Attempt to recreate the cache directory. + //noinspection ResultOfMethodCallIgnored + directory.mkdirs(); + try { + outputStream = new FileOutputStream(dirtyFile); + } catch (FileNotFoundException e2) { + // We are unable to recover. Silently eat the writes. + return NULL_OUTPUT_STREAM; + } + } + return new FaultHidingOutputStream(outputStream); + } } - } - @Override public void close() { - try { - out.close(); - } catch (IOException e) { - hasErrors = true; + /** + * Commits this edit so it is visible to readers. This releases the + * edit lock so another edit may be started on the same key. + */ + public void commit() throws IOException { + if (hasErrors) { + completeEdit(this, false); + remove(entry.key); // The previous entry is stale. + } else { + completeEdit(this, true); + } } - } - @Override public void flush() { - try { - out.flush(); - } catch (IOException e) { - hasErrors = true; + /** + * Aborts this edit. This releases the edit lock so another edit may be + * started on the same key. + */ + public void abort() throws IOException { + completeEdit(this, false); } - } - } - } - private final class Entry { - private final String key; + private class FaultHidingOutputStream extends FilterOutputStream { + private FaultHidingOutputStream(OutputStream out) { + super(out); + } + + @Override + public void write(int oneByte) { + try { + out.write(oneByte); + } catch (IOException e) { + hasErrors = true; + } + } + + @Override + public void write(byte[] buffer, int offset, int length) { + try { + out.write(buffer, offset, length); + } catch (IOException e) { + hasErrors = true; + } + } + + @Override + public void close() { + try { + out.close(); + } catch (IOException e) { + hasErrors = true; + } + } + + @Override + public void flush() { + try { + out.flush(); + } catch (IOException e) { + hasErrors = true; + } + } + } + } - /** Lengths of this entry's files. */ - private final long[] lengths; + private final class Entry { + private final String key; - /** True if this entry has ever been published. */ - private boolean readable; + /** + * Lengths of this entry's files. + */ + private final long[] lengths; - /** The ongoing edit or null if this entry is not being edited. */ - private Editor currentEditor; + /** + * True if this entry has ever been published. + */ + private boolean readable; - /** The sequence number of the most recently committed edit to this entry. */ - private long sequenceNumber; + /** + * The ongoing edit or null if this entry is not being edited. + */ + private Editor currentEditor; - private Entry(String key) { - this.key = key; - this.lengths = new long[valueCount]; - } + /** + * The sequence number of the most recently committed edit to this entry. + */ + private long sequenceNumber; - public String getLengths() { - StringBuilder result = new StringBuilder(); - for (long size : lengths) { - result.append(' ').append(size); - } - return result.toString(); - } + private Entry(String key) { + this.key = key; + this.lengths = new long[valueCount]; + } - /** Set lengths using decimal numbers like "10123". */ - private void setLengths(String[] strings) throws IOException { - if (strings.length != valueCount) { - throw invalidLengths(strings); - } + public String getLengths() { + StringBuilder result = new StringBuilder(); + for (long size : lengths) { + result.append(' ').append(size); + } + return result.toString(); + } - try { - for (int i = 0; i < strings.length; i++) { - lengths[i] = Long.parseLong(strings[i]); + /** + * Set lengths using decimal numbers like "10123". + */ + private void setLengths(String[] strings) throws IOException { + if (strings.length != valueCount) { + throw invalidLengths(strings); + } + + try { + for (int i = 0; i < strings.length; i++) { + lengths[i] = Long.parseLong(strings[i]); + } + } catch (NumberFormatException e) { + throw invalidLengths(strings); + } } - } catch (NumberFormatException e) { - throw invalidLengths(strings); - } - } - private IOException invalidLengths(String[] strings) throws IOException { - throw new IOException("unexpected journal line: " + java.util.Arrays.toString(strings)); - } + private IOException invalidLengths(String[] strings) throws IOException { + throw new IOException("unexpected journal line: " + java.util.Arrays.toString(strings)); + } - public File getCleanFile(int i) { - return new File(directory, key + "." + i); - } + public File getCleanFile(int i) { + return new File(directory, key + "." + i); + } - public File getDirtyFile(int i) { - return new File(directory, key + "." + i + ".tmp"); + public File getDirtyFile(int i) { + return new File(directory, key + "." + i + ".tmp"); + } } - } } diff --git a/src/org/lineageos/eleven/cache/disklrucache/Util.java b/src/org/lineageos/eleven/cache/disklrucache/Util.java index 801eca4fa55f395e3e28be7ab36b448c846536e6..dfdce5b5322811fac79ddf5feddcb5a54fc0f9ad 100644 --- a/src/org/lineageos/eleven/cache/disklrucache/Util.java +++ b/src/org/lineageos/eleven/cache/disklrucache/Util.java @@ -22,11 +22,12 @@ import java.io.IOException; import java.io.Reader; import java.io.StringWriter; import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; /** Junk drawer of utility methods. */ final class Util { - static final Charset US_ASCII = Charset.forName("US-ASCII"); - static final Charset UTF_8 = Charset.forName("UTF-8"); + static final Charset US_ASCII = StandardCharsets.US_ASCII; + static final Charset UTF_8 = StandardCharsets.UTF_8; private Util() { } diff --git a/src/org/lineageos/eleven/dragdrop/DragSortController.java b/src/org/lineageos/eleven/dragdrop/DragSortController.java deleted file mode 100644 index b4aebd1fcb2690f2ca8ff040015635f2ad5e582e..0000000000000000000000000000000000000000 --- a/src/org/lineageos/eleven/dragdrop/DragSortController.java +++ /dev/null @@ -1,442 +0,0 @@ - -package org.lineageos.eleven.dragdrop; - -import android.graphics.Point; -import android.view.GestureDetector; -import android.view.HapticFeedbackConstants; -import android.view.MotionEvent; -import android.view.View; -import android.view.ViewConfiguration; -import android.widget.AdapterView; - -/** - * Class that starts and stops item drags on a {@link DragSortListView} based on - * touch gestures. This class also inherits from {@link SimpleFloatViewManager}, - * which provides basic float View creation. An instance of this class is meant - * to be passed to the methods {@link DragSortListView#setTouchListener()} and - * {@link DragSortListView#setFloatViewManager()} of your - * {@link DragSortListView} instance. - */ -public class DragSortController extends SimpleFloatViewManager implements View.OnTouchListener, - GestureDetector.OnGestureListener { - - public final static int ON_DOWN = 0; - - public final static int ON_DRAG = 1; - - public final static int ON_LONG_PRESS = 2; - - public final static int FLING_RIGHT_REMOVE = 0; - - public final static int FLING_LEFT_REMOVE = 1; - - public final static int SLIDE_RIGHT_REMOVE = 2; - - public final static int SLIDE_LEFT_REMOVE = 3; - - public final static int MISS = -1; - - private final GestureDetector mDetector; - - private final GestureDetector mFlingRemoveDetector; - - private final int mTouchSlop; - - private final int[] mTempLoc = new int[2]; - - private final float mFlingSpeed = 500f; - - private final DragSortListView mDslv; - - private boolean mSortEnabled = true; - - private boolean mRemoveEnabled = false; - - private boolean mDragging = false; - - private int mDragInitMode = ON_DOWN; - - private int mRemoveMode; - - private int mHitPos = MISS; - - private int mItemX; - - private int mItemY; - - private int mCurrX; - - private int mCurrY; - - private int mDragHandleId; - - private float mOrigFloatAlpha = 1.0f; - - /** - * Calls {@link #DragSortController(DragSortListView, int)} with a 0 drag - * handle id, FLING_RIGHT_REMOVE remove mode, and ON_DOWN drag init. By - * default, sorting is enabled, and removal is disabled. - * - * @param dslv The DSLV instance - */ - public DragSortController(DragSortListView dslv) { - this(dslv, 0, ON_DOWN, FLING_RIGHT_REMOVE); - } - - /** - * By default, sorting is enabled, and removal is disabled. - * - * @param dslv The DSLV instance - * @param dragHandleId The resource id of the View that represents the drag - * handle in a list item. - */ - public DragSortController(DragSortListView dslv, int dragHandleId, int dragInitMode, - int removeMode) { - super(dslv); - mDslv = dslv; - mDetector = new GestureDetector(dslv.getContext(), this); - mFlingRemoveDetector = new GestureDetector(dslv.getContext(), mFlingRemoveListener); - mFlingRemoveDetector.setIsLongpressEnabled(false); - mTouchSlop = ViewConfiguration.get(dslv.getContext()).getScaledTouchSlop(); - mDragHandleId = dragHandleId; - setRemoveMode(removeMode); - setDragInitMode(dragInitMode); - mOrigFloatAlpha = dslv.getFloatAlpha(); - } - - /** - * @return The current drag init mode. - */ - public int getDragInitMode() { - return mDragInitMode; - } - - /** - * Set how a drag is initiated. Needs to be one of {@link ON_DOWN}, - * {@link ON_DRAG}, or {@link ON_LONG_PRESS}. - * - * @param mode The drag init mode. - */ - public void setDragInitMode(int mode) { - mDragInitMode = mode; - } - - /** - * Enable/Disable list item sorting. Disabling is useful if only item - * removal is desired. Prevents drags in the vertical direction. - * - * @param enabled Set true to enable list item sorting. - */ - public void setSortEnabled(boolean enabled) { - mSortEnabled = enabled; - } - - /** - * @return True if sort is enabled, false otherwise. - */ - public boolean isSortEnabled() { - return mSortEnabled; - } - - /** - * One of {@link FLING_RIGHT_REMOVE}, {@link FLING_LEFT_REMOVE}, - * {@link SLIDE_RIGHT_REMOVE}, or {@link SLIDE_LEFT_REMOVE}. - */ - public void setRemoveMode(int mode) { - mRemoveMode = mode; - } - - /** - * @return The current remove mode. - */ - public int getRemoveMode() { - return mRemoveMode; - } - - /** - * Enable/Disable item removal without affecting remove mode. - */ - public void setRemoveEnabled(boolean enabled) { - mRemoveEnabled = enabled; - } - - /** - * @return True if remove is enabled, false otherwise. - */ - public boolean isRemoveEnabled() { - return mRemoveEnabled; - } - - /** - * Set the resource id for the View that represents the drag handle in a - * list item. - * - * @param id An android resource id. - */ - public void setDragHandleId(int id) { - mDragHandleId = id; - } - - /** - * Sets flags to restrict certain motions of the floating View based on - * DragSortController settings (such as remove mode). Starts the drag on the - * DragSortListView. - * - * @param position The list item position (includes headers). - * @param deltaX Touch x-coord minus left edge of floating View. - * @param deltaY Touch y-coord minus top edge of floating View. - * @return True if drag started, false otherwise. - */ - public boolean startDrag(int position, int deltaX, int deltaY) { - - int mDragFlags = 0; - if (mSortEnabled) { - mDragFlags |= DragSortListView.DRAG_POS_Y | DragSortListView.DRAG_NEG_Y; - } - - if (mRemoveEnabled) { - if (mRemoveMode == FLING_RIGHT_REMOVE) { - mDragFlags |= DragSortListView.DRAG_POS_X; - } else if (mRemoveMode == FLING_LEFT_REMOVE) { - mDragFlags |= DragSortListView.DRAG_NEG_X; - } - } - - mDragging = mDslv.startDrag(position - mDslv.getHeaderViewsCount(), mDragFlags, deltaX, - deltaY); - return mDragging; - } - - /** - * {@inheritDoc} - */ - @Override - public boolean onTouch(View v, MotionEvent ev) { - mDetector.onTouchEvent(ev); - if (mRemoveEnabled && mDragging - && (mRemoveMode == FLING_RIGHT_REMOVE || mRemoveMode == FLING_LEFT_REMOVE)) { - mFlingRemoveDetector.onTouchEvent(ev); - } - - final int mAction = ev.getAction() & MotionEvent.ACTION_MASK; - - switch (mAction) { - case MotionEvent.ACTION_DOWN: - mCurrX = (int)ev.getX(); - mCurrY = (int)ev.getY(); - break; - case MotionEvent.ACTION_UP: - if (mRemoveEnabled) { - final int x = (int)ev.getX(); - int thirdW = mDslv.getWidth() / 3; - int twoThirdW = mDslv.getWidth() - thirdW; - if ((mRemoveMode == SLIDE_RIGHT_REMOVE && x > twoThirdW) - || (mRemoveMode == SLIDE_LEFT_REMOVE && x < thirdW)) { - mDslv.stopDrag(true); - } - } - case MotionEvent.ACTION_CANCEL: - mDragging = false; - break; - } - return false; - } - - /** - * Overrides to provide fading when slide removal is enabled. - */ - @Override - public void onDragFloatView(View floatView, Point position, Point touch) { - - if (mRemoveEnabled) { - int x = touch.x; - - if (mRemoveMode == SLIDE_RIGHT_REMOVE) { - int width = mDslv.getWidth(); - int thirdWidth = width / 3; - - float alpha; - if (x < thirdWidth) { - alpha = 1.0f; - } else if (x < width - thirdWidth) { - alpha = ((float)(width - thirdWidth - x)) / ((float)thirdWidth); - } else { - alpha = 0.0f; - } - mDslv.setFloatAlpha(mOrigFloatAlpha * alpha); - } else if (mRemoveMode == SLIDE_LEFT_REMOVE) { - int width = mDslv.getWidth(); - int thirdWidth = width / 3; - - float alpha; - if (x < thirdWidth) { - alpha = 0.0f; - } else if (x < width - thirdWidth) { - alpha = ((float)(x - thirdWidth)) / ((float)thirdWidth); - } else { - alpha = 1.0f; - } - mDslv.setFloatAlpha(mOrigFloatAlpha * alpha); - } - } - } - - /** - * Get the position to start dragging based on the ACTION_DOWN MotionEvent. - * This function simply calls {@link #dragHandleHitPosition(MotionEvent)}. - * Override to change drag handle behavior; this function is called - * internally when an ACTION_DOWN event is detected. - * - * @param ev The ACTION_DOWN MotionEvent. - * @return The list position to drag if a drag-init gesture is detected; - * MISS if unsuccessful. - */ - public int startDragPosition(MotionEvent ev) { - return dragHandleHitPosition(ev); - } - - /** - * Checks for the touch of an item's drag handle (specified by - * {@link #setDragHandleId(int)}), and returns that item's position if a - * drag handle touch was detected. - * - * @param ev The ACTION_DOWN MotionEvent. - * @return The list position of the item whose drag handle was touched; MISS - * if unsuccessful. - */ - public int dragHandleHitPosition(MotionEvent ev) { - final int x = (int)ev.getX(); - final int y = (int)ev.getY(); - - int touchPos = mDslv.pointToPosition(x, y); - - final int numHeaders = mDslv.getHeaderViewsCount(); - final int numFooters = mDslv.getFooterViewsCount(); - final int count = mDslv.getCount(); - - if (touchPos != AdapterView.INVALID_POSITION && touchPos >= numHeaders - && touchPos < (count - numFooters)) { - final View item = mDslv.getChildAt(touchPos - mDslv.getFirstVisiblePosition()); - final int rawX = (int)ev.getRawX(); - final int rawY = (int)ev.getRawY(); - - View dragBox = item.findViewById(mDragHandleId); - if (dragBox != null) { - dragBox.getLocationOnScreen(mTempLoc); - - if (rawX > mTempLoc[0] && rawY > mTempLoc[1] - && rawX < mTempLoc[0] + dragBox.getWidth() - && rawY < mTempLoc[1] + dragBox.getHeight()) { - - mItemX = item.getLeft(); - mItemY = item.getTop(); - - return touchPos; - } - } - } - return MISS; - } - - /** - * {@inheritDoc} - */ - @Override - public boolean onDown(MotionEvent ev) { - mHitPos = startDragPosition(ev); - - if (mHitPos != MISS && mDragInitMode == ON_DOWN) { - startDrag(mHitPos, (int)ev.getX() - mItemX, (int)ev.getY() - mItemY); - } - - return true; - } - - /** - * {@inheritDoc} - */ - @Override - public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) { - if (mHitPos != MISS && mDragInitMode == ON_DRAG && !mDragging) { - final int x1 = (int)e1.getX(); - final int y1 = (int)e1.getY(); - final int x2 = (int)e2.getX(); - final int y2 = (int)e2.getY(); - - boolean start = false; - if (mRemoveEnabled && mSortEnabled) { - start = true; - } else if (mRemoveEnabled) { - start = Math.abs(x2 - x1) > mTouchSlop; - } else if (mSortEnabled) { - start = Math.abs(y2 - y1) > mTouchSlop; - } - - if (start) { - startDrag(mHitPos, x2 - mItemX, y2 - mItemY); - } - } - return false; - } - - /** - * {@inheritDoc} - */ - @Override - public void onLongPress(MotionEvent e) { - if (mHitPos != MISS && mDragInitMode == ON_LONG_PRESS) { - mDslv.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS); - startDrag(mHitPos, mCurrX - mItemX, mCurrY - mItemY); - } - } - - /** - * {@inheritDoc} - */ - @Override - public final boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) { - return false; - } - - /** - * {@inheritDoc} - */ - @Override - public boolean onSingleTapUp(MotionEvent ev) { - return false; - } - - /** - * {@inheritDoc} - */ - @Override - public void onShowPress(MotionEvent ev) { - } - - private final GestureDetector.OnGestureListener mFlingRemoveListener = new GestureDetector.SimpleOnGestureListener() { - - /** - * {@inheritDoc} - */ - @Override - public final boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, - float velocityY) { - if (mRemoveEnabled) { - switch (mRemoveMode) { - case FLING_RIGHT_REMOVE: - if (velocityX > mFlingSpeed) { - mDslv.stopDrag(true); - } - break; - case FLING_LEFT_REMOVE: - if (velocityX < -mFlingSpeed) { - mDslv.stopDrag(true); - } - break; - } - } - return false; - } - }; - -} diff --git a/src/org/lineageos/eleven/dragdrop/DragSortListView.java b/src/org/lineageos/eleven/dragdrop/DragSortListView.java deleted file mode 100644 index 36476434529ad36801892b7166d5bde79ff8e27e..0000000000000000000000000000000000000000 --- a/src/org/lineageos/eleven/dragdrop/DragSortListView.java +++ /dev/null @@ -1,2123 +0,0 @@ -/* - * DragSortListView. A subclass of the Android ListView component that enables - * drag and drop re-ordering of list items. Copyright 2012 Carl Bauer Licensed - * under the Apache License, Version 2.0 (the "License"); you may not use this - * file except in compliance with the License. You may obtain a copy of the - * License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by - * applicable law or agreed to in writing, software distributed under the - * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS - * OF ANY KIND, either express or implied. See the License for the specific - * language governing permissions and limitations under the License. - */ - -package org.lineageos.eleven.dragdrop; - -import android.content.Context; -import android.database.DataSetObserver; -import android.graphics.Canvas; -import android.graphics.Point; -import android.graphics.drawable.Drawable; -import android.os.SystemClock; -import android.util.AttributeSet; -import android.view.Gravity; -import android.view.MotionEvent; -import android.view.View; -import android.view.ViewGroup; -import android.widget.AbsListView; -import android.widget.BaseAdapter; -import android.widget.HeaderViewListAdapter; -import android.widget.ListAdapter; -import android.widget.ListView; -import android.widget.RelativeLayout; - -import org.lineageos.eleven.R; - -import java.io.File; -import java.io.FileWriter; -import java.io.IOException; - -/** - * ListView subclass that mediates drag and drop resorting of items. - * - * @author heycosmo - */ -public class DragSortListView extends ListView { - - /** - * The View that floats above the ListView and represents the dragged item. - */ - private View mFloatView; - - /** - * A proposed float View location based on touch location and given deltaX - * and deltaY. - */ - private final Point mFloatLoc = new Point(); - - /** - * The middle (in the y-direction) of the floating View. - */ - private int mFloatViewMid; - - /** - * Left edge of floating View. - */ - private int mFloatViewLeft; - - /** - * Top edge of floating View. - */ - private int mFloatViewTop; - - /** - * Watch the Adapter for data changes. Cancel a drag if coincident with a - * change. - */ - private final DataSetObserver mObserver; - - /** - * Transparency for the floating View (XML attribute). - */ - private final float mFloatAlpha = 1.0f; - - private float mCurrFloatAlpha = 1.0f; - - /** - * While drag-sorting, the current position of the floating View. If - * dropped, the dragged item will land in this position. - */ - private int mFloatPos; - - /** - * The amount to scroll during the next layout pass. Used only for - * drag-scrolling, not standard ListView scrolling. - */ - private int mScrollY = 0; - - /** - * The first expanded ListView position that helps represent the drop slot - * tracking the floating View. - */ - private int mFirstExpPos; - - /** - * The second expanded ListView position that helps represent the drop slot - * tracking the floating View. This can equal mFirstExpPos if there is no - * slide shuffle occurring; otherwise it is equal to mFirstExpPos + 1. - */ - private int mSecondExpPos; - - /** - * Flag set if slide shuffling is enabled. - */ - private boolean mAnimate = false; - - /** - * The user dragged from this position. - */ - private int mSrcPos; - - /** - * Offset (in x) within the dragged item at which the user picked it up (or - * first touched down with the digitalis). - */ - private int mDragDeltaX; - - /** - * Offset (in y) within the dragged item at which the user picked it up (or - * first touched down with the digitalis). - */ - private int mDragDeltaY; - - /** - * A listener that receives callbacks whenever the floating View hovers over - * a new position. - */ - private DragListener mDragListener; - - /** - * A listener that receives a callback when the floating View is dropped. - */ - private DropListener mDropListener; - - /** - * A listener that receives a callback when the floating View (or more - * precisely the originally dragged item) is removed by one of the provided - * gestures. - */ - private RemoveListener mRemoveListener; - - /** - * Enable/Disable item dragging - */ - private boolean mDragEnabled = true; - - /** - * Drag state enum. - */ - private final static int IDLE = 0; - - private final static int STOPPED = 1; - - private final static int DRAGGING = 2; - - private int mDragState = IDLE; - - /** - * Height in pixels to which the originally dragged item is collapsed during - * a drag-sort. Currently, this value must be greater than zero. - */ - private int mItemHeightCollapsed = 1; - - /** - * Height of the floating View. Stored for the purpose of providing the - * tracking drop slot. - */ - private int mFloatViewHeight; - - /** - * Convenience member. See above. - */ - private int mFloatViewHeightHalf; - - /** - * Save the given width spec for use in measuring children - */ - private int mWidthMeasureSpec = 0; - - /** - * Sample Views ultimately used for calculating the height of ListView items - * that are off-screen. - */ - private View[] mSampleViewTypes = new View[1]; - - /** - * Drag-scroll encapsulator! - */ - private final DragScroller mDragScroller; - - /** - * Determines the start of the upward drag-scroll region at the top of the - * ListView. Specified by a fraction of the ListView height, thus screen - * resolution agnostic. - */ - private float mDragUpScrollStartFrac = 1.0f / 3.0f; - - /** - * Determines the start of the downward drag-scroll region at the bottom of - * the ListView. Specified by a fraction of the ListView height, thus screen - * resolution agnostic. - */ - private float mDragDownScrollStartFrac = 1.0f / 3.0f; - - /** - * The following are calculated from the above fracs. - */ - private int mUpScrollStartY; - - private int mDownScrollStartY; - - private float mDownScrollStartYF; - - private float mUpScrollStartYF; - - /** - * Calculated from above above and current ListView height. - */ - private float mDragUpScrollHeight; - - /** - * Calculated from above above and current ListView height. - */ - private float mDragDownScrollHeight; - - /** - * Maximum drag-scroll speed in pixels per ms. Only used with default linear - * drag-scroll profile. - */ - private float mMaxScrollSpeed = 0.3f; - - /** - * Defines the scroll speed during a drag-scroll. User can provide their - * own; this default is a simple linear profile where scroll speed increases - * linearly as the floating View nears the top/bottom of the ListView. - */ - private DragScrollProfile mScrollProfile = new DragScrollProfile() { - - /** - * {@inheritDoc} - */ - @Override - public float getSpeed(final float w, final long t) { - return mMaxScrollSpeed * w; - } - }; - - /** - * Current touch x. - */ - private int mX; - - /** - * Current touch y. - */ - private int mY; - - /** - * Last touch y. - */ - private int mLastY; - - /** - * Drag flag bit. Floating View can move in the positive x direction. - */ - public final static int DRAG_POS_X = 0x1; - - /** - * Drag flag bit. Floating View can move in the negative x direction. - */ - public final static int DRAG_NEG_X = 0x2; - - /** - * Drag flag bit. Floating View can move in the positive y direction. This - * is subtle. What this actually means is that, if enabled, the floating - * View can be dragged below its starting position. Remove in favor of - * upper-bounding item position? - */ - public final static int DRAG_POS_Y = 0x4; - - /** - * Drag flag bit. Floating View can move in the negative y direction. This - * is subtle. What this actually means is that the floating View can be - * dragged above its starting position. Remove in favor of lower-bounding - * item position? - */ - public final static int DRAG_NEG_Y = 0x8; - - /** - * Flags that determine limits on the motion of the floating View. See flags - * above. - */ - private int mDragFlags = 0; - - /** - * Last call to an on*TouchEvent was a call to onInterceptTouchEvent. - */ - private boolean mLastCallWasIntercept = false; - - /** - * A touch event is in progress. - */ - private boolean mInTouchEvent = false; - - /** - * Let the user customize the floating View. - */ - private FloatViewManager mFloatViewManager = null; - - /** - * Given to ListView to cancel its action when a drag-sort begins. - */ - private final MotionEvent mCancelEvent; - - /** - * Enum telling where to cancel the ListView action when a drag-sort begins - */ - private static final int NO_CANCEL = 0; - - private static final int ON_TOUCH_EVENT = 1; - - private static final int ON_INTERCEPT_TOUCH_EVENT = 2; - - /** - * Where to cancel the ListView action when a drag-sort begins - */ - private int mCancelMethod = NO_CANCEL; - - /** - * Determines when a slide shuffle animation starts. That is, defines how - * close to the edge of the drop slot the floating View must be to initiate - * the slide. - */ - private float mSlideRegionFrac = 0.25f; - - /** - * Number between 0 and 1 indicating the relative location of a sliding item - * (only used if drag-sort animations are turned on). Nearly 1 means the - * item is at the top of the slide region (nearly full blank item is - * directly below). - */ - private float mSlideFrac = 0.0f; - - /** - * Wraps the user-provided ListAdapter. This is used to wrap each item View - * given by the user inside another View (currenly a RelativeLayout) which - * expands and collapses to simulate the item shuffling. - */ - private AdapterWrapper mAdapterWrapper; - - /** - * Turn on custom debugger. - */ - private final boolean mTrackDragSort = false; - - /** - * Debugging class. - */ - private DragSortTracker mDragSortTracker; - - /** - * Needed for adjusting item heights from within layoutChildren - */ - private boolean mBlockLayoutRequests = false; - - private final DragSortController mController; - - /** - * @param context The {@link Context} to use - * @param attrs The attributes of the XML tag that is inflating the view. - */ - public DragSortListView(final Context context, final AttributeSet attrs) { - super(context, attrs); - mItemHeightCollapsed = 1; - - mCurrFloatAlpha = mFloatAlpha; - - mSlideRegionFrac = 0.75f; - - mAnimate = mSlideRegionFrac > 0.0f; - - setDragScrollStart(mDragUpScrollStartFrac); - - mController = new DragSortController(this, R.id.edit_track_list_item_handle, - DragSortController.ON_DOWN, DragSortController.FLING_RIGHT_REMOVE); - mController.setRemoveEnabled(true); - mController.setSortEnabled(true); - mController - .setBackgroundColor(getResources().getColor(R.color.accent)); - - mFloatViewManager = mController; - setOnTouchListener(mController); - - mDragScroller = new DragScroller(); - setOnScrollListener(mDragScroller); - - mCancelEvent = MotionEvent.obtain(0, 0, MotionEvent.ACTION_CANCEL, 0f, 0f, 0f, 0f, 0, 0f, - 0f, 0, 0); - - mObserver = new DataSetObserver() { - private void cancel() { - if (mDragState == DRAGGING) { - stopDrag(false); - } - } - - /** - * {@inheritDoc} - */ - @Override - public void onChanged() { - cancel(); - } - - /** - * {@inheritDoc} - */ - @Override - public void onInvalidated() { - cancel(); - } - }; - } - - /** - * Usually called from a FloatViewManager. The float alpha will be reset to - * the xml-defined value every time a drag is stopped. - */ - public void setFloatAlpha(final float alpha) { - mCurrFloatAlpha = alpha; - } - - public float getFloatAlpha() { - return mCurrFloatAlpha; - } - - /** - * Set maximum drag scroll speed in positions/second. Only applies if using - * default ScrollSpeedProfile. - * - * @param max Maximum scroll speed. - */ - public void setMaxScrollSpeed(final float max) { - mMaxScrollSpeed = max; - } - - /** - * {@inheritDoc} - */ - @Override - public void setAdapter(final ListAdapter adapter) { - mAdapterWrapper = new AdapterWrapper(adapter); - adapter.registerDataSetObserver(mObserver); - super.setAdapter(mAdapterWrapper); - } - - /** - * As opposed to {@link ListView#getAdapter()}, which returns a heavily - * wrapped ListAdapter (DragSortListView wraps the input ListAdapter {\emph - * and} ListView wraps the wrapped one). - * - * @return The ListAdapter set as the argument of {@link setAdapter()} - */ - public ListAdapter getInputAdapter() { - if (mAdapterWrapper == null) { - return null; - } else { - return mAdapterWrapper.getAdapter(); - } - } - - private class AdapterWrapper extends HeaderViewListAdapter { - private final ListAdapter mAdapter; - - public AdapterWrapper(final ListAdapter adapter) { - super(null, null, adapter); - mAdapter = adapter; - } - - public ListAdapter getAdapter() { - return mAdapter; - } - - /** - * {@inheritDoc} - */ - @Override - public View getView(final int position, final View convertView, final ViewGroup parent) { - - RelativeLayout v; - View child; - if (convertView != null) { - - v = (RelativeLayout)convertView; - final View oldChild = v.getChildAt(0); - try { - child = mAdapter.getView(position, oldChild, v); - if (child != oldChild) { - v.removeViewAt(0); - v.addView(child); - } - } catch (final Exception nullz) { - - } - } else { - final AbsListView.LayoutParams params = new AbsListView.LayoutParams( - ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT); - v = new RelativeLayout(getContext()); - v.setLayoutParams(params); - try { - child = mAdapter.getView(position, null, v); - v.addView(child); - } catch (final Exception todo) { - - } - } - adjustItem(position + getHeaderViewsCount(), v, true); - return v; - } - } - - private void drawDivider(final int expPosition, final Canvas canvas) { - - final Drawable divider = getDivider(); - final int dividerHeight = getDividerHeight(); - - if (divider != null && dividerHeight != 0) { - final ViewGroup expItem = (ViewGroup)getChildAt(expPosition - getFirstVisiblePosition()); - if (expItem != null) { - final int l = getPaddingLeft(); - final int r = getWidth() - getPaddingRight(); - final int t; - final int b; - - final int childHeight = expItem.getChildAt(0).getHeight(); - - if (expPosition > mSrcPos) { - t = expItem.getTop() + childHeight; - b = t + dividerHeight; - } else { - b = expItem.getBottom() - childHeight; - t = b - dividerHeight; - } - - divider.setBounds(l, t, r, b); - divider.draw(canvas); - } - } - } - - /** - * {@inheritDoc} - */ - @Override - protected void dispatchDraw(final Canvas canvas) { - super.dispatchDraw(canvas); - - if (mFloatView != null) { - if (mFirstExpPos != mSrcPos) { - drawDivider(mFirstExpPos, canvas); - } - if (mSecondExpPos != mFirstExpPos && mSecondExpPos != mSrcPos) { - drawDivider(mSecondExpPos, canvas); - } - - final int w = mFloatView.getWidth(); - final int h = mFloatView.getHeight(); - final int alpha = (int)(255f * mCurrFloatAlpha); - - canvas.save(); - canvas.translate(mFloatViewLeft, mFloatViewTop); - canvas.clipRect(0, 0, w, h); - - canvas.saveLayerAlpha(0, 0, w, h, alpha, Canvas.ALL_SAVE_FLAG); - mFloatView.draw(canvas); - canvas.restore(); - canvas.restore(); - } - } - - private class ItemHeights { - int item; - - int child; - } - - private void measureItemAndGetHeights(final int position, final View item, - final ItemHeights heights) { - ViewGroup.LayoutParams lp = item.getLayoutParams(); - - final boolean isHeadFoot = position < getHeaderViewsCount() - || position >= getCount() - getFooterViewsCount(); - - int height = lp == null ? 0 : lp.height; - if (height > 0) { - heights.item = height; - - // get height of child, measure if we have to - if (isHeadFoot) { - heights.child = heights.item; - } else if (position == mSrcPos) { - heights.child = 0; - } else { - final View child = ((ViewGroup)item).getChildAt(0); - lp = child.getLayoutParams(); - height = lp == null ? 0 : lp.height; - if (height > 0) { - heights.child = height; - } else { - final int hspec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED); - final int wspec = ViewGroup.getChildMeasureSpec(mWidthMeasureSpec, - getListPaddingLeft() + getListPaddingRight(), lp.width); - child.measure(wspec, hspec); - heights.child = child.getMeasuredHeight(); - } - } - } else { - final int hspec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED); - final int wspec = ViewGroup.getChildMeasureSpec(mWidthMeasureSpec, getListPaddingLeft() - + getListPaddingRight(), lp == null ? ViewGroup.LayoutParams.MATCH_PARENT - : lp.width); - item.measure(wspec, hspec); - - heights.item = item.getMeasuredHeight(); - if (isHeadFoot) { - heights.child = heights.item; - } else if (position == mSrcPos) { - heights.child = 0; - } else { - heights.child = ((ViewGroup)item).getChildAt(0).getMeasuredHeight(); - } - } - } - - /** - * Get the height of the given wrapped item and its child. - * - * @param position Position from which item was obtained. - * @param item List item (usually obtained from - * {@link ListView#getChildAt()}). - * @param heights Object to fill with heights of item. - */ - private void getItemHeights(final int position, final View item, final ItemHeights heights) { - final boolean isHeadFoot = position < getHeaderViewsCount() - || position >= getCount() - getFooterViewsCount(); - - heights.item = item.getHeight(); - - if (isHeadFoot) { - heights.child = heights.item; - } else if (position == mSrcPos) { - heights.child = 0; - } else { - heights.child = ((ViewGroup)item).getChildAt(0).getHeight(); - } - } - - /** - * This function works for arbitrary positions (could be off-screen). If - * requested position is off-screen, this function calls - * getView to get height information. - * - * @param position ListView position. - * @param heights Object to fill with heights of item at - * position. - */ - private void getItemHeights(final int position, final ItemHeights heights) { - - final int first = getFirstVisiblePosition(); - final int last = getLastVisiblePosition(); - - if (position >= first && position <= last) { - getItemHeights(position, getChildAt(position - first), heights); - } else { - // Log.d("mobeta", "getView for height"); - - final ListAdapter adapter = getAdapter(); - final int type = adapter.getItemViewType(position); - - // There might be a better place for checking for the following - final int typeCount = adapter.getViewTypeCount(); - if (typeCount != mSampleViewTypes.length) { - mSampleViewTypes = new View[typeCount]; - } - - View v; - if (type >= 0) { - if (mSampleViewTypes[type] == null) { - v = adapter.getView(position, null, this); - mSampleViewTypes[type] = v; - } else { - v = adapter.getView(position, mSampleViewTypes[type], this); - } - } else { - // type is HEADER_OR_FOOTER or IGNORE - v = adapter.getView(position, null, this); - } - - measureItemAndGetHeights(position, v, heights); - } - - } - - private int getShuffleEdge(final int position, final int top) { - return getShuffleEdge(position, top, null); - } - - /** - * Get the shuffle edge for item at position when top of item is at y-coord - * top - * - * @param position - * @param top - * @param height Height of item at position. If -1, this function calculates - * this height. - * @return Shuffle line between position-1 and position (for the given view - * of the list; that is, for when top of item at position has - * y-coord of given `top`). If floating View (treated as horizontal - * line) is dropped immediately above this line, it lands in - * position-1. If dropped immediately below this line, it lands in - * position. - */ - private int getShuffleEdge(final int position, final int top, ItemHeights heights) { - - final int numHeaders = getHeaderViewsCount(); - final int numFooters = getFooterViewsCount(); - - // shuffle edges are defined between items that can be - // dragged; there are N-1 of them if there are N draggable - // items. - - if (position <= numHeaders || position >= getCount() - numFooters) { - return top; - } - - final int divHeight = getDividerHeight(); - - int edge; - - final int maxBlankHeight = mFloatViewHeight - mItemHeightCollapsed; - - if (heights == null) { - heights = new ItemHeights(); - getItemHeights(position, heights); - } - - // first calculate top of item given that floating View is - // centered over src position - int otop = top; - if (mSecondExpPos <= mSrcPos) { - // items are expanded on and/or above the source position - - if (position == mSecondExpPos && mFirstExpPos != mSecondExpPos) { - if (position == mSrcPos) { - otop = top + heights.item - mFloatViewHeight; - } else { - final int blankHeight = heights.item - heights.child; - otop = top + blankHeight - maxBlankHeight; - } - } else if (position > mSecondExpPos && position <= mSrcPos) { - otop = top - maxBlankHeight; - } - - } else { - // items are expanded on and/or below the source position - - if (position > mSrcPos && position <= mFirstExpPos) { - otop = top + maxBlankHeight; - } else if (position == mSecondExpPos && mFirstExpPos != mSecondExpPos) { - final int blankHeight = heights.item - heights.child; - otop = top + blankHeight; - } - } - - // otop is set - if (position <= mSrcPos) { - final ItemHeights tmpHeights = new ItemHeights(); - getItemHeights(position - 1, tmpHeights); - edge = otop + (mFloatViewHeight - divHeight - tmpHeights.child) / 2; - } else { - edge = otop + (heights.child - divHeight - mFloatViewHeight) / 2; - } - - return edge; - } - - private boolean updatePositions() { - - final int first = getFirstVisiblePosition(); - int startPos = mFirstExpPos; - View startView = getChildAt(startPos - first); - - if (startView == null) { - startPos = first + getChildCount() / 2; - startView = getChildAt(startPos - first); - } - final int startTop = startView.getTop() + mScrollY; - - final ItemHeights itemHeights = new ItemHeights(); - getItemHeights(startPos, startView, itemHeights); - - int edge = getShuffleEdge(startPos, startTop, itemHeights); - int lastEdge = edge; - - final int divHeight = getDividerHeight(); - - // Log.d("mobeta", "float mid="+mFloatViewMid); - - int itemPos = startPos; - int itemTop = startTop; - if (mFloatViewMid < edge) { - // scanning up for float position - // Log.d("mobeta", " edge="+edge); - while (itemPos >= 0) { - itemPos--; - getItemHeights(itemPos, itemHeights); - - // if (itemPos <= 0) - if (itemPos == 0) { - edge = itemTop - divHeight - itemHeights.item; - // itemPos = 0; - break; - } - - itemTop -= itemHeights.item + divHeight; - edge = getShuffleEdge(itemPos, itemTop, itemHeights); - // Log.d("mobeta", " edge="+edge); - - if (mFloatViewMid >= edge) { - break; - } - - lastEdge = edge; - } - } else { - // scanning down for float position - // Log.d("mobeta", " edge="+edge); - final int count = getCount(); - while (itemPos < count) { - if (itemPos == count - 1) { - edge = itemTop + divHeight + itemHeights.item; - break; - } - - itemTop += divHeight + itemHeights.item; - getItemHeights(itemPos + 1, itemHeights); - edge = getShuffleEdge(itemPos + 1, itemTop, itemHeights); - // Log.d("mobeta", " edge="+edge); - - // test for hit - if (mFloatViewMid < edge) { - break; - } - - lastEdge = edge; - itemPos++; - } - } - - final int numHeaders = getHeaderViewsCount(); - final int numFooters = getFooterViewsCount(); - - boolean updated = false; - - final int oldFirstExpPos = mFirstExpPos; - final int oldSecondExpPos = mSecondExpPos; - final float oldSlideFrac = mSlideFrac; - - if (mAnimate) { - final int edgeToEdge = Math.abs(edge - lastEdge); - - int edgeTop, edgeBottom; - if (mFloatViewMid < edge) { - edgeBottom = edge; - edgeTop = lastEdge; - } else { - edgeTop = edge; - edgeBottom = lastEdge; - } - // Log.d("mobeta", "edgeTop="+edgeTop+" edgeBot="+edgeBottom); - - final int slideRgnHeight = (int)(0.5f * mSlideRegionFrac * edgeToEdge); - final int slideEdgeTop = edgeTop + slideRgnHeight; - final int slideEdgeBottom = edgeBottom - slideRgnHeight; - - // Three regions - if (mFloatViewMid < slideEdgeTop) { - mFirstExpPos = itemPos - 1; - mSecondExpPos = itemPos; - mSlideFrac = 0.5f * (slideEdgeTop - mFloatViewMid) / (float) slideRgnHeight; - // Log.d("mobeta", - // "firstExp="+mFirstExpPos+" secExp="+mSecondExpPos+" slideFrac="+mSlideFrac); - } else if (mFloatViewMid < slideEdgeBottom) { - mFirstExpPos = itemPos; - mSecondExpPos = itemPos; - } else { - mFirstExpPos = itemPos; - mSecondExpPos = itemPos + 1; - mSlideFrac = 0.5f * (1.0f + (edgeBottom - mFloatViewMid) / (float) slideRgnHeight); - // Log.d("mobeta", - // "firstExp="+mFirstExpPos+" secExp="+mSecondExpPos+" slideFrac="+mSlideFrac); - } - - } else { - mFirstExpPos = itemPos; - mSecondExpPos = itemPos; - } - - // correct for headers and footers - if (mFirstExpPos < numHeaders) { - itemPos = numHeaders; - mFirstExpPos = itemPos; - mSecondExpPos = itemPos; - } else if (mSecondExpPos >= getCount() - numFooters) { - itemPos = getCount() - numFooters - 1; - mFirstExpPos = itemPos; - mSecondExpPos = itemPos; - } - - if (mFirstExpPos != oldFirstExpPos || mSecondExpPos != oldSecondExpPos - || mSlideFrac != oldSlideFrac) { - updated = true; - } - - if (itemPos != mFloatPos) { - if (mDragListener != null) { - mDragListener.drag(mFloatPos - numHeaders, itemPos - numHeaders); - } - - mFloatPos = itemPos; - updated = true; - } - - return updated; - } - - /** - * {@inheritDoc} - */ - @Override - protected void onDraw(final Canvas canvas) { - super.onDraw(canvas); - - if (mTrackDragSort) { - mDragSortTracker.appendState(); - } - } - - /** - * Stop a drag in progress. Pass true if you would like to - * remove the dragged item from the list. - * - * @param remove Remove the dragged item from the list. Calls a registered - * DropListener, if one exists. - * @return True if the stop was successful. - */ - public boolean stopDrag(final boolean remove) { - if (mFloatView != null) { - mDragState = STOPPED; - - // stop the drag - dropFloatView(remove); - - return true; - } else { - // stop failed - return false; - } - } - - /** - * {@inheritDoc} - */ - @Override - public boolean onTouchEvent(final MotionEvent ev) { - - if (!mDragEnabled) { - return super.onTouchEvent(ev); - } - - boolean more = false; - - final boolean lastCallWasIntercept = mLastCallWasIntercept; - mLastCallWasIntercept = false; - - if (!lastCallWasIntercept) { - saveTouchCoords(ev); - } - - if (mFloatView != null) { - onDragTouchEvent(ev); - more = true; // give us more! - } else { - // what if float view is null b/c we dropped in middle - // of drag touch event? - - if (mDragState != STOPPED) { - if (super.onTouchEvent(ev)) { - more = true; - } - } - - final int action = ev.getAction() & MotionEvent.ACTION_MASK; - switch (action) { - case MotionEvent.ACTION_CANCEL: - case MotionEvent.ACTION_UP: - doActionUpOrCancel(); - break; - default: - if (more) { - mCancelMethod = ON_TOUCH_EVENT; - } - } - } - - return more; - - } - - private void doActionUpOrCancel() { - mCancelMethod = NO_CANCEL; - mInTouchEvent = false; - mDragState = IDLE; - mCurrFloatAlpha = mFloatAlpha; - } - - private void saveTouchCoords(final MotionEvent ev) { - final int action = ev.getAction() & MotionEvent.ACTION_MASK; - if (action != MotionEvent.ACTION_DOWN) { - mLastY = mY; - } - mX = (int)ev.getX(); - mY = (int)ev.getY(); - if (action == MotionEvent.ACTION_DOWN) { - mLastY = mY; - } - } - - /** - * {@inheritDoc} - */ - @Override - public boolean onInterceptTouchEvent(final MotionEvent ev) { - if (!mDragEnabled) { - return super.onInterceptTouchEvent(ev); - } - - saveTouchCoords(ev); - mLastCallWasIntercept = true; - - boolean intercept = false; - - final int action = ev.getAction() & MotionEvent.ACTION_MASK; - - if (action == MotionEvent.ACTION_DOWN) { - mInTouchEvent = true; - } - - // the following deals with calls to super.onInterceptTouchEvent - if (mFloatView != null) { - // super's touch event canceled in startDrag - intercept = true; - } else { - if (super.onInterceptTouchEvent(ev)) { - intercept = true; - } - - switch (action) { - case MotionEvent.ACTION_CANCEL: - case MotionEvent.ACTION_UP: - doActionUpOrCancel(); - break; - default: - if (intercept) { - mCancelMethod = ON_TOUCH_EVENT; - } else { - mCancelMethod = ON_INTERCEPT_TOUCH_EVENT; - } - } - } - - // check for startDragging - - if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL) { - mInTouchEvent = false; - } - - return intercept; - } - - /** - * Set the width of each drag scroll region by specifying a fraction of the - * ListView height. - * - * @param heightFraction Fraction of ListView height. Capped at 0.5f. - */ - public void setDragScrollStart(final float heightFraction) { - setDragScrollStarts(heightFraction, heightFraction); - } - - /** - * Set the width of each drag scroll region by specifying a fraction of the - * ListView height. - * - * @param upperFrac Fraction of ListView height for up-scroll bound. Capped - * at 0.5f. - * @param lowerFrac Fraction of ListView height for down-scroll bound. - * Capped at 0.5f. - */ - public void setDragScrollStarts(final float upperFrac, final float lowerFrac) { - if (lowerFrac > 0.5f) { - mDragDownScrollStartFrac = 0.5f; - } else { - mDragDownScrollStartFrac = lowerFrac; - } - - if (upperFrac > 0.5f) { - mDragUpScrollStartFrac = 0.5f; - } else { - mDragUpScrollStartFrac = upperFrac; - } - - if (getHeight() != 0) { - updateScrollStarts(); - } - } - - private void continueDrag(final int x, final int y) { - - // Log.d("mobeta", "move"); - dragView(x, y); - - // if (mTrackDragSort) { - // mDragSortTracker.appendState(); - // } - - requestLayout(); - - final int minY = Math.min(y, mFloatViewMid + mFloatViewHeightHalf); - final int maxY = Math.max(y, mFloatViewMid - mFloatViewHeightHalf); - - // get the current scroll direction - final int currentScrollDir = mDragScroller.getScrollDir(); - - if (minY > mLastY && minY > mDownScrollStartY && currentScrollDir != DragScroller.DOWN) { - // dragged down, it is below the down scroll start and it is not - // scrolling up - - if (currentScrollDir != DragScroller.STOP) { - // moved directly from up scroll to down scroll - mDragScroller.stopScrolling(true); - } - - // start scrolling down - mDragScroller.startScrolling(DragScroller.DOWN); - } else if (maxY < mLastY && maxY < mUpScrollStartY && currentScrollDir != DragScroller.UP) { - // dragged up, it is above the up scroll start and it is not - // scrolling up - - if (currentScrollDir != DragScroller.STOP) { - // moved directly from down scroll to up scroll - mDragScroller.stopScrolling(true); - } - - // start scrolling up - mDragScroller.startScrolling(DragScroller.UP); - } else if (maxY >= mUpScrollStartY && minY <= mDownScrollStartY - && mDragScroller.isScrolling()) { - // not in the upper nor in the lower drag-scroll regions but it is - // still scrolling - - mDragScroller.stopScrolling(true); - } - } - - private void updateScrollStarts() { - final int padTop = getPaddingTop(); - final int listHeight = getHeight() - padTop - getPaddingBottom(); - - mUpScrollStartYF = padTop + mDragUpScrollStartFrac * (float) listHeight; - mDownScrollStartYF = padTop + (1.0f - mDragDownScrollStartFrac) * (float) listHeight; - - mUpScrollStartY = (int)mUpScrollStartYF; - mDownScrollStartY = (int)mDownScrollStartYF; - - mDragUpScrollHeight = mUpScrollStartYF - padTop; - mDragDownScrollHeight = padTop + listHeight - mDownScrollStartYF; - } - - /** - * {@inheritDoc} - */ - @Override - protected void onSizeChanged(final int w, final int h, final int oldw, final int oldh) { - super.onSizeChanged(w, h, oldw, oldh); - updateScrollStarts(); - } - - private void dropFloatView(final boolean removeSrcItem) { - - mDragScroller.stopScrolling(true); - - if (removeSrcItem) { - if (mRemoveListener != null) { - mRemoveListener.remove(mSrcPos - getHeaderViewsCount()); - } - } else { - if (mDropListener != null && mFloatPos >= 0 && mFloatPos < getCount()) { - final int numHeaders = getHeaderViewsCount(); - mDropListener.drop(mSrcPos - numHeaders, mFloatPos - numHeaders); - } - - // adjustAllItems(); - - final int firstPos = getFirstVisiblePosition(); - if (mSrcPos < firstPos) { - // collapsed src item is off screen; - // adjust the scroll after item heights have been fixed - final View v = getChildAt(0); - int top = 0; - if (v != null) { - top = v.getTop(); - } - // Log.d("mobeta", "top="+top+" fvh="+mFloatViewHeight); - setSelectionFromTop(firstPos - 1, top - getPaddingTop()); - } - } - - mSrcPos = -1; - mFirstExpPos = -1; - mSecondExpPos = -1; - mFloatPos = -1; - - removeFloatView(); - - if (mTrackDragSort) { - mDragSortTracker.stopTracking(); - } - } - - private void adjustAllItems() { - final int first = getFirstVisiblePosition(); - final int last = getLastVisiblePosition(); - - final int begin = Math.max(0, getHeaderViewsCount() - first); - final int end = Math.min(last - first, getCount() - 1 - getFooterViewsCount() - first); - - for (int i = begin; i <= end; ++i) { - final View v = getChildAt(i); - if (v != null) { - adjustItem(first + i, v, false); - } - } - } - - private void adjustItem(final int position, final View v, final boolean needsMeasure) { - - final ViewGroup.LayoutParams lp = v.getLayoutParams(); - final int oldHeight = lp.height; - int height = oldHeight; - - getDividerHeight(); - - final boolean isSliding = mAnimate && mFirstExpPos != mSecondExpPos; - final int maxNonSrcBlankHeight = mFloatViewHeight - mItemHeightCollapsed; - final int slideHeight = (int)(mSlideFrac * maxNonSrcBlankHeight); - - if (position == mSrcPos) { - if (mSrcPos == mFirstExpPos) { - if (isSliding) { - height = slideHeight + mItemHeightCollapsed; - } else { - height = mFloatViewHeight; - } - } else if (mSrcPos == mSecondExpPos) { - // if gets here, we know an item is sliding - height = mFloatViewHeight - slideHeight; - } else { - height = mItemHeightCollapsed; - } - } else if (position == mFirstExpPos || position == mSecondExpPos) { - // position is not src - - final ItemHeights itemHeights = new ItemHeights(); - if (needsMeasure) { - measureItemAndGetHeights(position, v, itemHeights); - } else { - getItemHeights(position, v, itemHeights); - } - - if (position == mFirstExpPos) { - if (isSliding) { - height = itemHeights.child + slideHeight; - } else { - height = itemHeights.child + maxNonSrcBlankHeight; - } - } else { // position=mSecondExpPos - // we know an item is sliding (b/c 2ndPos != 1stPos) - height = itemHeights.child + maxNonSrcBlankHeight - slideHeight; - } - } else { - height = ViewGroup.LayoutParams.WRAP_CONTENT; - } - - if (height != oldHeight) { - lp.height = height; - - v.setLayoutParams(lp); - } - - // Adjust item gravity - - if (position == mFirstExpPos || position == mSecondExpPos) { - if (position < mSrcPos) { - ((RelativeLayout)v).setGravity(Gravity.BOTTOM); - } else if (position > mSrcPos) { - ((RelativeLayout)v).setGravity(Gravity.TOP); - } - } - - // Finally adjust item visibility - - final int oldVis = v.getVisibility(); - int vis = View.VISIBLE; - - if (position == mSrcPos && mFloatView != null) { - vis = View.INVISIBLE; - } - - if (vis != oldVis) { - v.setVisibility(vis); - } - } - - /** - * {@inheritDoc} - */ - @Override - public void requestLayout() { - if (!mBlockLayoutRequests) { - super.requestLayout(); - } - } - - private void doDragScroll(final int oldFirstExpPos, final int oldSecondExpPos) { - if (mScrollY == 0) { - return; - } - - final int padTop = getPaddingTop(); - final int listHeight = getHeight() - padTop - getPaddingBottom(); - final int first = getFirstVisiblePosition(); - final int last = getLastVisiblePosition(); - - int movePos; - - if (mScrollY >= 0) { - mScrollY = Math.min(listHeight, mScrollY); - movePos = first; - } else { - mScrollY = Math.max(-listHeight, mScrollY); - movePos = last; - } - - final View moveItem = getChildAt(movePos - first); - int top = moveItem.getTop() + mScrollY; - - if (movePos == 0 && top > padTop) { - top = padTop; - } - - final ItemHeights itemHeightsBefore = new ItemHeights(); - getItemHeights(movePos, moveItem, itemHeightsBefore); - final int moveHeightBefore = itemHeightsBefore.item; - final int moveBlankBefore = moveHeightBefore - itemHeightsBefore.child; - - final ItemHeights itemHeightsAfter = new ItemHeights(); - measureItemAndGetHeights(movePos, moveItem, itemHeightsAfter); - final int moveHeightAfter = itemHeightsAfter.item; - final int moveBlankAfter = moveHeightAfter - itemHeightsAfter.child; - - if (movePos <= oldFirstExpPos) { - if (movePos > mFirstExpPos) { - top += mFloatViewHeight - moveBlankAfter; - } - } else if (movePos == oldSecondExpPos) { - if (movePos <= mFirstExpPos) { - top += moveBlankBefore - mFloatViewHeight; - } else if (movePos == mSecondExpPos) { - top += moveHeightBefore - moveHeightAfter; - } else { - top += moveBlankBefore; - } - } else { - if (movePos <= mFirstExpPos) { - top -= mFloatViewHeight; - } else if (movePos == mSecondExpPos) { - top -= moveBlankAfter; - } - } - - setSelectionFromTop(movePos, top - padTop); - - mScrollY = 0; - } - - private void measureFloatView() { - if (mFloatView != null) { - ViewGroup.LayoutParams lp = mFloatView.getLayoutParams(); - if (lp == null) { - lp = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, - ViewGroup.LayoutParams.WRAP_CONTENT); - } - final int wspec = ViewGroup.getChildMeasureSpec(mWidthMeasureSpec, getListPaddingLeft() - + getListPaddingRight(), lp.width); - int hspec; - if (lp.height > 0) { - hspec = MeasureSpec.makeMeasureSpec(lp.height, MeasureSpec.EXACTLY); - } else { - hspec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED); - } - mFloatView.measure(wspec, hspec); - mFloatViewHeight = mFloatView.getMeasuredHeight(); - mFloatViewHeightHalf = mFloatViewHeight / 2; - } - } - - /** - * {@inheritDoc} - */ - @Override - protected void onMeasure(final int widthMeasureSpec, final int heightMeasureSpec) { - super.onMeasure(widthMeasureSpec, heightMeasureSpec); - if (mFloatView != null) { - if (mFloatView.isLayoutRequested()) { - measureFloatView(); - } - } - mWidthMeasureSpec = widthMeasureSpec; - mDragScroller.setListHeight(getHeight()); - } - - /** - * {@inheritDoc} - */ - @Override - protected void layoutChildren() { - - if (mFloatView != null) { - mFloatView.layout(0, 0, mFloatView.getMeasuredWidth(), mFloatView.getMeasuredHeight()); - - // Log.d("mobeta", "layout children"); - final int oldFirstExpPos = mFirstExpPos; - final int oldSecondExpPos = mSecondExpPos; - - mBlockLayoutRequests = true; - - if (getChildCount() > 0 && updatePositions()) { - adjustAllItems(); - } - - if (mScrollY != 0) { - doDragScroll(oldFirstExpPos, oldSecondExpPos); - } - - mBlockLayoutRequests = false; - } - - super.layoutChildren(); - } - - protected boolean onDragTouchEvent(final MotionEvent ev) { - switch (ev.getAction() & MotionEvent.ACTION_MASK) { - case MotionEvent.ACTION_CANCEL: - case MotionEvent.ACTION_UP: - stopDrag(false); - doActionUpOrCancel(); - break; - case MotionEvent.ACTION_MOVE: - continueDrag((int)ev.getX(), (int)ev.getY()); - break; - } - - return true; - } - - /** - * Start a drag of item at position using the registered - * FloatViewManager. Calls through to - * {@link #startDrag(int,View,int,int,int)} after obtaining the floating - * View from the FloatViewManager. - * - * @param position Item to drag. - * @param dragFlags Flags that restrict some movements of the floating View. - * For example, set dragFlags |= - * ~{@link #DRAG_NEG_X} to allow dragging the floating View in all - * directions except off the screen to the left. - * @param deltaX Offset in x of the touch coordinate from the left edge of - * the floating View (i.e. touch-x minus float View left). - * @param deltaY Offset in y of the touch coordinate from the top edge of - * the floating View (i.e. touch-y minus float View top). - * @return True if the drag was started, false otherwise. This - * startDrag will fail if we are not currently in a - * touch event, there is no registered FloatViewManager, or the - * FloatViewManager returns a null View. - */ - public boolean startDrag(final int position, final int dragFlags, final int deltaX, - final int deltaY) { - if (!mInTouchEvent || mFloatViewManager == null) { - return false; - } - - final View v = mFloatViewManager.onCreateFloatView(position); - - if (v == null) { - return false; - } else { - return startDrag(position, v, dragFlags, deltaX, deltaY); - } - - } - - /** - * Start a drag of item at position without using a - * FloatViewManager. - * - * @param position Item to drag. - * @param floatView Floating View. - * @param dragFlags Flags that restrict some movements of the floating View. - * For example, set dragFlags |= - * ~{@link #DRAG_NEG_X} to allow dragging the floating View in all - * directions except off the screen to the left. - * @param deltaX Offset in x of the touch coordinate from the left edge of - * the floating View (i.e. touch-x minus float View left). - * @param deltaY Offset in y of the touch coordinate from the top edge of - * the floating View (i.e. touch-y minus float View top). - * @return True if the drag was started, false otherwise. This - * startDrag will fail if we are not currently in a - * touch event, floatView is null, or there is a drag - * in progress. - */ - public boolean startDrag(final int position, final View floatView, final int dragFlags, - final int deltaX, final int deltaY) { - if (!mInTouchEvent || mFloatView != null || floatView == null) { - return false; - } - - if (getParent() != null) { - getParent().requestDisallowInterceptTouchEvent(true); - } - - final int pos = position + getHeaderViewsCount(); - mFirstExpPos = pos; - mSecondExpPos = pos; - mSrcPos = pos; - mFloatPos = pos; - - // mDragState = dragType; - mDragState = DRAGGING; - mDragFlags = 0; - mDragFlags |= dragFlags; - - mFloatView = floatView; - measureFloatView(); // sets mFloatViewHeight - - mDragDeltaX = deltaX; - mDragDeltaY = deltaY; - updateFloatView(mX - mDragDeltaX, mY - mDragDeltaY); - - // set src item invisible - final View srcItem = getChildAt(mSrcPos - getFirstVisiblePosition()); - if (srcItem != null) { - srcItem.setVisibility(View.INVISIBLE); - } - - if (mTrackDragSort) { - mDragSortTracker.startTracking(); - } - - // once float view is created, events are no longer passed - // to ListView - switch (mCancelMethod) { - case ON_TOUCH_EVENT: - super.onTouchEvent(mCancelEvent); - break; - case ON_INTERCEPT_TOUCH_EVENT: - super.onInterceptTouchEvent(mCancelEvent); - break; - } - - requestLayout(); - - return true; - } - - /** - * Sets float View location based on suggested values and constraints set in - * mDragFlags. - */ - private void updateFloatView(final int floatX, final int floatY) { - - // restrict x motion - final int padLeft = getPaddingLeft(); - if ((mDragFlags & DRAG_POS_X) == 0 && floatX > padLeft) { - mFloatViewLeft = padLeft; - } else if ((mDragFlags & DRAG_NEG_X) == 0 && floatX < padLeft) { - mFloatViewLeft = padLeft; - } else { - mFloatViewLeft = floatX; - } - - // keep floating view from going past bottom of last header view - final int numHeaders = getHeaderViewsCount(); - final int numFooters = getFooterViewsCount(); - final int firstPos = getFirstVisiblePosition(); - final int lastPos = getLastVisiblePosition(); - - // Log.d("mobeta", - // "nHead="+numHeaders+" nFoot="+numFooters+" first="+firstPos+" last="+lastPos); - int topLimit = getPaddingTop(); - if (firstPos < numHeaders) { - topLimit = getChildAt(numHeaders - firstPos - 1).getBottom(); - } - if ((mDragFlags & DRAG_NEG_Y) == 0) { - if (firstPos <= mSrcPos) { - topLimit = Math.max(getChildAt(mSrcPos - firstPos).getTop(), topLimit); - } - } - // bottom limit is top of first footer View or - // bottom of last item in list - int bottomLimit = getHeight() - getPaddingBottom(); - if (lastPos >= getCount() - numFooters - 1) { - bottomLimit = getChildAt(getCount() - numFooters - 1 - firstPos).getBottom(); - } - if ((mDragFlags & DRAG_POS_Y) == 0) { - if (lastPos >= mSrcPos) { - bottomLimit = Math.min(getChildAt(mSrcPos - firstPos).getBottom(), bottomLimit); - } - } - - // Log.d("mobeta", "dragView top=" + (y - mDragDeltaY)); - // Log.d("mobeta", "limit=" + limit); - // Log.d("mobeta", "mDragDeltaY=" + mDragDeltaY); - - if (floatY < topLimit) { - mFloatViewTop = topLimit; - } else if (floatY + mFloatViewHeight > bottomLimit) { - mFloatViewTop = bottomLimit - mFloatViewHeight; - } else { - mFloatViewTop = floatY; - } - - // get y-midpoint of floating view (constrained to ListView bounds) - mFloatViewMid = mFloatViewTop + mFloatViewHeightHalf; - } - - private void dragView(final int x, final int y) { - // Log.d("mobeta", "float view pure x=" + x + " y=" + y); - - // proposed position - mFloatLoc.x = x - mDragDeltaX; - mFloatLoc.y = y - mDragDeltaY; - - final Point touch = new Point(x, y); - - // let manager adjust proposed position first - if (mFloatViewManager != null) { - mFloatViewManager.onDragFloatView(mFloatView, mFloatLoc, touch); - } - - // then we override if manager gives an unsatisfactory - // position (e.g. over a header/footer view). Also, - // dragFlags override manager adjustments. - updateFloatView(mFloatLoc.x, mFloatLoc.y); - } - - private void removeFloatView() { - if (mFloatView != null) { - mFloatView.setVisibility(GONE); - if (mFloatViewManager != null) { - mFloatViewManager.onDestroyFloatView(mFloatView); - } - mFloatView = null; - } - } - - /** - * Interface for customization of the floating View appearance and dragging - * behavior. Implement your own and pass it to {@link #setFloatViewManager}. - * If your own is not passed, the default {@link SimpleFloatViewManager} - * implementation is used. - */ - public interface FloatViewManager { - /** - * Return the floating View for item at position. - * DragSortListView will measure and layout this View for you, so feel - * free to just inflate it. You can help DSLV by setting some - * {@link ViewGroup.LayoutParams} on this View; otherwise it will set - * some for you (with a width of FILL_PARENT and a height of - * WRAP_CONTENT). - * - * @param position Position of item to drag (NOTE: position - * excludes header Views; thus, if you want to call - * {@link ListView#getChildAt(int)}, you will need to add - * {@link ListView#getHeaderViewsCount()} to the index). - * @return The View you wish to display as the floating View. - */ - public View onCreateFloatView(int position); - - /** - * Called whenever the floating View is dragged. Float View properties - * can be changed here. Also, the upcoming location of the float View - * can be altered by setting location.x and - * location.y. - * - * @param floatView The floating View. - * @param location The location (top-left; relative to DSLV top-left) at - * which the float View would like to appear, given the - * current touch location and the offset provided in - * {@link DragSortListView#startDrag}. - * @param touch The current touch location (relative to DSLV top-left). - */ - public void onDragFloatView(View floatView, Point location, Point touch); - - /** - * Called when the float View is dropped; lets you perform any necessary - * cleanup. The internal DSLV floating View reference is set to null - * immediately after this is called. - * - * @param floatView The floating View passed to - * {@link #onCreateFloatView(int)}. - */ - public void onDestroyFloatView(View floatView); - } - - public void setFloatViewManager(final FloatViewManager manager) { - mFloatViewManager = manager; - } - - public void setDragListener(final DragListener l) { - mDragListener = l; - } - - /** - * Allows for easy toggling between a DragSortListView and a regular old - * ListView. If enabled, items are draggable, where the drag init mode - * determines how items are lifted (see {@link setDragInitMode(int)}). If - * disabled, items cannot be dragged. - * - * @param enabled Set true to enable list item dragging - */ - public void setDragEnabled(final boolean enabled) { - mDragEnabled = enabled; - } - - public boolean isDragEnabled() { - return mDragEnabled; - } - - /** - * This better reorder your ListAdapter! DragSortListView does not do this - * for you; doesn't make sense to. Make sure - * {@link BaseAdapter#notifyDataSetChanged()} or something like it is called - * in your implementation. - * - * @param l - */ - public void setDropListener(final DropListener l) { - mDropListener = l; - } - - /** - * Probably a no-brainer, but make sure that your remove listener calls - * {@link BaseAdapter#notifyDataSetChanged()} or something like it. When an - * item removal occurs, DragSortListView relies on a redraw of all the items - * to recover invisible views and such. Strictly speaking, if you remove - * something, your dataset has changed... - * - * @param l - */ - public void setRemoveListener(final RemoveListener l) { - if (mController != null && l == null) { - mController.setRemoveEnabled(false); - } - mRemoveListener = l; - } - - public interface DragListener { - public void drag(int from, int to); - } - - /** - * Your implementation of this has to reorder your ListAdapter! Make sure to - * call {@link BaseAdapter#notifyDataSetChanged()} or something like it in - * your implementation. - * - * @author heycosmo - */ - public interface DropListener { - public void drop(int from, int to); - } - - /** - * Make sure to call {@link BaseAdapter#notifyDataSetChanged()} or something - * like it in your implementation. - * - * @author heycosmo - */ - public interface RemoveListener { - public void remove(int which); - } - - public interface DragSortListener extends DropListener, DragListener, RemoveListener { - } - - public void setDragSortListener(final DragSortListener l) { - setDropListener(l); - setDragListener(l); - setRemoveListener(l); - } - - /** - * Completely custom scroll speed profile. Default increases linearly with - * position and is constant in time. Create your own by implementing - * {@link DragSortListView.DragScrollProfile}. - * - * @param ssp - */ - public void setDragScrollProfile(final DragScrollProfile ssp) { - if (ssp != null) { - mScrollProfile = ssp; - } - } - - /** - * Interface for controlling scroll speed as a function of touch position - * and time. Use - * {@link DragSortListView#setDragScrollProfile(DragScrollProfile)} to set - * custom profile. - * - * @author heycosmo - */ - public interface DragScrollProfile { - /** - * Return a scroll speed in pixels/millisecond. Always return a positive - * number. - * - * @param w Normalized position in scroll region (i.e. w \in [0,1]). - * Small w typically means slow scrolling. - * @param t Time (in milliseconds) since start of scroll (handy if you - * want scroll acceleration). - * @return Scroll speed at position w and time t in pixels/ms. - */ - float getSpeed(float w, long t); - } - - private class DragScroller implements Runnable, AbsListView.OnScrollListener { - - private boolean mAbort; - - private long mPrevTime; - - private int dy; - - private float dt; - - private long tStart; - - private int scrollDir; - - public final static int STOP = -1; - - public final static int UP = 0; - - public final static int DOWN = 1; - - private float mScrollSpeed; // pixels per ms - - private boolean mScrolling = false; - - private int mMaxScrollSpeed; - - public boolean isScrolling() { - return mScrolling; - } - - public int getScrollDir() { - return mScrolling ? scrollDir : STOP; - } - - public DragScroller() { - } - - public void startScrolling(final int dir) { - if (!mScrolling) { - // Debug.startMethodTracing("dslv-scroll"); - mAbort = false; - mScrolling = true; - tStart = SystemClock.uptimeMillis(); - mPrevTime = tStart; - scrollDir = dir; - post(this); - } - } - - public void stopScrolling(final boolean now) { - if (now) { - removeCallbacks(this); - mScrolling = false; - } else { - mAbort = true; - } - - } - - public void setListHeight(final int height) { - // cap the max scroll speed per frame to be 1/5 of the list height - mMaxScrollSpeed = height / 5; - } - - /** - * {@inheritDoc} - */ - @Override - public void run() { - if (mAbort) { - mScrolling = false; - return; - } - - final int first = getFirstVisiblePosition(); - final int last = getLastVisiblePosition(); - final int count = getCount(); - final int padTop = getPaddingTop(); - final int listHeight = getHeight() - padTop - getPaddingBottom(); - - final int minY = Math.min(mY, mFloatViewMid + mFloatViewHeightHalf); - final int maxY = Math.max(mY, mFloatViewMid - mFloatViewHeightHalf); - - if (scrollDir == UP) { - final View v = getChildAt(0); - if (v == null) { - mScrolling = false; - return; - } else { - if (first == 0 && v.getTop() == padTop) { - mScrolling = false; - return; - } - } - mScrollSpeed = mScrollProfile.getSpeed((mUpScrollStartYF - maxY) - / mDragUpScrollHeight, mPrevTime); - } else { - final View v = getChildAt(last - first); - if (v == null) { - mScrolling = false; - return; - } else { - if (last == count - 1 && v.getBottom() <= listHeight + padTop) { - mScrolling = false; - return; - } - } - mScrollSpeed = -mScrollProfile.getSpeed((minY - mDownScrollStartYF) - / mDragDownScrollHeight, mPrevTime); - } - - dt = SystemClock.uptimeMillis() - mPrevTime; - // dy is change in View position of a list item; i.e. positive dy - // means user is scrolling up (list item moves down the screen, - // remember - // y=0 is at top of View). - dy = Math.round(mScrollSpeed * dt); - mScrollY += dy; - - // cap the scroll speed - mScrollY = Math.max(Math.min(mScrollY, mMaxScrollSpeed), -mMaxScrollSpeed); - - requestLayout(); - - mPrevTime += dt; - - post(this); - } - - /** - * {@inheritDoc} - */ - @Override - public void onScroll(final AbsListView view, final int firstVisibleItem, - final int visibleItemCount, final int totalItemCount) { - if (mScrolling && visibleItemCount != 0) { - dragView(mX, mY); - } - } - - /** - * {@inheritDoc} - */ - @Override - public void onScrollStateChanged(final AbsListView view, final int scrollState) { - } - - } - - private class DragSortTracker { - StringBuilder mBuilder = new StringBuilder(); - - File mFile; - - private int mNumInBuffer = 0; - - private int mNumFlushes = 0; - - private boolean mTracking = false; - - public void startTracking() { - mBuilder.append("\n"); - mNumFlushes = 0; - mTracking = true; - } - - public void appendState() { - if (!mTracking) { - return; - } - - mBuilder.append("\n"); - final int children = getChildCount(); - final int first = getFirstVisiblePosition(); - final ItemHeights itemHeights = new ItemHeights(); - mBuilder.append(" "); - for (int i = 0; i < children; ++i) { - mBuilder.append(first + i).append(","); - } - mBuilder.append("\n"); - - mBuilder.append(" "); - for (int i = 0; i < children; ++i) { - mBuilder.append(getChildAt(i).getTop()).append(","); - } - mBuilder.append("\n"); - mBuilder.append(" "); - for (int i = 0; i < children; ++i) { - mBuilder.append(getChildAt(i).getBottom()).append(","); - } - mBuilder.append("\n"); - - mBuilder.append(" ").append(mFirstExpPos).append("\n"); - getItemHeights(mFirstExpPos, itemHeights); - mBuilder.append(" ") - .append(itemHeights.item - itemHeights.child) - .append("\n"); - mBuilder.append(" ").append(mSecondExpPos).append("\n"); - getItemHeights(mSecondExpPos, itemHeights); - mBuilder.append(" ") - .append(itemHeights.item - itemHeights.child) - .append("\n"); - mBuilder.append(" ").append(mSrcPos).append("\n"); - mBuilder.append(" ").append(mFloatViewHeight + getDividerHeight()) - .append("\n"); - mBuilder.append(" ").append(getHeight()).append("\n"); - mBuilder.append(" ").append(mLastY).append("\n"); - mBuilder.append(" ").append(mFloatViewMid).append("\n"); - mBuilder.append(" "); - for (int i = 0; i < children; ++i) { - mBuilder.append(getShuffleEdge(first + i, getChildAt(i).getTop())).append(","); - } - mBuilder.append("\n"); - - mBuilder.append("\n"); - mNumInBuffer++; - - if (mNumInBuffer > 1000) { - flush(); - mNumInBuffer = 0; - } - } - - public void flush() { - if (!mTracking) { - return; - } - - // save to file on sdcard - try { - boolean append = true; - if (mNumFlushes == 0) { - append = false; - } - final FileWriter writer = new FileWriter(mFile, append); - - writer.write(mBuilder.toString()); - mBuilder.delete(0, mBuilder.length()); - - writer.flush(); - writer.close(); - - mNumFlushes++; - } catch (final IOException e) { - // do nothing - } - } - - public void stopTracking() { - if (mTracking) { - mBuilder.append("\n"); - flush(); - mTracking = false; - } - } - - } - -} diff --git a/src/org/lineageos/eleven/dragdrop/SimpleFloatViewManager.java b/src/org/lineageos/eleven/dragdrop/SimpleFloatViewManager.java deleted file mode 100644 index ce5cb60ff2ea8cf7111f3a8a6c1edde8b2aadb8b..0000000000000000000000000000000000000000 --- a/src/org/lineageos/eleven/dragdrop/SimpleFloatViewManager.java +++ /dev/null @@ -1,77 +0,0 @@ - -package org.lineageos.eleven.dragdrop; - -import android.graphics.Bitmap; -import android.graphics.Color; -import android.graphics.Point; -import android.view.View; -import android.widget.ImageView; -import android.widget.ListView; - -/** - * Simple implementation of the FloatViewManager class. Uses list items as they - * appear in the ListView to create the floating View. - */ -public class SimpleFloatViewManager implements DragSortListView.FloatViewManager { - - private final ListView mListView; - - private Bitmap mFloatBitmap; - - private int mFloatBGColor = Color.BLACK; - - public SimpleFloatViewManager(ListView lv) { - mListView = lv; - } - - public void setBackgroundColor(int color) { - mFloatBGColor = color; - } - - /** - * This simple implementation creates a Bitmap copy of the list item - * currently shown at ListView position. - */ - @Override - public View onCreateFloatView(int position) { - View v = mListView.getChildAt(position + mListView.getHeaderViewsCount() - - mListView.getFirstVisiblePosition()); - - if (v == null) { - return null; - } - - v.setPressed(false); - - v.setDrawingCacheEnabled(true); - mFloatBitmap = Bitmap.createBitmap(v.getDrawingCache()); - v.setDrawingCacheEnabled(false); - - ImageView iv = new ImageView(mListView.getContext()); - iv.setBackgroundColor(mFloatBGColor); - iv.setPadding(0, 0, 0, 0); - iv.setImageBitmap(mFloatBitmap); - - return iv; - } - - /** - * Removes the Bitmap from the ImageView created in onCreateFloatView() and - * tells the system to recycle it. - */ - @Override - public void onDestroyFloatView(View floatView) { - ((ImageView)floatView).setImageDrawable(null); - - mFloatBitmap.recycle(); - mFloatBitmap = null; - } - - /** - * {@inheritDoc} - */ - @Override - public void onDragFloatView(View floatView, Point position, Point touch) { - /* Nothing to do */ - } -} diff --git a/src/org/lineageos/eleven/format/PrefixHighlighter.java b/src/org/lineageos/eleven/format/PrefixHighlighter.java deleted file mode 100644 index 67618985cb8991427b93a95509d4a9e11503578c..0000000000000000000000000000000000000000 --- a/src/org/lineageos/eleven/format/PrefixHighlighter.java +++ /dev/null @@ -1,133 +0,0 @@ -/* - * Copyright (C) 2011 The Android Open Source Project Licensed under the Apache - * License, Version 2.0 (the "License"); you may not use this file except in - * compliance with the License. You may obtain a copy of the License at - * http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law - * or agreed to in writing, software distributed under the License is - * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ - -package org.lineageos.eleven.format; - -import android.content.Context; -import android.text.SpannableString; -import android.text.TextUtils; -import android.text.style.ForegroundColorSpan; -import android.widget.TextView; - -import org.lineageos.eleven.utils.PreferenceUtils; - -/** - * Highlights the text in a text field. - */ -public class PrefixHighlighter { - - /* Color used when highlighting the prefixes */ - private final int mPrefixHighlightColor; - - private ForegroundColorSpan mPrefixColorSpan; - - /** - * @param prefixHighlightColor The color used to highlight the prefixes. - */ - public PrefixHighlighter(final Context context) { - mPrefixHighlightColor = PreferenceUtils.getInstance(context).getDefaultThemeColor(context); - } - - /** - * Sets the text on the given {@link TextView}, highlighting the word that - * matches the given prefix. - * - * @param view The {@link TextView} on which to set the text - * @param text The string to use as the text - * @param prefix The prefix to look for - */ - public void setText(final TextView view, final String text, final char[] prefix) { - if (view == null || TextUtils.isEmpty(text) || prefix == null || prefix.length == 0) { - return; - } - view.setText(apply(text, prefix)); - } - - /** - * Returns a {@link CharSequence} which highlights the given prefix if found - * in the given text. - * - * @param text the text to which to apply the highlight - * @param prefix the prefix to look for - */ - public CharSequence apply(final CharSequence text, final char[] prefix) { - int mIndex = indexOfPrefix(text, prefix, true); - // prefer word prefix, if not search through the entire word - if (mIndex == -1) { - mIndex = indexOfPrefix(text, prefix, false); - } - - if (mIndex != -1) { - if (mPrefixColorSpan == null) { - mPrefixColorSpan = new ForegroundColorSpan(mPrefixHighlightColor); - } - final SpannableString mResult = new SpannableString(text); - mResult.setSpan(mPrefixColorSpan, mIndex, mIndex + prefix.length, 0); - return mResult; - } else { - return text; - } - } - - /** - * Finds the index of the first character that starts with the given prefix. If - * not found, returns -1. - * - * @param text the text in which to search for the prefix - * @param prefix the text to find, in upper case letters - * @param wordOnly only search for word prefixes if true - */ - private int indexOfPrefix(final CharSequence text, final char[] prefix, boolean wordOnly) { - if (TextUtils.isEmpty(text) || prefix == null) { - return -1; - } - - final int mTextLength = text.length(); - final int mPrefixLength = prefix.length; - - if (mPrefixLength == 0 || mTextLength < mPrefixLength) { - return -1; - } - - int i = 0; - while (i < mTextLength) { - /* Skip non-word characters */ - while (i < mTextLength && !Character.isLetterOrDigit(text.charAt(i))) { - i++; - } - - if (i + mPrefixLength > mTextLength) { - return -1; - } - - /* Compare the prefixes */ - int j; - for (j = 0; j < mPrefixLength; j++) { - if (Character.toUpperCase(text.charAt(i + j)) != prefix[j]) { - break; - } - } - if (j == mPrefixLength) { - return i; - } - - if (wordOnly) { - /* Skip this word */ - while (i < mTextLength && Character.isLetterOrDigit(text.charAt(i))) { - i++; - } - } else { - i++; - } - } - return -1; - } -} diff --git a/src/org/lineageos/eleven/loaders/AlbumLoader.java b/src/org/lineageos/eleven/loaders/AlbumLoader.java index 49a5bc47a1e4a2da8c5c5f6923a9e7f5f646fc7f..fe221679fd6065d5b8d5292b615ce0fffb796ede 100644 --- a/src/org/lineageos/eleven/loaders/AlbumLoader.java +++ b/src/org/lineageos/eleven/loaders/AlbumLoader.java @@ -1,7 +1,7 @@ /* * Copyright (C) 2012 Andrew Neal * Copyright (C) 2014 The CyanogenMod Project - * Copyright (C) 2020 The LineageOS Project + * Copyright (C) 2020-2021 The LineageOS Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -15,7 +15,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package org.lineageos.eleven.loaders; import android.content.Context; @@ -29,6 +28,7 @@ import org.lineageos.eleven.model.Album; import org.lineageos.eleven.provider.LocalizedStore; import org.lineageos.eleven.provider.LocalizedStore.SortParameter; import org.lineageos.eleven.sectionadapter.SectionCreator; +import org.lineageos.eleven.utils.EmptyCursor; import org.lineageos.eleven.utils.Lists; import org.lineageos.eleven.utils.MusicUtils; import org.lineageos.eleven.utils.PreferenceUtils; @@ -38,7 +38,7 @@ import java.util.ArrayList; import java.util.List; /** - * Used to query {@link MediaStore.Audio.Albums.EXTERNAL_CONTENT_URI} and return + * Used to query MediaStore.Audio.Albums.EXTERNAL_CONTENT_URI and return * the albums on a user's device. * * @author Andrew Neal (andrewdneal@gmail.com) @@ -48,12 +48,12 @@ public class AlbumLoader extends SectionCreator.SimpleListLoader { /** * The result */ - private ArrayList mAlbumsList = Lists.newArrayList(); + private final ArrayList mAlbumsList = Lists.newArrayList(); /** * Additional selection filter */ - protected Long mArtistId; + protected final Long mArtistId; /** * @param context The {@link Context} to use @@ -63,7 +63,7 @@ public class AlbumLoader extends SectionCreator.SimpleListLoader { } /** - * @param context The {@link Context} to use + * @param context The {@link Context} to use * @param artistId The artistId to filter against or null if none */ public AlbumLoader(final Context context, final Long artistId) { @@ -72,9 +72,6 @@ public class AlbumLoader extends SectionCreator.SimpleListLoader { mArtistId = artistId; } - /** - * {@inheritDoc} - */ @Override public List loadInBackground() { // Create the Cursor @@ -102,21 +99,14 @@ public class AlbumLoader extends SectionCreator.SimpleListLoader { continue; } - // Create a new album + // Create a new album and add everything up final Album album = new Album(id, albumName, artist, songCount, year); - - if (cursor instanceof SortedCursor) { - album.mBucketLabel = (String)((SortedCursor) cursor).getExtraData(); - } - - // Add everything up mAlbumsList.add(album); } while (cursor.moveToNext()); } // Close the cursor if (cursor != null) { cursor.close(); - cursor = null; } return mAlbumsList; @@ -124,6 +114,7 @@ public class AlbumLoader extends SectionCreator.SimpleListLoader { /** * For string-based sorts, return the localized store sort parameter, otherwise return null + * * @param sortOrder the song ordering preference selected by the user */ private static LocalizedStore.SortParameter getSortParameter(String sortOrder) { @@ -140,20 +131,23 @@ public class AlbumLoader extends SectionCreator.SimpleListLoader { /** * Creates the {@link Cursor} used to run the query. * - * @param context The {@link Context} to use. + * @param context The {@link Context} to use. * @param artistId The artistId we want to find albums for or null if we want all albums * @return The {@link Cursor} used to run the album query. */ - public static final Cursor makeAlbumCursor(final Context context, final Long artistId) { + public static Cursor makeAlbumCursor(final Context context, final Long artistId) { // requested album ordering final String albumSortOrder = PreferenceUtils.getInstance(context).getAlbumSortOrder(); Uri uri = MediaStore.Audio.Albums.EXTERNAL_CONTENT_URI; if (artistId != null) { + if (artistId == -1) { + return new EmptyCursor(); + } uri = MediaStore.Audio.Artists.Albums.getContentUri("external", artistId); } Cursor cursor = context.getContentResolver().query(uri, - new String[] { + new String[]{ /* 0 */ AlbumColumns.ALBUM_ID, /* 1 */ @@ -169,7 +163,7 @@ public class AlbumLoader extends SectionCreator.SimpleListLoader { // if our sort is a localized-based sort, grab localized data from the store final SortParameter sortParameter = getSortParameter(albumSortOrder); if (sortParameter != null && cursor != null) { - final boolean descending = MusicUtils.isSortOrderDesending(albumSortOrder); + final boolean descending = MusicUtils.isSortOrderDescending(albumSortOrder); return LocalizedStore.getInstance(context).getLocalizedSort(cursor, AlbumColumns.ALBUM_ID, SortParameter.Album, sortParameter, descending, artistId == null); diff --git a/src/org/lineageos/eleven/loaders/AlbumSongLoader.java b/src/org/lineageos/eleven/loaders/AlbumSongLoader.java index 81596e07bc2d0425eec47c8f0edc678d52de2b35..de17c5133f245829e27cb403c73c04d3cc1ac48b 100644 --- a/src/org/lineageos/eleven/loaders/AlbumSongLoader.java +++ b/src/org/lineageos/eleven/loaders/AlbumSongLoader.java @@ -1,16 +1,20 @@ /* * Copyright (C) 2012 Andrew Neal * Copyright (C) 2014 The CyanogenMod Project - * Licensed under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law - * or agreed to in writing, software distributed under the License is - * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the specific language - * governing permissions and limitations under the License. + * Copyright (C) 2021 The LineageOS Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ - package org.lineageos.eleven.loaders; import android.content.Context; @@ -27,7 +31,7 @@ import java.util.ArrayList; import java.util.List; /** - * Used to query {@link MediaStore.Audio.Media.EXTERNAL_CONTENT_URI} and return + * Used to query MediaStore.Audio.Media.EXTERNAL_CONTENT_URI and return * the Song for a particular album. * * @author Andrew Neal (andrewdneal@gmail.com) @@ -55,9 +59,6 @@ public class AlbumSongLoader extends WrappedAsyncTaskLoader> { mAlbumID = albumId; } - /** - * {@inheritDoc} - */ @Override public List loadInBackground() { // Create the Cursor @@ -96,7 +97,6 @@ public class AlbumSongLoader extends WrappedAsyncTaskLoader> { // Close the cursor if (cursor != null) { cursor.close(); - cursor = null; } return mSongList; } @@ -106,13 +106,13 @@ public class AlbumSongLoader extends WrappedAsyncTaskLoader> { * @param albumId The Id of the album the songs belong to. * @return The {@link Cursor} used to run the query. */ - public static final Cursor makeAlbumSongCursor(final Context context, final Long albumId) { + public static Cursor makeAlbumSongCursor(final Context context, final Long albumId) { // Match the songs up with the artist String selection = (AudioColumns.IS_MUSIC + "=1") + " AND " + AudioColumns.TITLE + " != ''" + " AND " + AudioColumns.ALBUM_ID + "=" + albumId; return context.getContentResolver().query(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, - new String[] { + new String[]{ /* 0 */ BaseColumns._ID, /* 1 */ @@ -128,5 +128,4 @@ public class AlbumSongLoader extends WrappedAsyncTaskLoader> { }, selection, null, PreferenceUtils.getInstance(context).getAlbumSongSortOrder()); } - } diff --git a/src/org/lineageos/eleven/loaders/ArtistLoader.java b/src/org/lineageos/eleven/loaders/ArtistLoader.java index 9a22ca1ac01b0714e907c0ef895eae03c4c8d2d1..3268e55f3e8cb79a11af63384fce00712deb0c0c 100644 --- a/src/org/lineageos/eleven/loaders/ArtistLoader.java +++ b/src/org/lineageos/eleven/loaders/ArtistLoader.java @@ -1,16 +1,20 @@ /* * Copyright (C) 2012 Andrew Neal * Copyright (C) 2014 The CyanogenMod Project - * Licensed under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law - * or agreed to in writing, software distributed under the License is - * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the specific language - * governing permissions and limitations under the License. + * Copyright (C) 2021 The LineageOS Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ - package org.lineageos.eleven.loaders; import android.content.Context; @@ -31,7 +35,7 @@ import java.util.ArrayList; import java.util.List; /** - * Used to query {@link MediaStore.Audio.Artists.EXTERNAL_CONTENT_URI} and + * Used to query MediaStore.Audio.Artists.EXTERNAL_CONTENT_URI and * return the artists on a user's device. * * @author Andrew Neal (andrewdneal@gmail.com) @@ -41,7 +45,7 @@ public class ArtistLoader extends SectionCreator.SimpleListLoader { /** * The result */ - private ArrayList mArtistsList = Lists.newArrayList(); + private final ArrayList mArtistsList = Lists.newArrayList(); /** * Constructor of ArtistLoader @@ -52,9 +56,6 @@ public class ArtistLoader extends SectionCreator.SimpleListLoader { super(context); } - /** - * {@inheritDoc} - */ @Override public List loadInBackground() { // Create the Cursor @@ -92,7 +93,6 @@ public class ArtistLoader extends SectionCreator.SimpleListLoader { // Close the cursor if (cursor != null) { cursor.close(); - cursor = null; } return mArtistsList; @@ -116,7 +116,7 @@ public class ArtistLoader extends SectionCreator.SimpleListLoader { * @param context The {@link Context} to use. * @return The {@link Cursor} used to run the artist query. */ - public static final Cursor makeArtistCursor(final Context context) { + public static Cursor makeArtistCursor(final Context context) { // requested artist ordering final String artistSortOrder = PreferenceUtils.getInstance(context).getArtistSortOrder(); @@ -135,7 +135,7 @@ public class ArtistLoader extends SectionCreator.SimpleListLoader { // if our sort is a localized-based sort, grab localized data from the store final SortParameter sortParameter = getSortParameter(artistSortOrder); if (sortParameter != null && cursor != null) { - final boolean descending = MusicUtils.isSortOrderDesending(artistSortOrder); + final boolean descending = MusicUtils.isSortOrderDescending(artistSortOrder); return LocalizedStore.getInstance(context).getLocalizedSort(cursor, Artists._ID, SortParameter.Artist, sortParameter, descending, true); } diff --git a/src/org/lineageos/eleven/loaders/AsyncHandler.java b/src/org/lineageos/eleven/loaders/AsyncHandler.java deleted file mode 100644 index 94126c50ecbe104ffbf2150a459a3ab798e739bb..0000000000000000000000000000000000000000 --- a/src/org/lineageos/eleven/loaders/AsyncHandler.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project Licensed under the Apache - * License, Version 2.0 (the "License"); you may not use this file except in - * compliance with the License. You may obtain a copy of the License at - * http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law - * or agreed to in writing, software distributed under the License is - * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ - -package org.lineageos.eleven.loaders; - -import android.os.Handler; -import android.os.HandlerThread; - -/** - * Helper class for managing the background thread used to perform io operations - * and handle async broadcasts. - */ -public final class AsyncHandler { - - private static final HandlerThread sHandlerThread = new HandlerThread("AsyncHandler"); - - private static final Handler sHandler; - - static { - sHandlerThread.start(); - sHandler = new Handler(sHandlerThread.getLooper()); - } - - /* This class is never initiated */ - private AsyncHandler() { - } - - /** - * @param r The {@link Runnable} to execute. - */ - public static void post(final Runnable r) { - sHandler.post(r); - } - -} diff --git a/src/org/lineageos/eleven/loaders/LastAddedLoader.java b/src/org/lineageos/eleven/loaders/LastAddedLoader.java index 4e1fe77acddfb4b1a4e8ab522ef16fc2a08e7332..584b8665ef1e6be33a73657533db14898a2ab206 100644 --- a/src/org/lineageos/eleven/loaders/LastAddedLoader.java +++ b/src/org/lineageos/eleven/loaders/LastAddedLoader.java @@ -1,16 +1,20 @@ /* * Copyright (C) 2012 Andrew Neal * Copyright (C) 2014 The CyanogenMod Project - * Licensed under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law - * or agreed to in writing, software distributed under the License is - * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the specific language - * governing permissions and limitations under the License. + * Copyright (C) 2021 The LineageOS Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ - package org.lineageos.eleven.loaders; import android.content.Context; @@ -28,7 +32,7 @@ import java.util.ArrayList; import java.util.List; /** - * Used to query {@link MediaStore.Audio.Media.EXTERNAL_CONTENT_URI} and return + * Used to query MediaStore.Audio.Media.EXTERNAL_CONTENT_URI and return * the Song the user added over the past four of weeks. * * @author Andrew Neal (andrewdneal@gmail.com) @@ -48,9 +52,6 @@ public class LastAddedLoader extends SectionCreator.SimpleListLoader { super(context); } - /** - * {@inheritDoc} - */ @Override public List loadInBackground() { // Create the xCursor @@ -83,7 +84,8 @@ public class LastAddedLoader extends SectionCreator.SimpleListLoader { final int year = cursor.getInt(6); // Create a new song - final Song song = new Song(id, songName, artist, album, albumId, durationInSecs, year); + final Song song = new Song(id, songName, artist, album, albumId, durationInSecs, + year); // Add everything up mSongList.add(song); @@ -92,7 +94,6 @@ public class LastAddedLoader extends SectionCreator.SimpleListLoader { // Close the cursor if (cursor != null) { cursor.close(); - cursor = null; } return mSongList; } @@ -101,13 +102,15 @@ public class LastAddedLoader extends SectionCreator.SimpleListLoader { * @param context The {@link Context} to use. * @return The {@link Cursor} used to run the song query. */ - public static final Cursor makeLastAddedCursor(final Context context) { + public static Cursor makeLastAddedCursor(final Context context) { // timestamp of four weeks ago long fourWeeksAgo = (System.currentTimeMillis() / 1000) - (4 * 3600 * 24 * 7); // possible saved timestamp caused by user "clearing" the last added playlist long cutoff = PreferenceUtils.getInstance(context).getLastAddedCutoff() / 1000; // use the most recent of the two timestamps - if(cutoff < fourWeeksAgo) { cutoff = fourWeeksAgo; } + if (cutoff < fourWeeksAgo) { + cutoff = fourWeeksAgo; + } String selection = (AudioColumns.IS_MUSIC + "=1") + " AND " + AudioColumns.TITLE + " != ''" + @@ -115,7 +118,7 @@ public class LastAddedLoader extends SectionCreator.SimpleListLoader { cutoff; return context.getContentResolver().query(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, - new String[] { + new String[]{ /* 0 */ BaseColumns._ID, /* 1 */ diff --git a/src/org/lineageos/eleven/loaders/NowPlayingCursor.java b/src/org/lineageos/eleven/loaders/NowPlayingCursor.java index f686a3b1945f0d9782f904cbf0b6d756a6eeae13..c057be6b262504f9ecc3189bf7cd25a8f86e4f98 100644 --- a/src/org/lineageos/eleven/loaders/NowPlayingCursor.java +++ b/src/org/lineageos/eleven/loaders/NowPlayingCursor.java @@ -1,11 +1,25 @@ - +/* + * Copyright (C) 2014 The CyanogenMod Project + * Copyright (C) 2021 The LineageOS Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package org.lineageos.eleven.loaders; import android.annotation.SuppressLint; import android.content.Context; import android.database.AbstractCursor; import android.database.Cursor; -import android.os.RemoteException; import android.provider.BaseColumns; import android.provider.MediaStore; import android.provider.MediaStore.Audio.AudioColumns; @@ -60,17 +74,11 @@ public class NowPlayingCursor extends AbstractCursor { makeNowPlayingCursor(); } - /** - * {@inheritDoc} - */ @Override public int getCount() { return mSize; } - /** - * {@inheritDoc} - */ @Override public boolean onMove(final int oldPosition, final int newPosition) { if (oldPosition == newPosition) { @@ -88,9 +96,6 @@ public class NowPlayingCursor extends AbstractCursor { return true; } - /** - * {@inheritDoc} - */ @Override public String getString(final int column) { try { @@ -101,17 +106,11 @@ public class NowPlayingCursor extends AbstractCursor { } } - /** - * {@inheritDoc} - */ @Override public short getShort(final int column) { return mQueueCursor.getShort(column); } - /** - * {@inheritDoc} - */ @Override public int getInt(final int column) { try { @@ -122,9 +121,6 @@ public class NowPlayingCursor extends AbstractCursor { } } - /** - * {@inheritDoc} - */ @Override public long getLong(final int column) { try { @@ -135,49 +131,31 @@ public class NowPlayingCursor extends AbstractCursor { } } - /** - * {@inheritDoc} - */ @Override public float getFloat(final int column) { return mQueueCursor.getFloat(column); } - /** - * {@inheritDoc} - */ @Override public double getDouble(final int column) { return mQueueCursor.getDouble(column); } - /** - * {@inheritDoc} - */ @Override public int getType(final int column) { return mQueueCursor.getType(column); } - /** - * {@inheritDoc} - */ @Override public boolean isNull(final int column) { return mQueueCursor.isNull(column); } - /** - * {@inheritDoc} - */ @Override public String[] getColumnNames() { return PROJECTION; } - /** - * {@inheritDoc} - */ @SuppressWarnings("deprecation") @Override public void deactivate() { @@ -186,18 +164,12 @@ public class NowPlayingCursor extends AbstractCursor { } } - /** - * {@inheritDoc} - */ @Override public boolean requery() { makeNowPlayingCursor(); return true; } - /** - * {@inheritDoc} - */ @Override public void close() { try { @@ -205,10 +177,10 @@ public class NowPlayingCursor extends AbstractCursor { mQueueCursor.close(); mQueueCursor = null; } - } catch (final Exception close) { + } catch (final Exception ignored) { } super.close(); - }; + } /** * Actually makes the queue @@ -270,11 +242,10 @@ public class NowPlayingCursor extends AbstractCursor { /** * @param which The position to remove - * @return True if sucessfull, false othersise */ - public boolean removeItem(final int which) { + public void removeItem(final int which) { if (!MusicUtils.removeTrackAtPosition(mNowPlaying[which], which)) { - return false; + return; } int i = which; mSize--; @@ -283,6 +254,5 @@ public class NowPlayingCursor extends AbstractCursor { i++; } onMove(-1, mCurPos); - return true; } } diff --git a/src/org/lineageos/eleven/loaders/PlaylistLoader.java b/src/org/lineageos/eleven/loaders/PlaylistLoader.java index dfcdae80243ce2cc47fb947c0314502d22d96750..1f3a47e136af2c44a0b3a138f5bd2a7a1bbfe1ae 100644 --- a/src/org/lineageos/eleven/loaders/PlaylistLoader.java +++ b/src/org/lineageos/eleven/loaders/PlaylistLoader.java @@ -1,16 +1,20 @@ /* * Copyright (C) 2012 Andrew Neal * Copyright (C) 2014 The CyanogenMod Project - * Licensed under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law - * or agreed to in writing, software distributed under the License is - * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the specific language - * governing permissions and limitations under the License. + * Copyright (C) 2021 The LineageOS Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ - package org.lineageos.eleven.loaders; import android.content.Context; @@ -29,7 +33,7 @@ import java.util.ArrayList; import java.util.List; /** - * Used to query {@link MediaStore.Audio.Playlists.EXTERNAL_CONTENT_URI} and + * Used to query MediaStore.Audio.Playlists.EXTERNAL_CONTENT_URI and * return the playlists on a user's device. * * @author Andrew Neal (andrewdneal@gmail.com) @@ -50,12 +54,9 @@ public class PlaylistLoader extends WrappedAsyncTaskLoader> { super(context); } - /** - * {@inheritDoc} - */ @Override public List loadInBackground() { - // Add the deafult playlits to the adapter + // Add the default playlist to the adapter makeDefaultPlaylists(); // Create the Cursor @@ -81,7 +82,6 @@ public class PlaylistLoader extends WrappedAsyncTaskLoader> { // Close the cursor if (cursor != null) { cursor.close(); - cursor = null; } return mPlaylistList; } @@ -112,9 +112,9 @@ public class PlaylistLoader extends WrappedAsyncTaskLoader> { * @param context The {@link Context} to use. * @return The {@link Cursor} used to run the playlist query. */ - public static final Cursor makePlaylistCursor(final Context context) { + public static Cursor makePlaylistCursor(final Context context) { return context.getContentResolver().query(MediaStore.Audio.Playlists.EXTERNAL_CONTENT_URI, - new String[] { + new String[]{ /* 0 */ BaseColumns._ID, /* 1 */ diff --git a/src/org/lineageos/eleven/loaders/PlaylistSongLoader.java b/src/org/lineageos/eleven/loaders/PlaylistSongLoader.java index f9cb03a6cbd75842f83e951479c8c58acc5e4926..19ac9ac4761efa199d428256f9b17842720f2f65 100644 --- a/src/org/lineageos/eleven/loaders/PlaylistSongLoader.java +++ b/src/org/lineageos/eleven/loaders/PlaylistSongLoader.java @@ -1,16 +1,20 @@ /* * Copyright (C) 2012 Andrew Neal * Copyright (C) 2014 The CyanogenMod Project - * Licensed under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law - * or agreed to in writing, software distributed under the License is - * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the specific language - * governing permissions and limitations under the License. + * Copyright (C) 2021 The LineageOS Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ - package org.lineageos.eleven.loaders; import android.content.ContentProviderOperation; @@ -31,7 +35,7 @@ import java.util.ArrayList; import java.util.List; /** - * Used to query {@link MediaStore.Audio.Playlists.EXTERNAL_CONTENT_URI} and + * Used to query MediaStore.Audio.Playlists.EXTERNAL_CONTENT_URI and * return the songs for a particular playlist. * * @author Andrew Neal (andrewdneal@gmail.com) @@ -60,9 +64,6 @@ public class PlaylistSongLoader extends WrappedAsyncTaskLoader> { mPlaylistID = playlistId; } - /** - * {@inheritDoc} - */ @Override public List loadInBackground() { final int playlistCount = countPlaylist(getContext(), mPlaylistID); @@ -74,8 +75,8 @@ public class PlaylistSongLoader extends WrappedAsyncTaskLoader> { boolean runCleanup = false; // if the raw playlist count differs from the mapped playlist count (ie the raw mapping - // table vs the mapping table join the audio table) that means the playlist mapping table - // is messed up + // table vs the mapping table join the audio table) that means the playlist mapping + // table is messed up if (cursor.getCount() != playlistCount) { Log.w(TAG, "Count Differs - raw is: " + playlistCount + " while cursor is " + cursor.getCount()); @@ -149,7 +150,8 @@ public class PlaylistSongLoader extends WrappedAsyncTaskLoader> { .getColumnIndexOrThrow(AudioColumns.YEAR)); // Create a new song - final Song song = new Song(id, songName, artist, album, albumId, durationInSecs, year); + final Song song = new Song(id, songName, artist, album, albumId, durationInSecs, + year); // Add everything up mSongList.add(song); @@ -158,23 +160,23 @@ public class PlaylistSongLoader extends WrappedAsyncTaskLoader> { // Close the cursor if (cursor != null) { cursor.close(); - cursor = null; } return mSongList; } /** * Cleans up the playlist based on the passed in cursor's data - * @param context The {@link Context} to use + * + * @param context The {@link Context} to use * @param playlistId playlistId to clean up - * @param cursor data to repopulate the playlist with + * @param cursor data to repopulate the playlist with */ private static void cleanupPlaylist(final Context context, final long playlistId, - final Cursor cursor) { + final Cursor cursor) { Log.w(TAG, "Cleaning up playlist: " + playlistId); - final int idCol = cursor.getColumnIndexOrThrow(MediaStore.Audio.Playlists.Members.AUDIO_ID); - final Uri uri = MediaStore.Audio.Playlists.Members.getContentUri("external", playlistId); + final int idCol = cursor.getColumnIndexOrThrow(Playlists.Members.AUDIO_ID); + final Uri uri = Playlists.Members.getContentUri("external", playlistId); ArrayList ops = new ArrayList<>(); @@ -213,31 +215,22 @@ public class PlaylistSongLoader extends WrappedAsyncTaskLoader> { /** * Returns the playlist count for the raw playlist mapping table - * @param context The {@link Context} to use + * + * @param context The {@link Context} to use * @param playlistId playlistId to count * @return the number of tracks in the raw playlist mapping table */ private static int countPlaylist(final Context context, final long playlistId) { - Cursor c = null; - try { + try (Cursor c = context.getContentResolver().query( + Playlists.Members.getContentUri("external", playlistId), + new String[]{Playlists.Members.AUDIO_ID,}, null, null, + Playlists.Members.DEFAULT_SORT_ORDER)) { // when we query using only the audio_id column we will get the raw mapping table // results - which will tell us if the table has rows that don't exist in the normal // table - c = context.getContentResolver().query( - MediaStore.Audio.Playlists.Members.getContentUri("external", playlistId), - new String[]{ - MediaStore.Audio.Playlists.Members.AUDIO_ID, - }, null, null, - MediaStore.Audio.Playlists.Members.DEFAULT_SORT_ORDER); - if (c != null) { return c.getCount(); } - } finally { - if (c != null) { - c.close(); - c = null; - } } return 0; @@ -246,20 +239,20 @@ public class PlaylistSongLoader extends WrappedAsyncTaskLoader> { /** * Creates the {@link Cursor} used to run the query. * - * @param context The {@link Context} to use. + * @param context The {@link Context} to use. * @param playlistID The playlist the songs belong to. * @return The {@link Cursor} used to run the song query. */ - public static final Cursor makePlaylistSongCursor(final Context context, final Long playlistID) { + public static Cursor makePlaylistSongCursor(final Context context, final Long playlistID) { String mSelection = (AudioColumns.IS_MUSIC + "=1") + " AND " + AudioColumns.TITLE + " != ''"; return context.getContentResolver().query( - MediaStore.Audio.Playlists.Members.getContentUri("external", playlistID), - new String[] { + Playlists.Members.getContentUri("external", playlistID), + new String[]{ /* 0 */ - MediaStore.Audio.Playlists.Members._ID, + Playlists.Members._ID, /* 1 */ - MediaStore.Audio.Playlists.Members.AUDIO_ID, + Playlists.Members.AUDIO_ID, /* 2 */ AudioColumns.TITLE, /* 3 */ @@ -275,6 +268,6 @@ public class PlaylistSongLoader extends WrappedAsyncTaskLoader> { /* 8 */ Playlists.Members.PLAY_ORDER, }, mSelection, null, - MediaStore.Audio.Playlists.Members.DEFAULT_SORT_ORDER); + Playlists.Members.DEFAULT_SORT_ORDER); } } diff --git a/src/org/lineageos/eleven/loaders/QueueLoader.java b/src/org/lineageos/eleven/loaders/QueueLoader.java index ccf8f6d0d94b629c1de06e98d07ae0e6865baa49..8208b895830b5b361a67e4db42356aa14cdf96ca 100644 --- a/src/org/lineageos/eleven/loaders/QueueLoader.java +++ b/src/org/lineageos/eleven/loaders/QueueLoader.java @@ -1,16 +1,20 @@ /* * Copyright (C) 2012 Andrew Neal * Copyright (C) 2014 The CyanogenMod Project - * Licensed under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law - * or agreed to in writing, software distributed under the License is - * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the specific language - * governing permissions and limitations under the License. + * Copyright (C) 2021 The LineageOS Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ - package org.lineageos.eleven.loaders; import android.content.Context; @@ -43,15 +47,12 @@ public class QueueLoader extends WrappedAsyncTaskLoader> { super(context); } - /** - * {@inheritDoc} - */ @Override public List loadInBackground() { // Create the Cursor NowPlayingCursor cursor = new NowPlayingCursor(getContext()); // Gather the data - if (cursor != null && cursor.moveToFirst()) { + if (cursor.moveToFirst()) { do { // Copy the song Id final long id = cursor.getLong(0); @@ -78,17 +79,15 @@ public class QueueLoader extends WrappedAsyncTaskLoader> { final int year = cursor.getInt(6); // Create a new song - final Song song = new Song(id, songName, artist, album, albumId, durationInSecs, year); + final Song song = new Song(id, songName, artist, album, albumId, + durationInSecs, year); // Add everything up mSongList.add(song); } while (cursor.moveToNext()); } // Close the cursor - if (cursor != null) { - cursor.close(); - cursor = null; - } + cursor.close(); return mSongList; } @@ -98,7 +97,7 @@ public class QueueLoader extends WrappedAsyncTaskLoader> { * @param context The {@link Context} to use. * @return The {@link Cursor} used to run the song query. */ - public static final Cursor makeQueueCursor(final Context context) { + public static Cursor makeQueueCursor(final Context context) { return new NowPlayingCursor(context); } } diff --git a/src/org/lineageos/eleven/loaders/SearchLoader.java b/src/org/lineageos/eleven/loaders/SearchLoader.java deleted file mode 100644 index 09ef5194b969b950ec3dfdabc2a59c3b2e3a151e..0000000000000000000000000000000000000000 --- a/src/org/lineageos/eleven/loaders/SearchLoader.java +++ /dev/null @@ -1,132 +0,0 @@ -/* - * Copyright (C) 2012 Andrew Neal - * Copyright (C) 2014 The CyanogenMod Project - * Licensed under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law - * or agreed to in writing, software distributed under the License is - * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ - -package org.lineageos.eleven.loaders; - -import android.content.Context; -import android.database.Cursor; -import android.net.Uri; -import android.provider.BaseColumns; -import android.provider.MediaStore; -import android.text.TextUtils; - -import org.lineageos.eleven.model.Song; -import org.lineageos.eleven.utils.Lists; - -import java.util.ArrayList; -import java.util.List; - -/** - * @author Andrew Neal (andrewdneal@gmail.com) - */ -public class SearchLoader extends WrappedAsyncTaskLoader> { - - /** - * The result - */ - private final ArrayList mSongList = Lists.newArrayList(); - - /** - * The query - */ - private String mQuery; - - /** - * Constructor of SongLoader - * - * @param context The {@link Context} to use - * @param query The search query - */ - public SearchLoader(final Context context, final String query) { - super(context); - mQuery = query; - } - - /** - * {@inheritDoc} - */ - @Override - public List loadInBackground() { - // Gather the data - Cursor cursor = makeSearchCursor(getContext(), mQuery); - if (cursor != null && cursor.moveToFirst()) { - do { - // Copy the song Id - long id = -1; - - // Copy the song name - final String songName = cursor.getString(cursor - .getColumnIndexOrThrow(MediaStore.Audio.Media.TITLE)); - - // Check for a song Id - if (!TextUtils.isEmpty(songName)) { - id = cursor.getLong(cursor - .getColumnIndexOrThrow(MediaStore.Audio.Media._ID)); - } - - // Copy the album name - final String album = cursor.getString(cursor - .getColumnIndexOrThrow(MediaStore.Audio.Albums.ALBUM)); - - // Copy the album id - final long albumId = cursor.getLong(cursor - .getColumnIndexOrThrow(MediaStore.Audio.Albums.ALBUM_ID)); - - // Check for a album Id - if (id < 0 && !TextUtils.isEmpty(album)) { - id = cursor.getLong(cursor - .getColumnIndexOrThrow(MediaStore.Audio.Albums._ID)); - } - - // Copy the artist name - final String artist = cursor.getString(cursor - .getColumnIndexOrThrow(MediaStore.Audio.Artists.ARTIST)); - - // Check for a artist Id - if (id < 0 && !TextUtils.isEmpty(artist)) { - id = cursor.getLong(cursor - .getColumnIndexOrThrow(MediaStore.Audio.Artists._ID)); - } - - // Create a new song - final Song song = new Song(id, songName, artist, album, albumId, -1, -1); - - // Add everything up - mSongList.add(song); - } while (cursor.moveToNext()); - } - // Close the cursor - if (cursor != null) { - cursor.close(); - cursor = null; - } - return mSongList; - } - - /** - * * @param context The {@link Context} to use. - * - * @param query The user's query. - * @return The {@link Cursor} used to perform the search. - */ - public static final Cursor makeSearchCursor(final Context context, final String query) { - return context.getContentResolver().query( - Uri.parse("content://media/external/audio/search/fancy/" + Uri.encode(query)), - new String[] { - BaseColumns._ID, MediaStore.Audio.Media.MIME_TYPE, - MediaStore.Audio.Artists.ARTIST, MediaStore.Audio.Albums.ALBUM_ID, - MediaStore.Audio.Albums.ALBUM, MediaStore.Audio.Media.TITLE, "data1", "data2" //$NON-NLS-2$ - }, null, null, null); - } - -} diff --git a/src/org/lineageos/eleven/loaders/SongLoader.java b/src/org/lineageos/eleven/loaders/SongLoader.java index e013f8057b03cb376ca6b38c2f0e13bf16bfd086..3021ece840adb3e4576f9483baa5be87f8a6ff89 100644 --- a/src/org/lineageos/eleven/loaders/SongLoader.java +++ b/src/org/lineageos/eleven/loaders/SongLoader.java @@ -1,16 +1,20 @@ /* * Copyright (C) 2012 Andrew Neal * Copyright (C) 2014 The CyanogenMod Project - * Licensed under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law - * or agreed to in writing, software distributed under the License is - * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the specific language - * governing permissions and limitations under the License. + * Copyright (C) 2021 The LineageOS Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ - package org.lineageos.eleven.loaders; import android.content.Context; @@ -32,7 +36,7 @@ import java.util.ArrayList; import java.util.List; /** - * Used to query {@link MediaStore.Audio.Media.EXTERNAL_CONTENT_URI} and return + * Used to query MediaStore.Audio.Media.EXTERNAL_CONTENT_URI and return * the songs on a user's device. * * @author Andrew Neal (andrewdneal@gmail.com) @@ -42,12 +46,12 @@ public class SongLoader extends SectionCreator.SimpleListLoader { /** * The result */ - protected ArrayList mSongList = Lists.newArrayList(); + protected final ArrayList mSongList = Lists.newArrayList(); /** * Additional selection filter */ - protected String mSelection; + protected final String mSelection; /** * @param context The {@link Context} to use @@ -57,7 +61,7 @@ public class SongLoader extends SectionCreator.SimpleListLoader { } /** - * @param context The {@link Context} to use + * @param context The {@link Context} to use * @param selection Additional selection filter to apply to the loader */ public SongLoader(final Context context, final String selection) { @@ -66,9 +70,6 @@ public class SongLoader extends SectionCreator.SimpleListLoader { mSelection = selection; } - /** - * {@inheritDoc} - */ @Override public List loadInBackground() { // Create the Cursor @@ -103,10 +104,10 @@ public class SongLoader extends SectionCreator.SimpleListLoader { // Create a new song final Song song = new Song(id, songName, artist, album, albumId, - durationInSecs, year); + durationInSecs, year); if (cursor instanceof SortedCursor) { - song.mBucketLabel = (String)((SortedCursor)cursor).getExtraData(); + song.mBucketLabel = (String) ((SortedCursor) cursor).getExtraData(); } mSongList.add(song); @@ -115,7 +116,6 @@ public class SongLoader extends SectionCreator.SimpleListLoader { // Close the cursor if (cursor != null) { cursor.close(); - cursor = null; } return mSongList; @@ -123,6 +123,7 @@ public class SongLoader extends SectionCreator.SimpleListLoader { /** * Gets the cursor for the loader - can be overriden + * * @return cursor to load */ protected Cursor getCursor() { @@ -131,6 +132,7 @@ public class SongLoader extends SectionCreator.SimpleListLoader { /** * For string-based sorts, return the localized store sort parameter, otherwise return null + * * @param sortOrder the song ordering preference selected by the user */ private static LocalizedStore.SortParameter getSortParameter(String sortOrder) { @@ -150,26 +152,26 @@ public class SongLoader extends SectionCreator.SimpleListLoader { /** * Creates the {@link Cursor} used to run the query. * - * @param context The {@link Context} to use. + * @param context The {@link Context} to use. * @param selection Additional selection statement to use * @return The {@link Cursor} used to run the song query. */ - public static final Cursor makeSongCursor(final Context context, final String selection) { + public static Cursor makeSongCursor(final Context context, final String selection) { return makeSongCursor(context, selection, true); } /** * Creates the {@link Cursor} used to run the query. * - * @param context The {@link Context} to use. + * @param context The {@link Context} to use. * @param selection Additional selection statement to use - * @param runSort For localized sorts this can enable/disable the logic for running the - * additional localization sort. Queries that apply their own sorts can pass - * in false for a boost in perf + * @param runSort For localized sorts this can enable/disable the logic for running the + * additional localization sort. Queries that apply their own sorts can pass + * in false for a boost in perf * @return The {@link Cursor} used to run the song query. */ - public static final Cursor makeSongCursor(final Context context, final String selection, - final boolean runSort) { + public static Cursor makeSongCursor(final Context context, final String selection, + final boolean runSort) { String selectionStatement = MusicUtils.MUSIC_ONLY_SELECTION; if (!TextUtils.isEmpty(selection)) { selectionStatement += " AND " + selection; @@ -178,7 +180,7 @@ public class SongLoader extends SectionCreator.SimpleListLoader { final String songSortOrder = PreferenceUtils.getInstance(context).getSongSortOrder(); Cursor cursor = context.getContentResolver().query(Audio.Media.EXTERNAL_CONTENT_URI, - new String[] { + new String[]{ /* 0 */ Audio.Media._ID, /* 1 */ @@ -198,7 +200,7 @@ public class SongLoader extends SectionCreator.SimpleListLoader { // if our sort is a localized-based sort, grab localized data from the store final SortParameter sortParameter = getSortParameter(songSortOrder); if (runSort && sortParameter != null && cursor != null) { - final boolean descending = MusicUtils.isSortOrderDesending(songSortOrder); + final boolean descending = MusicUtils.isSortOrderDescending(songSortOrder); return LocalizedStore.getInstance(context).getLocalizedSort(cursor, Audio.Media._ID, SortParameter.Song, sortParameter, descending, TextUtils.isEmpty(selection)); } diff --git a/src/org/lineageos/eleven/loaders/SortedCursor.java b/src/org/lineageos/eleven/loaders/SortedCursor.java index 1b97e48775bc8ec1e72208b6a242c8f1ed7579a7..7e1380e08e526fd13831a42bec8eb8192e170255 100644 --- a/src/org/lineageos/eleven/loaders/SortedCursor.java +++ b/src/org/lineageos/eleven/loaders/SortedCursor.java @@ -1,18 +1,19 @@ /* -* Copyright (C) 2014 The CyanogenMod Project -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ + * Copyright (C) 2014 The CyanogenMod Project + * Copyright (C) 2021 The LineageOS Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package org.lineageos.eleven.loaders; import android.database.AbstractCursor; @@ -34,19 +35,19 @@ public class SortedCursor extends AbstractCursor { // the map of external indices to internal indices private ArrayList mOrderedPositions; // this contains the ids that weren't found in the underlying cursor - private ArrayList mMissingIds; + private final ArrayList mMissingIds; // this contains the mapped cursor positions and afterwards the extra ids that weren't found private HashMap mMapCursorPositions; // extra we want to store with the cursor private ArrayList mExtraData; /** - * @param cursor to wrap - * @param order the list of unique ids in sorted order to display + * @param cursor to wrap + * @param order the list of unique ids in sorted order to display * @param columnName the column name of the id to look up in the internal cursor */ public SortedCursor(final Cursor cursor, final long[] order, final String columnName, - final List extraData) { + final List extraData) { if (cursor == null) { throw new IllegalArgumentException("Non-null cursor is needed"); } @@ -58,12 +59,13 @@ public class SortedCursor extends AbstractCursor { /** * This function populates mOrderedPositions with the cursor positions in the order based * on the order passed in - * @param order the target order of the internal cursor + * + * @param order the target order of the internal cursor * @param extraData Extra data we want to add to the cursor * @return returns the ids that aren't found in the underlying cursor */ - private ArrayList buildCursorPositionMapping(final long[] order, - final String columnName, final List extraData) { + private ArrayList buildCursorPositionMapping(final long[] order, final String columnName, + final List extraData) { ArrayList missingIds = new ArrayList<>(); mOrderedPositions = new ArrayList<>(mCursor.getCount()); diff --git a/src/org/lineageos/eleven/loaders/TopTracksLoader.java b/src/org/lineageos/eleven/loaders/TopTracksLoader.java index 7daf6223c3d64297de04170ba99dc3fe1ac24ae3..ce5e969afcdba6be7ba22bf62f8b340859b4edd4 100644 --- a/src/org/lineageos/eleven/loaders/TopTracksLoader.java +++ b/src/org/lineageos/eleven/loaders/TopTracksLoader.java @@ -1,19 +1,19 @@ /* -* Copyright (C) 2014 The CyanogenMod Project -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ - + * Copyright (C) 2014 The CyanogenMod Project + * Copyright (C) 2021 The LineageOS Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package org.lineageos.eleven.loaders; import android.content.Context; @@ -27,7 +27,7 @@ import org.lineageos.eleven.provider.SongPlayCount.SongPlayCountColumns; import java.util.ArrayList; /** - * Used to query {@link android.provider.MediaStore.Audio.Media.EXTERNAL_CONTENT_URI} and return + * Used to query MediaStore.Audio.Media.EXTERNAL_CONTENT_URI and return * a sorted list of songs based on either the TopTracks or the RecentSongs */ public class TopTracksLoader extends SongLoader { @@ -39,7 +39,7 @@ public class TopTracksLoader extends SongLoader { RecentSongs, } - protected QueryType mQueryType; + protected final QueryType mQueryType; public TopTracksLoader(final Context context, QueryType type) { super(context); @@ -60,8 +60,8 @@ public class TopTracksLoader extends SongLoader { if (retCursor != null) { ArrayList missingIds = retCursor.getMissingIds(); if (missingIds != null && missingIds.size() > 0) { - // for each unfound id, remove it from the database - // this codepath should only really be hit if the user removes songs + // for each not found id, remove it from the database + // this code-path should only really be hit if the user removes songs // outside of the Eleven app for (long id : missingIds) { if (mQueryType == QueryType.TopTracks) { @@ -78,53 +78,43 @@ public class TopTracksLoader extends SongLoader { /** * This creates a sorted cursor based on the top played results + * * @param context Android context * @return sorted cursor */ - public static final SortedCursor makeTopTracksCursor(final Context context) { + public static SortedCursor makeTopTracksCursor(final Context context) { // first get the top results ids from the internal database - Cursor songs = SongPlayCount.getInstance(context).getTopPlayedResults(NUMBER_OF_SONGS); - - try { + try (Cursor songs = SongPlayCount.getInstance(context) + .getTopPlayedResults(NUMBER_OF_SONGS)) { return makeSortedCursor(context, songs, songs.getColumnIndex(SongPlayCountColumns.ID)); - } finally { - if (songs != null) { - songs.close(); - songs = null; - } } } /** * This creates a sorted cursor based on the recently played tracks + * * @param context Android context * @return sorted cursor */ - public static final SortedCursor makeRecentTracksCursor(final Context context) { + public static SortedCursor makeRecentTracksCursor(final Context context) { // first get the top results ids from the internal database - Cursor songs = RecentStore.getInstance(context).queryRecentIds(null); - - try { + try (Cursor songs = RecentStore.getInstance(context).queryRecentIds(null)) { return makeSortedCursor(context, songs, songs.getColumnIndex(SongPlayCountColumns.ID)); - } finally { - if (songs != null) { - songs.close(); - songs = null; - } } } /** * This creates a sorted song cursor given a cursor that contains the sort order - * @param context Android context - * @param cursor This is the cursor used to determine the order of the ids + * + * @param context Android context + * @param cursor This is the cursor used to determine the order of the ids * @param idColumn the id column index of the cursor * @return a Sorted Cursor of songs */ - public static final SortedCursor makeSortedCursor(final Context context, final Cursor cursor, - final int idColumn) { + public static SortedCursor makeSortedCursor(final Context context, final Cursor cursor, + final int idColumn) { if (cursor != null && cursor.moveToFirst()) { // create the list of ids to select against StringBuilder selection = new StringBuilder(); @@ -143,7 +133,7 @@ public class TopTracksLoader extends SongLoader { id = cursor.getLong(idColumn); order[cursor.getPosition()] = id; - selection.append(String.valueOf(id)); + selection.append(id); } selection.append(")"); diff --git a/src/org/lineageos/eleven/loaders/WrappedAsyncTaskLoader.java b/src/org/lineageos/eleven/loaders/WrappedAsyncTaskLoader.java index b378b7a340f16b92e61b89fbd75e25a7d9b4000f..d6e9ef4f1b3abff3e6d564880990cfa6a032266e 100644 --- a/src/org/lineageos/eleven/loaders/WrappedAsyncTaskLoader.java +++ b/src/org/lineageos/eleven/loaders/WrappedAsyncTaskLoader.java @@ -1,4 +1,19 @@ - +/* + * Copyright (C) 2014 The CyanogenMod Project + * Copyright (C) 2021 The LineageOS Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package org.lineageos.eleven.loaders; import android.content.Context; @@ -24,22 +39,14 @@ public abstract class WrappedAsyncTaskLoader extends AsyncTaskLoader { super(context); } - /** - * {@inheritDoc} - */ @Override public void deliverResult(D data) { if (!isReset()) { this.mData = data; super.deliverResult(data); - } else { - // An asynchronous query came in while the loader is stopped } } - /** - * {@inheritDoc} - */ @Override protected void onStartLoading() { if (this.mData != null) { @@ -49,18 +56,12 @@ public abstract class WrappedAsyncTaskLoader extends AsyncTaskLoader { } } - /** - * {@inheritDoc} - */ @Override protected void onStopLoading() { // Attempt to cancel the current load task if possible cancelLoad(); } - /** - * {@inheritDoc} - */ @Override protected void onReset() { super.onReset(); diff --git a/src/org/lineageos/eleven/locale/LocaleChangeReceiver.java b/src/org/lineageos/eleven/locale/LocaleChangeReceiver.java index 37902f02e209b33fc70f7cb62b43d4e049b9ecde..f7b5aab405ecc09495d1ef35bd7591b5c2e3dc44 100644 --- a/src/org/lineageos/eleven/locale/LocaleChangeReceiver.java +++ b/src/org/lineageos/eleven/locale/LocaleChangeReceiver.java @@ -1,19 +1,19 @@ /* * Copyright (C) 2010 The Android Open Source Project + * Copyright (C) 2021 The LineageOS Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and - * limitations under the License + * limitations under the License. */ - package org.lineageos.eleven.locale; import android.content.BroadcastReceiver; diff --git a/src/org/lineageos/eleven/locale/LocaleSet.java b/src/org/lineageos/eleven/locale/LocaleSet.java index 4d75d0fc907fb798515e2e5adfdfc405744247fa..c450ca818a901a24f0a3678f217cee18e30c3cb6 100644 --- a/src/org/lineageos/eleven/locale/LocaleSet.java +++ b/src/org/lineageos/eleven/locale/LocaleSet.java @@ -1,5 +1,6 @@ /* * Copyright (C) 2014 The Android Open Source Project + * Copyright (C) 2021 The LineageOS Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -11,16 +12,16 @@ * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and - * limitations under the License + * limitations under the License. */ - package org.lineageos.eleven.locale; import android.text.TextUtils; -import androidx.annotation.VisibleForTesting; +import androidx.annotation.NonNull; import java.util.Locale; +import java.util.Objects; public class LocaleSet { private static final String CHINESE_LANGUAGE = Locale.CHINESE.getLanguage().toLowerCase(); @@ -58,7 +59,7 @@ public class LocaleSet { } public boolean isLocale(Locale locale) { - return mLocale == null ? (locale == null) : mLocale.equals(locale); + return Objects.equals(mLocale, locale); } public boolean isLocaleCJK() { @@ -70,6 +71,7 @@ public class LocaleSet { : mLanguage.equalsIgnoreCase(language); } + @NonNull public String toString() { return mLocale != null ? mLocale.toLanguageTag() : "(null)"; } @@ -102,12 +104,10 @@ public class LocaleSet { final String[] locales = localeString.split(";"); final Locale primaryLocale = Locale.forLanguageTag(locales[0]); // ICU tags undefined/unparseable locales "und" - if (primaryLocale != null && - !TextUtils.equals(primaryLocale.toLanguageTag(), "und")) { + if (!TextUtils.equals(primaryLocale.toLanguageTag(), "und")) { if (locales.length > 1 && locales[1] != null) { final Locale secondaryLocale = Locale.forLanguageTag(locales[1]); - if (secondaryLocale != null && - !TextUtils.equals(secondaryLocale.toLanguageTag(), "und")) { + if (!TextUtils.equals(secondaryLocale.toLanguageTag(), "und")) { return new LocaleSet(primaryLocale, secondaryLocale); } } @@ -123,7 +123,8 @@ public class LocaleSet { public LocaleSet(Locale primaryLocale, Locale secondaryLocale) { mPrimaryLocale = new LocaleWrapper(primaryLocale); mSecondaryLocale = new LocaleWrapper( - mPrimaryLocale.equals(secondaryLocale) ? null : secondaryLocale); + Objects.equals(mPrimaryLocale, new LocaleWrapper(secondaryLocale)) ? + null : secondaryLocale); } public LocaleSet normalize() { @@ -166,53 +167,6 @@ public class LocaleSet { return mSecondaryLocale.isLocale(locale); } - private static final String SCRIPT_SIMPLIFIED_CHINESE = "Hans"; - private static final String SCRIPT_TRADITIONAL_CHINESE = "Hant"; - - @VisibleForTesting - public static boolean isLocaleSimplifiedChinese(Locale locale) { - // language must match - if (locale == null || !TextUtils.equals(locale.getLanguage(), CHINESE_LANGUAGE)) { - return false; - } - // script is optional but if present must match - if (!TextUtils.isEmpty(locale.getScript())) { - return locale.getScript().equals(SCRIPT_SIMPLIFIED_CHINESE); - } - // if no script, must match known country - return locale.equals(Locale.SIMPLIFIED_CHINESE); - } - - public boolean isPrimaryLocaleSimplifiedChinese() { - return isLocaleSimplifiedChinese(getPrimaryLocale()); - } - - public boolean isSecondaryLocaleSimplifiedChinese() { - return isLocaleSimplifiedChinese(getSecondaryLocale()); - } - - @VisibleForTesting - public static boolean isLocaleTraditionalChinese(Locale locale) { - // language must match - if (locale == null || !TextUtils.equals(locale.getLanguage(), CHINESE_LANGUAGE)) { - return false; - } - // script is optional but if present must match - if (!TextUtils.isEmpty(locale.getScript())) { - return locale.getScript().equals(SCRIPT_TRADITIONAL_CHINESE); - } - // if no script, must match known country - return locale.equals(Locale.TRADITIONAL_CHINESE); - } - - public boolean isPrimaryLocaleTraditionalChinese() { - return isLocaleTraditionalChinese(getPrimaryLocale()); - } - - public boolean isSecondaryLocaleTraditionalChinese() { - return isLocaleTraditionalChinese(getSecondaryLocale()); - } - public boolean isPrimaryLocaleCJK() { return mPrimaryLocale.isLocaleCJK(); } diff --git a/src/org/lineageos/eleven/locale/LocaleSetManager.java b/src/org/lineageos/eleven/locale/LocaleSetManager.java index 8213296c79bec70e4351141382034df3ea0140de..ec1ae79a2f7545e9053bd3e7ad77f6b8edc99860 100644 --- a/src/org/lineageos/eleven/locale/LocaleSetManager.java +++ b/src/org/lineageos/eleven/locale/LocaleSetManager.java @@ -1,6 +1,7 @@ /* - * Copyright (C) 2014 The CyanogenMod Project * Copyright (C) 2009 The Android Open Source Project + * Copyright (C) 2014 The CyanogenMod Project + * Copyright (C) 2021 The LineageOS Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,7 +13,7 @@ * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and - * limitations under the License + * limitations under the License. */ package org.lineageos.eleven.locale; @@ -59,7 +60,7 @@ public class LocaleSetManager { .getProperty(PropertiesStore.DbProperties.ICU_VERSION); if (!String.valueOf(Build.VERSION.SDK_INT).equals(storedICUversion)) { Log.d(TAG, "ICU version has changed from: " + storedICUversion + " to " - + String.valueOf(Build.VERSION.SDK_INT)); + + Build.VERSION.SDK_INT); return true; } @@ -69,17 +70,20 @@ public class LocaleSetManager { /** * Sets up the locale set + * * @param localeSet value to set it to */ public void updateLocaleSet(LocaleSet localeSet) { Log.d(TAG, "Locale Changed from: " + mCurrentLocales + " to " + localeSet); mCurrentLocales = localeSet; + //noinspection AccessStaticViaInstance LocaleUtils.getInstance().setLocales(mCurrentLocales); } /** * This takes an old and new locale set and creates a combined locale set. If they share a * primary then the old one is returned + * * @return the combined locale set */ private static LocaleSet getCombinedLocaleSet(LocaleSet oldLocales, Locale newLocale) { diff --git a/src/org/lineageos/eleven/locale/LocaleUtils.java b/src/org/lineageos/eleven/locale/LocaleUtils.java index 60f038af73700d6a478afc8416a26f99e4d77a5a..16e18f7124333acf82e52c98655f20f955e9cd93 100644 --- a/src/org/lineageos/eleven/locale/LocaleUtils.java +++ b/src/org/lineageos/eleven/locale/LocaleUtils.java @@ -1,5 +1,6 @@ /* * Copyright (C) 2010 The Android Open Source Project + * Copyright (C) 2021 The LineageOS Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -11,24 +12,20 @@ * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and - * limitations under the License + * limitations under the License. */ - package org.lineageos.eleven.locale; import android.icu.text.AlphabeticIndex; import android.util.Log; -import androidx.annotation.VisibleForTesting; - import java.util.ArrayList; -import java.util.Iterator; import java.util.Locale; /** * This utility class provides specialized handling for locale specific * information: labels, name lookup keys. - * + *

* This class has been modified from ContactLocaleUtils.java for now to rip out * Chinese/Japanese specific Alphabetic Indexers because the MediaProvider's sort * is using a Collator sort which can result in confusing behavior, so for now we will @@ -52,17 +49,17 @@ public class LocaleUtils { /** * This class is the default implementation and should be the base class * for other locales. - * + *

* sortKey: same as name * nameLookupKeys: none * labels: uses ICU AlphabeticIndex for labels and extends by labeling - * phone numbers "#". Eg English labels are: [A-Z], #, " " + * phone numbers "#". Eg English labels are: [A-Z], #, " " */ private static class LocaleUtilsBase { private static final String EMPTY_STRING = ""; private static final String NUMBER_STRING = "#"; - protected final AlphabeticIndex.ImmutableIndex mAlphabeticIndex; + protected final AlphabeticIndex.ImmutableIndex mAlphabeticIndex; private final int mAlphabeticIndexBucketCount; private final int mNumberBucketIndex; @@ -80,29 +77,25 @@ public class LocaleUtils { // Cyrillic because their alphabets are complementary supersets // of Russian. final Locale secondaryLocale = locales.getSecondaryLocale(); - AlphabeticIndex ai = new AlphabeticIndex(locales.getPrimaryLocale()) - .setMaxLabelCount(300); + AlphabeticIndex ai = new AlphabeticIndex<>(locales.getPrimaryLocale()) + .setMaxLabelCount(300); if (secondaryLocale != null) { ai.addLabels(secondaryLocale); } mAlphabeticIndex = ai.addLabels(Locale.ENGLISH) - .addLabels(Locale.JAPANESE) - .addLabels(Locale.KOREAN) - .addLabels(LOCALE_THAI) - .addLabels(LOCALE_ARABIC) - .addLabels(LOCALE_HEBREW) - .addLabels(LOCALE_GREEK) - .addLabels(LOCALE_UKRAINIAN) - .addLabels(LOCALE_SERBIAN) - .buildImmutableIndex(); + .addLabels(Locale.JAPANESE) + .addLabels(Locale.KOREAN) + .addLabels(LOCALE_THAI) + .addLabels(LOCALE_ARABIC) + .addLabels(LOCALE_HEBREW) + .addLabels(LOCALE_GREEK) + .addLabels(LOCALE_UKRAINIAN) + .addLabels(LOCALE_SERBIAN) + .buildImmutableIndex(); mAlphabeticIndexBucketCount = mAlphabeticIndex.getBucketCount(); mNumberBucketIndex = mAlphabeticIndexBucketCount - 1; } - public String getSortKey(String name) { - return name; - } - /** * Returns the bucket index for the specified string. AlphabeticIndex * sorts strings into buckets numbered in order from 0 to N, where the @@ -127,9 +120,9 @@ public class LocaleUtils { prefixIsNumeric = true; break; } else if (!Character.isSpaceChar(codePoint) && - codePoint != '+' && codePoint != '(' && - codePoint != ')' && codePoint != '.' && - codePoint != '-' && codePoint != '#') { + codePoint != '+' && codePoint != '(' && + codePoint != ')' && codePoint != '.' && + codePoint != '-' && codePoint != '#') { break; } offset += Character.charCount(codePoint); @@ -172,15 +165,10 @@ public class LocaleUtils { return mAlphabeticIndex.getBucket(bucketIndex).getLabel(); } - @SuppressWarnings("unused") - public Iterator getNameLookupKeys(String name, int nameStyle) { - return null; - } - public ArrayList getLabels() { final int bucketCount = getBucketCount(); final ArrayList labels = new ArrayList<>(bucketCount); - for(int i = 0; i < bucketCount; ++i) { + for (int i = 0; i < bucketCount; ++i) { labels.add(getBucketLabel(i)); } return labels; @@ -193,12 +181,7 @@ public class LocaleUtils { private final LocaleUtilsBase mUtils; private LocaleUtils(LocaleSet locales) { - if (locales == null) { - mLocales = LocaleSet.getDefault(); - } else { - mLocales = locales; - } - + mLocales = locales == null ? LocaleSet.getDefault() : locales; mUtils = new LocaleUtilsBase(mLocales); Log.i(TAG, "AddressBook Labels [" + mLocales.toString() + "]: " + getLabels().toString()); @@ -215,29 +198,16 @@ public class LocaleUtils { return sSingleton; } - @VisibleForTesting - public static synchronized void setLocale(Locale locale) { - setLocales(new LocaleSet(locale)); - } - public static synchronized void setLocales(LocaleSet locales) { if (sSingleton == null || !sSingleton.isLocale(locales)) { sSingleton = new LocaleUtils(locales); } } - public String getSortKey(String name, int nameStyle) { - return mUtils.getSortKey(name); - } - public int getBucketIndex(String name) { return mUtils.getBucketIndex(name); } - public int getBucketCount() { - return mUtils.getBucketCount(); - } - public String getBucketLabel(int bucketIndex) { return mUtils.getBucketLabel(bucketIndex); } diff --git a/src/org/lineageos/eleven/menu/BasePlaylistDialog.java b/src/org/lineageos/eleven/menu/BasePlaylistDialog.java index 69a20eb2ecde13e99d991f7327d425f6ee8b0b8b..5c4e1a6c7ef1444c8a89741c78576a1b10f4b398 100644 --- a/src/org/lineageos/eleven/menu/BasePlaylistDialog.java +++ b/src/org/lineageos/eleven/menu/BasePlaylistDialog.java @@ -1,7 +1,7 @@ /* * Copyright (C) 2012 Andrew Neal * Copyright (C) 2014 The CyanogenMod Project - * Copyright (C) 2019 The LineageOS Project + * Copyright (C) 2019-2021 The LineageOS Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -15,7 +15,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package org.lineageos.eleven.menu; import android.app.AlertDialog; @@ -28,6 +27,7 @@ import android.widget.Button; import android.widget.EditText; import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import androidx.core.content.ContextCompat; import androidx.fragment.app.DialogFragment; @@ -61,7 +61,7 @@ public abstract class BasePlaylistDialog extends DialogFragment implements TextW @NonNull @Override - public Dialog onCreateDialog(@NonNull final Bundle savedInstanceState) { + public Dialog onCreateDialog(@Nullable final Bundle savedInstanceState) { mPlaylistDialog = new AlertDialog.Builder(getActivity()).create(); mPlaylistDialog.setButton(Dialog.BUTTON_POSITIVE, getString(R.string.save), (dialog, which) -> { @@ -109,7 +109,7 @@ public abstract class BasePlaylistDialog extends DialogFragment implements TextW @Override public void beforeTextChanged(final CharSequence s, final int start, final int count, - final int after) { + final int after) { /* Nothing to do */ } diff --git a/src/org/lineageos/eleven/menu/ConfirmDialog.java b/src/org/lineageos/eleven/menu/ConfirmDialog.java index befbc781c23ab3589e26a2481b03d96463b26707..b745a8ecbdec07423f57969bbb004dfbf2a0230b 100644 --- a/src/org/lineageos/eleven/menu/ConfirmDialog.java +++ b/src/org/lineageos/eleven/menu/ConfirmDialog.java @@ -1,45 +1,49 @@ /* -* Copyright (C) 2014 The CyanogenMod Project -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ - + * Copyright (C) 2014 The CyanogenMod Project + * Copyright (C) 2021 The LineageOS Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package org.lineageos.eleven.menu; import android.app.AlertDialog; import android.app.Dialog; -import android.content.DialogInterface; -import android.content.DialogInterface.OnClickListener; import android.os.Bundle; +import androidx.annotation.NonNull; import androidx.fragment.app.DialogFragment; import androidx.fragment.app.Fragment; import org.lineageos.eleven.R; -/** Dialog to confirm a non-reversible action */ +/** + * Dialog to confirm a non-reversible action + */ public class ConfirmDialog extends DialogFragment { private static final String TITLE_ID = "titleId"; private static final String OK_ID = "okId"; public interface ConfirmCallback { - public void confirmOk(int requestCode); + void confirmOk(int requestCode); } - public ConfirmDialog() {} + public ConfirmDialog() { + } - /** @param title describes action user is confirming - * @param okId text for Ok button */ + /** + * @param titleId describes action user is confirming + * @param okId text for Ok button + */ public static void show(Fragment target, int requestCode, int titleId, int okId) { final ConfirmDialog frag = new ConfirmDialog(); final Bundle args = new Bundle(); @@ -47,29 +51,25 @@ public class ConfirmDialog extends DialogFragment { args.putInt(OK_ID, okId); frag.setArguments(args); frag.setTargetFragment(target, requestCode); - frag.show(target.getFragmentManager(), "ConfirmDialog"); + frag.show(target.getChildFragmentManager(), "ConfirmDialog"); } + @NonNull @Override public Dialog onCreateDialog(final Bundle savedInstanceState) { Bundle args = getArguments(); return new AlertDialog.Builder(getActivity()) - .setTitle(args.getInt(TITLE_ID)) - .setMessage(R.string.cannot_be_undone) - .setPositiveButton(args.getInt(OK_ID), new OnClickListener() { - @Override - public void onClick(final DialogInterface dialog, final int which) { - Fragment target = getTargetFragment(); - if (target instanceof ConfirmCallback) { - ((ConfirmCallback)target).confirmOk(getTargetRequestCode()); - } - dialog.dismiss(); - } - }).setNegativeButton(R.string.cancel, new OnClickListener() { - @Override - public void onClick(final DialogInterface dialog, final int which) { - dialog.dismiss(); - } - }).create(); + .setTitle(args == null ? R.string.app_name : args.getInt(TITLE_ID)) + .setMessage(R.string.cannot_be_undone) + .setPositiveButton(args == null ? android.R.string.ok : args.getInt(OK_ID), + (dialog, which) -> { + Fragment target = getTargetFragment(); + if (target instanceof ConfirmCallback) { + ((ConfirmCallback) target).confirmOk(getTargetRequestCode()); + } + dialog.dismiss(); + }) + .setNegativeButton(R.string.cancel, (dialog, which) -> dialog.dismiss()) + .create(); } -} \ No newline at end of file +} diff --git a/src/org/lineageos/eleven/menu/CreateNewPlaylist.java b/src/org/lineageos/eleven/menu/CreateNewPlaylist.java index dd0db7cf685398a76253a27b889e8083f850b4bb..c25c88add6371c4271fed0fb093a9030200b8439 100644 --- a/src/org/lineageos/eleven/menu/CreateNewPlaylist.java +++ b/src/org/lineageos/eleven/menu/CreateNewPlaylist.java @@ -1,7 +1,7 @@ /* * Copyright (C) 2012 Andrew Neal * Copyright (C) 2014 The CyanogenMod Project - * Copyright (C) 2019 The LineageOS Project + * Copyright (C) 2019-2021 The LineageOS Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -15,7 +15,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package org.lineageos.eleven.menu; import android.app.Activity; @@ -58,26 +57,36 @@ public class CreateNewPlaylist extends BasePlaylistDialog { ? savedInstanceState.getString(EXTRA_DEFAULT_NAME) : makePlaylistName(); if (mDefaultName == null) { - getDialog().dismiss(); + final Dialog dialog = getDialog(); + if (dialog != null) { + dialog.dismiss(); + } return; } - mPlaylistList = getArguments().getLongArray(EXTRA_PLAYLIST_LIST); + final Bundle args = getArguments(); + mPlaylistList = args == null ? new long[]{} : args.getLongArray(EXTRA_PLAYLIST_LIST); mPrompt = getString(R.string.create_playlist_prompt); } @Override public void onSaveClick() { final String playlistName = mPlaylist.getText().toString(); - if (!TextUtils.isEmpty(playlistName)) { - final int playlistId = (int) MusicUtils.getIdForPlaylist(getActivity(), playlistName); - if (playlistId >= 0) { - MusicUtils.clearPlaylist(getActivity(), playlistId); - MusicUtils.addToPlaylist(getActivity(), mPlaylistList, playlistId); - } else { - final long newId = MusicUtils.createPlaylist(getActivity(), playlistName); - MusicUtils.addToPlaylist(getActivity(), mPlaylistList, newId); - } - getDialog().dismiss(); + final Activity activity = getActivity(); + if (activity == null || TextUtils.isEmpty(playlistName)) { + return; + } + + final int playlistId = (int) MusicUtils.getIdForPlaylist(getActivity(), playlistName); + if (playlistId >= 0) { + MusicUtils.clearPlaylist(activity, playlistId); + MusicUtils.addToPlaylist(activity, mPlaylistList, playlistId); + } else { + final long newId = MusicUtils.createPlaylist(getActivity(), playlistName); + MusicUtils.addToPlaylist(activity, mPlaylistList, newId); + } + final Dialog dialog = getDialog(); + if (dialog != null) { + dialog.dismiss(); } } @@ -124,8 +133,8 @@ public class CreateNewPlaylist extends BasePlaylistDialog { done = true; cursor.moveToFirst(); while (!cursor.isAfterLast()) { - final String playlistname = cursor.getString(0); - if (playlistname.compareToIgnoreCase(suggestedname) == 0) { + final String playlistName = cursor.getString(0); + if (playlistName.compareToIgnoreCase(suggestedname) == 0) { suggestedname = String.format(template, num++); done = false; } diff --git a/src/org/lineageos/eleven/menu/DeleteDialog.java b/src/org/lineageos/eleven/menu/DeleteDialog.java index 0ca366b9d8b0459a9e132bf144449a8c7e274c3c..a0c892458d657b70d5417806bb54f5cadecc9e34 100644 --- a/src/org/lineageos/eleven/menu/DeleteDialog.java +++ b/src/org/lineageos/eleven/menu/DeleteDialog.java @@ -1,24 +1,27 @@ /* * Copyright (C) 2012 Andrew Neal * Copyright (C) 2014 The CyanogenMod Project - * Licensed under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law - * or agreed to in writing, software distributed under the License is - * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the specific language - * governing permissions and limitations under the License. + * Copyright (C) 2021 The LineageOS Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ - package org.lineageos.eleven.menu; import android.app.AlertDialog; import android.app.Dialog; -import android.content.DialogInterface; -import android.content.DialogInterface.OnClickListener; import android.os.Bundle; +import androidx.annotation.NonNull; import androidx.fragment.app.DialogFragment; import org.lineageos.eleven.Config; @@ -37,7 +40,7 @@ import org.lineageos.eleven.utils.MusicUtils; public class DeleteDialog extends DialogFragment { public interface DeleteDialogCallback { - public void onDelete(long[] id); + void onDelete(long[] id); } /** @@ -51,7 +54,7 @@ public class DeleteDialog extends DialogFragment { private ImageFetcher mFetcher; /** - * Empty constructor as per the {@link Fragment} documentation + * Empty constructor as per the Fragment documentation */ public DeleteDialog() { } @@ -59,10 +62,11 @@ public class DeleteDialog extends DialogFragment { /** * @param title The title of the artist, album, or song to delete * @param items The item(s) to delete - * @param key The key used to remove items from the cache. + * @param key The key used to remove items from the cache. * @return A new instance of the dialog */ - public static DeleteDialog newInstance(final String title, final long[] items, final String key) { + public static DeleteDialog newInstance(final String title, final long[] items, + final String key) { final DeleteDialog frag = new DeleteDialog(); final Bundle args = new Bundle(); args.putString(Config.NAME, title); @@ -72,44 +76,34 @@ public class DeleteDialog extends DialogFragment { return frag; } - /** - * {@inheritDoc} - */ + @NonNull @Override public Dialog onCreateDialog(final Bundle savedInstanceState) { final String delete = getString(R.string.context_menu_delete); final Bundle arguments = getArguments(); // Get the image cache key - final String key = arguments.getString("cachekey"); + final String key = arguments == null ? "" : arguments.getString("cachekey"); // Get the track(s) to delete - mItemList = arguments.getLongArray("items"); + mItemList = arguments == null ? new long[]{} : arguments.getLongArray("items"); // Get the dialog title - final String title = arguments.getString(Config.NAME); + final String title = arguments == null ? "" : arguments.getString(Config.NAME); final String dialogTitle = getString(R.string.delete_dialog_title, title); // Initialize the image cache mFetcher = ElevenUtils.getImageFetcher(getActivity()); // Build the dialog return new AlertDialog.Builder(getActivity()).setTitle(dialogTitle) .setMessage(R.string.cannot_be_undone) - .setPositiveButton(delete, new OnClickListener() { - - @Override - public void onClick(final DialogInterface dialog, final int which) { - // Remove the items from the image cache - mFetcher.removeFromCache(key); - // Delete the selected item(s) - MusicUtils.deleteTracks(getActivity(), mItemList); - if (getActivity() instanceof DeleteDialogCallback) { - ((DeleteDialogCallback)getActivity()).onDelete(mItemList); - } - dialog.dismiss(); - } - }).setNegativeButton(R.string.cancel, new OnClickListener() { - - @Override - public void onClick(final DialogInterface dialog, final int which) { - dialog.dismiss(); + .setPositiveButton(delete, (dialog, which) -> { + // Remove the items from the image cache + mFetcher.removeFromCache(key); + // Delete the selected item(s) + MusicUtils.deleteTracks(getActivity(), mItemList); + if (getActivity() instanceof DeleteDialogCallback) { + ((DeleteDialogCallback) getActivity()).onDelete(mItemList); } - }).create(); + dialog.dismiss(); + }) + .setNegativeButton(R.string.cancel, (dialog, which) -> dialog.dismiss()) + .create(); } } diff --git a/src/org/lineageos/eleven/menu/FragmentMenuItems.java b/src/org/lineageos/eleven/menu/FragmentMenuItems.java index 7dca614d4cf87a073a698aee2e94cb66344b22fd..462d19e797b381f3d6ae91581103e7c74032f429 100644 --- a/src/org/lineageos/eleven/menu/FragmentMenuItems.java +++ b/src/org/lineageos/eleven/menu/FragmentMenuItems.java @@ -1,14 +1,19 @@ /* * Copyright (C) 2012 Andrew Neal * Copyright (C) 2014 The CyanogenMod Project - * Licensed under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law - * or agreed to in writing, software distributed under the License is - * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the specific language - * governing permissions and limitations under the License. + * Copyright (C) 2021 The LineageOS Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package org.lineageos.eleven.menu; @@ -19,24 +24,24 @@ package org.lineageos.eleven.menu; * _and_ to determine the sort order of the items. */ public interface FragmentMenuItems { - int PLAY_SELECTION = 10; // play the selected song, album, etc. - int PLAY_NEXT = 20; // queue a track to be played next - int PLAY_ALBUM = 25; // play the album that this track belongs to + int PLAY_SELECTION = 10; // play the selected song, album, etc. + int PLAY_NEXT = 20; // queue a track to be played next + int PLAY_ALBUM = 25; // play the album that this track belongs to // SHUFFLE = 30 // defined in res/menu - int ADD_TO_QUEUE = 40; // add to end of current queue - int ADD_TO_PLAYLIST = 50; // append to a playlist - int REMOVE_FROM_QUEUE = 60; // remove track from play queue - int REMOVE_FROM_PLAYLIST= 70; // remove track from playlist - int REMOVE_FROM_RECENT = 80; // remove track from recently played list - int RENAME_PLAYLIST = 90; // change name of playlist - int MORE_BY_ARTIST = 100; // jump to artist detail page - int USE_AS_RINGTONE = 110; // set track as ringtone - int DELETE = 120; // delete track from device - int NEW_PLAYLIST = 130; // create new playlist - also in res/menu! - int PLAYLIST_SELECTED = 140; // this is used for existing playlists - int CHANGE_IMAGE = 150; // set new art for artist/album + int ADD_TO_QUEUE = 40; // add to end of current queue + int ADD_TO_PLAYLIST = 50; // append to a playlist + int REMOVE_FROM_QUEUE = 60; // remove track from play queue + int REMOVE_FROM_PLAYLIST = 70; // remove track from playlist + int REMOVE_FROM_RECENT = 80; // remove track from recently played list + int RENAME_PLAYLIST = 90; // change name of playlist + int MORE_BY_ARTIST = 100; // jump to artist detail page + int USE_AS_RINGTONE = 110; // set track as ringtone + int DELETE = 120; // delete track from device + int NEW_PLAYLIST = 130; // create new playlist - also in res/menu! + int PLAYLIST_SELECTED = 140; // this is used for existing playlists + int CHANGE_IMAGE = 150; // set new art for artist/album // not currently in use - int FETCH_ARTIST_IMAGE = 200; - int FETCH_ALBUM_ART = 210; -} \ No newline at end of file + int FETCH_ARTIST_IMAGE = 200; + int FETCH_ALBUM_ART = 210; +} diff --git a/src/org/lineageos/eleven/menu/PhotoSelectionDialog.java b/src/org/lineageos/eleven/menu/PhotoSelectionDialog.java index d232520252b2952d3b3c5974e565a1cc52bce94d..41d5a0245701ba6dfe756ac24ced7690cc7ac10f 100644 --- a/src/org/lineageos/eleven/menu/PhotoSelectionDialog.java +++ b/src/org/lineageos/eleven/menu/PhotoSelectionDialog.java @@ -1,7 +1,7 @@ /* * Copyright (C) 2012 Andrew Neal * Copyright (C) 2014 The CyanogenMod Project - * Copyright (C) 2020 The LineageOS Project + * Copyright (C) 2020-2021 The LineageOS Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -15,30 +15,26 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package org.lineageos.eleven.menu; import android.app.AlertDialog; import android.app.Dialog; -import android.content.DialogInterface; import android.os.Bundle; import android.widget.ArrayAdapter; import android.widget.ListAdapter; +import androidx.annotation.NonNull; import androidx.fragment.app.DialogFragment; import org.lineageos.eleven.Config; import org.lineageos.eleven.R; import org.lineageos.eleven.ui.activities.HomeActivity; -import org.lineageos.eleven.utils.Lists; import org.lineageos.eleven.utils.MusicUtils; -import java.util.ArrayList; - /** * Used when the user requests to modify Album art or Artist image - * It provides an easy interface for them to choose a new image, use the old - * image, or search Google for one. + * It provides an easy interface for them to choose a new image or use the old + * image. * * @author Andrew Neal (andrewdneal@gmail.com) */ @@ -46,103 +42,60 @@ public class PhotoSelectionDialog extends DialogFragment { private static final int NEW_PHOTO = 0; - private static final int OLD_PHOTO = 1; - - private final ArrayList mChoices = Lists.newArrayList(); - - private static ProfileType mProfileType; + private static final int DEFAULT_PHOTO = 1; private String mKey; /** - * Empty constructor as per the {@link Fragment} documentation + * Empty constructor as per the Fragment documentation */ public PhotoSelectionDialog() { } /** * @param title The dialog title. - * @param type Either Artist or Album - * @param key key to query ImageFetcher + * @param key key to query ImageFetcher * @return A new instance of the dialog. */ - public static PhotoSelectionDialog newInstance(final String title, final ProfileType type, - String key) { + public static PhotoSelectionDialog newInstance(final String title, String key) { final PhotoSelectionDialog frag = new PhotoSelectionDialog(); final Bundle args = new Bundle(); args.putString(Config.NAME, title); frag.setArguments(args); - mProfileType = type; frag.mKey = key; return frag; } - /** - * {@inheritDoc} - */ + @NonNull @Override public Dialog onCreateDialog(final Bundle savedInstanceState) { - final String title = getArguments().getString(Config.NAME); - switch (mProfileType) { - case ARTIST: - setArtistChoices(); - break; - case ALBUM: - setAlbumChoices(); - break; - case OTHER: - setOtherChoices(); - break; - default: - break; - } + final Bundle args = getArguments(); + final String title = args == null ? "" : args.getString(Config.NAME); + final String[] choices = new String[2]; + // Select a photo from the gallery + choices[NEW_PHOTO] = getString(R.string.new_photo); + // Default photo + choices[DEFAULT_PHOTO] = getString(R.string.use_default); + // Dialog item Adapter final HomeActivity activity = (HomeActivity) getActivity(); final ListAdapter adapter = new ArrayAdapter<>(activity, - R.layout.custom_select_dialog_item, mChoices); + R.layout.custom_select_dialog_item, choices); return new AlertDialog.Builder(activity).setTitle(title) .setAdapter(adapter, (dialog, which) -> { switch (which) { case NEW_PHOTO: - activity.selectNewPhoto(mKey); + if (activity != null) { + activity.selectNewPhoto(mKey); + } break; - case OLD_PHOTO: + case DEFAULT_PHOTO: MusicUtils.selectOldPhoto(activity, mKey); break; default: break; } - }).create(); - } - - /** - * Adds the choices for the artist profile image. - */ - private void setArtistChoices() { - // Select a photo from the gallery - mChoices.add(NEW_PHOTO, getString(R.string.new_photo)); - } - - /** - * Adds the choices for the album profile image. - */ - private void setAlbumChoices() { - // Select a photo from the gallery - mChoices.add(NEW_PHOTO, getString(R.string.new_photo)); - } - - /** - * Adds the choices for the genre and playlist images. - */ - private void setOtherChoices() { - // Select a photo from the gallery - mChoices.add(NEW_PHOTO, getString(R.string.new_photo)); - } - - /** - * Easily detect the MIME type - */ - public enum ProfileType { - ARTIST, ALBUM, ProfileType, OTHER + }) + .create(); } } diff --git a/src/org/lineageos/eleven/menu/RenamePlaylist.java b/src/org/lineageos/eleven/menu/RenamePlaylist.java index cb5f880ae6301e2c9f9c6cef6c1c34b68343956b..99b670ca066f9f3a3e30ef9c9c3ecd4f499c4356 100644 --- a/src/org/lineageos/eleven/menu/RenamePlaylist.java +++ b/src/org/lineageos/eleven/menu/RenamePlaylist.java @@ -1,7 +1,7 @@ /* * Copyright (C) 2012 Andrew Neal * Copyright (C) 2014 The CyanogenMod Project - * Copyright (C) 2019 The LineageOS Project + * Copyright (C) 2019-2021 The LineageOS Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -15,13 +15,15 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package org.lineageos.eleven.menu; +import android.app.Activity; import android.app.Dialog; import android.content.ContentResolver; +import android.content.ContentUris; import android.content.ContentValues; import android.os.Bundle; +import android.net.Uri; import android.provider.MediaStore; import android.provider.MediaStore.Audio; import android.text.Editable; @@ -60,15 +62,16 @@ public class RenamePlaylist extends BasePlaylistDialog { @Override public void initialize(final Bundle savedInstanceState) { + final Bundle args = getArguments(); mRenameId = savedInstanceState != null ? savedInstanceState.getLong(EXTRA_RENAME) - : getArguments().getLong(EXTRA_RENAME, -1); + : args == null ? -1 : args.getLong(EXTRA_RENAME, -1); final String originalName = MusicUtils.getNameForPlaylist(getContext(), mRenameId); mDefaultName = savedInstanceState != null ? savedInstanceState.getString(EXTRA_DEFAULT_NAME) : originalName; if (mRenameId < 0 || originalName == null || mDefaultName == null) { - getDialog().dismiss(); + dismissDialog(); return; } mPrompt = getString(R.string.create_playlist_prompt); @@ -77,15 +80,20 @@ public class RenamePlaylist extends BasePlaylistDialog { @Override public void onSaveClick() { final String playlistName = mPlaylist.getText().toString(); - if (!TextUtils.isEmpty(playlistName)) { - final ContentResolver resolver = getActivity().getContentResolver(); - final ContentValues values = new ContentValues(1); - values.put(Audio.Playlists.NAME, playlistName); - resolver.update(Audio.Playlists.EXTERNAL_CONTENT_URI, values, - MediaStore.Audio.Playlists._ID + "=?", new String[]{ - String.valueOf(mRenameId) - }); - getDialog().dismiss(); + final Activity activity = getActivity(); + if (activity == null || TextUtils.isEmpty(playlistName)) { + return; + } + final ContentResolver resolver = activity.getContentResolver(); + final Uri uri = ContentUris.withAppendedId( + MediaStore.Audio.Playlists.EXTERNAL_CONTENT_URI, + mRenameId); + final ContentValues values = new ContentValues(1); + values.put(Audio.Playlists.NAME, playlistName); + resolver.update(uri, values, null, null); + final Dialog dialog = getDialog(); + if (dialog != null) { + dialog.dismiss(); } } @@ -108,4 +116,11 @@ public class RenamePlaylist extends BasePlaylistDialog { } } } + + private void dismissDialog() { + final Dialog dialog = getDialog(); + if (dialog != null) { + dialog.dismiss(); + } + } } diff --git a/src/org/lineageos/eleven/model/Album.java b/src/org/lineageos/eleven/model/Album.java index 055df9fd895b85086427f2583f44475230901e11..17ffbed64a551f513c50203074f8626a8d932257 100644 --- a/src/org/lineageos/eleven/model/Album.java +++ b/src/org/lineageos/eleven/model/Album.java @@ -1,19 +1,26 @@ /* * Copyright (C) 2012 Andrew Neal * Copyright (C) 2014 The CyanogenMod Project - * Licensed under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law - * or agreed to in writing, software distributed under the License is - * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the specific language - * governing permissions and limitations under the License. + * Copyright (C) 2021 The LineageOS Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package org.lineageos.eleven.model; -import android.text.TextUtils; +import androidx.annotation.NonNull; + +import java.util.Objects; /** * A class that represents an album. @@ -25,45 +32,39 @@ public class Album { /** * The unique Id of the album */ - public long mAlbumId; + public final long mAlbumId; /** * The name of the album */ - public String mAlbumName; + public final String mAlbumName; /** * The album artist */ - public String mArtistName; + public final String mArtistName; /** * The number of songs in the album */ - public int mSongNumber; + public final int mSongNumber; /** * The year the album was released */ - public String mYear; - - /** - * Bucket label for the name - may not necessarily be the name - for example albums sorted by - * artists would be the artist bucket label and not the album name bucket label - */ - public String mBucketLabel; + public final String mYear; /** * Constructor of Album * - * @param albumId The Id of the album - * @param albumName The name of the album + * @param albumId The Id of the album + * @param albumName The name of the album * @param artistName The album artist * @param songNumber The number of songs in the album - * @param albumYear The year the album was released + * @param albumYear The year the album was released */ public Album(final long albumId, final String albumName, final String artistName, - final int songNumber, final String albumYear) { + final int songNumber, final String albumYear) { super(); mAlbumId = albumId; mAlbumName = albumName; @@ -72,60 +73,26 @@ public class Album { mYear = albumYear; } - /** - * {@inheritDoc} - */ @Override - public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result + (int) mAlbumId; - result = prime * result + (mAlbumName == null ? 0 : mAlbumName.hashCode()); - result = prime * result + (mArtistName == null ? 0 : mArtistName.hashCode()); - result = prime * result + mSongNumber; - result = prime * result + (mYear == null ? 0 : mYear.hashCode()); - return result; + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + Album album = (Album) o; + return mAlbumId == album.mAlbumId && + mSongNumber == album.mSongNumber && + Objects.equals(mAlbumName, album.mAlbumName) && + Objects.equals(mArtistName, album.mArtistName) && + Objects.equals(mYear, album.mYear); } - /** - * {@inheritDoc} - */ @Override - public boolean equals(final Object obj) { - if (this == obj) { - return true; - } - if (obj == null) { - return false; - } - if (getClass() != obj.getClass()) { - return false; - } - final Album other = (Album)obj; - if (mAlbumId != other.mAlbumId) { - return false; - } - if (!TextUtils.equals(mAlbumName, other.mAlbumName)) { - return false; - } - if (!TextUtils.equals(mArtistName, other.mArtistName)) { - return false; - } - if (mSongNumber != other.mSongNumber) { - return false; - } - if (!TextUtils.equals(mYear, other.mYear)) { - return false; - } - return true; + public int hashCode() { + return Objects.hash(mAlbumId, mAlbumName, mArtistName, mSongNumber, mYear); } - /** - * {@inheritDoc} - */ + @NonNull @Override public String toString() { return mAlbumName; } - } diff --git a/src/org/lineageos/eleven/model/AlbumArtistDetails.java b/src/org/lineageos/eleven/model/AlbumArtistDetails.java index 59c39b750874e27eef73c5a49028ae8beaca9d76..d577d88a45765ea8589510e7e53dbbcb73cc1b6c 100644 --- a/src/org/lineageos/eleven/model/AlbumArtistDetails.java +++ b/src/org/lineageos/eleven/model/AlbumArtistDetails.java @@ -1,18 +1,19 @@ /* -* Copyright (C) 2014 The CyanogenMod Project -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ + * Copyright (C) 2014 The CyanogenMod Project + * Copyright (C) 2021 The LineageOS Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package org.lineageos.eleven.model; /** @@ -23,4 +24,4 @@ public class AlbumArtistDetails { public long mAlbumId; public String mAlbumName; public String mArtistName; -} \ No newline at end of file +} diff --git a/src/org/lineageos/eleven/model/Artist.java b/src/org/lineageos/eleven/model/Artist.java index ca6a0401f77274cc03a27c5fae16cf7e6da72fd9..64c1997a189bcb14106b7428d5c7cd8d95559d7c 100644 --- a/src/org/lineageos/eleven/model/Artist.java +++ b/src/org/lineageos/eleven/model/Artist.java @@ -1,19 +1,26 @@ /* * Copyright (C) 2012 Andrew Neal * Copyright (C) 2014 The CyanogenMod Project - * Licensed under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law - * or agreed to in writing, software distributed under the License is - * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the specific language - * governing permissions and limitations under the License. + * Copyright (C) 2021 The LineageOS Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package org.lineageos.eleven.model; -import android.text.TextUtils; +import androidx.annotation.NonNull; + +import java.util.Objects; /** * A class that represents an artist. @@ -25,22 +32,22 @@ public class Artist { /** * The unique Id of the artist */ - public long mArtistId; + public final long mArtistId; /** * The artist name */ - public String mArtistName; + public final String mArtistName; /** * The number of albums for the artist */ - public int mAlbumNumber; + public final int mAlbumNumber; /** * The number of songs for the artist */ - public int mSongNumber; + public final int mSongNumber; /** * Bucket label for the artist name if it exists @@ -50,13 +57,13 @@ public class Artist { /** * Constructor of Artist * - * @param artistId The Id of the artist - * @param artistName The artist name - * @param songNumber The number of songs for the artist + * @param artistId The Id of the artist + * @param artistName The artist name + * @param songNumber The number of songs for the artist * @param albumNumber The number of albums for the artist */ public Artist(final long artistId, final String artistName, final int songNumber, - final int albumNumber) { + final int albumNumber) { super(); mArtistId = artistId; mArtistName = artistName; @@ -64,56 +71,25 @@ public class Artist { mAlbumNumber = albumNumber; } - /** - * {@inheritDoc} - */ @Override - public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result + mAlbumNumber; - result = prime * result + (int) mArtistId; - result = prime * result + (mArtistName == null ? 0 : mArtistName.hashCode()); - result = prime * result + mSongNumber; - return result; + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + Artist artist = (Artist) o; + return mArtistId == artist.mArtistId && + mAlbumNumber == artist.mAlbumNumber && + mSongNumber == artist.mSongNumber && + Objects.equals(mArtistName, artist.mArtistName); } - /** - * {@inheritDoc} - */ @Override - public boolean equals(final Object obj) { - if (this == obj) { - return true; - } - if (obj == null) { - return false; - } - if (getClass() != obj.getClass()) { - return false; - } - final Artist other = (Artist)obj; - if (mAlbumNumber != other.mAlbumNumber) { - return false; - } - if (mArtistId != other.mArtistId) { - return false; - } - if (!TextUtils.equals(mArtistName, other.mArtistName)) { - return false; - } - if (mSongNumber != other.mSongNumber) { - return false; - } - return true; + public int hashCode() { + return Objects.hash(mArtistId, mArtistName, mAlbumNumber, mSongNumber); } - /** - * {@inheritDoc} - */ + @NonNull @Override public String toString() { return mArtistName; } - } diff --git a/src/org/lineageos/eleven/model/Genre.java b/src/org/lineageos/eleven/model/Genre.java deleted file mode 100644 index 7842e0236ebd02214c648a8a021f37748a279e39..0000000000000000000000000000000000000000 --- a/src/org/lineageos/eleven/model/Genre.java +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Copyright (C) 2012 Andrew Neal - * Copyright (C) 2014 The CyanogenMod Project - * Licensed under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law - * or agreed to in writing, software distributed under the License is - * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ - -package org.lineageos.eleven.model; - -import android.text.TextUtils; - -/** - * A class that represents a genre. - * - * @author Andrew Neal (andrewdneal@gmail.com) - */ -public class Genre { - - /** - * The unique Id of the genre - */ - public long mGenreId; - - /** - * The genre name - */ - public String mGenreName; - - /** - * Constructor of Genre - * - * @param genreId The Id of the genre - * @param genreName The genre name - */ - public Genre(final long genreId, final String genreName) { - super(); - mGenreId = genreId; - mGenreName = genreName; - } - - /** - * {@inheritDoc} - */ - @Override - public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result + (int) mGenreId; - result = prime * result + (mGenreName == null ? 0 : mGenreName.hashCode()); - return result; - } - - /** - * {@inheritDoc} - */ - @Override - public boolean equals(final Object obj) { - if (this == obj) { - return true; - } - if (obj == null) { - return false; - } - if (getClass() != obj.getClass()) { - return false; - } - final Genre other = (Genre)obj; - if (mGenreId != other.mGenreId) { - return false; - } - return TextUtils.equals(mGenreName, other.mGenreName); - } - - /** - * {@inheritDoc} - */ - @Override - public String toString() { - return mGenreName; - } - -} diff --git a/src/org/lineageos/eleven/model/Playlist.java b/src/org/lineageos/eleven/model/Playlist.java index a8507db8dfcbfe66897802ee7045b1528529bdac..86af238f40b0180f1b4325510b959c0d83bac990 100644 --- a/src/org/lineageos/eleven/model/Playlist.java +++ b/src/org/lineageos/eleven/model/Playlist.java @@ -1,7 +1,7 @@ /* * Copyright (C) 2012 Andrew Neal * Copyright (C) 2014 The CyanogenMod Project - * Copyright (C) 2019 The LineageOS Project + * Copyright (C) 2019-2021 The LineageOS Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -15,15 +15,13 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package org.lineageos.eleven.model; -import android.text.TextUtils; +import java.util.Comparator; +import java.util.Objects; import androidx.annotation.NonNull; -import java.util.Comparator; - /** * A class that represents a playlist. * @@ -34,7 +32,7 @@ public class Playlist { /** * The unique Id of the playlist */ - public long mPlaylistId; + public final long mPlaylistId; /** * The playlist name @@ -44,12 +42,12 @@ public class Playlist { /** * The number of songs in this playlist */ - public int mSongCount; + public final int mSongCount; /** * Constructor of Genre * - * @param playlistId The Id of the playlist + * @param playlistId The Id of the playlist * @param playlistName The playlist name */ public Playlist(final long playlistId, final String playlistName, final int songCount) { @@ -60,36 +58,18 @@ public class Playlist { } @Override - public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result + (int) mPlaylistId; - result = prime * result + (mPlaylistName == null ? 0 : mPlaylistName.hashCode()); - result = prime * result + mSongCount; - return result; + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + Playlist playlist = (Playlist) o; + return mPlaylistId == playlist.mPlaylistId && + mSongCount == playlist.mSongCount && + Objects.equals(mPlaylistName, playlist.mPlaylistName); } @Override - public boolean equals(final Object obj) { - if (this == obj) { - return true; - } - if (obj == null) { - return false; - } - if (getClass() != obj.getClass()) { - return false; - } - final Playlist other = (Playlist)obj; - if (mPlaylistId != other.mPlaylistId) { - return false; - } - - if (mSongCount != other.mSongCount) { - return false; - } - - return TextUtils.equals(mPlaylistName, other.mPlaylistName); + public int hashCode() { + return Objects.hash(mPlaylistId, mPlaylistName, mSongCount); } @NonNull diff --git a/src/org/lineageos/eleven/model/SearchResult.java b/src/org/lineageos/eleven/model/SearchResult.java deleted file mode 100644 index 692edd271503d05cc4b7c7438e6d3a8212e12d93..0000000000000000000000000000000000000000 --- a/src/org/lineageos/eleven/model/SearchResult.java +++ /dev/null @@ -1,151 +0,0 @@ -/* -* Copyright (C) 2014 The CyanogenMod Project -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ -package org.lineageos.eleven.model; - -import android.database.Cursor; -import android.provider.MediaStore; -import android.util.Log; - -import org.lineageos.eleven.Config; - -import java.util.Comparator; - -public class SearchResult { - private static final String TAG = SearchResult.class.getSimpleName(); - - public static final Comparator COMPARATOR = new Comparator() { - @Override - public int compare(final SearchResult lhs, final SearchResult rhs) { - return lhs.mType.ordinal() - rhs.mType.ordinal(); - } - }; - - public static enum ResultType { - Song, - Artist, - Album, - Playlist, - Unknown; - - public static int getNumTypes() { - // # of items minus the unknown - return ResultType.values().length - 1; - } - - public static ResultType getResultType(final String mimetype) { - if (mimetype != null) { - if (mimetype.equals("artist")) { - return Artist; - } else if (mimetype.equals("album")) { - return Album; - } else if (mimetype.startsWith("audio/") || mimetype.equals("application/ogg") - || mimetype.equals("application/x-ogg")) { - return Song; - } - } - - return Unknown; - } - - public static ResultType getResultType(final Cursor cursor, int index) { - return getResultType(cursor.getString(index)); - } - - public static ResultType getResultType(final Cursor cursor) { - try { - return getResultType(cursor, - cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.MIME_TYPE)); - } catch(IllegalArgumentException ex) { - return Unknown; - } - } - - public Config.IdType getSourceType() { - switch (this) { - case Artist: - return Config.IdType.Artist; - case Album: - return Config.IdType.Album; - case Playlist: - return Config.IdType.Playlist; - case Song: - default: - return Config.IdType.NA; - } - } - }; - - public ResultType mType; - public String mArtist; - public String mAlbum; - public String mTitle; - public long mId; - public long mAlbumId; - public int mAlbumCount; - public int mSongCount; - - public static SearchResult createSearchResult(final Cursor cursor) { - SearchResult result = new SearchResult(); - - result.mType = ResultType.getResultType(cursor); - - // not a valid mime type - quitting - if (result.mType == ResultType.Unknown) { - Log.e(TAG, "No valid mime type found!"); - return null; - } - - // Get the Id of the content - result.mId = cursor.getLong(cursor - .getColumnIndexOrThrow(android.provider.BaseColumns._ID)); - - // title - result.mTitle = cursor.getString(cursor - .getColumnIndexOrThrow(MediaStore.Audio.Media.TITLE)); - - // Get the artist name - result.mArtist = cursor.getString(cursor - .getColumnIndexOrThrow(MediaStore.Audio.Artists.ARTIST)); - - // Get the album name - result.mAlbum = cursor.getString(cursor - .getColumnIndexOrThrow(MediaStore.Audio.Albums.ALBUM)); - - // album count - result.mAlbumCount = cursor.getInt(cursor.getColumnIndexOrThrow("data1")); - - // song count - result.mSongCount = cursor.getInt(cursor.getColumnIndexOrThrow("data2")); - - return result; - } - - public static SearchResult createPlaylistResult(final Cursor cursor) { - SearchResult result = new SearchResult(); - - result.mType = ResultType.Playlist; - - // Get the Id of the content - result.mId = cursor.getLong(cursor - .getColumnIndexOrThrow(android.provider.BaseColumns._ID)); - - // title - result.mTitle = cursor.getString(cursor - .getColumnIndexOrThrow(MediaStore.Audio.PlaylistsColumns.NAME)); - - return result; - } -} \ No newline at end of file diff --git a/src/org/lineageos/eleven/model/Song.java b/src/org/lineageos/eleven/model/Song.java index 785c38754a3025eaeedaf5abda5d2f33f2b787c8..9490c29af975b9453c13f0dc1cfff8fd8e4a2fe2 100644 --- a/src/org/lineageos/eleven/model/Song.java +++ b/src/org/lineageos/eleven/model/Song.java @@ -1,19 +1,26 @@ /* * Copyright (C) 2012 Andrew Neal * Copyright (C) 2014 The CyanogenMod Project - * Licensed under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law - * or agreed to in writing, software distributed under the License is - * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the specific language - * governing permissions and limitations under the License. + * Copyright (C) 2021 The LineageOS Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package org.lineageos.eleven.model; -import android.text.TextUtils; +import androidx.annotation.NonNull; + +import java.util.Objects; /** * A class that represents a song. @@ -25,37 +32,37 @@ public class Song { /** * The unique Id of the song */ - public long mSongId; + public final long mSongId; /** * The song name */ - public String mSongName; + public final String mSongName; /** * The song artist */ - public String mArtistName; + public final String mArtistName; /** * The song album */ - public String mAlbumName; + public final String mAlbumName; /** * The album id */ - public long mAlbumId; + public final long mAlbumId; /** * The song duration in seconds */ - public int mDuration; + public final int mDuration; /** * The year the song was recorded */ - public int mYear; + public final int mYear; /** * Bucket label for the name - may not necessarily be the name - for example songs sorted by @@ -66,15 +73,15 @@ public class Song { /** * Constructor of Song * - * @param songId The Id of the song - * @param songName The name of the song + * @param songId The Id of the song + * @param songName The name of the song * @param artistName The song artist - * @param albumName The song album - * @param duration The duration of a song in seconds - * @param year The year the song was recorded + * @param albumName The song album + * @param duration The duration of a song in seconds + * @param year The year the song was recorded */ public Song(final long songId, final String songName, final String artistName, - final String albumName, final long albumId, final int duration, final int year) { + final String albumName, final long albumId, final int duration, final int year) { mSongId = songId; mSongName = songName; mArtistName = artistName; @@ -84,67 +91,27 @@ public class Song { mYear = year; } - /** - * {@inheritDoc} - */ @Override - public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result + (mAlbumName == null ? 0 : mAlbumName.hashCode()); - result = prime * result + (int) mAlbumId; - result = prime * result + (mArtistName == null ? 0 : mArtistName.hashCode()); - result = prime * result + mDuration; - result = prime * result + (int) mSongId; - result = prime * result + (mSongName == null ? 0 : mSongName.hashCode()); - result = prime * result + mYear; - return result; + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + Song song = (Song) o; + return mSongId == song.mSongId && + mAlbumId == song.mAlbumId && + mDuration == song.mDuration && + mYear == song.mYear && + Objects.equals(mSongName, song.mSongName) && + Objects.equals(mArtistName, song.mArtistName) && + Objects.equals(mAlbumName, song.mAlbumName); } - /** - * {@inheritDoc} - */ @Override - public boolean equals(final Object obj) { - if (this == obj) { - return true; - } - if (obj == null) { - return false; - } - if (getClass() != obj.getClass()) { - return false; - } - final Song other = (Song)obj; - if (mSongId != other.mSongId) { - return false; - } - if (!TextUtils.equals(mAlbumName, other.mAlbumName)) { - return false; - } - if (mAlbumId != other.mAlbumId) { - return false; - } - if (!TextUtils.equals(mArtistName, other.mArtistName)) { - return false; - } - if (mDuration != other.mDuration) { - return false; - } - if (!TextUtils.equals(mSongName, other.mSongName)) { - return false; - } - - if (mYear != other.mYear) { - return false; - } - - return true; + public int hashCode() { + return Objects.hash(mSongId, mSongName, mArtistName, mAlbumName, + mAlbumId, mDuration, mYear); } - /** - * {@inheritDoc} - */ + @NonNull @Override public String toString() { return mSongName; diff --git a/src/org/lineageos/eleven/provider/LocalizedStore.java b/src/org/lineageos/eleven/provider/LocalizedStore.java index 0e3ae9dcd8f70bd1f35bb3543c8105c9adc56505..30b22c9628dce9c13673712e59b97067b9dc0536 100644 --- a/src/org/lineageos/eleven/provider/LocalizedStore.java +++ b/src/org/lineageos/eleven/provider/LocalizedStore.java @@ -1,5 +1,6 @@ /* * Copyright (C) 2014 The CyanogenMod Project + * Copyright (C) 2021 The LineageOS Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -11,7 +12,7 @@ * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and - * limitations under the License + * limitations under the License. */ package org.lineageos.eleven.provider; @@ -29,6 +30,8 @@ import android.provider.MediaStore.Audio.AudioColumns; import android.text.TextUtils; import android.util.Log; +import androidx.annotation.NonNull; + import org.lineageos.eleven.loaders.SortedCursor; import org.lineageos.eleven.locale.LocaleSet; import org.lineageos.eleven.locale.LocaleSetManager; @@ -63,7 +66,7 @@ public class LocalizedStore { Song, Artist, Album, - }; + } private static class SortData { long[] ids; @@ -74,7 +77,7 @@ public class LocalizedStore { * @param context The {@link android.content.Context} to use * @return A new instance of this class. */ - public static final synchronized LocalizedStore getInstance(final Context context) { + public static synchronized LocalizedStore getInstance(final Context context) { if (sInstance == null) { sInstance = new LocalizedStore(context.getApplicationContext()); } @@ -91,7 +94,7 @@ public class LocalizedStore { mHandlerThread.start(); mHandler = new Handler(mHandlerThread.getLooper()) { @Override - public void handleMessage(Message msg) { + public void handleMessage(@NonNull Message msg) { if (msg.what == LOCALE_CHANGED && mLocaleSetManager.localeSetNeedsUpdate()) { rebuildLocaleData(mLocaleSetManager.getSystemLocaleSet()); } @@ -103,28 +106,27 @@ public class LocalizedStore { } public void onCreate(final SQLiteDatabase db) { - String[] tables = new String[]{ - "CREATE TABLE IF NOT EXISTS " + SongSortColumns.TABLE_NAME + "(" + - SongSortColumns.ID + " INTEGER PRIMARY KEY," + - SongSortColumns.ARTIST_ID + " INTEGER NOT NULL," + - SongSortColumns.ALBUM_ID + " INTEGER NOT NULL," + - SongSortColumns.NAME + " TEXT COLLATE LOCALIZED," + - SongSortColumns.NAME_LABEL + " TEXT," + - SongSortColumns.NAME_BUCKET + " INTEGER);", - - "CREATE TABLE IF NOT EXISTS " + AlbumSortColumns.TABLE_NAME + "(" + - AlbumSortColumns.ID + " INTEGER PRIMARY KEY," + - AlbumSortColumns.ARTIST_ID + " INTEGER NOT NULL," + - AlbumSortColumns.NAME + " TEXT COLLATE LOCALIZED," + - AlbumSortColumns.NAME_LABEL + " TEXT," + - AlbumSortColumns.NAME_BUCKET + " INTEGER);", - - "CREATE TABLE IF NOT EXISTS " + ArtistSortColumns.TABLE_NAME + "(" + - ArtistSortColumns.ID + " INTEGER PRIMARY KEY," + - ArtistSortColumns.NAME + " TEXT COLLATE LOCALIZED," + - ArtistSortColumns.NAME_LABEL + " TEXT," + - ArtistSortColumns.NAME_BUCKET + " INTEGER);", + "CREATE TABLE IF NOT EXISTS " + SongSortColumns.TABLE_NAME + "(" + + SongSortColumns.ID + " INTEGER PRIMARY KEY," + + SongSortColumns.ARTIST_ID + " INTEGER NOT NULL," + + SongSortColumns.ALBUM_ID + " INTEGER NOT NULL," + + SongSortColumns.NAME + " TEXT COLLATE LOCALIZED," + + SongSortColumns.NAME_LABEL + " TEXT," + + SongSortColumns.NAME_BUCKET + " INTEGER);", + + "CREATE TABLE IF NOT EXISTS " + AlbumSortColumns.TABLE_NAME + "(" + + AlbumSortColumns.ID + " INTEGER PRIMARY KEY," + + AlbumSortColumns.ARTIST_ID + " INTEGER NOT NULL," + + AlbumSortColumns.NAME + " TEXT COLLATE LOCALIZED," + + AlbumSortColumns.NAME_LABEL + " TEXT," + + AlbumSortColumns.NAME_BUCKET + " INTEGER);", + + "CREATE TABLE IF NOT EXISTS " + ArtistSortColumns.TABLE_NAME + "(" + + ArtistSortColumns.ID + " INTEGER PRIMARY KEY," + + ArtistSortColumns.NAME + " TEXT COLLATE LOCALIZED," + + ArtistSortColumns.NAME_LABEL + " TEXT," + + ArtistSortColumns.NAME_BUCKET + " INTEGER);", }; for (String table : tables) { @@ -135,7 +137,7 @@ public class LocalizedStore { } } - public void onUpgrade(final SQLiteDatabase db, final int oldVersion, final int newVersion) { + public void onUpgrade(final SQLiteDatabase db, final int oldVersion) { // this table was created in version 3 so call the onCreate method if oldVersion <= 2 // in version 4 we need to recreate the SongSortcolumns table so drop the table and call // onCreate if oldVersion <= 3 @@ -145,7 +147,7 @@ public class LocalizedStore { } } - public void onDowngrade(SQLiteDatabase db, int oldVersion, int newVersion) { + public void onDowngrade(SQLiteDatabase db) { // If we ever have downgrade, drop the table to be safe db.execSQL("DROP TABLE IF EXISTS " + SongSortColumns.TABLE_NAME); db.execSQL("DROP TABLE IF EXISTS " + AlbumSortColumns.TABLE_NAME); @@ -180,7 +182,8 @@ public class LocalizedStore { // But assume that ICU versions are only able to change on Android version upgrades and // use SDK INT as identifier. PropertiesStore.getInstance(mContext).storeProperty( - PropertiesStore.DbProperties.ICU_VERSION, String.valueOf(Build.VERSION.SDK_INT)); + PropertiesStore.DbProperties.ICU_VERSION, + String.valueOf(Build.VERSION.SDK_INT)); PropertiesStore.getInstance(mContext).storeProperty(PropertiesStore.DbProperties.LOCALE, locales.toString()); @@ -190,12 +193,14 @@ public class LocalizedStore { } if (DEBUG) { - Log.i(TAG, "Locale change completed in " + (SystemClock.elapsedRealtime() - start) + "ms"); + Log.i(TAG, "Locale change completed in " + (SystemClock.elapsedRealtime() - start) + + "ms"); } } /** - * This will grab all the songs from the medistore and add the localized data to the db + * This will grab all the songs from the MediaStore and add the localized data to the db + * * @param selection if we only want to do this for some songs, this selection will filter it out */ private void updateLocalizedStore(final SQLiteDatabase db, final String selection) { @@ -253,13 +258,13 @@ public class LocalizedStore { updateAlbumData(db, albumId, cursor.getString(5), artistId); } - updateSongData(db, cursor.getLong(0), cursor.getString(1), artistId, albumId); + updateSongData(db, cursor.getLong(0), cursor.getString(1), artistId, + albumId); } while (cursor.moveToNext()); } } finally { if (cursor != null) { cursor.close(); - cursor = null; } } @@ -326,18 +331,19 @@ public class LocalizedStore { /** * Gets the list of saved ids and labels for the itemType in localized sorted order - * @param itemType the type of item we're querying for (artists, albums, songs) - * @param sortType the type we want to sort by (eg songs sorted by artists, - * albums sorted by artists). Note some combinations don't make sense and - * will fallback to the basic sort, for example Artists sorted by songs - * doesn't make sense + * + * @param itemType the type of item we're querying for (artists, albums, songs) + * @param sortType the type we want to sort by (eg songs sorted by artists, + * albums sorted by artists). Note some combinations don't make sense and + * will fallback to the basic sort, for example Artists sorted by songs + * doesn't make sense * @param descending Whether we want to sort ascending or descending. This will only apply to - * the basic searches (ie when sortType == itemType), - * otherwise ascending is always assumed + * the basic searches (ie when sortType == itemType), + * otherwise ascending is always assumed * @return sorted list of ids and bucket labels for the itemType */ public SortData getSortOrder(SortParameter itemType, SortParameter sortType, - boolean descending) { + boolean descending) { SortData sortData = new SortData(); String tableName = ""; String joinClause = ""; @@ -410,13 +416,14 @@ public class LocalizedStore { /** * Wraps the cursor with a sorted cursor that sorts it in the proper localized order - * @param cursor underlying cursor to sort + * + * @param cursor underlying cursor to sort * @param columnName the column name of the id - * @param idType the type of item that the cursor contains - * @param sortType the type to sort by (for example can be song sorted by albums) + * @param idType the type of item that the cursor contains + * @param sortType the type to sort by (for example can be song sorted by albums) * @param descending descending? - * @param update do we want to update any discrepencies we find - only should be true if the - * cursor contains all songs/artists/albums and not a subset + * @param update do we want to update any discrepencies we find - only should be true if the + * cursor contains all songs/artists/albums and not a subset * @return the sorted cursor */ public Cursor getLocalizedSort(Cursor cursor, String columnName, SortParameter idType, @@ -441,13 +448,14 @@ public class LocalizedStore { return sortedCursor; } - return cursor; + return null; } /** * Updates the localized store based on the cursor + * * @param sortedCursor the current sorting cursor based on the LocalizedStore sort - * @param type the item type in the cursor + * @param type the item type in the cursor * @return true if there are new ids in the cursor that aren't tracked in the store */ private boolean updateDiscrepancies(SortedCursor sortedCursor, SortParameter type) { @@ -607,5 +615,4 @@ public class LocalizedStore { return createOrderBy(NAME_BUCKET, NAME, descending); } } - } diff --git a/src/org/lineageos/eleven/provider/MusicDB.java b/src/org/lineageos/eleven/provider/MusicDB.java index 84cf5dfb602f42c6c75a7e41dbe8bbbd36dade9e..2a92578ff7c0f519b3e7fdafa7abcef8e8526356 100644 --- a/src/org/lineageos/eleven/provider/MusicDB.java +++ b/src/org/lineageos/eleven/provider/MusicDB.java @@ -1,18 +1,19 @@ /* -* Copyright (C) 2014 The CyanogenMod Project -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ + * Copyright (C) 2014 The CyanogenMod Project + * Copyright (C) 2021 The LineageOS Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package org.lineageos.eleven.provider; import android.content.Context; @@ -24,16 +25,15 @@ public class MusicDB extends SQLiteOpenHelper { /** * Version History * v1 Sept 22 2014 Initial Merge of tables - * Has PlaylistArtworkstore, RecentStore, SongPlayCount + * Has PlaylistArtworkstore, RecentStore, SongPlayCount * v2 Oct 7 2014 Added a new class MusicPlaybackState - need to bump version so the new - * tables are created, but need to remove all drops from other classes to - * maintain data + * tables are created, but need to remove all drops from other classes to + * maintain data * v3 Dec 4 2014 Add Sorting tables similar to Contacts to enable other languages like - * Chinese to properly sort as they would expect + * Chinese to properly sort as they would expect * v4 Jan 6 2015 Missed Collate keyword on the LocalizedSongSortTable */ - /* Version constant to increment when the database should be rebuilt */ private static final int VERSION = 4; @@ -73,22 +73,19 @@ public class MusicDB extends SQLiteOpenHelper { @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { PropertiesStore.getInstance(mContext).onUpgrade(db, oldVersion, newVersion); - PlaylistArtworkStore.getInstance(mContext).onUpgrade(db, oldVersion, newVersion); - RecentStore.getInstance(mContext).onUpgrade(db, oldVersion, newVersion); - SongPlayCount.getInstance(mContext).onUpgrade(db, oldVersion, newVersion); MusicPlaybackState.getInstance(mContext).onUpgrade(db, oldVersion, newVersion); - LocalizedStore.getInstance(mContext).onUpgrade(db, oldVersion, newVersion); + LocalizedStore.getInstance(mContext).onUpgrade(db, oldVersion); } @Override public void onDowngrade(SQLiteDatabase db, int oldVersion, int newVersion) { Log.w(MusicDB.class.getSimpleName(), "Downgrading from: " + oldVersion + " to " + newVersion + ". Dropping tables"); - PropertiesStore.getInstance(mContext).onDowngrade(db, oldVersion, newVersion); - PlaylistArtworkStore.getInstance(mContext).onDowngrade(db, oldVersion, newVersion); - RecentStore.getInstance(mContext).onDowngrade(db, oldVersion, newVersion); - SongPlayCount.getInstance(mContext).onDowngrade(db, oldVersion, newVersion); - MusicPlaybackState.getInstance(mContext).onDowngrade(db, oldVersion, newVersion); - LocalizedStore.getInstance(mContext).onDowngrade(db, oldVersion, newVersion); + PropertiesStore.getInstance(mContext).onDowngrade(db); + PlaylistArtworkStore.getInstance(mContext).onDowngrade(db); + RecentStore.getInstance(mContext).onDowngrade(db); + SongPlayCount.getInstance(mContext).onDowngrade(db); + MusicPlaybackState.getInstance(mContext).onDowngrade(db); + LocalizedStore.getInstance(mContext).onDowngrade(db); } } diff --git a/src/org/lineageos/eleven/provider/MusicPlaybackState.java b/src/org/lineageos/eleven/provider/MusicPlaybackState.java index e0bb66cf268a1b2135f3f210ee59d4f5f41470f7..5848261ef46bd0aeb1395f159dd88e3e2594f633 100644 --- a/src/org/lineageos/eleven/provider/MusicPlaybackState.java +++ b/src/org/lineageos/eleven/provider/MusicPlaybackState.java @@ -1,18 +1,19 @@ /* -* Copyright (C) 2014 The CyanogenMod Project -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ + * Copyright (C) 2014 The CyanogenMod Project + * Copyright (C) 2021 The LineageOS Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package org.lineageos.eleven.provider; import android.content.ContentValues; @@ -34,7 +35,7 @@ import java.util.LinkedList; public class MusicPlaybackState { private static MusicPlaybackState sInstance = null; - private MusicDB mMusicDatabase = null; + private final MusicDB mMusicDatabase; /** * Constructor of MusicPlaybackState @@ -83,7 +84,7 @@ public class MusicPlaybackState { } } - public void onDowngrade(SQLiteDatabase db, int oldVersion, int newVersion) { + public void onDowngrade(SQLiteDatabase db) { // If we ever have downgrade, drop the table to be safe db.execSQL("DROP TABLE IF EXISTS " + PlaybackQueueColumns.NAME); db.execSQL("DROP TABLE IF EXISTS " + PlaybackHistoryColumns.NAME); @@ -94,7 +95,7 @@ public class MusicPlaybackState { * @param context The {@link android.content.Context} to use * @return A new instance of this class. */ - public static final synchronized MusicPlaybackState getInstance(final Context context) { + public static synchronized MusicPlaybackState getInstance(final Context context) { if (sInstance == null) { sInstance = new MusicPlaybackState(context.getApplicationContext()); } @@ -104,7 +105,8 @@ public class MusicPlaybackState { /** * Clears the existing database and saves the queue and history into the db so that when the * app is restarted, the tracks you were listening to is restored - * @param queue the queue to save + * + * @param queue the queue to save * @param history the history to save */ public synchronized void saveState(final ArrayList queue, @@ -166,11 +168,8 @@ public class MusicPlaybackState { public ArrayList getQueue() { ArrayList results = Lists.newArrayList(); - Cursor cursor = null; - try { - cursor = mMusicDatabase.getReadableDatabase().query(PlaybackQueueColumns.NAME, null, - null, null, null, null, null); - + try (Cursor cursor = mMusicDatabase.getReadableDatabase().query(PlaybackQueueColumns.NAME, + null, null, null, null, null, null)) { if (cursor != null && cursor.moveToFirst()) { results.ensureCapacity(cursor.getCount()); @@ -181,22 +180,14 @@ public class MusicPlaybackState { } return results; - } finally { - if (cursor != null) { - cursor.close(); - cursor = null; - } } } public LinkedList getHistory(final int playlistSize) { LinkedList results = Lists.newLinkedList(); - Cursor cursor = null; - try { - cursor = mMusicDatabase.getReadableDatabase().query(PlaybackHistoryColumns.NAME, null, - null, null, null, null, null); - + try (Cursor cursor = mMusicDatabase.getReadableDatabase().query(PlaybackHistoryColumns.NAME, + null, null, null, null, null, null)) { if (cursor != null && cursor.moveToFirst()) { do { int pos = cursor.getInt(0); @@ -207,15 +198,10 @@ public class MusicPlaybackState { } return results; - } finally { - if (cursor != null) { - cursor.close(); - cursor = null; - } } } - public class PlaybackQueueColumns { + public static class PlaybackQueueColumns { /* Table name */ public static final String NAME = "playbackqueue"; @@ -232,7 +218,7 @@ public class MusicPlaybackState { public static final String SOURCE_POSITION = "sourceposition"; } - public class PlaybackHistoryColumns { + public static class PlaybackHistoryColumns { /* Table name */ public static final String NAME = "playbackhistory"; diff --git a/src/org/lineageos/eleven/provider/PlaylistArtworkStore.java b/src/org/lineageos/eleven/provider/PlaylistArtworkStore.java index 21e638a3f746887463a13970eec9d1c457c294b3..d9952b0dc10a09f65b7c75204b0c7debfeed382b 100644 --- a/src/org/lineageos/eleven/provider/PlaylistArtworkStore.java +++ b/src/org/lineageos/eleven/provider/PlaylistArtworkStore.java @@ -1,6 +1,6 @@ /* * Copyright (C) 2014 The CyanogenMod Project - * Copyright (C) 2019 The LineageOS Project + * Copyright (C) 2019-2021 The LineageOS Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -91,11 +91,7 @@ public class PlaylistArtworkStore { db.execSQL(builder); } - public void onUpgrade(final SQLiteDatabase db, final int oldVersion, final int newVersion) { - // No upgrade path needed yet - } - - public void onDowngrade(SQLiteDatabase db, int oldVersion, int newVersion) { + public void onDowngrade(SQLiteDatabase db) { // If we ever have downgrade, drop the table to be safe db.execSQL("DROP TABLE IF EXISTS " + PlaylistArtworkStoreColumns.NAME); onCreate(db); @@ -123,6 +119,7 @@ public class PlaylistArtworkStore { /** * Updates the time and the # of songs in the db for the artist section of the table + * * @param playlistId playlist identifier */ public void updateArtistArt(final long playlistId) { @@ -133,6 +130,7 @@ public class PlaylistArtworkStore { /** * Updates the time and the # of songs in the db for the cover art of the table + * * @param playlistId playlist identifier */ public void updateCoverArt(final long playlistId) { @@ -143,11 +141,13 @@ public class PlaylistArtworkStore { /** * Internal function to update the entry for the columns passed in - * @param playlistId playlist identifier - * @param columnName the column to update to the current time + * + * @param playlistId playlist identifier + * @param columnName the column to update to the current time * @param countColumnName the column to set the # of songs to based on the playlist */ - private void updateOrInsertTime(final long playlistId, final String columnName, final String countColumnName) { + private void updateOrInsertTime(final long playlistId, final String columnName, + final String countColumnName) { final SQLiteDatabase database = mMusicDatabase.getWritableDatabase(); database.beginTransaction(); @@ -173,10 +173,12 @@ public class PlaylistArtworkStore { /** * Internal function to get the existing values for a playlist entry + * * @param playlistId playlist identifier * @return the content values */ - private ContentValues getExistingContentValues(final SQLiteDatabase database, final long playlistId) { + private ContentValues getExistingContentValues(final SQLiteDatabase database, + final long playlistId) { final ContentValues values = new ContentValues(5); try (final Cursor c = getEntry(database, playlistId)) { if (c != null && c.moveToFirst()) { @@ -193,12 +195,13 @@ public class PlaylistArtworkStore { /** * Internal function to return whether the columns show that this needs an update - * @param playlistId playlist identifier - * @param columnName the column to inspect + * + * @param playlistId playlist identifier + * @param columnName the column to inspect * @param countColumnName the column count to inspect - * @return */ - private boolean needsUpdate(final long playlistId, final String columnName, final String countColumnName) { + private boolean needsUpdate(final long playlistId, final String columnName, + final String countColumnName) { final SQLiteDatabase database = mMusicDatabase.getReadableDatabase(); try (final Cursor c = getEntry(database, playlistId)) { if (c != null && c.moveToFirst()) { @@ -220,6 +223,7 @@ public class PlaylistArtworkStore { /** * Internal function to get the cursor entry for the playlist + * * @param playlistId playlist identifier * @return cursor */ @@ -230,21 +234,21 @@ public class PlaylistArtworkStore { public interface PlaylistArtworkStoreColumns { /* Table name */ - public static final String NAME = "playlist_details"; + String NAME = "playlist_details"; /* Playlist ID column */ - public static final String ID = "playlistid"; + String ID = "playlistid"; /* When the top artist was last updated */ - public static final String LAST_UPDATE_ARTIST = "last_updated_artist"; + String LAST_UPDATE_ARTIST = "last_updated_artist"; /* The number of songs when we last updated the artist */ - public static final String NUM_SONGS_LAST_UPDATE_ARTIST = "num_songs_last_updated_artist"; + String NUM_SONGS_LAST_UPDATE_ARTIST = "num_songs_last_updated_artist"; /* When the cover art was last updated */ - public static final String LAST_UPDATE_COVER = "last_updated_cover"; + String LAST_UPDATE_COVER = "last_updated_cover"; /* The number of songs when we last updated the cover */ - public static final String NUM_SONGS_LAST_UPDATE_COVER = "num_songs_last_updated_cover"; + String NUM_SONGS_LAST_UPDATE_COVER = "num_songs_last_updated_cover"; } } diff --git a/src/org/lineageos/eleven/provider/PropertiesStore.java b/src/org/lineageos/eleven/provider/PropertiesStore.java index 9d84c750147034d848fa6ce28840e99968f3fc68..fd11e556c60a6e8068375dfd273989f026980db6 100644 --- a/src/org/lineageos/eleven/provider/PropertiesStore.java +++ b/src/org/lineageos/eleven/provider/PropertiesStore.java @@ -1,6 +1,7 @@ /* - * Copyright (C) 2014 The CyanogenMod Project * Copyright (C) 2009 The Android Open Source Project + * Copyright (C) 2014 The CyanogenMod Project + * Copyright (C) 2021 The LineageOS Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,10 +13,11 @@ * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and - * limitations under the License + * limitations under the License. */ package org.lineageos.eleven.provider; +import android.annotation.SuppressLint; import android.content.ContentValues; import android.content.Context; import android.database.Cursor; @@ -25,7 +27,7 @@ public class PropertiesStore { private final MusicDB mMusicDatabase; private static PropertiesStore sInstance = null; - public static final synchronized PropertiesStore getInstance(final Context context) { + public static synchronized PropertiesStore getInstance(final Context context) { if (sInstance == null) { sInstance = new PropertiesStore(context.getApplicationContext()); } @@ -36,6 +38,7 @@ public class PropertiesStore { mMusicDatabase = MusicDB.getInstance(context); } + @SuppressLint("SQLiteString") public void onCreate(final SQLiteDatabase db) { db.execSQL("CREATE TABLE IF NOT EXISTS " + PropertiesColumns.TABLE_NAME + "(" + PropertiesColumns.PROPERTY_KEY + " STRING PRIMARY KEY," + @@ -49,7 +52,7 @@ public class PropertiesStore { } } - public void onDowngrade(SQLiteDatabase db, int oldVersion, int newVersion) { + public void onDowngrade(SQLiteDatabase db) { // If we ever have downgrade, drop the table to be safe db.execSQL("DROP TABLE IF EXISTS " + PropertiesColumns.TABLE_NAME); onCreate(db); @@ -60,19 +63,18 @@ public class PropertiesStore { } public String getProperty(String key, String defaultValue) { - Cursor cursor = mMusicDatabase.getReadableDatabase().query(PropertiesColumns.TABLE_NAME, - new String[] { PropertiesColumns.PROPERTY_VALUE }, + if (key == null) { + return defaultValue; + } + + try (Cursor cursor = mMusicDatabase.getReadableDatabase().query( + PropertiesColumns.TABLE_NAME, + new String[]{PropertiesColumns.PROPERTY_VALUE}, PropertiesColumns.PROPERTY_KEY + "=?", - new String[] { key }, null, null, null); - try { + new String[]{key}, null, null, null)) { if (cursor != null && cursor.moveToFirst()) { return cursor.getString(0); } - } finally { - if (cursor != null) { - cursor.close(); - cursor = null; - } } return defaultValue; diff --git a/src/org/lineageos/eleven/provider/RecentStore.java b/src/org/lineageos/eleven/provider/RecentStore.java index e03f52b7b6d4c5777e90a79807734f276ccb11e9..0db0961fb5d7d2fa03644fb6ac4df5c8ee78a101 100644 --- a/src/org/lineageos/eleven/provider/RecentStore.java +++ b/src/org/lineageos/eleven/provider/RecentStore.java @@ -1,16 +1,20 @@ /* * Copyright (C) 2012 Andrew Neal * Copyright (C) 2014 The CyanogenMod Project - * Licensed under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law - * or agreed to in writing, software distributed under the License is - * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the specific language - * governing permissions and limitations under the License. + * Copyright (C) 2021 The LineageOS Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ - package org.lineageos.eleven.provider; import android.content.ContentValues; @@ -24,7 +28,7 @@ public class RecentStore { private static RecentStore sInstance = null; - private MusicDB mMusicDatabase = null; + private final MusicDB mMusicDatabase; /** * Constructor of RecentStore @@ -37,15 +41,11 @@ public class RecentStore { public void onCreate(final SQLiteDatabase db) { db.execSQL("CREATE TABLE IF NOT EXISTS " + RecentStoreColumns.NAME + " (" - + RecentStoreColumns.ID + " LONG NOT NULL," + RecentStoreColumns.TIMEPLAYED + + RecentStoreColumns.ID + " LONG NOT NULL," + RecentStoreColumns.TIME_PLAYED + " LONG NOT NULL);"); } - public void onUpgrade(final SQLiteDatabase db, final int oldVersion, final int newVersion) { - // No upgrade path needed yet - } - - public void onDowngrade(SQLiteDatabase db, int oldVersion, int newVersion) { + public void onDowngrade(SQLiteDatabase db) { // If we ever have downgrade, drop the table to be safe db.execSQL("DROP TABLE IF EXISTS " + RecentStoreColumns.NAME); onCreate(db); @@ -55,7 +55,7 @@ public class RecentStore { * @param context The {@link Context} to use * @return A new instance of this class. */ - public static final synchronized RecentStore getInstance(final Context context) { + public static synchronized RecentStore getInstance(final Context context) { if (sInstance == null) { sInstance = new RecentStore(context.getApplicationContext()); } @@ -73,47 +73,32 @@ public class RecentStore { try { // see if the most recent item is the same song id, if it is then don't insert - Cursor mostRecentItem = null; - try { - mostRecentItem = queryRecentIds("1"); + try (Cursor mostRecentItem = queryRecentIds("1")) { if (mostRecentItem != null && mostRecentItem.moveToFirst()) { if (songId == mostRecentItem.getLong(0)) { return; } } - } finally { - if (mostRecentItem != null) { - mostRecentItem.close(); - mostRecentItem = null; - } } // add the entry final ContentValues values = new ContentValues(2); values.put(RecentStoreColumns.ID, songId); - values.put(RecentStoreColumns.TIMEPLAYED, System.currentTimeMillis()); + values.put(RecentStoreColumns.TIME_PLAYED, System.currentTimeMillis()); database.insert(RecentStoreColumns.NAME, null, values); // if our db is too large, delete the extra items - Cursor oldest = null; - try { - oldest = database.query(RecentStoreColumns.NAME, - new String[]{RecentStoreColumns.TIMEPLAYED}, null, null, null, null, - RecentStoreColumns.TIMEPLAYED + " ASC"); + try (Cursor oldest = database.query(RecentStoreColumns.NAME, + new String[]{RecentStoreColumns.TIME_PLAYED}, null, null, null, null, + RecentStoreColumns.TIME_PLAYED + " ASC")) { if (oldest != null && oldest.getCount() > MAX_ITEMS_IN_DB) { oldest.moveToPosition(oldest.getCount() - MAX_ITEMS_IN_DB); long timeOfRecordToKeep = oldest.getLong(0); database.delete(RecentStoreColumns.NAME, - RecentStoreColumns.TIMEPLAYED + " < ?", - new String[] { String.valueOf(timeOfRecordToKeep) }); - - } - } finally { - if (oldest != null) { - oldest.close(); - oldest = null; + RecentStoreColumns.TIME_PLAYED + " < ?", + new String[]{String.valueOf(timeOfRecordToKeep)}); } } } finally { @@ -127,8 +112,8 @@ public class RecentStore { */ public void removeItem(final long songId) { final SQLiteDatabase database = mMusicDatabase.getWritableDatabase(); - database.delete(RecentStoreColumns.NAME, RecentStoreColumns.ID + " = ?", new String[] { - String.valueOf(songId) + database.delete(RecentStoreColumns.NAME, RecentStoreColumns.ID + " = ?", new String[]{ + String.valueOf(songId) }); } @@ -140,6 +125,7 @@ public class RecentStore { /** * Gets a cursor to the list of recently played content + * * @param limit # of songs to limit the result to * @return cursor */ @@ -147,17 +133,17 @@ public class RecentStore { final SQLiteDatabase database = mMusicDatabase.getReadableDatabase(); return database.query(RecentStoreColumns.NAME, new String[]{RecentStoreColumns.ID}, null, null, null, null, - RecentStoreColumns.TIMEPLAYED + " DESC", limit); + RecentStoreColumns.TIME_PLAYED + " DESC", limit); } public interface RecentStoreColumns { /* Table name */ - public static final String NAME = "recenthistory"; + String NAME = "recenthistory"; /* Album IDs column */ - public static final String ID = "songid"; + String ID = "songid"; /* Time played column */ - public static final String TIMEPLAYED = "timeplayed"; + String TIME_PLAYED = "timeplayed"; } } diff --git a/src/org/lineageos/eleven/provider/SongPlayCount.java b/src/org/lineageos/eleven/provider/SongPlayCount.java index 5dfaaa62b68f8ef89b914b3596775ea4cd4620bd..d3677b305748cc9d85910838cb314a2cac8bef5a 100644 --- a/src/org/lineageos/eleven/provider/SongPlayCount.java +++ b/src/org/lineageos/eleven/provider/SongPlayCount.java @@ -1,19 +1,19 @@ /* -* Copyright (C) 2014 The CyanogenMod Project -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ - + * Copyright (C) 2014 The CyanogenMod Project + * Copyright (C) 2021 The LineageOS Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package org.lineageos.eleven.provider; import android.content.ContentValues; @@ -24,7 +24,6 @@ import android.view.animation.AccelerateInterpolator; import android.view.animation.Interpolator; import java.util.HashSet; -import java.util.Iterator; /** * This database tracks the number of play counts for an individual song. This is used to drive @@ -33,28 +32,28 @@ import java.util.Iterator; public class SongPlayCount { private static SongPlayCount sInstance = null; - private MusicDB mMusicDatabase = null; + private final MusicDB mMusicDatabase; // interpolator curve applied for measuring the curve - private static Interpolator sInterpolator = new AccelerateInterpolator(1.5f); + private static final Interpolator sInterpolator = new AccelerateInterpolator(1.5f); // how many weeks worth of playback to track private static final int NUM_WEEKS = 52; // how high to multiply the interpolation curve - private static int INTERPOLATOR_HEIGHT = 50; + private static final int INTERPOLATOR_HEIGHT = 50; // how high the base value is. The ratio of the Height to Base is what really matters - private static int INTERPOLATOR_BASE = 25; + private static final int INTERPOLATOR_BASE = 25; - private static int ONE_WEEK_IN_MS = 1000 * 60 * 60 * 24 * 7; + private static final int ONE_WEEK_IN_MS = 1000 * 60 * 60 * 24 * 7; - private static String WHERE_ID_EQUALS = SongPlayCountColumns.ID + "=?"; + private static final String WHERE_ID_EQUALS = SongPlayCountColumns.ID + "=?"; // number of weeks since epoch time - private int mNumberOfWeeksSinceEpoch; + private final int mNumberOfWeeksSinceEpoch; - // used to track if we've walkd through the db and updated all the rows + // used to track if we've walked through the db and updated all the rows private boolean mDatabaseUpdated; /** @@ -66,9 +65,7 @@ public class SongPlayCount { mMusicDatabase = MusicDB.getInstance(context); long msSinceEpoch = System.currentTimeMillis(); - mNumberOfWeeksSinceEpoch = (int)(msSinceEpoch / ONE_WEEK_IN_MS); - - mDatabaseUpdated = false; + mNumberOfWeeksSinceEpoch = (int) (msSinceEpoch / ONE_WEEK_IN_MS); } public void onCreate(final SQLiteDatabase db) { @@ -90,17 +87,13 @@ public class SongPlayCount { builder.append(SongPlayCountColumns.LAST_UPDATED_WEEK_INDEX); builder.append(" INT NOT NULL,"); - builder.append(SongPlayCountColumns.PLAYCOUNTSCORE); + builder.append(SongPlayCountColumns.PLAY_COUNT_SCORE); builder.append(" REAL DEFAULT 0);"); db.execSQL(builder.toString()); } - public void onUpgrade(final SQLiteDatabase db, final int oldVersion, final int newVersion) { - // No upgrade path needed yet - } - - public void onDowngrade(SQLiteDatabase db, int oldVersion, int newVersion) { + public void onDowngrade(SQLiteDatabase db) { // If we ever have downgrade, drop the table to be safe db.execSQL("DROP TABLE IF EXISTS " + SongPlayCountColumns.NAME); onCreate(db); @@ -110,7 +103,7 @@ public class SongPlayCount { * @param context The {@link android.content.Context} to use * @return A new instance of this class. */ - public static final synchronized SongPlayCount getInstance(final Context context) { + public static synchronized SongPlayCount getInstance(final Context context) { if (sInstance == null) { sInstance = new SongPlayCount(context.getApplicationContext()); } @@ -119,6 +112,7 @@ public class SongPlayCount { /** * Increases the play count of a song by 1 + * * @param songId The song id to increase the play count */ public void bumpSongCount(final long songId) { @@ -132,8 +126,9 @@ public class SongPlayCount { /** * This creates a new entry that indicates a song has been played once as well as its score + * * @param database a writeable database - * @param songId the id of the track + * @param songId the id of the track */ private void createNewPlayedEntry(final SQLiteDatabase database, final long songId) { // no row exists, create a new one @@ -142,7 +137,7 @@ public class SongPlayCount { final ContentValues values = new ContentValues(3); values.put(SongPlayCountColumns.ID, songId); - values.put(SongPlayCountColumns.PLAYCOUNTSCORE, newScore); + values.put(SongPlayCountColumns.PLAY_COUNT_SCORE, newScore); values.put(SongPlayCountColumns.LAST_UPDATED_WEEK_INDEX, mNumberOfWeeksSinceEpoch); values.put(getColumnNameForWeek(0), newPlayCount); @@ -152,11 +147,13 @@ public class SongPlayCount { /** * This function will take a song entry and update it to the latest week and increase the count * for the current week by 1 if necessary - * @param database a writeable database - * @param id the id of the track to bump + * + * @param database a writeable database + * @param id the id of the track to bump * @param bumpCount whether to bump the current's week play count by 1 and adjust the score */ - private void updateExistingRow(final SQLiteDatabase database, final long id, boolean bumpCount) { + private void updateExistingRow(final SQLiteDatabase database, final long id, + boolean bumpCount) { String stringId = String.valueOf(id); // begin the transaction @@ -164,12 +161,13 @@ public class SongPlayCount { // get the cursor of this content inside the transaction final Cursor cursor = database.query(SongPlayCountColumns.NAME, null, WHERE_ID_EQUALS, - new String[] { stringId }, null, null, null); + new String[]{stringId}, null, null, null); // if we have a result if (cursor != null && cursor.moveToFirst()) { // figure how many weeks since we last updated - int lastUpdatedIndex = cursor.getColumnIndex(SongPlayCountColumns.LAST_UPDATED_WEEK_INDEX); + int lastUpdatedIndex = cursor.getColumnIndex( + SongPlayCountColumns.LAST_UPDATED_WEEK_INDEX); int lastUpdatedWeek = cursor.getInt(lastUpdatedIndex); int weekDiff = mNumberOfWeeksSinceEpoch - lastUpdatedWeek; @@ -189,7 +187,7 @@ public class SongPlayCount { for (int i = 0; i < NUM_WEEKS - weekDiff; i++) { playCounts[i + weekDiff] = cursor.getInt(getColumnIndexForWeek(i)); } - } else if (weekDiff < 0) { + } else { // time is shifted backwards (by user) - nor typical behavior but we // will still handle it @@ -215,8 +213,9 @@ public class SongPlayCount { } else { // create the content values ContentValues values = new ContentValues(NUM_WEEKS + 2); - values.put(SongPlayCountColumns.LAST_UPDATED_WEEK_INDEX, mNumberOfWeeksSinceEpoch); - values.put(SongPlayCountColumns.PLAYCOUNTSCORE, score); + values.put(SongPlayCountColumns.LAST_UPDATED_WEEK_INDEX, + mNumberOfWeeksSinceEpoch); + values.put(SongPlayCountColumns.PLAY_COUNT_SCORE, score); for (int i = 0; i < NUM_WEEKS; i++) { values.put(getColumnNameForWeek(i), playCounts[i]); @@ -231,9 +230,9 @@ public class SongPlayCount { ContentValues values = new ContentValues(2); // increase the score by a single score amount - int scoreIndex = cursor.getColumnIndex(SongPlayCountColumns.PLAYCOUNTSCORE); + int scoreIndex = cursor.getColumnIndex(SongPlayCountColumns.PLAY_COUNT_SCORE); float score = cursor.getFloat(scoreIndex) + getScoreMultiplierForWeek(0); - values.put(SongPlayCountColumns.PLAYCOUNTSCORE, score); + values.put(SongPlayCountColumns.PLAY_COUNT_SCORE, score); // increase the play count by 1 values.put(getColumnNameForWeek(0), cursor.getInt(getColumnIndexForWeek(0)) + 1); @@ -261,6 +260,7 @@ public class SongPlayCount { /** * Gets a cursor containing the top songs played. Note this only returns songs that have been * played at least once in the past NUM_WEEKS + * * @param numResults number of results to limit by. If <= 0 it returns all results * @return the top tracks */ @@ -268,13 +268,14 @@ public class SongPlayCount { updateResults(); final SQLiteDatabase database = mMusicDatabase.getReadableDatabase(); - return database.query(SongPlayCountColumns.NAME, new String[] { SongPlayCountColumns.ID }, - null, null, null, null, SongPlayCountColumns.PLAYCOUNTSCORE + " DESC", + return database.query(SongPlayCountColumns.NAME, new String[]{SongPlayCountColumns.ID}, + null, null, null, null, SongPlayCountColumns.PLAY_COUNT_SCORE + " DESC", (numResults <= 0 ? null : String.valueOf(numResults))); } /** * Given a list of ids, it sorts the results based on the most played results + * * @param ids list * @return sorted list - this may be smaller than the list passed in for performance reasons */ @@ -320,13 +321,11 @@ public class SongPlayCount { // now query for the songs final SQLiteDatabase database = mMusicDatabase.getReadableDatabase(); - Cursor topSongsCursor = null; int idx = 0; - try { - topSongsCursor = database.query(SongPlayCountColumns.NAME, - new String[]{ SongPlayCountColumns.ID }, selection.toString(), null, null, - null, SongPlayCountColumns.PLAYCOUNTSCORE + " DESC"); + try (Cursor topSongsCursor = database.query(SongPlayCountColumns.NAME, + new String[]{SongPlayCountColumns.ID}, selection.toString(), null, null, + null, SongPlayCountColumns.PLAY_COUNT_SCORE + " DESC")) { if (topSongsCursor != null && topSongsCursor.moveToFirst()) { do { @@ -336,11 +335,6 @@ public class SongPlayCount { uniqueIds.remove(id); } while (topSongsCursor.moveToNext()); } - } finally { - if (topSongsCursor != null) { - topSongsCursor.close(); - topSongsCursor = null; - } } // append the remaining items - these are songs that haven't been played recently @@ -371,7 +365,7 @@ public class SongPlayCount { // get the remaining rows Cursor cursor = database.query(SongPlayCountColumns.NAME, - new String[] { SongPlayCountColumns.ID }, + new String[]{SongPlayCountColumns.ID}, null, null, null, null, null); if (cursor != null && cursor.moveToFirst()) { @@ -381,7 +375,6 @@ public class SongPlayCount { } while (cursor.moveToNext()); cursor.close(); - cursor = null; } mDatabaseUpdated = true; @@ -399,6 +392,7 @@ public class SongPlayCount { /** * Deletes the entry + * * @param database database to use * @param stringId id to delete */ @@ -408,6 +402,7 @@ public class SongPlayCount { /** * Calculates the score of the song given the play counts + * * @param playCounts an array of the # of times a song has been played for each week * where playCounts[N] is the # of times it was played N weeks ago * @return the score @@ -427,26 +422,29 @@ public class SongPlayCount { /** * Gets the column name for each week # + * * @param week number * @return the column name */ private static String getColumnNameForWeek(final int week) { - return SongPlayCountColumns.WEEK_PLAY_COUNT + String.valueOf(week); + return SongPlayCountColumns.WEEK_PLAY_COUNT + week; } /** * Gets the score multiplier for each week + * * @param week number * @return the multiplier to apply */ private static float getScoreMultiplierForWeek(final int week) { - return sInterpolator.getInterpolation(1 - (week / (float)NUM_WEEKS)) * INTERPOLATOR_HEIGHT + return sInterpolator.getInterpolation(1 - (week / (float) NUM_WEEKS)) * INTERPOLATOR_HEIGHT + INTERPOLATOR_BASE; } /** * For some performance gain, return a static value for the column index for a week * WARNIGN: This function assumes you have selected all columns for it to work + * * @param week number * @return column index of that week */ @@ -458,18 +456,18 @@ public class SongPlayCount { public interface SongPlayCountColumns { /* Table name */ - public static final String NAME = "songplaycount"; + String NAME = "songplaycount"; /* Song IDs column */ - public static final String ID = "songid"; + String ID = "songid"; /* Week Play Count */ - public static final String WEEK_PLAY_COUNT = "week"; + String WEEK_PLAY_COUNT = "week"; /* Weeks since Epoch */ - public static final String LAST_UPDATED_WEEK_INDEX = "weekindex"; + String LAST_UPDATED_WEEK_INDEX = "weekindex"; /* Play count */ - public static final String PLAYCOUNTSCORE = "playcountscore"; + String PLAY_COUNT_SCORE = "playcountscore"; } } diff --git a/src/org/lineageos/eleven/recycler/RecycleHolder.java b/src/org/lineageos/eleven/recycler/RecycleHolder.java deleted file mode 100644 index c3d9d080b4e3099b1940a7020f7260d1e5c0f64b..0000000000000000000000000000000000000000 --- a/src/org/lineageos/eleven/recycler/RecycleHolder.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright (C) 2012 Andrew Neal - * Copyright (C) 2014 The CyanogenMod Project - * Licensed under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law - * or agreed to in writing, software distributed under the License is - * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ - -package org.lineageos.eleven.recycler; - -import android.view.View; -import android.widget.AbsListView.RecyclerListener; - -import org.lineageos.eleven.cache.ImageWorker; -import org.lineageos.eleven.ui.MusicHolder; - -/** - * A @ {@link RecyclerListener} for {@link MusicHolder}'s views. - * - * @author Andrew Neal (andrewdneal@gmail.com) - */ -public class RecycleHolder implements RecyclerListener { - - /** - * {@inheritDoc} - */ - @Override - public void onMovedToScrapHeap(final View view) { - MusicHolder holder = (MusicHolder)view.getTag(); - if (holder == null) { - holder = new MusicHolder(view); - view.setTag(holder); - } - - // Release mImage's reference - if (holder.mImage.get() != null) { - ImageWorker.cancelWork(holder.mImage.get()); - holder.mImage.get().setImageDrawable(null); - holder.mImage.get().setImageBitmap(null); - } - - // Release mLineOne's reference - if (holder.mLineOne.get() != null) { - holder.mLineOne.get().setText(null); - } - - // Release mLineTwo's reference - if (holder.mLineTwo.get() != null) { - holder.mLineTwo.get().setText(null); - } - - // Stop the play pause button logic - if (holder.mPlayPauseProgressButton.get() != null) { - holder.mPlayPauseProgressButton.get().disableAndHide(); - } - } - -} diff --git a/src/org/lineageos/eleven/sectionadapter/SectionAdapter.java b/src/org/lineageos/eleven/sectionadapter/SectionAdapter.java deleted file mode 100644 index 81c59f07eb6cb7613a712763636373ebfbc9a305..0000000000000000000000000000000000000000 --- a/src/org/lineageos/eleven/sectionadapter/SectionAdapter.java +++ /dev/null @@ -1,419 +0,0 @@ -/* -* Copyright (C) 2014 The CyanogenMod Project -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ -package org.lineageos.eleven.sectionadapter; - -import android.app.Activity; -import android.content.Context; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.ArrayAdapter; -import android.widget.BaseAdapter; -import android.widget.TextView; - -import org.lineageos.eleven.R; -import org.lineageos.eleven.ui.MusicHolder; -import org.lineageos.eleven.utils.SectionCreatorUtils.Section; -import org.lineageos.eleven.utils.SectionCreatorUtils.SectionType; -import org.lineageos.eleven.widgets.IPopupMenuCallback; - -import java.util.TreeMap; - -/** - * This class wraps an ArrayAdapter that implements BasicAdapter and allows Sections to be inserted - * into the list. This wraps the methods for getting the view/indices and returns the section - * heads and if it is an underlying item it flows it through the underlying adapter - * @param The underlying item that is in the array adapter - * @param the arrayadapter that contains TItem and implements BasicAdapter - */ -public class SectionAdapter & SectionAdapter.BasicAdapter & IPopupMenuCallback> - extends BaseAdapter implements IPopupMenuCallback, IPopupMenuCallback.IListener { - /** - * Basic interface that the adapters implement - */ - public interface BasicAdapter { - public void unload(); - public void buildCache(); - public void flush(); - public int getItemPosition(long id); - } - - /** - * The underlying adapter to wrap - */ - protected TArrayAdapter mUnderlyingAdapter; - - /** - * A map of external position to the Section type and Identifier - */ - protected TreeMap mSections; - - protected int mHeaderLayoutId; - protected boolean mHeaderEnabled; - - protected int mFooterLayoutId; - protected boolean mFooterEnabled; - - /** - * Popup menu click listener - */ - protected IListener mListener; - - /** - * {@link Context} - */ - protected final Context mContext; - - /** - * Creates a SectionAdapter - * @param context The {@link Context} to use. - * @param underlyingAdapter the underlying adapter to wrap - */ - public SectionAdapter(final Activity context, final TArrayAdapter underlyingAdapter) { - mContext = context; - mUnderlyingAdapter = underlyingAdapter; - mUnderlyingAdapter.setPopupMenuClickedListener(this); - mSections = new TreeMap<>(); - setupHeaderParameters(R.layout.list_header, false); - // since we have no good default footer, just re-use the header layout - setupFooterParameters(R.layout.list_header, false); - } - - /** - * Gets the underlying array adapter - * @return the underlying array adapter - */ - public TArrayAdapter getUnderlyingAdapter() { - return mUnderlyingAdapter; - } - - /** - * {@inheritDoc} - */ - @Override - public View getView(final int position, View convertView, final ViewGroup parent) { - if (isSection(position)) { - if (convertView == null) { - int layoutId = mHeaderLayoutId; - if (isSectionFooter(position)) { - layoutId = mFooterLayoutId; - } - - convertView = LayoutInflater.from(mContext).inflate(layoutId, parent, false); - } - - TextView title = (TextView)convertView.findViewById(R.id.title); - title.setText(mSections.get(position).mIdentifier); - } else { - convertView = mUnderlyingAdapter.getView( - getInternalPosition(position), convertView, parent); - - Object tag = convertView.getTag(); - if (tag instanceof MusicHolder) { - MusicHolder holder = (MusicHolder)tag; - View divider = holder.mDivider.get(); - if (divider != null) { - // if it is the last item in the list, or it is an item before a section divider - // then hide the divider, otherwise show it - if (position == getCount() - 1 || isSection(position + 1)) { - divider.setVisibility(View.INVISIBLE); - } else { - divider.setVisibility(View.VISIBLE); - } - } - } - } - - return convertView; - } - - /** - * Setup the header parameters - * @param layoutId the layout id used to inflate - * @param enabled whether clicking is enabled on the header - */ - public void setupHeaderParameters(int layoutId, boolean enabled) { - mHeaderLayoutId = layoutId; - mHeaderEnabled = enabled; - } - - /** - * Setup the footer parameters - * @param layoutId the layout id used to inflate - * @param enabled whether clicking is enabled on the footer - */ - public void setupFooterParameters(int layoutId, boolean enabled) { - mFooterLayoutId = layoutId; - mFooterEnabled = enabled; - } - - /** - * {@inheritDoc} - */ - @Override - public int getCount() { - return mSections.size() + mUnderlyingAdapter.getCount(); - } - - /** - * {@inheritDoc} - */ - @Override - public Object getItem(int position) { - if (isSection(position)) { - return mSections.get(position); - } - - return mUnderlyingAdapter.getItem(getInternalPosition(position)); - } - - /** - * Gets the underlying adapter's item - * @param position position to query for - * @return the underlying item or null if a section header is queried - */ - public TItem getTItem(int position) { - if (isSection(position)) { - return null; - } - - return mUnderlyingAdapter.getItem(getInternalPosition(position)); - } - - /** - * {@inheritDoc} - */ - @Override - public long getItemId(int position) { - return position; - } - - /** - * {@inheritDoc} - */ - @Override - public boolean hasStableIds() { - return true; - } - - /** - * {@inheritDoc} - */ - @Override - public int getItemViewType(int position) { - if (isSectionHeader(position)) { - // use the last view type id as the section header - return getViewTypeCount() - 1; - } else if (isSectionFooter(position)) { - // use the last view type id as the section header - return getViewTypeCount() - 2; - } - - return mUnderlyingAdapter.getItemViewType(getInternalPosition(position)); - } - - /** - * {@inheritDoc} - */ - @Override - public int getViewTypeCount() { - // increment view type count by 2 for section headers and section footers - return mUnderlyingAdapter.getViewTypeCount() + 2; - } - - /** - * {@inheritDoc} - */ - @Override - public void notifyDataSetChanged() { - super.notifyDataSetChanged(); - - mUnderlyingAdapter.notifyDataSetChanged(); - } - - /** - * {@inheritDoc} - */ - @Override - public void notifyDataSetInvalidated() { - super.notifyDataSetInvalidated(); - - mUnderlyingAdapter.notifyDataSetInvalidated(); - } - - /** - * {@inheritDoc} - */ - @Override - public boolean isEnabled(int position) { - if (isSectionHeader(position)) { - return mHeaderEnabled; - } else if (isSectionFooter(position)) { - return mFooterEnabled; - } - - return true; - } - - /** - * {@inheritDoc} - */ - @Override - public boolean areAllItemsEnabled() { - return false; - } - - /** - * Determines whether the item at the position is a section header - * @param position position in the overall lis - * @return true if a section header - */ - public boolean isSectionHeader(int position) { - return mSections.containsKey(position) && mSections.get(position).mType == SectionType.Header; - } - - /** - * Determines whether the item at the position is a section footer - * @param position position in the overall lis - * @return true if a section footer - */ - public boolean isSectionFooter(int position) { - return mSections.containsKey(position) && mSections.get(position).mType == SectionType.Footer; - } - - /** - * Determines whether the item at the position is a section of some type - * @param position position in the overall lis - * @return true if the item is a section - */ - public boolean isSection(int position) { - return mSections.containsKey(position); - } - - /** - * Converts the external position to the internal position. This is needed to determine - * the position to pass into the underlying adapter - * @param position external position - * @return the internal position - */ - public int getInternalPosition(int position) { - if (isSection(position)) { - return -1; - } - - int countSectionHeaders = 0; - - for (Integer sectionPosition : mSections.keySet()) { - if (sectionPosition <= position) { - countSectionHeaders++; - } else { - break; - } - } - - return position - countSectionHeaders; - } - - /** - * Converts the underlaying adapter position to wrapped adapter position - * @param internalPosition the position of the underlying adapter - * @return the position of the wrapped adapter - */ - public int getExternalPosition(int internalPosition) { - int externalPosition = internalPosition; - for (Integer sectionPosition : mSections.keySet()) { - // because the section headers are tracking the 'merged' lists, we need to keep bumping - // our position for each found section header - if (sectionPosition <= externalPosition) { - externalPosition++; - } else { - break; - } - } - - return externalPosition; - } - - /** - * Sets the data on the adapter - * @param data data to set - */ - public void setData(SectionListContainer data) { - mUnderlyingAdapter.unload(); - - if (data.mSections == null) { - mSections.clear(); - } else { - mSections = data.mSections; - } - - mUnderlyingAdapter.addAll(data.mListResults); - - mUnderlyingAdapter.buildCache(); - - notifyDataSetChanged(); - } - - /** - * unloads the underlying adapter - */ - public void unload() { - mSections.clear(); - mUnderlyingAdapter.unload(); - notifyDataSetChanged(); - } - - /** - * flushes the underlying adapter - */ - public void flush() { - mUnderlyingAdapter.flush(); - notifyDataSetChanged(); - } - - public void clear() { - mSections.clear(); - mUnderlyingAdapter.clear(); - mSections.clear(); - } - - /** - * Gets the item position for the given identifier - * @param identifier used to identify the object - * @return item position, or -1 if not found - */ - public int getItemPosition(long identifier) { - int internalPosition = mUnderlyingAdapter.getItemPosition(identifier); - if (internalPosition >= 0) { - return getExternalPosition(internalPosition); - } - - return -1; - } - - @Override - public void setPopupMenuClickedListener(IListener listener) { - mListener = listener; - } - - @Override - public void onPopupMenuClicked(View v, int position) { - if (mListener != null) { - mListener.onPopupMenuClicked(v, getExternalPosition(position)); - } - } -} diff --git a/src/org/lineageos/eleven/sectionadapter/SectionCreator.java b/src/org/lineageos/eleven/sectionadapter/SectionCreator.java index 5c9eda1edd687840aca197c32e13a8c851811e30..7b4449c9ac9480ef32e70416ae60578bffc5d0d3 100644 --- a/src/org/lineageos/eleven/sectionadapter/SectionCreator.java +++ b/src/org/lineageos/eleven/sectionadapter/SectionCreator.java @@ -1,22 +1,25 @@ /* -* Copyright (C) 2014 The CyanogenMod Project -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ + * Copyright (C) 2014 The CyanogenMod Project + * Copyright (C) 2021 The LineageOS Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package org.lineageos.eleven.sectionadapter; import android.content.Context; +import androidx.annotation.NonNull; + import org.lineageos.eleven.loaders.WrappedAsyncTaskLoader; import org.lineageos.eleven.utils.SectionCreatorUtils; @@ -25,33 +28,37 @@ import java.util.TreeMap; /** * This class wraps a SimpleListLoader and creates header sections for the sections + * * @param The type of item that is loaded */ public class SectionCreator extends WrappedAsyncTaskLoader> { /** * Simple list loader class that exposes a load method + * * @param type of item to load */ public static abstract class SimpleListLoader extends WrappedAsyncTaskLoader> { - protected Context mContext; + protected final Context mContext; public SimpleListLoader(Context context) { super(context); mContext = context; } + @NonNull public Context getContext() { return mContext; } } - private SimpleListLoader mLoader; - private SectionCreatorUtils.IItemCompare mComparator; + private final SimpleListLoader mLoader; + private final SectionCreatorUtils.IItemCompare mComparator; /** * Creates a SectionCreator object which loads @loader - * @param context The {@link Context} to use. - * @param loader loader to wrap + * + * @param context The {@link Context} to use. + * @param loader loader to wrap * @param comparator the comparison object to run to create the sections */ public SectionCreator(Context context, SimpleListLoader loader, @@ -61,9 +68,6 @@ public class SectionCreator extends WrappedAsyncTaskLoader loadInBackground() { List results = mLoader.loadInBackground(); diff --git a/src/org/lineageos/eleven/sectionadapter/SectionListContainer.java b/src/org/lineageos/eleven/sectionadapter/SectionListContainer.java index 93bcf7d48f29d3888f82b2b3b979f6544469c412..4c6b4e89d5d1a555a6ca9309fc1bf3163903fc34 100644 --- a/src/org/lineageos/eleven/sectionadapter/SectionListContainer.java +++ b/src/org/lineageos/eleven/sectionadapter/SectionListContainer.java @@ -1,18 +1,19 @@ /* -* Copyright (C) 2014 The CyanogenMod Project -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ + * Copyright (C) 2014 The CyanogenMod Project + * Copyright (C) 2021 The LineageOS Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package org.lineageos.eleven.sectionadapter; import org.lineageos.eleven.utils.SectionCreatorUtils; @@ -22,11 +23,12 @@ import java.util.TreeMap; /** * Simple Container that contains a list of T items as well as the map of section information + * * @param the type of item that the list contains */ public class SectionListContainer { - public TreeMap mSections; - public List mListResults; + public final TreeMap mSections; + public final List mListResults; public SectionListContainer(final TreeMap sections, final List results) { diff --git a/src/org/lineageos/eleven/service/MusicPlaybackTrack.java b/src/org/lineageos/eleven/service/MusicPlaybackTrack.java index 5939caca65352be024b2b720b339b190324c6d37..88e2b63af08c91976f8d3b66e584b034683acdb8 100644 --- a/src/org/lineageos/eleven/service/MusicPlaybackTrack.java +++ b/src/org/lineageos/eleven/service/MusicPlaybackTrack.java @@ -1,18 +1,19 @@ /* -* Copyright (C) 2014 The CyanogenMod Project -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ + * Copyright (C) 2014 The CyanogenMod Project + * Copyright (C) 2021 The LineageOS Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package org.lineageos.eleven.service; import android.os.Parcel; @@ -29,24 +30,24 @@ public class MusicPlaybackTrack implements Parcelable { /** * The track id */ - public long mId; + public final long mId; /** * Where was this track added from? Artist id/Album id/Playlist id */ - public long mSourceId; + public final long mSourceId; /** * Where was this track added from? Artist/Album/Playlist */ - public Config.IdType mSourceType; + public final Config.IdType mSourceType; /** * This is only used for playlists since it is possible that a playlist can contain the same * song multiple times. So to prevent the song indicator showing up multiple times, we need * to keep track of the position */ - public int mSourcePosition; + public final int mSourcePosition; /** * Parcelable creator @@ -94,16 +95,10 @@ public class MusicPlaybackTrack implements Parcelable { public boolean equals(Object o) { if (o instanceof MusicPlaybackTrack) { MusicPlaybackTrack other = (MusicPlaybackTrack)o; - if (other != null) { - if (mId == other.mId - && mSourceId == other.mSourceId - && mSourceType == other.mSourceType - && mSourcePosition == other.mSourcePosition) { - return true; - } - - return false; - } + return mId == other.mId + && mSourceId == other.mSourceId + && mSourceType == other.mSourceType + && mSourcePosition == other.mSourcePosition; } return super.equals(o); diff --git a/src/org/lineageos/eleven/slidinguppanel/SlidingUpPanelLayout.java b/src/org/lineageos/eleven/slidinguppanel/SlidingUpPanelLayout.java index 623be54c9877965600b2c0ff5322d819b5330c52..3b2d3e1fd51d573573c72e7529bc7a7fc5b5b5d6 100644 --- a/src/org/lineageos/eleven/slidinguppanel/SlidingUpPanelLayout.java +++ b/src/org/lineageos/eleven/slidinguppanel/SlidingUpPanelLayout.java @@ -1,3 +1,19 @@ +/* + * Copyright (C) 2014 The CyanogenMod Project + * Copyright (C) 2021 The LineageOS Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package org.lineageos.eleven.slidinguppanel; import android.annotation.SuppressLint; @@ -17,15 +33,13 @@ import android.view.View; import android.view.ViewGroup; import android.view.accessibility.AccessibilityEvent; -import androidx.core.view.MotionEventCompat; +import androidx.core.content.ContextCompat; import androidx.core.view.ViewCompat; import org.lineageos.eleven.R; public class SlidingUpPanelLayout extends ViewGroup { - private static final String TAG = SlidingUpPanelLayout.class.getSimpleName(); - /** * Default peeking out panel height */ @@ -39,7 +53,7 @@ public class SlidingUpPanelLayout extends ViewGroup { /** * Default initial state for the component */ - private static SlideState DEFAULT_SLIDE_STATE = SlideState.COLLAPSED; + private static final SlideState DEFAULT_SLIDE_STATE = SlideState.COLLAPSED; /** * Default height of the shadow above the peeking out panel @@ -67,24 +81,19 @@ public class SlidingUpPanelLayout extends ViewGroup { /** * Default attributes for layout */ - private static final int[] DEFAULT_ATTRS = new int[] { - android.R.attr.gravity + private static final int[] DEFAULT_ATTRS = new int[]{ + android.R.attr.gravity }; - /** - * Minimum velocity that will be detected as a fling - */ - private int mMinFlingVelocity = DEFAULT_MIN_FLING_VELOCITY; - /** * The fade color used for the panel covered by the slider. 0 = no fading. */ private int mCoveredFadeColor = DEFAULT_FADE_COLOR; /** - * Default paralax length of the main view + * Default parallax length of the main view */ - private static final int DEFAULT_PARALAX_OFFSET = 0; + private static final int DEFAULT_PARALLAX_OFFSET = 0; /** * Default slide panel offset when collapsed @@ -122,12 +131,12 @@ public class SlidingUpPanelLayout extends ViewGroup { private int mShadowHeight = -1; /** - * Paralax offset + * Parallax offset */ private int mParallaxOffset = -1; /** - * Clamps the Main view to the slideable view + * Clamps the Main view to the slide-able view */ private boolean mDirectOffset = false; @@ -168,11 +177,6 @@ public class SlidingUpPanelLayout extends ViewGroup { */ private View mMainView; - /** - * The background view - */ - private View mBackgroundView; - /** * Current state of the slideable view. */ @@ -183,6 +187,7 @@ public class SlidingUpPanelLayout extends ViewGroup { HIDDEN, DRAGGING } + private SlideState mSlideState = SlideState.COLLAPSED; /** @@ -192,7 +197,7 @@ public class SlidingUpPanelLayout extends ViewGroup { private float mSlideOffset; /** - * How far in pixels the slideable panel may move. + * How far in pixels the slide-able panel may move. */ private int mSlideRange; @@ -207,14 +212,6 @@ public class SlidingUpPanelLayout extends ViewGroup { */ private boolean mIsSlidingEnabled; - /** - * Flag indicating if a drag view can have its own touch events. If set - * to true, a drag view can scroll horizontally and have its own click listener. - * - * Default is set to false. - */ - private boolean mIsUsingDragViewTouchEvents; - private float mInitialMotionX; private float mInitialMotionY; private float mAnchorPoint = 1.f; @@ -238,33 +235,41 @@ public class SlidingUpPanelLayout extends ViewGroup { public interface PanelSlideListener { /** * Called when a sliding pane's position changes. - * @param panel The child view that was moved + * + * @param panel The child view that was moved * @param slideOffset The new offset of this sliding pane within its range, from 0-1 */ - public void onPanelSlide(View panel, float slideOffset); + void onPanelSlide(View panel, float slideOffset); + /** * Called when a sliding panel becomes slid completely collapsed. + * * @param panel The child view that was slid to an collapsed position */ - public void onPanelCollapsed(View panel); + void onPanelCollapsed(View panel); /** * Called when a sliding panel becomes slid completely expanded. + * * @param panel The child view that was slid to a expanded position */ - public void onPanelExpanded(View panel); + void onPanelExpanded(View panel); /** * Called when a sliding panel becomes anchored. + * * @param panel The child view that was slid to a anchored position */ - public void onPanelAnchored(View panel); + @SuppressWarnings("unused") + void onPanelAnchored(View panel); /** * Called when a sliding panel becomes completely hidden. + * * @param panel The child view that was slid to a hidden position */ - public void onPanelHidden(View panel); + @SuppressWarnings("unused") + void onPanelHidden(View panel); } /** @@ -275,15 +280,19 @@ public class SlidingUpPanelLayout extends ViewGroup { @Override public void onPanelSlide(View panel, float slideOffset) { } + @Override public void onPanelCollapsed(View panel) { } + @Override public void onPanelExpanded(View panel) { } + @Override public void onPanelAnchored(View panel) { } + @Override public void onPanelHidden(View panel) { } @@ -300,46 +309,57 @@ public class SlidingUpPanelLayout extends ViewGroup { public SlidingUpPanelLayout(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); - if(isInEditMode()) { + if (isInEditMode()) { mShadowDrawable = null; mDragHelper = null; return; } + // Minimum velocity that will be detected as a fling + int minFlingVelocity = DEFAULT_MIN_FLING_VELOCITY; if (attrs != null) { TypedArray defAttrs = context.obtainStyledAttributes(attrs, DEFAULT_ATTRS); - if (defAttrs != null) { - int gravity = defAttrs.getInt(0, Gravity.NO_GRAVITY); - if (gravity != Gravity.TOP && gravity != Gravity.BOTTOM) { - throw new IllegalArgumentException("gravity must be set to either top or bottom"); - } - mIsSlidingUp = gravity == Gravity.BOTTOM; + int gravity = defAttrs.getInt(0, Gravity.NO_GRAVITY); + if (gravity != Gravity.TOP && gravity != Gravity.BOTTOM) { + throw new IllegalArgumentException("gravity must be set to either top or bottom"); } + mIsSlidingUp = gravity == Gravity.BOTTOM; defAttrs.recycle(); TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.SlidingUpPanelLayout); - if (ta != null) { - mPanelHeight = ta.getDimensionPixelSize(R.styleable.SlidingUpPanelLayout_panelHeight, -1); - mSlidePanelOffset = ta.getDimensionPixelSize(R.styleable.SlidingUpPanelLayout_slidePanelOffset, DEFAULT_SLIDE_PANEL_OFFSET); - mShadowHeight = ta.getDimensionPixelSize(R.styleable.SlidingUpPanelLayout_shadowHeight, -1); - mParallaxOffset = ta.getDimensionPixelSize(R.styleable.SlidingUpPanelLayout_paralaxOffset, -1); - mDirectOffset = ta.getBoolean(R.styleable.SlidingUpPanelLayout_directOffset,DEFAULT_DIRECT_OFFSET_FLAG); - - mMinFlingVelocity = ta.getInt(R.styleable.SlidingUpPanelLayout_flingVelocity, DEFAULT_MIN_FLING_VELOCITY); - mCoveredFadeColor = ta.getColor(R.styleable.SlidingUpPanelLayout_fadeColor, DEFAULT_FADE_COLOR); - - mDragViewResId = ta.getResourceId(R.styleable.SlidingUpPanelLayout_dragView, -1); - mDragViewClickable = ta.getBoolean(R.styleable.SlidingUpPanelLayout_dragViewClickable, DEFAULT_DRAG_VIEW_CLICKABLE); - - mOverlayContent = ta.getBoolean(R.styleable.SlidingUpPanelLayout_overlay,DEFAULT_OVERLAY_FLAG); - - mAnchorPoint = ta.getFloat(R.styleable.SlidingUpPanelLayout_anchorPoint, DEFAULT_ANCHOR_POINT); - - mSlideState = SlideState.values()[ta.getInt(R.styleable.SlidingUpPanelLayout_initialState, DEFAULT_SLIDE_STATE.ordinal())]; - } + mPanelHeight = ta.getDimensionPixelSize( + R.styleable.SlidingUpPanelLayout_panelHeight, -1); + mSlidePanelOffset = ta.getDimensionPixelSize( + R.styleable.SlidingUpPanelLayout_slidePanelOffset, DEFAULT_SLIDE_PANEL_OFFSET); + mShadowHeight = ta.getDimensionPixelSize( + R.styleable.SlidingUpPanelLayout_shadowHeight, -1); + mParallaxOffset = ta.getDimensionPixelSize( + R.styleable.SlidingUpPanelLayout_paralaxOffset, -1); + mDirectOffset = ta.getBoolean( + R.styleable.SlidingUpPanelLayout_directOffset, DEFAULT_DIRECT_OFFSET_FLAG); + + minFlingVelocity = ta.getInt( + R.styleable.SlidingUpPanelLayout_flingVelocity, DEFAULT_MIN_FLING_VELOCITY); + mCoveredFadeColor = ta.getColor( + R.styleable.SlidingUpPanelLayout_fadeColor, DEFAULT_FADE_COLOR); + + mDragViewResId = ta.getResourceId( + R.styleable.SlidingUpPanelLayout_dragView, -1); + mDragViewClickable = ta.getBoolean( + R.styleable.SlidingUpPanelLayout_dragViewClickable, + DEFAULT_DRAG_VIEW_CLICKABLE); + + mOverlayContent = ta.getBoolean( + R.styleable.SlidingUpPanelLayout_overlay, DEFAULT_OVERLAY_FLAG); + + mAnchorPoint = ta.getFloat( + R.styleable.SlidingUpPanelLayout_anchorPoint, DEFAULT_ANCHOR_POINT); + + mSlideState = SlideState.values()[ta.getInt( + R.styleable.SlidingUpPanelLayout_initialState, DEFAULT_SLIDE_STATE.ordinal())]; ta.recycle(); } @@ -352,16 +372,12 @@ public class SlidingUpPanelLayout extends ViewGroup { mShadowHeight = (int) (DEFAULT_SHADOW_HEIGHT * density + 0.5f); } if (mParallaxOffset == -1) { - mParallaxOffset = (int) (DEFAULT_PARALAX_OFFSET * density); + mParallaxOffset = (int) (DEFAULT_PARALLAX_OFFSET * density); } // If the shadow height is zero, don't show the shadow if (mShadowHeight > 0) { - if (mIsSlidingUp) { - mShadowDrawable = getResources().getDrawable(R.drawable.above_shadow); - } else { - mShadowDrawable = getResources().getDrawable(R.drawable.below_shadow); - } - + mShadowDrawable = ContextCompat.getDrawable(getContext(), + mIsSlidingUp ? R.drawable.above_shadow : R.drawable.below_shadow); } else { mShadowDrawable = null; } @@ -369,7 +385,7 @@ public class SlidingUpPanelLayout extends ViewGroup { setWillNotDraw(false); mDragHelper = ViewDragHelper.create(this, 0.5f, new DragHelperCallback()); - mDragHelper.setMinVelocity(mMinFlingVelocity * density); + mDragHelper.setMinVelocity(minFlingVelocity * density); mIsSlidingEnabled = true; } @@ -385,26 +401,9 @@ public class SlidingUpPanelLayout extends ViewGroup { } } - /** - * Set the color used to fade the pane covered by the sliding pane out when the pane - * will become fully covered in the expanded state. - * - * @param color An ARGB-packed color value - */ - public void setCoveredFadeColor(int color) { - mCoveredFadeColor = color; - invalidate(); - } - - /** - * @return The ARGB-packed color value used to fade the fixed pane - */ - public int getCoveredFadeColor() { - return mCoveredFadeColor; - } - /** * Set sliding enabled flag + * * @param enabled flag value */ public void setSlidingEnabled(boolean enabled) { @@ -415,23 +414,6 @@ public class SlidingUpPanelLayout extends ViewGroup { return mIsSlidingEnabled && mSlideableView != null; } - /** - * Set the collapsed panel height in pixels - * - * @param val A height in pixels - */ - public void setPanelHeight(int val) { - mPanelHeight = val; - requestLayout(); - } - - /** - * @return The current collapsed panel height - */ - public int getPanelHeight() { - return mPanelHeight; - } - /** * Sets the panel offset when collapsed so you can exit * the boundaries of the top of the screen @@ -446,12 +428,12 @@ public class SlidingUpPanelLayout extends ViewGroup { /** * @return The current paralax offset */ - public int getCurrentParalaxOffset() { + public int getCurrentParallaxOffset() { if (mParallaxOffset < 0) { return 0; } - return (int)(mParallaxOffset * getDirectionalSlideOffset()); + return (int) (mParallaxOffset * getDirectionalSlideOffset()); } /** @@ -463,7 +445,6 @@ public class SlidingUpPanelLayout extends ViewGroup { /** * Sets the panel slide listener - * @param listener */ public void setPanelSlideListener(PanelSlideListener listener) { mPanelSlideListener = listener; @@ -478,63 +459,25 @@ public class SlidingUpPanelLayout extends ViewGroup { if (mDragView != null && mDragViewClickable) { mDragView.setOnClickListener(null); } + mDragView = dragView; if (mDragView != null) { mDragView.setClickable(true); mDragView.setFocusable(false); mDragView.setFocusableInTouchMode(false); if (mDragViewClickable) { - mDragView.setOnClickListener(new OnClickListener() { - @Override - public void onClick(View v) { - if (!isEnabled()) return; - if (!isPanelExpanded() && !isPanelAnchored()) { - expandPanel(mAnchorPoint); - } else { - collapsePanel(); - } + mDragView.setOnClickListener(v -> { + if (!isEnabled()) return; + if (!isPanelExpanded() && !isPanelAnchored()) { + expandPanel(mAnchorPoint); + } else { + collapsePanel(); } }); } } } - /** - * Set an anchor point where the panel can stop during sliding - * - * @param anchorPoint A value between 0 and 1, determining the position of the anchor point - * starting from the top of the layout. - */ - public void setAnchorPoint(float anchorPoint) { - if (anchorPoint > 0 && anchorPoint <= 1) { - mAnchorPoint = anchorPoint; - } - } - - /** - * Gets the currently set anchor point - * - * @return the currently set anchor point - */ - public float getAnchorPoint() { - return mAnchorPoint; - } - - /** - * Sets whether or not the panel overlays the content - * @param overlayed - */ - public void setOverlayed(boolean overlayed) { - mOverlayContent = overlayed; - } - - /** - * Check if the panel is set as an overlay. - */ - public boolean isOverlayed() { - return mOverlayContent; - } - void dispatchOnPanelSlide(View panel) { if (mPanelSlideListener != null) { mPanelSlideListener.onPanelSlide(panel, mSlideOffset); @@ -646,14 +589,14 @@ public class SlidingUpPanelLayout extends ViewGroup { final int childCount = getChildCount(); if (childCount != 2 && childCount != 3) { - throw new IllegalStateException("Sliding up panel layout must have exactly 2 or 3 children!"); + throw new IllegalStateException( + "Sliding up panel layout must have exactly 2 or 3 children!"); } if (childCount == 2) { mMainView = getChildAt(0); mSlideableView = getChildAt(1); } else { - mBackgroundView = getChildAt(0); mMainView = getChildAt(1); mSlideableView = getChildAt(2); } @@ -674,7 +617,8 @@ public class SlidingUpPanelLayout extends ViewGroup { final View child = getChildAt(i); final LayoutParams lp = (LayoutParams) child.getLayoutParams(); - // We always measure the sliding panel in order to know it's height (needed for show panel) + // We always measure the sliding panel in order to know it's height + // (needed for show panel) if (child.getVisibility() == GONE && child == mMainView) { continue; } @@ -703,7 +647,8 @@ public class SlidingUpPanelLayout extends ViewGroup { } if (child == mSlideableView) { - mSlideRange = MeasureSpec.getSize(childHeightSpec) - mPanelHeight + mSlidePanelOffset; + mSlideRange = MeasureSpec.getSize( + childHeightSpec) - mPanelHeight + mSlidePanelOffset; childHeightSpec += mSlidePanelOffset; } @@ -722,19 +667,20 @@ public class SlidingUpPanelLayout extends ViewGroup { if (mFirstLayout) { switch (mSlideState) { - case EXPANDED: - mSlideOffset = 1.0f; - break; - case ANCHORED: - mSlideOffset = mAnchorPoint; - break; - case HIDDEN: - int newTop = computePanelTopPosition(0.0f) + (mIsSlidingUp ? +mPanelHeight : -mPanelHeight); - mSlideOffset = computeSlideOffset(newTop); - break; - default: - mSlideOffset = 0.f; - break; + case EXPANDED: + mSlideOffset = 1.0f; + break; + case ANCHORED: + mSlideOffset = mAnchorPoint; + break; + case HIDDEN: + int newTop = computePanelTopPosition(0.0f) + + (mIsSlidingUp ? +mPanelHeight : -mPanelHeight); + mSlideOffset = computeSlideOffset(newTop); + break; + default: + mSlideOffset = 0.f; + break; } } @@ -755,14 +701,14 @@ public class SlidingUpPanelLayout extends ViewGroup { if (!mIsSlidingUp) { if (child == mMainView && !mOverlayContent) { - childTop = computePanelTopPosition(mSlideOffset) + mSlideableView.getMeasuredHeight(); + childTop = computePanelTopPosition(mSlideOffset) + + mSlideableView.getMeasuredHeight(); } } final int childBottom = childTop + childHeight; - final int childLeft = paddingLeft; - final int childRight = childLeft + child.getMeasuredWidth(); + final int childRight = paddingLeft + child.getMeasuredWidth(); - child.layout(childLeft, childTop, childRight, childBottom); + child.layout(paddingLeft, childTop, childRight, childBottom); } if (mFirstLayout) { @@ -781,16 +727,6 @@ public class SlidingUpPanelLayout extends ViewGroup { } } - /** - * Set if the drag view can have its own touch events. If set - * to true, a drag view can scroll horizontally and have its own click listener. - * - * Default is set to false. - */ - public void setEnableDragViewTouchEvents(boolean enabled) { - mIsUsingDragViewTouchEvents = enabled; - } - @Override public void setEnabled(boolean enabled) { if (!enabled) { @@ -801,10 +737,11 @@ public class SlidingUpPanelLayout extends ViewGroup { @Override public boolean onInterceptTouchEvent(MotionEvent ev) { - final int action = MotionEventCompat.getActionMasked(ev); + final int action = ev.getActionMasked(); - if (!isEnabled() || !mIsSlidingEnabled || (mIsUnableToDrag && action != MotionEvent.ACTION_DOWN)) { + if (!isEnabled() || !mIsSlidingEnabled || + (mIsUnableToDrag && action != MotionEvent.ACTION_DOWN)) { mDragHelper.cancel(); return super.onInterceptTouchEvent(ev); } @@ -830,12 +767,8 @@ public class SlidingUpPanelLayout extends ViewGroup { final float ady = Math.abs(y - mInitialMotionY); final int dragSlop = mDragHelper.getTouchSlop(); - // Handle any horizontal scrolling on the drag view. - if (mIsUsingDragViewTouchEvents && adx > dragSlop && ady < dragSlop) { - return super.onInterceptTouchEvent(ev); - } - - if ((ady > dragSlop && adx > ady) || !isDragViewUnder((int)mInitialMotionX, (int)mInitialMotionY)) { + if ((ady > dragSlop && adx > ady) || + !isDragViewUnder((int) mInitialMotionX, (int) mInitialMotionY)) { mDragHelper.cancel(); mIsUnableToDrag = true; return false; @@ -868,14 +801,6 @@ public class SlidingUpPanelLayout extends ViewGroup { screenY >= viewLocation[1] && screenY < viewLocation[1] + mDragView.getHeight(); } - private boolean expandPanel(View pane, int initialVelocity, float mSlideOffset) { - return mFirstLayout || smoothSlideTo(mSlideOffset, initialVelocity); - } - - private boolean collapsePanel(View pane, int initialVelocity) { - return mFirstLayout || smoothSlideTo(0.0f, initialVelocity); - } - /* * Computes the top position of the panel based on the slide offset. */ @@ -906,57 +831,39 @@ public class SlidingUpPanelLayout extends ViewGroup { * Collapse the sliding pane if it is currently slideable. If first layout * has already completed this will animate. * - * @return true if the pane was slideable and is now collapsed/in the process of collapsing */ - public boolean collapsePanel() { + public void collapsePanel() { if (mFirstLayout) { mSlideState = SlideState.COLLAPSED; - return true; } else { if (mSlideState == SlideState.HIDDEN || mSlideState == SlideState.COLLAPSED) - return false; - return collapsePanel(mSlideableView, 0); + return; + smoothSlideTo(0.0f); } } /** * Expand the sliding pane if it is currently slideable. - * - * @return true if the pane was slideable and is now expanded/in the process of expading */ - public boolean expandPanel() { + public void expandPanel() { if (mFirstLayout) { mSlideState = SlideState.EXPANDED; - return true; - } else { - return expandPanel(1.0f); - } - } - - /** - * Expand the sliding pane to the anchor point if it is currently slideable. - * - * @return true if the pane was slideable and is now expanded/in the process of expading - */ - public boolean anchorPanel() { - if (mFirstLayout) { - mSlideState = SlideState.ANCHORED; - return true; } else { - return expandPanel(mAnchorPoint); + expandPanel(1.0f); } } /** * Partially expand the sliding panel up to a specific offset * - * @param mSlideOffset Value between 0 and 1, where 0 is completely expanded. - * @return true if the pane was slideable and is now expanded/in the process of expanding + * @param slideOffset Value between 0 and 1, where 0 is completely expanded. */ - public boolean expandPanel(float mSlideOffset) { - if (mSlideableView == null || mSlideState == SlideState.EXPANDED) return false; + public void expandPanel(float slideOffset) { + if (mSlideableView == null || mSlideState == SlideState.EXPANDED) return; mSlideableView.setVisibility(View.VISIBLE); - return expandPanel(mSlideableView, 0, mSlideOffset); + if (!mFirstLayout) { + smoothSlideTo(slideOffset); + } } /** @@ -977,42 +884,6 @@ public class SlidingUpPanelLayout extends ViewGroup { return mSlideState == SlideState.ANCHORED; } - /** - * Check if the sliding panel in this layout is currently visible. - * - * @return true if the sliding panel is visible. - */ - public boolean isPanelHidden() { - return mSlideState == SlideState.HIDDEN; - } - - /** - * Shows the panel from the hidden state - */ - public void showPanel() { - if (mFirstLayout) { - mSlideState = SlideState.COLLAPSED; - } else { - if (mSlideableView == null || mSlideState != SlideState.HIDDEN) return; - mSlideableView.setVisibility(View.VISIBLE); - requestLayout(); - smoothSlideTo(0, 0); - } - } - - /** - * Hides the sliding panel entirely. - */ - public void hidePanel() { - if (mFirstLayout) { - mSlideState = SlideState.HIDDEN; - } else { - if (mSlideState == SlideState.DRAGGING || mSlideState == SlideState.HIDDEN) return; - int newTop = computePanelTopPosition(0.0f) + (mIsSlidingUp ? +mPanelHeight : -mPanelHeight); - smoothSlideTo(computeSlideOffset(newTop), 0); - } - } - @SuppressLint("NewApi") private void onPanelDragged(int newTop) { mSlideState = SlideState.DRAGGING; @@ -1020,12 +891,9 @@ public class SlidingUpPanelLayout extends ViewGroup { mSlideOffset = computeSlideOffset(newTop); // Update the parallax based on the new slide offset if ((mParallaxOffset > 0 || mDirectOffset) && mSlideOffset >= 0) { - int mainViewOffset = 0; - if (mParallaxOffset > 0) { - mainViewOffset = getCurrentParalaxOffset(); - } else { - mainViewOffset = (int)(getDirectionalSlideOffset() * mSlideRange); - } + int mainViewOffset = mParallaxOffset > 0 ? + getCurrentParallaxOffset() : + (int) (getDirectionalSlideOffset() * mSlideRange); mMainView.setTranslationY(mainViewOffset); } @@ -1036,8 +904,11 @@ public class SlidingUpPanelLayout extends ViewGroup { // height of the main content if (mSlideOffset <= 0 && !mOverlayContent) { // expand the main view - LayoutParams lp = (LayoutParams)mMainView.getLayoutParams(); - lp.height = mIsSlidingUp ? (newTop - getPaddingBottom()) : (getHeight() - getPaddingBottom() - mSlideableView.getMeasuredHeight() - newTop); + LayoutParams lp = (LayoutParams) mMainView.getLayoutParams(); + lp.height = mIsSlidingUp ? + (newTop - getPaddingBottom()) : + (getHeight() - getPaddingBottom() - mSlideableView.getMeasuredHeight() + - newTop); mMainView.requestLayout(); } } @@ -1066,8 +937,8 @@ public class SlidingUpPanelLayout extends ViewGroup { if (mCoveredFadeColor != 0 && mSlideOffset > 0) { final int baseAlpha = (mCoveredFadeColor & 0xff000000) >>> 24; - final int imag = (int) (baseAlpha * mSlideOffset); - final int color = imag << 24 | (mCoveredFadeColor & 0xffffff); + final int image = (int) (baseAlpha * mSlideOffset); + final int color = image << 24 | (mCoveredFadeColor & 0xffffff); mCoveredFadePaint.setColor(color); canvas.drawRect(mTmpRect, mCoveredFadePaint); } @@ -1079,21 +950,18 @@ public class SlidingUpPanelLayout extends ViewGroup { * Smoothly animate mDraggingPane to the target X position within its range. * * @param slideOffset position to animate to - * @param velocity initial velocity in case of fling, or 0. */ - boolean smoothSlideTo(float slideOffset, int velocity) { + void smoothSlideTo(float slideOffset) { if (!isSlidingEnabled()) { // Nothing to do. - return false; + return; } int panelTop = computePanelTopPosition(slideOffset); if (mDragHelper.smoothSlideViewTo(mSlideableView, mSlideableView.getLeft(), panelTop)) { setAllChildrenVisible(); ViewCompat.postInvalidateOnAnimation(this); - return true; } - return false; } @Override @@ -1135,38 +1003,6 @@ public class SlidingUpPanelLayout extends ViewGroup { } } - /** - * Tests scrollability within child views of v given a delta of dx. - * - * @param v View to test for horizontal scrollability - * @param checkV Whether the view v passed should itself be checked for scrollability (true), - * or just its children (false). - * @param dx Delta scrolled in pixels - * @param x X coordinate of the active touch point - * @param y Y coordinate of the active touch point - * @return true if child views of v can be scrolled by delta of dx. - */ - protected boolean canScroll(View v, boolean checkV, int dx, int x, int y) { - if (v instanceof ViewGroup) { - final ViewGroup group = (ViewGroup) v; - final int scrollX = v.getScrollX(); - final int scrollY = v.getScrollY(); - final int count = group.getChildCount(); - // Count backwards - let topmost views consume scroll distance first. - for (int i = count - 1; i >= 0; i--) { - final View child = group.getChildAt(i); - if (x + scrollX >= child.getLeft() && x + scrollX < child.getRight() && - y + scrollY >= child.getTop() && y + scrollY < child.getBottom() && - canScroll(child, true, dx, x + scrollX - child.getLeft(), - y + scrollY - child.getTop())) { - return true; - } - } - } - return checkV && ViewCompat.canScrollHorizontally(v, -dx); - } - - @Override protected ViewGroup.LayoutParams generateDefaultLayoutParams() { return new LayoutParams(); @@ -1219,29 +1055,31 @@ public class SlidingUpPanelLayout extends ViewGroup { @Override public void onViewDragStateChanged(int state) { - if (mDragHelper.getViewDragState() == ViewDragHelper.STATE_IDLE) { - mSlideOffset = computeSlideOffset(mSlideableView.getTop()); - - if (mSlideOffset == 1) { - if (mSlideState != SlideState.EXPANDED) { - updateObscuredViewVisibility(); - mSlideState = SlideState.EXPANDED; - dispatchOnPanelExpanded(mSlideableView); - } - } else if (mSlideOffset == 0) { - if (mSlideState != SlideState.COLLAPSED) { - mSlideState = SlideState.COLLAPSED; - dispatchOnPanelCollapsed(mSlideableView); - } - } else if (mSlideOffset < 0) { - mSlideState = SlideState.HIDDEN; - mSlideableView.setVisibility(View.GONE); - dispatchOnPanelHidden(mSlideableView); - } else if (mSlideState != SlideState.ANCHORED) { + if (mDragHelper == null || + mDragHelper.getViewDragState() != ViewDragHelper.STATE_IDLE) { + return; + } + + mSlideOffset = computeSlideOffset(mSlideableView.getTop()); + if (mSlideOffset == 1) { + if (mSlideState != SlideState.EXPANDED) { updateObscuredViewVisibility(); - mSlideState = SlideState.ANCHORED; - dispatchOnPanelAnchored(mSlideableView); + mSlideState = SlideState.EXPANDED; + dispatchOnPanelExpanded(mSlideableView); } + } else if (mSlideOffset == 0) { + if (mSlideState != SlideState.COLLAPSED) { + mSlideState = SlideState.COLLAPSED; + dispatchOnPanelCollapsed(mSlideableView); + } + } else if (mSlideOffset < 0) { + mSlideState = SlideState.HIDDEN; + mSlideableView.setVisibility(View.GONE); + dispatchOnPanelHidden(mSlideableView); + } else if (mSlideState != SlideState.ANCHORED) { + updateObscuredViewVisibility(); + mSlideState = SlideState.ANCHORED; + dispatchOnPanelAnchored(mSlideableView); } } @@ -1257,11 +1095,11 @@ public class SlidingUpPanelLayout extends ViewGroup { } @Override - public void onViewReleased(View releasedChild, float xvel, float yvel) { - int target = 0; + public void onViewReleased(View releasedChild, float xVel, float yVel) { + int target; // direction is always positive if we are sliding in the expanded direction - float direction = mIsSlidingUp ? -yvel : yvel; + float direction = mIsSlidingUp ? -yVel : yVel; if (direction > 0) { // swipe up -> expand @@ -1284,7 +1122,9 @@ public class SlidingUpPanelLayout extends ViewGroup { target = computePanelTopPosition(0.0f); } - mDragHelper.settleCapturedViewAt(releasedChild.getLeft(), target); + if (mDragHelper != null) { + mDragHelper.settleCapturedViewAt(releasedChild.getLeft(), target); + } invalidate(); } @@ -1306,18 +1146,14 @@ public class SlidingUpPanelLayout extends ViewGroup { } public static class LayoutParams extends ViewGroup.MarginLayoutParams { - private static final int[] ATTRS = new int[] { - android.R.attr.layout_weight + private static final int[] ATTRS = new int[]{ + android.R.attr.layout_weight }; public LayoutParams() { super(MATCH_PARENT, MATCH_PARENT); } - public LayoutParams(int width, int height) { - super(width, height); - } - public LayoutParams(android.view.ViewGroup.LayoutParams source) { super(source); } @@ -1326,17 +1162,12 @@ public class SlidingUpPanelLayout extends ViewGroup { super(source); } - public LayoutParams(LayoutParams source) { - super(source); - } - public LayoutParams(Context c, AttributeSet attrs) { super(c, attrs); final TypedArray a = c.obtainStyledAttributes(attrs, ATTRS); a.recycle(); } - } static class SavedState extends BaseSavedState { @@ -1363,15 +1194,15 @@ public class SlidingUpPanelLayout extends ViewGroup { public static final Parcelable.Creator CREATOR = new Parcelable.Creator() { - @Override - public SavedState createFromParcel(Parcel in) { - return new SavedState(in); - } + @Override + public SavedState createFromParcel(Parcel in) { + return new SavedState(in); + } - @Override - public SavedState[] newArray(int size) { - return new SavedState[size]; - } - }; + @Override + public SavedState[] newArray(int size) { + return new SavedState[size]; + } + }; } } diff --git a/src/org/lineageos/eleven/slidinguppanel/ViewDragHelper.java b/src/org/lineageos/eleven/slidinguppanel/ViewDragHelper.java index 39497c98a40c65cd11f2d03bab097dad6849d17e..55dc1896be194a4736dc627e3d1702b37fc214ab 100644 --- a/src/org/lineageos/eleven/slidinguppanel/ViewDragHelper.java +++ b/src/org/lineageos/eleven/slidinguppanel/ViewDragHelper.java @@ -1,5 +1,6 @@ /* * Copyright (C) 2013 The Android Open Source Project + * Copyright (C) 2021 The LineageOS Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -13,12 +14,8 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - - package org.lineageos.eleven.slidinguppanel; -import java.util.Arrays; - import android.content.Context; import android.view.MotionEvent; import android.view.VelocityTracker; @@ -27,10 +24,9 @@ import android.view.ViewConfiguration; import android.view.ViewGroup; import android.view.animation.Interpolator; -import androidx.core.view.MotionEventCompat; -import androidx.core.view.VelocityTrackerCompat; -import androidx.core.view.ViewCompat; -import androidx.core.widget.ScrollerCompat; +import android.widget.OverScroller; + +import java.util.Arrays; /** * ViewDragHelper is a utility class for writing custom ViewGroups. It offers a number @@ -65,7 +61,7 @@ public class ViewDragHelper { /** * Edge flag indicating that the left edge should be affected. */ - public static final int EDGE_LEFT = 1 << 0; + public static final int EDGE_LEFT = 1; /** * Edge flag indicating that the right edge should be affected. @@ -82,31 +78,13 @@ public class ViewDragHelper { */ public static final int EDGE_BOTTOM = 1 << 3; - /** - * Edge flag set indicating all edges should be affected. - */ - public static final int EDGE_ALL = EDGE_LEFT | EDGE_TOP | EDGE_RIGHT | EDGE_BOTTOM; - - /** - * Indicates that a check should occur along the horizontal axis - */ - public static final int DIRECTION_HORIZONTAL = 1 << 0; - - /** - * Indicates that a check should occur along the vertical axis - */ - public static final int DIRECTION_VERTICAL = 1 << 1; - - /** - * Indicates that a check should occur along all axes - */ - public static final int DIRECTION_ALL = DIRECTION_HORIZONTAL | DIRECTION_VERTICAL; - private static final int EDGE_SIZE = 20; // dp private static final int BASE_SETTLE_DURATION = 256; // ms private static final int MAX_SETTLE_DURATION = 600; // ms + private static final int TRACKING_EDGES = 0; + // Current drag state; idle, dragging or settling private int mDragState; @@ -122,16 +100,14 @@ public class ViewDragHelper { private int[] mInitialEdgesTouched; private int[] mEdgeDragsInProgress; private int[] mEdgeDragsLocked; - private int mPointersDown; private VelocityTracker mVelocityTracker; - private float mMaxVelocity; + private final float mMaxVelocity; private float mMinVelocity; - private int mEdgeSize; - private int mTrackingEdges; + private final int mEdgeSize; - private ScrollerCompat mScroller; + private final OverScroller mScroller; private final Callback mCallback; @@ -147,29 +123,31 @@ public class ViewDragHelper { * about the state of the parent view upon request. The callback also makes decisions * governing the range and draggability of child views. */ + @SuppressWarnings("unused") public static abstract class Callback { /** * Called when the drag state changes. See the STATE_* constants * for more information. * * @param state The new drag state - * * @see #STATE_IDLE * @see #STATE_DRAGGING * @see #STATE_SETTLING */ - public void onViewDragStateChanged(int state) {} + public void onViewDragStateChanged(int state) { + } /** * Called when the captured view's position changes as the result of a drag or settle. * * @param changedView View whose position changed - * @param left New X coordinate of the left edge of the view - * @param top New Y coordinate of the top edge of the view - * @param dx Change in X position from the last call - * @param dy Change in Y position from the last call + * @param left New X coordinate of the left edge of the view + * @param top New Y coordinate of the top edge of the view + * @param dx Change in X position from the last call + * @param dy Change in Y position from the last call */ - public void onViewPositionChanged(View changedView, int left, int top, int dx, int dy) {} + public void onViewPositionChanged(View changedView, int left, int top, int dx, int dy) { + } /** * Called when a child view is captured for dragging or settling. The ID of the pointer @@ -177,10 +155,11 @@ public class ViewDragHelper { * identified as {@link #INVALID_POINTER} the capture is programmatic instead of * pointer-initiated. * - * @param capturedChild Child view that was captured + * @param capturedChild Child view that was captured * @param activePointerId Pointer id tracking the child capture */ - public void onViewCaptured(View capturedChild, int activePointerId) {} + public void onViewCaptured(View capturedChild, int activePointerId) { + } /** * Called when the child view is no longer being actively dragged. @@ -188,19 +167,22 @@ public class ViewDragHelper { * be clamped to system minimums or maximums. * *

Calling code may decide to fling or otherwise release the view to let it - * settle into place. It should do so using {@link #settleCapturedViewAt(int, int)} - * or {@link #flingCapturedView(int, int, int, int)}. If the Callback invokes - * one of these methods, the ViewDragHelper will enter {@link #STATE_SETTLING} - * and the view capture will not fully end until it comes to a complete stop. + * settle into place. It should do so using {@link #settleCapturedViewAt(int, int)}. + * If the Callback invokes one of these methods, the ViewDragHelper will enter + * {@link #STATE_SETTLING} and the view capture will not fully end until it comes to a + * complete stop. * If neither of these methods is invoked before onViewReleased returns, * the view will stop in place and the ViewDragHelper will return to * {@link #STATE_IDLE}.

* * @param releasedChild The captured child view now being released - * @param xvel X velocity of the pointer as it left the screen in pixels per second. - * @param yvel Y velocity of the pointer as it left the screen in pixels per second. + * @param xVel X velocity of the pointer as it left the screen in pixels per + * second. + * @param yVel Y velocity of the pointer as it left the screen in pixels per + * second. */ - public void onViewReleased(View releasedChild, float xvel, float yvel) {} + public void onViewReleased(View releasedChild, float xVel, float yVel) { + } /** * Called when one of the subscribed edges in the parent view has been touched @@ -213,7 +195,9 @@ public class ViewDragHelper { * @see #EDGE_RIGHT * @see #EDGE_BOTTOM */ - public void onEdgeTouched(int edgeFlags, int pointerId) {} + @SuppressWarnings("EmptyMethod") + public void onEdgeTouched(int edgeFlags, int pointerId) { + } /** * Called when the given edge may become locked. This can happen if an edge drag @@ -224,6 +208,7 @@ public class ViewDragHelper { * @param edgeFlags A combination of edge flags describing the edge(s) locked * @return true to lock the edge, false to leave it unlocked */ + @SuppressWarnings("SameReturnValue") public boolean onEdgeLock(int edgeFlags) { return false; } @@ -239,7 +224,9 @@ public class ViewDragHelper { * @see #EDGE_RIGHT * @see #EDGE_BOTTOM */ - public void onEdgeDragStarted(int edgeFlags, int pointerId) {} + @SuppressWarnings("EmptyMethod") + public void onEdgeDragStarted(int edgeFlags, int pointerId) { + } /** * Called to determine the Z-order of child views. @@ -258,6 +245,7 @@ public class ViewDragHelper { * @param child Child view to check * @return range of horizontal motion in pixels */ + @SuppressWarnings("SameReturnValue") public int getViewHorizontalDragRange(View child) { return 0; } @@ -285,7 +273,7 @@ public class ViewDragHelper { *

If this method returns true, a call to {@link #onViewCaptured(android.view.View, int)} * will follow if the capture is successful.

* - * @param child Child the user is attempting to capture + * @param child Child the user is attempting to capture * @param pointerId ID of the pointer attempting the capture * @return true if capture should be allowed, false otherwise */ @@ -296,12 +284,12 @@ public class ViewDragHelper { * The default implementation does not allow horizontal motion; the extending * class must override this method and provide the desired clamping. * - * * @param child Child view being dragged - * @param left Attempted motion along the X axis - * @param dx Proposed change in position for left + * @param left Attempted motion along the X axis + * @param dx Proposed change in position for left * @return The new clamped position for left */ + @SuppressWarnings("SameReturnValue") public int clampViewPositionHorizontal(View child, int left, int dx) { return 0; } @@ -311,10 +299,9 @@ public class ViewDragHelper { * The default implementation does not allow vertical motion; the extending * class must override this method and provide the desired clamping. * - * * @param child Child view being dragged - * @param top Attempted motion along the Y axis - * @param dy Proposed change in position for top + * @param top Attempted motion along the Y axis + * @param dy Proposed change in position for top * @return The new clamped position for top */ public int clampViewPositionVertical(View child, int top, int dy) { @@ -325,24 +312,18 @@ public class ViewDragHelper { /** * Interpolator defining the animation curve for mScroller */ - private static final Interpolator sInterpolator = new Interpolator() { - public float getInterpolation(float t) { - t -= 1.0f; - return t * t * t * t * t + 1.0f; - } + private static final Interpolator sInterpolator = t -> { + t -= 1.0f; + return t * t * t * t * t + 1.0f; }; - private final Runnable mSetIdleRunnable = new Runnable() { - public void run() { - setDragState(STATE_IDLE); - } - }; + private final Runnable mSetIdleRunnable = () -> setDragState(STATE_IDLE); /** * Factory method to create a new ViewDragHelper. * * @param forParent Parent view to monitor - * @param cb Callback to provide information and receive events + * @param cb Callback to provide information and receive events * @return a new ViewDragHelper instance */ public static ViewDragHelper create(ViewGroup forParent, Callback cb) { @@ -352,10 +333,10 @@ public class ViewDragHelper { /** * Factory method to create a new ViewDragHelper. * - * @param forParent Parent view to monitor + * @param forParent Parent view to monitor * @param sensitivity Multiplier for how sensitive the helper should be about detecting * the start of a drag. Larger values are more sensitive. 1.0f is normal. - * @param cb Callback to provide information and receive events + * @param cb Callback to provide information and receive events * @return a new ViewDragHelper instance */ public static ViewDragHelper create(ViewGroup forParent, float sensitivity, Callback cb) { @@ -369,7 +350,7 @@ public class ViewDragHelper { * This will allow VDH to use internal compatibility implementations for different * platform versions. * - * @param context Context to initialize config-dependent params from + * @param context Context to initialize config-dependent params from * @param forParent Parent view to monitor */ private ViewDragHelper(Context context, ViewGroup forParent, Callback cb) { @@ -390,7 +371,7 @@ public class ViewDragHelper { mTouchSlop = vc.getScaledTouchSlop(); mMaxVelocity = vc.getScaledMaximumFlingVelocity(); mMinVelocity = vc.getScaledMinimumFlingVelocity(); - mScroller = ScrollerCompat.create(context, sInterpolator); + mScroller = new OverScroller(context, sInterpolator); } /** @@ -403,59 +384,22 @@ public class ViewDragHelper { mMinVelocity = minVel; } - /** - * Return the currently configured minimum velocity. Any flings with a magnitude less - * than this value in pixels per second. Callback methods accepting a velocity will receive - * zero as a velocity value if the real detected velocity was below this threshold. - * - * @return the minimum velocity that will be detected - */ - public float getMinVelocity() { - return mMinVelocity; - } - /** * Retrieve the current drag state of this helper. This will return one of * {@link #STATE_IDLE}, {@link #STATE_DRAGGING} or {@link #STATE_SETTLING}. + * * @return The current drag state */ public int getViewDragState() { return mDragState; } - /** - * Enable edge tracking for the selected edges of the parent view. - * The callback's {@link Callback#onEdgeTouched(int, int)} and - * {@link Callback#onEdgeDragStarted(int, int)} methods will only be invoked - * for edges for which edge tracking has been enabled. - * - * @param edgeFlags Combination of edge flags describing the edges to watch - * @see #EDGE_LEFT - * @see #EDGE_TOP - * @see #EDGE_RIGHT - * @see #EDGE_BOTTOM - */ - public void setEdgeTrackingEnabled(int edgeFlags) { - mTrackingEdges = edgeFlags; - } - - /** - * Return the size of an edge. This is the range in pixels along the edges of this view - * that will actively detect edge touches or drags if edge tracking is enabled. - * - * @return The size of an edge in pixels - * @see #setEdgeTrackingEnabled(int) - */ - public int getEdgeSize() { - return mEdgeSize; - } - /** * Capture a specific child view for dragging within the parent. The callback will be notified * but {@link Callback#tryCaptureView(android.view.View, int)} will not be asked permission to * capture this view. * - * @param childView Child view to capture + * @param childView Child view to capture * @param activePointerId ID of the pointer that is dragging the captured child view */ public void captureChildView(View childView, int activePointerId) { @@ -470,21 +414,6 @@ public class ViewDragHelper { setDragState(STATE_DRAGGING); } - /** - * @return The currently captured view, or null if no view has been captured. - */ - public View getCapturedView() { - return mCapturedView; - } - - /** - * @return The ID of the pointer currently dragging the captured view, - * or {@link #INVALID_POINTER}. - */ - public int getActivePointerId() { - return mActivePointerId; - } - /** * @return The minimum distance in pixels that the user must travel to initiate a drag */ @@ -529,12 +458,11 @@ public class ViewDragHelper { * on each subsequent frame to continue the motion until it returns false. If this method * returns false there is no further work to do to complete the movement. * - *

This operation does not count as a capture event, though {@link #getCapturedView()} - * will still report the sliding view while the slide is in progress.

+ *

This operation does not count as a capture event

* - * @param child Child view to capture and animate + * @param child Child view to capture and animate * @param finalLeft Final left position of child - * @param finalTop Final top position of child + * @param finalTop Final top position of child * @return true if animation should continue through {@link #continueSettling(boolean)} calls */ public boolean smoothSlideViewTo(View child, int finalLeft, int finalTop) { @@ -552,27 +480,26 @@ public class ViewDragHelper { * returns false there is no further work to do to complete the movement. * * @param finalLeft Settled left edge position for the captured view - * @param finalTop Settled top edge position for the captured view - * @return true if animation should continue through {@link #continueSettling(boolean)} calls + * @param finalTop Settled top edge position for the captured view */ - public boolean settleCapturedViewAt(int finalLeft, int finalTop) { + public void settleCapturedViewAt(int finalLeft, int finalTop) { if (!mReleaseInProgress) { throw new IllegalStateException("Cannot settleCapturedViewAt outside of a call to " + "Callback#onViewReleased"); } - return forceSettleCapturedViewAt(finalLeft, finalTop, - (int) VelocityTrackerCompat.getXVelocity(mVelocityTracker, mActivePointerId), - (int) VelocityTrackerCompat.getYVelocity(mVelocityTracker, mActivePointerId)); + forceSettleCapturedViewAt(finalLeft, finalTop, + (int) mVelocityTracker.getXVelocity(mActivePointerId), + (int) mVelocityTracker.getYVelocity(mActivePointerId)); } /** * Settle the captured view at the given (left, top) position. * * @param finalLeft Target left position for the captured view - * @param finalTop Target top position for the captured view - * @param xvel Horizontal velocity - * @param yvel Vertical velocity + * @param finalTop Target top position for the captured view + * @param xvel Horizontal velocity + * @param yvel Vertical velocity * @return true if animation should continue through {@link #continueSettling(boolean)} calls */ private boolean forceSettleCapturedViewAt(int finalLeft, int finalTop, int xvel, int yvel) { @@ -643,7 +570,7 @@ public class ViewDragHelper { * If the value is below the minimum, it will be clamped to zero. * If the value is above the maximum, it will be clamped to the maximum. * - * @param value Value to clamp + * @param value Value to clamp * @param absMin Absolute value of the minimum significant value to return * @param absMax Absolute value of the maximum value to return * @return The clamped value with the same sign as value @@ -660,7 +587,7 @@ public class ViewDragHelper { * If the value is below the minimum, it will be clamped to zero. * If the value is above the maximum, it will be clamped to the maximum. * - * @param value Value to clamp + * @param value Value to clamp * @param absMin Absolute value of the minimum significant value to return * @param absMax Absolute value of the maximum value to return * @return The clamped value with the same sign as value @@ -678,30 +605,6 @@ public class ViewDragHelper { return (float) Math.sin(f); } - /** - * Settle the captured view based on standard free-moving fling behavior. - * The caller should invoke {@link #continueSettling(boolean)} on each subsequent frame - * to continue the motion until it returns false. - * - * @param minLeft Minimum X position for the view's left edge - * @param minTop Minimum Y position for the view's top edge - * @param maxLeft Maximum X position for the view's left edge - * @param maxTop Maximum Y position for the view's top edge - */ - public void flingCapturedView(int minLeft, int minTop, int maxLeft, int maxTop) { - if (!mReleaseInProgress) { - throw new IllegalStateException("Cannot flingCapturedView outside of a call to " + - "Callback#onViewReleased"); - } - - mScroller.fling(mCapturedView.getLeft(), mCapturedView.getTop(), - (int) VelocityTrackerCompat.getXVelocity(mVelocityTracker, mActivePointerId), - (int) VelocityTrackerCompat.getYVelocity(mVelocityTracker, mActivePointerId), - minLeft, maxLeft, minTop, maxTop); - - setDragState(STATE_SETTLING); - } - /** * Move the captured settling view by the appropriate amount for the current time. * If continueSettling returns true, the caller should call it again @@ -754,8 +657,7 @@ public class ViewDragHelper { /** * Like all callback events this must happen on the UI thread, but release * involves some extra semantics. During a release (mReleaseInProgress) - * is the only time it is valid to call {@link #settleCapturedViewAt(int, int)} - * or {@link #flingCapturedView(int, int, int, int)}. + * is the only time it is valid to call {@link #settleCapturedViewAt(int, int)}. */ private void dispatchViewReleased(float xvel, float yvel) { mReleaseInProgress = true; @@ -779,7 +681,6 @@ public class ViewDragHelper { Arrays.fill(mInitialEdgesTouched, 0); Arrays.fill(mEdgeDragsInProgress, 0); Arrays.fill(mEdgeDragsLocked, 0); - mPointersDown = 0; } private void clearMotionHistory(int pointerId) { @@ -793,7 +694,6 @@ public class ViewDragHelper { mInitialEdgesTouched[pointerId] = 0; mEdgeDragsInProgress[pointerId] = 0; mEdgeDragsLocked[pointerId] = 0; - mPointersDown &= ~(1 << pointerId); } private void ensureMotionHistorySizeForId(int pointerId) { @@ -831,37 +731,19 @@ public class ViewDragHelper { mInitialMotionX[pointerId] = mLastMotionX[pointerId] = x; mInitialMotionY[pointerId] = mLastMotionY[pointerId] = y; mInitialEdgesTouched[pointerId] = getEdgesTouched((int) x, (int) y); - mPointersDown |= 1 << pointerId; } private void saveLastMotion(MotionEvent ev) { - final int pointerCount = MotionEventCompat.getPointerCount(ev); + final int pointerCount = ev.getPointerCount(); for (int i = 0; i < pointerCount; i++) { - final int pointerId = MotionEventCompat.getPointerId(ev, i); - final float x = MotionEventCompat.getX(ev, i); - final float y = MotionEventCompat.getY(ev, i); + final int pointerId = ev.getPointerId(i); + final float x = ev.getX(i); + final float y = ev.getY(i); mLastMotionX[pointerId] = x; mLastMotionY[pointerId] = y; } } - /** - * Check if the given pointer ID represents a pointer that is currently down (to the best - * of the ViewDragHelper's knowledge). - * - *

The state used to report this information is populated by the methods - * {@link #shouldInterceptTouchEvent(android.view.MotionEvent)} or - * {@link #processTouchEvent(android.view.MotionEvent)}. If one of these methods has not - * been called for all relevant MotionEvents to track, the information reported - * by this method may be stale or incorrect.

- * - * @param pointerId pointer ID to check; corresponds to IDs provided by MotionEvent - * @return true if the pointer with the given ID is still down - */ - public boolean isPointerDown(int pointerId) { - return (mPointersDown & 1 << pointerId) != 0; - } - void setDragState(int state) { if (mDragState != state) { mDragState = state; @@ -894,42 +776,6 @@ public class ViewDragHelper { return false; } - /** - * Tests scrollability within child views of v given a delta of dx. - * - * @param v View to test for horizontal scrollability - * @param checkV Whether the view v passed should itself be checked for scrollability (true), - * or just its children (false). - * @param dx Delta scrolled in pixels along the X axis - * @param dy Delta scrolled in pixels along the Y axis - * @param x X coordinate of the active touch point - * @param y Y coordinate of the active touch point - * @return true if child views of v can be scrolled by delta of dx. - */ - protected boolean canScroll(View v, boolean checkV, int dx, int dy, int x, int y) { - if (v instanceof ViewGroup) { - final ViewGroup group = (ViewGroup) v; - final int scrollX = v.getScrollX(); - final int scrollY = v.getScrollY(); - final int count = group.getChildCount(); - // Count backwards - let topmost views consume scroll distance first. - for (int i = count - 1; i >= 0; i--) { - // TODO: Add versioned support here for transformed views. - // This will not work for transformed views in Honeycomb+ - final View child = group.getChildAt(i); - if (x + scrollX >= child.getLeft() && x + scrollX < child.getRight() && - y + scrollY >= child.getTop() && y + scrollY < child.getBottom() && - canScroll(child, true, dx, dy, x + scrollX - child.getLeft(), - y + scrollY - child.getTop())) { - return true; - } - } - } - - return checkV && (ViewCompat.canScrollHorizontally(v, -dx) || - ViewCompat.canScrollVertically(v, -dy)); - } - /** * Check if this event as provided to the parent view's onInterceptTouchEvent should * cause the parent to intercept the touch event stream. @@ -938,8 +784,8 @@ public class ViewDragHelper { * @return true if the parent view should return true from onInterceptTouchEvent */ public boolean shouldInterceptTouchEvent(MotionEvent ev) { - final int action = MotionEventCompat.getActionMasked(ev); - final int actionIndex = MotionEventCompat.getActionIndex(ev); + final int action = ev.getActionMasked(); + final int actionIndex = ev.getActionIndex(); if (action == MotionEvent.ACTION_DOWN) { // Reset things for a new event stream, just in case we didn't get @@ -956,7 +802,7 @@ public class ViewDragHelper { case MotionEvent.ACTION_DOWN: { final float x = ev.getX(); final float y = ev.getY(); - final int pointerId = MotionEventCompat.getPointerId(ev, 0); + final int pointerId = ev.getPointerId(0); saveInitialMotion(x, y, pointerId); final View toCapture = findTopChildUnder((int) x, (int) y); @@ -967,24 +813,24 @@ public class ViewDragHelper { } final int edgesTouched = mInitialEdgesTouched[pointerId]; - if ((edgesTouched & mTrackingEdges) != 0) { - mCallback.onEdgeTouched(edgesTouched & mTrackingEdges, pointerId); + if ((edgesTouched & TRACKING_EDGES) != 0) { + mCallback.onEdgeTouched(edgesTouched & TRACKING_EDGES, pointerId); } break; } - case MotionEventCompat.ACTION_POINTER_DOWN: { - final int pointerId = MotionEventCompat.getPointerId(ev, actionIndex); - final float x = MotionEventCompat.getX(ev, actionIndex); - final float y = MotionEventCompat.getY(ev, actionIndex); + case MotionEvent.ACTION_POINTER_DOWN: { + final int pointerId = ev.getPointerId(actionIndex); + final float x = ev.getX(actionIndex); + final float y = ev.getY(actionIndex); saveInitialMotion(x, y, pointerId); // A ViewDragHelper can only manipulate one view at a time. if (mDragState == STATE_IDLE) { final int edgesTouched = mInitialEdgesTouched[pointerId]; - if ((edgesTouched & mTrackingEdges) != 0) { - mCallback.onEdgeTouched(edgesTouched & mTrackingEdges, pointerId); + if ((edgesTouched & TRACKING_EDGES) != 0) { + mCallback.onEdgeTouched(edgesTouched & TRACKING_EDGES, pointerId); } } else if (mDragState == STATE_SETTLING) { // Catch a settling view if possible. @@ -998,11 +844,12 @@ public class ViewDragHelper { case MotionEvent.ACTION_MOVE: { // First to cross a touch slop over a draggable view wins. Also report edge drags. - final int pointerCount = MotionEventCompat.getPointerCount(ev); - for (int i = 0; i < pointerCount && mInitialMotionX != null && mInitialMotionY != null; i++) { - final int pointerId = MotionEventCompat.getPointerId(ev, i); - final float x = MotionEventCompat.getX(ev, i); - final float y = MotionEventCompat.getY(ev, i); + final int pointerCount = ev.getPointerCount(); + for (int i = 0; i < pointerCount && mInitialMotionX != null && + mInitialMotionY != null; i++) { + final int pointerId = ev.getPointerId(i); + final float x = ev.getX(i); + final float y = ev.getY(i); final float dx = x - mInitialMotionX[pointerId]; final float dy = y - mInitialMotionY[pointerId]; @@ -1012,8 +859,9 @@ public class ViewDragHelper { break; } - final View toCapture = findTopChildUnder((int)mInitialMotionX[pointerId], (int)mInitialMotionY[pointerId]); - if (toCapture != null && checkTouchSlop(toCapture, dx, dy) && + final View toCapture = findTopChildUnder( + (int) mInitialMotionX[pointerId], (int) mInitialMotionY[pointerId]); + if (checkTouchSlop(toCapture, dx, dy) && tryCaptureViewForDrag(toCapture, pointerId)) { break; } @@ -1022,8 +870,8 @@ public class ViewDragHelper { break; } - case MotionEventCompat.ACTION_POINTER_UP: { - final int pointerId = MotionEventCompat.getPointerId(ev, actionIndex); + case MotionEvent.ACTION_POINTER_UP: { + final int pointerId = ev.getPointerId(actionIndex); clearMotionHistory(pointerId); break; } @@ -1045,8 +893,8 @@ public class ViewDragHelper { * @param ev The touch event received by the parent view */ public void processTouchEvent(MotionEvent ev) { - final int action = MotionEventCompat.getActionMasked(ev); - final int actionIndex = MotionEventCompat.getActionIndex(ev); + final int action = ev.getActionMasked(); + final int actionIndex = ev.getActionIndex(); if (action == MotionEvent.ACTION_DOWN) { // Reset things for a new event stream, just in case we didn't get @@ -1063,7 +911,7 @@ public class ViewDragHelper { case MotionEvent.ACTION_DOWN: { final float x = ev.getX(); final float y = ev.getY(); - final int pointerId = MotionEventCompat.getPointerId(ev, 0); + final int pointerId = ev.getPointerId(0); final View toCapture = findTopChildUnder((int) x, (int) y); saveInitialMotion(x, y, pointerId); @@ -1074,16 +922,16 @@ public class ViewDragHelper { tryCaptureViewForDrag(toCapture, pointerId); final int edgesTouched = mInitialEdgesTouched[pointerId]; - if ((edgesTouched & mTrackingEdges) != 0) { - mCallback.onEdgeTouched(edgesTouched & mTrackingEdges, pointerId); + if ((edgesTouched & TRACKING_EDGES) != 0) { + mCallback.onEdgeTouched(edgesTouched & TRACKING_EDGES, pointerId); } break; } - case MotionEventCompat.ACTION_POINTER_DOWN: { - final int pointerId = MotionEventCompat.getPointerId(ev, actionIndex); - final float x = MotionEventCompat.getX(ev, actionIndex); - final float y = MotionEventCompat.getY(ev, actionIndex); + case MotionEvent.ACTION_POINTER_DOWN: { + final int pointerId = ev.getPointerId(actionIndex); + final float x = ev.getX(actionIndex); + final float y = ev.getY(actionIndex); saveInitialMotion(x, y, pointerId); @@ -1095,8 +943,8 @@ public class ViewDragHelper { tryCaptureViewForDrag(toCapture, pointerId); final int edgesTouched = mInitialEdgesTouched[pointerId]; - if ((edgesTouched & mTrackingEdges) != 0) { - mCallback.onEdgeTouched(edgesTouched & mTrackingEdges, pointerId); + if ((edgesTouched & TRACKING_EDGES) != 0) { + mCallback.onEdgeTouched(edgesTouched & TRACKING_EDGES, pointerId); } } else if (isCapturedViewUnder((int) x, (int) y)) { // We're still tracking a captured view. If the same view is under this @@ -1110,22 +958,20 @@ public class ViewDragHelper { case MotionEvent.ACTION_MOVE: { if (mDragState == STATE_DRAGGING) { - final int index = MotionEventCompat.findPointerIndex(ev, mActivePointerId); - final float x = MotionEventCompat.getX(ev, index); - final float y = MotionEventCompat.getY(ev, index); + final int index = ev.findPointerIndex(mActivePointerId); + final float x = ev.getX(index); + final float y = ev.getY(index); final int idx = (int) (x - mLastMotionX[mActivePointerId]); final int idy = (int) (y - mLastMotionY[mActivePointerId]); dragTo(mCapturedView.getLeft() + idx, mCapturedView.getTop() + idy, idx, idy); - - saveLastMotion(ev); } else { // Check to see if any pointer is now over a draggable view. - final int pointerCount = MotionEventCompat.getPointerCount(ev); + final int pointerCount = ev.getPointerCount(); for (int i = 0; i < pointerCount; i++) { - final int pointerId = MotionEventCompat.getPointerId(ev, i); - final float x = MotionEventCompat.getX(ev, i); - final float y = MotionEventCompat.getY(ev, i); + final int pointerId = ev.getPointerId(i); + final float x = ev.getX(i); + final float y = ev.getY(i); final float dx = x - mInitialMotionX[pointerId]; final float dy = y - mInitialMotionY[pointerId]; @@ -1141,26 +987,26 @@ public class ViewDragHelper { break; } } - saveLastMotion(ev); } + saveLastMotion(ev); break; } - case MotionEventCompat.ACTION_POINTER_UP: { - final int pointerId = MotionEventCompat.getPointerId(ev, actionIndex); + case MotionEvent.ACTION_POINTER_UP: { + final int pointerId = ev.getPointerId(actionIndex); if (mDragState == STATE_DRAGGING && pointerId == mActivePointerId) { // Try to find another pointer that's still holding on to the captured view. int newActivePointer = INVALID_POINTER; - final int pointerCount = MotionEventCompat.getPointerCount(ev); + final int pointerCount = ev.getPointerCount(); for (int i = 0; i < pointerCount; i++) { - final int id = MotionEventCompat.getPointerId(ev, i); + final int id = ev.getPointerId(i); if (id == mActivePointerId) { // This one's going away, skip. continue; } - final float x = MotionEventCompat.getX(ev, i); - final float y = MotionEventCompat.getY(ev, i); + final float x = ev.getX(i); + final float y = ev.getY(i); if (findTopChildUnder((int) x, (int) y) == mCapturedView && tryCaptureViewForDrag(mCapturedView, id)) { newActivePointer = mActivePointerId; @@ -1220,7 +1066,7 @@ public class ViewDragHelper { final float absDelta = Math.abs(delta); final float absODelta = Math.abs(odelta); - if ((mInitialEdgesTouched[pointerId] & edge) != edge || (mTrackingEdges & edge) == 0 || + if ((mInitialEdgesTouched[pointerId] & edge) != edge || (TRACKING_EDGES & edge) == 0 || (mEdgeDragsLocked[pointerId] & edge) == edge || (mEdgeDragsInProgress[pointerId] & edge) == edge || (absDelta <= mTouchSlop && absODelta <= mTouchSlop)) { @@ -1239,8 +1085,8 @@ public class ViewDragHelper { * along that axis will not count toward the slop check. * * @param child Child to check - * @param dx Motion since initial position along X axis - * @param dy Motion since initial position along Y axis + * @param dx Motion since initial position along X axis + * @param dy Motion since initial position along Y axis * @return true if the touch slop has been crossed */ private boolean checkTouchSlop(View child, float dx, float dy) { @@ -1260,108 +1106,15 @@ public class ViewDragHelper { return false; } - /** - * Check if any pointer tracked in the current gesture has crossed - * the required slop threshold. - * - *

This depends on internal state populated by - * {@link #shouldInterceptTouchEvent(android.view.MotionEvent)} or - * {@link #processTouchEvent(android.view.MotionEvent)}. You should only rely on - * the results of this method after all currently available touch data - * has been provided to one of these two methods.

- * - * @param directions Combination of direction flags, see {@link #DIRECTION_HORIZONTAL}, - * {@link #DIRECTION_VERTICAL}, {@link #DIRECTION_ALL} - * @return true if the slop threshold has been crossed, false otherwise - */ - public boolean checkTouchSlop(int directions) { - final int count = mInitialMotionX.length; - for (int i = 0; i < count; i++) { - if (checkTouchSlop(directions, i)) { - return true; - } - } - return false; - } - - /** - * Check if the specified pointer tracked in the current gesture has crossed - * the required slop threshold. - * - *

This depends on internal state populated by - * {@link #shouldInterceptTouchEvent(android.view.MotionEvent)} or - * {@link #processTouchEvent(android.view.MotionEvent)}. You should only rely on - * the results of this method after all currently available touch data - * has been provided to one of these two methods.

- * - * @param directions Combination of direction flags, see {@link #DIRECTION_HORIZONTAL}, - * {@link #DIRECTION_VERTICAL}, {@link #DIRECTION_ALL} - * @param pointerId ID of the pointer to slop check as specified by MotionEvent - * @return true if the slop threshold has been crossed, false otherwise - */ - public boolean checkTouchSlop(int directions, int pointerId) { - if (!isPointerDown(pointerId)) { - return false; - } - - final boolean checkHorizontal = (directions & DIRECTION_HORIZONTAL) == DIRECTION_HORIZONTAL; - final boolean checkVertical = (directions & DIRECTION_VERTICAL) == DIRECTION_VERTICAL; - - final float dx = mLastMotionX[pointerId] - mInitialMotionX[pointerId]; - final float dy = mLastMotionY[pointerId] - mInitialMotionY[pointerId]; - - if (checkHorizontal && checkVertical) { - return dx * dx + dy * dy > mTouchSlop * mTouchSlop; - } else if (checkHorizontal) { - return Math.abs(dx) > mTouchSlop; - } else if (checkVertical) { - return Math.abs(dy) > mTouchSlop; - } - return false; - } - - /** - * Check if any of the edges specified were initially touched in the currently active gesture. - * If there is no currently active gesture this method will return false. - * - * @param edges Edges to check for an initial edge touch. See {@link #EDGE_LEFT}, - * {@link #EDGE_TOP}, {@link #EDGE_RIGHT}, {@link #EDGE_BOTTOM} and - * {@link #EDGE_ALL} - * @return true if any of the edges specified were initially touched in the current gesture - */ - public boolean isEdgeTouched(int edges) { - final int count = mInitialEdgesTouched.length; - for (int i = 0; i < count; i++) { - if (isEdgeTouched(edges, i)) { - return true; - } - } - return false; - } - - /** - * Check if any of the edges specified were initially touched by the pointer with - * the specified ID. If there is no currently active gesture or if there is no pointer with - * the given ID currently down this method will return false. - * - * @param edges Edges to check for an initial edge touch. See {@link #EDGE_LEFT}, - * {@link #EDGE_TOP}, {@link #EDGE_RIGHT}, {@link #EDGE_BOTTOM} and - * {@link #EDGE_ALL} - * @return true if any of the edges specified were initially touched in the current gesture - */ - public boolean isEdgeTouched(int edges, int pointerId) { - return isPointerDown(pointerId) && (mInitialEdgesTouched[pointerId] & edges) != 0; - } - private void releaseViewForPointerUp() { mVelocityTracker.computeCurrentVelocity(1000, mMaxVelocity); - final float xvel = clampMag( - VelocityTrackerCompat.getXVelocity(mVelocityTracker, mActivePointerId), + final float xVel = clampMag( + mVelocityTracker.getXVelocity(mActivePointerId), mMinVelocity, mMaxVelocity); - final float yvel = clampMag( - VelocityTrackerCompat.getYVelocity(mVelocityTracker, mActivePointerId), + final float yVel = clampMag( + mVelocityTracker.getYVelocity(mActivePointerId), mMinVelocity, mMaxVelocity); - dispatchViewReleased(xvel, yvel); + dispatchViewReleased(xVel, yVel); } private void dragTo(int left, int top, int dx, int dy) { @@ -1404,8 +1157,8 @@ public class ViewDragHelper { * parent view's coordinate system. * * @param view Child view of the parent to hit test - * @param x X position to test in the parent's coordinate system - * @param y Y position to test in the parent's coordinate system + * @param x X position to test in the parent's coordinate system + * @param y Y position to test in the parent's coordinate system * @return true if the supplied view is under the given point, false otherwise */ public boolean isViewUnder(View view, int x, int y) { @@ -1448,4 +1201,4 @@ public class ViewDragHelper { return result; } -} \ No newline at end of file +} diff --git a/src/org/lineageos/eleven/ui/HeaderBar.java b/src/org/lineageos/eleven/ui/HeaderBar.java index 67bc32ab15c85f6915c0d0df66929a1c9062b2a4..ea678a3c3f4978b6adfd0f19e681b83d884f71f9 100644 --- a/src/org/lineageos/eleven/ui/HeaderBar.java +++ b/src/org/lineageos/eleven/ui/HeaderBar.java @@ -1,18 +1,19 @@ /* -* Copyright (C) 2014 The CyanogenMod Project -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ + * Copyright (C) 2014 The CyanogenMod Project + * Copyright (C) 2021 The LineageOS Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package org.lineageos.eleven.ui; import android.content.Context; @@ -60,27 +61,18 @@ public class HeaderBar extends LinearLayout { protected void onFinishInflate() { super.onFinishInflate(); - mMenuButton = (ImageView)findViewById(R.id.header_bar_menu_button); - mMenuButton.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - showPopupMenu(); - } - }); + mMenuButton = findViewById(R.id.header_bar_menu_button); + mMenuButton.setOnClickListener(v -> showPopupMenu()); - mBackButton = (ImageView)findViewById(R.id.header_bar_up); + mBackButton = findViewById(R.id.header_bar_up); - mTitleText = (TextView)findViewById(R.id.header_bar_title); + mTitleText = findViewById(R.id.header_bar_title); } public void hideBackButton() { mBackButton.setVisibility(View.GONE); } - public void showBackButton() { - mBackButton.setVisibility(View.VISIBLE); - } - /** * @param resId set the title text */ @@ -88,24 +80,9 @@ public class HeaderBar extends LinearLayout { mTitleText.setText(resId); } - /** - * @param text set the title text - */ - public void setTitleText(String text) { - mTitleText.setText(text); - } - - /** - * Sets the back button listener - * @param listener listener - */ - public void setBackListener(final OnClickListener listener) { - mBackButton.setOnClickListener(listener); - setOnClickListener(listener); - } - /** * Sets the header bar listener + * * @param listener listener */ public void setHeaderClickListener(final OnClickListener listener) { @@ -116,12 +93,7 @@ public class HeaderBar extends LinearLayout { // create the popup menu if (mPopupMenu == null) { mPopupMenu = new PopupMenu(mFragment.getActivity(), mMenuButton); - mPopupMenu.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() { - @Override - public boolean onMenuItemClick(MenuItem item) { - return onPopupMenuItemClick(item); - } - }); + mPopupMenu.setOnMenuItemClickListener(this::onPopupMenuItemClick); } final Menu menu = mPopupMenu.getMenu(); @@ -143,29 +115,25 @@ public class HeaderBar extends LinearLayout { } public boolean onPopupMenuItemClick(final MenuItem item) { - switch (item.getItemId()) { - case R.id.menu_shuffle_all: - // Shuffle all the songs - MusicUtils.shuffleAll(mFragment.getActivity()); - return true; - case R.id.menu_settings: - // Settings - NavUtils.openSettings(mFragment.getActivity()); - return true; - case R.id.menu_save_queue: - NowPlayingCursor queue = (NowPlayingCursor) QueueLoader - .makeQueueCursor(mFragment.getActivity()); - CreateNewPlaylist.getInstance(MusicUtils.getSongListForCursor(queue)).show( - mFragment.getFragmentManager(), "CreatePlaylist"); - queue.close(); - return true; - case R.id.menu_clear_queue: - MusicUtils.clearQueue(); - return true; - default: - break; + final int id = item.getItemId(); + if (id == R.id.menu_shuffle_all) { + // Shuffle all the songs + MusicUtils.shuffleAll(mFragment.getActivity()); + } else if (id == R.id.menu_settings) { + // Settings + NavUtils.openSettings(mFragment.getActivity()); + } else if (id == R.id.menu_save_queue) { + NowPlayingCursor queue = (NowPlayingCursor) QueueLoader + .makeQueueCursor(mFragment.getActivity()); + CreateNewPlaylist.getInstance(MusicUtils.getSongListForCursor(queue)).show( + mFragment.getChildFragmentManager(), "CreatePlaylist"); + queue.close(); + } else if (id == R.id.menu_clear_queue) { + MusicUtils.clearQueue(); + } else { + return false; } - return false; + return true; } } diff --git a/src/org/lineageos/eleven/ui/MusicHolder.java b/src/org/lineageos/eleven/ui/MusicHolder.java index 4f2650d5a8cb774aa15f9e874b764cc600bb0d3a..9b7494429c8d30735a7ca40868e0c47d73c80565 100644 --- a/src/org/lineageos/eleven/ui/MusicHolder.java +++ b/src/org/lineageos/eleven/ui/MusicHolder.java @@ -1,7 +1,7 @@ /* * Copyright (C) 2012 Andrew Neal * Copyright (C) 2014 The CyanogenMod Project - * Copyright (C) 2019 The LineageOS Project + * Copyright (C) 2019-2021 The LineageOS Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -15,15 +15,14 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package org.lineageos.eleven.ui; -import android.content.Context; import android.view.View; import android.widget.ImageView; -import android.widget.RelativeLayout; import android.widget.TextView; +import androidx.recyclerview.widget.RecyclerView; + import org.lineageos.eleven.R; import org.lineageos.eleven.widgets.PlayPauseButtonContainer; import org.lineageos.eleven.widgets.PopupMenuButton; @@ -36,90 +35,81 @@ import java.lang.ref.WeakReference; * * @author Andrew Neal (andrewdneal@gmail.com) */ -public class MusicHolder { - - /** - * This is the overlay ontop of the background artist, playlist, or genre - * image - */ - public WeakReference mOverlay; +public class MusicHolder extends RecyclerView.ViewHolder { /** * This is the artist or album image */ - public WeakReference mImage; + public final WeakReference mImage; /** * This is the first line displayed in the list or grid * - * @see {@code #getView()} of a specific adapter for more detailed info + * see getView() of a specific adapter for more detailed info */ - public WeakReference mLineOne; + public final WeakReference mLineOne; /** * This is displayed on the right side of the first line in the list or grid * - * @see {@code #getView()} of a specific adapter for more detailed info + * see getView() of a specific adapter for more detailed info */ - public WeakReference mLineOneRight; + public final WeakReference mLineOneRight; /** * This is the second line displayed in the list or grid * - * @see {@code #getView()} of a specific adapter for more detailed info + * see getView() of a specific adapter for more detailed info */ - public WeakReference mLineTwo; + public final WeakReference mLineTwo; /** * The container for the circular progress bar and play/pause button * - * @see {@code #getView()} of a specific adapter for more detailed info + * see getView() of a specific adapter for more detailed info */ - public WeakReference mPlayPauseProgressButton; + public final WeakReference mPlayPauseProgressButton; /** * The Padding container for the circular progress bar */ - public WeakReference mPlayPauseProgressContainer; + public final WeakReference mPlayPauseProgressContainer; /** * The song indicator for the currently playing track */ - public WeakReference mNowPlayingIndicator; + public final WeakReference mNowPlayingIndicator; /** * The divider for the list item */ - public WeakReference mDivider; + public final WeakReference mDivider; /** * The divider for the list item */ - public WeakReference mPopupMenuButton; + public final WeakReference mPopupMenuButton; /** * Constructor of ViewHolder - * - * @param context The {@link Context} to use. */ public MusicHolder(final View view) { - super(); + super(view); // Initialize mImage - mImage = new WeakReference<>((ImageView) view.findViewById(R.id.image)); + mImage = new WeakReference<>(view.findViewById(R.id.image)); // Initialize mLineOne - mLineOne = new WeakReference<>((TextView) view.findViewById(R.id.line_one)); + mLineOne = new WeakReference<>(view.findViewById(R.id.line_one)); // Initialize mLineOneRight - mLineOneRight = new WeakReference<>( - (TextView) view.findViewById(R.id.line_one_right)); + mLineOneRight = new WeakReference<>(view.findViewById(R.id.line_one_right)); // Initialize mLineTwo - mLineTwo = new WeakReference<>((TextView) view.findViewById(R.id.line_two)); + mLineTwo = new WeakReference<>(view.findViewById(R.id.line_two)); // Initialize Circular progress bar container mPlayPauseProgressButton = new WeakReference<>( - (PlayPauseButtonContainer) view.findViewById(R.id.playPauseProgressButton)); + view.findViewById(R.id.playPauseProgressButton)); // Get the padding container for the progress bar mPlayPauseProgressContainer = new WeakReference<>( @@ -132,39 +122,36 @@ public class MusicHolder { // Get the pop up menu button mPopupMenuButton = new WeakReference<>( - (PopupMenuButton) view.findViewById(R.id.popup_menu_button)); + view.findViewById(R.id.popup_menu_button)); } - /** - * @param view The {@link View} used to initialize content - */ public final static class DataHolder { /** * This is the ID of the item being loaded in the adapter */ - public long mItemId; + public long itemId; /** * This is the first line displayed in the list or grid * - * @see {@code #getView()} of a specific adapter for more detailed info + * see getView() of a specific adapter for more detailed info */ - public String mLineOne; + public String lineOne; /** * This is displayed on the right side of the first line in the list or grid * - * @see {@code #getView()} of a specific adapter for more detailed info + * see getView() of a specific adapter for more detailed info */ - public String mLineOneRight; + public String lineOneRight; /** * This is the second line displayed in the list or grid * - * @see {@code #getView()} of a specific adapter for more detailed info + * see getView() of a specific adapter for more detailed info */ - public String mLineTwo; + public String lineTwo; /** * Constructor of DataHolder @@ -172,6 +159,5 @@ public class MusicHolder { public DataHolder() { super(); } - } } diff --git a/src/org/lineageos/eleven/ui/activities/BaseActivity.java b/src/org/lineageos/eleven/ui/activities/BaseActivity.java index ba75556aa55609000bb7f6b76f4801d3b4857b7e..5f20e0449cedba7a6f49d77a8b17553902db249d 100644 --- a/src/org/lineageos/eleven/ui/activities/BaseActivity.java +++ b/src/org/lineageos/eleven/ui/activities/BaseActivity.java @@ -1,7 +1,7 @@ /* * Copyright (C) 2012 Andrew Neal * Copyright (C) 2014 The CyanogenMod Project - * Copyright (C) 2019 The LineageOS Project + * Copyright (C) 2019-2021 The LineageOS Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -15,7 +15,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package org.lineageos.eleven.ui.activities; import android.content.BroadcastReceiver; @@ -46,14 +45,13 @@ import androidx.fragment.app.FragmentActivity; import org.lineageos.eleven.MusicPlaybackService; import org.lineageos.eleven.MusicStateListener; import org.lineageos.eleven.R; -import org.lineageos.eleven.cache.ICacheListener; -import org.lineageos.eleven.cache.ImageFetcher; import org.lineageos.eleven.utils.ElevenUtils; import org.lineageos.eleven.utils.Lists; import org.lineageos.eleven.utils.MusicUtils; import org.lineageos.eleven.utils.MusicUtils.ServiceToken; import org.lineageos.eleven.utils.NavUtils; import org.lineageos.eleven.widgets.PlayPauseButtonContainer; +import org.lineageos.eleven.widgets.PlayPauseProgressButton; import java.lang.ref.WeakReference; import java.util.ArrayList; @@ -67,10 +65,10 @@ import java.util.ArrayList; * @author Andrew Neal (andrewdneal@gmail.com) */ public abstract class BaseActivity extends AppCompatActivity implements ServiceConnection, - MusicStateListener, ICacheListener { + MusicStateListener { /** - * Playstate and meta change listener + * Play-State and meta change listener */ private final ArrayList mMusicStateListener = Lists.newArrayList(); @@ -86,8 +84,10 @@ public abstract class BaseActivity extends AppCompatActivity implements ServiceC /** * Play pause progress button */ + private PlayPauseProgressButton mPlayPauseProgressButton; private PlayPauseButtonContainer mPlayPauseButtonContainer; + /** * Track name (BAB) */ @@ -111,12 +111,10 @@ public abstract class BaseActivity extends AppCompatActivity implements ServiceC private Drawable mActionBarBackground; /** - * {@inheritDoc} + * Called when all requirements (like permissions) are satisfied and we are ready + * to initialize the app. */ - @Override - protected void onCreate(final Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - + protected void init(final Bundle savedInstanceState) { // Control the media volume setVolumeControlStream(AudioManager.STREAM_MUSIC); @@ -125,14 +123,13 @@ public abstract class BaseActivity extends AppCompatActivity implements ServiceC // Calculate ActionBar height TypedValue value = new TypedValue(); - if (getTheme().resolveAttribute(android.R.attr.actionBarSize, value, true)) - { + if (getTheme().resolveAttribute(android.R.attr.actionBarSize, value, true)) { mActionBarHeight = TypedValue.complexToDimensionPixelSize(value.data, getResources().getDisplayMetrics()); } // Set the layout - setContentView(setContentView()); + setContentView(R.layout.activity_base); mToolBar = findViewById(R.id.toolbar); setSupportActionBar(mToolBar); @@ -142,16 +139,14 @@ public abstract class BaseActivity extends AppCompatActivity implements ServiceC // set the background on the root view getWindow().getDecorView().getRootView().setBackgroundColor( ContextCompat.getColor(this, R.color.background_color)); - // Initialze the bottom action bar + // Initialize the bottom action bar initBottomActionBar(); + } - // listen to changes to the cache status - ImageFetcher.getInstance(this).addCacheListener(this); + public boolean isInitialized() { + return mToken != null; } - /** - * {@inheritDoc} - */ @Override public void onServiceConnected(final ComponentName name, final IBinder service) { // Set the playback drawables @@ -162,16 +157,10 @@ public abstract class BaseActivity extends AppCompatActivity implements ServiceC handlePendingPlaybackRequests(); } - /** - * {@inheritDoc} - */ @Override public void onServiceDisconnected(final ComponentName name) { } - /** - * {@inheritDoc} - */ @Override public boolean onCreateOptionsMenu(final Menu menu) { // Settings @@ -180,38 +169,28 @@ public abstract class BaseActivity extends AppCompatActivity implements ServiceC return super.onCreateOptionsMenu(menu); } - /** - * {@inheritDoc} - */ @Override public boolean onOptionsItemSelected(final MenuItem item) { - switch (item.getItemId()) { - case R.id.menu_settings: - // Settings - NavUtils.openSettings(this); - return true; - - default: - break; + if (item.getItemId() == R.id.menu_settings) { + // Settings + NavUtils.openSettings(this); + return true; } return super.onOptionsItemSelected(item); } - /** - * {@inheritDoc} - */ @Override protected void onResume() { super.onResume(); - // Set the playback drawables - updatePlaybackControls(); - // Current info - onMetaChanged(); + + if (isInitialized()) { + // Set the playback drawables + updatePlaybackControls(); + // Current info + onMetaChanged(); + } } - /** - * {@inheritDoc} - */ @Override protected void onStart() { super.onStart(); @@ -233,9 +212,6 @@ public abstract class BaseActivity extends AppCompatActivity implements ServiceC registerReceiver(mPlaybackStatus, filter); } - /** - * {@inheritDoc} - */ @Override protected void onStop() { super.onStop(); @@ -252,18 +228,12 @@ public abstract class BaseActivity extends AppCompatActivity implements ServiceC } } - /** - * {@inheritDoc} - */ @Override protected void onDestroy() { super.onDestroy(); // Remove any music status listeners mMusicStateListener.clear(); - - // remove cache listeners - ImageFetcher.getInstance(this).removeCacheListener(this); } public void setupActionBar(int resId) { @@ -311,6 +281,8 @@ public abstract class BaseActivity extends AppCompatActivity implements ServiceC */ protected void initBottomActionBar() { // Play and pause button + mPlayPauseProgressButton = findViewById(R.id.playPauseProgressButtonAlt); + mPlayPauseProgressButton.enableAndShow(); mPlayPauseButtonContainer = findViewById(R.id.playPauseProgressButton); mPlayPauseButtonContainer.enableAndShow(); @@ -346,24 +318,18 @@ public abstract class BaseActivity extends AppCompatActivity implements ServiceC private void updatePlaybackControls() { // Set the play and pause image mPlayPauseButtonContainer.updateState(); + mPlayPauseProgressButton.updateState(); } /** * Opens the album profile of the currently playing album */ - private final View.OnClickListener mOpenCurrentAlbumProfile = new View.OnClickListener() { - - /** - * {@inheritDoc} - */ - @Override - public void onClick(final View v) { - if (MusicUtils.getCurrentAudioId() != -1) { - NavUtils.openAlbumProfile(BaseActivity.this, MusicUtils.getAlbumName(), - MusicUtils.getArtistName(), MusicUtils.getCurrentAlbumId()); - } else { - MusicUtils.shuffleAll(BaseActivity.this); - } + private final View.OnClickListener mOpenCurrentAlbumProfile = v -> { + if (MusicUtils.getCurrentAudioId() != -1) { + NavUtils.openAlbumProfile(BaseActivity.this, MusicUtils.getAlbumName(), + MusicUtils.getArtistName(), MusicUtils.getCurrentAlbumId()); + } else { + MusicUtils.shuffleAll(BaseActivity.this); } }; @@ -381,9 +347,6 @@ public abstract class BaseActivity extends AppCompatActivity implements ServiceC mReference = new WeakReference<>(activity); } - /** - * {@inheritDoc} - */ @Override public void onReceive(final Context context, final Intent intent) { final String action = intent.getAction(); @@ -392,26 +355,22 @@ public abstract class BaseActivity extends AppCompatActivity implements ServiceC } final BaseActivity baseActivity = mReference.get(); - if (baseActivity != null) { - switch (action) { - case MusicPlaybackService.META_CHANGED: - baseActivity.onMetaChanged(); - break; - case MusicPlaybackService.PLAYSTATE_CHANGED: - baseActivity.mPlayPauseButtonContainer.updateState(); - break; - case MusicPlaybackService.REFRESH: - baseActivity.restartLoader(); - break; - case MusicPlaybackService.PLAYLIST_CHANGED: - baseActivity.onPlaylistChanged(); - break; - case MusicPlaybackService.TRACK_ERROR: - final String errorMsg = context.getString(R.string.error_playing_track, - intent.getStringExtra(MusicPlaybackService.TrackErrorExtra.TRACK_NAME)); - Toast.makeText(baseActivity, errorMsg, Toast.LENGTH_SHORT).show(); - break; - } + if (baseActivity == null) { + return; + } + if (MusicPlaybackService.META_CHANGED.equals(action)) { + baseActivity.onMetaChanged(); + } else if (MusicPlaybackService.PLAYSTATE_CHANGED.equals(action)) { + baseActivity.mPlayPauseButtonContainer.updateState(); + baseActivity.mPlayPauseProgressButton.updateState(); + } else if (MusicPlaybackService.REFRESH.equals(action)) { + baseActivity.restartLoader(); + } else if (MusicPlaybackService.PLAYLIST_CHANGED.equals(action)) { + baseActivity.onPlaylistChanged(); + } else if (MusicPlaybackService.TRACK_ERROR.equals(action)) { + final String errorMsg = context.getString(R.string.error_playing_track, + intent.getStringExtra(MusicPlaybackService.TrackErrorExtra.TRACK_NAME)); + Toast.makeText(baseActivity, errorMsg, Toast.LENGTH_SHORT).show(); } } } @@ -421,7 +380,7 @@ public abstract class BaseActivity extends AppCompatActivity implements ServiceC // update action bar info updateBottomActionBarInfo(); - // Let the listener know to the meta chnaged + // Let the listener know to the meta changed for (final MusicStateListener listener : mMusicStateListener) { if (listener != null) { listener.onMetaChanged(); @@ -471,17 +430,6 @@ public abstract class BaseActivity extends AppCompatActivity implements ServiceC } } - @Override - public void onCacheUnpaused() { - // Set the album art - ElevenUtils.getImageFetcher(this).loadCurrentArtwork(mAlbumArt); - } - - /** - * @return The resource ID to be inflated. - */ - public abstract int setContentView(); - /** * handle pending playback requests */ diff --git a/src/org/lineageos/eleven/ui/activities/HomeActivity.java b/src/org/lineageos/eleven/ui/activities/HomeActivity.java index e6461e85275d90bf999ef65c062c5587cc660abb..f2309b36f27fdd7e748b4ca2b4eb3679a827e830 100644 --- a/src/org/lineageos/eleven/ui/activities/HomeActivity.java +++ b/src/org/lineageos/eleven/ui/activities/HomeActivity.java @@ -1,6 +1,6 @@ /* * Copyright (C) 2014 The CyanogenMod Project - * Copyright (C) 2019 The LineageOS Project + * Copyright (C) 2019-2021 The LineageOS Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,24 +16,30 @@ */ package org.lineageos.eleven.ui.activities; +import static org.lineageos.eleven.utils.PreferenceUtils.PERMISSION_REQUEST_STORAGE; + import android.Manifest; import android.animation.ArgbEvaluator; import android.animation.ObjectAnimator; +import android.app.ActionBar; import android.content.Intent; import android.content.pm.PackageManager; import android.graphics.Bitmap; import android.graphics.Color; import android.net.Uri; +import android.os.AsyncTask; import android.os.Bundle; import android.os.Handler; import android.provider.MediaStore; import android.text.TextUtils; import android.util.Log; import android.view.MenuItem; +import android.view.View; import android.view.Window; import androidx.annotation.NonNull; import androidx.core.content.ContextCompat; +import androidx.core.graphics.ColorUtils; import androidx.fragment.app.Fragment; import androidx.fragment.app.FragmentManager; import androidx.fragment.app.FragmentTransaction; @@ -51,9 +57,11 @@ import org.lineageos.eleven.ui.fragments.RecentFragment; import org.lineageos.eleven.ui.fragments.phone.MusicBrowserPhoneFragment; import org.lineageos.eleven.ui.fragments.profile.LastAddedFragment; import org.lineageos.eleven.ui.fragments.profile.TopTracksFragment; +import org.lineageos.eleven.utils.AnimatorEndListener; import org.lineageos.eleven.utils.ElevenUtils; import org.lineageos.eleven.utils.MusicUtils; import org.lineageos.eleven.utils.NavUtils; +import org.lineageos.eleven.utils.colors.BitmapWithColors; import java.util.ArrayList; @@ -63,7 +71,8 @@ public class HomeActivity extends SlidingPanelActivity implements private static final String ACTION_PREFIX = HomeActivity.class.getName(); public static final String ACTION_VIEW_ARTIST_DETAILS = ACTION_PREFIX + ".view.ArtistDetails"; public static final String ACTION_VIEW_ALBUM_DETAILS = ACTION_PREFIX + ".view.AlbumDetails"; - public static final String ACTION_VIEW_PLAYLIST_DETAILS = ACTION_PREFIX + ".view.PlaylistDetails"; + public static final String ACTION_VIEW_PLAYLIST_DETAILS = + ACTION_PREFIX + ".view.PlaylistDetails"; public static final String ACTION_VIEW_SMART_PLAYLIST = ACTION_PREFIX + ".view.SmartPlaylist"; public static final String EXTRA_BROWSE_PAGE_IDX = "BrowsePageIndex"; @@ -72,15 +81,16 @@ public class HomeActivity extends SlidingPanelActivity implements private static final int NEW_PHOTO = 1; public static final int EQUALIZER = 2; - private static final int PERMISSION_REQUEST_STORAGE = 1; private Bundle mSavedInstanceState; private String mKey; private boolean mLoadedBaseFragment = false; private boolean mHasPendingPlaybackRequest = false; - private Handler mHandler = new Handler(); + private final Handler mHandler = new Handler(); private boolean mBrowsePanelActive = true; + private View mRootView; + /** * Used by the up action to determine how to handle this */ @@ -91,13 +101,17 @@ public class HomeActivity extends SlidingPanelActivity implements super.onCreate(savedInstanceState); mSavedInstanceState = savedInstanceState; + mRootView = getWindow().getDecorView(); if (!needRequestStoragePermission()) { - init(); + init(savedInstanceState); } } - private void init() { + @Override + protected void init(Bundle savedInstanceState) { + super.init(savedInstanceState); + // if we've been launched by an intent, parse it Intent launchIntent = getIntent(); boolean intentHandled = false; @@ -106,7 +120,7 @@ public class HomeActivity extends SlidingPanelActivity implements } // if the intent didn't cause us to load a fragment, load the music browse one - if (mSavedInstanceState == null && !mLoadedBaseFragment) { + if (savedInstanceState == null && !mLoadedBaseFragment) { final MusicBrowserPhoneFragment fragment = new MusicBrowserPhoneFragment(); if (launchIntent != null) { fragment.setDefaultPageIdx(launchIntent.getIntExtra(EXTRA_BROWSE_PAGE_IDX, @@ -122,11 +136,10 @@ public class HomeActivity extends SlidingPanelActivity implements getSupportFragmentManager().addOnBackStackChangedListener(this); - // if we are resuming from a saved instance state - if (mSavedInstanceState != null) { + if (savedInstanceState != null) { // track which fragments are loaded and if this is the top level activity - mTopLevelActivity = mSavedInstanceState.getBoolean(STATE_KEY_BASE_FRAGMENT); + mTopLevelActivity = savedInstanceState.getBoolean(STATE_KEY_BASE_FRAGMENT); mLoadedBaseFragment = mTopLevelActivity; // update the action bar based on the top most fragment @@ -146,7 +159,7 @@ public class HomeActivity extends SlidingPanelActivity implements } @Override - protected void onSaveInstanceState(Bundle outState) { + protected void onSaveInstanceState(@NonNull Bundle outState) { super.onSaveInstanceState(outState); outState.putBoolean(STATE_KEY_BASE_FRAGMENT, mTopLevelActivity); } @@ -156,17 +169,14 @@ public class HomeActivity extends SlidingPanelActivity implements } public void postRemoveFragment(final Fragment frag) { - mHandler.post(new Runnable() { - @Override - public void run() { - // removing the fragment doesn't cause the backstack event to be triggered even if - // it is the top fragment, so if it is the top fragment, we will just manually - // call pop back stack - if (frag == getTopFragment()) { - getSupportFragmentManager().popBackStack(); - } else { - getSupportFragmentManager().beginTransaction().remove(frag).commit(); - } + mHandler.post(() -> { + // removing the fragment doesn't cause the backstack event to be triggered even if + // it is the top fragment, so if it is the top fragment, we will just manually + // call pop back stack + if (frag == getTopFragment()) { + getSupportFragmentManager().popBackStack(); + } else { + getSupportFragmentManager().beginTransaction().remove(frag).commit(); } }); } @@ -211,25 +221,23 @@ public class HomeActivity extends SlidingPanelActivity implements private void updateStatusBarColor() { if (mBrowsePanelActive || MusicUtils.getCurrentAlbumId() < 0) { updateStatusBarColor(Color.TRANSPARENT); + } else { + new AsyncTask() { + @Override + protected BitmapWithColors doInBackground(Void... params) { + ImageFetcher imageFetcher = ImageFetcher.getInstance(HomeActivity.this); + return imageFetcher.getArtwork( + MusicUtils.getAlbumName(), MusicUtils.getCurrentAlbumId(), true); + } + @Override + protected void onPostExecute(BitmapWithColors bmc) { + updateVisualizerColor(bmc != null + ? bmc.getContrastingColor() : Color.TRANSPARENT); + updateStatusBarColor(bmc != null + ? bmc.getVibrantDarkColor() : Color.TRANSPARENT); + } + }.execute(); } -// else { -// new AsyncTask() { -// @Override -// protected BitmapWithColors doInBackground(Void... params) { -// ImageFetcher imageFetcher = ImageFetcher.getInstance(HomeActivity.this); -// return imageFetcher.getArtwork( -// MusicUtils.getAlbumName(), MusicUtils.getCurrentAlbumId(), -// MusicUtils.getArtistName(), true); -// } -// @Override -// protected void onPostExecute(BitmapWithColors bmc) { -// updateVisualizerColor(bmc != null -// ? bmc.getContrastingColor() : Color.TRANSPARENT); -// updateStatusBarColor(bmc != null -// ? bmc.getVibrantDarkColor() : Color.TRANSPARENT); -// } -// }.execute(); -// } } private void updateVisualizerColor(int color) { @@ -237,7 +245,7 @@ public class HomeActivity extends SlidingPanelActivity implements color = ContextCompat.getColor(this, R.color.visualizer_fill_color); } - // check for null since updatestatusBarColor is a async task + // check for null since updateStatusBarColor is a async task AudioPlayerFragment fragment = getAudioPlayerFragment(); if (fragment != null) { fragment.setVisualizerColor(color); @@ -246,13 +254,23 @@ public class HomeActivity extends SlidingPanelActivity implements private void updateStatusBarColor(int color) { if (color == Color.TRANSPARENT) { - color = getResources().getColor(R.color.primary_dark); + color = ContextCompat.getColor(this, R.color.primary_dark); } + final boolean isDark = ColorUtils.calculateLuminance(color) > 0.5f; final Window window = getWindow(); - ObjectAnimator animator = ObjectAnimator.ofInt(window, + final ObjectAnimator animator = ObjectAnimator.ofInt(window, "statusBarColor", window.getStatusBarColor(), color); animator.setEvaluator(new ArgbEvaluator()); animator.setDuration(300); + animator.addListener((AnimatorEndListener) animation -> { + int flags = mRootView.getSystemUiVisibility(); + if (isDark) { + flags |= View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR; + } else { + flags &= ~View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR; + } + mRootView.setSystemUiVisibility(flags); + }); animator.start(); } @@ -265,16 +283,13 @@ public class HomeActivity extends SlidingPanelActivity implements if (action.equals(ACTION_VIEW_SMART_PLAYLIST)) { long playlistId = intent.getExtras().getLong(Config.SMART_PLAYLIST_TYPE); - switch (Config.SmartPlaylistType.getTypeById(playlistId)) { - case LastAdded: - targetFragment = new LastAddedFragment(); - break; - case RecentlyPlayed: - targetFragment = new RecentFragment(); - break; - case TopTracks: - targetFragment = new TopTracksFragment(); - break; + Config.SmartPlaylistType type = Config.SmartPlaylistType.getTypeById(playlistId); + if (Config.SmartPlaylistType.LastAdded.equals(type)) { + targetFragment = new LastAddedFragment(); + } else if (Config.SmartPlaylistType.RecentlyPlayed.equals(type)) { + targetFragment = new RecentFragment(); + } else if (Config.SmartPlaylistType.TopTracks.equals(type)) { + targetFragment = new TopTracksFragment(); } } else if (action.equals(ACTION_VIEW_PLAYLIST_DETAILS)) { targetFragment = new PlaylistDetailFragment(); @@ -301,7 +316,10 @@ public class HomeActivity extends SlidingPanelActivity implements // this happens when they launch search which is its own activity and then // browse through that back to home activity mLoadedBaseFragment = true; - getSupportActionBar().setDisplayHomeAsUpEnabled(true); + final ActionBar actionBar = getActionBar(); + if (actionBar != null) { + actionBar.setDisplayHomeAsUpEnabled(true); + } } // the current top fragment is about to be hidden by what we are replacing // it with -- so tell that fragment not to make its action bar menu items visible @@ -328,10 +346,8 @@ public class HomeActivity extends SlidingPanelActivity implements new Thread(() -> { Bitmap bitmap = ImageFetcher.decodeSampledBitmapFromUri(getContentResolver(), selectedImage); - ImageFetcher imageFetcher = ElevenUtils.getImageFetcher(HomeActivity.this); imageFetcher.addBitmapToCache(mKey, bitmap); - MusicUtils.refresh(); }).start(); } @@ -351,10 +367,9 @@ public class HomeActivity extends SlidingPanelActivity implements @Override public boolean onOptionsItemSelected(final MenuItem item) { - switch (item.getItemId()) { - case android.R.id.home: - navigateToTop(); - return true; + if (item.getItemId() == android.R.id.home) { + navigateToTop(); + return true; } return super.onOptionsItemSelected(item); @@ -387,7 +402,7 @@ public class HomeActivity extends SlidingPanelActivity implements } /** - * Immediately clears the backstack + * Immediately clears the back-stack */ protected void clearBackStack() { final FragmentManager fragmentManager = getSupportFragmentManager(); @@ -408,35 +423,33 @@ public class HomeActivity extends SlidingPanelActivity implements /** * Checks whether the passed intent contains a playback request, * and starts playback if that's the case - * @return true if the intent was consumed */ - private boolean handlePlaybackIntent(Intent intent) { - + private void handlePlaybackIntent(Intent intent) { if (intent == null) { - return false; + return; } else if ( !MusicUtils.isPlaybackServiceConnected() ) { mHasPendingPlaybackRequest = true; - return false; + return; } String mimeType = intent.getType(); boolean handled = false; if (MediaStore.Audio.Playlists.CONTENT_TYPE.equals(mimeType)) { - long id = parseIdFromIntent(intent, "playlistId", "playlist", -1); + long id = parseIdFromIntent(intent, "playlistId", "playlist"); if (id >= 0) { MusicUtils.playPlaylist(this, id, false); handled = true; } } else if (MediaStore.Audio.Albums.CONTENT_TYPE.equals(mimeType)) { - long id = parseIdFromIntent(intent, "albumId", "album", -1); + long id = parseIdFromIntent(intent, "albumId", "album"); if (id >= 0) { int position = intent.getIntExtra("position", 0); MusicUtils.playAlbum(this, id, position, false); handled = true; } } else if (MediaStore.Audio.Artists.CONTENT_TYPE.equals(mimeType)) { - long id = parseIdFromIntent(intent, "artistId", "artist", -1); + long id = parseIdFromIntent(intent, "artistId", "artist"); if (id >= 0) { int position = intent.getIntExtra("position", 0); MusicUtils.playArtist(this, id, position, false); @@ -448,13 +461,9 @@ public class HomeActivity extends SlidingPanelActivity implements if (handled) { setIntent(new Intent()); } - - return handled; - } - private long parseIdFromIntent(Intent intent, String longKey, - String stringKey, long defaultId) { + private long parseIdFromIntent(Intent intent, String longKey, String stringKey) { long id = intent.getLongExtra(longKey, -1); if (id < 0) { String idString = intent.getStringExtra(stringKey); @@ -462,7 +471,7 @@ public class HomeActivity extends SlidingPanelActivity implements try { id = Long.parseLong(idString); } catch (NumberFormatException e) { - Log.e(TAG, e.getMessage()); + Log.e(TAG, "Invalid id", e); } } } @@ -479,21 +488,23 @@ public class HomeActivity extends SlidingPanelActivity implements ISetupActionBar setupActionBar = (ISetupActionBar) topFragment; setupActionBar.setupActionBar(); - getSupportActionBar().setDisplayHomeAsUpEnabled( - !(topFragment instanceof MusicBrowserPhoneFragment)); + final androidx.appcompat.app.ActionBar actionBar = getSupportActionBar(); + if (actionBar != null) { + actionBar.setDisplayHomeAsUpEnabled( + !(topFragment instanceof MusicBrowserPhoneFragment)); + } } } @Override - public void onRequestPermissionsResult(int requestCode, @NonNull String permissions[], + public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { - switch (requestCode) { - case PERMISSION_REQUEST_STORAGE: { - if (checkPermissionGrantResults(grantResults)) { - init(); - } else { - finish(); - } + super.onRequestPermissionsResult(requestCode, permissions, grantResults); + if (requestCode == PERMISSION_REQUEST_STORAGE) { + if (checkPermissionGrantResults(grantResults)) { + init(mSavedInstanceState); + } else { + finish(); } } } @@ -535,5 +546,4 @@ public class HomeActivity extends SlidingPanelActivity implements } return true; } - } diff --git a/src/org/lineageos/eleven/ui/activities/SettingsActivity.java b/src/org/lineageos/eleven/ui/activities/SettingsActivity.java index 731db61f1adff07d32e86b27f4d503920cdc6302..83394202a7790da6b688802ea3408770f0e82705 100644 --- a/src/org/lineageos/eleven/ui/activities/SettingsActivity.java +++ b/src/org/lineageos/eleven/ui/activities/SettingsActivity.java @@ -1,7 +1,7 @@ /* * Copyright (C) 2012 Andrew Neal * Copyright (C) 2014 The CyanogenMod Project - * Copyright (C) 2018-2020 The LineageOS Project + * Copyright (C) 2018-2021 The LineageOS Project * Copyright (C) 2019 SHIFT GmbH * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -16,22 +16,28 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package org.lineageos.eleven.ui.activities; +import static android.content.pm.PackageManager.PERMISSION_GRANTED; + +import android.app.Activity; import android.app.AlertDialog; import android.content.ComponentName; import android.content.ServiceConnection; import android.content.SharedPreferences; +import android.Manifest.permission; import android.os.Bundle; import android.os.IBinder; import android.os.RemoteException; import android.view.MenuItem; +import androidx.annotation.NonNull; +import androidx.appcompat.app.ActionBar; import androidx.appcompat.app.AppCompatActivity; import androidx.appcompat.widget.Toolbar; import androidx.preference.Preference; import androidx.preference.PreferenceFragmentCompat; +import androidx.preference.SwitchPreference; import org.lineageos.eleven.IElevenService; import org.lineageos.eleven.R; @@ -49,25 +55,28 @@ public class SettingsActivity extends AppCompatActivity { final Toolbar toolbar = findViewById(R.id.toolbar); toolbar.setTitleTextColor(getResources().getColor(R.color.main_action_bar_text_color)); setSupportActionBar(toolbar); - getSupportActionBar().setDisplayHomeAsUpEnabled(true); + final ActionBar actionBar = getSupportActionBar(); + if (actionBar != null) { + actionBar.setDisplayHomeAsUpEnabled(true); + } } @Override public boolean onOptionsItemSelected(final MenuItem item) { - switch (item.getItemId()) { - case android.R.id.home: - onBackPressed(); - finish(); - return true; - default: - break; + if (item.getItemId() == android.R.id.home) { + onBackPressed(); + finish(); + return true; } + return super.onOptionsItemSelected(item); } public static class SettingsFragment extends PreferenceFragmentCompat implements ServiceConnection, SharedPreferences.OnSharedPreferenceChangeListener { + private SwitchPreference mShowVisualizer; + private MusicUtils.ServiceToken mToken; private IElevenService mService; @@ -77,17 +86,29 @@ public class SettingsActivity extends AppCompatActivity { super.onCreate(savedInstanceState); final Preference deleteCache = findPreference("delete_cache"); - deleteCache.setOnPreferenceClickListener(preference -> { - new AlertDialog.Builder(getContext()) - .setMessage(R.string.delete_warning) - .setPositiveButton(android.R.string.ok, (dialog, which) -> - ImageFetcher.getInstance(getContext()).clearCaches()) - .setNegativeButton(R.string.cancel, (dialog, which) -> dialog.dismiss()) - .show(); - return true; - }); - - PreferenceUtils.getInstance(getContext()).setOnSharedPreferenceChangeListener(this); + if (deleteCache != null) { + deleteCache.setOnPreferenceClickListener(preference -> { + new AlertDialog.Builder(getContext()) + .setMessage(R.string.delete_warning) + .setPositiveButton(android.R.string.ok, (dialog, which) -> + ImageFetcher.getInstance(getContext()).clearCaches()) + .setNegativeButton(R.string.cancel, (dialog, which) -> dialog.dismiss()) + .show(); + return true; + }); + } + + PreferenceUtils prefUtils = PreferenceUtils.getInstance(getContext()); + prefUtils.setOnSharedPreferenceChangeListener(this); + + mShowVisualizer = findPreference(PreferenceUtils.SHOW_VISUALIZER); + if (mShowVisualizer != null) { + final Activity activity = getActivity(); + // Otherwise we wouldn't notice if the permission has been denied via the Settings + // app since the last time + mShowVisualizer.setChecked(prefUtils.getShowVisualizer() && activity != null && + PreferenceUtils.canRecordAudio(activity)); + } } @Override @@ -130,21 +151,26 @@ public class SettingsActivity extends AppCompatActivity { @Override public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) { + final Activity activity = getActivity(); switch (key) { - case PreferenceUtils.SHOW_VISUALIZER: { + case PreferenceUtils.SHOW_VISUALIZER: final boolean showVisualizer = sharedPreferences.getBoolean(key, false); - if (showVisualizer && !PreferenceUtils.canRecordAudio(getActivity())) { - PreferenceUtils.requestRecordAudio(getActivity()); + if (showVisualizer && activity != null && + !PreferenceUtils.canRecordAudio(activity)) { + requestRecordAudio(); } break; - } - case PreferenceUtils.USE_BLUR: { - final boolean useBlur = sharedPreferences.getBoolean(key, false); - ImageFetcher.getInstance(getActivity()).setUseBlur(useBlur); - ImageFetcher.getInstance(getActivity()).clearCaches(); + + case PreferenceUtils.USE_BLUR: + if (activity != null) { + final boolean useBlur = sharedPreferences.getBoolean(key, false); + final ImageFetcher fetcher = ImageFetcher.getInstance(activity); + fetcher.setUseBlur(useBlur); + fetcher.clearCaches(); + } break; - } - case PreferenceUtils.SHAKE_TO_PLAY: { + + case PreferenceUtils.SHAKE_TO_PLAY: final boolean enableShakeToPlay = sharedPreferences.getBoolean(key, false); try { mService.setShakeToPlayEnabled(enableShakeToPlay); @@ -152,8 +178,33 @@ public class SettingsActivity extends AppCompatActivity { // do nothing } break; + } + } + + /* We can't call PreferenceUtils.requestRecordAudio since it's called from activity context + and we need requestPermissions to be called for the fragment so + onRequestPermissionsResult gets called */ + private void requestRecordAudio() { + requestPermissions(new String[]{permission.RECORD_AUDIO}, + PreferenceUtils.PERMISSION_REQUEST_RECORD_AUDIO); + } + + @Override + public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, + @NonNull int[] grantResults) { + if (requestCode == PreferenceUtils.PERMISSION_REQUEST_RECORD_AUDIO) { + boolean showRationale = shouldShowRequestPermissionRationale(permissions[0]); + if (grantResults.length == 0 || grantResults[0] != PERMISSION_GRANTED) { + mShowVisualizer.setChecked(false); + if (!showRationale) { + new AlertDialog.Builder(getContext()) + .setMessage(R.string.visualizer_perm_denied) + .setPositiveButton(android.R.string.ok, null) + .show(); + } } } + super.onRequestPermissionsResult(requestCode, permissions, grantResults); } } } diff --git a/src/org/lineageos/eleven/ui/activities/SlidingPanelActivity.java b/src/org/lineageos/eleven/ui/activities/SlidingPanelActivity.java index 1fa87ee8befebf2248f93e2272e12dcb02ff9d38..4be2f6a0666896263379bdc742a400986596f6d3 100644 --- a/src/org/lineageos/eleven/ui/activities/SlidingPanelActivity.java +++ b/src/org/lineageos/eleven/ui/activities/SlidingPanelActivity.java @@ -1,6 +1,7 @@ /* * Copyright (C) 2012 Andrew Neal - * Copyright (C) 2019 The LineageOS Project + * Copyright (C) 2019-2021 The LineageOS Project + * Copyright (C) 2021 SHIFT GmbH * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,7 +15,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package org.lineageos.eleven.ui.activities; import android.graphics.Color; @@ -23,6 +23,7 @@ import android.os.Bundle; import android.view.View; import android.widget.LinearLayout; +import androidx.annotation.NonNull; import androidx.fragment.app.Fragment; import androidx.viewpager.widget.ViewPager; @@ -46,8 +47,6 @@ import org.lineageos.eleven.widgets.AlbumScrimImage; */ public abstract class SlidingPanelActivity extends BaseActivity { - private LinearLayout slidingIndicator; - public enum Panel { Browse, MusicPlayer, @@ -61,7 +60,8 @@ public abstract class SlidingPanelActivity extends BaseActivity { private SlidingUpPanelLayout mSecondPanel; protected Panel mTargetNavigatePanel; - private final ShowPanelClickListener mShowMusicPlayer = new ShowPanelClickListener(Panel.MusicPlayer); + private final ShowPanelClickListener mShowMusicPlayer = + new ShowPanelClickListener(Panel.MusicPlayer); // this is the blurred image that goes behind the now playing and queue fragments private AlbumScrimImage mAlbumScrimImage; @@ -71,18 +71,11 @@ public abstract class SlidingPanelActivity extends BaseActivity { /** * Opens the now playing screen */ - private final View.OnClickListener mOpenNowPlaying = new View.OnClickListener() { - - /** - * {@inheritDoc} - */ - @Override - public void onClick(final View v) { - if (MusicUtils.getCurrentAudioId() != -1) { - openAudioPlayer(); - } else { - MusicUtils.shuffleAll(SlidingPanelActivity.this); - } + private final View.OnClickListener mOpenNowPlaying = v -> { + if (MusicUtils.getCurrentAudioId() != -1) { + openAudioPlayer(); + } else { + MusicUtils.shuffleAll(SlidingPanelActivity.this); } }; @@ -90,18 +83,16 @@ public abstract class SlidingPanelActivity extends BaseActivity { protected void initBottomActionBar() { super.initBottomActionBar(); // Bottom action bar - final LinearLayout bottomActionBar = (LinearLayout)findViewById(R.id.bottom_action_bar); + final LinearLayout bottomActionBar = findViewById(R.id.bottom_action_bar); // Display the now playing screen or shuffle if this isn't anything // playing bottomActionBar.setOnClickListener(mOpenNowPlaying); } - /** - * {@inheritDoc} - */ @Override - protected void onCreate(final Bundle savedInstanceState) { - super.onCreate(savedInstanceState); + protected void init(final Bundle savedInstanceState) { + super.init(savedInstanceState); + mUseBlur = PreferenceUtils.getInstance(this).getUseBlur(); mTargetNavigatePanel = Panel.None; @@ -109,8 +100,8 @@ public abstract class SlidingPanelActivity extends BaseActivity { setupFirstPanel(); setupSecondPanel(); - // get the blur scrim image - mAlbumScrimImage = findViewById(R.id.blurScrimImage); + // get the album scrim image + mAlbumScrimImage = findViewById(R.id.albumScrimImage); if (savedInstanceState != null) { int panelIndex = savedInstanceState.getInt(STATE_KEY_CURRENT_PANEL, @@ -127,7 +118,7 @@ public abstract class SlidingPanelActivity extends BaseActivity { } @Override - protected void onSaveInstanceState(Bundle outState) { + protected void onSaveInstanceState(@NonNull Bundle outState) { super.onSaveInstanceState(outState); outState.putInt(STATE_KEY_CURRENT_PANEL, getCurrentPanel().ordinal()); @@ -155,7 +146,6 @@ public abstract class SlidingPanelActivity extends BaseActivity { private void setupSecondPanel() { mSecondPanel = findViewById(R.id.sliding_layout2); - slidingIndicator = findViewById(R.id.indicator); mSecondPanel.setPanelSlideListener(new SimplePanelSlideListener() { @Override public void onPanelSlide(View panel, float slideOffset) { @@ -165,42 +155,36 @@ public abstract class SlidingPanelActivity extends BaseActivity { mFirstPanel.setSlidingEnabled(false); } - slidingIndicator.setVisibility(View.VISIBLE); onSlide(slideOffset); } @Override public void onPanelExpanded(View panel) { checkTargetNavigation(); - slidingIndicator.setVisibility(View.INVISIBLE); } @Override public void onPanelCollapsed(View panel) { // re-enable sliding when the second panel is collapsed - slidingIndicator.setVisibility(View.VISIBLE); mFirstPanel.setSlidingEnabled(true); checkTargetNavigation(); } }); // setup the header bar - setupQueueHeaderBar(R.id.secondHeaderBar, R.string.page_play_queue, mShowMusicPlayer); + setupQueueHeaderBar(mShowMusicPlayer); // set the drag view offset to allow the panel to go past the top of the viewport // since the previous view's is hiding the slide offset, we need to subtract that // from action bat height - int slideOffset = getResources().getDimensionPixelOffset(R.dimen.sliding_panel_indicator_height); + int slideOffset = getResources().getDimensionPixelOffset( + R.dimen.sliding_panel_indicator_height); slideOffset -= ElevenUtils.getActionBarHeight(this); mSecondPanel.setSlidePanelOffset(slideOffset); } @Override - protected void onPause() { - super.onPause(); - } - - @Override protected void onResume() { + protected void onResume() { super.onResume(); // recreate activity if blur preference has changed to apply changes @@ -210,14 +194,6 @@ public abstract class SlidingPanelActivity extends BaseActivity { } } - /** - * {@inheritDoc} - */ - @Override - public int setContentView() { - return R.layout.activity_base; - } - @Override public void onBackPressed() { Panel panel = getCurrentPanel(); @@ -283,6 +259,10 @@ public abstract class SlidingPanelActivity extends BaseActivity { } public Panel getCurrentPanel() { + if (!isInitialized()) { + return Panel.None; + } + if (mSecondPanel.isPanelExpanded()) { return Panel.Queue; } else if (mFirstPanel.isPanelExpanded()) { @@ -304,13 +284,6 @@ public abstract class SlidingPanelActivity extends BaseActivity { updateScrimImage(); } - @Override - public void onCacheUnpaused() { - super.onCacheUnpaused(); - - updateScrimImage(); - } - private void updateScrimImage() { ElevenUtils.getImageFetcher(this).updateScrimImage(mAlbumScrimImage, mColorExtractorCallback); @@ -340,11 +313,10 @@ public abstract class SlidingPanelActivity extends BaseActivity { mAlbumScrimImage.setGradientDrawable(gradientDrawable); }; - protected void setupQueueHeaderBar(final int containerId, final int textId, - final View.OnClickListener headerClickListener) { - final HeaderBar headerBar = findViewById(containerId); + protected void setupQueueHeaderBar(final View.OnClickListener headerClickListener) { + final HeaderBar headerBar = findViewById(R.id.secondHeaderBar); headerBar.setFragment(getQueueFragment()); - headerBar.setTitleText(textId); + headerBar.setTitleText(R.string.page_play_queue); headerBar.setBackgroundColor(Color.TRANSPARENT); headerBar.setHeaderClickListener(headerClickListener); @@ -353,7 +325,7 @@ public abstract class SlidingPanelActivity extends BaseActivity { private class ShowPanelClickListener implements View.OnClickListener { - private Panel mTargetPanel; + private final Panel mTargetPanel; public ShowPanelClickListener(Panel targetPanel) { mTargetPanel = targetPanel; diff --git a/src/org/lineageos/eleven/ui/activities/preview/AudioPreviewActivity.java b/src/org/lineageos/eleven/ui/activities/preview/AudioPreviewActivity.java index c021f154ca306360ad331c7f2c9145de61b6a0f0..44103ff37380b1082d907f5b170aed9ba78e7fde 100644 --- a/src/org/lineageos/eleven/ui/activities/preview/AudioPreviewActivity.java +++ b/src/org/lineageos/eleven/ui/activities/preview/AudioPreviewActivity.java @@ -1,6 +1,6 @@ /* * Copyright (C) 2015 The CyanogenMod Project - * Copyright (C) 2019-2020 The LineageOS Project + * Copyright (C) 2019-2021 The LineageOS Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,10 +14,8 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package org.lineageos.eleven.ui.activities.preview; -import android.app.Activity; import android.content.AsyncQueryHandler; import android.content.BroadcastReceiver; import android.content.Context; @@ -26,12 +24,15 @@ import android.content.IntentFilter; import android.content.pm.ActivityInfo; import android.database.Cursor; import android.graphics.Rect; +import android.media.AudioAttributes; +import android.media.AudioFocusRequest; import android.media.AudioManager; import android.media.AudioManager.OnAudioFocusChangeListener; import android.media.MediaPlayer; import android.net.Uri; import android.os.Bundle; import android.os.Handler; +import android.os.Looper; import android.os.Message; import android.provider.MediaStore.Audio.Media; import android.text.TextUtils; @@ -48,6 +49,7 @@ import android.widget.SeekBar.OnSeekBarChangeListener; import android.widget.TextView; import android.widget.Toast; +import androidx.annotation.NonNull; import androidx.appcompat.app.AppCompatActivity; import org.lineageos.eleven.R; @@ -76,7 +78,7 @@ public class AudioPreviewActivity extends AppCompatActivity implements private static final String AUTHORITY_MEDIA = "media"; private static final int CONTENT_QUERY_TOKEN = 1000; private static final int CONTENT_BAD_QUERY_TOKEN = CONTENT_QUERY_TOKEN + 1; - private static final String[] MEDIA_PROJECTION = new String[] { + private static final String[] MEDIA_PROJECTION = new String[]{ Media.TITLE, Media.ARTIST }; @@ -85,6 +87,8 @@ public class AudioPreviewActivity extends AppCompatActivity implements private boolean mIsSeeking = false; private boolean mWasPlaying = false; + private AudioFocusRequest mFocusRequest; + @Override public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { if (mPreviewPlayer != null && mIsSeeking) { @@ -122,20 +126,25 @@ public class AudioPreviewActivity extends AppCompatActivity implements * Handle some ui events * * - * @see {@link Handler} + * @see Handler */ - private class UiHandler extends Handler { + private static class UiHandler extends Handler { public static final int MSG_UPDATE_PROGRESS = 1000; + private final Runnable mUpdateProgressForPlayer; + + public UiHandler(@NonNull Looper looper, Runnable updateProgressForPlayer) { + super(looper); + mUpdateProgressForPlayer = updateProgressForPlayer; + } + @Override public void handleMessage(Message msg) { - switch (msg.what) { - case MSG_UPDATE_PROGRESS: - updateProgressForPlayer(); - break; - default: - super.handleMessage(msg); + if (msg.what == MSG_UPDATE_PROGRESS) { + mUpdateProgressForPlayer.run(); + } else { + super.handleMessage(msg); } } @@ -153,11 +162,12 @@ public class AudioPreviewActivity extends AppCompatActivity implements } } }; - private UiHandler mHandler = new UiHandler(); + private final UiHandler mHandler = new UiHandler(Looper.getMainLooper(), + this::updateProgressForPlayer); private static AsyncQueryHandler sAsyncQueryHandler; private AudioManager mAudioManager; private PreviewPlayer mPreviewPlayer; - private PreviewSong mPreviewSong = new PreviewSong(); + private final PreviewSong mPreviewSong = new PreviewSong(); private int mDuration = 0; private int mLastOrientationWhileBuffering; @@ -212,7 +222,7 @@ public class AudioPreviewActivity extends AppCompatActivity implements sAsyncQueryHandler = new AsyncQueryHandler(getContentResolver()) { @Override protected void onQueryComplete(int token, Object cookie, Cursor cursor) { - AudioPreviewActivity.this.onQueryComplete(token, cookie, cursor); + AudioPreviewActivity.this.onQueryComplete(token, cursor); } }; initializeInterface(); @@ -234,7 +244,7 @@ public class AudioPreviewActivity extends AppCompatActivity implements } @Override - public void onSaveInstanceState(Bundle outState) { + public void onSaveInstanceState(@NonNull Bundle outState) { if (mIsReceiverRegistered) { unregisterReceiver(mAudioNoisyReceiver); mIsReceiverRegistered = false; @@ -293,7 +303,7 @@ public class AudioPreviewActivity extends AppCompatActivity implements setRequestedOrientation(mLastOrientationWhileBuffering); } if (mPlayPauseBtn != null) { - mPlayPauseBtn.setImageResource(R.drawable.btn_playback_play); + mPlayPauseBtn.setImageResource(R.drawable.btn_preview_play); mPlayPauseBtn.setEnabled(true); mPlayPauseBtn.setOnClickListener(this); } @@ -301,14 +311,14 @@ public class AudioPreviewActivity extends AppCompatActivity implements case PLAYING: Logger.logd(TAG, "PLAYING"); if (mPlayPauseBtn != null) { - mPlayPauseBtn.setImageResource(R.drawable.btn_playback_pause); + mPlayPauseBtn.setImageResource(R.drawable.btn_preview_pause); mPlayPauseBtn.setEnabled(true); } break; case PAUSED: Logger.logd(TAG, "PAUSED"); if (mPlayPauseBtn != null) { - mPlayPauseBtn.setImageResource(R.drawable.btn_playback_play); + mPlayPauseBtn.setImageResource(R.drawable.btn_preview_play); mPlayPauseBtn.setEnabled(true); } break; @@ -316,7 +326,7 @@ public class AudioPreviewActivity extends AppCompatActivity implements setNames(); } - private void onQueryComplete(int token, Object cookie, Cursor cursor) { + private void onQueryComplete(int token, Cursor cursor) { String title = null; String artist = null; if (cursor == null || cursor.getCount() < 1) { @@ -328,7 +338,7 @@ public class AudioPreviewActivity extends AppCompatActivity implements Logger.loge(TAG, "Failed to read cursor!"); return; } - int index = -1; + int index; switch (token) { case CONTENT_QUERY_TOKEN: index = cursor.getColumnIndex(Media.TITLE); @@ -387,12 +397,12 @@ public class AudioPreviewActivity extends AppCompatActivity implements // Make it so if the user touches the background overlay we exit View v = findViewById(R.id.grp_transparent_wrapper); v.setOnTouchListener(this); - mTitleTextView = (TextView) findViewById(R.id.tv_title); - mArtistTextView = (TextView) findViewById(R.id.tv_artist); - mSeekBar = (SeekBar) findViewById(R.id.sb_progress); + mTitleTextView = findViewById(R.id.tv_title); + mArtistTextView = findViewById(R.id.tv_artist); + mSeekBar = findViewById(R.id.sb_progress); mSeekBar.setOnSeekBarChangeListener(this); - mProgressBar = (ProgressBar) findViewById(R.id.pb_loader); - mPlayPauseBtn = (ImageButton) findViewById(R.id.ib_playpause); + mProgressBar = findViewById(R.id.pb_loader); + mPlayPauseBtn = findViewById(R.id.ib_playpause); } private void processUri() { @@ -445,7 +455,7 @@ public class AudioPreviewActivity extends AppCompatActivity implements private void handleFileScheme() { String path = mPreviewSong.URI.getPath(); sAsyncQueryHandler.startQuery(CONTENT_QUERY_TOKEN, null, Media.EXTERNAL_CONTENT_URI, - MEDIA_PROJECTION, "_data=?", new String[] { path }, null); + MEDIA_PROJECTION, "_data=?", new String[]{path}, null); } private void handleHttpScheme() { @@ -498,7 +508,7 @@ public class AudioPreviewActivity extends AppCompatActivity implements break; case MediaPlayer.MEDIA_ERROR_UNKNOWN: default: - Toast.makeText(this, "An unkown error has occurred: " + what, Toast.LENGTH_LONG) + Toast.makeText(this, "An unknown error has occurred: " + what, Toast.LENGTH_LONG) .show(); break; } @@ -534,20 +544,16 @@ public class AudioPreviewActivity extends AppCompatActivity implements @Override public void onClick(View v) { - switch (v.getId()) { - case R.id.ib_playpause: - if (mCurrentState == State.PREPARED || mCurrentState == State.PAUSED) { - startPlayback(); - } else { - pausePlayback(); - } - break; - case R.id.grp_transparent_wrapper: - stopPlaybackAndTeardown(); - finish(); - break; - default: - break; + final int id = v.getId(); + if (id == R.id.ib_playpause) { + if (mCurrentState == State.PREPARED || mCurrentState == State.PAUSED) { + startPlayback(); + } else { + pausePlayback(); + } + } else if (id == R.id.grp_transparent_wrapper) { + stopPlaybackAndTeardown(); + finish(); } } @@ -555,14 +561,21 @@ public class AudioPreviewActivity extends AppCompatActivity implements if (mAudioManager == null) { return false; } - int r = mAudioManager.requestAudioFocus(this, AudioManager.STREAM_MUSIC, - AudioManager.AUDIOFOCUS_GAIN_TRANSIENT); + AudioAttributes attrs = new AudioAttributes.Builder() + .setLegacyStreamType(AudioManager.STREAM_MUSIC) + .build(); + mFocusRequest = new AudioFocusRequest.Builder(AudioManager.AUDIOFOCUS_GAIN_TRANSIENT) + .setOnAudioFocusChangeListener(this) + .setAudioAttributes(attrs) + .build(); + int r = mAudioManager.requestAudioFocus(mFocusRequest); return r == AudioManager.AUDIOFOCUS_REQUEST_GRANTED; } private void abandonAudioFocus() { - if (mAudioManager != null) { - mAudioManager.abandonAudioFocus(this); + if (mAudioManager != null && mFocusRequest != null) { + mAudioManager.abandonAudioFocusRequest(mFocusRequest); + mFocusRequest = null; } } @@ -613,8 +626,9 @@ public class AudioPreviewActivity extends AppCompatActivity implements @Override public void onAudioFocusChange(int focusChange) { if (mPreviewPlayer == null) { - if (mAudioManager != null) { - mAudioManager.abandonAudioFocus(this); + if (mAudioManager != null && mFocusRequest != null) { + mAudioManager.abandonAudioFocusRequest(mFocusRequest); + mFocusRequest = null; } } Logger.logd(TAG, "Focus change: " + focusChange); @@ -657,18 +671,16 @@ public class AudioPreviewActivity extends AppCompatActivity implements case KeyEvent.KEYCODE_MEDIA_PREVIOUS: case KeyEvent.KEYCODE_MEDIA_REWIND: case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD: - return result; + return true; case KeyEvent.KEYCODE_MEDIA_PLAY: startPlayback(); - return result; + return true; case KeyEvent.KEYCODE_MEDIA_PAUSE: pausePlayback(); - return result; + return true; case KeyEvent.KEYCODE_VOLUME_UP: case KeyEvent.KEYCODE_VOLUME_DOWN: case KeyEvent.KEYCODE_VOLUME_MUTE: - result = super.onKeyDown(keyCode, keyEvent); - return result; default: result = super.onKeyDown(keyCode, keyEvent); break; @@ -690,23 +702,23 @@ public class AudioPreviewActivity extends AppCompatActivity implements private WeakReference mActivityReference; // weakref from static class private boolean mIsPrepared = false; - /* package */ boolean isPrepared() { + boolean isPrepared() { return mIsPrepared; } - /* package */ PreviewPlayer() { + PreviewPlayer() { setOnPreparedListener(this); } - /* package */ void clearCallbackActivity() { + void clearCallbackActivity() { mActivityReference.clear(); mActivityReference = null; setOnErrorListener(null); setOnCompletionListener(null); } - /* package */ void setCallbackActivity(AudioPreviewActivity activity) - throws IllegalArgumentException{ + void setCallbackActivity(AudioPreviewActivity activity) + throws IllegalArgumentException { if (activity == null) { throw new IllegalArgumentException("'activity' cannot be null!"); } @@ -715,7 +727,7 @@ public class AudioPreviewActivity extends AppCompatActivity implements setOnCompletionListener(activity); } - /* package */ void setDataSourceAndPrepare(Uri uri) + void setDataSourceAndPrepare(Uri uri) throws IllegalArgumentException, IOException { if (uri == null || uri.toString().length() < 1) { throw new IllegalArgumentException("'uri' cannot be null or empty!"); @@ -737,6 +749,5 @@ public class AudioPreviewActivity extends AppCompatActivity implements } } } - } } diff --git a/src/org/lineageos/eleven/ui/activities/preview/PreviewSong.java b/src/org/lineageos/eleven/ui/activities/preview/PreviewSong.java index ba2b7af56fb7ed2f0390df8eb61962c4dfa7845f..fad2f7847454d1a581c401665623ffeabb78b850 100644 --- a/src/org/lineageos/eleven/ui/activities/preview/PreviewSong.java +++ b/src/org/lineageos/eleven/ui/activities/preview/PreviewSong.java @@ -1,19 +1,19 @@ /* -* Copyright (C) 2015 The CyanogenMod Project -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ - + * Copyright (C) 2015 The CyanogenMod Project + * Copyright (C) 2020-2021 The LineageOS Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package org.lineageos.eleven.ui.activities.preview; import android.net.Uri; @@ -21,13 +21,11 @@ import android.net.Uri; /** * PreviewSong *
- *     A POJO representation of a previewable external song
+ *     A POJO representation of a preview-able external song
  * 
*/ -/* package */ class PreviewSong { - +class PreviewSong { public Uri URI = null; public String TITLE = null; public String ARTIST = null; - } diff --git a/src/org/lineageos/eleven/ui/activities/preview/util/Logger.java b/src/org/lineageos/eleven/ui/activities/preview/util/Logger.java index a2056de0321e208434cba3c55430bb3ee04d4903..b7a93384b8cba121444b67760151d193e83d53c3 100644 --- a/src/org/lineageos/eleven/ui/activities/preview/util/Logger.java +++ b/src/org/lineageos/eleven/ui/activities/preview/util/Logger.java @@ -1,19 +1,19 @@ /* - * Copyright (c) 2015. The CyanogenMod Project + * Copyright (C) 2015. The CyanogenMod Project + * Copyright (C) 2020-2021 The LineageOS Project * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ - package org.lineageos.eleven.ui.activities.preview.util; import android.text.TextUtils; @@ -37,8 +37,6 @@ public class Logger { * * @param tag {@link String} * @param msg {@link String } - * - * @throws IllegalArgumentException {@link IllegalArgumentException} */ public static void logd(String tag, String msg) throws IllegalArgumentException { if (TextUtils.isEmpty(tag)) { @@ -57,8 +55,6 @@ public class Logger { * * @param tag {@link String} * @param msg {@link String } - * - * @throws IllegalArgumentException {@link IllegalArgumentException} */ public static void loge(String tag, String msg) throws IllegalArgumentException { if (TextUtils.isEmpty(tag)) { @@ -69,5 +65,4 @@ public class Logger { } Log.e(TAG, tag + " [ " + msg + " ]"); } - } diff --git a/src/org/lineageos/eleven/ui/fragments/AlbumDetailFragment.java b/src/org/lineageos/eleven/ui/fragments/AlbumDetailFragment.java index f81aed89f44500c54352ee3abaec8ea0d23c136c..9d6612f7816afbc70b8b825af9e28549006913d7 100644 --- a/src/org/lineageos/eleven/ui/fragments/AlbumDetailFragment.java +++ b/src/org/lineageos/eleven/ui/fragments/AlbumDetailFragment.java @@ -1,27 +1,35 @@ /* -* Copyright (C) 2014 The CyanogenMod Project -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ + * Copyright (C) 2014 The CyanogenMod Project + * Copyright (C) 2021 The LineageOS Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package org.lineageos.eleven.ui.fragments; import android.os.Bundle; +import android.os.Handler; import android.view.View; import android.widget.ImageView; -import android.widget.ListView; import android.widget.TextView; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.fragment.app.FragmentActivity; import androidx.loader.app.LoaderManager; +import androidx.loader.content.Loader; +import androidx.recyclerview.widget.DefaultItemAnimator; +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; import org.lineageos.eleven.Config; import org.lineageos.eleven.R; @@ -29,6 +37,7 @@ import org.lineageos.eleven.adapters.AlbumDetailSongAdapter; import org.lineageos.eleven.adapters.DetailSongAdapter; import org.lineageos.eleven.adapters.PagerAdapter; import org.lineageos.eleven.cache.ImageFetcher; +import org.lineageos.eleven.loaders.AlbumSongLoader; import org.lineageos.eleven.model.Album; import org.lineageos.eleven.model.Song; import org.lineageos.eleven.utils.AlbumPopupMenuHelper; @@ -36,15 +45,14 @@ import org.lineageos.eleven.utils.GenreFetcher; import org.lineageos.eleven.utils.MusicUtils; import org.lineageos.eleven.utils.PopupMenuHelper; import org.lineageos.eleven.utils.SongPopupMenuHelper; -import org.lineageos.eleven.widgets.IPopupMenuCallback; import org.lineageos.eleven.widgets.LoadingEmptyContainer; import java.util.List; -public class AlbumDetailFragment extends DetailFragment implements IChildFragment { +public class AlbumDetailFragment extends DetailFragment implements IChildFragment, + LoaderManager.LoaderCallbacks> { private static final int LOADER_ID = 1; - private ListView mSongs; private DetailSongAdapter mSongAdapter; private TextView mAlbumDuration; private TextView mGenre; @@ -62,22 +70,22 @@ public class AlbumDetailFragment extends DetailFragment implements IChildFragmen @Override protected String getTitle() { - return getArguments().getString(Config.ARTIST_NAME); + final Bundle args = getArguments(); + return args == null ? "" : args.getString(Config.ARTIST_NAME); } @Override protected void onViewCreated() { super.onViewCreated(); - Bundle arguments = getArguments(); - String artistName = arguments.getString(Config.ARTIST_NAME); + Bundle args = getArguments(); + String artistName = args == null ? "" : args.getString(Config.ARTIST_NAME); setupPopupMenuHelper(); - setupHeader(artistName, arguments); + setupHeader(artistName, args); setupSongList(); - LoaderManager lm = getLoaderManager(); - lm.initLoader(LOADER_ID, arguments, mSongAdapter); + LoaderManager.getInstance(this).initLoader(LOADER_ID, args, this); } @Override // DetailFragment @@ -90,7 +98,9 @@ public class AlbumDetailFragment extends DetailFragment implements IChildFragmen } @Override // DetailFragment - protected int getShuffleTitleId() { return R.string.menu_shuffle_album; } + protected int getShuffleTitleId() { + return R.string.menu_shuffle_album; + } @Override // DetailFragment protected void playShuffled() { @@ -98,37 +108,41 @@ public class AlbumDetailFragment extends DetailFragment implements IChildFragmen } private void setupHeader(String artist, Bundle arguments) { + if (arguments == null) { + return; + } mAlbumId = arguments.getLong(Config.ID); mArtistName = artist; mAlbumName = arguments.getString(Config.NAME); String year = arguments.getString(Config.ALBUM_YEAR); int songCount = arguments.getInt(Config.SONG_COUNT); - mAlbumArt = (ImageView)mRootView.findViewById(R.id.album_art); + mAlbumArt = mRootView.findViewById(R.id.album_art); mAlbumArt.setContentDescription(mAlbumName); - ImageFetcher.getInstance(getActivity()).loadAlbumImage(artist, mAlbumName, mAlbumId, mAlbumArt); + ImageFetcher.getInstance(getActivity()).loadAlbumImage(artist, + mAlbumName, mAlbumId, mAlbumArt); - TextView title = (TextView)mRootView.findViewById(R.id.title); + TextView title = mRootView.findViewById(R.id.title); title.setText(mAlbumName); setupCountAndYear(mRootView, year, songCount); // will be updated once we have song data - mAlbumDuration = (TextView)mRootView.findViewById(R.id.duration); - mGenre = (TextView)mRootView.findViewById(R.id.genre); + mAlbumDuration = mRootView.findViewById(R.id.duration); + mGenre = mRootView.findViewById(R.id.genre); } private void setupCountAndYear(View root, String year, int songCount) { - TextView songCountAndYear = (TextView)root.findViewById(R.id.song_count_and_year); - if(songCount > 0) { + TextView songCountAndYear = root.findViewById(R.id.song_count_and_year); + if (songCount > 0) { String countText = getResources(). getQuantityString(R.plurals.Nsongs, songCount, songCount); - if(year == null) { + if (year == null) { songCountAndYear.setText(countText); } else { songCountAndYear.setText(getString(R.string.combine_two_strings, countText, year)); } - } else if(year != null) { + } else if (year != null) { songCountAndYear.setText(year); } } @@ -153,47 +167,38 @@ public class AlbumDetailFragment extends DetailFragment implements IChildFragmen } private void setupSongList() { - mSongs = (ListView)mRootView.findViewById(R.id.songs); - mSongAdapter = new AlbumDetailSongAdapter(getActivity(), this) { - @Override - protected void onLoading() { - mLoadingEmptyContainer.showLoading(); - } - - @Override - protected void onNoResults() { - getContainingActivity().postRemoveFragment(AlbumDetailFragment.this); - } - }; - mSongAdapter.setPopupMenuClickedListener(new IPopupMenuCallback.IListener() { - @Override - public void onPopupMenuClicked(View v, int position) { - mSongMenuHelper.showPopupMenu(v, position); - } - }); - mSongs.setAdapter(mSongAdapter); - mSongs.setOnItemClickListener(mSongAdapter); - mLoadingEmptyContainer = - (LoadingEmptyContainer)mRootView.findViewById(R.id.loading_empty_container); - mSongs.setEmptyView(mLoadingEmptyContainer); + RecyclerView songsList = mRootView.findViewById(R.id.songs); + mSongAdapter = new AlbumDetailSongAdapter(getActivity()); + mSongAdapter.setPopupMenuClickedListener((v, position) -> + mSongMenuHelper.showPopupMenu(v, position)); + songsList.setLayoutManager(new LinearLayoutManager(getActivity())); + songsList.setItemAnimator(new DefaultItemAnimator()); + songsList.setAdapter(mSongAdapter); + mLoadingEmptyContainer = mRootView.findViewById(R.id.loading_empty_container); + mLoadingEmptyContainer.setVisibility(View.VISIBLE); } - /** called back by song loader */ + /** + * called back by song loader + */ public void update(List songs) { - /** compute total run time for album */ + final FragmentActivity activity = getActivity(); + // compute total run time for album int duration = 0; - for(Song s : songs) { duration += s.mDuration; } - mAlbumDuration.setText(MusicUtils.makeLongTimeString(getActivity(), duration)); + for (Song s : songs) { + duration += s.mDuration; + } + mAlbumDuration.setText(MusicUtils.makeLongTimeString(activity, duration)); - /** use the first song on the album to get a genre */ - if(!songs.isEmpty()) { - GenreFetcher.fetch(getActivity(), (int) songs.get(0).mSongId, mGenre); + // use the first song on the album to get a genre + if (!songs.isEmpty() && activity != null) { + GenreFetcher.fetch(activity , (int) songs.get(0).mSongId, mGenre); } } @Override public void restartLoader() { - getLoaderManager().restartLoader(LOADER_ID, getArguments(), mSongAdapter); + LoaderManager.getInstance(this).restartLoader(LOADER_ID, getArguments(), this); ImageFetcher.getInstance(getActivity()).loadAlbumImage(mArtistName, mAlbumName, mAlbumId, mAlbumArt); } @@ -209,4 +214,34 @@ public class AlbumDetailFragment extends DetailFragment implements IChildFragmen public PagerAdapter.MusicFragments getMusicFragmentParent() { return PagerAdapter.MusicFragments.ALBUM; } + + @NonNull + @Override + public Loader> onCreateLoader(int id, @Nullable Bundle args) { + mLoadingEmptyContainer.showLoading(); + long sourceId = args == null ? -1 : args.getLong(Config.ID); + mSongAdapter.setSourceId(sourceId); + return new AlbumSongLoader(getContext(), sourceId); + } + + @Override + public void onLoadFinished(@NonNull Loader> loader, List data) { + Handler handler = new Handler(requireActivity().getMainLooper()); + + if (data.isEmpty()) { + getContainingActivity().postRemoveFragment(AlbumDetailFragment.this); + return; + } + + mLoadingEmptyContainer.setVisibility(View.GONE); + // Do on UI thread: https://issuetracker.google.com/issues/37030377 + handler.post(() -> mSongAdapter.setData(data)); + update(data); + } + + @Override + public void onLoaderReset(@NonNull Loader> loader) { + // Clear the data in the adapter + mSongAdapter.unload(); + } } diff --git a/src/org/lineageos/eleven/ui/fragments/AlbumFragment.java b/src/org/lineageos/eleven/ui/fragments/AlbumFragment.java index f25f70a837a904cfa1ff6087ef7d4e8397e73aaf..fd03140f16fd92ea562e2898583d3b4d013e5273 100644 --- a/src/org/lineageos/eleven/ui/fragments/AlbumFragment.java +++ b/src/org/lineageos/eleven/ui/fragments/AlbumFragment.java @@ -1,31 +1,38 @@ /* * Copyright (C) 2012 Andrew Neal * Copyright (C) 2014 The CyanogenMod Project - * Licensed under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law - * or agreed to in writing, software distributed under the License is - * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the specific language - * governing permissions and limitations under the License. + * Copyright (C) 2021 The LineageOS Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ - package org.lineageos.eleven.ui.fragments; +import android.annotation.SuppressLint; +import android.app.Activity; import android.os.Bundle; +import android.os.Handler; import android.os.SystemClock; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; -import android.widget.AbsListView; -import android.widget.AbsListView.OnScrollListener; -import android.widget.AdapterView; -import android.widget.AdapterView.OnItemClickListener; -import android.widget.GridView; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import androidx.loader.app.LoaderManager; import androidx.loader.content.Loader; +import androidx.recyclerview.widget.DefaultItemAnimator; +import androidx.recyclerview.widget.GridLayoutManager; +import androidx.recyclerview.widget.RecyclerView; import org.lineageos.eleven.MusicStateListener; import org.lineageos.eleven.R; @@ -33,17 +40,14 @@ import org.lineageos.eleven.adapters.AlbumAdapter; import org.lineageos.eleven.adapters.PagerAdapter; import org.lineageos.eleven.loaders.AlbumLoader; import org.lineageos.eleven.model.Album; -import org.lineageos.eleven.recycler.RecycleHolder; import org.lineageos.eleven.sectionadapter.SectionCreator; import org.lineageos.eleven.sectionadapter.SectionListContainer; import org.lineageos.eleven.ui.activities.BaseActivity; import org.lineageos.eleven.ui.fragments.phone.MusicBrowserFragment; import org.lineageos.eleven.utils.AlbumPopupMenuHelper; import org.lineageos.eleven.utils.ElevenUtils; -import org.lineageos.eleven.utils.MusicUtils; import org.lineageos.eleven.utils.NavUtils; import org.lineageos.eleven.utils.PopupMenuHelper; -import org.lineageos.eleven.widgets.IPopupMenuCallback; import org.lineageos.eleven.widgets.LoadingEmptyContainer; /** @@ -52,8 +56,7 @@ import org.lineageos.eleven.widgets.LoadingEmptyContainer; * @author Andrew Neal (andrewdneal@gmail.com) */ public class AlbumFragment extends MusicBrowserFragment implements - LoaderManager.LoaderCallbacks>, OnScrollListener, - OnItemClickListener, MusicStateListener { + LoaderManager.LoaderCallbacks>, MusicStateListener { /** * Grid view column count. ONE - list, TWO - normal grid, FOUR - landscape @@ -70,11 +73,6 @@ public class AlbumFragment extends MusicBrowserFragment implements */ private AlbumAdapter mAdapter; - /** - * The grid view - */ - private GridView mGridView; - /** * Pop up menu helper */ @@ -90,14 +88,11 @@ public class AlbumFragment extends MusicBrowserFragment implements return PagerAdapter.MusicFragments.ALBUM.ordinal(); } - /** - * {@inheritDoc} - */ @Override public void onCreate(final Bundle savedInstanceState) { super.onCreate(savedInstanceState); - mPopupMenuHelper = new AlbumPopupMenuHelper(getActivity(), getFragmentManager()) { + mPopupMenuHelper = new AlbumPopupMenuHelper(getActivity(), getChildFragmentManager()) { public Album getAlbum(int position) { return mAdapter.getItem(position); } @@ -105,150 +100,85 @@ public class AlbumFragment extends MusicBrowserFragment implements int layout = R.layout.grid_items_normal; - mAdapter = new AlbumAdapter(getActivity(), layout); - mAdapter.setPopupMenuClickedListener(new IPopupMenuCallback.IListener() { - @Override - public void onPopupMenuClicked(View v, int position) { - mPopupMenuHelper.showPopupMenu(v, position); - } - }); + mAdapter = new AlbumAdapter(requireActivity(), layout, this::onItemClick); + mAdapter.setPopupMenuClickedListener((v, position) -> + mPopupMenuHelper.showPopupMenu(v, position)); } - /** - * {@inheritDoc} - */ + @SuppressLint("InflateParams") @Override public View onCreateView(final LayoutInflater inflater, final ViewGroup container, - final Bundle savedInstanceState) { - mRootView = (ViewGroup)inflater.inflate(R.layout.grid_base, null); + final Bundle savedInstanceState) { + mRootView = (ViewGroup) inflater.inflate(R.layout.grid_base, container, false); initGridView(); // Register the music status listener - ((BaseActivity)getActivity()).setMusicStateListenerListener(this); + final Activity activity = getActivity(); + if (activity instanceof BaseActivity) { + ((BaseActivity) activity).setMusicStateListenerListener(this); + } return mRootView; } - /** - * {@inheritDoc} - */ @Override - public void onActivityCreated(final Bundle savedInstanceState) { - super.onActivityCreated(savedInstanceState); + public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); // Enable the options menu setHasOptionsMenu(true); // Start the loader - initLoader(null, this); + initLoader(this); } @Override public void onDestroyView() { super.onDestroyView(); - ((BaseActivity)getActivity()).removeMusicStateListenerListener(this); + final Activity activity = getActivity(); + if (activity instanceof BaseActivity) { + ((BaseActivity) activity).removeMusicStateListenerListener(this); + } } - /** - * {@inheritDoc} - */ @Override public void onPause() { super.onPause(); mAdapter.flush(); } - /** - * {@inheritDoc} - */ - @Override - public void onScrollStateChanged(final AbsListView view, final int scrollState) { - // Pause disk cache access to ensure smoother scrolling - if (scrollState == AbsListView.OnScrollListener.SCROLL_STATE_FLING) { - mAdapter.setPauseDiskCache(true); - } else { - mAdapter.setPauseDiskCache(false); - mAdapter.notifyDataSetChanged(); - } - } - - /** - * {@inheritDoc} - */ - @Override - public void onItemClick(final AdapterView parent, final View view, final int position, - final long id) { - Album album = mAdapter.getItem(position); - NavUtils.openAlbumProfile(getActivity(), album.mAlbumName, album.mArtistName, album.mAlbumId); - } - - /** - * {@inheritDoc} - */ @Override + @NonNull public Loader> onCreateLoader(final int id, final Bundle args) { mLoadingEmptyContainer.showLoading(); - // if we ever decide to add section headers for grid items, we can pass a compartor + // if we ever decide to add section headers for grid items, we can pass a comparator // instead of null return new SectionCreator<>(getActivity(), new AlbumLoader(getActivity()), null); } - /** - * {@inheritDoc} - */ @Override - public void onLoadFinished(final Loader> loader, + public void onLoadFinished(@NonNull final Loader> loader, final SectionListContainer data) { + Handler handler = new Handler(requireActivity().getMainLooper()); + if (data.mListResults.isEmpty()) { - mAdapter.unload(); + // Do on UI thread: https://issuetracker.google.com/issues/37030377 + handler.post(() -> mAdapter.unload()); mLoadingEmptyContainer.showNoResults(); return; } - mAdapter.setData(data.mListResults); + mLoadingEmptyContainer.setVisibility(View.GONE); + // Do on UI thread: https://issuetracker.google.com/issues/37030377 + handler.post(() -> mAdapter.setData(data.mListResults)); } - /** - * {@inheritDoc} - */ @Override - public void onLoaderReset(final Loader> loader) { + public void onLoaderReset(@NonNull final Loader> loader) { // Clear the data in the adapter mAdapter.unload(); } - /** - * Scrolls the list to the currently playing album when the user touches the - * header in the {@link TitlePageIndicator}. - */ - public void scrollToCurrentAlbum() { - final int currentAlbumPosition = getItemPositionByAlbum(); - - if (currentAlbumPosition != 0) { - mGridView.setSelection(currentAlbumPosition); - } - } - - /** - * @return The position of an item in the list or grid based on the id of - * the currently playing album. - */ - private int getItemPositionByAlbum() { - final long albumId = MusicUtils.getCurrentAlbumId(); - if (mAdapter == null) { - return 0; - } - - int position = mAdapter.getItemPosition(albumId); - - // if for some reason we don't find the item, just jump to the top - if (position < 0) { - return 0; - } - - return position; - } - /** * Restarts the loader. */ @@ -258,27 +188,12 @@ public class AlbumFragment extends MusicBrowserFragment implements restartLoader(); } - /** - * {@inheritDoc} - */ - @Override - public void onScroll(final AbsListView view, final int firstVisibleItem, - final int visibleItemCount, final int totalItemCount) { - // Nothing to do - } - - /** - * {@inheritDoc} - */ @Override public void restartLoader() { // Update the list when the user deletes any items - restartLoader(null, this); + restartLoader(this); } - /** - * {@inheritDoc} - */ @Override public void onMetaChanged() { // Nothing to do @@ -289,36 +204,29 @@ public class AlbumFragment extends MusicBrowserFragment implements // Nothing to do } - /** - * Sets up various helpers for both the list and grid - * - * @param list The list or grid - */ - private void initAbsListView(final AbsListView list) { - // Release any references to the recycled Views - list.setRecyclerListener(new RecycleHolder()); - // Show the albums and songs from the selected artist - list.setOnItemClickListener(this); - // To help make scrolling smooth - list.setOnScrollListener(this); - } - /** * Sets up the grid view */ private void initGridView() { - int columns = ElevenUtils.isLandscape(getActivity()) ? FOUR : TWO; - mAdapter.setNumColumns(columns); + final Activity activity = getActivity(); + int columns = (activity != null && ElevenUtils.isLandscape(activity)) ? FOUR : TWO; + final GridLayoutManager layoutManager = new GridLayoutManager(activity, columns); // Initialize the grid - mGridView = (GridView)mRootView.findViewById(R.id.grid_base); - // Set the data behind the grid - mGridView.setAdapter(mAdapter); + RecyclerView gridView = mRootView.findViewById(R.id.grid_base); // Set up the helpers - initAbsListView(mGridView); - mGridView.setNumColumns(columns); + gridView.setLayoutManager(layoutManager); + // Set up the animator + gridView.setItemAnimator(new DefaultItemAnimator()); + // Set the data behind the grid + gridView.setAdapter(mAdapter); // Show progress bar - mLoadingEmptyContainer = (LoadingEmptyContainer)mRootView.findViewById(R.id.loading_empty_container); - mGridView.setEmptyView(mLoadingEmptyContainer); + mLoadingEmptyContainer = mRootView.findViewById(R.id.loading_empty_container); + mLoadingEmptyContainer.setVisibility(View.VISIBLE); + } + + private void onItemClick(Album album) { + NavUtils.openAlbumProfile(getActivity(), album.mAlbumName, album.mArtistName, + album.mAlbumId); } } diff --git a/src/org/lineageos/eleven/ui/fragments/ArtistDetailFragment.java b/src/org/lineageos/eleven/ui/fragments/ArtistDetailFragment.java index 798f58290cd239c901ccbd9b1b24a1364ffa6d36..9e97b28e820d36a53f93fd5511333c28272d8372 100644 --- a/src/org/lineageos/eleven/ui/fragments/ArtistDetailFragment.java +++ b/src/org/lineageos/eleven/ui/fragments/ArtistDetailFragment.java @@ -1,30 +1,35 @@ /* -* Copyright (C) 2014 The CyanogenMod Project -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ + * Copyright (C) 2014 The CyanogenMod Project + * Copyright (C) 2021 The LineageOS Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package org.lineageos.eleven.ui.fragments; import android.graphics.drawable.ColorDrawable; import android.os.Bundle; -import android.view.LayoutInflater; +import android.os.Handler; +import android.provider.MediaStore; import android.view.View; import android.view.ViewTreeObserver; import android.widget.ImageView; -import android.widget.ListView; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import androidx.core.content.ContextCompat; import androidx.loader.app.LoaderManager; +import androidx.loader.content.Loader; +import androidx.recyclerview.widget.DefaultItemAnimator; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; @@ -34,6 +39,8 @@ import org.lineageos.eleven.adapters.ArtistDetailAlbumAdapter; import org.lineageos.eleven.adapters.ArtistDetailSongAdapter; import org.lineageos.eleven.adapters.PagerAdapter; import org.lineageos.eleven.cache.ImageFetcher; +import org.lineageos.eleven.loaders.AlbumLoader; +import org.lineageos.eleven.loaders.SongLoader; import org.lineageos.eleven.menu.FragmentMenuItems; import org.lineageos.eleven.model.Album; import org.lineageos.eleven.model.Artist; @@ -43,12 +50,12 @@ import org.lineageos.eleven.utils.ArtistPopupMenuHelper; import org.lineageos.eleven.utils.MusicUtils; import org.lineageos.eleven.utils.PopupMenuHelper; import org.lineageos.eleven.utils.SongPopupMenuHelper; -import org.lineageos.eleven.widgets.IPopupMenuCallback; import org.lineageos.eleven.widgets.LoadingEmptyContainer; +import java.util.List; import java.util.TreeSet; -public class ArtistDetailFragment extends FadingBarFragment implements IChildFragment { +public class ArtistDetailFragment extends DetailFragment implements IChildFragment { private final int ALBUM_LOADER_ID = 0; private final int SONG_LOADER_ID = 1; @@ -56,12 +63,9 @@ public class ArtistDetailFragment extends FadingBarFragment implements IChildFra private String mArtistName; private ImageView mHero; - private View mHeader; - private ListView mSongs; private ArtistDetailSongAdapter mSongAdapter; - private RecyclerView mAlbums; private ArtistDetailAlbumAdapter mAlbumAdapter; private PopupMenuHelper mSongPopupMenuHelper; @@ -69,16 +73,81 @@ public class ArtistDetailFragment extends FadingBarFragment implements IChildFra private LoadingEmptyContainer mLoadingEmptyContainer; + private final LoaderManager.LoaderCallbacks> mSongsLoader = + new LoaderManager.LoaderCallbacks>() { + @NonNull + @Override + public Loader> onCreateLoader(int id, @Nullable Bundle args) { + mLoadingEmptyContainer.showLoading(); + long sourceId = args == null ? -1 : args.getLong(Config.ID); + final String selection = + MediaStore.Audio.AudioColumns.ARTIST_ID + "=" + sourceId; + return new SongLoader(getContext(), selection); + } + + @Override + public void onLoadFinished(@NonNull Loader> loader, List data) { + Handler handler = new Handler(requireActivity().getMainLooper()); + + if (data.isEmpty()) { + // no results - because the user deleted the last item - pop our fragment + // from the stack + getContainingActivity().postRemoveFragment(ArtistDetailFragment.this); + return; + } + + mLoadingEmptyContainer.setVisibility(View.GONE); + // Do on UI thread: https://issuetracker.google.com/issues/37030377 + handler.post(() -> mSongAdapter.setData(data)); + } + + @Override + public void onLoaderReset(@NonNull Loader> loader) { + mSongAdapter.unload(); + } + }; + + private final LoaderManager.LoaderCallbacks> mAlbumLoader = + new LoaderManager.LoaderCallbacks>() { + @NonNull + @Override + public Loader> onCreateLoader(int id, @Nullable Bundle args) { + return args == null + ? new Loader<>(requireContext()) + : new AlbumLoader(requireContext(), args.getLong(Config.ID)); + } + + @Override + public void onLoadFinished(@NonNull Loader> loader, List data) { + Handler handler = new Handler(requireActivity().getMainLooper()); + if (data.isEmpty()) { + return; + } + + // Do on UI thread: https://issuetracker.google.com/issues/37030377 + handler.post(() -> mAlbumAdapter.setData(data)); + } + + @Override + public void onLoaderReset(@NonNull Loader> loader) { + mAlbumAdapter.unload(); + } + }; + @Override - protected int getLayoutToInflate() { return R.layout.activity_artist_detail; } + protected int getLayoutToInflate() { + return R.layout.activity_artist_detail; + } @Override protected String getTitle() { - return getArguments().getString(Config.ARTIST_NAME); + final Bundle args = getArguments(); + return args == null ? "" : args.getString(Config.ARTIST_NAME); } protected long getArtistId() { - return getArguments().getLong(Config.ID); + final Bundle args = getArguments(); + return args == null ? -1 : getArguments().getLong(Config.ID); } @Override @@ -87,24 +156,24 @@ public class ArtistDetailFragment extends FadingBarFragment implements IChildFra getContainingActivity().setFragmentPadding(false); - Bundle arguments = getArguments(); - mArtistName = arguments.getString(Config.ARTIST_NAME); - mArtistId = arguments.getLong(Config.ID); + Bundle args = getArguments(); + mArtistName = args == null ? "" : args.getString(Config.ARTIST_NAME); + mArtistId = args == null ? -1 : args.getLong(Config.ID); setupPopupMenuHelpers(); setupSongList(); setupAlbumList(); setupHero(mArtistName); - LoaderManager lm = getLoaderManager(); - lm.initLoader(ALBUM_LOADER_ID, arguments, mAlbumAdapter); - lm.initLoader(SONG_LOADER_ID, arguments, mSongAdapter); + LoaderManager lm = LoaderManager.getInstance(this); + lm.initLoader(ALBUM_LOADER_ID, args, mAlbumLoader); + lm.initLoader(SONG_LOADER_ID, args, mSongsLoader); if (getContainingActivity().getSupportActionBar() != null) getContainingActivity().getSupportActionBar().setBackgroundDrawable( new ColorDrawable(ContextCompat.getColor(getContainingActivity(),R.color.primary_dark))); } - @Override // DetailFragment + @Override protected PopupMenuHelper createActionMenuHelper() { return new ArtistPopupMenuHelper(getActivity(), getChildFragmentManager()) { public Artist getArtist(int position) { @@ -113,73 +182,55 @@ public class ArtistDetailFragment extends FadingBarFragment implements IChildFra }; } - @Override // DetailFragment - protected int getShuffleTitleId() { return R.string.menu_shuffle_artist; } + @Override + protected int getShuffleTitleId() { + return R.string.menu_shuffle_artist; + } - @Override // DetailFragment + @Override protected void playShuffled() { MusicUtils.playArtist(getActivity(), mArtistId, -1, true); } private void setupHero(String artistName) { - mHero = (ImageView)mHeader.findViewById(R.id.hero); + mHero = mRootView.findViewById(R.id.hero); mHero.setContentDescription(artistName); // initiate loading the artist image - // since the artist image needs to be scaled to the image view bounds, we need to wait till the first layout - // traversal to be able to get the image view dimensions in the helper method that scales the image - mHero.getViewTreeObserver().addOnGlobalLayoutListener( new ViewTreeObserver.OnGlobalLayoutListener() { - @Override - public void onGlobalLayout() { - mHero.getViewTreeObserver().removeOnGlobalLayoutListener(this); - ImageFetcher.getInstance(getActivity()).loadArtistImage(mArtistName, mHero, true); - } - }); + // since the artist image needs to be scaled to the image view bounds, + // we need to wait till the first layout traversal to be able to get the image view + // dimensions in the helper method that scales the image + mHero.getViewTreeObserver().addOnGlobalLayoutListener( + new ViewTreeObserver.OnGlobalLayoutListener() { + @Override + public void onGlobalLayout() { + mHero.getViewTreeObserver().removeOnGlobalLayoutListener(this); + ImageFetcher.getInstance(getActivity()). + loadArtistImage(mArtistName, mHero, true); + } + }); } private void setupAlbumList() { - mAlbums = (RecyclerView) mHeader.findViewById(R.id.albums); - mAlbums.setHasFixedSize(true); - mAlbums.setLayoutManager(new LinearLayoutManager(getActivity(), LinearLayoutManager.HORIZONTAL, false)); + RecyclerView albumsList = mRootView.findViewById(R.id.albums); mAlbumAdapter = new ArtistDetailAlbumAdapter(getActivity()); - mAlbumAdapter.setPopupMenuClickedListener(new IPopupMenuCallback.IListener() { - @Override - public void onPopupMenuClicked(View v, int position) { - mAlbumPopupMenuHelper.showPopupMenu(v, position); - } - }); - mAlbums.setAdapter(mAlbumAdapter); + mAlbumAdapter.setPopupMenuClickedListener((v, position) -> + mAlbumPopupMenuHelper.showPopupMenu(v, position)); + albumsList.setLayoutManager(new LinearLayoutManager(getActivity(), + LinearLayoutManager.HORIZONTAL, false)); + albumsList.setItemAnimator(new DefaultItemAnimator()); + albumsList.setAdapter(mAlbumAdapter); } private void setupSongList() { - mSongs = (ListView)mRootView.findViewById(R.id.songs); - mHeader = LayoutInflater.from(getActivity()). - inflate(R.layout.artist_detail_header, mSongs, false); - mSongs.addHeaderView(mHeader); - mSongs.setOnScrollListener(this); - mSongAdapter = new ArtistDetailSongAdapter(getActivity()) { - @Override - protected void onLoading() { - mLoadingEmptyContainer.showLoading(); - } - - @Override - protected void onNoResults() { - // no results - because the user deleted the last item - pop our fragment - // from the stack - getContainingActivity().postRemoveFragment(ArtistDetailFragment.this); - } - }; - mSongAdapter.setPopupMenuClickedListener(new IPopupMenuCallback.IListener() { - @Override - public void onPopupMenuClicked(View v, int position) { - mSongPopupMenuHelper.showPopupMenu(v, position); - } - }); - mSongs.setAdapter(mSongAdapter); - mSongs.setOnItemClickListener(mSongAdapter); - mLoadingEmptyContainer = - (LoadingEmptyContainer)mRootView.findViewById(R.id.loading_empty_container); - mSongs.setEmptyView(mLoadingEmptyContainer); + RecyclerView songsList = mRootView.findViewById(R.id.songs); + mSongAdapter = new ArtistDetailSongAdapter(getActivity()); + mSongAdapter.setPopupMenuClickedListener((v, position) -> + mSongPopupMenuHelper.showPopupMenu(v, position)); + songsList.setLayoutManager(new LinearLayoutManager(requireActivity())); + songsList.setItemAnimator(new DefaultItemAnimator()); + songsList.setAdapter(mSongAdapter); + mLoadingEmptyContainer = mRootView.findViewById(R.id.loading_empty_container); + mLoadingEmptyContainer.showLoading(); } private void setupPopupMenuHelpers() { @@ -224,17 +275,12 @@ public class ArtistDetailFragment extends FadingBarFragment implements IChildFra }; } - // TODO: change this class to use the same header strategy as PlaylistDetail - protected int getHeaderHeight() { return mHero.getHeight(); } - - protected void setHeaderPosition(float y) { } - @Override public void restartLoader() { Bundle arguments = getArguments(); - LoaderManager lm = getLoaderManager(); - lm.restartLoader(ALBUM_LOADER_ID, arguments, mAlbumAdapter); - lm.restartLoader(SONG_LOADER_ID, arguments, mSongAdapter); + LoaderManager lm = LoaderManager.getInstance(this); + lm.restartLoader(ALBUM_LOADER_ID, arguments, mAlbumLoader); + lm.restartLoader(SONG_LOADER_ID, arguments, mSongsLoader); ImageFetcher.getInstance(getActivity()).loadArtistImage(mArtistName, mHero, true); } diff --git a/src/org/lineageos/eleven/ui/fragments/ArtistFragment.java b/src/org/lineageos/eleven/ui/fragments/ArtistFragment.java index b142af8ccceddc8c95931188fef316ea46911204..9bc297f2b9f25bd905a66c96fd22d86801cd6345 100644 --- a/src/org/lineageos/eleven/ui/fragments/ArtistFragment.java +++ b/src/org/lineageos/eleven/ui/fragments/ArtistFragment.java @@ -1,33 +1,39 @@ /* * Copyright (C) 2012 Andrew Neal - * Copyright (C) 2014 The CyanogenMod Project - * Licensed under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law - * or agreed to in writing, software distributed under the License is - * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the specific language - * governing permissions and limitations under the License. + * Copyright (C) 2021 The LineageOS Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ - package org.lineageos.eleven.ui.fragments; +import android.annotation.SuppressLint; +import android.app.Activity; import android.content.Context; import android.os.Bundle; +import android.os.Handler; import android.os.SystemClock; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; -import android.widget.AbsListView; -import android.widget.AbsListView.OnScrollListener; -import android.widget.AdapterView; -import android.widget.AdapterView.OnItemClickListener; -import android.widget.ListView; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import androidx.fragment.app.Fragment; import androidx.loader.app.LoaderManager; import androidx.loader.content.Loader; +import androidx.recyclerview.widget.DefaultItemAnimator; +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; import org.lineageos.eleven.MusicStateListener; import org.lineageos.eleven.R; @@ -35,20 +41,19 @@ import org.lineageos.eleven.adapters.ArtistAdapter; import org.lineageos.eleven.adapters.PagerAdapter; import org.lineageos.eleven.loaders.ArtistLoader; import org.lineageos.eleven.model.Artist; -import org.lineageos.eleven.recycler.RecycleHolder; -import org.lineageos.eleven.sectionadapter.SectionAdapter; import org.lineageos.eleven.sectionadapter.SectionCreator; import org.lineageos.eleven.sectionadapter.SectionListContainer; import org.lineageos.eleven.ui.activities.BaseActivity; import org.lineageos.eleven.ui.fragments.phone.MusicBrowserFragment; import org.lineageos.eleven.utils.ArtistPopupMenuHelper; -import org.lineageos.eleven.utils.MusicUtils; import org.lineageos.eleven.utils.NavUtils; import org.lineageos.eleven.utils.PopupMenuHelper; import org.lineageos.eleven.utils.SectionCreatorUtils; import org.lineageos.eleven.utils.SectionCreatorUtils.IItemCompare; -import org.lineageos.eleven.widgets.IPopupMenuCallback; import org.lineageos.eleven.widgets.LoadingEmptyContainer; +import org.lineageos.eleven.widgets.SectionSeparatorItemDecoration; + +import java.util.TreeMap; /** * This class is used to display all of the artists on a user's device. @@ -56,8 +61,7 @@ import org.lineageos.eleven.widgets.LoadingEmptyContainer; * @author Andrew Neal (andrewdneal@gmail.com) */ public class ArtistFragment extends MusicBrowserFragment implements - LoaderManager.LoaderCallbacks>, - OnScrollListener, OnItemClickListener, MusicStateListener { + LoaderManager.LoaderCallbacks>, MusicStateListener { /** * Fragment UI @@ -67,12 +71,7 @@ public class ArtistFragment extends MusicBrowserFragment implements /** * The adapter for the grid */ - private SectionAdapter mAdapter; - - /** - * The list view - */ - private ListView mListView; + private ArtistAdapter mAdapter; /** * Pop up menu helper @@ -83,6 +82,10 @@ public class ArtistFragment extends MusicBrowserFragment implements * Loading container and no results container */ private LoadingEmptyContainer mLoadingEmptyContainer; + /** + * The list view. + */ + private RecyclerView mListView; /** * Empty constructor as per the {@link Fragment} documentation @@ -95,44 +98,37 @@ public class ArtistFragment extends MusicBrowserFragment implements return PagerAdapter.MusicFragments.ARTIST.ordinal(); } - /** - * {@inheritDoc} - */ @Override public void onCreate(final Bundle savedInstanceState) { super.onCreate(savedInstanceState); - mPopupMenuHelper = new ArtistPopupMenuHelper(getActivity(), getFragmentManager()) { + mPopupMenuHelper = new ArtistPopupMenuHelper(getActivity(), getChildFragmentManager()) { @Override public Artist getArtist(int position) { - return mAdapter.getTItem(position); + return mAdapter.getItem(position); } }; // Create the adapter final int layout = R.layout.list_item_normal; - ArtistAdapter adapter = new ArtistAdapter(getActivity(), layout); - mAdapter = new SectionAdapter<>(getActivity(), adapter); - mAdapter.setPopupMenuClickedListener(new IPopupMenuCallback.IListener() { - @Override - public void onPopupMenuClicked(View v, int position) { - mPopupMenuHelper.showPopupMenu(v, position); - } - }); + mAdapter = new ArtistAdapter(requireActivity(), layout, this::onItemClick); + mAdapter.setPopupMenuClickedListener((v, position) -> + mPopupMenuHelper.showPopupMenu(v, position)); } - /** - * {@inheritDoc} - */ + @SuppressLint("InflateParams") @Override public View onCreateView(final LayoutInflater inflater, final ViewGroup container, - final Bundle savedInstanceState) { + final Bundle savedInstanceState) { // The View for the fragment's UI - mRootView = (ViewGroup)inflater.inflate(R.layout.list_base, null); + mRootView = (ViewGroup) inflater.inflate(R.layout.fragment_list, container, false); initListView(); // Register the music status listener - ((BaseActivity)getActivity()).setMusicStateListenerListener(this); + final Activity activity = getActivity(); + if (activity instanceof BaseActivity) { + ((BaseActivity) activity).setMusicStateListenerListener(this); + } return mRootView; } @@ -141,58 +137,33 @@ public class ArtistFragment extends MusicBrowserFragment implements public void onDestroyView() { super.onDestroyView(); - ((BaseActivity)getActivity()).removeMusicStateListenerListener(this); + final Activity activity = getActivity(); + if (activity instanceof BaseActivity) { + ((BaseActivity) activity).removeMusicStateListenerListener(this); + } } - - /** - * {@inheritDoc} - */ @Override - public void onActivityCreated(final Bundle savedInstanceState) { - super.onActivityCreated(savedInstanceState); + public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); // Enable the options menu setHasOptionsMenu(true); // Start the loader - initLoader(null, this); + initLoader(this); } - /** - * {@inheritDoc} - */ @Override public void onPause() { super.onPause(); mAdapter.flush(); } - /** - * {@inheritDoc} - */ - @Override - public void onScrollStateChanged(final AbsListView view, final int scrollState) { - // Pause disk cache access to ensure smoother scrolling - if (scrollState == AbsListView.OnScrollListener.SCROLL_STATE_FLING) { - mAdapter.getUnderlyingAdapter().setPauseDiskCache(true); - } else { - mAdapter.getUnderlyingAdapter().setPauseDiskCache(false); - mAdapter.notifyDataSetChanged(); - } - } - - /** - * {@inheritDoc} - */ - @Override - public void onItemClick(final AdapterView parent, final View view, final int position, - final long id) { - Artist artist = mAdapter.getTItem(position); + public void onItemClick(final int position) { + Artist artist = mAdapter.getItem(position); NavUtils.openArtistProfile(getActivity(), artist.mArtistName); } - /** - * {@inheritDoc} - */ + @NonNull @Override public Loader> onCreateLoader(final int id, final Bundle args) { mLoadingEmptyContainer.showLoading(); @@ -201,62 +172,28 @@ public class ArtistFragment extends MusicBrowserFragment implements return new SectionCreator<>(getActivity(), new ArtistLoader(context), comparator); } - /** - * {@inheritDoc} - */ @Override - public void onLoadFinished(final Loader> loader, + public void onLoadFinished(@NonNull final Loader> loader, final SectionListContainer data) { + Handler handler = new Handler(requireActivity().getMainLooper()); if (data.mListResults.isEmpty()) { - mAdapter.unload(); + handler.post(() -> mAdapter.unload()); mLoadingEmptyContainer.showNoResults(); return; } - mAdapter.setData(data); + mLoadingEmptyContainer.setVisibility(View.GONE); + + handler.post(() -> mAdapter.setData(data.mListResults)); + setHeaders(data.mSections); } - /** - * {@inheritDoc} - */ @Override - public void onLoaderReset(final Loader> loader) { + public void onLoaderReset(@NonNull final Loader> loader) { // Clear the data in the adapter mAdapter.unload(); } - /** - * Scrolls the list to the currently playing artist when the user touches - * the header in the {@link TitlePageIndicator}. - */ - public void scrollToCurrentArtist() { - final int currentArtistPosition = getItemPositionByArtist(); - - if (currentArtistPosition != 0) { - mListView.setSelection(currentArtistPosition); - } - } - - /** - * @return The position of an item in the list or grid based on the name of - * the currently playing artist. - */ - private int getItemPositionByArtist() { - final long artistId = MusicUtils.getCurrentArtistId(); - if (mAdapter == null) { - return 0; - } - - int position = mAdapter.getItemPosition(artistId); - - // if for some reason we don't find the item, just jump to the top - if (position < 0) { - return 0; - } - - return position; - } - /** * Restarts the loader. */ @@ -266,27 +203,12 @@ public class ArtistFragment extends MusicBrowserFragment implements restartLoader(); } - /** - * {@inheritDoc} - */ - @Override - public void onScroll(final AbsListView view, final int firstVisibleItem, - final int visibleItemCount, final int totalItemCount) { - // Nothing to do - } - - /** - * {@inheritDoc} - */ @Override public void restartLoader() { // Update the list when the user deletes any items - restartLoader(null, this); + restartLoader(this); } - /** - * {@inheritDoc} - */ @Override public void onMetaChanged() { // Nothing to do @@ -297,18 +219,11 @@ public class ArtistFragment extends MusicBrowserFragment implements // Nothing to do } - /** - * Sets up various helpers for both the list and grid - * - * @param list The list or grid - */ - private void initAbsListView(final AbsListView list) { - // Release any references to the recycled Views - list.setRecyclerListener(new RecycleHolder()); - // Show the albums and songs from the selected artist - list.setOnItemClickListener(this); - // To help make scrolling smooth - list.setOnScrollListener(this); + private void setHeaders(TreeMap sections) { + for (int i = 0; i < mListView.getItemDecorationCount(); i++) { + mListView.removeItemDecorationAt(i); + } + mListView.addItemDecoration(new SectionSeparatorItemDecoration(requireContext(), sections)); } /** @@ -316,13 +231,14 @@ public class ArtistFragment extends MusicBrowserFragment implements */ private void initListView() { // Initialize the grid - mListView = (ListView)mRootView.findViewById(R.id.list_base); + mListView = mRootView.findViewById(R.id.list_base); // Set the data behind the list mListView.setAdapter(mAdapter); + mListView.setLayoutManager(new LinearLayoutManager(requireActivity())); + mListView.setItemAnimator(new DefaultItemAnimator()); + // set the loading and empty view container - mLoadingEmptyContainer = (LoadingEmptyContainer)mRootView.findViewById(R.id.loading_empty_container); - mListView.setEmptyView(mLoadingEmptyContainer); - // Set up the helpers - initAbsListView(mListView); + mLoadingEmptyContainer = mRootView.findViewById(R.id.loading_empty_container); + mLoadingEmptyContainer.setVisibility(View.VISIBLE); } } diff --git a/src/org/lineageos/eleven/ui/fragments/AudioPlayerFragment.java b/src/org/lineageos/eleven/ui/fragments/AudioPlayerFragment.java index a427344f8a6a605e3929325e5cb4aee9ee3a73b3..41016cd7cb28811361e3c083baa68a83efddaba6 100644 --- a/src/org/lineageos/eleven/ui/fragments/AudioPlayerFragment.java +++ b/src/org/lineageos/eleven/ui/fragments/AudioPlayerFragment.java @@ -1,6 +1,6 @@ /* * Copyright (C) 2014 The CyanogenMod Project - * Copyright (C) 2018-2020 The LineageOS Project + * Copyright (C) 2018-2021 The LineageOS Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -27,6 +27,7 @@ import android.media.AudioManager; import android.os.Bundle; import android.os.Handler; import android.os.IBinder; +import android.os.Looper; import android.os.Message; import android.os.PowerManager; import android.text.Html; @@ -46,6 +47,8 @@ import androidx.annotation.Nullable; import androidx.appcompat.widget.Toolbar; import androidx.core.content.ContextCompat; import androidx.fragment.app.Fragment; +import androidx.fragment.app.FragmentActivity; +import androidx.fragment.app.FragmentManager; import androidx.viewpager.widget.ViewPager; import org.lineageos.eleven.MusicPlaybackService; @@ -112,29 +115,14 @@ public class AudioPlayerFragment extends Fragment implements ServiceConnection { private long mSelectedId = -1; - @Override - public void onActivityCreated(Bundle savedInstanceState) { - super.onActivityCreated(savedInstanceState); - - // Control the media volume - getActivity().setVolumeControlStream(AudioManager.STREAM_MUSIC); - - // Initialize the image fetcher/cache - mImageFetcher = ElevenUtils.getImageFetcher(getActivity()); - - // Initialize the handler used to update the current time - mTimeHandler = new TimeHandler(this); - - // Initialize the broadcast receiver - mPlaybackStatus = new PlaybackStatus(this); - } + private boolean mIgnoreAfterRequest; @Override public View onCreateView(@NonNull final LayoutInflater inflater, final ViewGroup container, - final Bundle savedInstanceState) { + final Bundle savedInstanceState) { // The View for the fragment's UI - mRootView = (ViewGroup) inflater.inflate(R.layout.activity_player_fragment, container, - false); + mRootView = (ViewGroup) inflater.inflate(R.layout.activity_player_fragment, + container, false); initHeaderBar(); initPlaybackControls(); @@ -152,10 +140,26 @@ public class AudioPlayerFragment extends Fragment implements ServiceConnection { public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); setHasOptionsMenu(true); + + // Control the media volume + final FragmentActivity activity = getActivity(); + if (activity != null) { + activity.setVolumeControlStream(AudioManager.STREAM_MUSIC); + } + + // Initialize the image fetcher/cache + mImageFetcher = ElevenUtils.getImageFetcher(getActivity()); + + // Initialize the handler used to update the current time + mTimeHandler = new TimeHandler(Looper.getMainLooper()); + mTimeHandler.setFragment(this); + + // Initialize the broadcast receiver + mPlaybackStatus = new PlaybackStatus(this); } @Override - public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { + public void onCreateOptionsMenu(@NonNull Menu menu, @NonNull MenuInflater inflater) { super.onCreateOptionsMenu(menu, inflater); final Menu playerMenu = mPlayerToolBar.getMenu(); @@ -167,7 +171,8 @@ public class AudioPlayerFragment extends Fragment implements ServiceConnection { // ringtone, and equalizer inflater.inflate(R.menu.audio_player, playerMenu); - if (!NavUtils.hasEffectsPanel(getActivity())) { + final FragmentActivity activity = getActivity(); + if (activity != null && !NavUtils.hasEffectsPanel(activity)) { playerMenu.removeItem(R.id.menu_audio_player_equalizer); } @@ -185,68 +190,72 @@ public class AudioPlayerFragment extends Fragment implements ServiceConnection { @Override public boolean onOptionsItemSelected(MenuItem item) { - switch (item.getItemId()) { - case R.id.menu_audio_player_add_to_playlist: { - // save the current track id - mSelectedId = MusicUtils.getCurrentAudioId(); - final List menuItemList = MusicUtils.makePlaylist(getActivity()); - - final AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); + final FragmentActivity activity = getActivity(); + final FragmentManager fragmentManager = activity == null ? + null : activity.getSupportFragmentManager(); + + final int id = item.getItemId(); + if (id == R.id.menu_audio_player_add_to_playlist) { + // save the current track id + mSelectedId = MusicUtils.getCurrentAudioId(); + if (activity != null) { + final List menuItemList = MusicUtils.makePlaylist(activity); + final AlertDialog.Builder builder = new AlertDialog.Builder(activity); builder.setTitle(R.string.add_to_playlist) .setItems(menuItemList.toArray(new String[0]), (dialog, which) -> { - final long playListId = MusicUtils.getIdForPlaylist(getActivity(), + final long playListId = MusicUtils.getIdForPlaylist(activity, menuItemList.get(which)); - MusicUtils.addToPlaylist(getActivity(), new long[]{mSelectedId}, + MusicUtils.addToPlaylist(activity, new long[]{mSelectedId}, playListId); }) .setPositiveButton(R.string.new_playlist, (dialog, which) -> { dialog.dismiss(); CreateNewPlaylist.getInstance(new long[]{mSelectedId}) - .show(getFragmentManager(), "CreatePlaylist"); + .show(fragmentManager, "CreatePlaylist"); }); mAlertDialog = builder.show(); - return true; } - case R.id.menu_shuffle_all: - // Shuffle all the songs - MusicUtils.shuffleAll(getActivity()); - return true; - case R.id.menu_audio_player_ringtone: + } else if (id == R.id.menu_shuffle_all) { + // Shuffle all the songs + MusicUtils.shuffleAll(activity); + } else if (id == R.id.menu_audio_player_ringtone) { + if (activity != null) { // Set the current track as a ringtone - MusicUtils.setRingtone(getActivity(), MusicUtils.getCurrentAudioId()); - return true; - case R.id.menu_audio_player_equalizer: + MusicUtils.setRingtone(activity, MusicUtils.getCurrentAudioId()); + } + } else if (id == R.id.menu_audio_player_equalizer) { + if (activity != null) { // Sound effects - NavUtils.openEffectsPanel(getActivity(), HomeActivity.EQUALIZER); - return true; - case R.id.menu_settings: - // Settings - NavUtils.openSettings(getActivity()); - return true; - case R.id.menu_audio_player_more_by_artist: - NavUtils.openArtistProfile(getActivity(), MusicUtils.getArtistName()); - return true; - case R.id.menu_audio_player_delete: - // Delete current song - DeleteDialog.newInstance(MusicUtils.getTrackName(), new long[]{ - MusicUtils.getCurrentAudioId() - }, null).show(getActivity().getSupportFragmentManager(), "DeleteDialog"); - return true; - case R.id.menu_save_queue: - NowPlayingCursor queue = (NowPlayingCursor) QueueLoader - .makeQueueCursor(getActivity()); - CreateNewPlaylist.getInstance(MusicUtils.getSongListForCursor(queue)).show( - getFragmentManager(), "CreatePlaylist"); - queue.close(); - return true; - case R.id.menu_clear_queue: - MusicUtils.clearQueue(); - return true; - default: - break; + NavUtils.openEffectsPanel(activity, HomeActivity.EQUALIZER); + } + } else if (id == R.id.menu_settings) { + // Settings + NavUtils.openSettings(activity); + } else if (id == R.id.menu_audio_player_more_by_artist) { + NavUtils.openArtistProfile(activity, MusicUtils.getArtistName()); + } else if (id == R.id.menu_audio_player_delete) { + // Delete current song + if (fragmentManager != null) { + DeleteDialog.newInstance( + MusicUtils.getTrackName(), + new long[]{MusicUtils.getCurrentAudioId()}, + null + ).show(fragmentManager, "DeleteDialog"); + } + } else if (id == R.id.menu_save_queue) { + NowPlayingCursor queue = (NowPlayingCursor) QueueLoader.makeQueueCursor(activity); + if (fragmentManager != null) { + CreateNewPlaylist.getInstance(MusicUtils.getSongListForCursor(queue)). + show(fragmentManager, "CreatePlaylist"); + } + queue.close(); + } else if (id == R.id.menu_clear_queue) { + MusicUtils.clearQueue(); + } else { + return super.onOptionsItemSelected(item); } - return super.onOptionsItemSelected(item); + return true; } @Override @@ -283,12 +292,16 @@ public class AudioPlayerFragment extends Fragment implements ServiceConnection { filter.addAction(MusicPlaybackService.REFRESH); // Listen to changes to the entire queue filter.addAction(MusicPlaybackService.QUEUE_CHANGED); + filter.addAction(MusicPlaybackService.QUEUE_MOVED); // Listen for lyrics text for the audio track filter.addAction(MusicPlaybackService.NEW_LYRICS); // Listen for power save mode changed filter.addAction(PowerManager.ACTION_POWER_SAVE_MODE_CHANGED); // Register the intent filters - getActivity().registerReceiver(mPlaybackStatus, filter); + final FragmentActivity activity = getActivity(); + if (activity != null) { + activity.registerReceiver(mPlaybackStatus, filter); + } // Refresh the current time final long next = refreshCurrentTime(); queueNextRefresh(next); @@ -313,7 +326,10 @@ public class AudioPlayerFragment extends Fragment implements ServiceConnection { // Unregister the receiver try { - getActivity().unregisterReceiver(mPlaybackStatus); + final FragmentActivity activity = getActivity(); + if (activity != null) { + activity.unregisterReceiver(mPlaybackStatus); + } } catch (final Throwable e) { //$FALL-THROUGH$ } @@ -343,7 +359,7 @@ public class AudioPlayerFragment extends Fragment implements ServiceConnection { public void onPageSelected(int position) { super.onPageSelected(position); - int currentPosition = 0; + int currentPosition; if (MusicUtils.getShuffleMode() == MusicPlaybackService.SHUFFLE_NONE) { // if we aren't shuffling, base the position on the queue position currentPosition = MusicUtils.getQueuePosition(); @@ -369,8 +385,11 @@ public class AudioPlayerFragment extends Fragment implements ServiceConnection { } private void setupNoResultsContainer(NoResultsContainer empty) { - int color = ContextCompat.getColor(getContext(), R.color.no_results_light); - empty.setTextColor(color); + final Context context = getContext(); + if (context != null) { + final int color = ContextCompat.getColor(getContext(), R.color.no_results_light); + empty.setTextColor(color); + } empty.setMainText(R.string.empty_queue_main); empty.setSecondaryText(R.string.empty_queue_secondary); } @@ -430,7 +449,7 @@ public class AudioPlayerFragment extends Fragment implements ServiceConnection { mAlbumArtViewPager.setAdapter(albumArtPagerAdapter); mAlbumArtViewPager.setCurrentItem(targetIndex); - if(queueSize == 0) { + if (queueSize == 0) { mAlbumArtViewPager.setVisibility(View.GONE); mQueueEmpty.showNoResults(); } else { @@ -473,7 +492,7 @@ public class AudioPlayerFragment extends Fragment implements ServiceConnection { mLyricsText.animate().alpha(0).setDuration(200); } else { lyrics = lyrics.replace("\n", "
"); - Spanned span = Html.fromHtml(lyrics); + Spanned span = Html.fromHtml(lyrics, Html.FROM_HTML_MODE_LEGACY); mLyricsText.setText(span); mLyricsText.animate().alpha(1).setDuration(200); @@ -481,11 +500,20 @@ public class AudioPlayerFragment extends Fragment implements ServiceConnection { } public void setVisualizerVisible(boolean visible) { - if (visible && PreferenceUtils.getInstance(getActivity()).getShowVisualizer()) { - if (PreferenceUtils.canRecordAudio(getActivity())) { + final FragmentActivity activity = getActivity(); + if (visible && activity != null && + PreferenceUtils.getInstance(activity).getShowVisualizer()) { + if (PreferenceUtils.canRecordAudio(activity)) { mVisualizerView.setVisible(true); + mIgnoreAfterRequest = false; } else { - PreferenceUtils.requestRecordAudio(getActivity()); + if (mIgnoreAfterRequest) { + mIgnoreAfterRequest = false; + mVisualizerView.setVisible(false); + } else { + mIgnoreAfterRequest = true; + PreferenceUtils.requestRecordAudio(activity); + } } } else { mVisualizerView.setVisible(false); @@ -493,8 +521,11 @@ public class AudioPlayerFragment extends Fragment implements ServiceConnection { } public void updateVisualizerPowerSaveMode() { - PowerManager pm = getActivity().getSystemService(PowerManager.class); - mVisualizerView.setPowerSaveMode(pm.isPowerSaveMode()); + final FragmentActivity activity = getActivity(); + if (activity != null) { + PowerManager pm = activity.getSystemService(PowerManager.class); + mVisualizerView.setPowerSaveMode(pm.isPowerSaveMode()); + } } public void setVisualizerColor(int color) { @@ -506,27 +537,24 @@ public class AudioPlayerFragment extends Fragment implements ServiceConnection { */ private static final class TimeHandler extends Handler { - private final WeakReference mAudioPlayer; + private WeakReference mAudioPlayer; - /** - * Constructor of TimeHandler - */ - TimeHandler(final AudioPlayerFragment player) { + public TimeHandler(@NonNull Looper looper) { + super(looper); + } + + public void setFragment(final AudioPlayerFragment player) { mAudioPlayer = new WeakReference<>(player); } @Override public void handleMessage(final Message msg) { - switch (msg.what) { - case REFRESH_TIME: - final long next = mAudioPlayer.get().refreshCurrentTime(); - mAudioPlayer.get().queueNextRefresh(next); - break; - default: - break; + if (msg.what == REFRESH_TIME) { + final long next = mAudioPlayer.get().refreshCurrentTime(); + mAudioPlayer.get().queueNextRefresh(next); } } - }; + } /** * Used to monitor the state of playback @@ -550,39 +578,33 @@ public class AudioPlayerFragment extends Fragment implements ServiceConnection { } final AudioPlayerFragment audioPlayerFragment = mReference.get(); - switch (action) { - case MusicPlaybackService.META_CHANGED: - // if we are repeating current and the track has changed, re-create the adapter - if (MusicUtils.getRepeatMode() == MusicPlaybackService.REPEAT_CURRENT) { - mReference.get().createAndSetAdapter(); - } - - // Current info - audioPlayerFragment.updateNowPlayingInfo(); - break; - case MusicPlaybackService.PLAYSTATE_CHANGED: - audioPlayerFragment.mMainPlaybackControls.updatePlayPauseState(); - audioPlayerFragment.mVisualizerView.setPlaying(MusicUtils.isPlaying()); - break; - case MusicPlaybackService.REPEATMODE_CHANGED: - case MusicPlaybackService.SHUFFLEMODE_CHANGED: - // Set the repeat image - audioPlayerFragment.mMainPlaybackControls.updateRepeatState(); - // Set the shuffle image - audioPlayerFragment.mMainPlaybackControls.updateShuffleState(); - - // Update the queue - audioPlayerFragment.createAndSetAdapter(); - break; - case MusicPlaybackService.QUEUE_CHANGED: - audioPlayerFragment.createAndSetAdapter(); - break; - case MusicPlaybackService.NEW_LYRICS: - audioPlayerFragment.onLyrics(intent.getStringExtra("lyrics")); - break; - case PowerManager.ACTION_POWER_SAVE_MODE_CHANGED: - audioPlayerFragment.updateVisualizerPowerSaveMode(); - break; + if (MusicPlaybackService.META_CHANGED.equals(action)) { + // if we are repeating current and the track has changed, re-create the adapter + if (MusicUtils.getRepeatMode() == MusicPlaybackService.REPEAT_CURRENT) { + mReference.get().createAndSetAdapter(); + } + + // Current info + audioPlayerFragment.updateNowPlayingInfo(); + } else if (MusicPlaybackService.PLAYSTATE_CHANGED.equals(action)) { + audioPlayerFragment.mMainPlaybackControls.updatePlayPauseState(); + audioPlayerFragment.mVisualizerView.setPlaying(MusicUtils.isPlaying()); + } else if (MusicPlaybackService.REPEATMODE_CHANGED.equals(action) || + MusicPlaybackService.SHUFFLEMODE_CHANGED.equals(action)) { + // Set the repeat image + audioPlayerFragment.mMainPlaybackControls.updateRepeatState(); + // Set the shuffle image + audioPlayerFragment.mMainPlaybackControls.updateShuffleState(); + + // Update the queue + audioPlayerFragment.createAndSetAdapter(); + } else if (MusicPlaybackService.QUEUE_CHANGED.equals(action) + || MusicPlaybackService.QUEUE_MOVED.equals(action)) { + audioPlayerFragment.createAndSetAdapter(); + } else if (MusicPlaybackService.NEW_LYRICS.equals(action)) { + audioPlayerFragment.onLyrics(intent.getStringExtra("lyrics")); + } else if (PowerManager.ACTION_POWER_SAVE_MODE_CHANGED.equals(action)) { + audioPlayerFragment.updateVisualizerPowerSaveMode(); } } } diff --git a/src/org/lineageos/eleven/ui/fragments/BaseFragment.java b/src/org/lineageos/eleven/ui/fragments/BaseFragment.java index 6fa37aeeaf0d748846c1c8d54c4ad8cd16c18d1a..705bc45858e257788ce4ca9b04f6367709dccc21 100644 --- a/src/org/lineageos/eleven/ui/fragments/BaseFragment.java +++ b/src/org/lineageos/eleven/ui/fragments/BaseFragment.java @@ -1,38 +1,41 @@ /* -* Copyright (C) 2014 The CyanogenMod Project -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ + * Copyright (C) 2014 The CyanogenMod Project + * Copyright (C) 2021 The LineageOS Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package org.lineageos.eleven.ui.fragments; +import android.content.Context; import android.os.Bundle; import android.view.LayoutInflater; -import android.view.MotionEvent; import android.view.View; import android.view.ViewGroup; +import androidx.core.content.ContextCompat; import androidx.fragment.app.Fragment; import org.lineageos.eleven.MusicStateListener; import org.lineageos.eleven.R; import org.lineageos.eleven.ui.activities.HomeActivity; -public abstract class BaseFragment extends Fragment implements MusicStateListener, - ISetupActionBar { +public abstract class BaseFragment extends Fragment + implements MusicStateListener, ISetupActionBar { protected ViewGroup mRootView; protected abstract String getTitle(); + protected abstract int getLayoutToInflate(); protected boolean needsElevatedActionBar() { @@ -47,10 +50,11 @@ public abstract class BaseFragment extends Fragment implements MusicStateListene @Override public void setupActionBar() { - getContainingActivity().setupActionBar(getTitle()); - getContainingActivity().setActionBarAlpha(255); - getContainingActivity().setFragmentPadding(true); - getContainingActivity().setActionBarElevation(needsElevatedActionBar()); + final HomeActivity activity = getContainingActivity(); + activity.setupActionBar(getTitle()); + activity.setActionBarAlpha(255); + activity.setFragmentPadding(true); + activity.setActionBarElevation(needsElevatedActionBar()); } protected HomeActivity getContainingActivity() { @@ -58,17 +62,19 @@ public abstract class BaseFragment extends Fragment implements MusicStateListene } @Override - public final View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + public final View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { // The View for the fragment's UI mRootView = (ViewGroup) inflater.inflate(getLayoutToInflate(), null); // set the background color - mRootView.setBackgroundColor(getResources().getColor(R.color.background_color)); + final Context context = getContext(); + if (context != null) { + mRootView.setBackgroundColor(ContextCompat.getColor(context, + R.color.background_color)); + } // eat any touches that fall through to the root so they aren't // passed on to fragments "behind" the current one. - mRootView.setOnTouchListener(new View.OnTouchListener() { - @Override - public boolean onTouch(View v, MotionEvent me) { return true; } - }); + mRootView.setOnTouchListener((v, me) -> true); setupActionBar(); onViewCreated(); @@ -83,17 +89,14 @@ public abstract class BaseFragment extends Fragment implements MusicStateListene @Override public void onDestroyView() { super.onDestroyView(); - getContainingActivity().removeMusicStateListenerListener(this); } @Override public void onMetaChanged() { - } @Override public void onPlaylistChanged() { - } } diff --git a/src/org/lineageos/eleven/ui/fragments/DetailFragment.java b/src/org/lineageos/eleven/ui/fragments/DetailFragment.java index 208e8a78079a02cf9cb2cb4f3c7c46911ddb37c0..f7300fe8870e539a4919185ce00b1eeceeee10d9 100644 --- a/src/org/lineageos/eleven/ui/fragments/DetailFragment.java +++ b/src/org/lineageos/eleven/ui/fragments/DetailFragment.java @@ -1,36 +1,47 @@ /* -* Copyright (C) 2014 The CyanogenMod Project -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ + * Copyright (C) 2014 The CyanogenMod Project + * Copyright (C) 2021 The LineageOS Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package org.lineageos.eleven.ui.fragments; import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; +import androidx.annotation.NonNull; + import org.lineageos.eleven.R; import org.lineageos.eleven.utils.PopupMenuHelper; public abstract class DetailFragment extends BaseFragment { protected PopupMenuHelper mActionMenuHelper; - /** create the popup menu helper used by the type of item - * for which this is a detail screen */ + /** + * create the popup menu helper used by the type of item + * for which this is a detail screen + */ protected abstract PopupMenuHelper createActionMenuHelper(); - /** menu title for the shuffle option for this screen */ + + /** + * menu title for the shuffle option for this screen + */ protected abstract int getShuffleTitleId(); - /** action to take if the shuffle menu is selected */ + + /** + * action to take if the shuffle menu is selected + */ protected abstract void playShuffled(); @Override @@ -40,7 +51,7 @@ public abstract class DetailFragment extends BaseFragment { } @Override - public void onCreateOptionsMenu(final Menu menu, final MenuInflater inflater) { + public void onCreateOptionsMenu(@NonNull final Menu menu, final MenuInflater inflater) { inflater.inflate(R.menu.shuffle_item, menu); menu.findItem(R.id.menu_shuffle_item).setTitle(getShuffleTitleId()); @@ -55,15 +66,17 @@ public abstract class DetailFragment extends BaseFragment { @Override public boolean onOptionsItemSelected(final MenuItem item) { - if(item.getItemId() == R.id.menu_shuffle_item) { + if (item.getItemId() == R.id.menu_shuffle_item) { playShuffled(); return true; } // delegate to the popup menu that represents the item // for which this is a detail screen - if(mActionMenuHelper.onMenuItemClick(item)) { return true; } + if (mActionMenuHelper.onMenuItemClick(item)) { + return true; + } return super.onOptionsItemSelected(item); } -} \ No newline at end of file +} diff --git a/src/org/lineageos/eleven/ui/fragments/FadingBarFragment.java b/src/org/lineageos/eleven/ui/fragments/FadingBarFragment.java deleted file mode 100644 index 89d5d3c504aea8efb69c4af04b51cb1c43200a86..0000000000000000000000000000000000000000 --- a/src/org/lineageos/eleven/ui/fragments/FadingBarFragment.java +++ /dev/null @@ -1,72 +0,0 @@ -/* -* Copyright (C) 2014 The CyanogenMod Project -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ -package org.lineageos.eleven.ui.fragments; - -import android.view.View; -import android.widget.AbsListView; -import android.widget.AbsListView.OnScrollListener; - -import org.lineageos.eleven.ui.activities.HomeActivity; - -public abstract class FadingBarFragment extends DetailFragment implements OnScrollListener { - protected static final int ACTION_BAR_DEFAULT_OPACITY = 100; - - @Override - public void setupActionBar() { - super.setupActionBar(); - - getContainingActivity().setActionBarAlpha(ACTION_BAR_DEFAULT_OPACITY); - getContainingActivity().setFragmentPadding(false); - } - - protected abstract int getHeaderHeight(); - - protected abstract void setHeaderPosition(float y); - - @Override // OnScrollListener - public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) { - View firstChild = view.getChildAt(0); - if (firstChild == null) { - return; - } - - float firstChildY = firstChild.getY(); - - int alpha = 255; - if (firstVisibleItem == 0) { - // move header to current top of list - setHeaderPosition(firstChildY); - // calculate alpha for the action bar - alpha = ACTION_BAR_DEFAULT_OPACITY + - (int)((255 - ACTION_BAR_DEFAULT_OPACITY) * -firstChildY / - (float)(firstChild.getHeight())); - if(alpha > 255) { alpha = 255; } - } else { - // header off screen - setHeaderPosition(-getHeaderHeight()); - } - - HomeActivity home = getContainingActivity(); - if (home != null && home.getTopFragment() == this) { - home.setActionBarAlpha(alpha); - } - } - - @Override // OnScrollListener - public void onScrollStateChanged(AbsListView view, int scrollState) { - - } -} diff --git a/src/org/lineageos/eleven/ui/fragments/IChildFragment.java b/src/org/lineageos/eleven/ui/fragments/IChildFragment.java index aec7aa85e91e8760cd5f0ec00e71fb859b85cab5..125c0650a1ecb1122f6f86c836a9895442f0e134 100644 --- a/src/org/lineageos/eleven/ui/fragments/IChildFragment.java +++ b/src/org/lineageos/eleven/ui/fragments/IChildFragment.java @@ -1,18 +1,19 @@ /* -* Copyright (C) 2014 The CyanogenMod Project -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ + * Copyright (C) 2014 The CyanogenMod Project + * Copyright (C) 2021 The LineageOS Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package org.lineageos.eleven.ui.fragments; import org.lineageos.eleven.adapters.PagerAdapter; diff --git a/src/org/lineageos/eleven/ui/fragments/ISetupActionBar.java b/src/org/lineageos/eleven/ui/fragments/ISetupActionBar.java index eb80656e1fe8c0d36374be87b0010d2d7fb00773..dfb7c5dbe768d50b5078702a19552aa4445bbde5 100644 --- a/src/org/lineageos/eleven/ui/fragments/ISetupActionBar.java +++ b/src/org/lineageos/eleven/ui/fragments/ISetupActionBar.java @@ -1,20 +1,21 @@ /* -* Copyright (C) 2014 The CyanogenMod Project -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ + * Copyright (C) 2014 The CyanogenMod Project + * Copyright (C) 2021 The LineageOS Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package org.lineageos.eleven.ui.fragments; public interface ISetupActionBar { - public void setupActionBar(); + void setupActionBar(); } diff --git a/src/org/lineageos/eleven/ui/fragments/PlaylistDetailFragment.java b/src/org/lineageos/eleven/ui/fragments/PlaylistDetailFragment.java index 832e1dd6086a4638cdba5f66b17453903ddabe46..0705d09d83c191e1fa353c359a58e8e48b99d7a4 100644 --- a/src/org/lineageos/eleven/ui/fragments/PlaylistDetailFragment.java +++ b/src/org/lineageos/eleven/ui/fragments/PlaylistDetailFragment.java @@ -1,54 +1,55 @@ /* -* Copyright (C) 2014 The CyanogenMod Project -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ + * Copyright (C) 2014 The CyanogenMod Project + * Copyright (C) 2021 The LineageOS Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package org.lineageos.eleven.ui.fragments; import android.database.Cursor; import android.net.Uri; import android.os.Bundle; +import android.os.Handler; import android.provider.MediaStore; import android.view.View; -import android.widget.AbsListView; -import android.widget.AdapterView; -import android.widget.AdapterView.OnItemClickListener; import android.widget.ImageView; import android.widget.TextView; +import androidx.annotation.NonNull; +import androidx.fragment.app.FragmentActivity; import androidx.loader.app.LoaderManager; import androidx.loader.content.Loader; +import androidx.recyclerview.widget.DefaultItemAnimator; +import androidx.recyclerview.widget.ItemTouchHelper; +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; import org.lineageos.eleven.Config; import org.lineageos.eleven.R; import org.lineageos.eleven.adapters.PagerAdapter; import org.lineageos.eleven.adapters.ProfileSongAdapter; import org.lineageos.eleven.cache.ImageFetcher; -import org.lineageos.eleven.dragdrop.DragSortListView; -import org.lineageos.eleven.dragdrop.DragSortListView.DragScrollProfile; -import org.lineageos.eleven.dragdrop.DragSortListView.DropListener; -import org.lineageos.eleven.dragdrop.DragSortListView.RemoveListener; import org.lineageos.eleven.loaders.PlaylistSongLoader; import org.lineageos.eleven.menu.FragmentMenuItems; import org.lineageos.eleven.model.Playlist; import org.lineageos.eleven.model.Song; -import org.lineageos.eleven.recycler.RecycleHolder; import org.lineageos.eleven.utils.MusicUtils; import org.lineageos.eleven.utils.PlaylistPopupMenuHelper; import org.lineageos.eleven.utils.PopupMenuHelper; import org.lineageos.eleven.utils.PopupMenuHelper.PopupMenuType; import org.lineageos.eleven.utils.SongPopupMenuHelper; -import org.lineageos.eleven.widgets.IPopupMenuCallback; +import org.lineageos.eleven.widgets.DragSortItemTouchHelperCallback; +import org.lineageos.eleven.widgets.DragSortListener; import org.lineageos.eleven.widgets.LoadingEmptyContainer; import org.lineageos.eleven.widgets.NoResultsContainer; @@ -56,19 +57,17 @@ import java.util.List; import java.util.TreeSet; public class PlaylistDetailFragment extends DetailFragment implements - LoaderManager.LoaderCallbacks>, OnItemClickListener, DropListener, - RemoveListener, DragScrollProfile, IChildFragment, AbsListView.OnScrollListener { + LoaderManager.LoaderCallbacks>, + IChildFragment, DragSortListener { /** * LoaderCallbacks identifier */ private static final int LOADER = 0; - private DragSortListView mListView; private ProfileSongAdapter mAdapter; private View mHeaderContainer; - private ImageView mPlaylistImageView; private LoadingEmptyContainer mLoadingEmptyContainer; @@ -81,13 +80,20 @@ public class PlaylistDetailFragment extends DetailFragment implements private long mPlaylistId; private String mPlaylistName; + /** + * Drag sort item helper. + */ + private ItemTouchHelper mDragSortHelper; + /** * Pop up menu helper */ private PopupMenuHelper mPopupMenuHelper; @Override - protected String getTitle() { return mPlaylistName; } + protected String getTitle() { + return mPlaylistName; + } @Override protected int getLayoutToInflate() { @@ -97,6 +103,7 @@ public class PlaylistDetailFragment extends DetailFragment implements @Override protected void onViewCreated() { super.onViewCreated(); + LoaderManager.getInstance(this).initLoader(0, getArguments(), this); setupHero(); setupSongList(); } @@ -105,7 +112,7 @@ public class PlaylistDetailFragment extends DetailFragment implements mPlaylistName = MusicUtils.getNameForPlaylist(getActivity(), mPlaylistId); } - @Override // DetailFragment + @Override protected PopupMenuHelper createActionMenuHelper() { return new PlaylistPopupMenuHelper( getActivity(), getChildFragmentManager(), PopupMenuType.Playlist) { @@ -115,33 +122,23 @@ public class PlaylistDetailFragment extends DetailFragment implements }; } - @Override // DetailFragment - protected int getShuffleTitleId() { return R.string.menu_shuffle_playlist; } - - @Override // DetailFragment - protected void playShuffled() { - MusicUtils.playPlaylist(getActivity(), mPlaylistId, true); + @Override + protected int getShuffleTitleId() { + return R.string.menu_shuffle_playlist; } @Override - public void onActivityCreated(Bundle savedInstanceState) { - super.onActivityCreated(savedInstanceState); - - LoaderManager lm = getLoaderManager(); - lm.initLoader(0, getArguments(), this); + protected void playShuffled() { + MusicUtils.playPlaylist(getActivity(), mPlaylistId, true); } @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - mPopupMenuHelper = new SongPopupMenuHelper(getActivity(), getFragmentManager()) { + mPopupMenuHelper = new SongPopupMenuHelper(getActivity(), getChildFragmentManager()) { @Override public Song getSong(int position) { - if (position == 0) { - return null; - } - return mAdapter.getItem(position); } @@ -165,65 +162,57 @@ public class PlaylistDetailFragment extends DetailFragment implements @Override protected void removeFromPlaylist() { - mAdapter.remove(mSong); - mAdapter.buildCache(); - mAdapter.notifyDataSetChanged(); - MusicUtils.removeFromPlaylist(getActivity(), mSong.mSongId, mPlaylistId); - getLoaderManager().restartLoader(LOADER, null, PlaylistDetailFragment.this); + remove(mSong); + final FragmentActivity activity = getActivity(); + if (activity != null) { + MusicUtils.removeFromPlaylist(activity, mSong.mSongId, mPlaylistId); + } + LoaderManager.getInstance(PlaylistDetailFragment.this) + .restartLoader(LOADER, null, PlaylistDetailFragment.this); } }; - mPlaylistId = getArguments().getLong(Config.ID); + final Bundle args = getArguments(); + mPlaylistId = args == null ? -1 : args.getLong(Config.ID); lookupName(); + + mAdapter = new ProfileSongAdapter( + mPlaylistId, + getActivity(), + R.layout.edit_track_list_item, + this::onItemClick + ); + mAdapter.setPopupMenuClickedListener((v, position) -> + mPopupMenuHelper.showPopupMenu(v, position)); + mDragSortHelper = new ItemTouchHelper(new DragSortItemTouchHelperCallback(this)); } private void setupHero() { - mPlaylistImageView = (ImageView)mRootView.findViewById(R.id.image); + final ImageView playlistImageView = mRootView.findViewById(R.id.image); mHeaderContainer = mRootView.findViewById(R.id.playlist_header); - mNumberOfSongs = (TextView)mRootView.findViewById(R.id.number_of_songs_text); - mDurationOfPlaylist = (TextView)mRootView.findViewById(R.id.duration_text); + mNumberOfSongs = mRootView.findViewById(R.id.number_of_songs_text); + mDurationOfPlaylist = mRootView.findViewById(R.id.duration_text); final ImageFetcher imageFetcher = ImageFetcher.getInstance(getActivity()); - imageFetcher.loadPlaylistArtistImage(mPlaylistId, mPlaylistImageView); + imageFetcher.loadPlaylistArtistImage(mPlaylistId, playlistImageView); } private void setupSongList() { - mListView = (DragSortListView) mRootView.findViewById(R.id.list_base); - mListView.setOnScrollListener(PlaylistDetailFragment.this); + final RecyclerView listView = mRootView.findViewById(R.id.list_base); - mAdapter = new ProfileSongAdapter( - mPlaylistId, - getActivity(), - R.layout.edit_track_list_item, - R.layout.faux_playlist_header - ); - mAdapter.setPopupMenuClickedListener(new IPopupMenuCallback.IListener() { - @Override - public void onPopupMenuClicked(View v, int position) { - mPopupMenuHelper.showPopupMenu(v, position); - } - }); - mListView.setAdapter(mAdapter); - // Release any references to the recycled Views - mListView.setRecyclerListener(new RecycleHolder()); - // Play the selected song - mListView.setOnItemClickListener(this); - // Set the drop listener - mListView.setDropListener(this); - // Set the swipe to remove listener - mListView.setRemoveListener(this); - // Quick scroll while dragging - mListView.setDragScrollProfile(this); + listView.setAdapter(mAdapter); + listView.setLayoutManager(new LinearLayoutManager(requireActivity())); + listView.setItemAnimator(new DefaultItemAnimator()); + mDragSortHelper.attachToRecyclerView(listView); // Adjust the progress bar padding to account for the header int padTop = getResources().getDimensionPixelSize(R.dimen.playlist_detail_header_height); mRootView.findViewById(R.id.progressbar).setPadding(0, padTop, 0, 0); // set the loading and empty view container - mLoadingEmptyContainer = - (LoadingEmptyContainer)mRootView.findViewById(R.id.loading_empty_container); + mLoadingEmptyContainer = mRootView.findViewById(R.id.loading_empty_container); setupNoResultsContainer(mLoadingEmptyContainer.getNoResultsContainer()); - mListView.setEmptyView(mLoadingEmptyContainer); + mLoadingEmptyContainer.setVisibility(View.VISIBLE); } private void setupNoResultsContainer(final NoResultsContainer container) { @@ -231,147 +220,84 @@ public class PlaylistDetailFragment extends DetailFragment implements container.setSecondaryText(R.string.empty_playlist_secondary); } - /** - * {@inheritDoc} - */ - @Override - public float getSpeed(final float w, final long t) { - if (w > 0.8f) { - return mAdapter.getCount() / 0.001f; - } else { - return 10.0f * w; - } - } - - /** - * {@inheritDoc} - */ - @Override - public void remove(final int which) { - if (which == 0) { - return; - } - - Song song = mAdapter.getItem(which); - mAdapter.remove(song); - mAdapter.buildCache(); - mAdapter.notifyDataSetChanged(); - final Uri uri = MediaStore.Audio.Playlists.Members.getContentUri("external", mPlaylistId); - getActivity().getContentResolver().delete(uri, - MediaStore.Audio.Playlists.Members.AUDIO_ID + "=" + song.mSongId, - null); + private void remove(Song song) { + Handler handler = new Handler(requireActivity().getMainLooper()); + handler.post(() -> { + mAdapter.remove(song); + + final Uri uri = MediaStore.Audio.Playlists.Members.getContentUri("external", + mPlaylistId); + final FragmentActivity activity = getActivity(); + if (activity != null) { + activity.getContentResolver().delete(uri, + MediaStore.Audio.Playlists.Members.AUDIO_ID + "=" + song.mSongId, + null); + } - MusicUtils.refresh(); + MusicUtils.refresh(); + }); } - /** - * {@inheritDoc} - */ - @Override - public void drop(int from, int to) { - from = Math.max(ProfileSongAdapter.NUM_HEADERS, from); - to = Math.max(ProfileSongAdapter.NUM_HEADERS, to); - - Song song = mAdapter.getItem(from); - mAdapter.remove(song); - mAdapter.insert(song, to); - mAdapter.buildCache(); - mAdapter.notifyDataSetChanged(); - - final int realFrom = from - ProfileSongAdapter.NUM_HEADERS; - final int realTo = to - ProfileSongAdapter.NUM_HEADERS; - MediaStore.Audio.Playlists.Members.moveItem(getActivity().getContentResolver(), - mPlaylistId, realFrom, realTo); - } - /** - * {@inheritDoc} - */ - @Override - public void onItemClick(final AdapterView parent, final View view, final int position, - final long id) { - if (position == 0) { + public void onItemClick(final int position) { + final FragmentActivity activity = getActivity(); + if (position == 0 || activity == null) { return; } + Cursor cursor = PlaylistSongLoader.makePlaylistSongCursor(getActivity(), mPlaylistId); final long[] list = MusicUtils.getSongListForCursor(cursor); - MusicUtils.playAll(getActivity(), list, position - ProfileSongAdapter.NUM_HEADERS, - mPlaylistId, Config.IdType.Playlist, false); + MusicUtils.playAll(list, position, mPlaylistId, Config.IdType.Playlist, false); cursor.close(); - cursor = null; - } - - @Override - public void onScrollStateChanged(AbsListView view, int scrollState) { - if (scrollState == AbsListView.OnScrollListener.SCROLL_STATE_FLING) { - mAdapter.setPauseDiskCache(true); - } else { - mAdapter.setPauseDiskCache(false); - mAdapter.notifyDataSetChanged(); - } } - @Override - public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) { - View firstChild = view.getChildAt(0); - if (firstChild == null) { - return; - } - - float firstChildY = firstChild.getY(); - - if (firstVisibleItem == 0) { - // move header to current top of list - setHeaderPosition(firstChildY); - } else { - // header off screen - setHeaderPosition(-getHeaderHeight()); - } - } - - protected int getHeaderHeight() { return mHeaderContainer.getHeight(); } - - protected void setHeaderPosition(float y) { - // Offset the header height to account for the faux header - y = y - getResources().getDimension(R.dimen.header_bar_height); - mHeaderContainer.setY(y); - } + @NonNull @Override public Loader> onCreateLoader(int i, Bundle bundle) { - mLoadingEmptyContainer.showLoading(); + if (mLoadingEmptyContainer != null) { + mLoadingEmptyContainer.showLoading(); + } return new PlaylistSongLoader(getActivity(), mPlaylistId); } @Override - public void onLoadFinished(final Loader> loader, final List data) { + public void onLoadFinished(@NonNull final Loader> loader, final List data) { + Handler handler = new Handler(requireActivity().getMainLooper()); if (data.isEmpty()) { mLoadingEmptyContainer.showNoResults(); + // need to call this after showNoResults, otherwise removing any would + // clear the whole list (not only visibly but it's gone even when re-entering the + // playlist) + mLoadingEmptyContainer.setVisibility(View.VISIBLE); // hide the header container mHeaderContainer.setVisibility(View.INVISIBLE); // Start fresh - mAdapter.unload(); + handler.post(() -> mAdapter.unload()); } else { + mLoadingEmptyContainer.setVisibility(View.GONE); // show the header container mHeaderContainer.setVisibility(View.VISIBLE); // pause notifying the adapter and make changes before re-enabling it so that the list // view doesn't reset to the top of the list - mAdapter.setNotifyOnChange(false); - // Start fresh - mAdapter.unload(); - // Return the correct count - mAdapter.addAll(data); - // build the cache - mAdapter.buildCache(); - // re-enable the notify by calling notify dataset changes - mAdapter.notifyDataSetChanged(); + handler.post(() -> { + // Start fresh + mAdapter.unload(); + // Return the correct count + mAdapter.setData(data); + }); + // set the number of songs - String numberOfSongs = MusicUtils.makeLabel(getActivity(), R.plurals.Nsongs, + final FragmentActivity activity = getActivity(); + if (activity == null) { + return; + } + String numberOfSongs = MusicUtils.makeLabel(activity, R.plurals.Nsongs, data.size()); mNumberOfSongs.setText(numberOfSongs); @@ -389,15 +315,16 @@ public class PlaylistDetailFragment extends DetailFragment implements } @Override - public void onLoaderReset(final Loader> loader) { + public void onLoaderReset(@NonNull final Loader> loader) { // Clear the data in the adapter - mAdapter.unload(); + Handler handler = new Handler(requireActivity().getMainLooper()); + handler.post(() -> mAdapter.unload()); } @Override public void restartLoader() { lookupName(); // playlist name may have changed - if(mPlaylistName == null) { + if (mPlaylistName == null) { // if name is null, we've been deleted, so close the this fragment getContainingActivity().postRemoveFragment(this); return; @@ -413,7 +340,7 @@ public class PlaylistDetailFragment extends DetailFragment implements getContainingActivity().setActionBarTitle(mPlaylistName); // and reload the song list - getLoaderManager().restartLoader(0, getArguments(), this); + LoaderManager.getInstance(this).restartLoader(0, getArguments(), this); } @Override @@ -434,4 +361,16 @@ public class PlaylistDetailFragment extends DetailFragment implements public PagerAdapter.MusicFragments getMusicFragmentParent() { return PagerAdapter.MusicFragments.PLAYLIST; } + + @Override + public void onItemMove(int startPosition, int endPosition) { + Handler handler = new Handler(requireActivity().getMainLooper()); + handler.post(() -> mAdapter.move(startPosition, endPosition)); + + final FragmentActivity activity = getActivity(); + if (activity != null) { + MediaStore.Audio.Playlists.Members.moveItem(activity.getContentResolver(), + mPlaylistId, startPosition, endPosition); + } + } } diff --git a/src/org/lineageos/eleven/ui/fragments/PlaylistFragment.java b/src/org/lineageos/eleven/ui/fragments/PlaylistFragment.java index 0d29bf61ea9c84d876aa3246e5e0b3367831b362..efa751750215895a7b4a196dd5c15c78825922ad 100644 --- a/src/org/lineageos/eleven/ui/fragments/PlaylistFragment.java +++ b/src/org/lineageos/eleven/ui/fragments/PlaylistFragment.java @@ -1,7 +1,7 @@ /* * Copyright (C) 2012 Andrew Neal * Copyright (C) 2014 The CyanogenMod Project - * Copyright (C) 2019 The LineageOS Project + * Copyright (C) 2019-2021 The LineageOS Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -15,21 +15,22 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package org.lineageos.eleven.ui.fragments; import android.os.Bundle; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; -import android.widget.AdapterView; -import android.widget.AdapterView.OnItemClickListener; -import android.widget.ListView; import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import androidx.fragment.app.Fragment; +import androidx.fragment.app.FragmentActivity; import androidx.loader.app.LoaderManager; import androidx.loader.content.Loader; +import androidx.recyclerview.widget.DefaultItemAnimator; +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; import org.lineageos.eleven.Config.SmartPlaylistType; import org.lineageos.eleven.MusicStateListener; @@ -38,16 +39,13 @@ import org.lineageos.eleven.adapters.PagerAdapter; import org.lineageos.eleven.adapters.PlaylistAdapter; import org.lineageos.eleven.loaders.PlaylistLoader; import org.lineageos.eleven.model.Playlist; -import org.lineageos.eleven.recycler.RecycleHolder; import org.lineageos.eleven.ui.activities.BaseActivity; import org.lineageos.eleven.ui.fragments.phone.MusicBrowserFragment; import org.lineageos.eleven.utils.NavUtils; import org.lineageos.eleven.utils.PlaylistPopupMenuHelper; import org.lineageos.eleven.utils.PopupMenuHelper; -import org.lineageos.eleven.widgets.IPopupMenuCallback; import org.lineageos.eleven.widgets.LoadingEmptyContainer; -import java.util.Collections; import java.util.Iterator; import java.util.List; @@ -57,19 +55,13 @@ import java.util.List; * @author Andrew Neal (andrewdneal@gmail.com) */ public class PlaylistFragment extends MusicBrowserFragment implements - LoaderManager.LoaderCallbacks>, - OnItemClickListener, MusicStateListener { + LoaderManager.LoaderCallbacks>, MusicStateListener { /** * The adapter for the list */ private PlaylistAdapter mAdapter; - /** - * The list view - */ - private ListView mListView; - /** * Pop up menu helper */ @@ -95,7 +87,8 @@ public class PlaylistFragment extends MusicBrowserFragment implements @Override public void onCreate(final Bundle savedInstanceState) { super.onCreate(savedInstanceState); - mPopupMenuHelper = new PlaylistPopupMenuHelper(getActivity(), getFragmentManager(), null) { + mPopupMenuHelper = new PlaylistPopupMenuHelper(getActivity(), getChildFragmentManager(), + null) { @Override public Playlist getPlaylist(int position) { return mAdapter.getItem(position); @@ -103,29 +96,33 @@ public class PlaylistFragment extends MusicBrowserFragment implements }; // Create the adapter - mAdapter = new PlaylistAdapter(getActivity()); - mAdapter.setPopupMenuClickedListener((v, position) -> mPopupMenuHelper.showPopupMenu(v, position)); + mAdapter = new PlaylistAdapter(requireActivity(), this::onItemClick); + mAdapter.setPopupMenuClickedListener((v, position) -> + mPopupMenuHelper.showPopupMenu(v, position)); } @Override public View onCreateView(@NonNull final LayoutInflater inflater, final ViewGroup container, final Bundle savedInstanceState) { // The View for the fragment's UI - final ViewGroup rootView = (ViewGroup) inflater.inflate(R.layout.list_base, container, false); + final ViewGroup rootView = (ViewGroup) inflater.inflate(R.layout.fragment_list, + container, false); // Initialize the list - mListView = rootView.findViewById(R.id.list_base); - // Set the data behind the grid - mListView.setAdapter(mAdapter); - // Release any references to the recycled Views - mListView.setRecyclerListener(new RecycleHolder()); - // Play the selected song - mListView.setOnItemClickListener(this); + // The list view + RecyclerView listView = rootView.findViewById(R.id.list_base); + listView.setLayoutManager(new LinearLayoutManager(requireActivity())); + listView.setItemAnimator(new DefaultItemAnimator()); + listView.setAdapter(mAdapter); + // Setup the loading and empty state mLoadingEmptyContainer = rootView.findViewById(R.id.loading_empty_container); - mListView.setEmptyView(mLoadingEmptyContainer); + mLoadingEmptyContainer.setVisibility(View.VISIBLE); // Register the music status listener - ((BaseActivity)getActivity()).setMusicStateListenerListener(this); + final FragmentActivity activity = getActivity(); + if (activity instanceof BaseActivity) { + ((BaseActivity) activity).setMusicStateListenerListener(this); + } return rootView; } @@ -134,21 +131,22 @@ public class PlaylistFragment extends MusicBrowserFragment implements public void onDestroyView() { super.onDestroyView(); - ((BaseActivity)getActivity()).removeMusicStateListenerListener(this); + final FragmentActivity activity = getActivity(); + if (activity instanceof BaseActivity) { + ((BaseActivity) activity).removeMusicStateListenerListener(this); + } } @Override - public void onActivityCreated(final Bundle savedInstanceState) { - super.onActivityCreated(savedInstanceState); + public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); // Enable the options menu setHasOptionsMenu(true); // Start the loader - initLoader(null, this); + initLoader(this); } - @Override - public void onItemClick(final AdapterView parent, final View view, final int position, - final long id) { + private void onItemClick(int position) { Playlist playlist = mAdapter.getItem(position); SmartPlaylistType playlistType = SmartPlaylistType.getTypeById(playlist.mPlaylistId); @@ -168,12 +166,15 @@ public class PlaylistFragment extends MusicBrowserFragment implements } @Override - public void onLoadFinished(@NonNull final Loader> loader, final List data) { + public void onLoadFinished(@NonNull final Loader> loader, + final List data) { if (data.isEmpty()) { mLoadingEmptyContainer.showNoResults(); return; } + mLoadingEmptyContainer.setVisibility(View.GONE); + // Start fresh, fill adapter with new data and create cache mAdapter.unload(); @@ -188,7 +189,7 @@ public class PlaylistFragment extends MusicBrowserFragment implements } // after the "smart playlists" are added, sort and add remaining playlists - Collections.sort(data, new Playlist.IgnoreCaseComparator()); + data.sort(new Playlist.IgnoreCaseComparator()); for (final Playlist playlist : data) { mAdapter.add(playlist); } @@ -204,7 +205,7 @@ public class PlaylistFragment extends MusicBrowserFragment implements @Override public void restartLoader() { - restartLoader(null, this); + restartLoader(this); } @Override diff --git a/src/org/lineageos/eleven/ui/fragments/QueueFragment.java b/src/org/lineageos/eleven/ui/fragments/QueueFragment.java index 3447d647ca6dfaf47488b529da99054b4616339f..1c2c9058c11868c0a7cf14a061df33ef8fe0badc 100644 --- a/src/org/lineageos/eleven/ui/fragments/QueueFragment.java +++ b/src/org/lineageos/eleven/ui/fragments/QueueFragment.java @@ -1,7 +1,7 @@ /* * Copyright (C) 2012 Andrew Neal * Copyright (C) 2014 The CyanogenMod Project - * Copyright (C) 2019 The LineageOS Project + * Copyright (C) 2019-2021 The LineageOS Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -15,9 +15,9 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package org.lineageos.eleven.ui.fragments; +import android.annotation.SuppressLint; import android.content.BroadcastReceiver; import android.content.ComponentName; import android.content.Context; @@ -25,6 +25,7 @@ import android.content.Intent; import android.content.IntentFilter; import android.content.ServiceConnection; import android.os.Bundle; +import android.os.Handler; import android.os.IBinder; import android.provider.MediaStore; import android.view.LayoutInflater; @@ -35,29 +36,31 @@ import android.widget.AdapterView.OnItemClickListener; import android.widget.FrameLayout; import androidx.core.content.ContextCompat; +import androidx.annotation.NonNull; import androidx.fragment.app.Fragment; +import androidx.fragment.app.FragmentActivity; import androidx.loader.app.LoaderManager; import androidx.loader.content.Loader; +import androidx.recyclerview.widget.DefaultItemAnimator; +import androidx.recyclerview.widget.ItemTouchHelper; +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; import org.lineageos.eleven.Config; import org.lineageos.eleven.MusicPlaybackService; import org.lineageos.eleven.R; -import org.lineageos.eleven.adapters.SongAdapter; -import org.lineageos.eleven.dragdrop.DragSortListView; -import org.lineageos.eleven.dragdrop.DragSortListView.DragScrollProfile; -import org.lineageos.eleven.dragdrop.DragSortListView.DropListener; -import org.lineageos.eleven.dragdrop.DragSortListView.RemoveListener; +import org.lineageos.eleven.adapters.QueueSongAdapter; import org.lineageos.eleven.loaders.NowPlayingCursor; import org.lineageos.eleven.loaders.QueueLoader; import org.lineageos.eleven.menu.DeleteDialog; import org.lineageos.eleven.menu.FragmentMenuItems; import org.lineageos.eleven.model.Song; -import org.lineageos.eleven.recycler.RecycleHolder; import org.lineageos.eleven.service.MusicPlaybackTrack; import org.lineageos.eleven.ui.activities.SlidingPanelActivity; import org.lineageos.eleven.utils.MusicUtils; import org.lineageos.eleven.utils.PopupMenuHelper; -import org.lineageos.eleven.widgets.IPopupMenuCallback; +import org.lineageos.eleven.widgets.DragSortItemTouchHelperCallback; +import org.lineageos.eleven.widgets.DragSortListener; import org.lineageos.eleven.widgets.LoadingEmptyContainer; import org.lineageos.eleven.widgets.NoResultsContainer; @@ -71,7 +74,7 @@ import java.util.TreeSet; * @author Andrew Neal (andrewdneal@gmail.com) */ public class QueueFragment extends Fragment implements LoaderManager.LoaderCallbacks>, - OnItemClickListener, DropListener, RemoveListener, DragScrollProfile, ServiceConnection { + ServiceConnection, DragSortListener { /** * LoaderCallbacks identifier @@ -91,28 +94,22 @@ public class QueueFragment extends Fragment implements LoaderManager.LoaderCallb /** * The adapter for the list */ - private SongAdapter mAdapter; + private QueueSongAdapter mAdapter; /** - * The list view + * Drag sort item helper. */ - private DragSortListView mListView; + private ItemTouchHelper mDragSortHelper; /** * Pop up menu helper */ private PopupMenuHelper mPopupMenuHelper; - /** - * Root view - */ - private ViewGroup mRootView; - /** * This holds the loading progress bar as well as the no results message */ private LoadingEmptyContainer mLoadingEmptyContainer; - private FrameLayout layout; /** * Empty constructor as per the {@link Fragment} documentation @@ -120,13 +117,10 @@ public class QueueFragment extends Fragment implements LoaderManager.LoaderCallb public QueueFragment() { } - /** - * {@inheritDoc} - */ @Override public void onCreate(final Bundle savedInstanceState) { super.onCreate(savedInstanceState); - mPopupMenuHelper = new PopupMenuHelper(getActivity(), getFragmentManager()) { + mPopupMenuHelper = new PopupMenuHelper(getActivity(), getChildFragmentManager()) { private Song mSong; private int mSelectedPosition; private MusicPlaybackTrack mSelectedTrack; @@ -142,7 +136,7 @@ public class QueueFragment extends Fragment implements LoaderManager.LoaderCallb @Override protected long[] getIdList() { - return new long[] { mSong.mSongId }; + return new long[]{mSong.mSongId}; } @Override @@ -170,17 +164,16 @@ public class QueueFragment extends Fragment implements LoaderManager.LoaderCallb @Override protected void onDeleteClicked() { - DeleteDialog.newInstance(mSong.mSongName, - new long[] { getId() }, null).show(getFragmentManager(), "DeleteDialog"); + DeleteDialog.newInstance(mSong.mSongName, new long[]{getId()}, null) + .show(getChildFragmentManager(), "DeleteDialog"); } @Override protected void playNext() { - NowPlayingCursor queue = (NowPlayingCursor)QueueLoader + NowPlayingCursor queue = (NowPlayingCursor) QueueLoader .makeQueueCursor(getActivity()); queue.removeItem(mSelectedPosition); queue.close(); - queue = null; MusicUtils.playNext(getIdList(), getSourceId(), getSourceType()); refreshQueue(); } @@ -188,6 +181,7 @@ public class QueueFragment extends Fragment implements LoaderManager.LoaderCallb @Override protected void removeFromQueue() { MusicUtils.removeTrackAtPosition(getId(), mSelectedPosition); + remove(mSelectedPosition); refreshQueue(); } @@ -203,65 +197,38 @@ public class QueueFragment extends Fragment implements LoaderManager.LoaderCallb }; // Create the adapter - mAdapter = new SongAdapter(getActivity(), R.layout.edit_queue_list_item, - -1, Config.IdType.NA); - mAdapter.setPopupMenuClickedListener(new IPopupMenuCallback.IListener() { - @Override - public void onPopupMenuClicked(View v, int position) { - mPopupMenuHelper.showPopupMenu(v, position); - } - }); + mAdapter = new QueueSongAdapter(requireActivity(), R.layout.edit_queue_list_item, + -1, Config.IdType.NA, this::onItemClick); + mAdapter.setPopupMenuClickedListener((v, position) -> + mPopupMenuHelper.showPopupMenu(v, position)); + mDragSortHelper = new ItemTouchHelper(new DragSortItemTouchHelperCallback(this)); + + // Initialize the broadcast receiver + mQueueUpdateListener = new QueueUpdateListener(this); } - /** - * {@inheritDoc} - */ + @SuppressLint("InflateParams") @Override public View onCreateView(final LayoutInflater inflater, final ViewGroup container, - final Bundle savedInstanceState) { + final Bundle savedInstanceState) { // The View for the fragment's UI - mRootView = (ViewGroup)inflater.inflate(R.layout.list_base, null); + ViewGroup rootView = (ViewGroup) inflater.inflate(R.layout.fragment_list, + container, false); // Initialize the list - mListView = (DragSortListView)mRootView.findViewById(R.id.list_base); + RecyclerView listView = rootView.findViewById(R.id.list_base); + listView.setLayoutManager(new LinearLayoutManager(requireActivity())); + listView.setItemAnimator(new DefaultItemAnimator()); // Set the data behind the list - mListView.setAdapter(mAdapter); - // Release any references to the recycled Views - mListView.setRecyclerListener(new RecycleHolder()); - // Play the selected song - mListView.setOnItemClickListener(this); - // Set the drop listener - mListView.setDropListener(this); - // Set the swipe to remove listener - mListView.setRemoveListener(this); - // Quick scroll while dragging - mListView.setDragScrollProfile(this); - // Enable fast scroll bars - mListView.setFastScrollEnabled(true); + listView.setAdapter(mAdapter); + mDragSortHelper.attachToRecyclerView(listView); // Setup the loading and empty state - mLoadingEmptyContainer = - (LoadingEmptyContainer)mRootView.findViewById(R.id.loading_empty_container); + mLoadingEmptyContainer = rootView.findViewById(R.id.loading_empty_container); // Setup the container strings setupNoResultsContainer(mLoadingEmptyContainer.getNoResultsContainer()); - mListView.setEmptyView(mLoadingEmptyContainer); - layout = (FrameLayout)mRootView.findViewById(R.id.list_base_container); - layout.setBackgroundColor(ContextCompat.getColor(getActivity(),R.color.primary)); - return mRootView; + mLoadingEmptyContainer.setVisibility(View.VISIBLE); + return rootView; } - /** - * {@inheritDoc} - */ - @Override - public void onActivityCreated(final Bundle savedInstanceState) { - super.onActivityCreated(savedInstanceState); - - // Initialize the broadcast receiver - mQueueUpdateListener = new QueueUpdateListener(this); - } - - /** - * {@inheritDoc} - */ @Override public void onServiceConnected(final ComponentName name, final IBinder service) { refreshQueue(); @@ -286,7 +253,10 @@ public class QueueFragment extends Fragment implements LoaderManager.LoaderCallb // Track changes filter.addAction(MusicPlaybackService.META_CHANGED); - getActivity().registerReceiver(mQueueUpdateListener, filter); + final FragmentActivity activity = getActivity(); + if (activity != null) { + activity.registerReceiver(mQueueUpdateListener, filter); + } } @Override @@ -294,7 +264,10 @@ public class QueueFragment extends Fragment implements LoaderManager.LoaderCallb super.onStop(); try { - getActivity().unregisterReceiver(mQueueUpdateListener); + final FragmentActivity activity = getActivity(); + if (activity != null) { + activity.unregisterReceiver(mQueueUpdateListener); + } } catch (final Throwable e) { //$FALL-THROUGH$ } @@ -303,99 +276,63 @@ public class QueueFragment extends Fragment implements LoaderManager.LoaderCallb mToken = null; } - /** - * {@inheritDoc} - */ - @Override - public void onItemClick(final AdapterView parent, final View view, final int position, - final long id) { + public void onItemClick(final int position) { // When selecting a track from the queue, just jump there instead of // reloading the queue. This is both faster, and prevents accidentally // dropping out of party shuffle. MusicUtils.setQueuePosition(position); } - /** - * {@inheritDoc} - */ + @NonNull @Override public Loader> onCreateLoader(final int id, final Bundle args) { mLoadingEmptyContainer.showLoading(); return new QueueLoader(getActivity()); } - /** - * {@inheritDoc} - */ @Override - public void onLoadFinished(final Loader> loader, final List data) { - // pause notifying the adapter and make changes before re-enabling it so that the list - // view doesn't reset to the top of the list - mAdapter.setNotifyOnChange(false); - mAdapter.unload(); // Start fresh + public void onLoadFinished(@NonNull final Loader> loader, final List data) { + Handler handler = new Handler(requireActivity().getMainLooper()); + handler.post(() -> mAdapter.unload()); // Start fresh if (data.isEmpty()) { mLoadingEmptyContainer.showNoResults(); - mAdapter.setCurrentQueuePosition(SongAdapter.NOTHING_PLAYING); - ((SlidingPanelActivity)getActivity()).clearMetaInfo(); + mAdapter.setCurrentlyPlayingTrack(null); + final FragmentActivity activity = getActivity(); + if (activity instanceof SlidingPanelActivity) { + ((SlidingPanelActivity) activity).clearMetaInfo(); + } } else { + mLoadingEmptyContainer.setVisibility(View.GONE); + // Add the songs found to the adapter - for (final Song song : data) { mAdapter.add(song); } - // Build the cache - mAdapter.buildCache(); - // Set the currently playing audio - mAdapter.setCurrentQueuePosition(MusicUtils.getQueuePosition()); + handler.post(() -> { + mAdapter.setData(data); + + // Set the currently playing audio + mAdapter.setCurrentlyPlayingTrack(MusicUtils.getCurrentTrack()); + }); } - // re-enable the notify by calling notify dataset changes - mAdapter.notifyDataSetChanged(); } - /** - * {@inheritDoc} - */ @Override - public void onLoaderReset(final Loader> loader) { + public void onLoaderReset(@NonNull final Loader> loader) { // Clear the data in the adapter mAdapter.unload(); } - /** - * {@inheritDoc} - */ @Override - public float getSpeed(final float w, final long t) { - if (w > 0.8f) { - return mAdapter.getCount() / 0.001f; - } else { - return 10.0f * w; - } + public void onItemMove(int startPosition, int endPosition) { + Handler handler = new Handler(requireActivity().getMainLooper()); + handler.post(() -> mAdapter.move(startPosition, endPosition)); + MusicUtils.moveQueueItem(startPosition, endPosition); } - /** - * {@inheritDoc} - */ - @Override public void remove(final int which) { Song song = mAdapter.getItem(which); - mAdapter.remove(song); - mAdapter.notifyDataSetChanged(); + Handler handler = new Handler(requireActivity().getMainLooper()); + handler.post(() -> mAdapter.remove(which)); MusicUtils.removeTrackAtPosition(song.mSongId, which); - // Build the cache - mAdapter.buildCache(); - } - - /** - * {@inheritDoc} - */ - @Override - public void drop(final int from, final int to) { - Song song = mAdapter.getItem(from); - mAdapter.remove(song); - mAdapter.insert(song, to); - mAdapter.notifyDataSetChanged(); - MusicUtils.moveQueueItem(from, to); - // Build the cache - mAdapter.buildCache(); } /** @@ -403,13 +340,16 @@ public class QueueFragment extends Fragment implements LoaderManager.LoaderCallb */ public void refreshQueue() { if (isAdded()) { - getLoaderManager().restartLoader(LOADER, null, this); + LoaderManager.getInstance(this).restartLoader(LOADER, null, this); } } private void setupNoResultsContainer(NoResultsContainer empty) { - int color = getResources().getColor(R.color.no_results_light); - empty.setTextColor(color); + final Context context = getContext(); + if (context != null) { + int color = ContextCompat.getColor(context, R.color.no_results_light); + empty.setTextColor(color); + } empty.setMainText(R.string.empty_queue_main); empty.setSecondaryText(R.string.empty_queue_secondary); } @@ -428,28 +368,16 @@ public class QueueFragment extends Fragment implements LoaderManager.LoaderCallb mReference = new WeakReference<>(fragment); } - /** - * {@inheritDoc} - */ @Override public void onReceive(final Context context, final Intent intent) { - // TODO: Invalid options menu if opened? final String action = intent.getAction(); - if (action == null || action.isEmpty()) { - return; + if (MusicPlaybackService.META_CHANGED.equals(action) + || MusicPlaybackService.PLAYSTATE_CHANGED.equals(action)) { + mReference.get().mAdapter.setCurrentlyPlayingTrack(MusicUtils.getCurrentTrack()); + } else if (MusicPlaybackService.QUEUE_CHANGED.equals(action)) { + mReference.get().refreshQueue(); } - switch (action) { - case MusicPlaybackService.META_CHANGED: - mReference.get().mAdapter.setCurrentQueuePosition(MusicUtils.getQueuePosition()); - break; - case MusicPlaybackService.PLAYSTATE_CHANGED: - mReference.get().mAdapter.notifyDataSetChanged(); - break; - case MusicPlaybackService.QUEUE_CHANGED: - mReference.get().refreshQueue(); - break; - } } } } diff --git a/src/org/lineageos/eleven/ui/fragments/RecentFragment.java b/src/org/lineageos/eleven/ui/fragments/RecentFragment.java index 0348bb9549c712f1a6a611bea257aab6a7091ec8..69568a9297b28d3a67bff03b5b062ba92f0de61d 100644 --- a/src/org/lineageos/eleven/ui/fragments/RecentFragment.java +++ b/src/org/lineageos/eleven/ui/fragments/RecentFragment.java @@ -1,30 +1,35 @@ /* * Copyright (C) 2012 Andrew Neal * Copyright (C) 2014 The CyanogenMod Project - * Licensed under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law - * or agreed to in writing, software distributed under the License is - * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the specific language - * governing permissions and limitations under the License. + * Copyright (C) 2021 The LineageOS Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ - package org.lineageos.eleven.ui.fragments; -import android.app.Activity; import android.os.Bundle; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; +import androidx.annotation.NonNull; +import androidx.fragment.app.FragmentActivity; import androidx.loader.content.Loader; import org.lineageos.eleven.Config; import org.lineageos.eleven.Config.SmartPlaylistType; import org.lineageos.eleven.R; -import org.lineageos.eleven.adapters.SongAdapter; +import org.lineageos.eleven.adapters.SongListAdapter; import org.lineageos.eleven.loaders.TopTracksLoader; import org.lineageos.eleven.menu.FragmentMenuItems; import org.lineageos.eleven.model.Song; @@ -36,6 +41,7 @@ import org.lineageos.eleven.utils.MusicUtils; import org.lineageos.eleven.widgets.NoResultsContainer; import java.util.TreeSet; +import java.util.function.Consumer; /** * This class is used to display all of the recently listened to songs by the @@ -55,9 +61,7 @@ public class RecentFragment extends SmartPlaylistFragment implements ISetupActio set.add(FragmentMenuItems.REMOVE_FROM_RECENT); } - /** - * {@inheritDoc} - */ + @NonNull @Override public Loader> onCreateLoader(final int id, final Bundle args) { // show the loading progress bar @@ -68,9 +72,6 @@ public class RecentFragment extends SmartPlaylistFragment implements ISetupActio return new SectionCreator<>(getActivity(), loader, null); } - /** - * {@inheritDoc} - */ @Override public void onMetaChanged() { super.onMetaChanged(); @@ -89,15 +90,19 @@ public class RecentFragment extends SmartPlaylistFragment implements ISetupActio @Override public final View onCreateView(LayoutInflater inflater, ViewGroup container, - Bundle savedInstanceState) { + Bundle savedInstanceState) { setupActionBar(); return super.onCreateView(inflater, container, savedInstanceState); } @Override public void setupActionBar() { - ((BaseActivity)getActivity()).setupActionBar(R.string.playlist_recently_played); - ((BaseActivity)getActivity()).setActionBarElevation(true); + final FragmentActivity activity = getActivity(); + if (activity instanceof BaseActivity) { + final BaseActivity baseActivity = (BaseActivity) activity; + baseActivity.setupActionBar(R.string.playlist_recently_played); + baseActivity.setActionBarElevation(true); + } } @Override @@ -106,18 +111,20 @@ public class RecentFragment extends SmartPlaylistFragment implements ISetupActio } @Override - protected SongAdapter createAdapter() { + protected SongListAdapter createAdapter() { return new RecentAdapter( - getActivity(), - R.layout.list_item_normal, - getFragmentSourceId(), - getFragmentSourceType() + getActivity(), + R.layout.list_item_normal, + getFragmentSourceId(), + getFragmentSourceType(), + this::onItemClick ); } - private class RecentAdapter extends SongAdapter { - public RecentAdapter(Activity context, int layoutId, long sourceId, Config.IdType sourceType) { - super(context, layoutId, sourceId, sourceType); + private static class RecentAdapter extends SongListAdapter { + public RecentAdapter(FragmentActivity context, int layoutId, long sourceId, + Config.IdType sourceType, Consumer onItemClickListener) { + super(context, layoutId, sourceId, sourceType, onItemClickListener); } @Override @@ -127,11 +134,17 @@ public class RecentFragment extends SmartPlaylistFragment implements ISetupActio } @Override - protected int getShuffleTitleId() { return R.string.menu_shuffle_recent; } + protected int getShuffleTitleId() { + return R.string.menu_shuffle_recent; + } @Override - protected int getClearTitleId() { return R.string.clear_recent_title; } + protected int getClearTitleId() { + return R.string.clear_recent_title; + } @Override - protected void clearList() { MusicUtils.clearRecent(getActivity()); } + protected void clearList() { + MusicUtils.clearRecent(getActivity()); + } } diff --git a/src/org/lineageos/eleven/ui/fragments/SongFragment.java b/src/org/lineageos/eleven/ui/fragments/SongFragment.java index d124dea1b98fb842b6cf5b14a8da318c4e0fa03c..167fd8585aae9917c29c1c93101e899b617f0894 100644 --- a/src/org/lineageos/eleven/ui/fragments/SongFragment.java +++ b/src/org/lineageos/eleven/ui/fragments/SongFragment.java @@ -1,21 +1,27 @@ /* * Copyright (C) 2012 Andrew Neal * Copyright (C) 2014 The CyanogenMod Project - * Licensed under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law - * or agreed to in writing, software distributed under the License is - * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the specific language - * governing permissions and limitations under the License. + * Copyright (C) 2021 The LineageOS Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ - package org.lineageos.eleven.ui.fragments; import android.content.Context; import android.os.Bundle; +import androidx.annotation.NonNull; +import androidx.fragment.app.Fragment; import androidx.loader.app.LoaderManager; import androidx.loader.content.Loader; @@ -36,20 +42,14 @@ import org.lineageos.eleven.utils.SectionCreatorUtils; */ public class SongFragment extends BasicSongFragment { - /** - * {@inheritDoc} - */ public void playAll(int position) { - int internalPosition = mAdapter.getInternalPosition(position); - final long[] list = mAdapter.getUnderlyingAdapter().getSongIds(); + final long[] list = mAdapter.getSongIds(); if (list != null) { - MusicUtils.playAll(getActivity(), list, internalPosition, -1, Config.IdType.NA, false); + MusicUtils.playAll(list, position, -1, Config.IdType.NA, false); } } - /** - * {@inheritDoc} - */ + @NonNull @Override public Loader> onCreateLoader(final int id, final Bundle args) { // show the loading progress bar @@ -62,7 +62,8 @@ public class SongFragment extends BasicSongFragment { SongLoader songLoader = new SongLoader(context); // get the song comparison method to create the headers with - SectionCreatorUtils.IItemCompare songComparison = SectionCreatorUtils.createSongComparison(context); + SectionCreatorUtils.IItemCompare songComparison = + SectionCreatorUtils.createSongComparison(context); // return the wrapped section creator return new SectionCreator<>(context, songLoader, songComparison); @@ -74,40 +75,14 @@ public class SongFragment extends BasicSongFragment { return PagerAdapter.MusicFragments.SONG.ordinal(); } - /** - * Scrolls the list to the currently playing song when the user touches the - * header in the {@link TitlePageIndicator}. - */ - public void scrollToCurrentSong() { - final int currentSongPosition = getItemPositionBySong(); - - if (currentSongPosition != 0) { - mListView.setSelection(currentSongPosition); - } - } - - /** - * @return The position of an item in the list based on the name of the - * currently playing song. - */ - private int getItemPositionBySong() { - final long trackId = MusicUtils.getCurrentAudioId(); - if (mAdapter == null) { - return 0; - } - - int position = mAdapter.getItemPosition(trackId); - - // if for some reason we don't find the item, just jump to the top - if (position < 0) { - return 0; - } - - return position; + @Override + public LoaderManager getFragmentLoaderManager() { + final Fragment parent = getParentFragment(); + return parent == null ? null : LoaderManager.getInstance(parent); } @Override - public LoaderManager getFragmentLoaderManager() { - return getParentFragment().getLoaderManager(); + protected boolean hasHeaders() { + return true; } } diff --git a/src/org/lineageos/eleven/ui/fragments/phone/MusicBrowserFragment.java b/src/org/lineageos/eleven/ui/fragments/phone/MusicBrowserFragment.java index a0fe8358f2dc479820bd9b6408c06f948975d7cc..e8886d9bc69f2da4e98e0f845b2077ecb97b26bf 100644 --- a/src/org/lineageos/eleven/ui/fragments/phone/MusicBrowserFragment.java +++ b/src/org/lineageos/eleven/ui/fragments/phone/MusicBrowserFragment.java @@ -1,11 +1,12 @@ /* * Copyright (C) 2014 The CyanogenMod Project + * Copyright (C) 2021 The LineageOS Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -15,8 +16,6 @@ */ package org.lineageos.eleven.ui.fragments.phone; -import android.os.Bundle; - import androidx.fragment.app.Fragment; import androidx.loader.app.LoaderManager; @@ -30,16 +29,15 @@ public abstract class MusicBrowserFragment extends Fragment { public abstract int getLoaderId(); public LoaderManager getContainingLoaderManager() { - return getParentFragment().getLoaderManager(); + final Fragment parent = getParentFragment(); + return parent == null ? null : LoaderManager.getInstance(getParentFragment()); } - protected void initLoader(Bundle args, - LoaderManager.LoaderCallbacks callback) { - getContainingLoaderManager().initLoader(getLoaderId(), args, callback); + protected void initLoader(LoaderManager.LoaderCallbacks callback) { + getContainingLoaderManager().initLoader(getLoaderId(), null, callback); } - protected void restartLoader(Bundle args, - LoaderManager.LoaderCallbacks callback) { - getContainingLoaderManager().restartLoader(getLoaderId(), args, callback); + protected void restartLoader(LoaderManager.LoaderCallbacks callback) { + getContainingLoaderManager().restartLoader(getLoaderId(), null, callback); } } diff --git a/src/org/lineageos/eleven/ui/fragments/phone/MusicBrowserPhoneFragment.java b/src/org/lineageos/eleven/ui/fragments/phone/MusicBrowserPhoneFragment.java index 1237e795a37e930e2d09971d730c49b10118802c..e47c7c9eeec9d1153d50f8f76ac80ccf573c84cd 100644 --- a/src/org/lineageos/eleven/ui/fragments/phone/MusicBrowserPhoneFragment.java +++ b/src/org/lineageos/eleven/ui/fragments/phone/MusicBrowserPhoneFragment.java @@ -1,16 +1,20 @@ /* * Copyright (C) 2012 Andrew Neal * Copyright (C) 2014 The CyanogenMod Project - * Licensed under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law - * or agreed to in writing, software distributed under the License is - * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the specific language - * governing permissions and limitations under the License. + * Copyright (C) 2021 The LineageOS Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ - package org.lineageos.eleven.ui.fragments.phone; import android.os.Bundle; @@ -18,6 +22,7 @@ import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; +import androidx.annotation.NonNull; import androidx.fragment.app.Fragment; import androidx.viewpager.widget.ViewPager; @@ -38,10 +43,12 @@ import org.lineageos.eleven.widgets.ViewPagerTabs; * This class is used to hold the {@link ViewPager} used for swiping between the * playlists, recent, artists, albums, songs, and genre {@link Fragment} * s for phones. - * - * @NOTE: The reason the sort orders are taken care of in this fragment rather - * than the individual fragments is to keep from showing all of the menu - * items on tablet interfaces. + * + *

+ * NOTE: The reason the sort orders are taken care of in this fragment rather + * than the individual fragments is to keep from showing all of the menu + * items on tablet interfaces. + * * @author Andrew Neal (andrewdneal@gmail.com) */ public class MusicBrowserPhoneFragment extends BaseFragment { @@ -53,7 +60,7 @@ public class MusicBrowserPhoneFragment extends BaseFragment { private ViewPager mViewPager; /** - * VP's adapter + * ViewPager's Adapter */ private PagerAdapter mPagerAdapter; @@ -80,9 +87,6 @@ public class MusicBrowserPhoneFragment extends BaseFragment { return getString(R.string.app_name); } - /** - * {@inheritDoc} - */ @Override public void onCreate(final Bundle savedInstanceState) { super.onCreate(savedInstanceState); @@ -103,25 +107,27 @@ public class MusicBrowserPhoneFragment extends BaseFragment { } // Initialize the ViewPager - mViewPager = (ViewPager)mRootView.findViewById(R.id.fragment_home_phone_pager); - // Attch the adapter + mViewPager = mRootView.findViewById(R.id.fragment_home_phone_pager); + // Attach the adapter mViewPager.setAdapter(mPagerAdapter); // Offscreen pager loading limit mViewPager.setOffscreenPageLimit(mPagerAdapter.getCount() - 1); // Initialize the tab strip - final ViewPagerTabs tabs = (ViewPagerTabs) - mRootView.findViewById(R.id.fragment_home_phone_pager_titles); + final ViewPagerTabs tabs = mRootView.findViewById(R.id.fragment_home_phone_pager_titles); // Attach the ViewPager tabs.setViewPager(mViewPager); - mViewPager.setOnPageChangeListener(tabs); + mViewPager.addOnPageChangeListener(tabs); - if (mDefaultPageIdx != INVALID_PAGE_INDEX) { + if (mDefaultPageIdx != INVALID_PAGE_INDEX) { navigateToPage(mDefaultPageIdx); } else { // Start on the last page the user was on navigateToPage(mPreferences.getStartPage()); } + + // Enable the options menu + setHasOptionsMenu(true); } public void setDefaultPageIdx(final int pageIdx) { @@ -136,19 +142,6 @@ public class MusicBrowserPhoneFragment extends BaseFragment { } } - /** - * {@inheritDoc} - */ - @Override - public void onActivityCreated(final Bundle savedInstanceState) { - super.onActivityCreated(savedInstanceState); - // Enable the options menu - setHasOptionsMenu(true); - } - - /** - * {@inheritDoc} - */ @Override public void onPause() { super.onPause(); @@ -156,22 +149,17 @@ public class MusicBrowserPhoneFragment extends BaseFragment { mPreferences.setStartPage(mViewPager.getCurrentItem()); } - /** - * {@inheritDoc} - */ @Override - public void onPrepareOptionsMenu(final Menu menu) { + public void onPrepareOptionsMenu(@NonNull final Menu menu) { super.onPrepareOptionsMenu(menu); } - /** - * {@inheritDoc} - */ @Override - public void onCreateOptionsMenu(final Menu menu, final MenuInflater inflater) { + public void onCreateOptionsMenu(@NonNull final Menu menu, + @NonNull final MenuInflater inflater) { super.onCreateOptionsMenu(menu, inflater); - inflater.inflate(R.menu.shuffle_all, menu); // Shuffle all + inflater.inflate(R.menu.shuffle_all, menu); if (isArtistPage()) { inflater.inflate(R.menu.artist_sort_by, menu); } else if (isAlbumPage()) { @@ -183,102 +171,90 @@ public class MusicBrowserPhoneFragment extends BaseFragment { } } - /** - * {@inheritDoc} - */ @Override public boolean onOptionsItemSelected(final MenuItem item) { - switch (item.getItemId()) { - case R.id.menu_shuffle_all: - // Shuffle all the songs - MusicUtils.shuffleAll(getActivity()); - return true; - case R.id.menu_sort_by_az: - if (isArtistPage()) { - mPreferences.setArtistSortOrder(SortOrder.ArtistSortOrder.ARTIST_A_Z); - getArtistFragment().refresh(); - } else if (isAlbumPage()) { - mPreferences.setAlbumSortOrder(SortOrder.AlbumSortOrder.ALBUM_A_Z); - getAlbumFragment().refresh(); - } else if (isSongPage()) { - mPreferences.setSongSortOrder(SortOrder.SongSortOrder.SONG_A_Z); - getSongFragment().refresh(); - } - return true; - case R.id.menu_sort_by_za: - if (isArtistPage()) { - mPreferences.setArtistSortOrder(SortOrder.ArtistSortOrder.ARTIST_Z_A); - getArtistFragment().refresh(); - } else if (isAlbumPage()) { - mPreferences.setAlbumSortOrder(SortOrder.AlbumSortOrder.ALBUM_Z_A); - getAlbumFragment().refresh(); - } else if (isSongPage()) { - mPreferences.setSongSortOrder(SortOrder.SongSortOrder.SONG_Z_A); - getSongFragment().refresh(); - } - return true; - case R.id.menu_sort_by_artist: - if (isAlbumPage()) { - mPreferences.setAlbumSortOrder(SortOrder.AlbumSortOrder.ALBUM_ARTIST); - getAlbumFragment().refresh(); - } else if (isSongPage()) { - mPreferences.setSongSortOrder(SortOrder.SongSortOrder.SONG_ARTIST); - getSongFragment().refresh(); - } - return true; - case R.id.menu_sort_by_album: - if (isSongPage()) { - mPreferences.setSongSortOrder(SortOrder.SongSortOrder.SONG_ALBUM); - getSongFragment().refresh(); - } - return true; - case R.id.menu_sort_by_year: - if (isAlbumPage()) { - mPreferences.setAlbumSortOrder(SortOrder.AlbumSortOrder.ALBUM_YEAR); - getAlbumFragment().refresh(); - } else if (isSongPage()) { - mPreferences.setSongSortOrder(SortOrder.SongSortOrder.SONG_YEAR); - getSongFragment().refresh(); - } - return true; - case R.id.menu_sort_by_duration: - if (isSongPage()) { - mPreferences.setSongSortOrder(SortOrder.SongSortOrder.SONG_DURATION); - getSongFragment().refresh(); - } - return true; - case R.id.menu_sort_by_number_of_songs: - if (isArtistPage()) { - mPreferences - .setArtistSortOrder(SortOrder.ArtistSortOrder.ARTIST_NUMBER_OF_SONGS); - getArtistFragment().refresh(); - } else if (isAlbumPage()) { - mPreferences.setAlbumSortOrder(SortOrder.AlbumSortOrder.ALBUM_NUMBER_OF_SONGS); - getAlbumFragment().refresh(); - } - return true; - case R.id.menu_sort_by_number_of_albums: - if (isArtistPage()) { - mPreferences - .setArtistSortOrder(SortOrder.ArtistSortOrder.ARTIST_NUMBER_OF_ALBUMS); - getArtistFragment().refresh(); - } - return true; - case R.id.menu_sort_by_filename: - if(isSongPage()) { - mPreferences.setSongSortOrder(SortOrder.SongSortOrder.SONG_FILENAME); - getSongFragment().refresh(); - } - return true; - case R.id.menu_new_playlist: - if(isPlaylistPage()) { - CreateNewPlaylist.getInstance(new long[0]).show(getFragmentManager(), "CreatePlaylist"); - } - return true; - default: - break; + final int id = item.getItemId(); + if (id == R.id.menu_shuffle_all) { + // Shuffle all the songs + MusicUtils.shuffleAll(getActivity()); + } else if (id == R.id.menu_sort_by_az) { + if (isArtistPage()) { + mPreferences.setArtistSortOrder(SortOrder.ArtistSortOrder.ARTIST_A_Z); + getArtistFragment().refresh(); + } else if (isAlbumPage()) { + mPreferences.setAlbumSortOrder(SortOrder.AlbumSortOrder.ALBUM_A_Z); + getAlbumFragment().refresh(); + } else if (isSongPage()) { + mPreferences.setSongSortOrder(SortOrder.SongSortOrder.SONG_A_Z); + getSongFragment().refresh(); + } + } else if (id == R.id.menu_sort_by_za) { + if (isArtistPage()) { + mPreferences.setArtistSortOrder(SortOrder.ArtistSortOrder.ARTIST_Z_A); + getArtistFragment().refresh(); + } else if (isAlbumPage()) { + mPreferences.setAlbumSortOrder(SortOrder.AlbumSortOrder.ALBUM_Z_A); + getAlbumFragment().refresh(); + } else if (isSongPage()) { + mPreferences.setSongSortOrder(SortOrder.SongSortOrder.SONG_Z_A); + getSongFragment().refresh(); + } + } else if (id == R.id.menu_sort_by_artist) { + if (isAlbumPage()) { + mPreferences.setAlbumSortOrder(SortOrder.AlbumSortOrder.ALBUM_ARTIST); + getAlbumFragment().refresh(); + } else if (isSongPage()) { + mPreferences.setSongSortOrder(SortOrder.SongSortOrder.SONG_ARTIST); + getSongFragment().refresh(); + } + } else if (id == R.id.menu_sort_by_album) { + if (isSongPage()) { + mPreferences.setSongSortOrder(SortOrder.SongSortOrder.SONG_ALBUM); + getSongFragment().refresh(); + } + } else if (id == R.id.menu_sort_by_year) { + if (isAlbumPage()) { + mPreferences.setAlbumSortOrder(SortOrder.AlbumSortOrder.ALBUM_YEAR); + getAlbumFragment().refresh(); + } else if (isSongPage()) { + mPreferences.setSongSortOrder(SortOrder.SongSortOrder.SONG_YEAR); + getSongFragment().refresh(); + } + } else if (id == R.id.menu_sort_by_duration) { + if (isSongPage()) { + mPreferences.setSongSortOrder(SortOrder.SongSortOrder.SONG_DURATION); + getSongFragment().refresh(); + } + } else if (id == R.id.menu_sort_by_number_of_songs) { + if (isArtistPage()) { + mPreferences + .setArtistSortOrder(SortOrder.ArtistSortOrder.ARTIST_NUMBER_OF_SONGS); + getArtistFragment().refresh(); + } else if (isAlbumPage()) { + mPreferences.setAlbumSortOrder(SortOrder.AlbumSortOrder.ALBUM_NUMBER_OF_SONGS); + getAlbumFragment().refresh(); + } + } else if (id == R.id.menu_sort_by_number_of_albums) { + if (isArtistPage()) { + mPreferences + .setArtistSortOrder(SortOrder.ArtistSortOrder.ARTIST_NUMBER_OF_ALBUMS); + getArtistFragment().refresh(); + } + } else if (id == R.id.menu_sort_by_filename) { + if (isSongPage()) { + mPreferences.setSongSortOrder(SortOrder.SongSortOrder.SONG_FILENAME); + getSongFragment().refresh(); + } + } else if (id == R.id.menu_new_playlist) { + if (isPlaylistPage()) { + CreateNewPlaylist.getInstance(new long[0]).show(getChildFragmentManager(), + "CreatePlaylist"); + } + } else { + return super.onOptionsItemSelected(item); } - return super.onOptionsItemSelected(item); + + return true; } @Override @@ -292,7 +268,7 @@ public class MusicBrowserPhoneFragment extends BaseFragment { } public ArtistFragment getArtistFragment() { - return (ArtistFragment)mPagerAdapter.getFragment(MusicFragments.ARTIST.ordinal()); + return (ArtistFragment) mPagerAdapter.getFragment(MusicFragments.ARTIST.ordinal()); } private boolean isAlbumPage() { @@ -300,7 +276,7 @@ public class MusicBrowserPhoneFragment extends BaseFragment { } public AlbumFragment getAlbumFragment() { - return (AlbumFragment)mPagerAdapter.getFragment(MusicFragments.ALBUM.ordinal()); + return (AlbumFragment) mPagerAdapter.getFragment(MusicFragments.ALBUM.ordinal()); } private boolean isSongPage() { @@ -308,7 +284,7 @@ public class MusicBrowserPhoneFragment extends BaseFragment { } public SongFragment getSongFragment() { - return (SongFragment)mPagerAdapter.getFragment(MusicFragments.SONG.ordinal()); + return (SongFragment) mPagerAdapter.getFragment(MusicFragments.SONG.ordinal()); } @Override diff --git a/src/org/lineageos/eleven/ui/fragments/profile/BasicSongFragment.java b/src/org/lineageos/eleven/ui/fragments/profile/BasicSongFragment.java index 5ef709d26413584c6b0090bc8b095bf2c4e8c32e..2567db9bee4ac2a3061ea872024ded8419bd3540 100644 --- a/src/org/lineageos/eleven/ui/fragments/profile/BasicSongFragment.java +++ b/src/org/lineageos/eleven/ui/fragments/profile/BasicSongFragment.java @@ -1,49 +1,59 @@ /* * Copyright (C) 2012 Andrew Neal * Copyright (C) 2014 The CyanogenMod Project - * Licensed under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law - * or agreed to in writing, software distributed under the License is - * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the specific language - * governing permissions and limitations under the License. + * Copyright (C) 2021 The LineageOS Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ - package org.lineageos.eleven.ui.fragments.profile; +import android.annotation.SuppressLint; +import android.app.Activity; +import android.content.Context; import android.os.Bundle; +import android.os.Handler; import android.os.SystemClock; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; -import android.widget.AbsListView; -import android.widget.AdapterView; -import android.widget.AdapterView.OnItemClickListener; -import android.widget.ListView; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.core.content.ContextCompat; import androidx.fragment.app.Fragment; import androidx.loader.app.LoaderManager; import androidx.loader.content.Loader; +import androidx.recyclerview.widget.DefaultItemAnimator; +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; import org.lineageos.eleven.Config; import org.lineageos.eleven.MusicStateListener; import org.lineageos.eleven.R; -import org.lineageos.eleven.adapters.SongAdapter; +import org.lineageos.eleven.adapters.SongListAdapter; import org.lineageos.eleven.model.Song; -import org.lineageos.eleven.recycler.RecycleHolder; -import org.lineageos.eleven.sectionadapter.SectionAdapter; import org.lineageos.eleven.sectionadapter.SectionListContainer; import org.lineageos.eleven.service.MusicPlaybackTrack; import org.lineageos.eleven.ui.activities.BaseActivity; import org.lineageos.eleven.utils.MusicUtils; import org.lineageos.eleven.utils.PopupMenuHelper; +import org.lineageos.eleven.utils.SectionCreatorUtils; import org.lineageos.eleven.utils.SongPopupMenuHelper; -import org.lineageos.eleven.widgets.IPopupMenuCallback; import org.lineageos.eleven.widgets.LoadingEmptyContainer; import org.lineageos.eleven.widgets.NoResultsContainer; +import org.lineageos.eleven.widgets.SectionSeparatorItemDecoration; +import java.util.TreeMap; import java.util.TreeSet; /** @@ -52,8 +62,7 @@ import java.util.TreeSet; * @author Andrew Neal (andrewdneal@gmail.com) */ public abstract class BasicSongFragment extends Fragment implements - LoaderManager.LoaderCallbacks>, - OnItemClickListener, MusicStateListener { + LoaderManager.LoaderCallbacks>, MusicStateListener { /** * Fragment UI @@ -63,12 +72,12 @@ public abstract class BasicSongFragment extends Fragment implements /** * The adapter for the list */ - protected SectionAdapter mAdapter; + protected SongListAdapter mAdapter; /** * The list view */ - protected ListView mListView; + protected RecyclerView mListView; /** * Pop up menu helper @@ -86,16 +95,13 @@ public abstract class BasicSongFragment extends Fragment implements public BasicSongFragment() { } - /** - * {@inheritDoc} - */ @Override public void onCreate(final Bundle savedInstanceState) { super.onCreate(savedInstanceState); - mPopupMenuHelper = new SongPopupMenuHelper(getActivity(), getFragmentManager()) { + mPopupMenuHelper = new SongPopupMenuHelper(getActivity(), getChildFragmentManager()) { @Override public Song getSong(int position) { - return mAdapter.getTItem(position); + return mAdapter.getItem(position); } @Override @@ -116,13 +122,9 @@ public abstract class BasicSongFragment extends Fragment implements }; // Create the adapter - mAdapter = new SectionAdapter<>(getActivity(), createAdapter()); - mAdapter.setPopupMenuClickedListener(new IPopupMenuCallback.IListener() { - @Override - public void onPopupMenuClicked(View v, int position) { - mPopupMenuHelper.showPopupMenu(v, position); - } - }); + mAdapter = createAdapter(); + mAdapter.setPopupMenuClickedListener((v, position) -> + mPopupMenuHelper.showPopupMenu(v, position)); } protected long getFragmentSourceId() { @@ -137,52 +139,35 @@ public abstract class BasicSongFragment extends Fragment implements // do nothing - let subclasses override } - /** - * {@inheritDoc} - */ + @SuppressLint("InflateParams") @Override public View onCreateView(final LayoutInflater inflater, final ViewGroup container, final Bundle savedInstanceState) { // The View for the fragment's UI - mRootView = (ViewGroup) inflater.inflate(R.layout.list_base, null); + mRootView = (ViewGroup) inflater.inflate(R.layout.fragment_list, container, false); // set the background on the root view - mRootView.setBackgroundColor(getResources().getColor(R.color.background_color)); + final Context context = getContext(); + if (context != null) { + mRootView.setBackgroundColor(ContextCompat.getColor(context, R.color.background_color)); + } // Initialize the list - mListView = (ListView) mRootView.findViewById(R.id.list_base); + mListView = mRootView.findViewById(R.id.list_base); // Set the data behind the list mListView.setAdapter(mAdapter); - // Release any references to the recycled Views - mListView.setRecyclerListener(new RecycleHolder()); - // Play the selected song - mListView.setOnItemClickListener(this); - // To help make scrolling smooth - mListView.setOnScrollListener(new AbsListView.OnScrollListener() { - @Override - public void onScrollStateChanged(AbsListView view, int scrollState) { - // Pause disk cache access to ensure smoother scrolling - if (scrollState == AbsListView.OnScrollListener.SCROLL_STATE_FLING) { - mAdapter.getUnderlyingAdapter().setPauseDiskCache(true); - } else { - mAdapter.getUnderlyingAdapter().setPauseDiskCache(false); - mAdapter.notifyDataSetChanged(); - } - } - - @Override - public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) { - - } - }); + mListView.setLayoutManager(new LinearLayoutManager(requireActivity())); + mListView.setItemAnimator(new DefaultItemAnimator()); // Show progress bar - mLoadingEmptyContainer = (LoadingEmptyContainer)mRootView.findViewById(R.id.loading_empty_container); + mLoadingEmptyContainer = mRootView.findViewById(R.id.loading_empty_container); // Setup the container strings setupNoResultsContainer(mLoadingEmptyContainer.getNoResultsContainer()); - mListView.setEmptyView(mLoadingEmptyContainer); + mLoadingEmptyContainer.setVisibility(View.VISIBLE); // Register the music status listener - ((BaseActivity)getActivity()).setMusicStateListenerListener(this); - + final Activity activity = getActivity(); + if (activity instanceof BaseActivity) { + ((BaseActivity) activity).setMusicStateListenerListener(this); + } return mRootView; } @@ -190,49 +175,48 @@ public abstract class BasicSongFragment extends Fragment implements public void onDestroyView() { super.onDestroyView(); - ((BaseActivity)getActivity()).removeMusicStateListenerListener(this); + final Activity activity = getActivity(); + if (activity instanceof BaseActivity) { + ((BaseActivity) activity).removeMusicStateListenerListener(this); + } } /** * This allows subclasses to customize the look and feel of the no results container + * * @param empty NoResultsContainer class */ public void setupNoResultsContainer(final NoResultsContainer empty) { // do nothing } - /** - * {@inheritDoc} - */ @Override - public void onActivityCreated(final Bundle savedInstanceState) { - super.onActivityCreated(savedInstanceState); + public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); // Start the loader getFragmentLoaderManager().initLoader(getLoaderId(), null, this); } - /** - * {@inheritDoc} - */ - @Override - public void onItemClick(final AdapterView parent, final View view, final int position, - final long id) { + protected void onItemClick(final int position) { playAll(position); } - /** - * {@inheritDoc} - */ @Override - public void onLoadFinished(final Loader> loader, + public void onLoadFinished(@NonNull final Loader> loader, final SectionListContainer data) { + Handler handler = new Handler(requireActivity().getMainLooper()); if (data.mListResults.isEmpty()) { - mAdapter.unload(); + handler.post(() -> mAdapter.unload()); mLoadingEmptyContainer.showNoResults(); return; } - mAdapter.setData(data); + mLoadingEmptyContainer.setVisibility(View.GONE); + + handler.post(() -> { + mAdapter.setData(data.mListResults); + setHeaders(data.mSections); + }); } /** @@ -240,10 +224,7 @@ public abstract class BasicSongFragment extends Fragment implements */ protected long[] getSongIdsFromAdapter() { if (mAdapter != null) { - final SongAdapter adapter = mAdapter.getUnderlyingAdapter(); - if (adapter != null) { - return adapter.getSongIds(); - } + return mAdapter.getSongIds(); } return null; @@ -258,51 +239,46 @@ public abstract class BasicSongFragment extends Fragment implements restartLoader(); } - /** - * {@inheritDoc} - */ @Override public void restartLoader() { // Update the list when the user deletes any items getFragmentLoaderManager().restartLoader(getLoaderId(), null, this); } - /** - * {@inheritDoc} - */ @Override - public void onLoaderReset(final Loader> loader) { + public void onLoaderReset(@NonNull final Loader> loader) { // Clear the data in the adapter mAdapter.unload(); } /** * If the subclasses want to use a customized SongAdapter they can override this method + * * @return the Song adapter */ - protected SongAdapter createAdapter() { - return new SongAdapter( - getActivity(), - R.layout.list_item_normal, - getFragmentSourceId(), - getFragmentSourceType() + protected SongListAdapter createAdapter() { + return new SongListAdapter( + requireActivity(), + R.layout.list_item_normal, + getFragmentSourceId(), + getFragmentSourceType(), + this::onItemClick ); } /** * Allow subclasses to specify a different loader manager + * * @return Loader Manager to use */ public LoaderManager getFragmentLoaderManager() { - return getLoaderManager(); + return LoaderManager.getInstance(this); } @Override public void onMetaChanged() { MusicPlaybackTrack currentTrack = MusicUtils.getCurrentTrack(); - if (mAdapter.getUnderlyingAdapter().setCurrentlyPlayingTrack(currentTrack)) { - mAdapter.notifyDataSetChanged(); - } + mAdapter.setCurrentlyPlayingTrack(currentTrack); } @Override @@ -316,10 +292,22 @@ public abstract class BasicSongFragment extends Fragment implements public abstract int getLoaderId(); /** - * If the user clisk play all + * If the user clicks play all * * @param position the position of the item clicked or -1 if shuffle all */ public abstract void playAll(int position); + protected abstract boolean hasHeaders(); + + private void setHeaders(TreeMap sections) { + if (!hasHeaders() || sections == null) { + return; + } + + for (int i = 0; i < mListView.getItemDecorationCount(); i++) { + mListView.removeItemDecorationAt(i); + } + mListView.addItemDecoration(new SectionSeparatorItemDecoration(requireContext(), sections)); + } } diff --git a/src/org/lineageos/eleven/ui/fragments/profile/LastAddedFragment.java b/src/org/lineageos/eleven/ui/fragments/profile/LastAddedFragment.java index f2a97ff9acc92dcc130e67d90777bdc4da00673e..e6a1434342305d2ce1d61919ae28792b9e848f16 100644 --- a/src/org/lineageos/eleven/ui/fragments/profile/LastAddedFragment.java +++ b/src/org/lineageos/eleven/ui/fragments/profile/LastAddedFragment.java @@ -1,16 +1,20 @@ /* * Copyright (C) 2012 Andrew Neal * Copyright (C) 2014 The CyanogenMod Project - * Licensed under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law - * or agreed to in writing, software distributed under the License is - * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the specific language - * governing permissions and limitations under the License. + * Copyright (C) 2021 The LineageOS Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ - package org.lineageos.eleven.ui.fragments.profile; import android.os.Bundle; @@ -18,6 +22,8 @@ import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; +import androidx.annotation.NonNull; +import androidx.fragment.app.FragmentActivity; import androidx.loader.content.Loader; import org.lineageos.eleven.Config; @@ -40,9 +46,7 @@ import org.lineageos.eleven.widgets.NoResultsContainer; */ public class LastAddedFragment extends SmartPlaylistFragment implements ISetupActionBar { - /** - * {@inheritDoc} - */ + @NonNull @Override public Loader> onCreateLoader(final int id, final Bundle args) { // show the loading progress bar @@ -62,15 +66,19 @@ public class LastAddedFragment extends SmartPlaylistFragment implements ISetupAc @Override public final View onCreateView(LayoutInflater inflater, ViewGroup container, - Bundle savedInstanceState) { + Bundle savedInstanceState) { setupActionBar(); return super.onCreateView(inflater, container, savedInstanceState); } @Override public void setupActionBar() { - ((BaseActivity)getActivity()).setupActionBar(R.string.playlist_last_added); - ((BaseActivity)getActivity()).setActionBarElevation(true); + final FragmentActivity activity = getActivity(); + if (activity instanceof BaseActivity) { + final BaseActivity baseActivity = (BaseActivity) activity; + baseActivity.setupActionBar(R.string.playlist_last_added); + baseActivity.setActionBarElevation(true); + } } @Override @@ -83,11 +91,17 @@ public class LastAddedFragment extends SmartPlaylistFragment implements ISetupAc } @Override - protected int getShuffleTitleId() { return R.string.menu_shuffle_last_added; } + protected int getShuffleTitleId() { + return R.string.menu_shuffle_last_added; + } @Override - protected int getClearTitleId() { return R.string.clear_last_added; } + protected int getClearTitleId() { + return R.string.clear_last_added; + } @Override - protected void clearList() { MusicUtils.clearLastAdded(getActivity()); } + protected void clearList() { + MusicUtils.clearLastAdded(getActivity()); + } } diff --git a/src/org/lineageos/eleven/ui/fragments/profile/SmartPlaylistFragment.java b/src/org/lineageos/eleven/ui/fragments/profile/SmartPlaylistFragment.java index d2d53b7e416d222fbe014e49a9c58d1d38a7e846..8323b6101f3471587245017bb9653eaa6af3ea98 100644 --- a/src/org/lineageos/eleven/ui/fragments/profile/SmartPlaylistFragment.java +++ b/src/org/lineageos/eleven/ui/fragments/profile/SmartPlaylistFragment.java @@ -1,18 +1,19 @@ /* -* Copyright (C) 2014 The CyanogenMod Project -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ + * Copyright (C) 2014 The CyanogenMod Project + * Copyright (C) 2021 The LineageOS Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package org.lineageos.eleven.ui.fragments.profile; import android.os.Bundle; @@ -23,8 +24,10 @@ import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; -import org.lineageos.eleven.Config.SmartPlaylistType; +import androidx.annotation.NonNull; + import org.lineageos.eleven.Config; +import org.lineageos.eleven.Config.SmartPlaylistType; import org.lineageos.eleven.R; import org.lineageos.eleven.adapters.PagerAdapter; import org.lineageos.eleven.menu.ConfirmDialog; @@ -45,11 +48,13 @@ public abstract class SmartPlaylistFragment extends BasicSongFragment private PopupMenuHelper mActionMenuHelper; @Override - public int getLoaderId() { return LOADER; } + public int getLoaderId() { + return LOADER; + } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, - Bundle savedInstanceState) { + Bundle savedInstanceState) { setHasOptionsMenu(true); return super.onCreateView(inflater, container, savedInstanceState); } @@ -60,7 +65,7 @@ public abstract class SmartPlaylistFragment extends BasicSongFragment } @Override - public void onCreateOptionsMenu(final Menu menu, final MenuInflater inflater) { + public void onCreateOptionsMenu(@NonNull final Menu menu, final MenuInflater inflater) { inflater.inflate(R.menu.shuffle_item, menu); menu.findItem(R.id.menu_shuffle_item).setTitle(getShuffleTitleId()); @@ -82,23 +87,20 @@ public abstract class SmartPlaylistFragment extends BasicSongFragment @Override public boolean onOptionsItemSelected(final MenuItem item) { - switch(item.getItemId()) { - case R.id.menu_shuffle_item: - playAll(-1, true); - return true; - case R.id.clear_list: - ConfirmDialog.show( - this, CLEAR_REQUEST, getClearTitleId(), R.string.clear); - return true; - default: - if(mActionMenuHelper.onMenuItemClick(item)) { return true; } + final int id = item.getItemId(); + if (id == R.id.menu_shuffle_item) { + playAll(-1, true); + } else if (id == R.id.clear_list) { + ConfirmDialog.show(this, CLEAR_REQUEST, getClearTitleId(), R.string.clear); + } else if (!mActionMenuHelper.onMenuItemClick(item)) { + super.onOptionsItemSelected(item); } - return super.onOptionsItemSelected(item); + return true; } @Override public void confirmOk(int requestCode) { - if(requestCode == CLEAR_REQUEST) { + if (requestCode == CLEAR_REQUEST) { mAdapter.unload(); clearList(); restartLoader(); @@ -120,7 +122,7 @@ public abstract class SmartPlaylistFragment extends BasicSongFragment // enter the page. long[] songIds = getSongIdsFromAdapter(); if (songIds != null) { - MusicUtils.playAll(getActivity(), songIds, position, getSmartPlaylistType().mId, + MusicUtils.playAll(songIds, position, getSmartPlaylistType().mId, Config.IdType.Playlist, shuffle); } } @@ -129,14 +131,25 @@ public abstract class SmartPlaylistFragment extends BasicSongFragment return PagerAdapter.MusicFragments.PLAYLIST; } + @Override + protected boolean hasHeaders() { + return false; + } + protected abstract SmartPlaylistType getSmartPlaylistType(); - /** text for menu item that shuffles items in this playlist */ + /** + * text for menu item that shuffles items in this playlist + */ protected abstract int getShuffleTitleId(); - /** text for confirmation dialog that clears this playlist */ + /** + * text for confirmation dialog that clears this playlist + */ protected abstract int getClearTitleId(); - /** action that clears this playlist */ + /** + * action that clears this playlist + */ protected abstract void clearList(); -} \ No newline at end of file +} diff --git a/src/org/lineageos/eleven/ui/fragments/profile/TopTracksFragment.java b/src/org/lineageos/eleven/ui/fragments/profile/TopTracksFragment.java index 62f3cba41fb1c8d7137845a5a55722bb9a23203d..4e8f4298a51b9987719fd0c98073144ff217c353 100644 --- a/src/org/lineageos/eleven/ui/fragments/profile/TopTracksFragment.java +++ b/src/org/lineageos/eleven/ui/fragments/profile/TopTracksFragment.java @@ -1,40 +1,48 @@ /* * Copyright (C) 2012 Andrew Neal * Copyright (C) 2014 The CyanogenMod Project - * Licensed under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law - * or agreed to in writing, software distributed under the License is - * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the specific language - * governing permissions and limitations under the License. + * Copyright (C) 2021 The LineageOS Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ - package org.lineageos.eleven.ui.fragments.profile; -import android.app.Activity; import android.os.Bundle; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.TextView; +import androidx.annotation.NonNull; +import androidx.fragment.app.FragmentActivity; import androidx.loader.content.Loader; import org.lineageos.eleven.Config; import org.lineageos.eleven.Config.SmartPlaylistType; import org.lineageos.eleven.R; -import org.lineageos.eleven.adapters.SongAdapter; +import org.lineageos.eleven.adapters.SongListAdapter; import org.lineageos.eleven.loaders.TopTracksLoader; import org.lineageos.eleven.model.Song; import org.lineageos.eleven.sectionadapter.SectionCreator; import org.lineageos.eleven.sectionadapter.SectionListContainer; +import org.lineageos.eleven.ui.MusicHolder; import org.lineageos.eleven.ui.activities.BaseActivity; import org.lineageos.eleven.ui.fragments.ISetupActionBar; import org.lineageos.eleven.utils.MusicUtils; import org.lineageos.eleven.widgets.NoResultsContainer; +import java.util.function.Consumer; + /** * This class is used to display all of the songs the user put on their device * within the last four weeks. @@ -42,16 +50,14 @@ import org.lineageos.eleven.widgets.NoResultsContainer; * @author Andrew Neal (andrewdneal@gmail.com) */ public class TopTracksFragment extends SmartPlaylistFragment -implements ISetupActionBar { + implements ISetupActionBar { @Override protected SmartPlaylistType getSmartPlaylistType() { return Config.SmartPlaylistType.TopTracks; } - /** - * {@inheritDoc} - */ + @NonNull @Override public Loader> onCreateLoader(final int id, final Bundle args) { // show the loading progress bar @@ -63,36 +69,41 @@ implements ISetupActionBar { } @Override - protected SongAdapter createAdapter() { + protected SongListAdapter createAdapter() { return new TopTracksAdapter( - getActivity(), - R.layout.list_item_top_tracks + getActivity(), + R.layout.list_item_top_tracks, + this::onItemClick ); } @Override public final View onCreateView(LayoutInflater inflater, ViewGroup container, - Bundle savedInstanceState) { + Bundle savedInstanceState) { setupActionBar(); return super.onCreateView(inflater, container, savedInstanceState); } public void setupActionBar() { - ((BaseActivity)getActivity()).setupActionBar(R.string.playlist_top_tracks); - ((BaseActivity)getActivity()).setActionBarElevation(true); + final FragmentActivity activity = getActivity(); + if (activity instanceof BaseActivity) { + final BaseActivity baseActivity = (BaseActivity) activity; + baseActivity.setupActionBar(R.string.playlist_top_tracks); + baseActivity.setActionBarElevation(true); + } } - public class TopTracksAdapter extends SongAdapter { - public TopTracksAdapter (final Activity context, final int layoutId) { - super(context, layoutId, getFragmentSourceId(), getFragmentSourceType()); + public class TopTracksAdapter extends SongListAdapter { + public TopTracksAdapter(final FragmentActivity context, final int layoutId, + final Consumer onItemClickListener) { + super(context, layoutId, getFragmentSourceId(), getFragmentSourceType(), + onItemClickListener); } @Override - public View getView(int position, View convertView, ViewGroup parent) { - View view = super.getView(position, convertView, parent); - TextView positionText = (TextView) view.findViewById(R.id.position_number); + protected void customizeBind(@NonNull MusicHolder holder, int position) { + TextView positionText = holder.itemView.findViewById(R.id.position_number); positionText.setText(String.valueOf(position + 1)); - return view; } } @@ -109,11 +120,17 @@ implements ISetupActionBar { return Config.SmartPlaylistType.TopTracks.mId; } - protected int getShuffleTitleId() { return R.string.menu_shuffle_top_tracks; } + protected int getShuffleTitleId() { + return R.string.menu_shuffle_top_tracks; + } @Override - protected int getClearTitleId() { return R.string.clear_top_tracks_title; } + protected int getClearTitleId() { + return R.string.clear_top_tracks_title; + } @Override - protected void clearList() { MusicUtils.clearTopTracks(getActivity()); } + protected void clearList() { + MusicUtils.clearTopTracks(getActivity()); + } } diff --git a/src/org/lineageos/eleven/utils/AlbumPopupMenuHelper.java b/src/org/lineageos/eleven/utils/AlbumPopupMenuHelper.java index 6774fbb10fe8cc541d87d3592d01d33368ae4ab3..1149a12e72c7304e2e70d844d896f648c3b253e8 100644 --- a/src/org/lineageos/eleven/utils/AlbumPopupMenuHelper.java +++ b/src/org/lineageos/eleven/utils/AlbumPopupMenuHelper.java @@ -1,18 +1,19 @@ /* -* Copyright (C) 2014 The CyanogenMod Project -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ + * Copyright (C) 2014 The CyanogenMod Project + * Copyright (C) 2021 The LineageOS Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package org.lineageos.eleven.utils; import android.app.Activity; @@ -84,14 +85,12 @@ public abstract class AlbumPopupMenuHelper extends PopupMenuHelper { public boolean onMenuItemClick(MenuItem item) { boolean handled = super.onMenuItemClick(item); if (!handled && item.getGroupId() == getGroupId()) { - switch (item.getItemId()) { - case FragmentMenuItems.CHANGE_IMAGE: - String key = ImageFetcher.generateAlbumCacheKey(mAlbum.mAlbumName, - getArtistName()); - PhotoSelectionDialog.newInstance(mAlbum.mAlbumName, - PhotoSelectionDialog.ProfileType.ALBUM, key) - .show(mFragmentManager, "PhotoSelectionDialog"); - return true; + if (item.getItemId() == FragmentMenuItems.CHANGE_IMAGE) { + String key = ImageFetcher.generateAlbumCacheKey(mAlbum.mAlbumName, + getArtistName()); + PhotoSelectionDialog.newInstance(mAlbum.mAlbumName, key) + .show(mFragmentManager, "PhotoSelectionDialog"); + return true; } } diff --git a/src/org/lineageos/eleven/utils/AnimatorEndListener.java b/src/org/lineageos/eleven/utils/AnimatorEndListener.java new file mode 100644 index 0000000000000000000000000000000000000000..599ddfc8c2f7d7d73c00afb9d7ebb35b0cbe59cf --- /dev/null +++ b/src/org/lineageos/eleven/utils/AnimatorEndListener.java @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2021 The LineageOS Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.lineageos.eleven.utils; + +import android.animation.Animator; + +public interface AnimatorEndListener extends Animator.AnimatorListener { + + @Override + default void onAnimationStart(Animator animation) { + // Do nothing + } + + @Override + default void onAnimationCancel(Animator animation) { + // Do nothing + } + + @Override + default void onAnimationRepeat(Animator animation) { + // Do nothing + } +} diff --git a/src/org/lineageos/eleven/utils/ArtistPopupMenuHelper.java b/src/org/lineageos/eleven/utils/ArtistPopupMenuHelper.java index eafb0621e7644547fb9ffa2e1dd8033f1f92d3ed..d3428d373da3ce2f8e862ce97c5ec000cde95c9b 100644 --- a/src/org/lineageos/eleven/utils/ArtistPopupMenuHelper.java +++ b/src/org/lineageos/eleven/utils/ArtistPopupMenuHelper.java @@ -1,18 +1,19 @@ /* -* Copyright (C) 2014 The CyanogenMod Project -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ + * Copyright (C) 2014 The CyanogenMod Project + * Copyright (C) 2021 The LineageOS Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package org.lineageos.eleven.utils; import android.app.Activity; @@ -74,15 +75,13 @@ public abstract class ArtistPopupMenuHelper extends PopupMenuHelper { public boolean onMenuItemClick(MenuItem item) { boolean handled = super.onMenuItemClick(item); if (!handled && item.getGroupId() == getGroupId()) { - switch (item.getItemId()) { - case FragmentMenuItems.CHANGE_IMAGE: - PhotoSelectionDialog.newInstance(getArtistName(), - PhotoSelectionDialog.ProfileType.ARTIST, getArtistName()) - .show(mFragmentManager, "PhotoSelectionDialog"); - return true; + if (item.getItemId() == FragmentMenuItems.CHANGE_IMAGE) { + PhotoSelectionDialog.newInstance(getArtistName(), getArtistName()) + .show(mFragmentManager, "PhotoSelectionDialog"); + return true; } } return handled; } -} \ No newline at end of file +} diff --git a/src/org/lineageos/eleven/utils/BitmapUtils.java b/src/org/lineageos/eleven/utils/BitmapUtils.java deleted file mode 100644 index 704e559f1b05fd4a145fb859fadcb8ec0e9a1492..0000000000000000000000000000000000000000 --- a/src/org/lineageos/eleven/utils/BitmapUtils.java +++ /dev/null @@ -1,295 +0,0 @@ -/* - * Copyright (C) 2012 Andrew Neal - * Copyright (C) 2014 The CyanogenMod Project - * Licensed under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law - * or agreed to in writing, software distributed under the License is - * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ - -package org.lineageos.eleven.utils; - -import android.graphics.Bitmap; -import android.graphics.Canvas; -import android.graphics.Paint; - -/** - * {@link Bitmap} specific helpers. - * - * @author Andrew Neal (andrewdneal@gmail.com) - */ -public final class BitmapUtils { - - /* Initial blur radius. */ - private static final int DEFAULT_BLUR_RADIUS = 8; - - /** This class is never instantiated */ - private BitmapUtils() { - } - - /** - * Takes a bitmap and creates a new slightly blurry version of it. - * - * @param sentBitmap The {@link Bitmap} to blur. - * @return A blurred version of the given {@link Bitmap}. - */ - public static final Bitmap createBlurredBitmap(final Bitmap sentBitmap) { - if (sentBitmap == null) { - return null; - } - - // Stack Blur v1.0 from - // http://www.quasimondo.com/StackBlurForCanvas/StackBlurDemo.html - // - // Java Author: Mario Klingemann - // http://incubator.quasimondo.com - // created Feburary 29, 2004 - // Android port : Yahel Bouaziz - // http://www.kayenko.com - // ported april 5th, 2012 - - // This is a compromise between Gaussian Blur and Box blur - // It creates much better looking blurs than Box Blur, but is - // 7x faster than my Gaussian Blur implementation. - // - // I called it Stack Blur because this describes best how this - // filter works internally: it creates a kind of moving stack - // of colors whilst scanning through the image. Thereby it - // just has to add one new block of color to the right side - // of the stack and remove the leftmost color. The remaining - // colors on the topmost layer of the stack are either added on - // or reduced by one, depending on if they are on the right or - // on the left side of the stack. - // - // If you are using this algorithm in your code please add - // the following line: - // - // Stack Blur Algorithm by Mario Klingemann - - final Bitmap mBitmap = sentBitmap.copy(sentBitmap.getConfig(), true); - - final int w = mBitmap.getWidth(); - final int h = mBitmap.getHeight(); - - final int[] pix = new int[w * h]; - mBitmap.getPixels(pix, 0, w, 0, 0, w, h); - - final int wm = w - 1; - final int hm = h - 1; - final int wh = w * h; - final int div = DEFAULT_BLUR_RADIUS + DEFAULT_BLUR_RADIUS + 1; - - final int r[] = new int[wh]; - final int g[] = new int[wh]; - final int b[] = new int[wh]; - final int vmin[] = new int[Math.max(w, h)]; - int rsum, gsum, bsum, x, y, i, p, yp, yi, yw; - - int divsum = div + 1 >> 1; - divsum *= divsum; - final int dv[] = new int[256 * divsum]; - for (i = 0; i < 256 * divsum; i++) { - dv[i] = i / divsum; - } - - yw = yi = 0; - - final int[][] stack = new int[div][3]; - int stackpointer; - int stackstart; - int[] sir; - int rbs; - final int r1 = DEFAULT_BLUR_RADIUS + 1; - int routsum, goutsum, boutsum; - int rinsum, ginsum, binsum; - - for (y = 0; y < h; y++) { - rinsum = ginsum = binsum = routsum = goutsum = boutsum = rsum = gsum = bsum = 0; - for (i = -DEFAULT_BLUR_RADIUS; i <= DEFAULT_BLUR_RADIUS; i++) { - p = pix[yi + Math.min(wm, Math.max(i, 0))]; - sir = stack[i + DEFAULT_BLUR_RADIUS]; - sir[0] = (p & 0xff0000) >> 16; - sir[1] = (p & 0x00ff00) >> 8; - sir[2] = p & 0x0000ff; - rbs = r1 - Math.abs(i); - rsum += sir[0] * rbs; - gsum += sir[1] * rbs; - bsum += sir[2] * rbs; - if (i > 0) { - rinsum += sir[0]; - ginsum += sir[1]; - binsum += sir[2]; - } else { - routsum += sir[0]; - goutsum += sir[1]; - boutsum += sir[2]; - } - } - stackpointer = DEFAULT_BLUR_RADIUS; - - for (x = 0; x < w; x++) { - - r[yi] = dv[rsum]; - g[yi] = dv[gsum]; - b[yi] = dv[bsum]; - - rsum -= routsum; - gsum -= goutsum; - bsum -= boutsum; - - stackstart = stackpointer - DEFAULT_BLUR_RADIUS + div; - sir = stack[stackstart % div]; - - routsum -= sir[0]; - goutsum -= sir[1]; - boutsum -= sir[2]; - - if (y == 0) { - vmin[x] = Math.min(x + DEFAULT_BLUR_RADIUS + 1, wm); - } - p = pix[yw + vmin[x]]; - - sir[0] = (p & 0xff0000) >> 16; - sir[1] = (p & 0x00ff00) >> 8; - sir[2] = p & 0x0000ff; - - rinsum += sir[0]; - ginsum += sir[1]; - binsum += sir[2]; - - rsum += rinsum; - gsum += ginsum; - bsum += binsum; - - stackpointer = (stackpointer + 1) % div; - sir = stack[stackpointer % div]; - - routsum += sir[0]; - goutsum += sir[1]; - boutsum += sir[2]; - - rinsum -= sir[0]; - ginsum -= sir[1]; - binsum -= sir[2]; - - yi++; - } - yw += w; - } - for (x = 0; x < w; x++) { - rinsum = ginsum = binsum = routsum = goutsum = boutsum = rsum = gsum = bsum = 0; - yp = -DEFAULT_BLUR_RADIUS * w; - for (i = -DEFAULT_BLUR_RADIUS; i <= DEFAULT_BLUR_RADIUS; i++) { - yi = Math.max(0, yp) + x; - - sir = stack[i + DEFAULT_BLUR_RADIUS]; - - sir[0] = r[yi]; - sir[1] = g[yi]; - sir[2] = b[yi]; - - rbs = r1 - Math.abs(i); - - rsum += r[yi] * rbs; - gsum += g[yi] * rbs; - bsum += b[yi] * rbs; - - if (i > 0) { - rinsum += sir[0]; - ginsum += sir[1]; - binsum += sir[2]; - } else { - routsum += sir[0]; - goutsum += sir[1]; - boutsum += sir[2]; - } - - if (i < hm) { - yp += w; - } - } - yi = x; - stackpointer = DEFAULT_BLUR_RADIUS; - for (y = 0; y < h; y++) { - pix[yi] = 0xff000000 | dv[rsum] << 16 | dv[gsum] << 8 | dv[bsum]; - - rsum -= routsum; - gsum -= goutsum; - bsum -= boutsum; - - stackstart = stackpointer - DEFAULT_BLUR_RADIUS + div; - sir = stack[stackstart % div]; - - routsum -= sir[0]; - goutsum -= sir[1]; - boutsum -= sir[2]; - - if (x == 0) { - vmin[y] = Math.min(y + r1, hm) * w; - } - p = x + vmin[y]; - - sir[0] = r[p]; - sir[1] = g[p]; - sir[2] = b[p]; - - rinsum += sir[0]; - ginsum += sir[1]; - binsum += sir[2]; - - rsum += rinsum; - gsum += ginsum; - bsum += binsum; - - stackpointer = (stackpointer + 1) % div; - sir = stack[stackpointer]; - - routsum += sir[0]; - goutsum += sir[1]; - boutsum += sir[2]; - - rinsum -= sir[0]; - ginsum -= sir[1]; - binsum -= sir[2]; - - yi += w; - } - } - - mBitmap.setPixels(pix, 0, w, 0, 0, w, h); - return mBitmap; - } - - /** - * This is only used when the launcher shortcut is created. - * - * @param bitmap The artist, album, genre, or playlist image that's going to - * be cropped. - * @param size The new size. - * @return A {@link Bitmap} that has been resized and cropped for a launcher - * shortcut. - */ - public static final Bitmap resizeAndCropCenter(final Bitmap bitmap, final int size) { - final int w = bitmap.getWidth(); - final int h = bitmap.getHeight(); - if (w == size && h == size) { - return bitmap; - } - - final float mScale = (float)size / Math.min(w, h); - - final Bitmap mTarget = Bitmap.createBitmap(size, size, Bitmap.Config.ARGB_8888); - final int mWidth = Math.round(mScale * bitmap.getWidth()); - final int mHeight = Math.round(mScale * bitmap.getHeight()); - final Canvas mCanvas = new Canvas(mTarget); - mCanvas.translate((size - mWidth) / 2f, (size - mHeight) / 2f); - mCanvas.scale(mScale, mScale); - final Paint paint = new Paint(Paint.FILTER_BITMAP_FLAG | Paint.DITHER_FLAG); - mCanvas.drawBitmap(bitmap, 0, 0, paint); - return mTarget; - } -} diff --git a/src/org/lineageos/eleven/utils/ElevenUtils.java b/src/org/lineageos/eleven/utils/ElevenUtils.java index aec0a9fe15c49d0b2fac19f703f1f7a19efb0184..2aa6666e6822f08ab71360e46843a01071a1f26c 100644 --- a/src/org/lineageos/eleven/utils/ElevenUtils.java +++ b/src/org/lineageos/eleven/utils/ElevenUtils.java @@ -1,7 +1,7 @@ /* * Copyright (C) 2012 Andrew Neal * Copyright (C) 2014 The CyanogenMod Project - * Copyright (C) 2018-2020 The LineageOS Project + * Copyright (C) 2018-2021 The LineageOS Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -15,33 +15,23 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package org.lineageos.eleven.utils; -import android.annotation.SuppressLint; import android.app.Activity; import android.content.Context; import android.content.res.Configuration; -import android.database.Cursor; -import android.graphics.Color; import android.graphics.Rect; -import android.net.Uri; import android.os.AsyncTask; -import android.provider.BaseColumns; -import android.provider.MediaStore; -import android.util.Log; import android.util.TypedValue; import android.view.Gravity; import android.view.View; -import android.view.ViewTreeObserver.OnGlobalLayoutListener; import android.widget.Toast; +import androidx.fragment.app.FragmentActivity; + import org.lineageos.eleven.cache.ImageCache; import org.lineageos.eleven.cache.ImageFetcher; -import java.util.concurrent.RejectedExecutionHandler; -import java.util.concurrent.ThreadPoolExecutor; - /** * Mostly general and UI helpers. * @@ -49,48 +39,6 @@ import java.util.concurrent.ThreadPoolExecutor; */ public final class ElevenUtils { - /** - * The threshold used calculate if a color is light or dark - */ - private static final int BRIGHTNESS_THRESHOLD = 130; - - /** - * Because cancelled tasks are not automatically removed from the queue, we can easily - * run over the queue limit - so here we will have a purge policy to purge those tasks - */ - public static class PurgePolicy implements RejectedExecutionHandler { - public void rejectedExecution(Runnable r, ThreadPoolExecutor e) { - // try purging all cancelled work items and re-executing - if (!e.isShutdown()) { - Log.d(PurgePolicy.class.getSimpleName(), "Before Purge: " + e.getQueue().size()); - e.purge(); - Log.d(PurgePolicy.class.getSimpleName(), "After Purge: " + e.getQueue().size()); - e.execute(r); - } - } - }; - - static { - ((ThreadPoolExecutor)AsyncTask.THREAD_POOL_EXECUTOR).setRejectedExecutionHandler( - new PurgePolicy() - ); - } - - /* This class is never initiated */ - public ElevenUtils() { - } - - /** - * Used to determine if the device is a tablet or not - * - * @param context The {@link Context} to use. - * @return True if the device is a tablet, false otherwise. - */ - public static boolean isTablet(final Context context) { - final int layout = context.getResources().getConfiguration().screenLayout; - return (layout & Configuration.SCREENLAYOUT_SIZE_MASK) >= Configuration.SCREENLAYOUT_SIZE_LARGE; - } - /** * Used to determine if the device is currently in landscape mode * @@ -105,19 +53,13 @@ public final class ElevenUtils { /** * Execute an {@link AsyncTask} on a thread pool * - * @param forceSerial True to force the task to run in serial order - * @param task Task to execute - * @param args Optional arguments to pass to - * {@link AsyncTask#execute(Object[])} - * @param Task argument type + * @param task Task to execute + * @param args Optional arguments to pass to + * {@link AsyncTask#execute(Object[])} */ - public static void execute(final boolean forceSerial, final AsyncTask task, - final T... args) { - if (forceSerial) { - task.execute(args); - } else { - task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, args); - } + @SafeVarargs + public static void execute(final AsyncTask task, final T... args) { + task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, args); } /** @@ -130,7 +72,7 @@ public final class ElevenUtils { final int[] screenPos = new int[2]; // origin is device display final Rect displayFrame = new Rect(); // includes decorations (e.g. - // status bar) + // status bar) view.getLocationOnScreen(screenPos); view.getWindowVisibleDisplayFrame(displayFrame); @@ -139,7 +81,8 @@ public final class ElevenUtils { final int viewHeight = view.getHeight(); final int viewCenterX = screenPos[0] + viewWidth / 2; final int screenWidth = context.getResources().getDisplayMetrics().widthPixels; - final int estimatedToastHeight = (int)(48 * context.getResources().getDisplayMetrics().density); + final int estimatedToastHeight = + (int) (48 * context.getResources().getDisplayMetrics().density); final Toast cheatSheet = Toast.makeText(context, view.getContentDescription(), Toast.LENGTH_SHORT); @@ -158,129 +101,30 @@ public final class ElevenUtils { cheatSheet.show(); } - /** - * Calculate whether a color is light or dark, based on a commonly known - * brightness formula. - * - * @see {@literal http://en.wikipedia.org/wiki/HSV_color_space%23Lightness} - */ - public static final boolean isColorDark(final int color) { - return (30 * Color.red(color) + 59 * Color.green(color) + 11 * Color.blue(color)) / 100 <= BRIGHTNESS_THRESHOLD; - } - - /** - * Runs a piece of code after the next layout run - * - * @param view The {@link View} used. - * @param runnable The {@link Runnable} used after the next layout run - */ - @SuppressLint("NewApi") - public static void doAfterLayout(final View view, final Runnable runnable) { - final OnGlobalLayoutListener listener = new OnGlobalLayoutListener() { - @SuppressWarnings("deprecation") - @Override - public void onGlobalLayout() { - /* Layout pass done, unregister for further events */ - view.getViewTreeObserver().removeOnGlobalLayoutListener(this); - runnable.run(); - } - }; - view.getViewTreeObserver().addOnGlobalLayoutListener(listener); - } - /** * Creates a new instance of the {@link ImageCache} and {@link ImageFetcher} * * @param activity The {@link Activity} to use. * @return A new {@link ImageFetcher} used to fetch images asynchronously. */ - public static final ImageFetcher getImageFetcher(final Activity activity) { + public static ImageFetcher getImageFetcher(final FragmentActivity activity) { final ImageFetcher imageFetcher = ImageFetcher.getInstance(activity); imageFetcher.setImageCache(ImageCache.findOrCreateCache(activity)); return imageFetcher; } - /** - * Method that removes the support for HardwareAcceleration from a {@link View}.
- *
- * Check AOSP notice:
- *

-     * 'ComposeShader can only contain shaders of different types (a BitmapShader and a
-     * LinearGradient for instance, but not two instances of BitmapShader)'. But, 'If your
-     * application is affected by any of these missing features or limitations, you can turn
-     * off hardware acceleration for just the affected portion of your application by calling
-     * setLayerType(View.LAYER_TYPE_SOFTWARE, null).'
- * - * @param v The view - */ - public static void removeHardwareAccelerationSupport(View v) { - if (v.getLayerType() != View.LAYER_TYPE_SOFTWARE) { - v.setLayerType(View.LAYER_TYPE_SOFTWARE, null); - } - } - /** * Gets the action bar height in pixels - * @param context + * * @return action bar height in pixels */ public static int getActionBarHeight(Context context) { - TypedValue tv = new TypedValue(); - View view = new View(context); - if (context.getTheme().resolveAttribute(android.R.attr.actionBarSize, tv, true)) { - return TypedValue.complexToDimensionPixelSize(tv.data, context.getResources().getDisplayMetrics()); + final TypedValue tv = new TypedValue(); + if (context.getTheme().resolveAttribute(android.R.attr.actionBarSize, tv, true)) { + return TypedValue.complexToDimensionPixelSize(tv.data, + context.getResources().getDisplayMetrics()); } return 0; } - - /** - * Returns a fancy search query cursor - * @param context - * @param query query string - * @return cursor of the results - */ - public static Cursor createSearchQueryCursor(final Context context, final String query) { - final Uri uri = Uri.parse("content://media/external/audio/search/fancy/" - + Uri.encode(query)); - final String[] projection = new String[] { - BaseColumns._ID, MediaStore.Audio.Media.MIME_TYPE, MediaStore.Audio.Artists.ARTIST, - MediaStore.Audio.Albums.ALBUM, MediaStore.Audio.Media.TITLE, "data1", "data2" - }; - - // no selection/selection/sort args - they are ignored by fancy search anyways - return context.getContentResolver().query(uri, projection, null, null, null); - } - - /** make a useful message from an exception without the stack track */ - public static String formatException(String message, Exception e) { - StringBuilder builder = new StringBuilder(); - if(message != null) { - builder.append(message); - if(e != null) { builder.append(" - "); } - } - - if(e != null) { - builder.append(e.getClass().getSimpleName()); - - String exceptionMessage = e.getMessage(); - if(exceptionMessage != null) { - builder.append(": "); - builder.append(exceptionMessage); - } - - for(Throwable cause = e.getCause(); cause != null; cause = cause.getCause()) { - builder.append(" (cause "); - builder.append(cause.getClass().getSimpleName()); - String causeMessage = e.getMessage(); - if(causeMessage != null) { - builder.append(": "); - builder.append(exceptionMessage); - } - builder.append(")"); - } - } - - return builder.toString(); - } } diff --git a/src/org/lineageos/eleven/utils/EmptyCursor.java b/src/org/lineageos/eleven/utils/EmptyCursor.java new file mode 100644 index 0000000000000000000000000000000000000000..69f27e6394830e08935ae75466e99985696e980d --- /dev/null +++ b/src/org/lineageos/eleven/utils/EmptyCursor.java @@ -0,0 +1,223 @@ +/* + * Copyright (C) 2021 The LineageOS Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.lineageos.eleven.utils; + +import android.content.ContentResolver; +import android.database.CharArrayBuffer; +import android.database.ContentObserver; +import android.database.Cursor; +import android.database.DataSetObserver; +import android.net.Uri; +import android.os.Bundle; + +public class EmptyCursor implements Cursor { + + @Override + public int getCount() { + return 0; + } + + @Override + public int getPosition() { + return 0; + } + + @Override + public boolean move(int offset) { + return false; + } + + @Override + public boolean moveToPosition(int position) { + return false; + } + + @Override + public boolean moveToFirst() { + return false; + } + + @Override + public boolean moveToLast() { + return false; + } + + @Override + public boolean moveToNext() { + return false; + } + + @Override + public boolean moveToPrevious() { + return false; + } + + @Override + public boolean isFirst() { + return false; + } + + @Override + public boolean isLast() { + return false; + } + + @Override + public boolean isBeforeFirst() { + return false; + } + + @Override + public boolean isAfterLast() { + return false; + } + + @Override + public int getColumnIndex(String columnName) { + return 0; + } + + @Override + public int getColumnIndexOrThrow(String columnName) throws IllegalArgumentException { + return 0; + } + + @Override + public String getColumnName(int columnIndex) { + return null; + } + + @Override + public String[] getColumnNames() { + return new String[0]; + } + + @Override + public int getColumnCount() { + return 0; + } + + @Override + public byte[] getBlob(int columnIndex) { + return new byte[0]; + } + + @Override + public String getString(int columnIndex) { + return null; + } + + @Override + public void copyStringToBuffer(int columnIndex, CharArrayBuffer buffer) { + } + + @Override + public short getShort(int columnIndex) { + return 0; + } + + @Override + public int getInt(int columnIndex) { + return 0; + } + + @Override + public long getLong(int columnIndex) { + return 0; + } + + @Override + public float getFloat(int columnIndex) { + return 0; + } + + @Override + public double getDouble(int columnIndex) { + return 0; + } + + @Override + public int getType(int columnIndex) { + return 0; + } + + @Override + public boolean isNull(int columnIndex) { + return false; + } + + @Override + public void deactivate() { + } + + @Override + public boolean requery() { + return false; + } + + @Override + public void close() { + } + + @Override + public boolean isClosed() { + return false; + } + + @Override + public void registerContentObserver(ContentObserver observer) { + } + + @Override + public void unregisterContentObserver(ContentObserver observer) { + } + + @Override + public void registerDataSetObserver(DataSetObserver observer) { + } + + @Override + public void unregisterDataSetObserver(DataSetObserver observer) { + } + + @Override + public void setNotificationUri(ContentResolver cr, Uri uri) { + } + + @Override + public Uri getNotificationUri() { + return null; + } + + @Override + public boolean getWantsAllOnMoveCalls() { + return false; + } + + @Override + public void setExtras(Bundle extras) { + } + + @Override + public Bundle getExtras() { + return null; + } + + @Override + public Bundle respond(Bundle extras) { + return null; + } +} diff --git a/src/org/lineageos/eleven/utils/GenreFetcher.java b/src/org/lineageos/eleven/utils/GenreFetcher.java index f9896c1dbe66aa66e60712d921daca6eb66199e9..df28e75e783cf7688a52eb0dbac1c9f98ed0e865 100644 --- a/src/org/lineageos/eleven/utils/GenreFetcher.java +++ b/src/org/lineageos/eleven/utils/GenreFetcher.java @@ -1,3 +1,19 @@ +/* + * Copyright (C) 2014 The CyanogenMod Project + * Copyright (C) 2021 The LineageOS Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package org.lineageos.eleven.utils; import android.content.Context; @@ -7,20 +23,21 @@ import android.provider.MediaStore; import android.view.View; import android.widget.TextView; +import androidx.annotation.NonNull; import androidx.fragment.app.FragmentActivity; import androidx.loader.app.LoaderManager; import androidx.loader.content.CursorLoader; import androidx.loader.content.Loader; public class GenreFetcher implements LoaderManager.LoaderCallbacks { - private static final String[] GENRE_PROJECTION = new String[] { MediaStore.Audio.Genres.NAME }; + private static final String[] GENRE_PROJECTION = new String[]{MediaStore.Audio.Genres.NAME}; - private Context mContext; - private int mSongId; - private TextView mTextView; + private final Context mContext; + private final int mSongId; + private final TextView mTextView; public static void fetch(FragmentActivity activity, int songId, TextView textView) { - LoaderManager lm = activity.getSupportLoaderManager(); + LoaderManager lm = LoaderManager.getInstance(activity); lm.restartLoader(0, null, new GenreFetcher(activity, songId, textView)); } @@ -30,18 +47,23 @@ public class GenreFetcher implements LoaderManager.LoaderCallbacks { mTextView = textView; } + @NonNull @Override public Loader onCreateLoader(int id, Bundle args) { return new CursorLoader(mContext, - MediaStore.Audio.Genres.getContentUriForAudioId("external", mSongId), - GENRE_PROJECTION, null, null, null); + MediaStore.Audio.Genres.getContentUriForAudioId("external", mSongId), + GENRE_PROJECTION, null, null, null); } @Override - public void onLoadFinished(Loader loader, Cursor cursor) { - if(mTextView != null && cursor.moveToFirst()) { + public void onLoadFinished(@NonNull Loader loader, Cursor cursor) { + if (mTextView == null) { + return; + } + + if (cursor.moveToFirst()) { String genre = cursor.getString(0); - if(!MusicUtils.isBlank(genre)) { + if (!MusicUtils.isBlank(genre)) { mTextView.setText(genre); mTextView.setVisibility(View.VISIBLE); return; @@ -52,5 +74,6 @@ public class GenreFetcher implements LoaderManager.LoaderCallbacks { } @Override - public void onLoaderReset(Loader loader) {} + public void onLoaderReset(@NonNull Loader loader) { + } } diff --git a/src/org/lineageos/eleven/utils/ImageUtils.java b/src/org/lineageos/eleven/utils/ImageUtils.java index 18455ffce8a4d3ca890b84bb83880c4caca07bcc..c8381755b0fc004551ae5bdba1603e995ba67625 100644 --- a/src/org/lineageos/eleven/utils/ImageUtils.java +++ b/src/org/lineageos/eleven/utils/ImageUtils.java @@ -1,82 +1,33 @@ /* -* Copyright (C) 2014 The CyanogenMod Project -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ + * Copyright (C) 2014 The CyanogenMod Project + * Copyright (C) 2021 The LineageOS Project + * Copyright (C) 2021 SHIFT GmbH + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package org.lineageos.eleven.utils; import android.graphics.Bitmap; -import android.graphics.BitmapFactory; +import android.graphics.Canvas; +import android.graphics.drawable.BitmapDrawable; +import android.graphics.drawable.Drawable; import android.widget.ImageView; public class ImageUtils { - private static final int DEFAULT_MAX_IMAGE_HEIGHT = 1024; - - private static final int DEFAULT_MAX_IMAGE_WIDTH = 1024; - /** - * Calculate an inSampleSize for use in a - * {@link android.graphics.BitmapFactory.Options} object when decoding - * bitmaps using the decode* methods from {@link BitmapFactory}. This - * implementation calculates the closest inSampleSize that will result in - * the final decoded bitmap having a width and height equal to or larger - * than the requested width and height. This implementation does not ensure - * a power of 2 is returned for inSampleSize which can be faster when - * decoding but results in a larger bitmap which isn't as useful for caching - * purposes. - * - * @param options An options object with out* params already populated (run - * through a decode* method with inJustDecodeBounds==true - * @param reqWidth The requested width of the resulting bitmap - * @param reqHeight The requested height of the resulting bitmap - * @return The value to be used for inSampleSize - */ - public static final int calculateInSampleSize(final BitmapFactory.Options options, - final int reqWidth, final int reqHeight) { - /* Raw height and width of image */ - final int height = options.outHeight; - final int width = options.outWidth; - int inSampleSize = 1; - - if (height > reqHeight || width > reqWidth) { - if (width > height) { - inSampleSize = Math.round((float)height / (float)reqHeight); - } else { - inSampleSize = Math.round((float)width / (float)reqWidth); - } - - // This offers some additional logic in case the image has a strange - // aspect ratio. For example, a panorama may have a much larger - // width than height. In these cases the total pixels might still - // end up being too large to fit comfortably in memory, so we should - // be more aggressive with sample down the image (=larger - // inSampleSize). - - final float totalPixels = width * height; - - /* More than 2x the requested pixels we'll sample down further */ - final float totalReqPixelsCap = reqWidth * reqHeight * 2; - - while (totalPixels / (inSampleSize * inSampleSize) > totalReqPixelsCap) { - inSampleSize++; - } - } - return inSampleSize; - } - - /** - * Scale the bitmap to an image view. The bitmap will fill the image view bounds. The bitmap will be scaled - * while maintaining the aspect ratio and cropped if it exceeds the image-view bounds. + * Scale the bitmap to an image view. The bitmap will fill the image view bounds. + * The bitmap will be scaled while maintaining the aspect ratio and cropped if it exceeds + * the image-view bounds. */ public static Bitmap scaleBitmapForImageView(Bitmap src, ImageView imageView) { if (src == null || imageView == null) { @@ -93,18 +44,41 @@ public class ImageUtils { int deltaWidth = viewWidth - srcWidth; int deltaHeight = viewHeight - srcHeight; - if (deltaWidth <= 0 && deltaWidth <= 0) // nothing to do if src bitmap is bigger than image-view + if (deltaWidth <= 0 && deltaHeight <= 0) { + // nothing to do if src bitmap is bigger than image-view return src; + } // scale bitmap along the dimension that is lacking the greatest - float scale = Math.max( ((float)viewWidth) / srcWidth, ((float)viewHeight) / srcHeight); + float scale = Math.max(((float) viewWidth) / srcWidth, ((float) viewHeight) / srcHeight); // calculate the new bitmap dimensions int dstHeight = (int) Math.ceil(srcHeight * scale); int dstWidth = (int) Math.ceil(srcWidth * scale); - Bitmap scaledBitmap = Bitmap.createScaledBitmap(src, dstWidth, dstHeight, false); + Bitmap scaledBitmap = Bitmap.createScaledBitmap(src, dstWidth, dstHeight, false); return Bitmap.createBitmap(scaledBitmap, 0, 0, viewWidth, viewHeight); + } + + public static Bitmap drawableToBitmap(Drawable drawable) { + if (drawable instanceof BitmapDrawable) { + BitmapDrawable bitmapDrawable = (BitmapDrawable) drawable; + if (bitmapDrawable.getBitmap() != null) { + return bitmapDrawable.getBitmap(); + } + } + + final Bitmap bitmap; + if (drawable.getIntrinsicWidth() <= 0 || drawable.getIntrinsicHeight() <= 0) { + bitmap = Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888); + } else { + bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(), + drawable.getIntrinsicHeight(), Bitmap.Config.ARGB_8888); + } + final Canvas canvas = new Canvas(bitmap); + drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight()); + drawable.draw(canvas); + return bitmap; } } diff --git a/src/org/lineageos/eleven/utils/Lists.java b/src/org/lineageos/eleven/utils/Lists.java index f48005c0b048bc4644020139008e42794b7e7ea9..11a79cfe55f7bcae32618e7e8eb5f08f1ffbe7c3 100644 --- a/src/org/lineageos/eleven/utils/Lists.java +++ b/src/org/lineageos/eleven/utils/Lists.java @@ -1,14 +1,19 @@ /* - * Copyright 2012 Google Inc. Licensed under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law - * or agreed to in writing, software distributed under the License is - * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the specific language - * governing permissions and limitations under the License. + * Copyright (C) 2012 Google Inc. + * Copyright (C) 2021 The LineageOS Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ - package org.lineageos.eleven.utils; import java.util.ArrayList; @@ -21,10 +26,6 @@ import java.util.LinkedList; */ public final class Lists { - /** This class is never instantiated */ - public Lists() { - } - /** * Creates an empty {@code ArrayList} instance. *

@@ -33,7 +34,7 @@ public final class Lists { * * @return a newly-created, initially-empty {@code ArrayList} */ - public static final ArrayList newArrayList() { + public static ArrayList newArrayList() { return new ArrayList<>(); } @@ -45,8 +46,7 @@ public final class Lists { * * @return a newly-created, initially-empty {@code LinkedList} */ - public static final LinkedList newLinkedList() { + public static LinkedList newLinkedList() { return new LinkedList<>(); } - } diff --git a/src/org/lineageos/eleven/utils/MusicUtils.java b/src/org/lineageos/eleven/utils/MusicUtils.java index 8d30f84c9a8aaa0a9d76984d44a17c326834b4ed..9c2c749631e51c1958ae8adbe6df5f66e56a7b62 100644 --- a/src/org/lineageos/eleven/utils/MusicUtils.java +++ b/src/org/lineageos/eleven/utils/MusicUtils.java @@ -1,7 +1,7 @@ /* * Copyright (C) 2012 Andrew Neal * Copyright (C) 2014 The CyanogenMod Project - * Copyright (C) 2018-2020 The LineageOS Project + * Copyright (C) 2018-2021 The LineageOS Project * Copyright (C) 2019 SHIFT GmbH * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -16,10 +16,8 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package org.lineageos.eleven.utils; -import android.app.Activity; import android.content.ComponentName; import android.content.ContentResolver; import android.content.ContentUris; @@ -46,6 +44,7 @@ import android.widget.Toast; import androidx.annotation.NonNull; import androidx.annotation.WorkerThread; +import androidx.fragment.app.FragmentActivity; import org.lineageos.eleven.BuildConfig; import org.lineageos.eleven.Config.IdType; @@ -87,16 +86,15 @@ public final class MusicUtils { public static final String TAG = MusicUtils.class.getSimpleName(); private static final long[] sEmptyList; - private static Set> sKnownTokens = new HashSet<>(); + private static final Set> sKnownTokens = new HashSet<>(); private static ContentValues[] mContentValuesCache = null; private static final int MIN_VALID_YEAR = 1900; // used to remove invalid years from metadata public static final String MUSIC_ONLY_SELECTION = MediaStore.Audio.AudioColumns.IS_MUSIC + "=1" - + " AND " + MediaStore.Audio.AudioColumns.TITLE + " != ''"; //$NON-NLS-2$ + + " AND " + MediaStore.Audio.AudioColumns.TITLE + " != ''"; //$NON-NLS-2$ public static final long UPDATE_FREQUENCY_MS = 500; - public static final long UPDATE_FREQUENCY_FAST_MS = 30; static { sEmptyList = new long[0]; @@ -107,12 +105,12 @@ public final class MusicUtils { } /** - * @param context The {@link Context} to use + * @param context The {@link Context} to use * @param callback The {@link ServiceConnection} to use * @return The new instance of {@link ServiceToken} */ public static ServiceToken bindToService(final Context context, - final ServiceConnection callback) { + final ServiceConnection callback) { final ServiceBinder binder = new ServiceBinder(callback); final Intent intent = new Intent(context, MusicPlaybackService.class); final int flags = Context.BIND_ADJUST_WITH_ACTIVITY | Context.BIND_AUTO_CREATE; @@ -182,7 +180,7 @@ public final class MusicUtils { * Constructor of ServiceToken * * @param context The context for the bind operation - * @param binder The {@link ServiceBinder} this token references + * @param binder The {@link ServiceBinder} this token references */ private ServiceToken(final Context context, final ServiceBinder binder) { mContextRef = new WeakReference<>(context); @@ -207,6 +205,7 @@ public final class MusicUtils { } return null; } + public static boolean isPlaybackServiceConnected() { return getService() != null; } @@ -215,14 +214,14 @@ public final class MusicUtils { * Used to make number of labels for the number of artists, albums, songs, * genres, and playlists. * - * @param context The {@link Context} to use. + * @param context The {@link Context} to use. * @param pluralInt The ID of the plural string to use. - * @param number The number of artists, albums, songs, genres, or playlists. + * @param number The number of artists, albums, songs, genres, or playlists. * @return A {@link String} used as a label for the number of artists, - * albums, songs, genres, and playlists. + * albums, songs, genres, and playlists. */ public static String makeLabel(final Context context, final int pluralInt, - final int number) { + final int number) { return context.getResources().getQuantityString(pluralInt, number, number); } @@ -230,7 +229,7 @@ public final class MusicUtils { * * Used to create a formatted time string for the duration of tracks. * * @param context The {@link Context} to use. - * @param secs The track in seconds. + * @param secs The track in seconds. * @return Duration of a track that's properly formatted. */ @NonNull @@ -251,7 +250,7 @@ public final class MusicUtils { * Used to create a formatted time string in the format of #h #m or #m if there is only minutes * * @param context The {@link Context} to use. - * @param secs The duration seconds. + * @param secs The duration seconds. * @return Duration properly formatted in #h #m format */ public static String makeLongTimeString(final Context context, long secs) { @@ -261,8 +260,8 @@ public final class MusicUtils { secs %= 3600; mins = secs / 60; - String hoursString = MusicUtils.makeLabel(context, R.plurals.Nhours, (int)hours); - String minutesString = MusicUtils.makeLabel(context, R.plurals.Nminutes, (int)mins); + String hoursString = MusicUtils.makeLabel(context, R.plurals.Nhours, (int) hours); + String minutesString = MusicUtils.makeLabel(context, R.plurals.Nminutes, (int) mins); if (hours == 0) { return minutesString; @@ -278,12 +277,12 @@ public final class MusicUtils { * Used to combine two strings with some kind of separator in between * * @param context The {@link Context} to use. - * @param first string to combine - * @param second string to combine + * @param first string to combine + * @param second string to combine * @return the combined string */ public static String makeCombinedString(final Context context, final String first, - final String second) { + final String second) { final String formatter = context.getResources().getString(R.string.combine_two_strings); return String.format(formatter, first, second); } @@ -314,16 +313,17 @@ public final class MusicUtils { /** * Changes to the previous track. * - * @NOTE The AIDL isn't used here in order to properly use the previous - * action. When the user is shuffling, because {@link - * MusicPlaybackService#openCurrentAndNext()} is used, the user won't - * be able to travel to the previously skipped track. To remedy this, - * {@link MusicPlaybackService#openCurrent()} is called in {@link - * MusicPlaybackService#prev(boolean)}. {@code #startService(Intent intent)} - * is called here to specifically invoke the onStartCommand used by - * {@link MusicPlaybackService}, which states if the current position - * less than 2000 ms, start the track over, otherwise move to the - * previously listened track. + *

+ * NOTE The AIDL isn't used here in order to properly use the previous + * action. When the user is shuffling, because + * MusicPlaybackService#openCurrentAndNext() is used, the user won't + * be able to travel to the previously skipped track. To remedy this, + * MusicPlaybackService#openCurrent() is called in {@link + * MusicPlaybackService#prev(boolean)}. {@code #startService(Intent intent)} + * is called here to specifically invoke the onStartCommand used by + * {@link MusicPlaybackService}, which states if the current position + * less than 2000 ms, start the track over, otherwise move to the + * previously listened track. */ public static void previous(final Context context, final boolean force) { final Intent previous = new Intent(context, MusicPlaybackService.class); @@ -358,22 +358,20 @@ public final class MusicUtils { */ public static void cycleRepeat() { try { - IElevenService service = getService(); - if (service != null) { - switch (service.getRepeatMode()) { - case MusicPlaybackService.REPEAT_NONE: - service.setRepeatMode(MusicPlaybackService.REPEAT_ALL); - break; - case MusicPlaybackService.REPEAT_ALL: - service.setRepeatMode(MusicPlaybackService.REPEAT_CURRENT); - if (service.getShuffleMode() != MusicPlaybackService.SHUFFLE_NONE) { - service.setShuffleMode(MusicPlaybackService.SHUFFLE_NONE); - } - break; - default: - service.setRepeatMode(MusicPlaybackService.REPEAT_NONE); - break; + final IElevenService service = getService(); + if (service == null) { + return; + } + final int repeatMode = service.getRepeatMode(); + if (repeatMode == MusicPlaybackService.REPEAT_NONE) { + service.setRepeatMode(MusicPlaybackService.REPEAT_ALL); + } else if (repeatMode == MusicPlaybackService.REPEAT_ALL) { + service.setRepeatMode(MusicPlaybackService.REPEAT_CURRENT); + if (service.getShuffleMode() != MusicPlaybackService.SHUFFLE_NONE) { + service.setShuffleMode(MusicPlaybackService.SHUFFLE_NONE); } + } else { + service.setRepeatMode(MusicPlaybackService.REPEAT_NONE); } } catch (final RemoteException exc) { Log.e(TAG, "cycleRepeat()", exc); @@ -385,24 +383,20 @@ public final class MusicUtils { */ public static void cycleShuffle() { try { - IElevenService service = getService(); - if (service != null) { - switch (service.getShuffleMode()) { - case MusicPlaybackService.SHUFFLE_NONE: - service.setShuffleMode(MusicPlaybackService.SHUFFLE_NORMAL); - if (service.getRepeatMode() == MusicPlaybackService.REPEAT_CURRENT) { - service.setRepeatMode(MusicPlaybackService.REPEAT_ALL); - } - break; - case MusicPlaybackService.SHUFFLE_NORMAL: - service.setShuffleMode(MusicPlaybackService.SHUFFLE_NONE); - break; - case MusicPlaybackService.SHUFFLE_AUTO: - service.setShuffleMode(MusicPlaybackService.SHUFFLE_NONE); - break; - default: - break; + final IElevenService service = getService(); + if (service == null) { + return; + } + final int shuffleMode = service.getShuffleMode(); + if (shuffleMode == MusicPlaybackService.SHUFFLE_NONE) { + service.setShuffleMode(MusicPlaybackService.SHUFFLE_NORMAL); + if (service.getRepeatMode() == MusicPlaybackService.REPEAT_CURRENT) { + service.setRepeatMode(MusicPlaybackService.REPEAT_ALL); } + } else if (shuffleMode == MusicPlaybackService.SHUFFLE_NORMAL) { + service.setShuffleMode(MusicPlaybackService.SHUFFLE_NONE); + } else if (shuffleMode == MusicPlaybackService.SHUFFLE_AUTO) { + service.setShuffleMode(MusicPlaybackService.SHUFFLE_NONE); } } catch (final RemoteException exc) { Log.e(TAG, "cycleShuffle()", exc); @@ -574,36 +568,6 @@ public final class MusicUtils { return -1; } - /** - * @return The previous song Id. - */ - public static long getPreviousAudioId() { - IElevenService service = getService(); - if (service != null) { - try { - return service.getPreviousAudioId(); - } catch (final RemoteException exc) { - Log.e(TAG, "getPreviousAudioId()", exc); - } - } - return -1; - } - - /** - * @return The current artist Id. - */ - public static long getCurrentArtistId() { - IElevenService service = getService(); - if (service != null) { - try { - return service.getArtistId(); - } catch (final RemoteException exc) { - Log.e(TAG, "getArtistId()", exc); - } - } - return -1; - } - /** * @return The audio session Id. */ @@ -709,21 +673,6 @@ public final class MusicUtils { return -1; } - /** - * @return The queue history - */ - public static int[] getQueueHistoryList() { - IElevenService service = getService(); - if (service != null) { - try { - return service.getQueueHistoryList(); - } catch (final RemoteException exc) { - Log.e(TAG, "getQueueHistoryList()", exc); - } - } - return null; - } - /** * @param id The ID of the track to remove. * @return removes track from a playlist or the queue. @@ -743,9 +692,8 @@ public final class MusicUtils { /** * Remove song at a specified position in the list * - * @param id The ID of the track to remove + * @param id The ID of the track to remove * @param position The position of the song - * * @return true if successful, false otherwise */ public static boolean removeTrackAtPosition(final long id, final int position) { @@ -771,7 +719,7 @@ public final class MusicUtils { final int len = cursor.getCount(); final long[] list = new long[len]; cursor.moveToFirst(); - int columnIndex = -1; + int columnIndex; try { columnIndex = cursor.getColumnIndexOrThrow(MediaStore.Audio.Playlists.Members.AUDIO_ID); } catch (final IllegalArgumentException notaplaylist) { @@ -790,12 +738,12 @@ public final class MusicUtils { /** * @param context The {@link Context} to use. - * @param id The ID of the artist. + * @param id The ID of the artist. * @return The song list for an artist. */ public static long[] getSongListForArtist(final Context context, final long id) { final String selection = AudioColumns.ARTIST_ID + "=" + id + " AND " - + AudioColumns.IS_MUSIC + "=1"; + + AudioColumns.IS_MUSIC + "= 1"; try (Cursor cursor = SongLoader.makeSongCursor(context, selection)) { if (cursor != null) { return getSongListForCursor(cursor); @@ -806,7 +754,7 @@ public final class MusicUtils { /** * @param context The {@link Context} to use. - * @param id The ID of the album. + * @param id The ID of the album. * @return The song list for an album. */ public static long[] getSongListForAlbum(final Context context, final long id) { @@ -821,74 +769,24 @@ public final class MusicUtils { /** * Plays songs by an artist. * - * @param context The {@link Context} to use. + * @param context The {@link Context} to use. * @param artistId The artist Id. * @param position Specify where to start. */ - public static void playArtist(final Context context, final long artistId, int position, boolean shuffle) { + public static void playArtist(final Context context, final long artistId, int position, + boolean shuffle) { final long[] artistList = getSongListForArtist(context, artistId); if (artistList != null) { - playAll(context, artistList, position, artistId, IdType.Artist, shuffle); + playAll(artistList, position, artistId, IdType.Artist, shuffle); } } /** - * @param context The {@link Context} to use. - * @param id The ID of the genre. - * @return The song list for an genre. - */ - public static long[] getSongListForGenre(final Context context, final long id) { - final String[] projection = new String[] { - BaseColumns._ID - }; - String selection = (AudioColumns.IS_MUSIC + "=1") + - " AND " + MediaColumns.TITLE + "!=''"; - final Uri uri = MediaStore.Audio.Genres.Members.getContentUri("external", id); - try (Cursor cursor = context.getContentResolver().query(uri, projection, selection, - null, null)) { - if (cursor != null) { - return getSongListForCursor(cursor); - } - } - return sEmptyList; - } - - /** - * @param context The {@link Context} to use - * @param uri The source of the file - */ - public static void playFile(final Context context, final Uri uri) { - IElevenService service = getService(); - if (uri == null || service == null) { - return; - } - - // If this is a file:// URI, just use the path directly instead - // of going through the open-from-filedescriptor codepath. - String filename; - String scheme = uri.getScheme(); - if ("file".equals(scheme)) { - filename = uri.getPath(); - } else { - filename = uri.toString(); - } - - try { - service.stop(); - service.openFile(filename); - service.play(); - } catch (final RemoteException exc) { - Log.e(TAG, "playFile(" + uri + ")", exc); - } - } - - /** - * @param context The {@link Context} to use. - * @param list The list of songs to play. - * @param position Specify where to start. + * @param list The list of songs to play. + * @param position Specify where to start. * @param forceShuffle True to force a shuffle, false otherwise. */ - public static void playAll(final Context context, final long[] list, int position, + public static void playAll(final long[] list, int position, final long sourceId, final IdType sourceType, final boolean forceShuffle) { IElevenService service = getService(); @@ -920,7 +818,8 @@ public final class MusicUtils { try { service.enqueue(list, MusicPlaybackService.NEXT, sourceId, sourceType.mId); } catch (final RemoteException exc) { - Log.e(TAG, "playNext(" + Arrays.asList(list) + ", " + sourceId + ", " + sourceType + ")", exc); + Log.e(TAG, "playNext(" + Collections.singletonList(list) + ", " + + sourceId + ", " + sourceType + ")", exc); } } @@ -961,13 +860,16 @@ public final class MusicUtils { * Returns The ID for a playlist. * * @param context The {@link Context} to use. - * @param name The name of the playlist. + * @param name The name of the playlist. * @return The ID for a playlist. */ public static long getIdForPlaylist(final Context context, final String name) { if (BuildConfig.DEBUG) { Log.d(TAG, "getIdForPlaylist(" + name + ")"); } + if (name == null) { + return -1; + } try (Cursor cursor = context.getContentResolver().query(Playlists.EXTERNAL_CONTENT_URI, new String[]{BaseColumns._ID}, PlaylistsColumns.NAME + "=?", @@ -982,9 +884,11 @@ public final class MusicUtils { return -1; } - /** @param context The {@link Context} to use. - * @param id The id of the playlist. - * @return The name for a playlist. */ + /** + * @param context The {@link Context} to use. + * @param id The id of the playlist. + * @return The name for a playlist. + */ public static String getNameForPlaylist(final Context context, final long id) { try (Cursor cursor = context.getContentResolver().query( Playlists.EXTERNAL_CONTENT_URI, new String[]{PlaylistsColumns.NAME}, @@ -1003,10 +907,13 @@ public final class MusicUtils { * Returns the Id for an artist. * * @param context The {@link Context} to use. - * @param name The name of the artist. + * @param name The name of the artist. * @return The ID for an artist. */ public static long getIdForArtist(final Context context, final String name) { + if (name == null) { + return -1; + } try (Cursor cursor = context.getContentResolver().query( MediaStore.Audio.Artists.EXTERNAL_CONTENT_URI, new String[]{BaseColumns._ID}, ArtistColumns.ARTIST + "=?", new String[]{name}, ArtistColumns.ARTIST)) { @@ -1020,46 +927,23 @@ public final class MusicUtils { return -1; } - /** - * Returns the ID for an album. - * - * @param context The {@link Context} to use. - * @param albumName The name of the album. - * @param artistName The name of the artist - * @return The ID for an album. - */ - public static long getIdForAlbum(final Context context, final String albumName, - final String artistName) { - try (Cursor cursor = context.getContentResolver().query( - MediaStore.Audio.Albums.EXTERNAL_CONTENT_URI, new String[]{BaseColumns._ID}, - AlbumColumns.ALBUM + "=? AND " + AlbumColumns.ARTIST + "=?", new String[]{ - albumName, artistName - }, AlbumColumns.ALBUM)) { - if (cursor != null) { - cursor.moveToFirst(); - if (!cursor.isAfterLast()) { - return cursor.getInt(0); - } - } - } - return -1; - } - /** * Plays songs from an album. * - * @param context The {@link Context} to use. - * @param albumId The album Id. + * @param context The {@link Context} to use. + * @param albumId The album Id. * @param position Specify where to start. */ - public static void playAlbum(final Context context, final long albumId, int position, boolean shuffle) { + public static void playAlbum(final Context context, final long albumId, int position, + boolean shuffle) { final long[] albumList = getSongListForAlbum(context, albumId); if (albumList != null) { - playAll(context, albumList, position, albumId, IdType.Album, shuffle); + playAll(albumList, position, albumId, IdType.Album, shuffle); } } - public static void makeInsertItems(final long[] ids, final int offset, int len, final int base) { + public static void makeInsertItems(final long[] ids, final int offset, int len, + final int base) { if (offset + len > ids.length) { len = ids.length - offset; } @@ -1078,14 +962,14 @@ public final class MusicUtils { /** * @param context The {@link Context} to use. - * @param name The name of the new playlist. + * @param name The name of the new playlist. * @return A new playlist ID. */ public static long createPlaylist(final Context context, final String name) { if (name != null && name.length() > 0) { final ContentResolver resolver = context.getContentResolver(); - final String[] projection = new String[] { - PlaylistsColumns.NAME + final String[] projection = new String[]{ + PlaylistsColumns.NAME }; final String selection = PlaylistsColumns.NAME + " = '" + name + "'"; try (Cursor cursor = resolver.query(Playlists.EXTERNAL_CONTENT_URI, @@ -1108,7 +992,7 @@ public final class MusicUtils { } /** - * @param context The {@link Context} to use. + * @param context The {@link Context} to use. * @param playlistId The playlist ID. */ public static void clearPlaylist(final Context context, final int playlistId) { @@ -1116,32 +1000,39 @@ public final class MusicUtils { context.getContentResolver().delete(uri, null, null); } - /** remove all backing data for top tracks playlist */ + /** + * remove all backing data for top tracks playlist + */ public static void clearTopTracks(Context context) { SongPlayCount.getInstance(context).deleteAll(); } - /** remove all backing data for top tracks playlist */ + /** + * remove all backing data for top tracks playlist + */ public static void clearRecent(Context context) { RecentStore.getInstance(context).deleteAll(); } - /** move up cutoff for last added songs so playlist will be cleared */ + /** + * move up cutoff for last added songs so playlist will be cleared + */ public static void clearLastAdded(Context context) { PreferenceUtils.getInstance(context) - .setLastAddedCutoff(System.currentTimeMillis()); + .setLastAddedCutoff(System.currentTimeMillis()); } /** - * @param context The {@link Context} to use. - * @param ids The id of the song(s) to add. + * @param context The {@link Context} to use. + * @param ids The id of the song(s) to add. * @param playlistid The id of the playlist being added to. */ - public static void addToPlaylist(final Context context, final long[] ids, final long playlistid) { + public static void addToPlaylist(final Context context, final long[] ids, + final long playlistid) { final int size = ids.length; final ContentResolver resolver = context.getContentResolver(); - final String[] projection = new String[] { - "max(" + Playlists.Members.PLAY_ORDER + ")", + final String[] projection = new String[]{ + "max(" + Playlists.Members.PLAY_ORDER + ")", }; final Uri uri = MediaStore.Audio.Playlists.Members.getContentUri("external", playlistid); @@ -1165,16 +1056,17 @@ public final class MusicUtils { /** * Removes a single track from a given playlist - * @param context The {@link Context} to use. - * @param id The id of the song to remove. + * + * @param context The {@link Context} to use. + * @param id The id of the song to remove. * @param playlistId The id of the playlist being removed from. */ public static void removeFromPlaylist(final Context context, final long id, - final long playlistId) { + final long playlistId) { final Uri uri = MediaStore.Audio.Playlists.Members.getContentUri("external", playlistId); final ContentResolver resolver = context.getContentResolver(); - resolver.delete(uri, Playlists.Members.AUDIO_ID + " = ? ", new String[] { - Long.toString(id) + resolver.delete(uri, Playlists.Members.AUDIO_ID + " = ? ", new String[]{ + Long.toString(id) }); final String message = context.getResources().getQuantityString( R.plurals.NNNtracksfromplaylist, 1, 1); @@ -1184,7 +1076,7 @@ public final class MusicUtils { /** * @param context The {@link Context} to use. - * @param list The list to enqueue. + * @param list The list to enqueue. */ public static void addToQueue(final Context context, final long[] list, long sourceId, IdType sourceType) { @@ -1203,7 +1095,7 @@ public final class MusicUtils { /** * @param context The {@link Context} to use - * @param id The song ID. + * @param id The song ID. */ public static void setRingtone(final Context context, final long id) { final ContentResolver resolver = context.getContentResolver(); @@ -1217,7 +1109,7 @@ public final class MusicUtils { return; } - final String[] projection = new String[] { + final String[] projection = new String[]{ BaseColumns._ID, MediaColumns.DATA, MediaColumns.TITLE }; @@ -1236,12 +1128,14 @@ public final class MusicUtils { /** * @param context The {@link Context} to use. - * @param id The id of the album. + * @param id The id of the album. * @return The song count for an album. */ public static int getSongCountForAlbumInt(final Context context, final long id) { int songCount = 0; - if (id == -1) { return songCount; } + if (id == -1) { + return songCount; + } Uri uri = ContentUris.withAppendedId(MediaStore.Audio.Albums.EXTERNAL_CONTENT_URI, id); try (Cursor cursor = context.getContentResolver().query(uri, @@ -1261,7 +1155,8 @@ public final class MusicUtils { /** * Gets the number of songs for a playlist - * @param context The {@link Context} to use. + * + * @param context The {@link Context} to use. * @param playlistId the id of the playlist * @return the # of songs in the playlist */ @@ -1285,15 +1180,15 @@ public final class MusicUtils { " AND " + BaseColumns._ID + " = '" + trackId + "'"; final Cursor cursor = context.getContentResolver().query( - MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, - new String[] { - /* 0 */ - MediaStore.Audio.AudioColumns.ALBUM_ID, - /* 1 */ - MediaStore.Audio.AudioColumns.ALBUM, - /* 2 */ - MediaStore.Audio.AlbumColumns.ARTIST, - }, selection, null, null + MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, + new String[]{ + /* 0 */ + MediaStore.Audio.AudioColumns.ALBUM_ID, + /* 1 */ + MediaStore.Audio.AudioColumns.ALBUM, + /* 2 */ + MediaStore.Audio.AlbumColumns.ARTIST, + }, selection, null, null ); if (cursor == null) { @@ -1318,7 +1213,7 @@ public final class MusicUtils { /** * @param context The {@link Context} to use. - * @param id The id of the album. + * @param id The id of the album. * @return The release date for an album. */ public static String getReleaseDateForAlbum(final Context context, final long id) { @@ -1327,7 +1222,7 @@ public final class MusicUtils { } Uri uri = ContentUris.withAppendedId(MediaStore.Audio.Albums.EXTERNAL_CONTENT_URI, id); String releaseDate = null; - try (Cursor cursor = context.getContentResolver().query(uri, new String[] { + try (Cursor cursor = context.getContentResolver().query(uri, new String[]{ AlbumColumns.FIRST_YEAR }, null, null, null)) { if (cursor != null) { @@ -1340,24 +1235,9 @@ public final class MusicUtils { return releaseDate; } - /** - * @return The path to the currently playing file as {@link String} - */ - public static String getFilePath() { - try { - IElevenService service = getService(); - if (service != null) { - return service.getPath(); - } - } catch (final RemoteException exc) { - Log.e(TAG, "getFilePath()", exc); - } - return null; - } - /** * @param from The index the item is currently at. - * @param to The index the item is moving to. + * @param to The index the item is moving to. */ public static void moveQueueItem(final int from, final int to) { try { @@ -1371,7 +1251,7 @@ public final class MusicUtils { } /** - * @param context The {@link Context} to sue + * @param context The {@link Context} to sue * @param playlistId The playlist Id * @return The track list for a playlist */ @@ -1387,23 +1267,23 @@ public final class MusicUtils { /** * Plays a user created playlist. * - * @param context The {@link Context} to use. + * @param context The {@link Context} to use. * @param playlistId The playlist Id. */ public static void playPlaylist(final Context context, final long playlistId, boolean shuffle) { final long[] playlistList = getSongListForPlaylist(context, playlistId); if (playlistList != null) { - playAll(context, playlistList, -1, playlistId, IdType.Playlist, shuffle); + playAll(playlistList, -1, playlistId, IdType.Playlist, shuffle); } } /** * @param context The {@link Context} to use - * @param type The Smart Playlist Type + * @param type The Smart Playlist Type * @return The song list for the last added playlist */ public static long[] getSongListForSmartPlaylist(final Context context, - final SmartPlaylistType type) { + final SmartPlaylistType type) { Cursor cursor = null; try { switch (type) { @@ -1425,18 +1305,6 @@ public final class MusicUtils { } } - /** - * Plays the smart playlist - * @param context The {@link Context} to use - * @param position the position to start playing from - * @param type The Smart Playlist Type - */ - public static void playSmartPlaylist(final Context context, final int position, - final SmartPlaylistType type, final boolean shuffle) { - final long[] list = getSongListForSmartPlaylist(context, type); - MusicUtils.playAll(context, list, position, type.mId, IdType.Playlist, shuffle); - } - /** * Creates a map used to add items to a new playlist or an existing one. * @@ -1458,9 +1326,7 @@ public final class MusicUtils { } // sort the list but ignore case - Collections.sort(menuItemMap, new IgnoreCaseComparator()); - // add new_playlist to the top of the sorted list - //menuItemMap.add(0, context.getString(R.string.new_playlist)); + menuItemMap.sort(new IgnoreCaseComparator()); return menuItemMap; } @@ -1520,9 +1386,7 @@ public final class MusicUtils { if (service != null) { try { service.seekRelative(deltaInMs); - } catch (final RemoteException exc) { - Log.e(TAG, "seekRelative(" + deltaInMs + ")", exc); - } catch (final IllegalStateException exc) { + } catch (final RemoteException | IllegalStateException exc) { Log.e(TAG, "seekRelative(" + deltaInMs + ")", exc); } } @@ -1536,9 +1400,7 @@ public final class MusicUtils { if (service != null) { try { return service.position(); - } catch (final RemoteException exc) { - Log.e(TAG, "position()", exc); - } catch (final IllegalStateException exc) { + } catch (final RemoteException | IllegalStateException exc) { Log.e(TAG, "position()", exc); } } @@ -1553,9 +1415,7 @@ public final class MusicUtils { if (service != null) { try { return service.duration(); - } catch (final RemoteException exc) { - Log.e(TAG, "duration()", exc); - } catch (final IllegalStateException exc) { + } catch (final RemoteException | IllegalStateException exc) { Log.e(TAG, "duration()", exc); } } @@ -1596,13 +1456,13 @@ public final class MusicUtils { } /** - * Perminately deletes item(s) from the user's device + * Permanently deletes item(s) from the user's device * * @param context The {@link Context} to use. - * @param list The item(s) to delete. + * @param list The item(s) to delete. */ public static void deleteTracks(final Context context, final long[] list) { - final String[] projection = new String[] { + final String[] projection = new String[]{ BaseColumns._ID, MediaColumns.DATA, AudioColumns.ALBUM_ID }; final StringBuilder selection = new StringBuilder(); @@ -1668,6 +1528,7 @@ public final class MusicUtils { /** * Simple function used to determine if the song/album year is invalid + * * @param year value to test * @return true if the app considers it valid */ @@ -1679,6 +1540,7 @@ public final class MusicUtils { * A snippet is taken from MediaStore.Audio.keyFor method * This will take a name, removes things like "the", "an", etc * as well as special characters and return it + * * @param name the string to trim * @return the trimmed name */ @@ -1702,7 +1564,7 @@ public final class MusicUtils { name.endsWith(", a") || name.endsWith(",a")) { name = name.substring(0, name.lastIndexOf(',')); } - name = name.replaceAll("[\\[\\]\\(\\)\"'.,?!]", "").trim(); + name = name.replaceAll("[\\[\\]()\"'.,?!]", "").trim(); return name; } @@ -1711,6 +1573,7 @@ public final class MusicUtils { * A snippet is taken from MediaStore.Audio.keyFor method * This will take a name, removes things like "the", "an", etc * as well as special characters, then find the localized label + * * @param name Name to get the label of * @return the localized label of the bucket that the name falls into */ @@ -1728,13 +1591,21 @@ public final class MusicUtils { return null; } - /** @return true if a string is null, empty, or contains only whitespace */ + /** + * @return true if a string is null, empty, or contains only whitespace + */ public static boolean isBlank(String s) { - if(s == null) { return true; } - if(s.isEmpty()) { return true; } - for(int i = 0; i < s.length(); i++) { + if (s == null) { + return true; + } + if (s.isEmpty()) { + return true; + } + for (int i = 0; i < s.length(); i++) { char c = s.charAt(i); - if(!Character.isWhitespace(c)) { return false; } + if (!Character.isWhitespace(c)) { + return false; + } } return true; } @@ -1743,7 +1614,7 @@ public final class MusicUtils { * Removes the header image from the cache. */ @WorkerThread - public static void removeFromCache(Activity activity, String key) { + public static void removeFromCache(FragmentActivity activity, String key) { ImageFetcher imageFetcher = ElevenUtils.getImageFetcher(activity); imageFetcher.removeFromCache(key); @@ -1755,26 +1626,25 @@ public final class MusicUtils { /** * Removes image from cache so that the stock image is retrieved on reload */ - public static void selectOldPhoto(Activity activity, String key) { + public static void selectOldPhoto(FragmentActivity activity, String key) { // First remove the old image removeFromCache(activity, key); MusicUtils.refresh(); } /** - * * @param sortOrder values are mostly derived from SortOrder.class or could also be any sql * order clause - * @return */ - public static boolean isSortOrderDesending(String sortOrder) { + public static boolean isSortOrderDescending(String sortOrder) { return sortOrder.endsWith(" DESC"); } /** * Takes a collection of items and builds a comma-separated list of them + * * @param items collection of items - * @return comma-separted list of items + * @return comma-separated list of items */ public static String buildCollectionAsString(Collection items) { Iterator iterator = items.iterator(); diff --git a/src/org/lineageos/eleven/utils/NavUtils.java b/src/org/lineageos/eleven/utils/NavUtils.java index 4c36220735092487331fd3878f1b62d1c98cc759..e066dd01b41cb4a71e97fc5b24405387dee315de 100644 --- a/src/org/lineageos/eleven/utils/NavUtils.java +++ b/src/org/lineageos/eleven/utils/NavUtils.java @@ -1,20 +1,23 @@ /* * Copyright (C) 2012 Andrew Neal * Copyright (C) 2014 The CyanogenMod Project - * Licensed under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law - * or agreed to in writing, software distributed under the License is - * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the specific language - * governing permissions and limitations under the License. + * Copyright (C) 2021 The LineageOS Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ - package org.lineageos.eleven.utils; import android.app.Activity; -import android.app.SearchManager; import android.content.ActivityNotFoundException; import android.content.Intent; import android.content.pm.PackageManager; @@ -38,7 +41,7 @@ public final class NavUtils { /** * Opens the profile of an artist. * - * @param context The {@link Activity} to use. + * @param context The {@link Activity} to use. * @param artistName The name of the artist */ public static void openArtistProfile(final Activity context, final String artistName) { @@ -58,14 +61,13 @@ public final class NavUtils { /** * Opens the profile of an album. * - * @param context The {@link Activity} to use. - * @param albumName The name of the album + * @param context The {@link Activity} to use. + * @param albumName The name of the album * @param artistName The name of the album artist - * @param albumId The id of the album + * @param albumId The id of the album */ - public static void openAlbumProfile(final Activity context, - final String albumName, final String artistName, final long albumId) { - + public static void openAlbumProfile(final Activity context, final String albumName, + final String artistName, final long albumId) { // Create a new bundle to transfer the album info final Bundle bundle = new Bundle(); bundle.putString(Config.ALBUM_YEAR, MusicUtils.getReleaseDateForAlbum(context, albumId)); @@ -82,7 +84,8 @@ public final class NavUtils { context.startActivity(intent); } - public static void openSmartPlaylist(final Activity context, final Config.SmartPlaylistType type) { + public static void openSmartPlaylist(final Activity context, + final Config.SmartPlaylistType type) { // Create the intent to launch the profile activity final Intent intent = new Intent(context, HomeActivity.class); intent.setAction(HomeActivity.ACTION_VIEW_SMART_PLAYLIST); @@ -93,8 +96,8 @@ public final class NavUtils { /** * Opens the playlist view * - * @param context The {@link Activity} to use. - * @param playlistId the id of the playlist + * @param context The {@link Activity} to use. + * @param playlistId the id of the playlist * @param playlistName the playlist name */ public static void openPlaylist(final Activity context, final long playlistId, @@ -123,7 +126,7 @@ public final class NavUtils { /** * Opens the sound effects panel AudioFX in LineageOS * - * @param context The {@link Activity} to use. + * @param context The {@link Activity} to use. * @param requestCode The request code passed into startActivityForResult */ public static void openEffectsPanel(final Activity context, final int requestCode) { diff --git a/src/org/lineageos/eleven/utils/PlaylistPopupMenuHelper.java b/src/org/lineageos/eleven/utils/PlaylistPopupMenuHelper.java index 984a41d597c170fa12eddd5b3a69381dc45e10c4..2ae2e2db2720f4df190b63c7fde62bc2f420b16b 100644 --- a/src/org/lineageos/eleven/utils/PlaylistPopupMenuHelper.java +++ b/src/org/lineageos/eleven/utils/PlaylistPopupMenuHelper.java @@ -1,25 +1,24 @@ /* -* Copyright (C) 2014 The CyanogenMod Project -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ + * Copyright (C) 2014 The CyanogenMod Project + * Copyright (C) 2021 The LineageOS Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package org.lineageos.eleven.utils; import android.app.Activity; import android.app.AlertDialog; import android.content.ContentUris; -import android.content.DialogInterface; -import android.content.DialogInterface.OnClickListener; import android.net.Uri; import android.provider.MediaStore; @@ -33,7 +32,8 @@ import org.lineageos.eleven.model.Playlist; public abstract class PlaylistPopupMenuHelper extends PopupMenuHelper { private Playlist mPlaylist; - public PlaylistPopupMenuHelper(Activity activity, FragmentManager fragmentManager, PopupMenuType type) { + public PlaylistPopupMenuHelper(Activity activity, FragmentManager fragmentManager, + PopupMenuType type) { super(activity, fragmentManager); mType = type; } @@ -48,7 +48,9 @@ public abstract class PlaylistPopupMenuHelper extends PopupMenuHelper { } public void updateName(String name) { - if(mPlaylist != null) { mPlaylist.mPlaylistName = name; } + if (mPlaylist != null) { + mPlaylist.mPlaylistName = name; + } } @Override @@ -64,11 +66,14 @@ public abstract class PlaylistPopupMenuHelper extends PopupMenuHelper { @Override protected long[] getIdList() { if (mPlaylist.isSmartPlaylist()) { - return MusicUtils.getSongListForSmartPlaylist(mActivity, - SmartPlaylistType.getTypeById(getSourceId())); + final Config.SmartPlaylistType type = SmartPlaylistType.getTypeById(getSourceId()); + if (type != null) { + return MusicUtils.getSongListForSmartPlaylist(mActivity, type); + } } else { return MusicUtils.getSongListForPlaylist(mActivity, getSourceId()); } + return new long[0]; } @Override @@ -86,28 +91,19 @@ public abstract class PlaylistPopupMenuHelper extends PopupMenuHelper { * Create a new {@link AlertDialog} for easy playlist deletion * * @param playlistName The title of the playlist being deleted - * @param playlistId The ID of the playlist being deleted + * @param playlistId The ID of the playlist being deleted * @return A new {@link AlertDialog} used to delete playlists */ - private final AlertDialog buildDeleteDialog(final long playlistId, final String playlistName) { + private AlertDialog buildDeleteDialog(final long playlistId, final String playlistName) { return new AlertDialog.Builder(mActivity) .setTitle(mActivity.getString(R.string.delete_dialog_title, playlistName)) - .setPositiveButton(R.string.context_menu_delete, new OnClickListener() { - - @Override - public void onClick(final DialogInterface dialog, final int which) { - final Uri mUri = ContentUris.withAppendedId( - MediaStore.Audio.Playlists.EXTERNAL_CONTENT_URI, - playlistId); - mActivity.getContentResolver().delete(mUri, null, null); - MusicUtils.refresh(); - } - }).setNegativeButton(R.string.cancel, new OnClickListener() { - - @Override - public void onClick(final DialogInterface dialog, final int which) { - dialog.dismiss(); - } - }).setMessage(R.string.cannot_be_undone).create(); + .setPositiveButton(R.string.context_menu_delete, (dialog, which) -> { + final Uri mUri = ContentUris.withAppendedId( + MediaStore.Audio.Playlists.EXTERNAL_CONTENT_URI, + playlistId); + mActivity.getContentResolver().delete(mUri, null, null); + MusicUtils.refresh(); + }).setNegativeButton(R.string.cancel, (dialog, which) -> + dialog.dismiss()).setMessage(R.string.cannot_be_undone).create(); } } \ No newline at end of file diff --git a/src/org/lineageos/eleven/utils/PopupMenuHelper.java b/src/org/lineageos/eleven/utils/PopupMenuHelper.java index ca4ecfe43910a9465eed9cef0cbe7e7aba0d6279..95da56f14e317d554b143292ee7a7f275239da89 100644 --- a/src/org/lineageos/eleven/utils/PopupMenuHelper.java +++ b/src/org/lineageos/eleven/utils/PopupMenuHelper.java @@ -1,18 +1,19 @@ /* -* Copyright (C) 2014 The CyanogenMod Project -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ + * Copyright (C) 2014 The CyanogenMod Project + * Copyright (C) 2021 The LineageOS Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package org.lineageos.eleven.utils; import android.annotation.SuppressLint; @@ -46,7 +47,7 @@ import java.util.TreeSet; */ public abstract class PopupMenuHelper implements PopupMenu.OnMenuItemClickListener { // the different types of pop up menus - public static enum PopupMenuType { + public enum PopupMenuType { Artist, Album, Song, @@ -56,9 +57,9 @@ public abstract class PopupMenuHelper implements PopupMenu.OnMenuItemClickListen Queue, } - protected Activity mActivity; + protected final Activity mActivity; protected PopupMenuType mType; - protected FragmentManager mFragmentManager; + protected final FragmentManager mFragmentManager; public PopupMenuHelper(final Activity activity, final FragmentManager fragmentManager) { mActivity = activity; @@ -67,7 +68,8 @@ public abstract class PopupMenuHelper implements PopupMenu.OnMenuItemClickListen /** * Call this to inflate and show the pop up menu - * @param view the view to anchor the popup menu against + * + * @param view the view to anchor the popup menu against * @param position the item that was clicked in the popup menu (or -1 if not relevant) */ @SuppressLint("RestrictedApi") @@ -93,6 +95,7 @@ public abstract class PopupMenuHelper implements PopupMenu.OnMenuItemClickListen /** * This function allows classes to setup any variables before showing the popup menu + * * @param position the position passed in from showPopupMenu * @return the pop up menu type, or null if we shouldn't show a pop up menu */ @@ -104,11 +107,13 @@ public abstract class PopupMenuHelper implements PopupMenu.OnMenuItemClickListen protected abstract long[] getIdList(); protected abstract long getSourceId(); + protected abstract Config.IdType getSourceType(); /** * @return the group id to be used for pop up menu inflating */ + @SuppressWarnings("SameReturnValue") protected int getGroupId() { return 0; } @@ -169,6 +174,7 @@ public abstract class PopupMenuHelper implements PopupMenu.OnMenuItemClickListen /** * Creates the pop up menu by inflating the menu items + * * @param menu Menu to use for adding to */ public void createPopupMenu(final Menu menu) { @@ -191,21 +197,22 @@ public abstract class PopupMenuHelper implements PopupMenu.OnMenuItemClickListen /** * Gets the default menu items for the specified type + * * @param type of pop up menu to create * @return list of menu items to inflate */ private static int[] getIdsForType(PopupMenuType type) { switch (type) { case Artist: - return new int[] { - FragmentMenuItems.PLAY_SELECTION, - FragmentMenuItems.ADD_TO_QUEUE, - FragmentMenuItems.ADD_TO_PLAYLIST, - FragmentMenuItems.DELETE, - FragmentMenuItems.CHANGE_IMAGE, + return new int[]{ + FragmentMenuItems.PLAY_SELECTION, + FragmentMenuItems.ADD_TO_QUEUE, + FragmentMenuItems.ADD_TO_PLAYLIST, + FragmentMenuItems.DELETE, + FragmentMenuItems.CHANGE_IMAGE, }; case Album: - return new int[] { + return new int[]{ FragmentMenuItems.PLAY_SELECTION, FragmentMenuItems.ADD_TO_QUEUE, FragmentMenuItems.ADD_TO_PLAYLIST, @@ -214,7 +221,7 @@ public abstract class PopupMenuHelper implements PopupMenu.OnMenuItemClickListen FragmentMenuItems.CHANGE_IMAGE, }; case Song: - return new int[] { + return new int[]{ FragmentMenuItems.PLAY_SELECTION, FragmentMenuItems.PLAY_NEXT, FragmentMenuItems.PLAY_ALBUM, @@ -225,25 +232,25 @@ public abstract class PopupMenuHelper implements PopupMenu.OnMenuItemClickListen FragmentMenuItems.DELETE, }; case Playlist: - return new int[] { + return new int[]{ FragmentMenuItems.PLAY_SELECTION, FragmentMenuItems.ADD_TO_QUEUE, FragmentMenuItems.RENAME_PLAYLIST, FragmentMenuItems.DELETE, }; case SmartPlaylist: - return new int[] { + return new int[]{ FragmentMenuItems.PLAY_SELECTION, FragmentMenuItems.ADD_TO_QUEUE, }; case SearchResult: - return new int[] { + return new int[]{ FragmentMenuItems.PLAY_SELECTION, FragmentMenuItems.ADD_TO_QUEUE, FragmentMenuItems.ADD_TO_PLAYLIST, }; case Queue: - return new int[] { + return new int[]{ FragmentMenuItems.PLAY_NEXT, FragmentMenuItems.ADD_TO_PLAYLIST, FragmentMenuItems.REMOVE_FROM_QUEUE, @@ -258,8 +265,9 @@ public abstract class PopupMenuHelper implements PopupMenu.OnMenuItemClickListen /** * Allows containing classes to add/remove ids to the menu + * * @param type the pop up menu type - * @param set the treeset to add/remove menu items + * @param set the treeset to add/remove menu items */ protected void updateMenuIds(PopupMenuType type, TreeSet set) { // do nothing @@ -268,6 +276,7 @@ public abstract class PopupMenuHelper implements PopupMenu.OnMenuItemClickListen /** * Gets the string resource for an id - if the string resource doesn't exist in this class * the containing class can override this method + * * @param id the menu id * @return string resource id */ @@ -277,6 +286,7 @@ public abstract class PopupMenuHelper implements PopupMenu.OnMenuItemClickListen /** * Gets the string resource for an id + * * @param id the menu id * @return string resource id */ @@ -337,8 +347,7 @@ public abstract class PopupMenuHelper implements PopupMenu.OnMenuItemClickListen MusicUtils.refresh(); return true; case FragmentMenuItems.PLAY_SELECTION: - MusicUtils.playAll(mActivity, getIdList(), 0, getSourceId(), getSourceType(), - false); + MusicUtils.playAll(getIdList(), 0, getSourceId(), getSourceType(), false); return true; case FragmentMenuItems.ADD_TO_QUEUE: MusicUtils.addToQueue(mActivity, getIdList(), getSourceId(), getSourceType()); diff --git a/src/org/lineageos/eleven/utils/PreferenceUtils.java b/src/org/lineageos/eleven/utils/PreferenceUtils.java index c116ca0055030b4b50d31483d6fe875bdf0f0928..d0bc14c57900c46da481372ee2b2696754a7dc90 100644 --- a/src/org/lineageos/eleven/utils/PreferenceUtils.java +++ b/src/org/lineageos/eleven/utils/PreferenceUtils.java @@ -1,7 +1,7 @@ /* * Copyright (C) 2012 Andrew Neal * Copyright (C) 2014 The CyanogenMod Project - * Copyright (C) 2018-2020 The LineageOS Project + * Copyright (C) 2018-2021 The LineageOS Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -15,19 +15,16 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package org.lineageos.eleven.utils; import android.Manifest.permission; import android.app.Activity; import android.content.Context; import android.content.SharedPreferences; -import android.content.pm.PackageManager; -import android.os.AsyncTask; import android.content.SharedPreferences.OnSharedPreferenceChangeListener; +import android.content.pm.PackageManager; import android.preference.PreferenceManager; -import org.lineageos.eleven.R; import org.lineageos.eleven.ui.fragments.AlbumFragment; import org.lineageos.eleven.ui.fragments.ArtistFragment; import org.lineageos.eleven.ui.fragments.SongFragment; @@ -41,21 +38,15 @@ import org.lineageos.eleven.ui.fragments.phone.MusicBrowserPhoneFragment; */ public final class PreferenceUtils { - /* Default start page (Artist page) */ - public static final int DEFFAULT_PAGE = 2; + // Default start page (Artist page) + public static final int DEFAULT_PAGE = 2; - /* Saves the last page the pager was on in {@link MusicBrowserPhoneFragment} */ + // Saves the last page the pager was on in {@link MusicBrowserPhoneFragment} public static final String START_PAGE = "start_page"; // Sort order for the artist list public static final String ARTIST_SORT_ORDER = "artist_sort_order"; - // Sort order for the artist song list - public static final String ARTIST_SONG_SORT_ORDER = "artist_song_sort_order"; - - // Sort order for the artist album list - public static final String ARTIST_ALBUM_SORT_ORDER = "artist_album_sort_order"; - // Sort order for the album list public static final String ALBUM_SORT_ORDER = "album_sort_order"; @@ -65,9 +56,6 @@ public final class PreferenceUtils { // Sort order for the song list public static final String SONG_SORT_ORDER = "song_sort_order"; - // Key used to set the overall theme color - public static final String DEFAULT_THEME_COLOR = "default_theme_color"; - // datetime cutoff for determining which songs go in last added playlist public static final String LAST_ADDED_CUTOFF = "last_added_cutoff"; @@ -83,7 +71,8 @@ public final class PreferenceUtils { // shake to play flag public static final String SHAKE_TO_PLAY = "shake_to_play"; - private static final int PERMISSION_REQUEST_RECORD_AUDIO = 1; + public static final int PERMISSION_REQUEST_STORAGE = 1; + public static final int PERMISSION_REQUEST_RECORD_AUDIO = 2; private static PreferenceUtils sInstance; @@ -102,7 +91,7 @@ public final class PreferenceUtils { * @param context The {@link Context} to use. * @return A singleton of this class */ - public static final PreferenceUtils getInstance(final Context context) { + public static PreferenceUtils getInstance(final Context context) { if (sInstance == null) { sInstance = new PreferenceUtils(context.getApplicationContext()); } @@ -113,93 +102,47 @@ public final class PreferenceUtils { * Saves the current page the user is on when they close the app. * * @param value The last page the pager was on when the onDestroy is called - * in {@link MusicBrowserPhoneFragment}. + * in {@link MusicBrowserPhoneFragment}. */ public void setStartPage(final int value) { - ElevenUtils.execute(false, new AsyncTask() { - @Override - protected Void doInBackground(final Void... unused) { - final SharedPreferences.Editor editor = mPreferences.edit(); - editor.putInt(START_PAGE, value); - editor.apply(); - - return null; - } - }, (Void[])null); + final SharedPreferences.Editor editor = mPreferences.edit(); + editor.putInt(START_PAGE, value); + editor.apply(); } /** * Set the listener for preference change - * @param listener */ - public void setOnSharedPreferenceChangeListener(OnSharedPreferenceChangeListener listener){ + public void setOnSharedPreferenceChangeListener(OnSharedPreferenceChangeListener listener) { mPreferences.registerOnSharedPreferenceChangeListener(listener); } /** * Set the listener for preference change - * @param listener */ - public void removeOnSharedPreferenceChangeListener(OnSharedPreferenceChangeListener listener){ + public void removeOnSharedPreferenceChangeListener(OnSharedPreferenceChangeListener listener) { mPreferences.unregisterOnSharedPreferenceChangeListener(listener); } - /** * Returns the last page the user was on when the app was exited. * * @return The page to start on when the app is opened. */ public final int getStartPage() { - return mPreferences.getInt(START_PAGE, DEFFAULT_PAGE); - } - - /** - * Sets the new theme color. - * - * @param value The new theme color to use. - */ - public void setDefaultThemeColor(final int value) { - ElevenUtils.execute(false, new AsyncTask() { - @Override - protected Void doInBackground(final Void... unused) { - final SharedPreferences.Editor editor = mPreferences.edit(); - editor.putInt(DEFAULT_THEME_COLOR, value); - editor.apply(); - - return null; - } - }, (Void[])null); - } - - /** - * Returns the current theme color. - * - * @param context The {@link Context} to use. - * @return The default theme color. - */ - public final int getDefaultThemeColor(final Context context) { - return mPreferences.getInt(DEFAULT_THEME_COLOR, - context.getResources().getColor(R.color.blue)); + return mPreferences.getInt(START_PAGE, DEFAULT_PAGE); } /** * Saves the sort order for a list. * - * @param key Which sort order to change + * @param key Which sort order to change * @param value The new sort order */ private void setSortOrder(final String key, final String value) { - ElevenUtils.execute(false, new AsyncTask() { - @Override - protected Void doInBackground(final Void... unused) { - final SharedPreferences.Editor editor = mPreferences.edit(); - editor.putString(key, value); - editor.apply(); - - return null; - } - }, (Void[])null); + final SharedPreferences.Editor editor = mPreferences.edit(); + editor.putString(key, value); + editor.apply(); } /** @@ -218,42 +161,6 @@ public final class PreferenceUtils { return mPreferences.getString(ARTIST_SORT_ORDER, SortOrder.ArtistSortOrder.ARTIST_A_Z); } - /** - * Sets the sort order for the artist song list. - * - * @param value The new sort order - */ - public void setArtistSongSortOrder(final String value) { - setSortOrder(ARTIST_SONG_SORT_ORDER, value); - } - - /** - * @return The sort order used for the artist song list in - * {@link ArtistDetailSongAdapter} - */ - public final String getArtistSongSortOrder() { - return mPreferences.getString(ARTIST_SONG_SORT_ORDER, - SortOrder.ArtistSongSortOrder.SONG_A_Z); - } - - /** - * Sets the sort order for the artist album list. - * - * @param value The new sort order - */ - public void setArtistAlbumSortOrder(final String value) { - setSortOrder(ARTIST_ALBUM_SORT_ORDER, value); - } - - /** - * @return The sort order used for the artist album list in - * {@link org.lineageos.eleven.ui.fragments.ArtistDetailFragment} - */ - public final String getArtistAlbumSortOrder() { - return mPreferences.getString(ARTIST_ALBUM_SORT_ORDER, - SortOrder.ArtistAlbumSortOrder.ALBUM_A_Z); - } - /** * Sets the sort order for the album list. * @@ -271,17 +178,7 @@ public final class PreferenceUtils { } /** - * Sets the sort order for the album song list. - * - * @param value The new sort order - */ - public void setAlbumSongSortOrder(final String value) { - setSortOrder(ALBUM_SONG_SORT_ORDER, value); - } - - /** - * @return The sort order used for the album song in - * {@link AlbumSongFragment} + * @return The sort order used for the album song in AlbumSongFragment */ public final String getAlbumSongSortOrder() { return mPreferences.getString(ALBUM_SONG_SORT_ORDER, @@ -304,7 +201,9 @@ public final class PreferenceUtils { return mPreferences.getString(SONG_SORT_ORDER, SortOrder.SongSortOrder.SONG_A_Z); } - /** @parm lastAddedMillis timestamp in millis used as a cutoff for last added playlist */ + /** + * @param lastAddedMillis timestamp in millis used as a cutoff for last added playlist + */ public void setLastAddedCutoff(long lastAddedMillis) { mPreferences.edit().putLong(LAST_ADDED_CUTOFF, lastAddedMillis).apply(); } @@ -327,7 +226,7 @@ public final class PreferenceUtils { public static void requestRecordAudio(Activity activity) { activity.requestPermissions( - new String[] {permission.RECORD_AUDIO}, + new String[]{permission.RECORD_AUDIO}, PERMISSION_REQUEST_RECORD_AUDIO); } diff --git a/src/org/lineageos/eleven/utils/SectionCreatorUtils.java b/src/org/lineageos/eleven/utils/SectionCreatorUtils.java index ca8f800da10272e33cbaa3df399a7bd8d9731e55..bb65abae48c770bfb710ea9af7cab024e23ad7ab 100644 --- a/src/org/lineageos/eleven/utils/SectionCreatorUtils.java +++ b/src/org/lineageos/eleven/utils/SectionCreatorUtils.java @@ -1,28 +1,26 @@ /* -* Copyright (C) 2014 The CyanogenMod Project -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ + * Copyright (C) 2014 The CyanogenMod Project + * Copyright (C) 2021 The LineageOS Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package org.lineageos.eleven.utils; import android.content.Context; import android.text.TextUtils; -import org.lineageos.eleven.Config; import org.lineageos.eleven.R; -import org.lineageos.eleven.model.Album; import org.lineageos.eleven.model.Artist; -import org.lineageos.eleven.model.SearchResult; import org.lineageos.eleven.model.Song; import java.util.List; @@ -39,8 +37,8 @@ public class SectionCreatorUtils { } public static class Section { - public SectionType mType; - public String mIdentifier; + public final SectionType mType; + public final String mIdentifier; public Section(final SectionType type, final String identifier) { mType = type; @@ -50,16 +48,19 @@ public class SectionCreatorUtils { /** * Interface to compare two items and create labels + * * @param type of item to compare */ + @SuppressWarnings({"unused", "SameReturnValue"}) public static class IItemCompare { /** * Compares to items and returns a section divider T if there should * be a section divider between first and second - * @param first the first element in the list. If null, it is checking to see - * if we need a divider at the beginning of the list - * @param second the second element in the list. - * @param items the source list of items that we are creating headers from + * + * @param first the first element in the list. If null, it is checking to see + * if we need a divider at the beginning of the list + * @param second the second element in the list. + * @param items the source list of items that we are creating headers from * @param firstIndex index of the first item we are looking at * @return String the expected separator label or null if none */ @@ -74,10 +75,11 @@ public class SectionCreatorUtils { /** * Compares to items and returns a section divider T if there should * be a section divider between first and second - * @param first the first element in the list. - * @param second the second element in the list. If null, it is checking to see if we need - * a divider at the end of the list - * @param items the source list of items that we are creating footers from + * + * @param first the first element in the list. + * @param second the second element in the list. If null, it is checking to see if we + * need a divider at the end of the list + * @param items the source list of items that we are creating footers from * @param firstIndex index of the first item we are looking at * @return String the expected separator label or null if none */ @@ -91,6 +93,7 @@ public class SectionCreatorUtils { /** * Returns the section label that corresponds to this item + * * @param item the item * @return the section label that this label falls under */ @@ -100,6 +103,7 @@ public class SectionCreatorUtils { /** * Returns the section label that corresponds to this item + * * @param item the item * @return the section label that this label falls under */ @@ -116,10 +120,11 @@ public class SectionCreatorUtils { /** * A localized String comparison implementation of IItemCompare + * * @param the type of item to compare */ public static abstract class LocalizedCompare extends IItemCompare { - protected Context mContext; + protected final Context mContext; private boolean mStopSectionCreation; public LocalizedCompare(Context context) { @@ -167,6 +172,7 @@ public class SectionCreatorUtils { /** * A simple int comparison implementation of IItemCompare + * * @param the type of item to compare */ public static abstract class IntCompare extends IItemCompare { @@ -191,10 +197,11 @@ public class SectionCreatorUtils { * A Bounded int comparison implementation of IntCompare * Basically this will take ints and determine what bounds it falls into * For example, 1-5 mintes, 5-10 minutes, 10+ minutes + * * @param the type of item to compare */ public static abstract class BoundedIntCompare extends IntCompare { - protected Context mContext; + protected final Context mContext; public BoundedIntCompare(Context context) { mContext = context; @@ -224,6 +231,7 @@ public class SectionCreatorUtils { /** * This implements BoundedIntCompare and gives duration buckets + * * @param the type of item to compare */ public static abstract class DurationCompare extends BoundedIntCompare { @@ -237,7 +245,7 @@ public class SectionCreatorUtils { protected int getStringId(int value) { if (value < 30) { return R.string.header_less_than_30s; - } else if (value < 1 * SECONDS_PER_MINUTE) { + } else if (value < SECONDS_PER_MINUTE) { return R.string.header_30_to_60_seconds; } else if (value < 2 * SECONDS_PER_MINUTE) { return R.string.header_1_to_2_minutes; @@ -261,6 +269,7 @@ public class SectionCreatorUtils { /** * This implements BoundedIntCompare and gives number of songs buckets + * * @param the type of item to compare */ public static abstract class NumberOfSongsCompare extends BoundedIntCompare { @@ -284,6 +293,7 @@ public class SectionCreatorUtils { /** * This implements BoundedIntCompare and gives number of albums buckets + * * @param the type of item to compare */ public static abstract class NumberOfAlbumsCompare extends BoundedIntCompare { @@ -336,13 +346,14 @@ public class SectionCreatorUtils { /** * This creates the sections given a list of items and the comparison algorithm - * @param list The list of items to analyze + * + * @param list The list of items to analyze * @param comparator The comparison function to use - * @param the type of item to compare + * @param the type of item to compare * @return Creates a TreeMap of indices (if the headers were part of the list) to section labels */ public static TreeMap createSections(final List list, - final IItemCompare comparator) { + final IItemCompare comparator) { if (list != null && list.size() > 0) { TreeMap sections = new TreeMap<>(); for (int i = 0; i < list.size() + 1; i++) { @@ -355,7 +366,7 @@ public class SectionCreatorUtils { String footer = comparator.createSectionFooter(first, second, list, i - 1); if (footer != null) { // add sectionHeaders.size() to store the indices of the combined list - sections.put(sections.size() + i, new Section(SectionType.Footer, footer)); + sections.put(i, new Section(SectionType.Footer, footer)); } } @@ -363,7 +374,7 @@ public class SectionCreatorUtils { String header = comparator.createSectionHeader(first, second, list, i - 1); if (header != null) { // add sectionHeaders.size() to store the indices of the combined list - sections.put(sections.size() + i, new Section(SectionType.Header, header)); + sections.put(i, new Section(SectionType.Header, header)); // stop section creation if (comparator.shouldStopSectionCreation()) { break; @@ -380,6 +391,7 @@ public class SectionCreatorUtils { /** * Returns an artist comparison based on the current sort + * * @param context Context for string generation * @return the artist comparison method */ @@ -427,97 +439,9 @@ public class SectionCreatorUtils { return sectionCreator; } - /** - * Returns an album comparison based on the current sort - * @param context Context for string generation - * @return the album comparison method - */ - public static IItemCompare createAlbumComparison(final Context context) { - IItemCompare sectionCreator = null; - - final String sortOrder = PreferenceUtils.getInstance(context).getAlbumSortOrder(); - switch (sortOrder) { - case SortOrder.AlbumSortOrder.ALBUM_A_Z: - case SortOrder.AlbumSortOrder.ALBUM_Z_A: - sectionCreator = new LocalizedCompare(context) { - @Override - public String getString(Album item) { - return item.mAlbumName; - } - - @Override - public String createHeaderLabel(Album item) { - if (item.mBucketLabel != null) { - return super.createHeaderLabel(item.mBucketLabel); - } - - return super.createHeaderLabel(item); - } - }; - break; - case SortOrder.AlbumSortOrder.ALBUM_ARTIST: - sectionCreator = new LocalizedCompare(context) { - @Override - public String getString(Album item) { - return item.mArtistName; - } - - @Override - public String createHeaderLabel(Album item) { - if (item.mBucketLabel != null) { - return super.createHeaderLabel(item.mBucketLabel); - } - - return super.createHeaderLabel(item); - } - }; - break; - case SortOrder.AlbumSortOrder.ALBUM_NUMBER_OF_SONGS: - sectionCreator = new NumberOfSongsCompare(context) { - @Override - public int getInt(Album item) { - return item.mSongNumber; - } - }; - break; - case SortOrder.AlbumSortOrder.ALBUM_YEAR: - sectionCreator = new IntCompare() { - private static final int INVALID_YEAR = -1; - - @Override - public int getInt(Album item) { - // if we don't have a year, treat it as invalid - if (item.mYear == null) { - return INVALID_YEAR; - } - - int year = Integer.valueOf(item.mYear); - - // if the year is extremely low, treat it as invalid too - if (MusicUtils.isInvalidYear(year)) { - return INVALID_YEAR; - } - - return year; - } - - @Override - public String createHeaderLabel(Album item) { - if (MusicUtils.isInvalidYear(getInt(item))) { - return context.getString(R.string.header_unknown_year); - } - - return item.mYear; - } - }; - break; - } - - return sectionCreator; - } - /** * Returns an song comparison based on the current sort + * * @param context Context for string generation * @return the song comparison method */ @@ -612,78 +536,4 @@ public class SectionCreatorUtils { return sectionCreator; } - - /** - * Returns an song comparison based on the current sort - * @param context Context for string generation - * @return the song comparison method - */ - public static IItemCompare createSearchResultComparison(final Context context) { - return new IItemCompare() { - - @Override - public String createSectionHeader(SearchResult first, SearchResult second) { - if (first == null || first.mType != second.mType) { - return createHeaderLabel(second); - } - - return null; - } - - @Override - public String createHeaderLabel(SearchResult item) { - switch (item.mType) { - case Artist: - return context.getString(R.string.page_artists); - case Album: - return context.getString(R.string.page_albums); - case Song: - return context.getString(R.string.page_songs); - case Playlist: - return context.getString(R.string.page_playlists); - } - - return null; - } - - @Override - public String createSectionFooter(SearchResult first, SearchResult second, - List items, int firstIndex) { - if (second == null || - (first != null && first.mType != second.mType)) { - // if we don't have SEARCH_NUM_RESULTS_TO_GET # of the same type of items - // then we don't have enough to show the footer. For example, if we show 5 - // items but only the last 2 items are artists, that means we only have 2 - // so there is no point in showing the "Show All" footer - // We start from 1 because we don't need to count - // the first item itself - for (int i = 1; i < Config.SEARCH_NUM_RESULTS_TO_GET; i++) { - if (firstIndex - i < 0 || items.get(firstIndex - i).mType != first.mType) { - return null; - } - } - - return createFooterLabel(first); - } - - return null; - } - - @Override - public String createFooterLabel(SearchResult item) { - switch (item.mType) { - case Artist: - return context.getString(R.string.footer_search_artists); - case Album: - return context.getString(R.string.footer_search_albums); - case Song: - return context.getString(R.string.footer_search_songs); - case Playlist: - return context.getString(R.string.footer_search_playlists); - } - - return null; - } - }; - } } diff --git a/src/org/lineageos/eleven/utils/ShakeDetector.java b/src/org/lineageos/eleven/utils/ShakeDetector.java index fb481f043a0b9ae198a9009011c5a8a00bd9b518..38797c3c9990b511dd13eefd1cdddec104c3998e 100644 --- a/src/org/lineageos/eleven/utils/ShakeDetector.java +++ b/src/org/lineageos/eleven/utils/ShakeDetector.java @@ -1,14 +1,12 @@ - -package org.lineageos.eleven.utils; - /* - * Copyright 2012 Square, Inc. + * Copyright (C) 2012 Square, Inc. + * Copyright (C) 2021 The LineageOS Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -16,13 +14,12 @@ package org.lineageos.eleven.utils; * See the License for the specific language governing permissions and * limitations under the License. */ +package org.lineageos.eleven.utils; import android.hardware.Sensor; import android.hardware.SensorEvent; import android.hardware.SensorEventListener; import android.hardware.SensorManager; -import java.util.ArrayList; -import java.util.List; /** * Detects phone shaking. If > 75% of the samples taken in the past 0.5s are accelerating, the @@ -45,9 +42,13 @@ public class ShakeDetector implements SensorEventListener { private long mDetectedShakeStartTime = 0; - /** Listens for shakes. */ + /** + * Listens for shakes. + */ public interface Listener { - /** Called on the main thread when the device is shaken. */ + /** + * Called on the main thread when the device is shaken. + */ void hearShake(); } @@ -64,8 +65,9 @@ public class ShakeDetector implements SensorEventListener { /** * Starts listening for shakes on devices with appropriate hardware. * - * @returns true if the device supports shake detection. + * @return true if the device supports shake detection. */ + @SuppressWarnings("UnusedReturnValue") public boolean start(SensorManager sensorManager) { // Already started? if (accelerometer != null) { @@ -103,7 +105,7 @@ public class ShakeDetector implements SensorEventListener { queue.add(timestamp, accelerating); if (queue.isShaking()) { /* - * detect time between two concecutive shakes and limit it to + * detect time between two consecutive shakes and limit it to * MIN_TIME_BETWEEN_TWO_SHAKES */ long currentTime = System.currentTimeMillis(); @@ -115,7 +117,9 @@ public class ShakeDetector implements SensorEventListener { } } - /** Returns true if the device is currently accelerating. */ + /** + * Returns true if the device is currently accelerating. + */ private boolean isAccelerating(SensorEvent event) { float ax = event.values[0]; float ay = event.values[1]; @@ -130,10 +134,14 @@ public class ShakeDetector implements SensorEventListener { * ACCELERATION_THRESHOLD; } - /** Queue of samples. Keeps a running average. */ + /** + * Queue of samples. Keeps a running average. + */ static class SampleQueue { - /** Window size in ns. Used to compute the average. */ + /** + * Window size in ns. Used to compute the average. + */ private static final long MAX_WINDOW_SIZE = 500000000; // 0.5s private static final long MIN_WINDOW_SIZE = MAX_WINDOW_SIZE >> 1; // 0.25s @@ -153,7 +161,7 @@ public class ShakeDetector implements SensorEventListener { /** * Adds a sample. * - * @param timestamp in nanoseconds of sample + * @param timestamp in nanoseconds of sample * @param accelerating true if > {@link #ACCELERATION_THRESHOLD}. */ void add(long timestamp, boolean accelerating) { @@ -180,7 +188,9 @@ public class ShakeDetector implements SensorEventListener { } } - /** Removes all samples from this queue. */ + /** + * Removes all samples from this queue. + */ void clear() { while (oldest != null) { Sample removed = oldest; @@ -192,7 +202,9 @@ public class ShakeDetector implements SensorEventListener { acceleratingCount = 0; } - /** Purges samples with timestamps older than cutoff. */ + /** + * Purges samples with timestamps older than cutoff. + */ void purge(long cutoff) { while (sampleCount >= MIN_QUEUE_SIZE && oldest != null && cutoff - oldest.timestamp > 0) { @@ -211,17 +223,6 @@ public class ShakeDetector implements SensorEventListener { } } - /** Copies the samples into a list, with the oldest entry at index 0. */ - List asList() { - List list = new ArrayList<>(); - Sample s = oldest; - while (s != null) { - list.add(s); - s = s.next; - } - return list; - } - /** * Returns true if we have enough samples and more than 3/4 of those samples are * accelerating. @@ -231,27 +232,39 @@ public class ShakeDetector implements SensorEventListener { && oldest != null && newest.timestamp - oldest.timestamp >= MIN_WINDOW_SIZE && acceleratingCount >= (sampleCount >> 1) - + (sampleCount >> 2); + + (sampleCount >> 2); } } - /** An accelerometer sample. */ + /** + * An accelerometer sample. + */ static class Sample { - /** Time sample was taken. */ + /** + * Time sample was taken. + */ long timestamp; - /** If acceleration > {@link #ACCELERATION_THRESHOLD}. */ + /** + * If acceleration > {@link #ACCELERATION_THRESHOLD}. + */ boolean accelerating; - /** Next sample in the queue or pool. */ + /** + * Next sample in the queue or pool. + */ Sample next; } - /** Pools samples. Avoids garbage collection. */ + /** + * Pools samples. Avoids garbage collection. + */ static class SamplePool { private Sample head; - /** Acquires a sample from the pool. */ + /** + * Acquires a sample from the pool. + */ Sample acquire() { Sample acquired = head; if (acquired == null) { @@ -263,7 +276,9 @@ public class ShakeDetector implements SensorEventListener { return acquired; } - /** Returns a sample to the pool. */ + /** + * Returns a sample to the pool. + */ void release(Sample sample) { sample.next = head; head = sample; diff --git a/src/org/lineageos/eleven/utils/SongPopupMenuHelper.java b/src/org/lineageos/eleven/utils/SongPopupMenuHelper.java index df0a546f405e95fbb5a19b5da3cd228dc9a0f719..d7e34aee38913295d1d40e1f0d847a44447b5cda 100644 --- a/src/org/lineageos/eleven/utils/SongPopupMenuHelper.java +++ b/src/org/lineageos/eleven/utils/SongPopupMenuHelper.java @@ -1,21 +1,21 @@ /* -* Copyright (C) 2014 The CyanogenMod Project -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ + * Copyright (C) 2014 The CyanogenMod Project + * Copyright (C) 2021 The LineageOS Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package org.lineageos.eleven.utils; - import android.app.Activity; import android.provider.MediaStore; diff --git a/src/org/lineageos/eleven/utils/SortOrder.java b/src/org/lineageos/eleven/utils/SortOrder.java index 25277cb08b58f1a48c963a9353c3c6e1b2eddbc1..9a40aa24c51594d16d4181022f236584de06eb85 100644 --- a/src/org/lineageos/eleven/utils/SortOrder.java +++ b/src/org/lineageos/eleven/utils/SortOrder.java @@ -1,16 +1,20 @@ /* * Copyright (C) 2012 Andrew Neal * Copyright (C) 2014 The CyanogenMod Project - * Licensed under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law - * or agreed to in writing, software distributed under the License is - * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the specific language - * governing permissions and limitations under the License. + * Copyright (C) 2021 The LineageOS Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ - package org.lineageos.eleven.utils; import android.provider.MediaStore; @@ -22,144 +26,77 @@ import android.provider.MediaStore; */ public final class SortOrder { - /** This class is never instantiated */ - public SortOrder() { - } - /** * Artist sort order entries. */ - public static interface ArtistSortOrder { + public interface ArtistSortOrder { /* Artist sort order A-Z */ - public final static String ARTIST_A_Z = MediaStore.Audio.Artists.DEFAULT_SORT_ORDER; + String ARTIST_A_Z = MediaStore.Audio.Artists.DEFAULT_SORT_ORDER; /* Artist sort order Z-A */ - public final static String ARTIST_Z_A = ARTIST_A_Z + " DESC"; + String ARTIST_Z_A = ARTIST_A_Z + " DESC"; /* Artist sort order number of songs */ - public final static String ARTIST_NUMBER_OF_SONGS = MediaStore.Audio.Artists.NUMBER_OF_TRACKS - + " DESC"; + String ARTIST_NUMBER_OF_SONGS = MediaStore.Audio.Artists.NUMBER_OF_TRACKS + " DESC"; /* Artist sort order number of albums */ - public final static String ARTIST_NUMBER_OF_ALBUMS = MediaStore.Audio.Artists.NUMBER_OF_ALBUMS - + " DESC"; + String ARTIST_NUMBER_OF_ALBUMS = MediaStore.Audio.Artists.NUMBER_OF_ALBUMS + " DESC"; } /** * Album sort order entries. */ - public static interface AlbumSortOrder { + public interface AlbumSortOrder { /* Album sort order A-Z */ - public final static String ALBUM_A_Z = MediaStore.Audio.Albums.DEFAULT_SORT_ORDER; + String ALBUM_A_Z = MediaStore.Audio.Albums.DEFAULT_SORT_ORDER; /* Album sort order Z-A */ - public final static String ALBUM_Z_A = ALBUM_A_Z + " DESC"; + String ALBUM_Z_A = ALBUM_A_Z + " DESC"; /* Album sort order songs */ - public final static String ALBUM_NUMBER_OF_SONGS = MediaStore.Audio.Albums.NUMBER_OF_SONGS + String ALBUM_NUMBER_OF_SONGS = MediaStore.Audio.Albums.NUMBER_OF_SONGS + " DESC"; /* Album sort order artist */ - public final static String ALBUM_ARTIST = MediaStore.Audio.Albums.ARTIST; + String ALBUM_ARTIST = MediaStore.Audio.Albums.ARTIST; /* Album sort order year */ - public final static String ALBUM_YEAR = MediaStore.Audio.Albums.FIRST_YEAR + " DESC"; + String ALBUM_YEAR = MediaStore.Audio.Albums.FIRST_YEAR + " DESC"; } /** * Song sort order entries. */ - public static interface SongSortOrder { + public interface SongSortOrder { /* Song sort order A-Z */ - public final static String SONG_A_Z = MediaStore.Audio.Media.DEFAULT_SORT_ORDER; + String SONG_A_Z = MediaStore.Audio.Media.DEFAULT_SORT_ORDER; /* Song sort order Z-A */ - public final static String SONG_Z_A = SONG_A_Z + " DESC"; + String SONG_Z_A = SONG_A_Z + " DESC"; /* Song sort order artist */ - public final static String SONG_ARTIST = MediaStore.Audio.Media.ARTIST; + String SONG_ARTIST = MediaStore.Audio.Media.ARTIST; /* Song sort order album */ - public final static String SONG_ALBUM = MediaStore.Audio.Media.ALBUM; + String SONG_ALBUM = MediaStore.Audio.Media.ALBUM; /* Song sort order year */ - public final static String SONG_YEAR = MediaStore.Audio.Media.YEAR + " DESC"; + String SONG_YEAR = MediaStore.Audio.Media.YEAR + " DESC"; /* Song sort order duration */ - public final static String SONG_DURATION = MediaStore.Audio.Media.DURATION + " DESC"; - - /* Song sort order date */ - public final static String SONG_DATE = MediaStore.Audio.Media.DATE_ADDED + " DESC"; + String SONG_DURATION = MediaStore.Audio.Media.DURATION + " DESC"; /* Song sort order filename */ - public final static String SONG_FILENAME = MediaStore.Audio.Media.DATA; + String SONG_FILENAME = MediaStore.Audio.Media.DATA; } /** * Album song sort order entries. */ - public static interface AlbumSongSortOrder { - /* Album song sort order A-Z */ - public final static String SONG_A_Z = MediaStore.Audio.Media.DEFAULT_SORT_ORDER; - - /* Album song sort order Z-A */ - public final static String SONG_Z_A = SONG_A_Z + " DESC"; - + public interface AlbumSongSortOrder { /* Album song sort order track list */ - public final static String SONG_TRACK_LIST = String.format("CAST(%s as int), %s", + String SONG_TRACK_LIST = String.format("CAST(%s as int), %s", MediaStore.Audio.Media.TRACK, MediaStore.Audio.Media.DEFAULT_SORT_ORDER); - - /* Album song sort order duration */ - public final static String SONG_DURATION = SongSortOrder.SONG_DURATION; - - /* Album song sort order filename */ - public final static String SONG_FILENAME = SongSortOrder.SONG_FILENAME; } - - /** - * Artist song sort order entries. - */ - public static interface ArtistSongSortOrder { - /* Artist song sort order A-Z */ - public final static String SONG_A_Z = MediaStore.Audio.Media.DEFAULT_SORT_ORDER; - - /* Artist song sort order Z-A */ - public final static String SONG_Z_A = SONG_A_Z + " DESC"; - - /* Artist song sort order album */ - public final static String SONG_ALBUM = MediaStore.Audio.Media.ALBUM; - - /* Artist song sort order year */ - public final static String SONG_YEAR = MediaStore.Audio.Media.YEAR + " DESC"; - - /* Artist song sort order duration */ - public final static String SONG_DURATION = MediaStore.Audio.Media.DURATION + " DESC"; - - /* Artist song sort order date */ - public final static String SONG_DATE = MediaStore.Audio.Media.DATE_ADDED + " DESC"; - - /* Artist song sort order filename */ - public final static String SONG_FILENAME = SongSortOrder.SONG_FILENAME; - } - - /** - * Artist album sort order entries. - */ - public static interface ArtistAlbumSortOrder { - /* Artist album sort order A-Z */ - public final static String ALBUM_A_Z = MediaStore.Audio.Albums.DEFAULT_SORT_ORDER; - - /* Artist album sort order Z-A */ - public final static String ALBUM_Z_A = ALBUM_A_Z + " DESC"; - - /* Artist album sort order songs */ - public final static String ALBUM_NUMBER_OF_SONGS = MediaStore.Audio.Artists.Albums.NUMBER_OF_SONGS - + " DESC"; - - /* Artist album sort order year */ - public final static String ALBUM_YEAR = MediaStore.Audio.Artists.Albums.FIRST_YEAR - + " DESC"; - } - } diff --git a/src/org/lineageos/eleven/utils/SrtManager.java b/src/org/lineageos/eleven/utils/SrtManager.java index b9aec4013abd47ac64712bdfc3e7e31bee8a80d8..099b4c31ad439d961f507a9288771c7f0c2b9200 100644 --- a/src/org/lineageos/eleven/utils/SrtManager.java +++ b/src/org/lineageos/eleven/utils/SrtManager.java @@ -1,18 +1,19 @@ /* -* Copyright (C) 2014 The CyanogenMod Project -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ + * Copyright (C) 2014 The CyanogenMod Project + * Copyright (C) 2021 The LineageOS Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package org.lineageos.eleven.utils; import android.media.MediaPlayer; @@ -134,7 +135,7 @@ public abstract class SrtManager implements Handler.Callback { try { seekTo(mMediaPlayer.getCurrentPosition()); - } catch(IllegalStateException e) { + } catch (IllegalStateException e) { Log.d(TAG, "illegal state but failing silently"); reset(); } @@ -144,7 +145,7 @@ public abstract class SrtManager implements Handler.Callback { private synchronized void postNextTimedText() { if (mEntries != null) { - long timeMs = 0; + long timeMs; try { timeMs = mMediaPlayer.getCurrentPosition(); } catch (IllegalStateException e) { @@ -191,10 +192,9 @@ public abstract class SrtManager implements Handler.Callback { @Override public boolean handleMessage(Message msg) { - switch (msg.what) { - case POST_TEXT_MSG: - postNextTimedText(); - return true; + if (msg.what == POST_TEXT_MSG) { + postNextTimedText(); + return true; } return false; diff --git a/src/org/lineageos/eleven/utils/SrtParser.java b/src/org/lineageos/eleven/utils/SrtParser.java index 2e2e6880d5ac35ed5350677ad5b1230fe732fa6b..06a61b4552e22e0dbe91c4479d284db7e1302cde 100644 --- a/src/org/lineageos/eleven/utils/SrtParser.java +++ b/src/org/lineageos/eleven/utils/SrtParser.java @@ -1,18 +1,19 @@ /* -* Copyright (C) 2014 The CyanogenMod Project -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ + * Copyright (C) 2014 The CyanogenMod Project + * Copyright (C) 2021 The LineageOS Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package org.lineageos.eleven.utils; import android.text.TextUtils; @@ -89,24 +90,17 @@ public class SrtParser { ret.add(entry); } - } catch (NumberFormatException nfe) { + } catch (ArrayIndexOutOfBoundsException | IOException | NumberFormatException nfe) { // The file isn't a valid srt format + // or the time is malformed Log.e(TAG, nfe.getMessage(), nfe); ret = null; - } catch (IOException ioe) { - // shouldn't happen - Log.e(TAG, ioe.getMessage(), ioe); - ret = null; - } catch (ArrayIndexOutOfBoundsException e) { - // if the time is malformed - Log.e(TAG, e.getMessage()); - ret = null; } finally { if (br != null) { try { br.close(); } catch (IOException e) { - Log.e(TAG, e.getMessage()); + Log.e(TAG, "Failed to close", e); } } @@ -114,7 +108,7 @@ public class SrtParser { try { reader.close(); } catch (IOException e) { - Log.e(TAG, e.getMessage()); + Log.e(TAG, "Failed to close reader", e); } } } diff --git a/src/org/lineageos/eleven/utils/colors/BitmapWithColors.java b/src/org/lineageos/eleven/utils/colors/BitmapWithColors.java index 20e595d9f9f587e89851cbf5346bd57a79ca89cc..e3945618a6fd94321a031643a9c625a7f09d4a1e 100644 --- a/src/org/lineageos/eleven/utils/colors/BitmapWithColors.java +++ b/src/org/lineageos/eleven/utils/colors/BitmapWithColors.java @@ -1,6 +1,6 @@ /* * Copyright (C) 2014 The CyanogenMod Project - * Copyright (C) 2019 The LineageOS Project + * Copyright (C) 2019-2021 The LineageOS Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -21,6 +21,7 @@ import android.graphics.Color; import android.os.Looper; import android.util.LruCache; +import androidx.annotation.NonNull; import androidx.palette.graphics.Palette; public class BitmapWithColors { @@ -72,8 +73,8 @@ public class BitmapWithColors { private static final LruCache sCachedColors = new LruCache<>(CACHE_SIZE_MAX); - private Bitmap mBitmap; - private int mBitmapKey; + private final Bitmap mBitmap; + private final int mBitmapKey; private BitmapColors mColors; public BitmapWithColors(Bitmap bitmap, int bitmapKey) { @@ -105,14 +106,6 @@ public class BitmapWithColors { return mColors.mVibrantColor; } - public int getVibrantLightColor() { - loadColorsIfNeeded(); - if (mColors.mVibrantLightColor == Color.TRANSPARENT) { - return getVibrantColor(); - } - return mColors.mVibrantLightColor; - } - public int getVibrantDarkColor() { loadColorsIfNeeded(); if (mColors.mVibrantDarkColor == Color.TRANSPARENT) { @@ -132,7 +125,7 @@ public class BitmapWithColors { mColors.mVibrantColor); int bestColor = mColors.mDominantColor; - float bestContrast = -1; + float bestContrast = -1f; if (contrastToVibrant > bestContrast) { bestColor = mColors.mVibrantColor; bestContrast = contrastToVibrant; @@ -143,13 +136,14 @@ public class BitmapWithColors { } if (contrastToLight > bestContrast) { bestColor = mColors.mVibrantLightColor; - bestContrast = contrastToLight; } return bestColor; } - /** Calculates the constrast between two colors, using the algorithm provided by the WCAG v2. */ + /** + * Calculates the constrast between two colors, using the algorithm provided by the WCAG v2. + */ private static float computeContrastBetweenColors(int bg, int fg) { if (bg == Color.TRANSPARENT || fg == Color.TRANSPARENT || bg == fg) { return -1; @@ -194,6 +188,7 @@ public class BitmapWithColors { } } + @NonNull @Override public String toString() { return "BitmapWithColors[key=" + mBitmapKey + ", colors=" + mColors + "]"; diff --git a/src/org/lineageos/eleven/utils/colors/ColorExtractor.java b/src/org/lineageos/eleven/utils/colors/ColorExtractor.java index c613d2c6dc6491c2a3569656c3e12b71ef85be35..639ca5f7cb529bd1541d48e69359afb8cd660653 100644 --- a/src/org/lineageos/eleven/utils/colors/ColorExtractor.java +++ b/src/org/lineageos/eleven/utils/colors/ColorExtractor.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2019 The LineageOS Project + * Copyright (C) 2019-2021 The LineageOS Project * Copyright (C) 2019 SHIFT GmbH * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -16,7 +16,6 @@ */ package org.lineageos.eleven.utils.colors; -import android.graphics.Bitmap; import android.os.AsyncTask; import org.lineageos.eleven.cache.ImageFetcher; @@ -27,13 +26,8 @@ public class ColorExtractor { void onColorExtracted(final BitmapWithColors bitmapWithColors); } - public static void extractColors(final Bitmap bitmap, final int bitmapKey, - final ColorExtractor.Callback callback) { - new ColorExtractionTask(bitmap, bitmapKey, callback).execute(); - } - public static void extractColors(final ImageFetcher imageFetcher, - final ColorExtractor.Callback callback) { + final ColorExtractor.Callback callback) { new ColorExtractionTask(imageFetcher, callback).execute(); } @@ -41,45 +35,28 @@ public class ColorExtractor { private final ImageFetcher imageFetcher; private final ColorExtractor.Callback callback; - private Bitmap bitmap; - private int bitmapKey; - - ColorExtractionTask(final Bitmap bitmap, final int bitmapKey, - final ColorExtractor.Callback callback) { - this.bitmap = bitmap; - this.bitmapKey = bitmapKey; - - this.imageFetcher = null; - this.callback = callback; - } - ColorExtractionTask(final ImageFetcher imageFetcher, - final ColorExtractor.Callback callback) { + final ColorExtractor.Callback callback) { this.imageFetcher = imageFetcher; this.callback = callback; } @Override protected BitmapWithColors doInBackground(Void... voids) { - if (bitmap == null && imageFetcher != null) { - final String albumName = MusicUtils.getAlbumName(); - final long albumId = MusicUtils.getCurrentAlbumId(); - final String artistName = MusicUtils.getArtistName(); - - // We are not playing anything, return null. Otherwise we will - // potentially override any default colors. - if (albumName == null && artistName == null && albumId == -1) { - return null; - } - - return imageFetcher.getArtwork(albumName, albumId, artistName, true); + if (imageFetcher == null) { + return null; } - - if (bitmap != null) { - return new BitmapWithColors(bitmap, bitmapKey); + final String albumName = MusicUtils.getAlbumName(); + final long albumId = MusicUtils.getCurrentAlbumId(); + final String artistName = MusicUtils.getArtistName(); + + // We are not playing anything, return null. Otherwise we will + // potentially override any default colors. + if (albumName == null && artistName == null && albumId == -1) { + return null; } - return null; + return imageFetcher.getArtwork(albumName, albumId, true); } @Override diff --git a/src/org/lineageos/eleven/widgets/AlbumScrimImage.java b/src/org/lineageos/eleven/widgets/AlbumScrimImage.java index b620066eac97a7d8af70bd41808dd1c4501f043d..905112e30a69886cea38469fdd75923f7fe84fa1 100644 --- a/src/org/lineageos/eleven/widgets/AlbumScrimImage.java +++ b/src/org/lineageos/eleven/widgets/AlbumScrimImage.java @@ -1,7 +1,7 @@ /* * Copyright (C) 2014 The CyanogenMod Project - * Copyright (C) 2019 The LineageOS Project - * Copyright (C) 2019 SHIFT GmbH + * Copyright (C) 2019-2021 The LineageOS Project + * Copyright (C) 2019-2021 SHIFT GmbH * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,7 +20,6 @@ package org.lineageos.eleven.widgets; import android.content.Context; import android.graphics.Bitmap; import android.graphics.Color; -import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.Drawable; import android.graphics.drawable.GradientDrawable; @@ -30,10 +29,11 @@ import android.view.View; import android.widget.FrameLayout; import android.widget.ImageView; -import androidx.core.content.ContextCompat; - import org.lineageos.eleven.R; import org.lineageos.eleven.cache.ImageWorker; +import org.lineageos.eleven.utils.ImageUtils; + +import androidx.core.content.ContextCompat; public class AlbumScrimImage extends FrameLayout { private static final int COLOR_GREY_30 = 0x4c000000; @@ -41,20 +41,27 @@ public class AlbumScrimImage extends FrameLayout { private ImageView mImageView; private View mScrimView; - private boolean mUsingDefaultBlur; + private final int mDefaultArtworkColor; + private boolean mUsingDefaultArtwork; public AlbumScrimImage(Context context, AttributeSet attrs) { super(context, attrs); - mUsingDefaultBlur = true; + mDefaultArtworkColor = ContextCompat.getColor(getContext(), R.color.default_artwork_color); } @Override protected void onFinishInflate() { super.onFinishInflate(); - mImageView = findViewById(R.id.blurImage); - mScrimView = findViewById(R.id.blurScrim); + mImageView = findViewById(R.id.albumImage); + mScrimView = findViewById(R.id.albumScrim); + + // generate and set default artwork + final Drawable defaultArtworkDrawable = createDefaultArtworkDrawable(); + mImageView.setImageDrawable(defaultArtworkDrawable); + + mUsingDefaultArtwork = true; } public ImageView getImageView() { @@ -65,23 +72,24 @@ public class AlbumScrimImage extends FrameLayout { * Transitions the image to the default state (default blur artwork) */ public void transitionToDefaultState() { - // if we are already showing the default blur and we are transitioning to the default blur - // then don't do the transition at all - if (mUsingDefaultBlur) { + // if we are already showing the default artwork and we are transitioning to the + // default artwork then don't do the transition at all + if (mUsingDefaultArtwork) { return; } - Drawable blurredDrawable = new ColorDrawable(ContextCompat.getColor(getContext(), R.color.background_color)); + final Drawable drawable = createDefaultArtworkDrawable(); + final Bitmap albumBitmap = ImageUtils.drawableToBitmap(drawable); - TransitionDrawable imageTransition = ImageWorker.createImageTransitionDrawable( - getResources(), mImageView.getDrawable(), blurredDrawable, - ImageWorker.FADE_IN_TIME_SLOW, true, true); + final TransitionDrawable imageTransition = ImageWorker.createImageTransitionDrawable( + getResources(), mImageView.getDrawable(), albumBitmap, + ImageWorker.FADE_IN_TIME_SLOW, true); - TransitionDrawable paletteTransition = ImageWorker.createPaletteTransition(this, + final TransitionDrawable paletteTransition = ImageWorker.createPaletteTransition(this, Color.TRANSPARENT); setTransitionDrawable(imageTransition, paletteTransition); - mUsingDefaultBlur = true; + mUsingDefaultArtwork = true; } /** @@ -91,10 +99,10 @@ public class AlbumScrimImage extends FrameLayout { * @param paletteTransition the transition for the scrim overlay */ public void setTransitionDrawable(TransitionDrawable imageTransition, - TransitionDrawable paletteTransition) { + TransitionDrawable paletteTransition) { mScrimView.setBackground(paletteTransition); mImageView.setImageDrawable(imageTransition); - mUsingDefaultBlur = false; + mUsingDefaultArtwork = false; } public void setGradientDrawable(GradientDrawable gradientDrawable) { @@ -103,6 +111,10 @@ public class AlbumScrimImage extends FrameLayout { mScrimView.setBackground(scrimDrawable); mImageView.setImageDrawable(gradientDrawable); - mUsingDefaultBlur = false; + mUsingDefaultArtwork = false; + } + + private Drawable createDefaultArtworkDrawable() { + return new ColorDrawable(mDefaultArtworkColor); } } diff --git a/src/org/lineageos/eleven/widgets/AlphaPatternDrawable.java b/src/org/lineageos/eleven/widgets/AlphaPatternDrawable.java index 582bb9d812c4fff65cd1fcaabece548d19e86b88..72f6a171052ea3a4d906eda7f91e45a90f5b3a50 100644 --- a/src/org/lineageos/eleven/widgets/AlphaPatternDrawable.java +++ b/src/org/lineageos/eleven/widgets/AlphaPatternDrawable.java @@ -1,14 +1,20 @@ /* - * Copyright (C) 2010 Daniel Nilsson Copyright (C) 2012 THe CyanogenMod Project - * Licensed under the Apache License, Version 2.0 (the "License"); you may not - * use this file except in compliance with the License. You may obtain a copy of - * the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by - * applicable law or agreed to in writing, software distributed under the - * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS - * OF ANY KIND, either express or implied. See the License for the specific - * language governing permissions and limitations under the License. + * Copyright (C) 2010 Daniel Nilsson + * Copyright (C) 2012 The CyanogenMod Project + * Copyright (C) 2021 The LineageOS Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ - package org.lineageos.eleven.widgets; import android.graphics.Bitmap; @@ -35,7 +41,7 @@ public class AlphaPatternDrawable extends Drawable { private final Paint mPaintGray = new Paint(); - private int mRectangleSize = 10; + private final int mRectangleSize; private int numRectanglesHorizontal; @@ -51,41 +57,26 @@ public class AlphaPatternDrawable extends Drawable { mPaintGray.setColor(0xffcbcbcb); } - /** - * {@inheritDoc} - */ @Override public void draw(final Canvas canvas) { canvas.drawBitmap(mBitmap, null, getBounds(), mPaint); } - /** - * {@inheritDoc} - */ @Override public int getOpacity() { return PixelFormat.OPAQUE; } - /** - * {@inheritDoc} - */ @Override public void setAlpha(final int alpha) { throw new UnsupportedOperationException("Alpha is not supported by this drawable."); } - /** - * {@inheritDoc} - */ @Override public void setColorFilter(final ColorFilter cf) { throw new UnsupportedOperationException("ColorFilter is not supported by this drawable."); } - /** - * {@inheritDoc} - */ @Override protected void onBoundsChange(final Rect bounds) { super.onBoundsChange(bounds); diff --git a/src/org/lineageos/eleven/widgets/AlphaTouchInterceptorOverlay.java b/src/org/lineageos/eleven/widgets/AlphaTouchInterceptorOverlay.java deleted file mode 100644 index 18f51186b127db572adfc735cbc75cd44b0d9704..0000000000000000000000000000000000000000 --- a/src/org/lineageos/eleven/widgets/AlphaTouchInterceptorOverlay.java +++ /dev/null @@ -1,111 +0,0 @@ -/* - * Copyright (C) 2012 The Android Open Source Project Licensed under the Apache - * License, Version 2.0 (the "License"); you may not use this file except in - * compliance with the License. You may obtain a copy of the License at - * http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law - * or agreed to in writing, software distributed under the License is - * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ - -package org.lineageos.eleven.widgets; - -import android.content.Context; -import android.view.View; -import android.widget.FrameLayout; - -/** - * A View that other Views can use to create a touch-interceptor layer above - * their other sub-views. This layer can be enabled and disabled; when enabled, - * clicks are intercepted and passed to a listener. Also supports an alpha layer - * to dim the content underneath. By default, the alpha layer is the same View - * as the touch-interceptor layer. However, for some use-cases, you want a few - * Views to not be dimmed, but still have touches intercepted. In this case, you - * can specify the View to use as the alpha layer via setAlphaLayer(); in this - * case you are responsible for managing the z-order of the alpha-layer with - * respect to your other sub-views. Typically, you would not use this class - * directly, but rather use another class that uses it, for example - * {@link FrameLayoutWithOverlay}. - */ -public class AlphaTouchInterceptorOverlay extends FrameLayout { - - private final View mInterceptorLayer; - - private float mAlpha = 0.0f; - - private View mAlphaLayer; - - /** - * @param context The {@link Context} to use. - */ - public AlphaTouchInterceptorOverlay(final Context context) { - super(context); - - mInterceptorLayer = new View(context); - mInterceptorLayer.setBackgroundColor(0); - addView(mInterceptorLayer); - - mAlphaLayer = this; - } - - /** - * Set the View that the overlay will use as its alpha-layer. If none is set - * it will use itself. Only necessary to set this if some child views need - * to appear above the alpha-layer but below the touch-interceptor. - */ - public void setAlphaLayer(final View alphaLayer) { - if (mAlphaLayer == alphaLayer) { - return; - } - - /* We're no longer the alpha-layer, so make ourself invisible. */ - if (mAlphaLayer == this) { - setAlphaOnViewBackground(this, 0.0f); - } - - mAlphaLayer = alphaLayer == null ? this : alphaLayer; - setAlphaLayerValue(mAlpha); - } - - /** Sets the alpha value on the alpha layer. */ - public void setAlphaLayerValue(final float alpha) { - mAlpha = alpha; - if (mAlphaLayer != null) { - setAlphaOnViewBackground(mAlphaLayer, mAlpha); - } - } - - /** Delegate to interceptor-layer. */ - public void setOverlayOnClickListener(final OnClickListener listener) { - mInterceptorLayer.setOnClickListener(listener); - } - - /** Delegate to interceptor-layer. */ - public void setOverlayClickable(final boolean clickable) { - mInterceptorLayer.setClickable(clickable); - } - - /** - * Sets an alpha value on the view. - */ - public static void setAlphaOnViewBackground(final View view, final float alpha) { - if (view != null) { - view.setBackgroundColor((int)(clamp(alpha, 0.0f, 1.0f) * 255) << 24); - } - } - - /** - * If the input value lies outside of the specified range, return the nearer - * bound. Otherwise, return the input value, unchanged. - */ - public static float clamp(final float input, final float lowerBound, final float upperBound) { - if (input < lowerBound) { - return lowerBound; - } else if (input > upperBound) { - return upperBound; - } - return input; - } - -} diff --git a/src/org/lineageos/eleven/widgets/AudioActivityButton.java b/src/org/lineageos/eleven/widgets/AudioActivityButton.java deleted file mode 100644 index fb76bf6b543f11f503d37494ca6d7da10a3e23fd..0000000000000000000000000000000000000000 --- a/src/org/lineageos/eleven/widgets/AudioActivityButton.java +++ /dev/null @@ -1,35 +0,0 @@ -/* -* Copyright (C) 2014 The CyanogenMod Project -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ -package org.lineageos.eleven.widgets; - -import android.content.Context; -import android.util.AttributeSet; - -import androidx.fragment.app.FragmentActivity; - -import org.lineageos.eleven.ui.activities.SlidingPanelActivity; - -public abstract class AudioActivityButton extends AudioButton { - protected SlidingPanelActivity mActivity; - - public AudioActivityButton(Context context, AttributeSet attrs) { - super(context, attrs); - } - - public void setActivity(FragmentActivity activity) { - mActivity = (SlidingPanelActivity)activity; - } -} \ No newline at end of file diff --git a/src/org/lineageos/eleven/widgets/AudioButton.java b/src/org/lineageos/eleven/widgets/AudioButton.java index 6967ddae4b3ae33b07227371949494019ebab8cf..eeac8381bb214ebf53aa42e4087bf7d8c24dbd50 100644 --- a/src/org/lineageos/eleven/widgets/AudioButton.java +++ b/src/org/lineageos/eleven/widgets/AudioButton.java @@ -1,3 +1,18 @@ +/* + * Copyright (C) 2021 The LineageOS Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package org.lineageos.eleven.widgets; import android.content.Context; @@ -6,20 +21,22 @@ import android.util.AttributeSet; import android.view.View; import android.view.View.OnClickListener; import android.view.View.OnLongClickListener; -import android.widget.ImageButton; + +import androidx.appcompat.widget.AppCompatImageButton; +import androidx.core.content.ContextCompat; import org.lineageos.eleven.R; import org.lineageos.eleven.utils.ElevenUtils; -public abstract class AudioButton extends ImageButton implements OnClickListener, OnLongClickListener { - public static float ACTIVE_ALPHA = 1.0f; - public static float INACTIVE_ALPHA = 0.4f; +public abstract class AudioButton extends AppCompatImageButton + implements OnClickListener, OnLongClickListener { + public static final float ACTIVE_ALPHA = 1.0f; + public static final float INACTIVE_ALPHA = 0.4f; - @SuppressWarnings("deprecation") public AudioButton(final Context context, final AttributeSet attrs) { super(context, attrs); setPadding(0, 0, 0, 0); - setBackground(getResources().getDrawable(R.drawable.selectable_background)); + setBackground(ContextCompat.getDrawable(context, R.drawable.selectable_background)); // Control playback (cycle shuffle) setOnClickListener(this); // Show the cheat sheet diff --git a/src/org/lineageos/eleven/widgets/BrowseButton.java b/src/org/lineageos/eleven/widgets/BrowseButton.java deleted file mode 100644 index 1d7dece9752b26fbef4269ed2a8973a0ade38383..0000000000000000000000000000000000000000 --- a/src/org/lineageos/eleven/widgets/BrowseButton.java +++ /dev/null @@ -1,34 +0,0 @@ -/* -* Copyright (C) 2014 The CyanogenMod Project -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ -package org.lineageos.eleven.widgets; - -import android.content.Context; -import android.util.AttributeSet; -import android.view.View; - -import org.lineageos.eleven.ui.activities.SlidingPanelActivity; - -public class BrowseButton extends AudioActivityButton { - - public BrowseButton(Context context, AttributeSet attrs) { - super(context, attrs); - } - - @Override - public void onClick(View view) { - mActivity.showPanel(SlidingPanelActivity.Panel.Browse); - } -} \ No newline at end of file diff --git a/src/org/lineageos/eleven/widgets/ColorPanelView.java b/src/org/lineageos/eleven/widgets/ColorPanelView.java index 8e77bb091e1e1a5e2f15d9c0bcb357a2ffce239b..9783f572df352e12d6cd821bc83b5c87607b55d0 100644 --- a/src/org/lineageos/eleven/widgets/ColorPanelView.java +++ b/src/org/lineageos/eleven/widgets/ColorPanelView.java @@ -1,14 +1,20 @@ /* - * Copyright (C) 2010 Daniel Nilsson Copyright (C) 2012 THe CyanogenMod Project - * Licensed under the Apache License, Version 2.0 (the "License"); you may not - * use this file except in compliance with the License. You may obtain a copy of - * the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by - * applicable law or agreed to in writing, software distributed under the - * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS - * OF ANY KIND, either express or implied. See the License for the specific - * language governing permissions and limitations under the License. + * Copyright (C) 2010 Daniel Nilsson + * Copyright (C) 2012 The CyanogenMod Project + * Copyright (C) 2021 The LineageOS Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ - package org.lineageos.eleven.widgets; import android.content.Context; @@ -20,8 +26,7 @@ import android.view.View; /** * This class draws a panel which which will be filled with a color which can be - * set. It can be used to show the currently selected color which you will get - * from the {@link ColorPickerView}. + * set. It can be used to show the currently selected color. * * @author Daniel Nilsson */ @@ -32,11 +37,11 @@ public class ColorPanelView extends View { */ private final static float BORDER_WIDTH_PX = 1; - private static float mDensity = 1f; + private final static int BORDER_COLOR = 0xff6E6E6E; - private int mBorderColor = 0xff6E6E6E; + private final static int PAINT_COLOR = 0xff000000; - private int mColor = 0xff000000; + private static float mDensity = 1f; private Paint mBorderPaint; @@ -67,28 +72,20 @@ public class ColorPanelView extends View { mDensity = getContext().getResources().getDisplayMetrics().density; } - /** - * {@inheritDoc} - */ @Override protected void onDraw(final Canvas canvas) { final RectF rect = mColorRect; - if (BORDER_WIDTH_PX > 0) { - mBorderPaint.setColor(mBorderColor); - canvas.drawRect(mDrawingRect, mBorderPaint); - } + mBorderPaint.setColor(BORDER_COLOR); + canvas.drawRect(mDrawingRect, mBorderPaint); if (mAlphaPattern != null) { mAlphaPattern.draw(canvas); } - mColorPaint.setColor(mColor); + mColorPaint.setColor(PAINT_COLOR); canvas.drawRect(rect, mColorPaint); } - /** - * {@inheritDoc} - */ @Override protected void onMeasure(final int widthMeasureSpec, final int heightMeasureSpec) { final int width = MeasureSpec.getSize(widthMeasureSpec); @@ -96,9 +93,6 @@ public class ColorPanelView extends View { setMeasuredDimension(width, height); } - /** - * {@inheritDoc} - */ @Override protected void onSizeChanged(final int w, final int h, final int oldw, final int oldh) { super.onSizeChanged(w, h, oldw, oldh); @@ -121,46 +115,10 @@ public class ColorPanelView extends View { mColorRect = new RectF(left, top, right, bottom); - mAlphaPattern = new AlphaPatternDrawable((int)(5 * mDensity)); + mAlphaPattern = new AlphaPatternDrawable((int) (5 * mDensity)); mAlphaPattern.setBounds(Math.round(mColorRect.left), Math.round(mColorRect.top), Math.round(mColorRect.right), Math.round(mColorRect.bottom)); } - /** - * Set the color that should be shown by this view. - * - * @param color - */ - public void setColor(final int color) { - mColor = color; - invalidate(); - } - - /** - * Get the color currently show by this view. - * - * @return - */ - public int getColor() { - return mColor; - } - - /** - * Set the color of the border surrounding the panel. - * - * @param color - */ - public void setBorderColor(final int color) { - mBorderColor = color; - invalidate(); - } - - /** - * Get the color of the border surrounding the panel. - */ - public int getBorderColor() { - return mBorderColor; - } - } diff --git a/src/org/lineageos/eleven/widgets/ColorPickerView.java b/src/org/lineageos/eleven/widgets/ColorPickerView.java deleted file mode 100644 index 1894e633ec2d3494f68c141c794cfabf59fb2ecf..0000000000000000000000000000000000000000 --- a/src/org/lineageos/eleven/widgets/ColorPickerView.java +++ /dev/null @@ -1,948 +0,0 @@ -/* - * Copyright (C) 2010 Daniel Nilsson Copyright (C) 2012 THe CyanogenMod Project - * Licensed under the Apache License, Version 2.0 (the "License"); you may not - * use this file except in compliance with the License. You may obtain a copy of - * the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by - * applicable law or agreed to in writing, software distributed under the - * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS - * OF ANY KIND, either express or implied. See the License for the specific - * language governing permissions and limitations under the License. - */ - -package org.lineageos.eleven.widgets; - -import android.content.Context; -import android.graphics.Canvas; -import android.graphics.Color; -import android.graphics.ComposeShader; -import android.graphics.LinearGradient; -import android.graphics.Paint; -import android.graphics.Paint.Align; -import android.graphics.Paint.Style; -import android.graphics.Point; -import android.graphics.PorterDuff; -import android.graphics.RectF; -import android.graphics.Shader; -import android.graphics.Shader.TileMode; -import android.text.TextUtils; -import android.util.AttributeSet; -import android.view.MotionEvent; -import android.view.View; - -/** - * Displays a color picker to the user and allow them to select a color. A - * slider for the alpha channel is also available. Enable it by setting - * setAlphaSliderVisible(boolean) to true. - * - * @author Daniel Nilsson - */ -public class ColorPickerView extends View { - - public interface OnColorChangedListener { - public void onColorChanged(int color); - } - - private final static int PANEL_SAT_VAL = 0; - - private final static int PANEL_HUE = 1; - - private final static int PANEL_ALPHA = 2; - - /** - * The width in pixels of the border surrounding all color panels. - */ - private final static float BORDER_WIDTH_PX = 1; - - /** - * The width in dp of the hue panel. - */ - private float HUE_PANEL_WIDTH = 30f; - - /** - * The height in dp of the alpha panel - */ - private float ALPHA_PANEL_HEIGHT = 20f; - - /** - * The distance in dp between the different color panels. - */ - private float PANEL_SPACING = 10f; - - /** - * The radius in dp of the color palette tracker circle. - */ - private float PALETTE_CIRCLE_TRACKER_RADIUS = 5f; - - /** - * The dp which the tracker of the hue or alpha panel will extend outside of - * its bounds. - */ - private float RECTANGLE_TRACKER_OFFSET = 2f; - - private static float mDensity = 1f; - - private OnColorChangedListener mListener; - - private Paint mSatValPaint; - - private Paint mSatValTrackerPaint; - - private Paint mHuePaint; - - private Paint mHueTrackerPaint; - - private Paint mAlphaPaint; - - private Paint mAlphaTextPaint; - - private Paint mBorderPaint; - - private Shader mValShader; - - private Shader mSatShader; - - private Shader mHueShader; - - private Shader mAlphaShader; - - private int mAlpha = 0xff; - - private float mHue = 360f; - - private float mSat = 0f; - - private float mVal = 0f; - - private String mAlphaSliderText = "Alpha"; - - private int mSliderTrackerColor = 0xff1c1c1c; - - private int mBorderColor = 0xff6E6E6E; - - private boolean mShowAlphaPanel = false; - - /* - * To remember which panel that has the "focus" when processing hardware - * button data. - */ - private int mLastTouchedPanel = PANEL_SAT_VAL; - - /** - * Offset from the edge we must have or else the finger tracker will get - * clipped when it is drawn outside of the view. - */ - private float mDrawingOffset; - - /* - * Distance form the edges of the view of where we are allowed to draw. - */ - private RectF mDrawingRect; - - private RectF mSatValRect; - - private RectF mHueRect; - - private RectF mAlphaRect; - - private AlphaPatternDrawable mAlphaPattern; - - private Point mStartTouchPoint = null; - - public ColorPickerView(final Context context) { - this(context, null); - } - - public ColorPickerView(final Context context, final AttributeSet attrs) { - this(context, attrs, 0); - } - - public ColorPickerView(final Context context, final AttributeSet attrs, final int defStyle) { - super(context, attrs, defStyle); - init(); - } - - private void init() { - mDensity = getContext().getResources().getDisplayMetrics().density; - PALETTE_CIRCLE_TRACKER_RADIUS *= mDensity; - RECTANGLE_TRACKER_OFFSET *= mDensity; - HUE_PANEL_WIDTH *= mDensity; - ALPHA_PANEL_HEIGHT *= mDensity; - PANEL_SPACING = PANEL_SPACING * mDensity; - - mDrawingOffset = calculateRequiredOffset(); - - initPaintTools(); - - // Needed for receiving track ball motion events. - setFocusable(true); - setFocusableInTouchMode(true); - } - - private void initPaintTools() { - - mSatValPaint = new Paint(); - mSatValTrackerPaint = new Paint(); - mHuePaint = new Paint(); - mHueTrackerPaint = new Paint(); - mAlphaPaint = new Paint(); - mAlphaTextPaint = new Paint(); - mBorderPaint = new Paint(); - - mSatValTrackerPaint.setStyle(Style.STROKE); - mSatValTrackerPaint.setStrokeWidth(2f * mDensity); - mSatValTrackerPaint.setAntiAlias(true); - - mHueTrackerPaint.setColor(mSliderTrackerColor); - mHueTrackerPaint.setStyle(Style.STROKE); - mHueTrackerPaint.setStrokeWidth(2f * mDensity); - mHueTrackerPaint.setAntiAlias(true); - - mAlphaTextPaint.setColor(0xff1c1c1c); - mAlphaTextPaint.setTextSize(14f * mDensity); - mAlphaTextPaint.setAntiAlias(true); - mAlphaTextPaint.setTextAlign(Align.CENTER); - mAlphaTextPaint.setFakeBoldText(true); - - } - - private float calculateRequiredOffset() { - float offset = Math.max(PALETTE_CIRCLE_TRACKER_RADIUS, RECTANGLE_TRACKER_OFFSET); - offset = Math.max(offset, BORDER_WIDTH_PX * mDensity); - - return offset * 1.5f; - } - - private int[] buildHueColorArray() { - - final int[] hue = new int[361]; - - int count = 0; - for (int i = hue.length - 1; i >= 0; i--, count++) { - hue[count] = Color.HSVToColor(new float[] { - i, 1f, 1f - }); - } - - return hue; - } - - @Override - protected void onDraw(final Canvas canvas) { - - if (mDrawingRect.width() <= 0 || mDrawingRect.height() <= 0) { - return; - } - - drawSatValPanel(canvas); - drawHuePanel(canvas); - drawAlphaPanel(canvas); - - } - - private void drawSatValPanel(final Canvas canvas) { - - final RectF rect = mSatValRect; - - if (BORDER_WIDTH_PX > 0) { - mBorderPaint.setColor(mBorderColor); - canvas.drawRect(mDrawingRect.left, mDrawingRect.top, rect.right + BORDER_WIDTH_PX, - rect.bottom + BORDER_WIDTH_PX, mBorderPaint); - } - - if (mValShader == null) { - mValShader = new LinearGradient(rect.left, rect.top, rect.left, rect.bottom, - 0xffffffff, 0xff000000, TileMode.CLAMP); - } - - final int rgb = Color.HSVToColor(new float[] { - mHue, 1f, 1f - }); - - mSatShader = new LinearGradient(rect.left, rect.top, rect.right, rect.top, 0xffffffff, rgb, - TileMode.CLAMP); - final ComposeShader mShader = new ComposeShader(mValShader, mSatShader, - PorterDuff.Mode.MULTIPLY); - mSatValPaint.setShader(mShader); - - canvas.drawRect(rect, mSatValPaint); - - final Point p = satValToPoint(mSat, mVal); - - mSatValTrackerPaint.setColor(0xff000000); - canvas.drawCircle(p.x, p.y, PALETTE_CIRCLE_TRACKER_RADIUS - 1f * mDensity, - mSatValTrackerPaint); - - mSatValTrackerPaint.setColor(0xffdddddd); - canvas.drawCircle(p.x, p.y, PALETTE_CIRCLE_TRACKER_RADIUS, mSatValTrackerPaint); - - } - - private void drawHuePanel(final Canvas canvas) { - - final RectF rect = mHueRect; - - if (BORDER_WIDTH_PX > 0) { - mBorderPaint.setColor(mBorderColor); - canvas.drawRect(rect.left - BORDER_WIDTH_PX, rect.top - BORDER_WIDTH_PX, rect.right - + BORDER_WIDTH_PX, rect.bottom + BORDER_WIDTH_PX, mBorderPaint); - } - - if (mHueShader == null) { - mHueShader = new LinearGradient(rect.left, rect.top, rect.left, rect.bottom, - buildHueColorArray(), null, TileMode.CLAMP); - mHuePaint.setShader(mHueShader); - } - - canvas.drawRect(rect, mHuePaint); - - final float rectHeight = 4 * mDensity / 2; - - final Point p = hueToPoint(mHue); - - final RectF r = new RectF(); - r.left = rect.left - RECTANGLE_TRACKER_OFFSET; - r.right = rect.right + RECTANGLE_TRACKER_OFFSET; - r.top = p.y - rectHeight; - r.bottom = p.y + rectHeight; - - canvas.drawRoundRect(r, 2, 2, mHueTrackerPaint); - - } - - private void drawAlphaPanel(final Canvas canvas) { - - if (!mShowAlphaPanel || mAlphaRect == null || mAlphaPattern == null) { - return; - } - - final RectF rect = mAlphaRect; - - if (BORDER_WIDTH_PX > 0) { - mBorderPaint.setColor(mBorderColor); - canvas.drawRect(rect.left - BORDER_WIDTH_PX, rect.top - BORDER_WIDTH_PX, rect.right - + BORDER_WIDTH_PX, rect.bottom + BORDER_WIDTH_PX, mBorderPaint); - } - - mAlphaPattern.draw(canvas); - - final float[] hsv = new float[] { - mHue, mSat, mVal - }; - final int color = Color.HSVToColor(hsv); - final int acolor = Color.HSVToColor(0, hsv); - - mAlphaShader = new LinearGradient(rect.left, rect.top, rect.right, rect.top, color, acolor, - TileMode.CLAMP); - - mAlphaPaint.setShader(mAlphaShader); - - canvas.drawRect(rect, mAlphaPaint); - - if (!TextUtils.isEmpty(mAlphaSliderText)) { - canvas.drawText(mAlphaSliderText, rect.centerX(), rect.centerY() + 4 * mDensity, - mAlphaTextPaint); - } - - final float rectWidth = 4 * mDensity / 2; - - final Point p = alphaToPoint(mAlpha); - - final RectF r = new RectF(); - r.left = p.x - rectWidth; - r.right = p.x + rectWidth; - r.top = rect.top - RECTANGLE_TRACKER_OFFSET; - r.bottom = rect.bottom + RECTANGLE_TRACKER_OFFSET; - - canvas.drawRoundRect(r, 2, 2, mHueTrackerPaint); - - } - - private Point hueToPoint(final float hue) { - - final RectF rect = mHueRect; - final float height = rect.height(); - - final Point p = new Point(); - - p.y = (int)(height - hue * height / 360f + rect.top); - p.x = (int)rect.left; - - return p; - } - - private Point satValToPoint(final float sat, final float val) { - - final RectF rect = mSatValRect; - final float height = rect.height(); - final float width = rect.width(); - - final Point p = new Point(); - - p.x = (int)(sat * width + rect.left); - p.y = (int)((1f - val) * height + rect.top); - - return p; - } - - private Point alphaToPoint(final int alpha) { - - final RectF rect = mAlphaRect; - final float width = rect.width(); - - final Point p = new Point(); - - p.x = (int)(width - alpha * width / 0xff + rect.left); - p.y = (int)rect.top; - - return p; - - } - - private float[] pointToSatVal(float x, float y) { - - final RectF rect = mSatValRect; - final float[] result = new float[2]; - - final float width = rect.width(); - final float height = rect.height(); - - if (x < rect.left) { - x = 0f; - } else if (x > rect.right) { - x = width; - } else { - x = x - rect.left; - } - - if (y < rect.top) { - y = 0f; - } else if (y > rect.bottom) { - y = height; - } else { - y = y - rect.top; - } - - result[0] = 1.f / width * x; - result[1] = 1.f - 1.f / height * y; - - return result; - } - - private float pointToHue(float y) { - - final RectF rect = mHueRect; - - final float height = rect.height(); - - if (y < rect.top) { - y = 0f; - } else if (y > rect.bottom) { - y = height; - } else { - y = y - rect.top; - } - - return 360f - y * 360f / height; - } - - private int pointToAlpha(int x) { - - final RectF rect = mAlphaRect; - final int width = (int)rect.width(); - - if (x < rect.left) { - x = 0; - } else if (x > rect.right) { - x = width; - } else { - x = x - (int)rect.left; - } - - return 0xff - x * 0xff / width; - - } - - @Override - public boolean onTrackballEvent(final MotionEvent event) { - - final float x = event.getX(); - final float y = event.getY(); - - boolean update = false; - - if (event.getAction() == MotionEvent.ACTION_MOVE) { - - switch (mLastTouchedPanel) { - - case PANEL_SAT_VAL: - - float sat, - val; - - sat = mSat + x / 50f; - val = mVal - y / 50f; - - if (sat < 0f) { - sat = 0f; - } else if (sat > 1f) { - sat = 1f; - } - - if (val < 0f) { - val = 0f; - } else if (val > 1f) { - val = 1f; - } - - mSat = sat; - mVal = val; - - update = true; - - break; - - case PANEL_HUE: - - float hue = mHue - y * 10f; - - if (hue < 0f) { - hue = 0f; - } else if (hue > 360f) { - hue = 360f; - } - - mHue = hue; - - update = true; - - break; - - case PANEL_ALPHA: - - if (!mShowAlphaPanel || mAlphaRect == null) { - update = false; - } else { - - int alpha = (int)(mAlpha - x * 10); - - if (alpha < 0) { - alpha = 0; - } else if (alpha > 0xff) { - alpha = 0xff; - } - - mAlpha = alpha; - - update = true; - } - - break; - } - - } - - if (update) { - - if (mListener != null) { - mListener.onColorChanged(Color.HSVToColor(mAlpha, new float[] { - mHue, mSat, mVal - })); - } - - invalidate(); - return true; - } - - return super.onTrackballEvent(event); - } - - @Override - public boolean onTouchEvent(final MotionEvent event) { - - boolean update = false; - - switch (event.getAction()) { - - case MotionEvent.ACTION_DOWN: - - mStartTouchPoint = new Point((int)event.getX(), (int)event.getY()); - - update = moveTrackersIfNeeded(event); - - break; - - case MotionEvent.ACTION_MOVE: - - update = moveTrackersIfNeeded(event); - - break; - - case MotionEvent.ACTION_UP: - - mStartTouchPoint = null; - - update = moveTrackersIfNeeded(event); - - break; - - } - - if (update) { - - if (mListener != null) { - mListener.onColorChanged(Color.HSVToColor(mAlpha, new float[] { - mHue, mSat, mVal - })); - } - - invalidate(); - return true; - } - - return super.onTouchEvent(event); - } - - private boolean moveTrackersIfNeeded(final MotionEvent event) { - - if (mStartTouchPoint == null) { - return false; - } - - boolean update = false; - - final int startX = mStartTouchPoint.x; - final int startY = mStartTouchPoint.y; - - if (mHueRect.contains(startX, startY)) { - mLastTouchedPanel = PANEL_HUE; - - mHue = pointToHue(event.getY()); - - update = true; - } else if (mSatValRect.contains(startX, startY)) { - - mLastTouchedPanel = PANEL_SAT_VAL; - - final float[] result = pointToSatVal(event.getX(), event.getY()); - - mSat = result[0]; - mVal = result[1]; - - update = true; - } else if (mAlphaRect != null && mAlphaRect.contains(startX, startY)) { - - mLastTouchedPanel = PANEL_ALPHA; - - mAlpha = pointToAlpha((int)event.getX()); - - update = true; - } - - return update; - } - - @Override - protected void onMeasure(final int widthMeasureSpec, final int heightMeasureSpec) { - - int width = 0; - int height = 0; - - final int widthMode = MeasureSpec.getMode(widthMeasureSpec); - final int heightMode = MeasureSpec.getMode(heightMeasureSpec); - - int widthAllowed = MeasureSpec.getSize(widthMeasureSpec); - int heightAllowed = MeasureSpec.getSize(heightMeasureSpec); - - widthAllowed = chooseWidth(widthMode, widthAllowed); - heightAllowed = chooseHeight(heightMode, heightAllowed); - - if (!mShowAlphaPanel) { - height = (int)(widthAllowed - PANEL_SPACING - HUE_PANEL_WIDTH); - - // If calculated height (based on the width) is more than the - // allowed height. - if (height > heightAllowed) { - height = heightAllowed; - width = (int)(height + PANEL_SPACING + HUE_PANEL_WIDTH); - } else { - width = widthAllowed; - } - } else { - - width = (int)(heightAllowed - ALPHA_PANEL_HEIGHT + HUE_PANEL_WIDTH); - - if (width > widthAllowed) { - width = widthAllowed; - height = (int)(widthAllowed - HUE_PANEL_WIDTH + ALPHA_PANEL_HEIGHT); - } else { - height = heightAllowed; - } - - } - - setMeasuredDimension(width, height); - } - - private int chooseWidth(final int mode, final int size) { - if (mode == MeasureSpec.AT_MOST || mode == MeasureSpec.EXACTLY) { - return size; - } else { // (mode == MeasureSpec.UNSPECIFIED) - return getPrefferedWidth(); - } - } - - private int chooseHeight(final int mode, final int size) { - if (mode == MeasureSpec.AT_MOST || mode == MeasureSpec.EXACTLY) { - return size; - } else { // (mode == MeasureSpec.UNSPECIFIED) - return getPrefferedHeight(); - } - } - - private int getPrefferedWidth() { - - int width = getPrefferedHeight(); - - if (mShowAlphaPanel) { - width -= PANEL_SPACING + ALPHA_PANEL_HEIGHT; - } - - return (int)(width + HUE_PANEL_WIDTH + PANEL_SPACING); - - } - - private int getPrefferedHeight() { - - int height = (int)(200 * mDensity); - - if (mShowAlphaPanel) { - height += PANEL_SPACING + ALPHA_PANEL_HEIGHT; - } - - return height; - } - - @Override - protected void onSizeChanged(final int w, final int h, final int oldw, final int oldh) { - super.onSizeChanged(w, h, oldw, oldh); - - mDrawingRect = new RectF(); - mDrawingRect.left = mDrawingOffset + getPaddingLeft(); - mDrawingRect.right = w - mDrawingOffset - getPaddingRight(); - mDrawingRect.top = mDrawingOffset + getPaddingTop(); - mDrawingRect.bottom = h - mDrawingOffset - getPaddingBottom(); - - setUpSatValRect(); - setUpHueRect(); - setUpAlphaRect(); - } - - private void setUpSatValRect() { - - final RectF dRect = mDrawingRect; - float panelSide = dRect.height() - BORDER_WIDTH_PX * 2; - - if (mShowAlphaPanel) { - panelSide -= PANEL_SPACING + ALPHA_PANEL_HEIGHT; - } - - final float left = dRect.left + BORDER_WIDTH_PX; - final float top = dRect.top + BORDER_WIDTH_PX; - final float bottom = top + panelSide; - final float right = left + panelSide; - - mSatValRect = new RectF(left, top, right, bottom); - } - - private void setUpHueRect() { - final RectF dRect = mDrawingRect; - - final float left = dRect.right - HUE_PANEL_WIDTH + BORDER_WIDTH_PX; - final float top = dRect.top + BORDER_WIDTH_PX; - final float bottom = dRect.bottom - BORDER_WIDTH_PX - - (mShowAlphaPanel ? PANEL_SPACING + ALPHA_PANEL_HEIGHT : 0); - final float right = dRect.right - BORDER_WIDTH_PX; - - mHueRect = new RectF(left, top, right, bottom); - } - - private void setUpAlphaRect() { - - if (!mShowAlphaPanel) { - return; - } - - final RectF dRect = mDrawingRect; - - final float left = dRect.left + BORDER_WIDTH_PX; - final float top = dRect.bottom - ALPHA_PANEL_HEIGHT + BORDER_WIDTH_PX; - final float bottom = dRect.bottom - BORDER_WIDTH_PX; - final float right = dRect.right - BORDER_WIDTH_PX; - - mAlphaRect = new RectF(left, top, right, bottom); - - mAlphaPattern = new AlphaPatternDrawable((int)(5 * mDensity)); - mAlphaPattern.setBounds(Math.round(mAlphaRect.left), Math.round(mAlphaRect.top), - Math.round(mAlphaRect.right), Math.round(mAlphaRect.bottom)); - - } - - /** - * Set a OnColorChangedListener to get notified when the color selected by - * the user has changed. - * - * @param listener - */ - public void setOnColorChangedListener(final OnColorChangedListener listener) { - mListener = listener; - } - - /** - * Set the color of the border surrounding all panels. - * - * @param color - */ - public void setBorderColor(final int color) { - mBorderColor = color; - invalidate(); - } - - /** - * Get the color of the border surrounding all panels. - */ - public int getBorderColor() { - return mBorderColor; - } - - /** - * Get the current color this view is showing. - * - * @return the current color. - */ - public int getColor() { - return Color.HSVToColor(mAlpha, new float[] { - mHue, mSat, mVal - }); - } - - /** - * Set the color the view should show. - * - * @param color The color that should be selected. - */ - public void setColor(final int color) { - setColor(color, false); - } - - /** - * Set the color this view should show. - * - * @param color The color that should be selected. - * @param callback If you want to get a callback to your - * OnColorChangedListener. - */ - public void setColor(final int color, final boolean callback) { - - final int alpha = Color.alpha(color); - final int red = Color.red(color); - final int blue = Color.blue(color); - final int green = Color.green(color); - - final float[] hsv = new float[3]; - - Color.RGBToHSV(red, green, blue, hsv); - - mAlpha = alpha; - mHue = hsv[0]; - mSat = hsv[1]; - mVal = hsv[2]; - - if (callback && mListener != null) { - mListener.onColorChanged(Color.HSVToColor(mAlpha, new float[] { - mHue, mSat, mVal - })); - } - - invalidate(); - } - - /** - * Get the drawing offset of the color picker view. The drawing offset is - * the distance from the side of a panel to the side of the view minus the - * padding. Useful if you want to have your own panel below showing the - * currently selected color and want to align it perfectly. - * - * @return The offset in pixels. - */ - public float getDrawingOffset() { - return mDrawingOffset; - } - - /** - * Set if the user is allowed to adjust the alpha panel. Default is false. - * If it is set to false no alpha will be set. - * - * @param visible - */ - public void setAlphaSliderVisible(final boolean visible) { - - if (mShowAlphaPanel != visible) { - mShowAlphaPanel = visible; - - /* - * Reset all shader to force a recreation. Otherwise they will not - * look right after the size of the view has changed. - */ - mValShader = null; - mSatShader = null; - mHueShader = null; - mAlphaShader = null; - - requestLayout(); - } - - } - - public void setSliderTrackerColor(final int color) { - mSliderTrackerColor = color; - - mHueTrackerPaint.setColor(mSliderTrackerColor); - - invalidate(); - } - - public int getSliderTrackerColor() { - return mSliderTrackerColor; - } - - /** - * Set the text that should be shown in the alpha slider. Set to null to - * disable text. - * - * @param res string resource id. - */ - public void setAlphaSliderText(final int res) { - final String text = getContext().getString(res); - setAlphaSliderText(text); - } - - /** - * Set the text that should be shown in the alpha slider. Set to null to - * disable text. - * - * @param text Text that should be shown. - */ - public void setAlphaSliderText(final String text) { - mAlphaSliderText = text; - invalidate(); - } - - /** - * Get the current value of the text that will be shown in the alpha slider. - * - * @return - */ - public String getAlphaSliderText() { - return mAlphaSliderText; - } -} diff --git a/src/org/lineageos/eleven/widgets/DragSortItemTouchHelperCallback.java b/src/org/lineageos/eleven/widgets/DragSortItemTouchHelperCallback.java new file mode 100644 index 0000000000000000000000000000000000000000..17d00e7e9e5976a57b7236e5a4880b73eee3f4ab --- /dev/null +++ b/src/org/lineageos/eleven/widgets/DragSortItemTouchHelperCallback.java @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2021 The LineageOS Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.lineageos.eleven.widgets; + +import androidx.annotation.NonNull; +import androidx.recyclerview.widget.ItemTouchHelper; +import androidx.recyclerview.widget.RecyclerView; + +public class DragSortItemTouchHelperCallback extends ItemTouchHelper.Callback { + + private final DragSortListener mListener; + + public DragSortItemTouchHelperCallback(DragSortListener listener) { + mListener = listener; + } + + @Override + public boolean isLongPressDragEnabled() { + return true; + } + + @Override + public int getMovementFlags(@NonNull RecyclerView recyclerView, + @NonNull RecyclerView.ViewHolder viewHolder) { + return makeMovementFlags(ItemTouchHelper.UP | ItemTouchHelper.DOWN, 0); + } + + @Override + public boolean onMove(@NonNull RecyclerView recyclerView, + @NonNull RecyclerView.ViewHolder source, + @NonNull RecyclerView.ViewHolder target) { + if (source.getItemViewType() != target.getItemViewType()) { + return false; + } + + //noinspection deprecation + mListener.onItemMove(source.getAdapterPosition(), target.getAdapterPosition()); + return true; + } + + @Override + public void onSwiped(@NonNull RecyclerView.ViewHolder viewHolder, int i) { + + } +} diff --git a/src/org/lineageos/eleven/widgets/DragSortListener.java b/src/org/lineageos/eleven/widgets/DragSortListener.java new file mode 100644 index 0000000000000000000000000000000000000000..763795862ec0b1e7ecc7c3ae49128163e93b0898 --- /dev/null +++ b/src/org/lineageos/eleven/widgets/DragSortListener.java @@ -0,0 +1,21 @@ +/* + * Copyright (C) 2021 The LineageOS Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.lineageos.eleven.widgets; + +public interface DragSortListener { + + void onItemMove(int startPosition, int endPosition); +} diff --git a/src/org/lineageos/eleven/widgets/FrameLayoutWithOverlay.java b/src/org/lineageos/eleven/widgets/FrameLayoutWithOverlay.java deleted file mode 100644 index 3a311f58fdf07a3e6295f2afe078362e2f062120..0000000000000000000000000000000000000000 --- a/src/org/lineageos/eleven/widgets/FrameLayoutWithOverlay.java +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Copyright (C) 2012 The Android Open Source Project Licensed under the Apache - * License, Version 2.0 (the "License"); you may not use this file except in - * compliance with the License. You may obtain a copy of the License at - * http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law - * or agreed to in writing, software distributed under the License is - * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ - -package org.lineageos.eleven.widgets; - -import android.content.Context; -import android.util.AttributeSet; -import android.view.View; -import android.view.ViewGroup; -import android.widget.FrameLayout; - -/** - * A FrameLayout whose contents are kept beneath an - * {@link AlphaTouchInterceptorOverlay}. If necessary, you can specify your own - * alpha-layer and manually manage its z-order. - */ -public class FrameLayoutWithOverlay extends FrameLayout { - - private final AlphaTouchInterceptorOverlay mOverlay; - - /** - * @param context The {@link Context} to use - * @param attrs The attributes of the XML tag that is inflating the view. - */ - public FrameLayoutWithOverlay(final Context context, final AttributeSet attrs) { - super(context, attrs); - - /* Programmatically create touch-interceptor View. */ - mOverlay = new AlphaTouchInterceptorOverlay(context); - - addView(mOverlay); - } - - /** - * After adding the View, bring the overlay to the front to ensure it's - * always on top. - */ - @Override - public void addView(final View child, final int index, final ViewGroup.LayoutParams params) { - super.addView(child, index, params); - mOverlay.bringToFront(); - } - - /** - * Delegate to overlay: set the View that it will use as its alpha-layer. If - * none is set, the overlay will use its own alpha layer. Only necessary to - * set this if some child views need to appear above the alpha-layer. - */ - protected void setAlphaLayer(final View layer) { - mOverlay.setAlphaLayer(layer); - } - - /** Delegate to overlay: set the alpha value on the alpha layer. */ - public void setAlphaLayerValue(final float alpha) { - mOverlay.setAlphaLayerValue(alpha); - } - - /** Delegate to overlay. */ - public void setOverlayOnClickListener(final OnClickListener listener) { - mOverlay.setOverlayOnClickListener(listener); - } - - /** Delegate to overlay. */ - public void setOverlayClickable(final boolean clickable) { - mOverlay.setOverlayClickable(clickable); - } -} diff --git a/src/org/lineageos/eleven/widgets/IPopupMenuCallback.java b/src/org/lineageos/eleven/widgets/IPopupMenuCallback.java index a7971757664cf1feb8bc398af009349792331b57..4c5030b5e1e94a6039096e181b7198e6f3adae5c 100644 --- a/src/org/lineageos/eleven/widgets/IPopupMenuCallback.java +++ b/src/org/lineageos/eleven/widgets/IPopupMenuCallback.java @@ -1,26 +1,27 @@ /* -* Copyright (C) 2014 The CyanogenMod Project -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ + * Copyright (C) 2014 The CyanogenMod Project + * Copyright (C) 2021 The LineageOS Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package org.lineageos.eleven.widgets; import android.view.View; public interface IPopupMenuCallback { - public static interface IListener { + interface IListener { void onPopupMenuClicked(final View v, final int position); - }; + } - public void setPopupMenuClickedListener(final IListener listener); + void setPopupMenuClickedListener(final IListener listener); } diff --git a/src/org/lineageos/eleven/widgets/LayoutSuppressingImageView.java b/src/org/lineageos/eleven/widgets/LayoutSuppressingImageView.java index 457a9947c2e3cdf1ae08a8876cb5c1909963aa18..f48ef9781c8607e9cecd10b5ef26985509628c2a 100644 --- a/src/org/lineageos/eleven/widgets/LayoutSuppressingImageView.java +++ b/src/org/lineageos/eleven/widgets/LayoutSuppressingImageView.java @@ -1,14 +1,19 @@ /* - * Copyright (C) 2012 Android Open Source Project Licensed under the Apache - * License, Version 2.0 (the "License"); you may not use this file except in - * compliance with the License. You may obtain a copy of the License at - * http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law - * or agreed to in writing, software distributed under the License is - * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the specific language - * governing permissions and limitations under the License. + * Copyright (C) 2012 The Android Open Source Project + * Copyright (C) 2021 The LineageOS Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ - package org.lineageos.eleven.widgets; import android.annotation.SuppressLint; @@ -16,29 +21,27 @@ import android.content.Context; import android.util.AttributeSet; import android.widget.ImageView; +import androidx.appcompat.widget.AppCompatImageView; + /** * A custom {@link ImageView} that improves the performance by not passing * requestLayout() to its parent, taking advantage of knowing that image size * won't change once set. */ -public class LayoutSuppressingImageView extends ImageView { +public class LayoutSuppressingImageView extends AppCompatImageView { /** * @param context The {@link Context} to use - * @param attrs The attributes of the XML tag that is inflating the view + * @param attrs The attributes of the XML tag that is inflating the view */ public LayoutSuppressingImageView(final Context context, final AttributeSet attrs) { super(context, attrs); } - /** - * {@inheritDoc} - */ @SuppressLint("MissingSuperCall") @Override public void requestLayout() { forceLayout(); } - } diff --git a/src/org/lineageos/eleven/widgets/LetterTileDrawable.java b/src/org/lineageos/eleven/widgets/LetterTileDrawable.java index 89ee8a8733ffb93b17c816d68b02d6aba509bf39..546c3a722f1ecbaca479b049bd0f0cb0efc9e1f6 100644 --- a/src/org/lineageos/eleven/widgets/LetterTileDrawable.java +++ b/src/org/lineageos/eleven/widgets/LetterTileDrawable.java @@ -1,5 +1,7 @@ /* * Copyright (C) 2013 The Android Open Source Project + * Copyright (C) 2021 The LineageOS Project + * Copyright (C) 2021 SHIFT GmbH * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -13,14 +15,12 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package org.lineageos.eleven.widgets; import android.content.Context; import android.content.res.Resources; import android.content.res.TypedArray; import android.graphics.Bitmap; -import android.graphics.BitmapFactory; import android.graphics.Canvas; import android.graphics.ColorFilter; import android.graphics.Paint; @@ -30,12 +30,14 @@ import android.graphics.Typeface; import android.graphics.drawable.Drawable; import android.text.TextUtils; +import androidx.annotation.NonNull; import androidx.core.content.ContextCompat; +import androidx.core.content.res.ResourcesCompat; import org.lineageos.eleven.R; import org.lineageos.eleven.cache.ImageWorker.ImageType; -import org.lineageos.eleven.utils.colors.BitmapWithColors; import org.lineageos.eleven.utils.MusicUtils; +import org.lineageos.eleven.utils.colors.BitmapWithColors; /** * A drawable that encapsulates all the functionality needed to display a letter tile to @@ -47,7 +49,9 @@ public class LetterTileDrawable extends Drawable { private final Paint mPaint; - /** Letter tile */ + /** + * Letter tile + */ private static TypedArray sColors; private static TypedArray sVibrantDarkColors; private static int sDefaultColor; @@ -60,16 +64,16 @@ public class LetterTileDrawable extends Drawable { private static Bitmap DEFAULT_PLAYLIST; private static Bitmap DEFAULT_PLAYLIST_LARGE; - /** Reusable components to avoid new allocations */ + /** + * Reusable components to avoid new allocations + */ private static final Paint sPaint = new Paint(); private static final Rect sRect = new Rect(); private static final char[] sChars = new char[2]; private String mDisplayName; private String mIdentifier; - private float mScale = 1.0f; private float mOffset = 0.0f; - private Resources res; private boolean mIsCircle = false; private ImageType mImageType; @@ -82,12 +86,29 @@ public class LetterTileDrawable extends Drawable { sDefaultColor = ContextCompat.getColor(context, R.color.letter_tile_default_color); sTileFontColor = ContextCompat.getColor(context, R.color.letter_tile_font_color); sLetterToTileRatio = res.getFraction(R.fraction.letter_to_tile_ratio, 1, 1); - DEFAULT_ARTIST = BitmapFactory.decodeResource(res, R.drawable.ic_artist); - DEFAULT_ARTIST_LARGE = BitmapFactory.decodeResource(res, R.drawable.ic_artist_lg); - DEFAULT_ALBUM = BitmapFactory.decodeResource(res, R.drawable.ic_album); - DEFAULT_ALBUM_LARGE = BitmapFactory.decodeResource(res, R.drawable.ic_album_lg); - DEFAULT_PLAYLIST = BitmapFactory.decodeResource(res, R.drawable.ic_playlist); - DEFAULT_PLAYLIST_LARGE = BitmapFactory.decodeResource(res, R.drawable.ic_playlist_lg); + + final Drawable artistDrawable = ResourcesCompat.getDrawable(res, + R.drawable.ic_artist, context.getTheme()); + final Drawable albumDrawable = ResourcesCompat.getDrawable(res, + R.drawable.ic_album, context.getTheme()); + final Drawable playlistDrawable = ResourcesCompat.getDrawable(res, + R.drawable.ic_playlist, context.getTheme()); + + final int defaultSize = res.getDimensionPixelSize(R.dimen.list_icon_default); + final int largeSize = res.getDimensionPixelSize(R.dimen.list_icon_large); + + if (artistDrawable != null) { + DEFAULT_ARTIST = setupBitmap(artistDrawable, defaultSize); + DEFAULT_ARTIST_LARGE = setupBitmap(artistDrawable, largeSize); + } + if (albumDrawable != null) { + DEFAULT_ALBUM = setupBitmap(albumDrawable, defaultSize); + DEFAULT_ALBUM_LARGE = setupBitmap(albumDrawable, largeSize); + } + if (playlistDrawable != null) { + DEFAULT_PLAYLIST = setupBitmap(playlistDrawable, defaultSize); + DEFAULT_PLAYLIST_LARGE = setupBitmap(playlistDrawable, largeSize); + } sPaint.setTypeface(Typeface.create( res.getString(R.string.letter_tile_letter_font_family), Typeface.NORMAL)); @@ -100,7 +121,6 @@ public class LetterTileDrawable extends Drawable { mPaint = new Paint(); mPaint.setFilterBitmap(true); mPaint.setDither(true); - res = context.getResources(); initializeStaticVariables(context); } @@ -136,6 +156,7 @@ public class LetterTileDrawable extends Drawable { } // Draw letter/digit only if the first character is an english letter + final float scale = 1.0f; if (mDisplayName != null && !mDisplayName.isEmpty() && isEnglishLetter(mDisplayName.charAt(0))) { int numChars = 1; @@ -149,7 +170,7 @@ public class LetterTileDrawable extends Drawable { } // Scale text by canvas bounds and user selected scaling factor - sPaint.setTextSize(mScale * sLetterToTileRatio * minDimension); + sPaint.setTextSize(sLetterToTileRatio * minDimension); //sPaint.setTextSize(sTileLetterFontSize); sPaint.getTextBounds(sChars, 0, numChars, sRect); sPaint.setColor(sTileFontColor); @@ -167,7 +188,7 @@ public class LetterTileDrawable extends Drawable { // height ratio. final Rect destRect = copyBounds(); - drawBitmap(bitmap, bitmap.getWidth(), bitmap.getHeight(), canvas, destRect, mScale, + drawBitmap(bitmap, bitmap.getWidth(), bitmap.getHeight(), canvas, destRect, mOffset, mPaint); } } @@ -230,8 +251,8 @@ public class LetterTileDrawable extends Drawable { return small ? DEFAULT_ARTIST : DEFAULT_ARTIST_LARGE; case ALBUM: return small ? DEFAULT_ALBUM : DEFAULT_ALBUM_LARGE; - case PLAYLIST: - return small ? DEFAULT_PLAYLIST : DEFAULT_PLAYLIST_LARGE; + case PLAYLIST: + return small ? DEFAULT_PLAYLIST : DEFAULT_PLAYLIST_LARGE; default: throw new IllegalArgumentException("Unrecognized image type"); } @@ -256,27 +277,17 @@ public class LetterTileDrawable extends Drawable { return android.graphics.PixelFormat.OPAQUE; } - /** - * Scale the drawn letter tile to a ratio of its default size - * - * @param scale The ratio the letter tile should be scaled to as a percentage of its default - * size, from a scale of 0 to 2.0f. The default is 1.0f. - */ - public void setScale(float scale) { - mScale = scale; - } - /** * Assigns the vertical offset of the position of the letter tile to the ContactDrawable * * @param offset The provided offset must be within the range of -0.5f to 0.5f. - * If set to -0.5f, the letter will be shifted upwards by 0.5 times the height of the canvas - * it is being drawn on, which means it will be drawn with the center of the letter starting - * at the top edge of the canvas. - * If set to 0.5f, the letter will be shifted downwards by 0.5 times the height of the canvas - * it is being drawn on, which means it will be drawn with the center of the letter starting - * at the bottom edge of the canvas. - * The default is 0.0f. + * If set to -0.5f, the letter will be shifted upwards by 0.5 times the height of + * the canvas it is being drawn on, which means it will be drawn with the center + * of the letter starting at the top edge of the canvas. + * If set to 0.5f, the letter will be shifted downwards by 0.5 times the height of + * the canvas it is being drawn on, which means it will be drawn with the center + * of the letter starting at the bottom edge of the canvas. + * The default is 0.0f. */ public void setOffset(float offset) { mOffset = offset; @@ -284,12 +295,13 @@ public class LetterTileDrawable extends Drawable { /** * Sets the tile data used to determine the display text and color + * * @param displayName the name to display - Some logic will be applied to do some trimming * and up to the first two letters will be displayed - * @param identifier the identifier used to determine the color of the background. For - * album, use albumId, for artist use artistName and for playlist use - * playlistId - * @param type the type of item that this tile drawable corresponds to + * @param identifier the identifier used to determine the color of the background. For + * album, use albumId, for artist use artistName and for playlist use + * playlistId + * @param type the type of item that this tile drawable corresponds to */ public void setTileDetails(final String displayName, final String identifier, final ImageType type) { @@ -304,13 +316,13 @@ public class LetterTileDrawable extends Drawable { } /** - * Draw the bitmap onto the canvas at the current bounds taking into account the current scale. + * Draw the bitmap onto the canvas at the current bounds. */ private static void drawBitmap(final Bitmap bitmap, final int width, final int height, - final Canvas canvas, final Rect destRect, final float scale, + final Canvas canvas, final Rect destRect, final float offset, final Paint paint) { - // Crop the destination bounds into a square, scaled and offset as appropriate - final int halfLength = (int) (scale * Math.min(destRect.width(), destRect.height()) / 2); + // Crop the destination bounds into a square, offset as appropriate + final int halfLength = (int) ((float) Math.min(destRect.width(), destRect.height()) / 2); destRect.set(destRect.centerX() - halfLength, (int) (destRect.centerY() - halfLength + offset * destRect.height()), @@ -325,16 +337,18 @@ public class LetterTileDrawable extends Drawable { /** * Draws the default letter tile drawable for the image type to a bitmap - * @param identifier the identifier used to determine the color of the background. For - * album, use albumId, for artist use artistName and for playlist use - * playlistId - * @param type the type of item that this tile drawable corresponds to - * @param isCircle whether to draw a circle or a square + * + * @param identifier the identifier used to determine the color of the background. For + * album, use albumId, for artist use artistName and for playlist use + * playlistId + * @param type the type of item that this tile drawable corresponds to + * @param isCircle whether to draw a circle or a square * @param smallArtwork true if you want to draw a smaller version of the default bitmap for * perf/memory reasons */ public static BitmapWithColors createDefaultBitmap(Context context, String identifier, - ImageType type, boolean isCircle, boolean smallArtwork) { + ImageType type, boolean isCircle, + boolean smallArtwork) { initializeStaticVariables(context); identifier = MusicUtils.getTrimmedName(identifier); @@ -364,8 +378,16 @@ public class LetterTileDrawable extends Drawable { // draw to the bitmap drawBitmap(defaultBitmap, defaultBitmap.getWidth(), defaultBitmap.getHeight(), canvas, - bounds, 1, 0, paint); + bounds, 0, paint); return new BitmapWithColors(createdBitmap, identifier.hashCode(), color, vibrantDarkColor); } + + private static Bitmap setupBitmap(@NonNull Drawable drawable, int size) { + final Bitmap bitmap = Bitmap.createBitmap(size, size, Bitmap.Config.ARGB_8888); + final Canvas c = new Canvas(bitmap); + drawable.setBounds(0, 0, c.getWidth(), c.getHeight()); + drawable.draw(c); + return bitmap; + } } diff --git a/src/org/lineageos/eleven/widgets/LoadingEmptyContainer.java b/src/org/lineageos/eleven/widgets/LoadingEmptyContainer.java index 767bc687975c9d3d30903a62551f010047863f16..8774660f255bb08bf1e854ccb27f2e0d93e0c12d 100644 --- a/src/org/lineageos/eleven/widgets/LoadingEmptyContainer.java +++ b/src/org/lineageos/eleven/widgets/LoadingEmptyContainer.java @@ -1,6 +1,6 @@ /* * Copyright (C) 2014 The CyanogenMod Project - * Copyright (C) 2019 The LineageOS Project + * Copyright (C) 2019-2021 The LineageOS Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -33,8 +33,8 @@ import org.lineageos.eleven.R; public class LoadingEmptyContainer extends FrameLayout { private static final int LOADING_DELAY = 300; - private Handler mHandler; - private Runnable mShowLoadingRunnable; + private final Handler mHandler; + private final Runnable mShowLoadingRunnable; public LoadingEmptyContainer(Context context, AttributeSet attrs) { super(context, attrs); @@ -76,6 +76,6 @@ public class LoadingEmptyContainer extends FrameLayout { } public NoResultsContainer getNoResultsContainer() { - return (NoResultsContainer)findViewById(R.id.no_results_container); + return (NoResultsContainer) findViewById(R.id.no_results_container); } } diff --git a/src/org/lineageos/eleven/widgets/MainPlaybackControls.java b/src/org/lineageos/eleven/widgets/MainPlaybackControls.java index b1cff8421d1c244a507c676e77c7a0eca91b2e28..de1a0dba66fb6cb71e5d75f3d82a5e1a972c72cc 100644 --- a/src/org/lineageos/eleven/widgets/MainPlaybackControls.java +++ b/src/org/lineageos/eleven/widgets/MainPlaybackControls.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2019 The LineageOS Project + * Copyright (C) 2019-2021 The LineageOS Project * Copyright (C) 2019 SHIFT GmbH * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -38,9 +38,7 @@ public class MainPlaybackControls extends FrameLayout { private final SeekBar mSeeker; private final ShuffleButton mShuffleButton; - private final RepeatingImageButton mPreviousButton; private final PlayPauseButtonContainer mPlayPauseButtonContainer; - private final RepeatingImageButton mNextButton; private final RepeatButton mRepeatButton; public MainPlaybackControls(@NonNull Context context) { @@ -69,14 +67,32 @@ public class MainPlaybackControls extends FrameLayout { mPlayPauseButtonContainer = findViewById(R.id.playPauseProgressButton); mShuffleButton = findViewById(R.id.action_button_shuffle); mRepeatButton = findViewById(R.id.action_button_repeat); - mPreviousButton = findViewById(R.id.action_button_previous); - mNextButton = findViewById(R.id.action_button_next); + final RepeatingImageButton previousButton = findViewById(R.id.action_button_previous); + final RepeatingImageButton nextButton = findViewById(R.id.action_button_next); + + mSeeker.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() { + @Override + public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { + if (fromUser) { + refreshCurrentTimeText(progress); + } + } + + @Override + public void onStartTrackingTouch(SeekBar seekBar) { + // ignore + } - mSeeker.setOnSeekBarChangeListener(mSeekerListener); + @Override + public void onStopTrackingTouch(SeekBar seekBar) { + final long wantedDurationInMs = seekBar.getProgress() * 1000L; + MusicUtils.seek(wantedDurationInMs); + } + }); - mPreviousButton.setRepeatListener( + previousButton.setRepeatListener( (v, delta, repeatCount) -> seekRelative(repeatCount, delta, false)); - mNextButton.setRepeatListener( + nextButton.setRepeatListener( (v, delta, repeatCount) -> seekRelative(repeatCount, delta, true)); mPlayPauseButtonContainer.enableAndShow(); @@ -138,28 +154,6 @@ public class MainPlaybackControls extends FrameLayout { } // endregion refresh time - // region seeking - private final SeekBar.OnSeekBarChangeListener mSeekerListener = - new SeekBar.OnSeekBarChangeListener() { - @Override - public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { - if (fromUser) { - refreshCurrentTimeText(progress); - } - } - - @Override - public void onStartTrackingTouch(SeekBar seekBar) { - // ignore - } - - @Override - public void onStopTrackingTouch(SeekBar seekBar) { - final long wantedDurationInMs = seekBar.getProgress() * 1000L; - MusicUtils.seek(wantedDurationInMs); - } - }; - private void seekRelative(final int repeatCount, long delta, boolean forwards) { if (!MusicUtils.isPlaybackServiceConnected()) { return; @@ -179,5 +173,4 @@ public class MainPlaybackControls extends FrameLayout { refreshCurrentTime(); } } - // endregion seeking } diff --git a/src/org/lineageos/eleven/widgets/NoResultsContainer.java b/src/org/lineageos/eleven/widgets/NoResultsContainer.java index 1bff189008d2d1a99d247da13b8c9310921572dc..ff9c4de552d29b1d7183818514a3b1dde2b02cfa 100644 --- a/src/org/lineageos/eleven/widgets/NoResultsContainer.java +++ b/src/org/lineageos/eleven/widgets/NoResultsContainer.java @@ -1,24 +1,24 @@ /* -* Copyright (C) 2014 The CyanogenMod Project -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ + * Copyright (C) 2014 The CyanogenMod Project + * Copyright (C) 2021 The LineageOS Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package org.lineageos.eleven.widgets; import android.content.Context; import android.graphics.PorterDuff; import android.util.AttributeSet; -import android.view.View; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.TextView; @@ -38,30 +38,22 @@ public class NoResultsContainer extends LinearLayout { /** * This changes the Main text (top-most text) of the empty container + * * @param resId String resource id */ public void setMainText(final int resId) { - ((TextView)findViewById(R.id.no_results_main_text)).setText(resId); - } - - public void setMainHighlightText(final String text) { - final TextView hightlightText = findViewById(R.id.no_results_main_highlight_text); - - if (text == null || text.isEmpty()) { - hightlightText.setVisibility(View.GONE); - } else { - hightlightText.setText(text); - hightlightText.setVisibility(View.VISIBLE); - } + ((TextView) findViewById(R.id.no_results_main_text)).setText(resId); } public void setSecondaryText(final int resId) { - ((TextView)findViewById(R.id.no_results_secondary_text)).setText(resId); + ((TextView) findViewById(R.id.no_results_secondary_text)).setText(resId); } public void setTextColor(int color) { - ((TextView)findViewById(R.id.no_results_main_text)).setTextColor(color); - ((TextView)findViewById(R.id.no_results_main_highlight_text)).setTextColor(color); - ((TextView)findViewById(R.id.no_results_secondary_text)).setTextColor(color); + ((ImageView) findViewById(R.id.no_results_image)) + .setColorFilter(color, PorterDuff.Mode.SRC_IN); + ((TextView) findViewById(R.id.no_results_main_text)).setTextColor(color); + ((TextView) findViewById(R.id.no_results_main_highlight_text)).setTextColor(color); + ((TextView) findViewById(R.id.no_results_secondary_text)).setTextColor(color); } } diff --git a/src/org/lineageos/eleven/widgets/PlayPauseButton.java b/src/org/lineageos/eleven/widgets/PlayPauseButton.java index 8edaf7f90f26fd93485ea24ac426663f759614f8..d2ed55533bb440c46c3af3a28be2d5f8043e732a 100644 --- a/src/org/lineageos/eleven/widgets/PlayPauseButton.java +++ b/src/org/lineageos/eleven/widgets/PlayPauseButton.java @@ -1,7 +1,8 @@ /* * Copyright (C) 2012 Andrew Neal * Copyright (C) 2014 The CyanogenMod Project - * Copyright (C) 2019 The LineageOS Project + * Copyright (C) 2019-2021 The LineageOS Project + * Copyright (C) 2021 SHIFT GmbH * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -15,19 +16,19 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package org.lineageos.eleven.widgets; -import android.animation.Animator; import android.content.Context; +import android.graphics.drawable.AnimatedVectorDrawable; +import android.graphics.drawable.Drawable; import android.text.TextUtils; import android.util.AttributeSet; import android.view.View; -import android.view.ViewAnimationUtils; import android.view.View.OnClickListener; import android.view.View.OnLongClickListener; import androidx.appcompat.widget.AppCompatImageButton; +import androidx.core.content.ContextCompat; import org.lineageos.eleven.R; import org.lineageos.eleven.utils.ElevenUtils; @@ -41,9 +42,11 @@ import org.lineageos.eleven.utils.MusicUtils; public class PlayPauseButton extends AppCompatImageButton implements OnClickListener, OnLongClickListener { + private boolean isPlaying; + /** * @param context The {@link Context} to use - * @param attrs The attributes of the XML tag that is inflating the view. + * @param attrs The attributes of the XML tag that is inflating the view. */ public PlayPauseButton(final Context context, final AttributeSet attrs) { super(context, attrs); @@ -57,17 +60,6 @@ public class PlayPauseButton extends AppCompatImageButton @Override public void onClick(final View v) { MusicUtils.playOrPause(); - int centerX = (v.getLeft() + v.getRight()) / 2; - int centerY = (v.getTop() + v.getBottom()) / 2; - int startRadius = 0; - int endRadius = (int) Math.hypot(v.getWidth(), v.getHeight()); - - Animator anim = ViewAnimationUtils.createCircularReveal( - v, centerX, centerY, startRadius, endRadius); - - anim.setDuration(800); - anim.start(); - updateState(); } @@ -85,12 +77,23 @@ public class PlayPauseButton extends AppCompatImageButton * Sets the correct drawable for playback. */ public void updateState() { - if (MusicUtils.isPlaying()) { + final boolean newState = MusicUtils.isPlaying(); + if (isPlaying == newState) { + return; + } + + isPlaying = newState; + final Drawable drawable; + if (newState) { setContentDescription(getResources().getString(R.string.accessibility_pause)); - setImageResource(R.drawable.btn_playback_pause); + drawable = ContextCompat.getDrawable(getContext(), R.drawable.avd_play_to_pause); } else { setContentDescription(getResources().getString(R.string.accessibility_play)); - setImageResource(R.drawable.btn_playback_play); + drawable = ContextCompat.getDrawable(getContext(), R.drawable.avd_pause_to_play); + } + setImageDrawable(drawable); + if (drawable instanceof AnimatedVectorDrawable) { + ((AnimatedVectorDrawable) drawable).start(); } } } diff --git a/src/org/lineageos/eleven/widgets/PlayPauseButtonContainer.java b/src/org/lineageos/eleven/widgets/PlayPauseButtonContainer.java index 181670f3693732009d202bdc4b47a5c86d536d12..8a0ef6f18220686bb54b7a0955de10f7017028fa 100644 --- a/src/org/lineageos/eleven/widgets/PlayPauseButtonContainer.java +++ b/src/org/lineageos/eleven/widgets/PlayPauseButtonContainer.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2019 The LineageOS Project + * Copyright (C) 2019-2021 The LineageOS Project * Copyright (C) 2019 SHIFT GmbH * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -19,13 +19,11 @@ package org.lineageos.eleven.widgets; import android.content.Context; import android.util.AttributeSet; import android.widget.FrameLayout; -import android.widget.ProgressBar; import org.lineageos.eleven.R; public class PlayPauseButtonContainer extends FrameLayout { private PlayPauseButton mPlayPauseButton; - private ProgressBar mCircularProgressBar; public PlayPauseButtonContainer(Context context, AttributeSet attrs) { super(context, attrs); @@ -39,7 +37,6 @@ public class PlayPauseButtonContainer extends FrameLayout { super.onFinishInflate(); mPlayPauseButton = findViewById(R.id.action_button_play); - mCircularProgressBar = findViewById(R.id.circularProgressBar); } @Override diff --git a/src/org/lineageos/eleven/widgets/PlayPauseProgressButton.java b/src/org/lineageos/eleven/widgets/PlayPauseProgressButton.java new file mode 100644 index 0000000000000000000000000000000000000000..608a905f674f7d1923277d68c1fdc00272336372 --- /dev/null +++ b/src/org/lineageos/eleven/widgets/PlayPauseProgressButton.java @@ -0,0 +1,173 @@ +/* + * Copyright (c) 2013, The Linux Foundation. All rights reserved. + * Copyright (C) 2015 The CyanogenMod Project + * Copyright (C) 2021 The LineageOS Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.lineageos.eleven.widgets; + +import android.content.Context; +import android.util.AttributeSet; +import android.widget.FrameLayout; +import android.widget.ProgressBar; + +import org.lineageos.eleven.R; +import org.lineageos.eleven.utils.MusicUtils; + +/** + * This class handles the play-pause button as well as the circular progress bar + * it self-updates the progress bar but the containing activity/fragment + * needs to add code to pause/resume this button to prevent unnecessary + * updates while the activity/fragment is not visible + */ +public class PlayPauseProgressButton extends FrameLayout { + private ProgressBar mProgressBar; + private PlayPauseButton mPlayPauseButton; + private Runnable mUpdateProgress; + private boolean mPaused; + + public PlayPauseProgressButton(Context context, AttributeSet attrs) { + super(context, attrs); + + // set enabled to false as default so that calling enableAndShow will execute + setEnabled(false); + + // set paused to false since we shouldn't be typically created while not visible + mPaused = false; + } + + @Override + protected void onFinishInflate() { + super.onFinishInflate(); + + mPlayPauseButton = findViewById(R.id.action_button_play); + mProgressBar = findViewById(R.id.circularProgressBarAlt); + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + + // Make the play pause button size dependent on the container size + int horizontalPadding = getMeasuredWidth() / 4; + int verticalPadding = getMeasuredHeight() / 4; + mPlayPauseButton.setPadding( + horizontalPadding, horizontalPadding, + verticalPadding, verticalPadding); + + // rotate the progress bar 90 degrees counter clockwise so that the + // starting position is at the top + mProgressBar.setPivotX(mProgressBar.getMeasuredWidth() / 2f); + mProgressBar.setPivotY(mProgressBar.getMeasuredHeight() / 2f); + mProgressBar.setRotation(-90); + } + + /** + * Enable and shows the container + */ + public void enableAndShow() { + // enable + setEnabled(true); + + // make our view visible + setVisibility(VISIBLE); + } + + @Override + public void setEnabled(boolean enabled) { + // if the enabled state isn't changed, quit + if (enabled == isEnabled()) { + return; + } + + super.setEnabled(enabled); + // signal our state has changed + onStateChanged(); + } + + /** + * Pauses the progress bar periodic update logic + */ + public void pause() { + if (mPaused) { + return; + } + + mPaused = true; + // signal our state has changed + onStateChanged(); + } + + /** + * Signaled if the state has changed (either the enabled or paused flag) + * When the state changes, we either kick off the updates or remove them + * based on those flags + */ + private void onStateChanged() { + // if we are enabled and not paused + if (isEnabled() && !mPaused) { + // update the state of the progress bar and play/pause button + updateState(); + + // kick off update states + postUpdate(); + } else { + // otherwise remove our update + removeUpdate(); + } + } + + /** + * Updates the state of the progress bar and the play pause button + */ + public void updateState() { + long currentSongDuration = MusicUtils.duration(); + long currentSongProgress = MusicUtils.position(); + + int progress = 0; + if (currentSongDuration > 0) { + progress = (int) (mProgressBar.getMax() * currentSongProgress / currentSongDuration); + } + + mProgressBar.setProgress(progress); + mPlayPauseButton.updateState(); + } + + /** + * Creates and posts the update runnable to the handler + */ + private void postUpdate() { + if (mUpdateProgress == null) { + mUpdateProgress = () -> { + updateState(); + postDelayed(mUpdateProgress, MusicUtils.UPDATE_FREQUENCY_MS); + }; + } + + // remove any existing callbacks + removeCallbacks(mUpdateProgress); + + // post ourselves as a delayed + post(mUpdateProgress); + } + + /** + * Removes the runnable from the handler + */ + private void removeUpdate() { + if (mUpdateProgress != null) { + removeCallbacks(mUpdateProgress); + } + } +} diff --git a/src/org/lineageos/eleven/widgets/PopupMenuButton.java b/src/org/lineageos/eleven/widgets/PopupMenuButton.java index a400bf47795b55836b8484089479d01e25b06060..c5042b378b3ceaa380034c9add4007792dbde4dc 100644 --- a/src/org/lineageos/eleven/widgets/PopupMenuButton.java +++ b/src/org/lineageos/eleven/widgets/PopupMenuButton.java @@ -1,30 +1,32 @@ /* -* Copyright (C) 2014 The CyanogenMod Project -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ - + * Copyright (C) 2014 The CyanogenMod Project + * Copyright (C) 2021 The LineageOS Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package org.lineageos.eleven.widgets; import android.content.Context; import android.util.AttributeSet; import android.view.View; -import android.widget.ImageView; + +import androidx.appcompat.widget.AppCompatImageButton; +import androidx.core.content.ContextCompat; import org.lineageos.eleven.R; -public class PopupMenuButton extends ImageView implements IPopupMenuCallback, - View.OnClickListener { +public class PopupMenuButton extends AppCompatImageButton + implements IPopupMenuCallback, View.OnClickListener { protected int mPosition = -1; protected IListener mClickListener = null; @@ -32,7 +34,7 @@ public class PopupMenuButton extends ImageView implements IPopupMenuCallback, super(context, attrs); setScaleType(ScaleType.CENTER_INSIDE); - setBackground(getResources().getDrawable(R.drawable.selectable_background_light)); + setBackground(ContextCompat.getDrawable(context, R.drawable.selectable_background_light)); setOnClickListener(this); } diff --git a/src/org/lineageos/eleven/widgets/QueueButton.java b/src/org/lineageos/eleven/widgets/QueueButton.java deleted file mode 100644 index f4aab93379ef3ee37da3a5aa8633784a61735da3..0000000000000000000000000000000000000000 --- a/src/org/lineageos/eleven/widgets/QueueButton.java +++ /dev/null @@ -1,34 +0,0 @@ -/* -* Copyright (C) 2014 The CyanogenMod Project -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ -package org.lineageos.eleven.widgets; - -import android.content.Context; -import android.util.AttributeSet; -import android.view.View; - -import org.lineageos.eleven.ui.activities.SlidingPanelActivity; - -public class QueueButton extends AudioActivityButton { - - public QueueButton(Context context, AttributeSet attrs) { - super(context, attrs); - } - - @Override - public void onClick(View view) { - mActivity.showPanel(SlidingPanelActivity.Panel.Queue); - } -} \ No newline at end of file diff --git a/src/org/lineageos/eleven/widgets/RepeatButton.java b/src/org/lineageos/eleven/widgets/RepeatButton.java index 8d69afd47e14951596e3e935c18bdc829cecc6e1..f9d593672a03de2e97ef2e43be4f73012770366c 100644 --- a/src/org/lineageos/eleven/widgets/RepeatButton.java +++ b/src/org/lineageos/eleven/widgets/RepeatButton.java @@ -1,16 +1,20 @@ /* * Copyright (C) 2012 Andrew Neal * Copyright (C) 2014 The CyanogenMod Project - * Licensed under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law - * or agreed to in writing, software distributed under the License is - * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the specific language - * governing permissions and limitations under the License. + * Copyright (C) 2021 The LineageOS Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ - package org.lineageos.eleven.widgets; import android.content.Context; @@ -38,7 +42,9 @@ public class RepeatButton extends AudioButton { updateRepeatState(); } - /** Sets the correct drawable for the repeat state. */ + /** + * Sets the correct drawable for the repeat state. + */ public void updateRepeatState() { switch (MusicUtils.getRepeatMode()) { case MusicPlaybackService.REPEAT_ALL: diff --git a/src/org/lineageos/eleven/widgets/RepeatingImageButton.java b/src/org/lineageos/eleven/widgets/RepeatingImageButton.java index e54f6f226caf1568d0a0a1bb4e25bcd60abcbda4..5495a04799159b20257f550c2b548396963b2344 100644 --- a/src/org/lineageos/eleven/widgets/RepeatingImageButton.java +++ b/src/org/lineageos/eleven/widgets/RepeatingImageButton.java @@ -1,14 +1,19 @@ /* - * Copyright (C) 2008 The Android Open Source Project Licensed under the Apache - * License, Version 2.0 (the "License"); you may not use this file except in - * compliance with the License. You may obtain a copy of the License at - * http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law - * or agreed to in writing, software distributed under the License is - * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the specific language - * governing permissions and limitations under the License. + * Copyright (C) 2008 The Android Open Source Project + * Copyright (C) 2021 The LineageOS Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ - package org.lineageos.eleven.widgets; import android.content.Context; @@ -18,18 +23,20 @@ import android.view.KeyEvent; import android.view.MotionEvent; import android.view.View; import android.view.View.OnClickListener; -import android.widget.ImageButton; + +import androidx.appcompat.widget.AppCompatImageButton; +import androidx.core.content.ContextCompat; import org.lineageos.eleven.R; import org.lineageos.eleven.utils.ElevenUtils; import org.lineageos.eleven.utils.MusicUtils; /** - * A {@link ImageButton} that will repeatedly call a 'listener' method as long - * as the button is pressed, otherwise functions like a typecal - * {@link ImageButton} + * A {@link AppCompatImageButton} that will repeatedly call a 'listener' method as long + * as the button is pressed, otherwise functions like a typical + * {@link AppCompatImageButton} */ -public class RepeatingImageButton extends ImageButton implements OnClickListener { +public class RepeatingImageButton extends AppCompatImageButton implements OnClickListener { private static final long sInterval = 400; @@ -41,32 +48,25 @@ public class RepeatingImageButton extends ImageButton implements OnClickListener /** * @param context The {@link Context} to use - * @param attrs The attributes of the XML tag that is inflating the view. + * @param attrs The attributes of the XML tag that is inflating the view. */ - @SuppressWarnings("deprecation") public RepeatingImageButton(final Context context, final AttributeSet attrs) { super(context, attrs); setPadding(0, 0, 0, 0); - setBackground(getResources().getDrawable(R.drawable.selectable_background)); + setBackground(ContextCompat.getDrawable(context, R.drawable.selectable_background)); setFocusable(true); setLongClickable(true); setOnClickListener(this); updateState(); } - /** - * {@inheritDoc} - */ @Override public void onClick(final View view) { - switch (view.getId()) { - case R.id.action_button_previous: - MusicUtils.previous(getContext(), false); - break; - case R.id.action_button_next: - MusicUtils.next(); - default: - break; + final int id = view.getId(); + if (id == R.id.action_button_previous) { + MusicUtils.previous(getContext(), false); + } else if (id == R.id.action_button_next) { + MusicUtils.next(); } } @@ -75,15 +75,11 @@ public class RepeatingImageButton extends ImageButton implements OnClickListener * interval in milliseconds with which it will be called. * * @param l The listener that will be called - * @param interval The interval in milliseconds for calls */ public void setRepeatListener(final RepeatListener l) { mListener = l; } - /** - * {@inheritDoc} - */ @Override public boolean performLongClick() { if (mListener == null) { @@ -95,9 +91,6 @@ public class RepeatingImageButton extends ImageButton implements OnClickListener return true; } - /** - * {@inheritDoc} - */ @Override public boolean onTouchEvent(final MotionEvent event) { if (event.getAction() == MotionEvent.ACTION_UP) { @@ -111,9 +104,6 @@ public class RepeatingImageButton extends ImageButton implements OnClickListener return super.onTouchEvent(event); } - /** - * {@inheritDoc} - */ @Override public boolean onKeyDown(final int keyCode, final KeyEvent event) { switch (keyCode) { @@ -129,9 +119,6 @@ public class RepeatingImageButton extends ImageButton implements OnClickListener return super.onKeyDown(keyCode, event); } - /** - * {@inheritDoc} - */ @Override public boolean onKeyUp(final int keyCode, final KeyEvent event) { switch (keyCode) { @@ -159,7 +146,7 @@ public class RepeatingImageButton extends ImageButton implements OnClickListener /** * @param shouldRepeat If True the repeat count stops at -1, false if to add - * incrementally add the repeat count + * incrementally add the repeat count */ private void doRepeat(final boolean shouldRepeat) { final long now = SystemClock.elapsedRealtime(); @@ -172,26 +159,23 @@ public class RepeatingImageButton extends ImageButton implements OnClickListener * Sets the correct drawable for playback. */ public void updateState() { - switch (getId()) { - case R.id.action_button_next: - setImageDrawable(getResources().getDrawable(R.drawable.btn_playback_next)); - break; - case R.id.action_button_previous: - setImageDrawable(getResources().getDrawable(R.drawable.btn_playback_previous)); - break; - default: - break; + final Context context = getContext(); + final int id = getId(); + if (id == R.id.action_button_next) { + setImageDrawable(ContextCompat.getDrawable(context, R.drawable.btn_playback_next)); + } else if (id == R.id.action_button_previous) { + setImageDrawable(ContextCompat.getDrawable(context, R.drawable.btn_playback_previous)); } } public interface RepeatListener { /** - * @param v View to be set - * @param duration Duration of the long press - * @param repeatcount The number of repeat counts + * @param v View to be set + * @param duration Duration of the long press + * @param repeatCount The number of repeat counts */ - void onRepeat(View v, long duration, int repeatcount); + void onRepeat(View v, long duration, int repeatCount); } } diff --git a/src/org/lineageos/eleven/widgets/SectionSeparatorItemDecoration.java b/src/org/lineageos/eleven/widgets/SectionSeparatorItemDecoration.java new file mode 100644 index 0000000000000000000000000000000000000000..94cd23c04c6cd362a569056cdf8aacf574fcb6bd --- /dev/null +++ b/src/org/lineageos/eleven/widgets/SectionSeparatorItemDecoration.java @@ -0,0 +1,140 @@ +/* + * Copyright 2019 Google LLC + * Copyright (C) 2021 The LineageOS Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.lineageos.eleven.widgets; + +import android.content.Context; +import android.content.res.TypedArray; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Paint; +import android.graphics.Rect; +import android.text.StaticLayout; +import android.text.TextPaint; +import android.util.SparseArray; +import android.view.View; + +import androidx.annotation.NonNull; +import androidx.recyclerview.widget.RecyclerView; + +import org.lineageos.eleven.R; +import org.lineageos.eleven.utils.SectionCreatorUtils; + +import java.util.TreeMap; + +public class SectionSeparatorItemDecoration extends RecyclerView.ItemDecoration { + + private final SparseArray mLabels; + private final TextPaint mPaint; + private final int mTextWidth; + private final int mDecorHeight; + private final int mHorizontalPadding; + private final int mVerticalPadding; + private final float mVerticalBias; + + public SectionSeparatorItemDecoration(Context context, + TreeMap items) { + mPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG | Paint.SUBPIXEL_TEXT_FLAG); + + TypedArray attrs = context.obtainStyledAttributes( + R.style.SectionSeparator, + R.styleable.SectionSeparator); + float textSize = attrs.getDimension(R.styleable.SectionSeparator_android_textSize, + mPaint.getTextSize()); + mPaint.setTextSize(textSize); + + int textColor = attrs.getColor(R.styleable.SectionSeparator_android_textColor, + Color.BLACK); + mPaint.setColor(textColor); + + mTextWidth = attrs.getDimensionPixelSize(R.styleable.SectionSeparator_android_width, 0); + int height = attrs.getDimensionPixelSize(R.styleable.SectionSeparator_android_height, 0); + int minHeight = (int) Math.ceil(textSize); + mDecorHeight = Math.max(minHeight, height); + + mHorizontalPadding = attrs.getDimensionPixelSize( + R.styleable.SectionSeparator_android_paddingHorizontal, 0); + mVerticalPadding = attrs.getDimensionPixelSize( + R.styleable.SectionSeparator_android_paddingVertical, 0); + + float bias = attrs.getFloat(R.styleable.SectionSeparator_verticalBias, 0.5f); + if (bias > 1f) { + bias = 1f; + } else if (bias < 0f) { + bias = 0f; + } + mVerticalBias = bias; + + attrs.recycle(); + mLabels = buildLabels(items); + } + + private SparseArray buildLabels(TreeMap items) { + SparseArray sparseArray = new SparseArray<>(); + items.forEach((index, section) -> { + String text = section.mIdentifier; + StaticLayout label = newStaticLayout(text); + sparseArray.put(index, label); + }); + return sparseArray; + } + + @Override + public void getItemOffsets(@NonNull Rect outRect, @NonNull View child, + @NonNull RecyclerView parent, @NonNull RecyclerView.State state) { + int position = parent.getChildAdapterPosition(child); + outRect.top = hasLabel(position) ? mDecorHeight : 0; + } + + @Override + public void onDraw(@NonNull Canvas c, @NonNull RecyclerView parent, + @NonNull RecyclerView.State state) { + RecyclerView.LayoutManager layoutManager = parent.getLayoutManager(); + if (layoutManager == null) { + return; + } + + for (int i = 0; i < parent.getChildCount(); i++) { + View child = parent.getChildAt(i); + if (child != null && child.getTop() < parent.getHeight() && child.getBottom() > 0) { + // Child is visible + StaticLayout layout = mLabels.get(parent.getChildAdapterPosition(child), null); + if (layout != null) { + float dy = mVerticalPadding + + layoutManager.getDecoratedTop(child) + + child.getTranslationY() + + // offset vertically within the space according to the bias + (mDecorHeight - layout.getHeight()) * mVerticalBias; + c.translate(mHorizontalPadding, dy); + layout.draw(c); + c.translate(-mHorizontalPadding, -dy); + } + } + } + } + + private StaticLayout newStaticLayout(CharSequence source) { + return StaticLayout.Builder.obtain(source, 0, source.length(), mPaint, mTextWidth) + .setLineSpacing(1f, 0f) + .setIncludePad(false) + .build(); + } + + private boolean hasLabel(int position) { + return mLabels.indexOfKey(position) > -1; + } +} diff --git a/src/org/lineageos/eleven/widgets/SeparatedListAdapter.java b/src/org/lineageos/eleven/widgets/SeparatedListAdapter.java deleted file mode 100644 index 5931d2e9f2a5d77b966e43754ab2428db91430ed..0000000000000000000000000000000000000000 --- a/src/org/lineageos/eleven/widgets/SeparatedListAdapter.java +++ /dev/null @@ -1,157 +0,0 @@ - -package org.lineageos.eleven.widgets; - -import android.content.Context; -import android.view.View; -import android.view.ViewGroup; -import android.widget.Adapter; -import android.widget.ArrayAdapter; -import android.widget.BaseAdapter; - -import org.lineageos.eleven.R; - -import java.util.LinkedHashMap; -import java.util.Map; - -public class SeparatedListAdapter extends BaseAdapter { - - public final Map mSections = new LinkedHashMap<>(); - - public final ArrayAdapter mHeaders; - - public final static int TYPE_SECTION_HEADER = 0; - - /** - * Constructor of SeparatedListAdapter - * - * @param context The {@link Context} to use. - */ - public SeparatedListAdapter(final Context context) { - mHeaders = new ArrayAdapter<>(context, R.layout.list_header); - } - - /** - * {@inheritDoc} - */ - @Override - public Object getItem(int position) { - for (final Object section : mSections.keySet()) { - final Adapter adapter = mSections.get(section); - final int size = adapter.getCount() + 1; - - // check if position inside this section - if (position == 0) { - return section; - } - if (position < size) { - return adapter.getItem(position - 1); - } - - // otherwise jump into next section - position -= size; - } - return null; - } - - /** - * {@inheritDoc} - */ - @Override - public int getCount() { - // total together all mSections, plus one for each section header - int total = 0; - for (final Adapter adapter : mSections.values()) { - total += adapter.getCount() + 1; - } - return total; - } - - /** - * {@inheritDoc} - */ - @Override - public int getViewTypeCount() { - // assume that mHeaders count as one, then total all mSections - int total = 1; - for (final Adapter adapter : mSections.values()) { - total += adapter.getViewTypeCount(); - } - return total; - } - - /** - * {@inheritDoc} - */ - @Override - public int getItemViewType(int position) { - int type = 1; - for (final Object section : mSections.keySet()) { - final Adapter adapter = mSections.get(section); - final int size = adapter.getCount() + 1; - - // check if position inside this section - if (position == 0) { - return TYPE_SECTION_HEADER; - } - if (position < size) { - return type + adapter.getItemViewType(position - 1); - } - - // otherwise jump into next section - position -= size; - type += adapter.getViewTypeCount(); - } - return -1; - } - - public boolean areAllItemsSelectable() { - return false; - } - - /** - * {@inheritDoc} - */ - @Override - public boolean isEnabled(final int position) { - return getItemViewType(position) != TYPE_SECTION_HEADER; - } - - /** - * {@inheritDoc} - */ - @Override - public View getView(int position, final View convertView, final ViewGroup parent) { - int sectionnum = 0; - for (final Object section : mSections.keySet()) { - final Adapter adapter = mSections.get(section); - final int size = adapter.getCount() + 1; - - // check if position inside this section - if (position == 0) { - return mHeaders.getView(sectionnum, convertView, parent); - } - if (position < size) { - return adapter.getView(position - 1, convertView, parent); - } - - // otherwise jump into next section - position -= size; - sectionnum++; - } - return null; - } - - /** - * {@inheritDoc} - */ - @Override - public long getItemId(final int position) { - return position; - } - - public void addSection(final String section, final Adapter adapter) { - mHeaders.add(section); - mSections.put(section, adapter); - } - -} diff --git a/src/org/lineageos/eleven/widgets/ShowHideMasterLayout.java b/src/org/lineageos/eleven/widgets/ShowHideMasterLayout.java deleted file mode 100644 index 8c8eb36601943d88943b4810ad8ba6fb63cb8db7..0000000000000000000000000000000000000000 --- a/src/org/lineageos/eleven/widgets/ShowHideMasterLayout.java +++ /dev/null @@ -1,398 +0,0 @@ -/* - * Copyright 2012 Google Inc. Licensed under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law - * or agreed to in writing, software distributed under the License is - * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ - -package org.lineageos.eleven.widgets; - -import android.animation.Animator; -import android.animation.AnimatorSet; -import android.animation.ObjectAnimator; -import android.annotation.TargetApi; -import android.content.Context; -import android.os.Build; -import android.util.AttributeSet; -import android.view.GestureDetector; -import android.view.MotionEvent; -import android.view.View; -import android.view.ViewConfiguration; -import android.view.ViewGroup; - -/** - * A layout that supports the Show/Hide pattern for portrait tablet layouts. See - * Android Design > Patterns > Multi-pane Layouts & gt; Compound Views - * and Orientation Changes for more details on this pattern. This layout - * should normally be used in association with the Up button. Specifically, show - * the master pane using {@link #showMaster(boolean, int)} when the Up button is - * pressed. If the master pane is visible, defer to normal Up behavior. - *

- * TODO: swiping should be more tactile and actually follow the user's finger. - *

- * Requires API level 11 - */ -@TargetApi(Build.VERSION_CODES.HONEYCOMB) -public class ShowHideMasterLayout extends ViewGroup implements Animator.AnimatorListener { - - /** - * A flag for {@link #showMaster(boolean, int)} indicating that the change - * in visiblity should not be animated. - */ - public final static int FLAG_IMMEDIATE = 0x1; - - private View sMasterView; - - private View mDetailView; - - private OnMasterVisibilityChangedListener mOnMasterVisibilityChangedListener; - - private GestureDetector mGestureDetector; - - private Runnable mShowMasterCompleteRunnable; - - private boolean mFirstShow = true; - - private boolean mMasterVisible = true; - - private boolean mFlingToExposeMaster; - - private boolean mIsAnimating; - - /* The last measured master width, including its margins */ - private int mTranslateAmount; - - public interface OnMasterVisibilityChangedListener { - public void onMasterVisibilityChanged(boolean visible); - } - - public ShowHideMasterLayout(final Context context) { - super(context); - init(); - } - - public ShowHideMasterLayout(final Context context, final AttributeSet attrs) { - super(context, attrs); - init(); - } - - public ShowHideMasterLayout(final Context context, final AttributeSet attrs, final int defStyle) { - super(context, attrs, defStyle); - init(); - } - - private void init() { - mGestureDetector = new GestureDetector(getContext(), mGestureListener); - } - - @Override - public LayoutParams generateLayoutParams(final AttributeSet attrs) { - return new MarginLayoutParams(getContext(), attrs); - } - - @Override - protected LayoutParams generateLayoutParams(final LayoutParams p) { - return new MarginLayoutParams(p); - } - - @Override - protected void onMeasure(final int widthMeasureSpec, final int heightMeasureSpec) { - final int mCount = getChildCount(); - - /* Measure once to find the maximum child size */ - int sMaxHeight = 0; - int sMaxWidth = 0; - int mChildState = 0; - - for (int i = 0; i < mCount; i++) { - final View mChild = getChildAt(i); - if (mChild.getVisibility() == GONE) { - continue; - } - - measureChildWithMargins(mChild, widthMeasureSpec, 0, heightMeasureSpec, 0); - final MarginLayoutParams mLayoutParams = (MarginLayoutParams)mChild.getLayoutParams(); - sMaxWidth = Math.max(sMaxWidth, mChild.getMeasuredWidth() + mLayoutParams.leftMargin - + mLayoutParams.rightMargin); - sMaxHeight = Math.max(sMaxHeight, mChild.getMeasuredHeight() + mLayoutParams.topMargin - + mLayoutParams.bottomMargin); - mChildState = combineMeasuredStates(mChildState, mChild.getMeasuredState()); - } - - /* Account for padding too */ - sMaxWidth += getPaddingLeft() + getPaddingRight(); - sMaxHeight += getPaddingLeft() + getPaddingRight(); - - /* Check against our minimum height and width */ - sMaxHeight = Math.max(sMaxHeight, getSuggestedMinimumHeight()); - sMaxWidth = Math.max(sMaxWidth, getSuggestedMinimumWidth()); - - /* Set our own measured size */ - setMeasuredDimension( - resolveSizeAndState(sMaxWidth, widthMeasureSpec, mChildState), - resolveSizeAndState(sMaxHeight, heightMeasureSpec, - mChildState << MEASURED_HEIGHT_STATE_SHIFT)); - - /* Measure children for them to set their measured dimensions */ - for (int i = 0; i < mCount; i++) { - final View child = getChildAt(i); - if (child.getVisibility() == GONE) { - continue; - } - - final MarginLayoutParams mLayoutParams = (MarginLayoutParams)child.getLayoutParams(); - - int mChildWidthMeasureSpec; - int mChildHeightMeasureSpec; - - if (mLayoutParams.width == LayoutParams.MATCH_PARENT) { - mChildWidthMeasureSpec = MeasureSpec.makeMeasureSpec(getMeasuredWidth() - - getPaddingLeft() - getPaddingRight() - mLayoutParams.leftMargin - - mLayoutParams.rightMargin, MeasureSpec.EXACTLY); - } else { - mChildWidthMeasureSpec = getChildMeasureSpec(widthMeasureSpec, getPaddingLeft() - + getPaddingRight() + mLayoutParams.leftMargin + mLayoutParams.rightMargin, - mLayoutParams.width); - } - - if (mLayoutParams.height == LayoutParams.MATCH_PARENT) { - mChildHeightMeasureSpec = MeasureSpec.makeMeasureSpec(getMeasuredHeight() - - getPaddingTop() - getPaddingBottom() - mLayoutParams.topMargin - - mLayoutParams.bottomMargin, MeasureSpec.EXACTLY); - } else { - mChildHeightMeasureSpec = getChildMeasureSpec(heightMeasureSpec, - getPaddingTop() + getPaddingBottom() + mLayoutParams.topMargin - + mLayoutParams.bottomMargin, mLayoutParams.height); - } - - child.measure(mChildWidthMeasureSpec, mChildHeightMeasureSpec); - } - } - - @Override - protected void onLayout(final boolean changed, final int l, final int t, final int r, - final int b) { - updateChildReferences(); - - if (sMasterView == null || mDetailView == null) { - return; - } - - final int sMasterWidth = sMasterView.getMeasuredWidth(); - final MarginLayoutParams sMasterLp = (MarginLayoutParams)sMasterView.getLayoutParams(); - final MarginLayoutParams mDetailLp = (MarginLayoutParams)mDetailView.getLayoutParams(); - - mTranslateAmount = sMasterWidth + sMasterLp.leftMargin + sMasterLp.rightMargin; - - sMasterView.layout(l + sMasterLp.leftMargin, t + sMasterLp.topMargin, l - + sMasterLp.leftMargin + sMasterWidth, b - sMasterLp.bottomMargin); - - mDetailView.layout(l + mDetailLp.leftMargin + mTranslateAmount, t + mDetailLp.topMargin, r - - mDetailLp.rightMargin + mTranslateAmount, b - mDetailLp.bottomMargin); - - /* Update translationX values */ - if (!mIsAnimating) { - final float mTranslationX = mMasterVisible ? 0 : -mTranslateAmount; - sMasterView.setTranslationX(mTranslationX); - mDetailView.setTranslationX(mTranslationX); - } - } - - private void updateChildReferences() { - final int mChildCount = getChildCount(); - sMasterView = mChildCount > 0 ? getChildAt(0) : null; - mDetailView = mChildCount > 1 ? getChildAt(1) : null; - } - - /** - * Allow or disallow the user to flick right on the detail pane to expose - * the master pane. - * - * @param enabled Whether or not to enable this interaction. - */ - public void setFlingToExposeMasterEnabled(final boolean enabled) { - mFlingToExposeMaster = enabled; - } - - /** - * Request the given listener be notified when the master pane is shown or - * hidden. - * - * @param listener The listener to notify when the master pane is shown or - * hidden. - */ - public void setOnMasterVisibilityChangedListener( - final OnMasterVisibilityChangedListener listener) { - mOnMasterVisibilityChangedListener = listener; - } - - /** - * Returns whether or not the master pane is visible. - * - * @return True if the master pane is visible. - */ - public boolean isMasterVisible() { - return mMasterVisible; - } - - /** - * Calls {@link #showMaster(boolean, int, Runnable)} with a null runnable. - */ - public void showMaster(final boolean show, final int flags) { - showMaster(show, flags, null); - } - - /** - * Shows or hides the master pane. - * - * @param show Whether or not to show the master pane. - * @param flags {@link #FLAG_IMMEDIATE} to show/hide immediately, or 0 to - * animate. - * @param completeRunnable An optional runnable to run when any animations - * related to this are complete. - */ - public void showMaster(final boolean show, final int flags, final Runnable completeRunnable) { - if (!mFirstShow && mMasterVisible == show) { - return; - } - - mShowMasterCompleteRunnable = completeRunnable; - mFirstShow = false; - - mMasterVisible = show; - if (mOnMasterVisibilityChangedListener != null) { - mOnMasterVisibilityChangedListener.onMasterVisibilityChanged(show); - } - - updateChildReferences(); - - if (sMasterView == null || mDetailView == null) { - return; - } - - final float mTranslationX = show ? 0 : -mTranslateAmount; - - if ((flags & FLAG_IMMEDIATE) != 0) { - sMasterView.setTranslationX(mTranslationX); - mDetailView.setTranslationX(mTranslationX); - if (mShowMasterCompleteRunnable != null) { - mShowMasterCompleteRunnable.run(); - mShowMasterCompleteRunnable = null; - } - } else { - final long mDuration = getResources() - .getInteger(android.R.integer.config_shortAnimTime); - - /* Animate if we have Honeycomb APIs, don't animate otherwise */ - mIsAnimating = true; - final AnimatorSet mAnimatorSet = new AnimatorSet(); - sMasterView.setLayerType(LAYER_TYPE_HARDWARE, null); - mDetailView.setLayerType(LAYER_TYPE_HARDWARE, null); - mAnimatorSet.play( - ObjectAnimator.ofFloat(sMasterView, "translationX", mTranslationX).setDuration( - mDuration)).with( - ObjectAnimator.ofFloat(mDetailView, "translationX", mTranslationX).setDuration( - mDuration)); - mAnimatorSet.addListener(this); - mAnimatorSet.start(); - } - } - - @Override - public void requestDisallowInterceptTouchEvent(final boolean disallowIntercept) { - // Really bad hack... we really shouldn't do this. - // super.requestDisallowInterceptTouchEvent(disallowIntercept); - } - - @Override - public boolean onInterceptTouchEvent(final MotionEvent event) { - if (mFlingToExposeMaster && !mMasterVisible) { - mGestureDetector.onTouchEvent(event); - } - - if (event.getAction() == MotionEvent.ACTION_DOWN && sMasterView != null && mMasterVisible) { - if (event.getX() > mTranslateAmount) { - return true; - } - } - return super.onInterceptTouchEvent(event); - } - - @Override - public boolean onTouchEvent(final MotionEvent event) { - if (mFlingToExposeMaster && !mMasterVisible && mGestureDetector.onTouchEvent(event)) { - return true; - } - - if (event.getAction() == MotionEvent.ACTION_DOWN && sMasterView != null && mMasterVisible) { - if (event.getX() > mTranslateAmount) { - showMaster(false, 0); - return true; - } - } - return super.onTouchEvent(event); - } - - @Override - public void onAnimationEnd(final Animator animator) { - mIsAnimating = false; - sMasterView.setLayerType(LAYER_TYPE_NONE, null); - mDetailView.setLayerType(LAYER_TYPE_NONE, null); - requestLayout(); - if (mShowMasterCompleteRunnable != null) { - mShowMasterCompleteRunnable.run(); - mShowMasterCompleteRunnable = null; - } - } - - @Override - public void onAnimationCancel(final Animator animator) { - mIsAnimating = false; - sMasterView.setLayerType(LAYER_TYPE_NONE, null); - mDetailView.setLayerType(LAYER_TYPE_NONE, null); - requestLayout(); - if (mShowMasterCompleteRunnable != null) { - mShowMasterCompleteRunnable.run(); - mShowMasterCompleteRunnable = null; - } - } - - private final GestureDetector.OnGestureListener mGestureListener = new GestureDetector.SimpleOnGestureListener() { - @Override - public boolean onDown(final MotionEvent e) { - return true; - } - - @Override - public boolean onFling(final MotionEvent e1, final MotionEvent e2, final float velocityX, - final float velocityY) { - final ViewConfiguration mViewConfig = ViewConfiguration.get(getContext()); - final float mAbsVelocityX = Math.abs(velocityX); - final float mAbsVelocityY = Math.abs(velocityY); - if (mFlingToExposeMaster && !mMasterVisible && velocityX > 0 - && mAbsVelocityX >= mAbsVelocityY - && mAbsVelocityX > mViewConfig.getScaledMinimumFlingVelocity() - && mAbsVelocityX < mViewConfig.getScaledMaximumFlingVelocity()) { - showMaster(true, 0); - return true; - } - return super.onFling(e1, e2, velocityX, velocityY); - } - }; - - @Override - public void onAnimationStart(final Animator animator) { - /* Nothing to do */ - } - - @Override - public void onAnimationRepeat(final Animator animator) { - /* Nothing to do */ - } -} diff --git a/src/org/lineageos/eleven/widgets/ShuffleButton.java b/src/org/lineageos/eleven/widgets/ShuffleButton.java index 432e3929a4fc91cd748a3a4e9dc42247150a88b0..fc96c40fe2e4fa33fc3110bc496d156c344bdfa1 100644 --- a/src/org/lineageos/eleven/widgets/ShuffleButton.java +++ b/src/org/lineageos/eleven/widgets/ShuffleButton.java @@ -1,16 +1,20 @@ /* * Copyright (C) 2012 Andrew Neal * Copyright (C) 2014 The CyanogenMod Project - * Licensed under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law - * or agreed to in writing, software distributed under the License is - * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the specific language - * governing permissions and limitations under the License. + * Copyright (C) 2021 The LineageOS Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ - package org.lineageos.eleven.widgets; import android.content.Context; @@ -35,13 +39,12 @@ public class ShuffleButton extends AudioButton { updateShuffleState(); } - /** Sets the correct drawable for the shuffle state. */ + /** + * Sets the correct drawable for the shuffle state. + */ public void updateShuffleState() { switch (MusicUtils.getShuffleMode()) { case MusicPlaybackService.SHUFFLE_NORMAL: - setContentDescription(getResources().getString(R.string.accessibility_shuffle_all)); - setAlpha(ACTIVE_ALPHA); - break; case MusicPlaybackService.SHUFFLE_AUTO: setContentDescription(getResources().getString(R.string.accessibility_shuffle_all)); setAlpha(ACTIVE_ALPHA); @@ -54,4 +57,4 @@ public class ShuffleButton extends AudioButton { break; } } -} \ No newline at end of file +} diff --git a/src/org/lineageos/eleven/widgets/SquareFrame.java b/src/org/lineageos/eleven/widgets/SquareFrame.java index 09048e33bd142ebc77da220b7f05a56170a1043b..a4c1dfc00a0a3d7a0fcdb1ee38c7f9f19db0761a 100644 --- a/src/org/lineageos/eleven/widgets/SquareFrame.java +++ b/src/org/lineageos/eleven/widgets/SquareFrame.java @@ -1,3 +1,18 @@ +/* + * Copyright (C) 2021 The LineageOS Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package org.lineageos.eleven.widgets; import android.content.Context; @@ -15,4 +30,4 @@ public class SquareFrame extends FrameLayout { final int mSize = Math.min(getMeasuredWidth(), getMeasuredHeight()); setMeasuredDimension(mSize, mSize); } -} \ No newline at end of file +} diff --git a/src/org/lineageos/eleven/widgets/SquareImageView.java b/src/org/lineageos/eleven/widgets/SquareImageView.java index 83f6bb76d283672033f5793f8b5ba294ad9da7ca..6372f244569c2dc7420558e63251b6f5d41a98dc 100644 --- a/src/org/lineageos/eleven/widgets/SquareImageView.java +++ b/src/org/lineageos/eleven/widgets/SquareImageView.java @@ -1,16 +1,20 @@ /* * Copyright (C) 2012 Andrew Neal * Copyright (C) 2014 The CyanogenMod Project - * Licensed under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law - * or agreed to in writing, software distributed under the License is - * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the specific language - * governing permissions and limitations under the License. + * Copyright (C) 2021 The LineageOS Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ - package org.lineageos.eleven.widgets; import android.content.Context; @@ -27,21 +31,17 @@ public class SquareImageView extends LayoutSuppressingImageView { /** * @param context The {@link Context} to use - * @param attrs The attributes of the XML tag that is inflating the view. + * @param attrs The attributes of the XML tag that is inflating the view. */ public SquareImageView(final Context context, final AttributeSet attrs) { super(context, attrs); } - /** - * {@inheritDoc} - */ @Override public void onMeasure(final int widthSpec, final int heightSpec) { super.onMeasure(widthSpec, heightSpec); final int mSize = Math.min(getMeasuredWidth(), getMeasuredHeight()); setMeasuredDimension(mSize, mSize); } - } diff --git a/src/org/lineageos/eleven/widgets/SquareView.java b/src/org/lineageos/eleven/widgets/SquareView.java index 1d83236409242868d61f7cd75c9d1ec6f38eed7f..54dbf2e0810b845cd19182f510f10731a5965d61 100644 --- a/src/org/lineageos/eleven/widgets/SquareView.java +++ b/src/org/lineageos/eleven/widgets/SquareView.java @@ -1,16 +1,20 @@ /* * Copyright (C) 2012 Andrew Neal * Copyright (C) 2014 The CyanogenMod Project - * Licensed under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law - * or agreed to in writing, software distributed under the License is - * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the specific language - * governing permissions and limitations under the License. + * Copyright (C) 2021 The LineageOS Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ - package org.lineageos.eleven.widgets; import android.annotation.SuppressLint; @@ -29,15 +33,12 @@ public class SquareView extends ViewGroup { /** * @param context The {@link Context} to use - * @param attrs The attributes of the XML tag that is inflating the view. + * @param attrs The attributes of the XML tag that is inflating the view. */ public SquareView(final Context context, final AttributeSet attrs) { super(context, attrs); } - /** - * {@inheritDoc} - */ @SuppressWarnings("SuspiciousNameCombination") @Override protected void onMeasure(final int widthMeasureSpec, final int heightMeasureSpec) { @@ -48,18 +49,12 @@ public class SquareView extends ViewGroup { setMeasuredDimension(mWidth, mWidth); } - /** - * {@inheritDoc} - */ @Override protected void onLayout(final boolean changed, final int l, final int u, final int r, - final int d) { + final int d) { getChildAt(0).layout(0, 0, r - l, d - u); } - /** - * {@inheritDoc} - */ @SuppressLint("MissingSuperCall") @Override public void requestLayout() { diff --git a/src/org/lineageos/eleven/widgets/SquareViewPager.java b/src/org/lineageos/eleven/widgets/SquareViewPager.java index 6a793c898ce29ec5a5e26a8e471c0b0414507081..73cb422c309962468ae7f96901a6c901c6d2699d 100644 --- a/src/org/lineageos/eleven/widgets/SquareViewPager.java +++ b/src/org/lineageos/eleven/widgets/SquareViewPager.java @@ -1,18 +1,19 @@ /* -* Copyright (C) 2014 The CyanogenMod Project -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ + * Copyright (C) 2014 The CyanogenMod Project + * Copyright (C) 2021 The LineageOS Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package org.lineageos.eleven.widgets; import android.content.Context; @@ -28,15 +29,12 @@ public class SquareViewPager extends ViewPager { /** * @param context The {@link Context} to use - * @param attrs The attributes of the XML tag that is inflating the view. + * @param attrs The attributes of the XML tag that is inflating the view. */ public SquareViewPager(Context context, AttributeSet attrs) { super(context, attrs); } - /** - * {@inheritDoc} - */ @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); diff --git a/src/org/lineageos/eleven/widgets/ViewPagerTabStrip.java b/src/org/lineageos/eleven/widgets/ViewPagerTabStrip.java index 0c2cc4a7c7142244779af5e11b51e6c26acb83fe..13d7cf09a2ff126debd13a92aa07dd6ee2ebeacd 100644 --- a/src/org/lineageos/eleven/widgets/ViewPagerTabStrip.java +++ b/src/org/lineageos/eleven/widgets/ViewPagerTabStrip.java @@ -1,5 +1,6 @@ /* * Copyright (C) 2014 The Android Open Source Project + * Copyright (C) 2021 The LineageOS Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -11,9 +12,8 @@ * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and - * limitations under the License + * limitations under the License. */ - package org.lineageos.eleven.widgets; import android.content.Context; @@ -24,10 +24,12 @@ import android.util.AttributeSet; import android.view.View; import android.widget.LinearLayout; +import androidx.core.content.ContextCompat; + import org.lineageos.eleven.R; public class ViewPagerTabStrip extends LinearLayout { - private int mSelectedUnderlineThickness; + private final int mSelectedUnderlineThickness; private final Paint mSelectedUnderlinePaint; private int mIndexForSelection; @@ -44,8 +46,8 @@ public class ViewPagerTabStrip extends LinearLayout { mSelectedUnderlineThickness = res.getDimensionPixelSize(R.dimen.tab_selected_underline_height); - int underlineColor = res.getColor(R.color.tab_selected_underline_color); - int backgroundColor = res.getColor(R.color.header_action_bar_color); + int underlineColor = ContextCompat.getColor(context, R.color.tab_selected_underline_color); + int backgroundColor = ContextCompat.getColor(context, R.color.header_action_bar_color); mSelectedUnderlinePaint = new Paint(); mSelectedUnderlinePaint.setColor(underlineColor); @@ -59,7 +61,7 @@ public class ViewPagerTabStrip extends LinearLayout { * and selection offset for interpolating the position and width of selection * underline. */ - void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { + void onPageScrolled(int position, float positionOffset) { mIndexForSelection = position; mSelectionOffset = positionOffset; invalidate(); diff --git a/src/org/lineageos/eleven/widgets/ViewPagerTabs.java b/src/org/lineageos/eleven/widgets/ViewPagerTabs.java index 6fbb46021727ea9aa7b8f8787be3d28da6258a2b..5a1e8f7fe4d9d7c80b389aecf8cae9b55d0a9b14 100644 --- a/src/org/lineageos/eleven/widgets/ViewPagerTabs.java +++ b/src/org/lineageos/eleven/widgets/ViewPagerTabs.java @@ -1,5 +1,6 @@ /* * Copyright (C) 2014 The Android Open Source Project + * Copyright (C) 2021 The LineageOS Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -43,8 +44,9 @@ import org.lineageos.eleven.R; */ public class ViewPagerTabs extends HorizontalScrollView implements ViewPager.OnPageChangeListener { - ViewPager mPager; - private ViewPagerTabStrip mTabStrip; + private final ViewPagerTabStrip mTabStrip; + + private ViewPager mPager; /** * Linearlayout that will contain the TextViews serving as tabs. This is the only child @@ -55,24 +57,24 @@ public class ViewPagerTabs extends HorizontalScrollView implements ViewPager.OnP final int mTextSize; final boolean mTextAllCaps; int mPrevSelected = -1; - int mSidePadding; + final int mSidePadding; private static final ViewOutlineProvider VIEW_BOUNDS_OUTLINE_PROVIDER = new ViewOutlineProvider() { - @Override - public void getOutline(View view, Outline outline) { - outline.setRect(0, 0, view.getWidth(), view.getHeight()); - } - }; + @Override + public void getOutline(View view, Outline outline) { + outline.setRect(0, 0, view.getWidth(), view.getHeight()); + } + }; private static final int TAB_SIDE_PADDING_IN_DPS = 10; // TODO: This should use in the future - private static final int[] ATTRS = new int[] { - android.R.attr.textSize, - android.R.attr.textStyle, - android.R.attr.textColor, - android.R.attr.textAllCaps + private static final int[] ATTRS = new int[]{ + android.R.attr.textSize, + android.R.attr.textStyle, + android.R.attr.textColor, + android.R.attr.textAllCaps }; /** @@ -95,7 +97,11 @@ public class ViewPagerTabs extends HorizontalScrollView implements ViewPager.OnP final int height = getHeight(); final int screenWidth = context.getResources().getDisplayMetrics().widthPixels; - Toast toast = Toast.makeText(context, mPager.getAdapter().getPageTitle(mPosition), + final PagerAdapter adapter = mPager.getAdapter(); + if (adapter == null) { + return false; + } + Toast toast = Toast.makeText(context, adapter.getPageTitle(mPosition), Toast.LENGTH_SHORT); // Show the toast under the tab @@ -138,7 +144,11 @@ public class ViewPagerTabs extends HorizontalScrollView implements ViewPager.OnP public void setViewPager(ViewPager viewPager) { mPager = viewPager; - addTabs(mPager.getAdapter()); + final PagerAdapter adapter = mPager.getAdapter(); + if (adapter != null) { + addTabs(adapter); + } + } private void addTabs(PagerAdapter adapter) { @@ -155,13 +165,7 @@ public class ViewPagerTabs extends HorizontalScrollView implements ViewPager.OnP textView.setText(tabTitle); textView.setBackgroundResource(R.drawable.view_pager_tab_background); textView.setGravity(Gravity.CENTER); - textView.setOnClickListener(new OnClickListener() { - @Override - public void onClick(View v) { - mPager.setCurrentItem(getRtlPosition(position)); - } - }); - + textView.setOnClickListener(v -> mPager.setCurrentItem(getRtlPosition(position))); textView.setOnLongClickListener(new OnTabLongClickListener(position)); // Assign various text appearance related attributes to child views. @@ -189,11 +193,11 @@ public class ViewPagerTabs extends HorizontalScrollView implements ViewPager.OnP public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { position = getRtlPosition(position); int tabStripChildCount = mTabStrip.getChildCount(); - if ((tabStripChildCount == 0) || (position < 0) || (position >= tabStripChildCount)) { + if (position < 0 || position >= tabStripChildCount) { return; } - mTabStrip.onPageScrolled(position, positionOffset, positionOffsetPixels); + mTabStrip.onPageScrolled(position, positionOffset); } @Override diff --git a/src/org/lineageos/eleven/widgets/VisualizerView.java b/src/org/lineageos/eleven/widgets/VisualizerView.java index 37f7319a21c927af4f86c5ecb3f50092173f88af..a1935a426a8a69d905b16eeba0c50b1cd9106661 100644 --- a/src/org/lineageos/eleven/widgets/VisualizerView.java +++ b/src/org/lineageos/eleven/widgets/VisualizerView.java @@ -1,12 +1,12 @@ /* * Copyright (C) 2014 The CyanogenMod Project - * Copyright (C) 2019 The LineageOS Project + * Copyright (C) 2019-2021 The LineageOS Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -44,8 +44,8 @@ public class VisualizerView extends View { private Visualizer mVisualizer; private ObjectAnimator mVisualizerColorAnimator; - private ValueAnimator[] mValueAnimators = new ValueAnimator[32]; - private float[] mFFTPoints = new float[128]; + private final ValueAnimator[] mValueAnimators = new ValueAnimator[32]; + private final float[] mFFTPoints = new float[128]; private boolean mVisible = false; private boolean mPlaying = false; @@ -54,7 +54,7 @@ public class VisualizerView extends View { private int mColor; - private Visualizer.OnDataCaptureListener mVisualizerListener = + private final Visualizer.OnDataCaptureListener mVisualizerListener = new Visualizer.OnDataCaptureListener() { byte rfk, ifk; int dbValue;