├── settings.gradle
├── app
├── src
│ └── main
│ │ ├── java
│ │ └── com
│ │ │ └── ringdroid
│ │ │ ├── soundfile
│ │ │ ├── .gitignore
│ │ │ └── WAVHeader.java
│ │ │ ├── AfterSaveActionDialog.java
│ │ │ ├── MarkerView.java
│ │ │ ├── SongMetadataReader.java
│ │ │ ├── FileSaveDialog.java
│ │ │ ├── SamplePlayer.java
│ │ │ ├── ChooseContactActivity.java
│ │ │ └── WaveformView.java
│ │ ├── res
│ │ ├── drawable
│ │ │ ├── bkgnd.png
│ │ │ ├── star.png
│ │ │ ├── search.png
│ │ │ ├── menu_about.png
│ │ │ ├── menu_reset.png
│ │ │ ├── menu_save.png
│ │ │ ├── type_alarm.png
│ │ │ ├── type_music.png
│ │ │ ├── ringdroidlogo.png
│ │ │ ├── type_ringtone.png
│ │ │ ├── button_options.png
│ │ │ ├── button_zoom_in.png
│ │ │ ├── button_zoom_out.png
│ │ │ ├── marker_left_normal.png
│ │ │ ├── type_notification.png
│ │ │ ├── marker_left_focused.png
│ │ │ ├── marker_left_pressed.png
│ │ │ ├── marker_right_focused.png
│ │ │ ├── marker_right_normal.png
│ │ │ ├── marker_right_pressed.png
│ │ │ ├── menu_show_all_audio.png
│ │ │ ├── bkgnd_normal.xml
│ │ │ ├── bkgnd_pressed.xml
│ │ │ ├── button_options_bkgnd.xml
│ │ │ ├── marker_left.xml
│ │ │ └── marker_right.xml
│ │ ├── drawable-hdpi
│ │ │ ├── content_save.png
│ │ │ ├── ic_action_search.png
│ │ │ ├── navigation_expand.png
│ │ │ └── ic_action_microphone.png
│ │ ├── menu
│ │ │ ├── edit_options.xml
│ │ │ └── select_options.xml
│ │ ├── layout
│ │ │ ├── media_select.xml
│ │ │ ├── record_audio.xml
│ │ │ ├── choose_contact.xml
│ │ │ ├── after_save_action.xml
│ │ │ ├── contact_row.xml
│ │ │ ├── file_save.xml
│ │ │ ├── media_select_row.xml
│ │ │ └── editor.xml
│ │ ├── layout-land
│ │ │ ├── media_select.xml
│ │ │ ├── after_save_action.xml
│ │ │ ├── media_select_row.xml
│ │ │ └── editor.xml
│ │ ├── values
│ │ │ ├── colors.xml
│ │ │ ├── styles.xml
│ │ │ └── strings.xml
│ │ ├── values-cn
│ │ │ └── strings.xml
│ │ ├── values-ja
│ │ │ └── strings.xml
│ │ ├── values-es
│ │ │ └── strings.xml
│ │ ├── values-pl
│ │ │ └── strings.xml
│ │ ├── values-ru
│ │ │ └── strings.xml
│ │ ├── values-it
│ │ │ └── strings.xml
│ │ ├── values-de
│ │ │ └── strings.xml
│ │ ├── values-nl
│ │ │ └── strings.xml
│ │ └── values-fr
│ │ │ └── strings.xml
│ │ └── AndroidManifest.xml
└── build.gradle
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── .gitignore
├── README.txt
├── gradlew.bat
├── README.md
└── gradlew
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app'
2 |
--------------------------------------------------------------------------------
/app/src/main/java/com/ringdroid/soundfile/.gitignore:
--------------------------------------------------------------------------------
1 | *.class
2 |
3 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/google/ringdroid/HEAD/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/app/src/main/res/drawable/bkgnd.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/google/ringdroid/HEAD/app/src/main/res/drawable/bkgnd.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/star.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/google/ringdroid/HEAD/app/src/main/res/drawable/star.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/search.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/google/ringdroid/HEAD/app/src/main/res/drawable/search.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/menu_about.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/google/ringdroid/HEAD/app/src/main/res/drawable/menu_about.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/menu_reset.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/google/ringdroid/HEAD/app/src/main/res/drawable/menu_reset.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/menu_save.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/google/ringdroid/HEAD/app/src/main/res/drawable/menu_save.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/type_alarm.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/google/ringdroid/HEAD/app/src/main/res/drawable/type_alarm.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/type_music.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/google/ringdroid/HEAD/app/src/main/res/drawable/type_music.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ringdroidlogo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/google/ringdroid/HEAD/app/src/main/res/drawable/ringdroidlogo.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/type_ringtone.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/google/ringdroid/HEAD/app/src/main/res/drawable/type_ringtone.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/button_options.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/google/ringdroid/HEAD/app/src/main/res/drawable/button_options.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/button_zoom_in.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/google/ringdroid/HEAD/app/src/main/res/drawable/button_zoom_in.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/button_zoom_out.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/google/ringdroid/HEAD/app/src/main/res/drawable/button_zoom_out.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/content_save.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/google/ringdroid/HEAD/app/src/main/res/drawable-hdpi/content_save.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/marker_left_normal.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/google/ringdroid/HEAD/app/src/main/res/drawable/marker_left_normal.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/type_notification.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/google/ringdroid/HEAD/app/src/main/res/drawable/type_notification.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/marker_left_focused.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/google/ringdroid/HEAD/app/src/main/res/drawable/marker_left_focused.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/marker_left_pressed.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/google/ringdroid/HEAD/app/src/main/res/drawable/marker_left_pressed.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/marker_right_focused.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/google/ringdroid/HEAD/app/src/main/res/drawable/marker_right_focused.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/marker_right_normal.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/google/ringdroid/HEAD/app/src/main/res/drawable/marker_right_normal.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/marker_right_pressed.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/google/ringdroid/HEAD/app/src/main/res/drawable/marker_right_pressed.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/menu_show_all_audio.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/google/ringdroid/HEAD/app/src/main/res/drawable/menu_show_all_audio.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/ic_action_search.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/google/ringdroid/HEAD/app/src/main/res/drawable-hdpi/ic_action_search.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/navigation_expand.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/google/ringdroid/HEAD/app/src/main/res/drawable-hdpi/navigation_expand.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/ic_action_microphone.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/google/ringdroid/HEAD/app/src/main/res/drawable-hdpi/ic_action_microphone.png
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionBase=GRADLE_USER_HOME
2 | distributionPath=wrapper/dists
3 | zipStoreBase=GRADLE_USER_HOME
4 | zipStorePath=wrapper/dists
5 | distributionUrl=https\://services.gradle.org/distributions/gradle-2.14.1-all.zip
6 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | build.xml
2 | bin
3 | gen
4 | out
5 | default.properties
6 | local.properties
7 | proguard.cfg
8 | .classpath
9 | .project
10 | project.properties
11 | .idea
12 | *.iml
13 | *.apk
14 | .gradle
15 | build
16 | app/build
17 | .DS_Store
18 |
19 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/edit_options.xml:
--------------------------------------------------------------------------------
1 |
2 |
17 |
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 |
3 | android {
4 | compileSdkVersion 25
5 | buildToolsVersion "25.0.0"
6 |
7 | defaultConfig {
8 | applicationId "com.ringdroid"
9 | minSdkVersion 16
10 | // WARNING: if you increase targetSdkVersion you will need to take care of requesting
11 | // permissions at run time, as described here:
12 | // https://developer.android.com/training/permissions/index.html
13 | targetSdkVersion 22
14 | versionCode 20704
15 | versionName "2.7.4"
16 | }
17 |
18 | buildTypes {
19 | release {
20 | minifyEnabled false
21 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'
22 | }
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/bkgnd_normal.xml:
--------------------------------------------------------------------------------
1 |
2 |
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/bkgnd_pressed.xml:
--------------------------------------------------------------------------------
1 |
2 |
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/select_options.xml:
--------------------------------------------------------------------------------
1 |
2 |
23 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/button_options_bkgnd.xml:
--------------------------------------------------------------------------------
1 |
2 |
16 |
17 |
18 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/marker_left.xml:
--------------------------------------------------------------------------------
1 |
2 |
16 |
17 |
18 |
20 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/marker_right.xml:
--------------------------------------------------------------------------------
1 |
2 |
16 |
17 |
18 |
20 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/media_select.xml:
--------------------------------------------------------------------------------
1 |
2 |
19 |
20 |
24 |
25 |
29 |
30 |
31 |
32 |
33 |
--------------------------------------------------------------------------------
/app/src/main/res/layout-land/media_select.xml:
--------------------------------------------------------------------------------
1 |
2 |
19 |
20 |
24 |
25 |
29 |
30 |
31 |
32 |
33 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/record_audio.xml:
--------------------------------------------------------------------------------
1 |
2 |
19 |
20 |
26 |
27 |
34 |
35 |
36 |
--------------------------------------------------------------------------------
/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
19 |
20 |
21 |
22 | #33b5e5
23 | #195a72
24 | #0a242d
25 | #ffffff
26 | #ffff66
27 | #66ffffff
28 | #ddffffdd
29 | #aa000000
30 |
31 | #88880000
32 | #88008888
33 | #88666600
34 | #88000000
35 | #88cccccc
36 |
37 |
38 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/choose_contact.xml:
--------------------------------------------------------------------------------
1 |
2 |
19 |
20 |
24 |
25 |
30 |
31 |
36 |
37 |
44 |
45 |
46 |
47 |
48 |
52 |
53 |
54 |
55 |
56 |
--------------------------------------------------------------------------------
/app/src/main/res/layout-land/after_save_action.xml:
--------------------------------------------------------------------------------
1 |
2 |
19 |
20 |
24 |
25 |
32 |
33 |
38 |
39 |
43 |
44 |
48 |
49 |
55 |
56 |
57 |
58 |
59 |
--------------------------------------------------------------------------------
/app/src/main/java/com/ringdroid/AfterSaveActionDialog.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2009 Google Inc.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.ringdroid;
18 |
19 | import android.app.Dialog;
20 | import android.content.Context;
21 | import android.os.Message;
22 | import android.view.View;
23 | import android.widget.Button;
24 |
25 | public class AfterSaveActionDialog extends Dialog {
26 |
27 | private Message mResponse;
28 |
29 | public AfterSaveActionDialog(Context context, Message response) {
30 | super(context);
31 |
32 | // Inflate our UI from its XML layout description.
33 | setContentView(R.layout.after_save_action);
34 |
35 | setTitle(R.string.alert_title_success);
36 |
37 | ((Button)findViewById(R.id.button_make_default))
38 | .setOnClickListener(new View.OnClickListener() {
39 | public void onClick(View view) {
40 | closeAndSendResult(R.id.button_make_default);
41 | }
42 | });
43 | ((Button)findViewById(R.id.button_choose_contact))
44 | .setOnClickListener(new View.OnClickListener() {
45 | public void onClick(View view) {
46 | closeAndSendResult(R.id.button_choose_contact);
47 | }
48 | });
49 | ((Button)findViewById(R.id.button_do_nothing))
50 | .setOnClickListener(new View.OnClickListener() {
51 | public void onClick(View view) {
52 | closeAndSendResult(R.id.button_do_nothing);
53 | }
54 | });
55 |
56 | mResponse = response;
57 | }
58 |
59 | private void closeAndSendResult(int clickedButtonId) {
60 | mResponse.arg1 = clickedButtonId;
61 | mResponse.sendToTarget();
62 | dismiss();
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/after_save_action.xml:
--------------------------------------------------------------------------------
1 |
2 |
19 |
20 |
26 |
27 |
37 |
38 |
45 |
46 |
53 |
54 |
62 |
63 |
64 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/contact_row.xml:
--------------------------------------------------------------------------------
1 |
2 |
19 |
20 |
27 |
28 |
36 |
37 |
46 |
47 |
53 |
54 |
65 |
66 |
67 |
68 |
69 |
--------------------------------------------------------------------------------
/README.txt:
--------------------------------------------------------------------------------
1 | ***************************************************************************
2 | *
3 | * Copyright (C) 2008 - 2011 Google Inc.
4 | *
5 | * Ringdroid is licensed under the Apache License, Version 2.0.
6 | * You may not use this source code except in compliance with the License.
7 | * You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | *
17 | ***************************************************************************
18 | *
19 | * Ringdroid
20 | *
21 | * https://github.com/google/ringdroid/
22 | * ringdroid@google.com
23 | *
24 | ***************************************************************************
25 |
26 | A sound editor and ringtone creator for the Android operating system.
27 |
28 | Questions, comments, feedback? Email ringdroid@google.com
29 |
30 | ### Build instructions when using Android Studio:
31 |
32 | Import the project using "Import project (Eclipse ADT, Gradle, etc.)"
33 | or File -> New -> Import Project...
34 | Select build.gradle (the one in the root directory, not app/build.gradle).
35 | Run the app (using the Run icon, or Run -> Run 'app'). This will build and install Ringdroid on the
36 | connected device.
37 |
38 | ### Build instructions when using a terminal:
39 |
40 | You need to have an environment variable JAVA_HOME pointing to your Java SDK.
41 | You also need to have an environment variable ANDROID_HOME pointing to your Android SDK.
42 | Then run:
43 |
44 | ./gradlew build
45 |
46 | This will download gradle if you don't have it already.
47 | The APKs are generated in ./app/build/outputs/apk/.
48 |
49 | To install the debug version just run:
50 |
51 | adb install ./app/build/outputs/apk/app-debug.apk
52 |
53 | ### Release mode
54 |
55 | http://developer.android.com/tools/publishing/app-signing.html
56 |
57 | On Android Studio:
58 | Build -> Generate Signed APK...
59 | Select the app module, enter the path to the keystore and the passwords, and then choose the
60 | destination folder before clicking on Finish.
61 |
62 | You can also directly modify the app/build.gradle to include a signing config as explained on
63 | http://developer.android.com/tools/publishing/app-signing.html#release-mode
64 |
65 | # Initial key generated with:
66 | # keytool -genkey -keystore ringdroid.keystore -alias ringdroid -validity 10000
67 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
12 | set DEFAULT_JVM_OPTS=
13 |
14 | set DIRNAME=%~dp0
15 | if "%DIRNAME%" == "" set DIRNAME=.
16 | set APP_BASE_NAME=%~n0
17 | set APP_HOME=%DIRNAME%
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windowz variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 | if "%@eval[2+2]" == "4" goto 4NT_args
53 |
54 | :win9xME_args
55 | @rem Slurp the command line arguments.
56 | set CMD_LINE_ARGS=
57 | set _SKIP=2
58 |
59 | :win9xME_args_slurp
60 | if "x%~1" == "x" goto execute
61 |
62 | set CMD_LINE_ARGS=%*
63 | goto execute
64 |
65 | :4NT_args
66 | @rem Get arguments from the 4NT Shell from JP Software
67 | set CMD_LINE_ARGS=%$
68 |
69 | :execute
70 | @rem Setup the command line
71 |
72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
73 |
74 | @rem Execute Gradle
75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
76 |
77 | :end
78 | @rem End local scope for the variables with windows NT shell
79 | if "%ERRORLEVEL%"=="0" goto mainEnd
80 |
81 | :fail
82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
83 | rem the _cmd.exe /c_ return code!
84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
85 | exit /b 1
86 |
87 | :mainEnd
88 | if "%OS%"=="Windows_NT" endlocal
89 |
90 | :omega
91 |
--------------------------------------------------------------------------------
/app/src/main/res/layout-land/media_select_row.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
10 |
11 |
17 |
18 |
23 |
24 |
32 |
33 |
34 |
35 |
40 |
41 |
50 |
51 |
60 |
61 |
62 |
63 |
64 |
65 |
74 |
75 |
76 |
77 |
78 |
--------------------------------------------------------------------------------
/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
19 |
20 |
21 |
22 |
33 |
34 |
37 |
38 |
41 |
42 |
48 |
49 |
55 |
61 |
62 |
67 |
72 |
73 |
74 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/file_save.xml:
--------------------------------------------------------------------------------
1 |
2 |
19 |
20 |
26 |
27 |
34 |
35 |
39 |
40 |
48 |
49 |
54 |
55 |
61 |
62 |
67 |
68 |
73 |
74 |
75 |
76 |
77 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/media_select_row.xml:
--------------------------------------------------------------------------------
1 |
2 |
19 |
20 |
23 |
24 |
30 |
31 |
40 |
41 |
44 |
45 |
53 |
54 |
62 |
63 |
64 |
65 |
76 |
77 |
78 |
79 |
80 |
81 |
90 |
91 |
92 |
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
21 |
22 |
26 |
27 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
43 |
44 |
45 |
46 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
67 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
80 |
81 |
82 |
83 |
84 |
85 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | 
2 |
3 | **Ringdroid is now on GitHub!**
4 |
5 | **2 December 2016: Ringdroid 2.7.4 contains a fix for an [audio bug](https://github.com/google/ringdroid/issues/20) reported by users using 'Nougat' (Android 7.x).**
6 |
7 | **22 June 2015: Ringdroid 2.7.3 contains fixes for several bugs reported by users of Ringdroid 2.7.2, and it uses WAV as a fall-back audio format for saving ringtones in case the default AAC (.m4a) encoding fails.**
8 |
9 | **11 May 2015: Ringdroid 2.7.2 does not require the full network communication permission anymore as the code in charge of gathering anonymous usage statistics has been removed.**
10 |
11 | **29 April 2015: Ringdroid 2.7 now supports 'Lollipop' (Android 5.x)! This version requests the audio recording permission in order to use the device's microphone. It also includes the ability to read OGG Vorbis audio files, and it now saves ringtones in AAC (.m4a) format. This is the recommended version for Android system versions 4.1 ('Jelly Bean') and newer.**
12 |
13 | **23 August 2012: Ringdroid 2.6 is the recommended version for Android system versions 3.0 ('Honeycomb') to 4.0.4 ('Ice Cream Sandwich'). This version of Ringdroid requests full network communication, but solely for the purpose of sending anonymous usage statistics as described in the app's 'Privacy' menu.**
14 |
15 | **2 January 2011: Ringdroid 2.5 is the recommended version for Android system versions 1.6 ('Donut') to 2.3.7 ('Gingerbread'). New features include a drop-down menu in the select view to edit/delete/assign ringtones and notifications, flinging support to scroll the waveform, and MR475 AMR files support. This version of Ringdroid requests full network communication, but solely for the purpose of sending anonymous usage statistics as described in the app's 'Privacy' menu.**
16 |
17 | Ringdroid is an [Android](https://developers.google.com/android) application for recording and editing sounds, and creating ringtones, directly on the handset.
18 |
19 | If you have an Android phone, just click on "Market" and search for "Ringdroid" to install it, or open the "Barcode Scanner" app and point to the [QR code](http://phandroid.com/2009/07/29/qr-code-faq-and-fun/) at the top of this page.
20 |
21 | * [FAQ](https://github.com/google/ringdroid/wiki/FAQ)
22 | * [User Guide](https://github.com/google/ringdroid/wiki/Using-Ringdroid)
23 | * [Screenshots](https://github.com/google/ringdroid/wiki/Screenshots)
24 | * [APKs](https://github.com/google/ringdroid/wiki/APKs)
25 | * [Survey](http://spreadsheets.google.com/viewform?key=pjClfOcMDHuckMdw44cfgNA)
26 | * [Ringdroid Discuss Group](http://groups.google.com/group/ringdroid-discuss)
27 |
28 | For developers:
29 |
30 | * [Developers](https://github.com/google/ringdroid/wiki/Developers)
31 | * [Building](https://github.com/google/ringdroid/wiki/Building)
32 | * [Emulator](https://github.com/google/ringdroid/wiki/Emulator)
33 |
34 | See also:
35 |
36 | * [Watch this video](http://www.phonedog.com/cell-phone-videos/t-mobile-g1-review-phone-and-ringtones.aspx) of Noah Kravitz of phonedog.com creating a ringtone using Ringdroid!
37 | * [How to put Ringtones on Droid HD](http://www.youtube.com/watch?v=AnAZ829lDVo)
38 |
39 | #### Features
40 |
41 | * Open an existing audio file
42 | * View a scrollable waveform representation of the audio file at 5 zoom levels
43 | * Set starting and ending points for a clip within the audio file, using an optional touch interface
44 | * Play the selected portion of the audio, including an indicator cursor and autoscrolling of the waveform
45 | * Play anywhere else by tapping the screen
46 | * Save the clipped audio as a new audio file and mark it as Music, Ringtone, Alarm, or Notification.
47 | * Record a new audio clip to edit
48 | * Delete audio (with confirmation alert)
49 | * Launches automatically in response to the GET_CONTENT intent with a mime type of audio/ if any other application wants to pick an audio file - for example the "Rings Extended" application.
50 | * Assign a ringtone directly to a contact.
51 |
52 | #### File formats
53 | Supported file formats right now include:
54 |
55 | * MP3
56 | * AAC/MP4 (including unprotected iTunes music)
57 | * WAV
58 | * 3GPP/AMR (this is the format used when you record sounds directly on the handset)
59 | * OGG
60 |
61 | 
62 |
--------------------------------------------------------------------------------
/app/src/main/java/com/ringdroid/MarkerView.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2008 Google Inc.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.ringdroid;
18 |
19 | import android.content.Context;
20 | import android.graphics.Canvas;
21 | import android.graphics.Rect;
22 | import android.util.AttributeSet;
23 | import android.view.KeyEvent;
24 | import android.view.MotionEvent;
25 | import android.widget.ImageView;
26 |
27 | /**
28 | * Represents a draggable start or end marker.
29 | *
30 | * Most events are passed back to the client class using a
31 | * listener interface.
32 | *
33 | * This class directly keeps track of its own velocity, though,
34 | * accelerating as the user holds down the left or right arrows
35 | * while this control is focused.
36 | */
37 | public class MarkerView extends ImageView {
38 |
39 | public interface MarkerListener {
40 | public void markerTouchStart(MarkerView marker, float pos);
41 | public void markerTouchMove(MarkerView marker, float pos);
42 | public void markerTouchEnd(MarkerView marker);
43 | public void markerFocus(MarkerView marker);
44 | public void markerLeft(MarkerView marker, int velocity);
45 | public void markerRight(MarkerView marker, int velocity);
46 | public void markerEnter(MarkerView marker);
47 | public void markerKeyUp();
48 | public void markerDraw();
49 | };
50 |
51 | private int mVelocity;
52 | private MarkerListener mListener;
53 |
54 | public MarkerView(Context context, AttributeSet attrs) {
55 | super(context, attrs);
56 |
57 | // Make sure we get keys
58 | setFocusable(true);
59 |
60 | mVelocity = 0;
61 | mListener = null;
62 | }
63 |
64 | public void setListener(MarkerListener listener) {
65 | mListener = listener;
66 | }
67 |
68 | @Override
69 | public boolean onTouchEvent(MotionEvent event) {
70 | switch(event.getAction()) {
71 | case MotionEvent.ACTION_DOWN:
72 | requestFocus();
73 | // We use raw x because this window itself is going to
74 | // move, which will screw up the "local" coordinates
75 | mListener.markerTouchStart(this, event.getRawX());
76 | break;
77 | case MotionEvent.ACTION_MOVE:
78 | // We use raw x because this window itself is going to
79 | // move, which will screw up the "local" coordinates
80 | mListener.markerTouchMove(this, event.getRawX());
81 | break;
82 | case MotionEvent.ACTION_UP:
83 | mListener.markerTouchEnd(this);
84 | break;
85 | }
86 | return true;
87 | }
88 |
89 | @Override
90 | protected void onFocusChanged(boolean gainFocus, int direction,
91 | Rect previouslyFocusedRect) {
92 | if (gainFocus && mListener != null)
93 | mListener.markerFocus(this);
94 | super.onFocusChanged(gainFocus, direction, previouslyFocusedRect);
95 | }
96 |
97 | @Override
98 | protected void onDraw(Canvas canvas) {
99 | super.onDraw(canvas);
100 |
101 | if (mListener != null)
102 | mListener.markerDraw();
103 | }
104 |
105 | @Override
106 | public boolean onKeyDown(int keyCode, KeyEvent event) {
107 | mVelocity++;
108 | int v = (int)Math.sqrt(1 + mVelocity / 2);
109 | if (mListener != null) {
110 | if (keyCode == KeyEvent.KEYCODE_DPAD_LEFT) {
111 | mListener.markerLeft(this, v);
112 | return true;
113 | } else if (keyCode == KeyEvent.KEYCODE_DPAD_RIGHT) {
114 | mListener.markerRight(this, v);
115 | return true;
116 | } else if (keyCode == KeyEvent.KEYCODE_DPAD_CENTER) {
117 | mListener.markerEnter(this);
118 | return true;
119 | }
120 | }
121 |
122 | return super.onKeyDown(keyCode, event);
123 | }
124 |
125 | @Override
126 | public boolean onKeyUp(int keyCode, KeyEvent event) {
127 | mVelocity = 0;
128 | if (mListener != null)
129 | mListener.markerKeyUp();
130 | return super.onKeyDown(keyCode, event);
131 | }
132 | }
133 |
--------------------------------------------------------------------------------
/app/src/main/java/com/ringdroid/soundfile/WAVHeader.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2015 Google Inc.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.ringdroid.soundfile;
18 |
19 | public class WAVHeader {
20 | private byte[] mHeader; // the complete header.
21 | private int mSampleRate; // sampling frequency in Hz (e.g. 44100).
22 | private int mChannels; // number of channels.
23 | private int mNumSamples; // total number of samples per channel.
24 | private int mNumBytesPerSample; // number of bytes per sample, all channels included.
25 |
26 | public WAVHeader(int sampleRate, int numChannels, int numSamples) {
27 | mSampleRate = sampleRate;
28 | mChannels = numChannels;
29 | mNumSamples = numSamples;
30 | mNumBytesPerSample = 2 * mChannels; // assuming 2 bytes per sample (for 1 channel)
31 | mHeader = null;
32 | setHeader();
33 | }
34 |
35 | public byte[] getWAVHeader() {
36 | return mHeader;
37 | }
38 |
39 | public static byte[] getWAVHeader(int sampleRate, int numChannels, int numSamples) {
40 | return new WAVHeader(sampleRate, numChannels, numSamples).mHeader;
41 | }
42 |
43 | public String toString() {
44 | String str = "";
45 | if (mHeader == null) {
46 | return str;
47 | }
48 | int num_32bits_per_lines = 8;
49 | int count = 0;
50 | for (byte b : mHeader) {
51 | boolean break_line = count > 0 && count % (num_32bits_per_lines * 4) == 0;
52 | boolean insert_space = count > 0 && count % 4 == 0 && !break_line;
53 | if (break_line) {
54 | str += '\n';
55 | }
56 | if (insert_space) {
57 | str += ' ';
58 | }
59 | str += String.format("%02X", b);
60 | count++;
61 | }
62 |
63 | return str;
64 | }
65 |
66 | private void setHeader() {
67 | byte[] header = new byte[46];
68 | int offset = 0;
69 | int size;
70 |
71 | // set the RIFF chunk
72 | System.arraycopy(new byte[] {'R', 'I', 'F', 'F'}, 0, header, offset, 4);
73 | offset += 4;
74 | size = 36 + mNumSamples * mNumBytesPerSample;
75 | header[offset++] = (byte)(size & 0xFF);
76 | header[offset++] = (byte)((size >> 8) & 0xFF);
77 | header[offset++] = (byte)((size >> 16) & 0xFF);
78 | header[offset++] = (byte)((size >> 24) & 0xFF);
79 | System.arraycopy(new byte[] {'W', 'A', 'V', 'E'}, 0, header, offset, 4);
80 | offset += 4;
81 |
82 | // set the fmt chunk
83 | System.arraycopy(new byte[] {'f', 'm', 't', ' '}, 0, header, offset, 4);
84 | offset += 4;
85 | System.arraycopy(new byte[] {0x10, 0, 0, 0}, 0, header, offset, 4); // chunk size = 16
86 | offset += 4;
87 | System.arraycopy(new byte[] {1, 0}, 0, header, offset, 2); // format = 1 for PCM
88 | offset += 2;
89 | header[offset++] = (byte)(mChannels & 0xFF);
90 | header[offset++] = (byte)((mChannels >> 8) & 0xFF);
91 | header[offset++] = (byte)(mSampleRate & 0xFF);
92 | header[offset++] = (byte)((mSampleRate >> 8) & 0xFF);
93 | header[offset++] = (byte)((mSampleRate >> 16) & 0xFF);
94 | header[offset++] = (byte)((mSampleRate >> 24) & 0xFF);
95 | int byteRate = mSampleRate * mNumBytesPerSample;
96 | header[offset++] = (byte)(byteRate & 0xFF);
97 | header[offset++] = (byte)((byteRate >> 8) & 0xFF);
98 | header[offset++] = (byte)((byteRate >> 16) & 0xFF);
99 | header[offset++] = (byte)((byteRate >> 24) & 0xFF);
100 | header[offset++] = (byte)(mNumBytesPerSample & 0xFF);
101 | header[offset++] = (byte)((mNumBytesPerSample >> 8) & 0xFF);
102 | System.arraycopy(new byte[] {0x10, 0}, 0, header, offset, 2);
103 | offset += 2;
104 |
105 | // set the beginning of the data chunk
106 | System.arraycopy(new byte[] {'d', 'a', 't', 'a'}, 0, header, offset, 4);
107 | offset += 4;
108 | size = mNumSamples * mNumBytesPerSample;
109 | header[offset++] = (byte)(size & 0xFF);
110 | header[offset++] = (byte)((size >> 8) & 0xFF);
111 | header[offset++] = (byte)((size >> 16) & 0xFF);
112 | header[offset++] = (byte)((size >> 24) & 0xFF);
113 |
114 | mHeader = header;
115 | }
116 | }
117 |
--------------------------------------------------------------------------------
/app/src/main/java/com/ringdroid/SongMetadataReader.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2009 Google Inc.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.ringdroid;
18 |
19 | import java.util.HashMap;
20 |
21 | import android.app.Activity;
22 | import android.database.Cursor;
23 | import android.net.Uri;
24 | import android.provider.MediaStore;
25 |
26 | public class SongMetadataReader {
27 | public Uri GENRES_URI = MediaStore.Audio.Genres.EXTERNAL_CONTENT_URI;
28 | public Activity mActivity = null;
29 | public String mFilename = "";
30 | public String mTitle = "";
31 | public String mArtist = "";
32 | public String mAlbum = "";
33 | public String mGenre = "";
34 | public int mYear = -1;
35 |
36 | SongMetadataReader(Activity activity, String filename) {
37 | mActivity = activity;
38 | mFilename = filename;
39 | mTitle = getBasename(filename);
40 | try {
41 | ReadMetadata();
42 | } catch (Exception e) {
43 | }
44 | }
45 |
46 | private void ReadMetadata() {
47 | // Get a map from genre ids to names
48 | HashMap genreIdMap = new HashMap();
49 | Cursor c = mActivity.getContentResolver().query(
50 | GENRES_URI,
51 | new String[] {
52 | MediaStore.Audio.Genres._ID,
53 | MediaStore.Audio.Genres.NAME },
54 | null, null, null);
55 | for (c.moveToFirst(); !c.isAfterLast(); c.moveToNext()) {
56 | genreIdMap.put(c.getString(0), c.getString(1));
57 | }
58 | c.close();
59 | mGenre = "";
60 | for (String genreId : genreIdMap.keySet()) {
61 | c = mActivity.getContentResolver().query(
62 | makeGenreUri(genreId),
63 | new String[] { MediaStore.Audio.Media.DATA },
64 | MediaStore.Audio.Media.DATA + " LIKE \"" + mFilename + "\"",
65 | null, null);
66 | if (c.getCount() != 0) {
67 | mGenre = genreIdMap.get(genreId);
68 | break;
69 | }
70 | c.close();
71 | c = null;
72 | }
73 |
74 | Uri uri = MediaStore.Audio.Media.getContentUriForPath(mFilename);
75 | c = mActivity.getContentResolver().query(
76 | uri,
77 | new String[] {
78 | MediaStore.Audio.Media._ID,
79 | MediaStore.Audio.Media.TITLE,
80 | MediaStore.Audio.Media.ARTIST,
81 | MediaStore.Audio.Media.ALBUM,
82 | MediaStore.Audio.Media.YEAR,
83 | MediaStore.Audio.Media.DATA },
84 | MediaStore.Audio.Media.DATA + " LIKE \"" + mFilename + "\"",
85 | null, null);
86 | if (c.getCount() == 0) {
87 | mTitle = getBasename(mFilename);
88 | mArtist = "";
89 | mAlbum = "";
90 | mYear = -1;
91 | return;
92 | }
93 | c.moveToFirst();
94 | mTitle = getStringFromColumn(c, MediaStore.Audio.Media.TITLE);
95 | if (mTitle == null || mTitle.length() == 0) {
96 | mTitle = getBasename(mFilename);
97 | }
98 | mArtist = getStringFromColumn(c, MediaStore.Audio.Media.ARTIST);
99 | mAlbum = getStringFromColumn(c, MediaStore.Audio.Media.ALBUM);
100 | mYear = getIntegerFromColumn(c, MediaStore.Audio.Media.YEAR);
101 | c.close();
102 | }
103 |
104 | private Uri makeGenreUri(String genreId) {
105 | String CONTENTDIR = MediaStore.Audio.Genres.Members.CONTENT_DIRECTORY;
106 | return Uri.parse(
107 | new StringBuilder()
108 | .append(GENRES_URI.toString())
109 | .append("/")
110 | .append(genreId)
111 | .append("/")
112 | .append(CONTENTDIR)
113 | .toString());
114 | }
115 |
116 | private String getStringFromColumn(Cursor c, String columnName) {
117 | int index = c.getColumnIndexOrThrow(columnName);
118 | String value = c.getString(index);
119 | if (value != null && value.length() > 0) {
120 | return value;
121 | } else {
122 | return null;
123 | }
124 | }
125 |
126 | private int getIntegerFromColumn(Cursor c, String columnName) {
127 | int index = c.getColumnIndexOrThrow(columnName);
128 | Integer value = c.getInt(index);
129 | if (value != null) {
130 | return value;
131 | } else {
132 | return -1;
133 | }
134 | }
135 |
136 | private String getBasename(String filename) {
137 | return filename.substring(filename.lastIndexOf('/') + 1,
138 | filename.lastIndexOf('.'));
139 | }
140 | }
141 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
10 | DEFAULT_JVM_OPTS=""
11 |
12 | APP_NAME="Gradle"
13 | APP_BASE_NAME=`basename "$0"`
14 |
15 | # Use the maximum available, or set MAX_FD != -1 to use that value.
16 | MAX_FD="maximum"
17 |
18 | warn ( ) {
19 | echo "$*"
20 | }
21 |
22 | die ( ) {
23 | echo
24 | echo "$*"
25 | echo
26 | exit 1
27 | }
28 |
29 | # OS specific support (must be 'true' or 'false').
30 | cygwin=false
31 | msys=false
32 | darwin=false
33 | case "`uname`" in
34 | CYGWIN* )
35 | cygwin=true
36 | ;;
37 | Darwin* )
38 | darwin=true
39 | ;;
40 | MINGW* )
41 | msys=true
42 | ;;
43 | esac
44 |
45 | # Attempt to set APP_HOME
46 | # Resolve links: $0 may be a link
47 | PRG="$0"
48 | # Need this for relative symlinks.
49 | while [ -h "$PRG" ] ; do
50 | ls=`ls -ld "$PRG"`
51 | link=`expr "$ls" : '.*-> \(.*\)$'`
52 | if expr "$link" : '/.*' > /dev/null; then
53 | PRG="$link"
54 | else
55 | PRG=`dirname "$PRG"`"/$link"
56 | fi
57 | done
58 | SAVED="`pwd`"
59 | cd "`dirname \"$PRG\"`/" >/dev/null
60 | APP_HOME="`pwd -P`"
61 | cd "$SAVED" >/dev/null
62 |
63 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
64 |
65 | # Determine the Java command to use to start the JVM.
66 | if [ -n "$JAVA_HOME" ] ; then
67 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
68 | # IBM's JDK on AIX uses strange locations for the executables
69 | JAVACMD="$JAVA_HOME/jre/sh/java"
70 | else
71 | JAVACMD="$JAVA_HOME/bin/java"
72 | fi
73 | if [ ! -x "$JAVACMD" ] ; then
74 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
75 |
76 | Please set the JAVA_HOME variable in your environment to match the
77 | location of your Java installation."
78 | fi
79 | else
80 | JAVACMD="java"
81 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
82 |
83 | Please set the JAVA_HOME variable in your environment to match the
84 | location of your Java installation."
85 | fi
86 |
87 | # Increase the maximum file descriptors if we can.
88 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
89 | MAX_FD_LIMIT=`ulimit -H -n`
90 | if [ $? -eq 0 ] ; then
91 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
92 | MAX_FD="$MAX_FD_LIMIT"
93 | fi
94 | ulimit -n $MAX_FD
95 | if [ $? -ne 0 ] ; then
96 | warn "Could not set maximum file descriptor limit: $MAX_FD"
97 | fi
98 | else
99 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
100 | fi
101 | fi
102 |
103 | # For Darwin, add options to specify how the application appears in the dock
104 | if $darwin; then
105 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
106 | fi
107 |
108 | # For Cygwin, switch paths to Windows format before running java
109 | if $cygwin ; then
110 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
111 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
112 | JAVACMD=`cygpath --unix "$JAVACMD"`
113 |
114 | # We build the pattern for arguments to be converted via cygpath
115 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
116 | SEP=""
117 | for dir in $ROOTDIRSRAW ; do
118 | ROOTDIRS="$ROOTDIRS$SEP$dir"
119 | SEP="|"
120 | done
121 | OURCYGPATTERN="(^($ROOTDIRS))"
122 | # Add a user-defined pattern to the cygpath arguments
123 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
124 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
125 | fi
126 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
127 | i=0
128 | for arg in "$@" ; do
129 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
130 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
131 |
132 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
133 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
134 | else
135 | eval `echo args$i`="\"$arg\""
136 | fi
137 | i=$((i+1))
138 | done
139 | case $i in
140 | (0) set -- ;;
141 | (1) set -- "$args0" ;;
142 | (2) set -- "$args0" "$args1" ;;
143 | (3) set -- "$args0" "$args1" "$args2" ;;
144 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
145 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
146 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
147 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
148 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
149 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
150 | esac
151 | fi
152 |
153 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
154 | function splitJvmOpts() {
155 | JVM_OPTS=("$@")
156 | }
157 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
158 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
159 |
160 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
161 |
--------------------------------------------------------------------------------
/app/src/main/res/layout-land/editor.xml:
--------------------------------------------------------------------------------
1 |
2 |
19 |
20 |
24 |
25 |
29 |
30 |
34 |
35 |
42 |
43 |
51 |
52 |
53 |
54 |
62 |
63 |
68 |
69 |
82 |
83 |
94 |
95 |
107 |
108 |
119 |
120 |
130 |
131 |
141 |
142 |
152 |
153 |
154 |
155 |
156 |
--------------------------------------------------------------------------------
/app/src/main/res/values-cn/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
19 |
20 | Ringdroid
21 |
24 | Ringdroid
25 | 新录制
26 | 抱歉,SD卡映射为只读,而Ringdroid需要其可写入。
27 | 抱歉,Ringdroid只在插入SD卡时运行。
28 | 抱歉,Ringdroid无法在手机映射为USB设备时运行。
29 |
32 |
33 | 开始:
34 | 结束:
35 | 编辑
36 | 秒数
37 |
39 | 已保存!要将其设为默认铃声或分配到某个联系人吗?
40 | 已保存!要将其设为默认通知吗?
41 | 设为默认
42 | 分配到联系人
43 | 关闭
44 |
45 | 载入中…
46 | Recording…
47 | 保持中…
48 | Cancel
49 | Stop
50 |
53 | 保存
54 | 重置
55 | 关于
56 | 显示所有音频
57 |
60 | 编辑
61 | 删除
62 | 分配到联系人
63 | 设为默认
64 | 设为默认
65 |
66 |
69 | 另存为:
70 | 保存
71 | 取消
72 | 类型:
73 | 音乐
74 | 闹铃
75 | 通知
76 | 铃声
77 | 名称:
78 | Ringdroid
79 |
82 | 删除铃声
83 | 删除闹铃
84 | 删除通知
85 | 删除音乐
86 | 删除音频
87 | 您确定要这样做吗?
88 | 是否确定?这个文件不是通过Ringdroid创建的!
89 | 删除
90 | 取消
91 | 无法删除文件
92 |
95 | 成功
96 | 错误
97 | 确定
98 | 是的,请吧!
99 | 不,谢谢。
100 | 已保存!
101 | 默认铃声已更改
102 | 无法播放此媒体文件
103 | 无法找到专属文件名
104 | Error recording audio
105 | 无法保存过小的文件,请尝试使其更长。
106 | 写文件时出错
107 | 读文件时出错
108 | 您的SD卡已满,没有足够空间保存此文件。
109 | 抱歉,Ringdroid尚不能编辑有类型的文件。
110 | 抱歉,Ringdroid不能编辑无扩展名(如.mp3、.wav)的文件
111 |
114 | 分配铃声到哪个联系人?
115 | 铃声成功分配到:
116 |
119 | 关于Ringdroid
120 |
121 |
122 |
--------------------------------------------------------------------------------
/app/src/main/java/com/ringdroid/FileSaveDialog.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2008 Google Inc.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.ringdroid;
18 |
19 | import java.util.ArrayList;
20 |
21 | import android.app.Dialog;
22 | import android.content.Context;
23 | import android.content.res.Resources;
24 | import android.os.Message;
25 | import android.view.View;
26 | import android.widget.AdapterView;
27 | import android.widget.AdapterView.OnItemSelectedListener;
28 | import android.widget.ArrayAdapter;
29 | import android.widget.Button;
30 | import android.widget.EditText;
31 | import android.widget.Spinner;
32 |
33 | public class FileSaveDialog extends Dialog {
34 |
35 | // File kinds - these should correspond to the order in which
36 | // they're presented in the spinner control
37 | public static final int FILE_KIND_MUSIC = 0;
38 | public static final int FILE_KIND_ALARM = 1;
39 | public static final int FILE_KIND_NOTIFICATION = 2;
40 | public static final int FILE_KIND_RINGTONE = 3;
41 |
42 | private Spinner mTypeSpinner;
43 | private EditText mFilename;
44 | private Message mResponse;
45 | private String mOriginalName;
46 | private ArrayList mTypeArray;
47 | private int mPreviousSelection;
48 |
49 | /**
50 | * Return a human-readable name for a kind (music, alarm, ringtone, ...).
51 | * These won't be displayed on-screen (just in logs) so they shouldn't
52 | * be translated.
53 | */
54 | public static String KindToName(int kind) {
55 | switch(kind) {
56 | default:
57 | return "Unknown";
58 | case FILE_KIND_MUSIC:
59 | return "Music";
60 | case FILE_KIND_ALARM:
61 | return "Alarm";
62 | case FILE_KIND_NOTIFICATION:
63 | return "Notification";
64 | case FILE_KIND_RINGTONE:
65 | return "Ringtone";
66 | }
67 | }
68 |
69 | public FileSaveDialog(Context context,
70 | Resources resources,
71 | String originalName,
72 | Message response) {
73 | super(context);
74 |
75 | // Inflate our UI from its XML layout description.
76 | setContentView(R.layout.file_save);
77 |
78 | setTitle(resources.getString(R.string.file_save_title));
79 |
80 | mTypeArray = new ArrayList();
81 | mTypeArray.add(resources.getString(R.string.type_music));
82 | mTypeArray.add(resources.getString(R.string.type_alarm));
83 | mTypeArray.add(resources.getString(R.string.type_notification));
84 | mTypeArray.add(resources.getString(R.string.type_ringtone));
85 |
86 | mFilename = (EditText)findViewById(R.id.filename);
87 | mOriginalName = originalName;
88 |
89 | ArrayAdapter adapter = new ArrayAdapter(
90 | context, android.R.layout.simple_spinner_item, mTypeArray);
91 | adapter.setDropDownViewResource(
92 | android.R.layout.simple_spinner_dropdown_item);
93 | mTypeSpinner = (Spinner) findViewById(R.id.ringtone_type);
94 | mTypeSpinner.setAdapter(adapter);
95 | mTypeSpinner.setSelection(FILE_KIND_RINGTONE);
96 | mPreviousSelection = FILE_KIND_RINGTONE;
97 |
98 | setFilenameEditBoxFromName(false);
99 |
100 | mTypeSpinner.setOnItemSelectedListener(new OnItemSelectedListener() {
101 | public void onItemSelected(AdapterView> parent,
102 | View v,
103 | int position,
104 | long id) {
105 | setFilenameEditBoxFromName(true);
106 | }
107 | public void onNothingSelected(AdapterView> parent) {
108 | }
109 | });
110 |
111 | Button save = (Button)findViewById(R.id.save);
112 | save.setOnClickListener(saveListener);
113 | Button cancel = (Button)findViewById(R.id.cancel);
114 | cancel.setOnClickListener(cancelListener);
115 | mResponse = response;
116 | }
117 |
118 | private void setFilenameEditBoxFromName(boolean onlyIfNotEdited) {
119 | if (onlyIfNotEdited) {
120 | CharSequence currentText = mFilename.getText();
121 | String expectedText = mOriginalName + " " +
122 | mTypeArray.get(mPreviousSelection);
123 |
124 | if (!expectedText.contentEquals(currentText)) {
125 | return;
126 | }
127 | }
128 |
129 | int newSelection = mTypeSpinner.getSelectedItemPosition();
130 | String newSuffix = mTypeArray.get(newSelection);
131 | mFilename.setText(mOriginalName + " " + newSuffix);
132 | mPreviousSelection = mTypeSpinner.getSelectedItemPosition();
133 | }
134 |
135 | private View.OnClickListener saveListener = new View.OnClickListener() {
136 | public void onClick(View view) {
137 | mResponse.obj = mFilename.getText();
138 | mResponse.arg1 = mTypeSpinner.getSelectedItemPosition();
139 | mResponse.sendToTarget();
140 | dismiss();
141 | }
142 | };
143 |
144 | private View.OnClickListener cancelListener = new View.OnClickListener() {
145 | public void onClick(View view) {
146 | dismiss();
147 | }
148 | };
149 | }
150 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/editor.xml:
--------------------------------------------------------------------------------
1 |
2 |
19 |
20 |
24 |
25 |
29 |
30 |
36 |
37 |
41 |
42 |
49 |
50 |
58 |
59 |
60 |
61 |
69 |
70 |
75 |
76 |
85 |
86 |
95 |
96 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
118 |
119 |
130 |
131 |
140 |
141 |
152 |
153 |
161 |
162 |
163 |
164 |
165 |
--------------------------------------------------------------------------------
/app/src/main/res/values-ja/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
19 |
20 |
21 |
22 | Ringdroid
23 |
24 |
27 |
28 | Ringdroid
29 |
30 | 新規録音
31 |
32 | SD カードが読み取り専用に設定されています。ロックを解除し、書き込み可能な状態にしてください。
33 | Ringdroid を起動するには SD カードを挿入してください。
34 | 電話機が USB デバイスとして認識されているため、Ringdroid を起動できません。
35 |
36 |
39 |
40 |
41 | 開始::
42 | 終了:
43 |
44 | 編集
45 |
46 | seconds
47 |
48 |
50 | 保存しました。通常の着信音または連絡先の着信音に設定しますか?
51 | 保存しました。通常の通知音に設定しますか?
52 |
53 | 通常の着信音に設定する
54 | 連絡先着信音に設定する
55 | 閉じる
56 |
57 |
58 | ロード中…
59 | Recording…
60 | Saving…
61 | Cancel
62 | Stop
63 |
64 |
67 |
68 | 保存
69 | リセット
70 | 詳細
71 | Show All Audio
72 |
73 |
76 |
77 | 編集
78 | 削除
79 | 連絡先着信音に設定する
80 | 通常の着信音に設定する
81 | 通常の着信音に設定する
82 |
83 |
86 |
87 | ファイル名をつけて保存する:
88 | 保存
89 | キャンセル
90 |
91 | タイプ:
92 |
93 | ミュージック
94 | アラーム音
95 | 通知音
96 | 着信音
97 |
98 | ファイル名:
99 |
100 | Ringdroid
101 |
102 |
105 |
106 | 着信音を削除する
107 | アラーム音を削除する
108 | 通知音を削除する
109 | 音楽を削除する
110 | オーディオファイルを削除する
111 |
112 | 本当に削除しますか?
113 | このファイルはRingdroid以外のアプリケーションを使用して作成されたものです。本当に削除しますか?
115 |
116 | 削除
117 | キャンセル
118 |
119 | ファイルを削除できません
120 |
121 |
124 |
125 | 成功
126 | エラー
127 | OK
128 | はい
129 | いいえ
130 |
131 | 保存しました
132 | 通常の着信音に設定しました
133 | メディアファイルを再生できません
134 | ユニーク
135 | Error recording audio
136 | ファイルが容量が小さすぎるため保存できません。もう少し長く録音してみてください。
137 | ファイル書き込みエラー
138 | Error reading file
139 |
140 | Sorry, Ringdroid is not yet able to edit files of type
141 | Sorry, Ringdroid can\'t edit a file if it doesn\'t have an extension like .mp3 or .wav
142 |
143 |
146 |
147 | 着信音を設定する連絡先を選択してください
148 | この連絡先の着信音に設定しました:
149 |
150 |
153 |
154 | Ringdroid について
155 |
156 |
157 |
158 |
--------------------------------------------------------------------------------
/app/src/main/java/com/ringdroid/SamplePlayer.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2015 Google Inc.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.ringdroid;
18 |
19 | import java.nio.ShortBuffer;
20 |
21 | import android.media.AudioFormat;
22 | import android.media.AudioManager;
23 | import android.media.AudioTrack;
24 |
25 | import com.ringdroid.soundfile.SoundFile;
26 |
27 | class SamplePlayer {
28 | public interface OnCompletionListener {
29 | public void onCompletion();
30 | };
31 |
32 | private ShortBuffer mSamples;
33 | private int mSampleRate;
34 | private int mChannels;
35 | private int mNumSamples; // Number of samples per channel.
36 | private AudioTrack mAudioTrack;
37 | private short[] mBuffer;
38 | private int mPlaybackStart; // Start offset, in samples.
39 | private Thread mPlayThread;
40 | private boolean mKeepPlaying;
41 | private OnCompletionListener mListener;
42 |
43 | public SamplePlayer(ShortBuffer samples, int sampleRate, int channels, int numSamples) {
44 | mSamples = samples;
45 | mSampleRate = sampleRate;
46 | mChannels = channels;
47 | mNumSamples = numSamples;
48 | mPlaybackStart = 0;
49 |
50 | int bufferSize = AudioTrack.getMinBufferSize(
51 | mSampleRate,
52 | mChannels == 1 ? AudioFormat.CHANNEL_OUT_MONO : AudioFormat.CHANNEL_OUT_STEREO,
53 | AudioFormat.ENCODING_PCM_16BIT);
54 | // make sure minBufferSize can contain at least 1 second of audio (16 bits sample).
55 | if (bufferSize < mChannels * mSampleRate * 2) {
56 | bufferSize = mChannels * mSampleRate * 2;
57 | }
58 | mBuffer = new short[bufferSize/2]; // bufferSize is in Bytes.
59 | mAudioTrack = new AudioTrack(
60 | AudioManager.STREAM_MUSIC,
61 | mSampleRate,
62 | mChannels == 1 ? AudioFormat.CHANNEL_OUT_MONO : AudioFormat.CHANNEL_OUT_STEREO,
63 | AudioFormat.ENCODING_PCM_16BIT,
64 | mBuffer.length * 2,
65 | AudioTrack.MODE_STREAM);
66 | // Check when player played all the given data and notify user if mListener is set.
67 | mAudioTrack.setNotificationMarkerPosition(mNumSamples - 1); // Set the marker to the end.
68 | mAudioTrack.setPlaybackPositionUpdateListener(
69 | new AudioTrack.OnPlaybackPositionUpdateListener() {
70 | @Override
71 | public void onPeriodicNotification(AudioTrack track) {}
72 |
73 | @Override
74 | public void onMarkerReached(AudioTrack track) {
75 | stop();
76 | if (mListener != null) {
77 | mListener.onCompletion();
78 | }
79 | }
80 | });
81 | mPlayThread = null;
82 | mKeepPlaying = true;
83 | mListener = null;
84 | }
85 |
86 | public SamplePlayer(SoundFile sf) {
87 | this(sf.getSamples(), sf.getSampleRate(), sf.getChannels(), sf.getNumSamples());
88 | }
89 |
90 | public void setOnCompletionListener(OnCompletionListener listener) {
91 | mListener = listener;
92 | }
93 |
94 | public boolean isPlaying() {
95 | return mAudioTrack.getPlayState() == AudioTrack.PLAYSTATE_PLAYING;
96 | }
97 |
98 | public boolean isPaused() {
99 | return mAudioTrack.getPlayState() == AudioTrack.PLAYSTATE_PAUSED;
100 | }
101 |
102 | public void start() {
103 | if (isPlaying()) {
104 | return;
105 | }
106 | mKeepPlaying = true;
107 | mAudioTrack.flush();
108 | mAudioTrack.play();
109 | // Setting thread feeding the audio samples to the audio hardware.
110 | // (Assumes mChannels = 1 or 2).
111 | mPlayThread = new Thread () {
112 | public void run() {
113 | int position = mPlaybackStart * mChannels;
114 | mSamples.position(position);
115 | int limit = mNumSamples * mChannels;
116 | while (mSamples.position() < limit && mKeepPlaying) {
117 | int numSamplesLeft = limit - mSamples.position();
118 | if(numSamplesLeft >= mBuffer.length) {
119 | mSamples.get(mBuffer);
120 | } else {
121 | for(int i=numSamplesLeft; i mNumSamples) {
167 | mPlaybackStart = mNumSamples; // Nothing to play...
168 | }
169 | mAudioTrack.setNotificationMarkerPosition(mNumSamples - 1 - mPlaybackStart);
170 | if (wasPlaying) {
171 | start();
172 | }
173 | }
174 |
175 | public int getCurrentPosition() {
176 | return (int)((mPlaybackStart + mAudioTrack.getPlaybackHeadPosition()) *
177 | (1000.0 / mSampleRate));
178 | }
179 | }
180 |
--------------------------------------------------------------------------------
/app/src/main/res/values-es/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
19 |
20 | Ringdroid
21 |
24 | Ringdroid
25 | Registro nuevo
26 | La tarjeta SD es de sólo lectura y Ringdroid precisa que sea de escritura.
27 | Ringdroid sólo puede funcionar con una arjeta SD insertada.
28 | Ringdroid no funciona si el aparato está montado en un dispositivo USB.
29 |
32 |
33 | Inicio:
34 | Fin:
35 | Editar
36 | segundos
37 |
38 | Guardado. ¿Quieres que sea el tono por defecto o para un contacto?
39 | Guardado. ¿Quieres que sea tu notificación por defecto?
40 | Por defecto
41 | Asignar a contacto
42 | Cerrar
43 |
44 | Cargando…
45 | Recording…
46 | Guardando…
47 | Cancel
48 | Stop
49 |
52 | Guardar
53 | Reiniciar
54 | Acerca de
55 | Mostrar sonidos
56 |
59 | Editar
60 | Eliminar
61 | Asignar a contacto
62 | Por defecto
63 | Por defecto
64 |
67 | Guardar como:
68 | Guardar
69 | Cancelar
70 | Tipo:
71 | Música
72 | Alarma
73 | Notificación
74 | Tono llamada
75 | Nombre:
76 | Ringdroid
77 |
80 | Eliminar tono
81 | Eliminar alarma
82 | Eliminar notificación
83 | Eliminar música
84 | Eliminar sonido
85 | ¿Seguro?
86 | ¿Seguro? Este archivo no se creó con Ringdroid.
87 | Eliminar
88 | Cancelar
89 | Imposible eliminar archivo
90 |
93 | Éxito
94 | Error
95 | Aceptar
96 | Sí, por favor.
97 | No, gracias.
98 | Guardado
99 | Tono por defecto cambiado
100 | Imposible reproducir este archivo multimedia
101 | Imposible encontrar un nombre de archivo único
102 | Error recording audio
103 | Imposible guardar un archivo tan corto, amplíalo.
104 | Error al escribir archivo
105 | Error al leer archivo
106 | La tarjeta SD está llena, no hay espacio para guardar este archivo.
107 | Ringdroid aún no puede editar este tipo de archivos.
108 | Ringdroid no puede editar un archivo si no tiene extensión .mp3 o .wav.
109 |
112 | ¿A qué contacto se asignar este tono?
113 | Tono asignado correctamente a:
114 |
117 | Acerca de Ringdroid
118 |
119 |
120 |
--------------------------------------------------------------------------------
/app/src/main/res/values-pl/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Ringdroid
7 |
8 |
9 |
10 | Ringdroid
11 |
12 | Nagraj nowy
13 |
14 | Niestety, karta SD jest kartą tylko do odczytu, Ringdroid wymaga, by była zapisywalna.
15 | Przepraszamy, nie można uruchomić Ringdroid bez karty SD.
16 | Nie można uruchomić Ringdroid, jeśli słuchawki podpięto jako urządz. USB.
17 |
18 |
19 |
20 |
21 | Start:
22 | Koniec:
23 |
24 | Edytuj
25 |
26 | s
27 |
28 |
29 | Zapisano! Ustawić dzwonek jako domyślny czy przypisać go do kontaktu?
30 | Zapisano! Ustawić jako powiadomienie dom.?
31 |
32 | Ustaw jako domyślny
33 | Przypisz do kontaktu
34 | Zamknij
35 |
36 |
37 | Wczytywanie…
38 | Recording…
39 | Zapisywanie…
40 | Cancel
41 | Stop
42 |
43 |
44 |
45 | Zapisz
46 | Resetuj
47 | O programie
48 | Pokaż wszystkie pliki audio
49 |
50 |
51 |
52 | Edytuj
53 | Skasuj
54 | Przypisz do kontaktu
55 | Ustaw jako domyślny
56 | Ustaw jako domyślny
57 |
58 |
59 |
60 | Zapisz jako:
61 | Zapisz
62 | Anuluj
63 |
64 | Typ:
65 |
66 | Muzyka
67 | Alarm
68 | Powiadomienie
69 | Dzwonek
70 |
71 | Nazwa:
72 |
73 | Ringdroid
74 |
75 |
76 |
77 | Usuń dzwonek
78 | Usuń alarm
79 | Usuń powiadomienie
80 | Usuń muzykę
81 | Usuń plik audio
82 |
83 | Na pewno?
84 | Na pewno? Ten plik nie został utworzony przez Ringdroid!
85 |
86 | Skasuj
87 | Anuluj
88 |
89 | Nie można usunąć pliku
90 |
91 |
92 |
93 | Gotowe
94 | Błąd
95 | OK
96 | Tak
97 | Nie
98 |
99 | Zapisano!
100 | Zmieniono dzwonek dom.
101 | Nie można odtworzyć tego pliku
102 | Nie można znaleźć unikalnej nazwy
103 | Error recording audio
104 | Nie można zapisać tak małego pliku, nagraj dłuższy plik.
105 | Błąd zapisu pliku
106 | Błąd odczytu pliku
107 |
108 | Karta SD pełna, brak miejsca do zapisania tego pliku.
109 |
110 | Niestety, Ringdroid nie edytuje plików tego typu
111 | Niestety, Ringdroid nie może edytować pliku o rozszerzeniu innym niż .mp3 lub .wav
112 |
113 |
114 |
115 | Do którego kontaktu przypisać dzwonek?
116 | Przypisano dzwonek do:
117 |
118 |
119 |
120 | O Ringdroid
121 |
122 |
123 |
124 |
--------------------------------------------------------------------------------
/app/src/main/res/values-ru/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Программа Ringdroid
7 |
8 |
9 |
10 | Программа Ringdroid
11 |
12 | Записать новый
13 |
14 | Извините, SD-карта только для чтения – для Ringdroid требуется записываемая карта.
15 | Извините, пока не вставлена SD-карта, Ringdroid не работает.
16 | Извините, пока телефон подключен к разъему USB, Ringdroid не работает.
17 |
18 |
19 |
20 |
21 | Начало:
22 | Конец:
23 |
24 | Изменить
25 |
26 | сек.
27 |
28 |
29 | Сохранено! Сделать сигналом звонка по умолчанию или назначить для контакта?
30 | Сохранено! Сделать уведомлением по умолчанию?
31 |
32 | По умолчанию
33 | Назначить для контакта
34 | Закрыть
35 |
36 |
37 | Загрузка…
38 | Recording…
39 | Сохранение…
40 | Cancel
41 | Stop
42 |
43 |
44 |
45 | Сохранить
46 | Сброс
47 | Сведения
48 | Показать все аудио
49 |
50 |
51 |
52 | Изменить
53 | Удалить
54 | Назначить для контакта
55 | По умолчанию
56 | По умолчанию
57 |
58 |
59 |
60 | Сохранить как:
61 | Сохранить
62 | Отменить
63 |
64 | Тип:
65 |
66 | Музыка
67 | Будильник
68 | Уведомление
69 | Сигнал звонка
70 |
71 | Имя:
72 |
73 | Программа Ringdroid
74 |
75 |
76 |
77 | Удалить сигнал звонка
78 | Удалить сигнал будильника
79 | Удалить уведомление
80 | Удалить музыку
81 | Удалить аудио
82 |
83 | Вы уверены?
84 | Вы уверены? Файл создан не в программе Ringdroid!
85 |
86 | Удалить
87 | Отменить
88 |
89 | Невозможно удалить файл
90 |
91 |
92 |
93 | Готово
94 | Ошибка
95 | ОК
96 | Да!
97 | Нет.
98 |
99 | Сохранено!
100 | Сигнал звонка по умолчанию изменен
101 | Невозможно воспроизвести файл мультимедиа
102 | Не удается найти уникальное имя файла
103 | Error recording audio
104 | Файл слишком короткий для сохранения, удлините его.
105 | Ошибка записи файла
106 | Ошибка чтения файла
107 |
108 | SD-карта заполнена, недостаточно места для сохранения этого файла.
109 |
110 | Извините, в Ringdroid пока невозможна редакция таких файлов
111 | Извините, в Ringdroid невозможна редакция файлов с расширением отличным от .mp3 или .wav
112 |
113 |
114 |
115 | Для которого контакта назначить сигнал звонка?
116 | Сигнал звонка успешно назначен контакту:
117 |
118 |
119 |
120 | О программе Ringdroid
121 |
122 |
123 |
124 |
--------------------------------------------------------------------------------
/app/src/main/res/values-it/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Ringdroid
7 |
8 |
9 |
10 | Ringdroid
11 |
12 | Registra nuovo
13 |
14 | Scheda SD di sola lettura. Ringdroid richiede una scheda scrivibile.
15 | Impossibile eseguire Ringdroid senza una scheda SD inserita.
16 | Impossibile eseguire Ringdroid con il telefono impostato come periferica USB.
17 |
18 |
19 |
20 |
21 | Inizio:
22 | Fine:
23 |
24 | Modifica
25 |
26 | secondi
27 |
28 |
29 | Salvataggio eseguito. Impostare come suoneria predefinita o assegnare a un contatto?
30 | Salvataggio eseguito. Impostare come notifica predefinita?
31 |
32 | Imposta predefinita
33 | Assegna a contatto
34 | Chiudi
35 |
36 |
37 | Caricamento…
38 | Recording…
39 | Salvataggio…
40 | Cancel
41 | Stop
42 |
43 |
44 |
45 | Salva
46 | Reimposta
47 | Info
48 | Mostra tutto audio
49 |
50 |
51 |
52 | Modifica
53 | Elimina
54 | Assegna a contatto
55 | Imposta predefinita
56 | Imposta predefinita
57 |
58 |
59 |
60 | Salva con nome:
61 | Salva
62 | Annulla
63 |
64 | Tipo:
65 |
66 | Musica
67 | Allarme
68 | Notifica
69 | Suoneria
70 |
71 | Nome:
72 |
73 | Ringdroid
74 |
75 |
76 |
77 | Elimina suoneria
78 | Elimina allarme
79 | Elimina notifica
80 | Elimina musica
81 | Elimina audio
82 |
83 | Continuare?
84 | Continuare? Questo file non è stato creato con Ringdroid.
85 |
86 | Elimina
87 | Annulla
88 |
89 | Impossibile eliminare file
90 |
91 |
92 |
93 | Operazione riuscita
94 | Errore
95 | OK
96 | Sì, grazie.
97 | No, grazie.
98 |
99 | Salvataggio eseguito.
100 | Suoneria predefinita cambiata
101 | Impossibile riprodurre file multimediale
102 | Impossibile trovare nome file univoco
103 | Error recording audio
104 | Impossibile salvare file troppo piccolo. Renderlo più lungo.
105 | Errore scrittura file
106 | Errore lettura file
107 |
108 | Scheda SD piena. Spazio insufficiente per salvare questo file.
109 |
110 | Ringdroid non può ancora modificare file di questo tipo.
111 | Ringdroid non può modificare un file con estensione diversa da .mp3 o .wav.
112 |
113 |
114 |
115 | A quale contatto assegnare la suoneria?
116 | Suoneria assegnata a:
117 |
118 |
119 |
120 | Info su Ringdroid
121 |
122 |
123 |
124 |
--------------------------------------------------------------------------------
/app/src/main/res/values-de/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Ringdroid
7 |
8 |
9 |
10 | Ringdroid
11 |
12 | Neu aufzeichnen
13 |
14 | Die SD-Karte ist schreibgeschützt. In Ringdroid muss sie beschreibbar sein.
15 | Ringdroid kann nur bei eingesetzter SD-Karte ausgeführt werden.
16 | Ringdroid kann nur mit einem als USB-Gerät angeschlossenen Gerät ausgeführt werden.
17 |
18 |
19 |
20 |
21 | Start:
22 | Ende:
23 |
24 | Bearbeiten
25 |
26 | Sekunden
27 |
28 |
29 | Gespeichert! Dieses Rufzeichen zum Standardrufzeichen machen oder einem Kontakt zuweisen?
30 | Gespeichert! Diese Benachrichtigung zur Standardbenachrichtigung machen?
31 |
32 | Zum Standard machen
33 | Einem Kontakt zuweisen
34 | Schließen
35 |
36 |
37 | Laden…
38 | Recording…
39 | Wird gespeichert…
40 | Cancel
41 | Stop
42 |
43 |
44 |
45 | Speichern
46 | Zurücksetzen
47 | Info
48 | Alle Audiodateien anz.
49 |
50 |
51 |
52 | Bearbeiten
53 | Löschen
54 | Einem Kontakt zuweisen
55 | Zum Standard machen
56 | Zum Standard machen
57 |
58 |
59 |
60 | Speichern unter:
61 | Speichern
62 | Abbrechen
63 |
64 | Typ:
65 |
66 | Musik
67 | Wecker
68 | Benachrichtigung
69 | Rufzeichen
70 |
71 | Name:
72 |
73 | Ringdroid
74 |
75 |
76 |
77 | Rufzeichen löschen
78 | Wecker löschen
79 | Benachrichtigung löschen
80 | Musik löschen
81 | Audio löschen
82 |
83 | Sind Sie sicher?
84 | Sind Sie sicher? Diese Datei wurde nicht mit Ringdroid erstellt!
85 |
86 | Löschen
87 | Abbrechen
88 |
89 | Datei konnte nicht gelöscht werden
90 |
91 |
92 |
93 | Erfolg
94 | Fehler
95 | OK
96 | Ja, bitte!
97 | Nein, vielen Dank.
98 |
99 | Gespeichert!
100 | Standardrufzeichen geändert
101 | Mediendatei kann nicht wiedergegeben werden
102 | Eindeutiger Dateiname nicht gefunden
103 | Error recording audio
104 | Eine so kleine Datei kann nicht gespeichert werden.
105 | Fehler beim Schreiben der Datei
106 | Fehler beim Lesen der Datei
107 |
108 | Ihre SD-Karte ist voll. Nicht genügend Platz zum Speichern der Datei.
109 |
110 | Ringdroid kann noch keine Dateien dieses Typs bearbeiten
111 | Ringdroid kann nur Dateien mit einer Erweiterung wie .mp3 oder .wav bearbeiten
112 |
113 |
114 |
115 | Welchen Kontakt soll das Rufzeichen zugewiesen werden?
116 | Rufzeichen erfolgreich zugewiesen an:
117 |
118 |
119 |
120 | Info über Ringdroid
121 |
122 |
123 |
124 |
--------------------------------------------------------------------------------
/app/src/main/res/values-nl/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
19 |
20 |
21 |
22 | Ringdroid
23 |
24 |
27 |
28 | Ringdroid
29 |
30 | Nieuwe opname
31 |
32 | De SD-kaart is gekoppeld als alleen-lezen en Ringdroid moet naar de kaart kunnen schrijven.
33 | Ringdroid kan niet worden uitgevoerd tenzij u een SD-kaart hebt geplaatst.
34 | Ringdroid kan niet worden uitgevoerd terwijl uw handset is gekoppeld als USB-apparaat.
35 |
36 |
39 |
40 |
41 | Start:
42 | Eind:
43 |
44 | Bewerken
45 |
46 | seconden
47 |
48 |
50 | Opgeslagen. Instellen als standaardbeltoon of toewijzen aan een contact?
51 | Opgeslagen. Instellen als standaardmelding?
52 |
53 | Instellen als standaard
54 | Toewijzen aan contact
55 | Sluiten
56 |
57 |
58 | Laden…
59 | Recording…
60 | Opslaan…
61 | Cancel
62 | Stop
63 |
64 |
67 |
68 | Opslaan
69 | Opnieuw instellen
70 | Over
71 | Alle audio weergeven
72 |
73 |
76 |
77 | Bewerken
78 | Verwijderen
79 | Toewijzen aan contact
80 | Instellen als standaard
81 | Instellen als standaard
82 |
83 |
86 |
87 | Opslaan als:
88 | Opslaan
89 | Annuleren
90 |
91 | Type:
92 |
93 | Muziek
94 | Alarm
95 | Melding
96 | Beltoon
97 |
98 | Naam:
99 |
100 | Ringdroid
101 |
102 |
105 |
106 | Beltoon verwijderen
107 | Alarm verwijderen
108 | Melding verwijderen
109 | Muziek verwijderen
110 | Audio verwijderen
111 |
112 | Weet u het zeker?
113 | Weet u het zeker? Dit bestand is niet gemaakt met Ringdroid.
114 |
115 | Verwijderen
116 | Annuleren
117 |
118 | Kan bestand niet verwijderen
119 |
120 |
123 |
124 | Succes
125 | Fout
126 | OK
127 | Ja, graag.
128 | Nee, bedankt.
129 |
130 | Opgeslagen.
131 | Standaardbeltoon gewijzigd
132 | Kan dit mediabestand niet afspelen
133 | Kan unieke bestandsnaam niet vinden
134 | Error recording audio
135 | Kan een bestand dat zo kort is, niet opslaan. Maak het langer.
136 | Fout bij schrijven van bestand
137 | Fout bij lezen van bestand
138 |
139 | De SD-kaart is vol. Onvoldoende ruimte om dit bestand op te slaan.
140 |
141 | Ringdroid kan bestanden van dit type niet bewerken
142 | Ringdroid kan een bestand niet bewerken als het geen extensie zoals .mp3 of .wav heeft
143 |
144 |
147 |
148 | Beltoon toewijzen aan welk contact?
149 | Beltoon toegewezen aan:
150 |
151 |
154 |
155 | Over Ringdroid
156 |
157 |
158 |
159 |
--------------------------------------------------------------------------------
/app/src/main/res/values-fr/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
19 |
20 |
21 |
22 | Ringdroid
23 |
24 |
27 |
28 | Ringdroid
29 |
30 | Nouvel enregistrement
31 |
32 | Désolé mais votre carte mémoire SD est en lecture seule et Ringdroid nécessite de l\'écriture.
33 | Désolé mais Ringdroid nécessite une carte mémoire SD pour fonctionner.
34 | Désolé mais Ringdroid ne peut fonctionner quand le téléphone est utilisé comme mémoire USB sur un ordinateur.
35 |
36 |
39 |
40 |
41 | Début:
42 | Fin:
43 |
44 | Modifier
45 |
46 | secondes
47 |
48 |
50 | Sauvegardé! En faire votre sonnerie ou l\'utiliser pour un contact?
51 | Sauvegardé! En faire votre notification par défaut?
52 |
53 | Utiliser comme défaut
54 | Utiliser pour un Contact
55 | Fermer
56 |
57 |
58 | Chargement…
59 | Enregistrement…
60 | Sauvegarde…
61 | Cancel
62 | Stop
63 |
64 |
67 |
68 | Sauver
69 | Mise à 0
70 | A propos
71 | Afficher tous les audio
72 |
73 |
76 |
77 | Modifier
78 | Efface
79 | Utiliser pour un Contact
80 | Utiliser comme défaut
81 | Utiliser comme défaut
82 |
83 |
86 |
87 | Sauver comme:
88 | Sauver
89 | Annuler
90 |
91 | Type:
92 |
93 | Musique
94 | Alarme
95 | Notification
96 | Sonnerie
97 |
98 | Nom:
99 |
100 | Ringdroid
101 |
102 |
105 |
106 | Effacer sonnerie
107 | Effacer alarme
108 | Effacer notification
109 | Effacer musique
110 | Effacer audio
111 |
112 | Etes vous sûr?
113 | Etes vous sûr? Ce fichier n\'a pas été créé en utilisant Ringdroid!
115 |
116 | Effacer
117 | Annuler
118 |
119 | Impossible d\'effacer le fichier
120 |
121 |
124 |
125 | Succès
126 | Erreur
127 | OK
128 | Oui, SVP!
129 | Non merci.
130 |
131 | Sauvegardé!
132 | Sonnerie par défaut modifiée
133 | Impossible de jouer ce fichier
134 | Impossible de trouver un nom unique
135 | Error recording audio
136 | Impossible de sauver un fichier si court, essayez de le faire plus long.
137 | Erreur d\'écriture fichier
138 | Erreur lecture fichier
139 |
140 | Votre carte mémoire SD est pleine, il n\'y a plus assez de place pour sauver le fichier.
141 |
142 | Désolé mais Ringdroid n\'est pas encore capable de modifier ce type de fichier
143 | Désolé mais Ringdroid n\'est pas encore capable de modifier si il n\'a pas d\'extension comme .mp3 or .wav
144 |
145 |
148 |
149 | Utilser comme sonnerie pour quel contact?
150 | La sonnerie est bien utilisée pour:
151 |
152 |
155 |
156 | A propos Ringdroid
157 |
158 |
159 |
160 |
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
19 |
20 |
23 |
24 | Ringdroid
25 |
26 |
29 |
30 | Ringdroid
31 |
32 | Search
33 |
34 | Record New
35 |
36 | Sorry, the SD Card is mounted as read-only and Ringdroid requires it to be writable.
37 | Sorry, Ringdroid can\'t run unless you have an SD Card inserted.
38 | Sorry, Ringdroid can\'t run while your handset is mounted as a USB device.
39 |
40 | Options
41 |
42 |
45 |
46 |
47 | Start:
48 | End:
49 |
50 | Edit
51 |
52 | seconds
53 |
54 |
56 | Saved! Make this your default ringtone or assign it to a contact?
57 | Saved! Make this your default notification?
58 |
59 | Make Default
60 | Assign to Contact
61 | Close
62 |
63 |
64 | Loading…
65 | Recording…
66 | Saving…
67 | Cancel
68 | Stop
69 |
70 |
71 |
72 | Start marker
73 | End marker
74 | Rewind
75 | Play
76 | Stop
77 | Fast forward
78 | Zoom In
79 | Zoom Out
80 | Save
81 |
82 |
85 |
86 | Save
87 | Reset
88 | About
89 | Show All Audio
90 |
91 |
94 |
95 | Edit
96 | Delete
97 | Set as Default Ringtone
98 | Assign to Contact
99 | Set as Default Notification
100 |
101 |
104 |
105 | Save As:
106 | Save
107 | Cancel
108 |
109 | Type:
110 |
111 | Music
112 | Alarm
113 | Notification
114 | Ringtone
115 |
116 | Name:
117 |
118 | Ringdroid
119 |
120 |
123 |
124 | Delete Ringtone
125 | Delete Alarm
126 | Delete Notification
127 | Delete Music
128 | Delete Audio
129 |
130 | Are you sure?
131 | Are you sure? This file was not created using Ringdroid!
133 |
134 | Delete
135 | Cancel
136 |
137 | Unable to delete file
138 |
139 |
142 |
143 | Success
144 | Error
145 | OK
146 | Yes, please!
147 | No, thanks.
148 |
149 | Saved!
150 | Changed default ringtone
151 | Changed default notification sound
152 | Unable to play this media file
153 | Unable to find unique filename
154 | Error recording audio
155 | Can\'t save a file that small, try making it longer.
156 | Error writing file
157 | Error reading file
158 |
159 | Your SD card is full, there is not enough space to save this file.
160 |
161 | Sorry, Ringdroid is not yet able to edit files of type
162 | Sorry, Ringdroid can\'t edit a file if it doesn\'t have an extension like .mp3 or .wav
163 |
164 |
167 |
168 | Assign ringtone to which contact?
169 | Successfully assigned ringtone to:
170 |
171 |
174 |
175 | About Ringdroid
176 |
177 |
178 |
179 |
--------------------------------------------------------------------------------
/app/src/main/java/com/ringdroid/ChooseContactActivity.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2009 Google Inc.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.ringdroid;
18 |
19 | import android.app.ListActivity;
20 | import android.app.LoaderManager;
21 | import android.content.ContentValues;
22 | import android.content.CursorLoader;
23 | import android.content.Intent;
24 | import android.content.Loader;
25 | import android.database.Cursor;
26 | import android.net.Uri;
27 | import android.os.Bundle;
28 | import android.provider.ContactsContract.Contacts;
29 | import android.text.Editable;
30 | import android.text.TextWatcher;
31 | import android.util.Log;
32 | import android.view.View;
33 | import android.widget.AdapterView;
34 | import android.widget.AdapterView.OnItemClickListener;
35 | import android.widget.SimpleCursorAdapter;
36 | import android.widget.TextView;
37 | import android.widget.Toast;
38 |
39 | /**
40 | * After a ringtone has been saved, this activity lets you pick a contact
41 | * and assign the ringtone to that contact.
42 | */
43 | public class ChooseContactActivity
44 | extends ListActivity
45 | implements TextWatcher, LoaderManager.LoaderCallbacks
46 | {
47 | private TextView mFilter;
48 | private SimpleCursorAdapter mAdapter;
49 | private Uri mRingtoneUri;
50 |
51 | public ChooseContactActivity() {
52 | }
53 |
54 | /**
55 | * Called when the activity is first created.
56 | */
57 | @Override
58 | public void onCreate(Bundle icicle) {
59 | super.onCreate(icicle);
60 |
61 | setTitle(R.string.choose_contact_title);
62 |
63 | Intent intent = getIntent();
64 | mRingtoneUri = intent.getData();
65 |
66 | // Inflate our UI from its XML layout description.
67 | setContentView(R.layout.choose_contact);
68 |
69 | try {
70 | mAdapter = new SimpleCursorAdapter(
71 | this,
72 | // Use a template that displays a text view
73 | R.layout.contact_row,
74 | // Set an empty cursor right now. Will be set in onLoadFinished()
75 | null,
76 | // Map from database columns...
77 | new String[] {
78 | Contacts.CUSTOM_RINGTONE,
79 | Contacts.STARRED,
80 | Contacts.DISPLAY_NAME },
81 | // To widget ids in the row layout...
82 | new int[] {
83 | R.id.row_ringtone,
84 | R.id.row_starred,
85 | R.id.row_display_name },
86 | 0);
87 |
88 | mAdapter.setViewBinder(new SimpleCursorAdapter.ViewBinder() {
89 | public boolean setViewValue(View view,
90 | Cursor cursor,
91 | int columnIndex) {
92 | String name = cursor.getColumnName(columnIndex);
93 | String value = cursor.getString(columnIndex);
94 | if (name.equals(Contacts.CUSTOM_RINGTONE)) {
95 | if (value != null && value.length() > 0) {
96 | view.setVisibility(View.VISIBLE);
97 | } else {
98 | view.setVisibility(View.INVISIBLE);
99 | }
100 | return true;
101 | }
102 | if (name.equals(Contacts.STARRED)) {
103 | if (value != null && value.equals("1")) {
104 | view.setVisibility(View.VISIBLE);
105 | } else {
106 | view.setVisibility(View.INVISIBLE);
107 | }
108 | return true;
109 | }
110 |
111 | return false;
112 | }
113 | });
114 |
115 | setListAdapter(mAdapter);
116 |
117 | // On click, assign ringtone to contact
118 | getListView().setOnItemClickListener(
119 | new OnItemClickListener() {
120 | public void onItemClick(AdapterView> parent,
121 | View view,
122 | int position,
123 | long id) {
124 | assignRingtoneToContact();
125 | }
126 | }
127 | );
128 |
129 | getLoaderManager().initLoader(0, null, this);
130 |
131 | } catch (SecurityException e) {
132 | // No permission to retrieve contacts?
133 | Log.e("Ringdroid", e.toString());
134 | }
135 |
136 | mFilter = (TextView) findViewById(R.id.search_filter);
137 | if (mFilter != null) {
138 | mFilter.addTextChangedListener(this);
139 | }
140 | }
141 |
142 | private void assignRingtoneToContact() {
143 | Cursor c = mAdapter.getCursor();
144 | int dataIndex = c.getColumnIndexOrThrow(Contacts._ID);
145 | String contactId = c.getString(dataIndex);
146 |
147 | dataIndex = c.getColumnIndexOrThrow(Contacts.DISPLAY_NAME);
148 | String displayName = c.getString(dataIndex);
149 |
150 | Uri uri = Uri.withAppendedPath(Contacts.CONTENT_URI, contactId);
151 |
152 | ContentValues values = new ContentValues();
153 | values.put(Contacts.CUSTOM_RINGTONE, mRingtoneUri.toString());
154 | getContentResolver().update(uri, values, null, null);
155 |
156 | String message =
157 | getResources().getText(R.string.success_contact_ringtone) +
158 | " " +
159 | displayName;
160 |
161 | Toast.makeText(this, message, Toast.LENGTH_SHORT)
162 | .show();
163 | finish();
164 | return;
165 | }
166 |
167 | /* Implementation of TextWatcher.beforeTextChanged */
168 | public void beforeTextChanged(CharSequence s, int start, int count, int after) {
169 | }
170 |
171 | /* Implementation of TextWatcher.onTextChanged */
172 | public void onTextChanged(CharSequence s, int start, int before, int count) {
173 | }
174 |
175 | /* Implementation of TextWatcher.afterTextChanged */
176 | public void afterTextChanged(Editable s) {
177 | //String filterStr = mFilter.getText().toString();
178 | //mAdapter.changeCursor(createCursor(filterStr));
179 | Bundle args = new Bundle();
180 | args.putString("filter", mFilter.getText().toString());
181 | getLoaderManager().restartLoader(0, args, this);
182 | }
183 |
184 | /* Implementation of LoaderCallbacks.onCreateLoader */
185 | @Override
186 | public Loader onCreateLoader(int id, Bundle args) {
187 | String selection = null;
188 | String filter = args != null ? args.getString("filter") : null;
189 | if (filter != null && filter.length() > 0) {
190 | selection = "(DISPLAY_NAME LIKE \"%" + filter + "%\")";
191 | }
192 | return new CursorLoader(
193 | this,
194 | Contacts.CONTENT_URI,
195 | new String[] {
196 | Contacts._ID,
197 | Contacts.CUSTOM_RINGTONE,
198 | Contacts.DISPLAY_NAME,
199 | Contacts.LAST_TIME_CONTACTED,
200 | Contacts.STARRED,
201 | Contacts.TIMES_CONTACTED },
202 | selection,
203 | null,
204 | "STARRED DESC, " +
205 | "TIMES_CONTACTED DESC, " +
206 | "LAST_TIME_CONTACTED DESC, " +
207 | "DISPLAY_NAME ASC"
208 | );
209 | }
210 |
211 | /* Implementation of LoaderCallbacks.onLoadFinished */
212 | @Override
213 | public void onLoadFinished(Loader loader, Cursor data) {
214 | Log.v("Ringdroid", data.getCount() + " contacts");
215 | mAdapter.swapCursor(data);
216 | }
217 |
218 | /* Implementation of LoaderCallbacks.onLoaderReset */
219 | @Override
220 | public void onLoaderReset(Loader loader) {
221 | // This is called when the last Cursor provided to onLoadFinished()
222 | // above is about to be closed. We need to make sure we are no
223 | // longer using it.
224 | mAdapter.swapCursor(null);
225 | }
226 | }
227 |
--------------------------------------------------------------------------------
/app/src/main/java/com/ringdroid/WaveformView.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2008 Google Inc.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.ringdroid;
18 |
19 | import android.content.Context;
20 | import android.content.res.Resources;
21 | import android.graphics.Canvas;
22 | import android.graphics.DashPathEffect;
23 | import android.graphics.Paint;
24 | import android.util.AttributeSet;
25 | import android.util.Log;
26 | import android.view.GestureDetector;
27 | import android.view.MotionEvent;
28 | import android.view.ScaleGestureDetector;
29 | import android.view.View;
30 |
31 | import com.ringdroid.soundfile.SoundFile;
32 |
33 | /**
34 | * WaveformView is an Android view that displays a visual representation
35 | * of an audio waveform. It retrieves the frame gains from a CheapSoundFile
36 | * object and recomputes the shape contour at several zoom levels.
37 | *
38 | * This class doesn't handle selection or any of the touch interactions
39 | * directly, so it exposes a listener interface. The class that embeds
40 | * this view should add itself as a listener and make the view scroll
41 | * and respond to other events appropriately.
42 | *
43 | * WaveformView doesn't actually handle selection, but it will just display
44 | * the selected part of the waveform in a different color.
45 | */
46 | public class WaveformView extends View {
47 | public interface WaveformListener {
48 | public void waveformTouchStart(float x);
49 | public void waveformTouchMove(float x);
50 | public void waveformTouchEnd();
51 | public void waveformFling(float x);
52 | public void waveformDraw();
53 | public void waveformZoomIn();
54 | public void waveformZoomOut();
55 | };
56 |
57 | // Colors
58 | private Paint mGridPaint;
59 | private Paint mSelectedLinePaint;
60 | private Paint mUnselectedLinePaint;
61 | private Paint mUnselectedBkgndLinePaint;
62 | private Paint mBorderLinePaint;
63 | private Paint mPlaybackLinePaint;
64 | private Paint mTimecodePaint;
65 |
66 | private SoundFile mSoundFile;
67 | private int[] mLenByZoomLevel;
68 | private double[][] mValuesByZoomLevel;
69 | private double[] mZoomFactorByZoomLevel;
70 | private int[] mHeightsAtThisZoomLevel;
71 | private int mZoomLevel;
72 | private int mNumZoomLevels;
73 | private int mSampleRate;
74 | private int mSamplesPerFrame;
75 | private int mOffset;
76 | private int mSelectionStart;
77 | private int mSelectionEnd;
78 | private int mPlaybackPos;
79 | private float mDensity;
80 | private float mInitialScaleSpan;
81 | private WaveformListener mListener;
82 | private GestureDetector mGestureDetector;
83 | private ScaleGestureDetector mScaleGestureDetector;
84 | private boolean mInitialized;
85 |
86 | public WaveformView(Context context, AttributeSet attrs) {
87 | super(context, attrs);
88 |
89 | // We don't want keys, the markers get these
90 | setFocusable(false);
91 |
92 | Resources res = getResources();
93 | mGridPaint = new Paint();
94 | mGridPaint.setAntiAlias(false);
95 | mGridPaint.setColor(res.getColor(R.color.grid_line));
96 | mSelectedLinePaint = new Paint();
97 | mSelectedLinePaint.setAntiAlias(false);
98 | mSelectedLinePaint.setColor(res.getColor(R.color.waveform_selected));
99 | mUnselectedLinePaint = new Paint();
100 | mUnselectedLinePaint.setAntiAlias(false);
101 | mUnselectedLinePaint.setColor(res.getColor(R.color.waveform_unselected));
102 | mUnselectedBkgndLinePaint = new Paint();
103 | mUnselectedBkgndLinePaint.setAntiAlias(false);
104 | mUnselectedBkgndLinePaint.setColor(res.getColor(R.color.waveform_unselected_bkgnd_overlay));
105 | mBorderLinePaint = new Paint();
106 | mBorderLinePaint.setAntiAlias(true);
107 | mBorderLinePaint.setStrokeWidth(1.5f);
108 | mBorderLinePaint.setPathEffect(new DashPathEffect(new float[] { 3.0f, 2.0f }, 0.0f));
109 | mBorderLinePaint.setColor(res.getColor(R.color.selection_border));
110 | mPlaybackLinePaint = new Paint();
111 | mPlaybackLinePaint.setAntiAlias(false);
112 | mPlaybackLinePaint.setColor(res.getColor(R.color.playback_indicator));
113 | mTimecodePaint = new Paint();
114 | mTimecodePaint.setTextSize(12);
115 | mTimecodePaint.setAntiAlias(true);
116 | mTimecodePaint.setColor(res.getColor(R.color.timecode));
117 | mTimecodePaint.setShadowLayer(2, 1, 1, res.getColor(R.color.timecode_shadow));
118 |
119 | mGestureDetector = new GestureDetector(
120 | context,
121 | new GestureDetector.SimpleOnGestureListener() {
122 | public boolean onFling(MotionEvent e1, MotionEvent e2, float vx, float vy) {
123 | mListener.waveformFling(vx);
124 | return true;
125 | }
126 | }
127 | );
128 |
129 | mScaleGestureDetector = new ScaleGestureDetector(
130 | context,
131 | new ScaleGestureDetector.SimpleOnScaleGestureListener() {
132 | public boolean onScaleBegin(ScaleGestureDetector d) {
133 | Log.v("Ringdroid", "ScaleBegin " + d.getCurrentSpanX());
134 | mInitialScaleSpan = Math.abs(d.getCurrentSpanX());
135 | return true;
136 | }
137 | public boolean onScale(ScaleGestureDetector d) {
138 | float scale = Math.abs(d.getCurrentSpanX());
139 | Log.v("Ringdroid", "Scale " + (scale - mInitialScaleSpan));
140 | if (scale - mInitialScaleSpan > 40) {
141 | mListener.waveformZoomIn();
142 | mInitialScaleSpan = scale;
143 | }
144 | if (scale - mInitialScaleSpan < -40) {
145 | mListener.waveformZoomOut();
146 | mInitialScaleSpan = scale;
147 | }
148 | return true;
149 | }
150 | public void onScaleEnd(ScaleGestureDetector d) {
151 | Log.v("Ringdroid", "ScaleEnd " + d.getCurrentSpanX());
152 | }
153 | }
154 | );
155 |
156 | mSoundFile = null;
157 | mLenByZoomLevel = null;
158 | mValuesByZoomLevel = null;
159 | mHeightsAtThisZoomLevel = null;
160 | mOffset = 0;
161 | mPlaybackPos = -1;
162 | mSelectionStart = 0;
163 | mSelectionEnd = 0;
164 | mDensity = 1.0f;
165 | mInitialized = false;
166 | }
167 |
168 | @Override
169 | public boolean onTouchEvent(MotionEvent event) {
170 | mScaleGestureDetector.onTouchEvent(event);
171 | if (mGestureDetector.onTouchEvent(event)) {
172 | return true;
173 | }
174 |
175 | switch(event.getAction()) {
176 | case MotionEvent.ACTION_DOWN:
177 | mListener.waveformTouchStart(event.getX());
178 | break;
179 | case MotionEvent.ACTION_MOVE:
180 | mListener.waveformTouchMove(event.getX());
181 | break;
182 | case MotionEvent.ACTION_UP:
183 | mListener.waveformTouchEnd();
184 | break;
185 | }
186 | return true;
187 | }
188 |
189 | public boolean hasSoundFile() {
190 | return mSoundFile != null;
191 | }
192 |
193 | public void setSoundFile(SoundFile soundFile) {
194 | mSoundFile = soundFile;
195 | mSampleRate = mSoundFile.getSampleRate();
196 | mSamplesPerFrame = mSoundFile.getSamplesPerFrame();
197 | computeDoublesForAllZoomLevels();
198 | mHeightsAtThisZoomLevel = null;
199 | }
200 |
201 | public boolean isInitialized() {
202 | return mInitialized;
203 | }
204 |
205 | public int getZoomLevel() {
206 | return mZoomLevel;
207 | }
208 |
209 | public void setZoomLevel(int zoomLevel) {
210 | while (mZoomLevel > zoomLevel) {
211 | zoomIn();
212 | }
213 | while (mZoomLevel < zoomLevel) {
214 | zoomOut();
215 | }
216 | }
217 |
218 | public boolean canZoomIn() {
219 | return (mZoomLevel > 0);
220 | }
221 |
222 | public void zoomIn() {
223 | if (canZoomIn()) {
224 | mZoomLevel--;
225 | mSelectionStart *= 2;
226 | mSelectionEnd *= 2;
227 | mHeightsAtThisZoomLevel = null;
228 | int offsetCenter = mOffset + getMeasuredWidth() / 2;
229 | offsetCenter *= 2;
230 | mOffset = offsetCenter - getMeasuredWidth() / 2;
231 | if (mOffset < 0)
232 | mOffset = 0;
233 | invalidate();
234 | }
235 | }
236 |
237 | public boolean canZoomOut() {
238 | return (mZoomLevel < mNumZoomLevels - 1);
239 | }
240 |
241 | public void zoomOut() {
242 | if (canZoomOut()) {
243 | mZoomLevel++;
244 | mSelectionStart /= 2;
245 | mSelectionEnd /= 2;
246 | int offsetCenter = mOffset + getMeasuredWidth() / 2;
247 | offsetCenter /= 2;
248 | mOffset = offsetCenter - getMeasuredWidth() / 2;
249 | if (mOffset < 0)
250 | mOffset = 0;
251 | mHeightsAtThisZoomLevel = null;
252 | invalidate();
253 | }
254 | }
255 |
256 | public int maxPos() {
257 | return mLenByZoomLevel[mZoomLevel];
258 | }
259 |
260 | public int secondsToFrames(double seconds) {
261 | return (int)(1.0 * seconds * mSampleRate / mSamplesPerFrame + 0.5);
262 | }
263 |
264 | public int secondsToPixels(double seconds) {
265 | double z = mZoomFactorByZoomLevel[mZoomLevel];
266 | return (int)(z * seconds * mSampleRate / mSamplesPerFrame + 0.5);
267 | }
268 |
269 | public double pixelsToSeconds(int pixels) {
270 | double z = mZoomFactorByZoomLevel[mZoomLevel];
271 | return (pixels * (double)mSamplesPerFrame / (mSampleRate * z));
272 | }
273 |
274 | public int millisecsToPixels(int msecs) {
275 | double z = mZoomFactorByZoomLevel[mZoomLevel];
276 | return (int)((msecs * 1.0 * mSampleRate * z) /
277 | (1000.0 * mSamplesPerFrame) + 0.5);
278 | }
279 |
280 | public int pixelsToMillisecs(int pixels) {
281 | double z = mZoomFactorByZoomLevel[mZoomLevel];
282 | return (int)(pixels * (1000.0 * mSamplesPerFrame) /
283 | (mSampleRate * z) + 0.5);
284 | }
285 |
286 | public void setParameters(int start, int end, int offset) {
287 | mSelectionStart = start;
288 | mSelectionEnd = end;
289 | mOffset = offset;
290 | }
291 |
292 | public int getStart() {
293 | return mSelectionStart;
294 | }
295 |
296 | public int getEnd() {
297 | return mSelectionEnd;
298 | }
299 |
300 | public int getOffset() {
301 | return mOffset;
302 | }
303 |
304 | public void setPlayback(int pos) {
305 | mPlaybackPos = pos;
306 | }
307 |
308 | public void setListener(WaveformListener listener) {
309 | mListener = listener;
310 | }
311 |
312 | public void recomputeHeights(float density) {
313 | mHeightsAtThisZoomLevel = null;
314 | mDensity = density;
315 | mTimecodePaint.setTextSize((int)(12 * density));
316 |
317 | invalidate();
318 | }
319 |
320 | protected void drawWaveformLine(Canvas canvas,
321 | int x, int y0, int y1,
322 | Paint paint) {
323 | canvas.drawLine(x, y0, x, y1, paint);
324 | }
325 |
326 | @Override
327 | protected void onDraw(Canvas canvas) {
328 | super.onDraw(canvas);
329 | if (mSoundFile == null)
330 | return;
331 |
332 | if (mHeightsAtThisZoomLevel == null)
333 | computeIntsForThisZoomLevel();
334 |
335 | // Draw waveform
336 | int measuredWidth = getMeasuredWidth();
337 | int measuredHeight = getMeasuredHeight();
338 | int start = mOffset;
339 | int width = mHeightsAtThisZoomLevel.length - start;
340 | int ctr = measuredHeight / 2;
341 |
342 | if (width > measuredWidth)
343 | width = measuredWidth;
344 |
345 | // Draw grid
346 | double onePixelInSecs = pixelsToSeconds(1);
347 | boolean onlyEveryFiveSecs = (onePixelInSecs > 1.0 / 50.0);
348 | double fractionalSecs = mOffset * onePixelInSecs;
349 | int integerSecs = (int) fractionalSecs;
350 | int i = 0;
351 | while (i < width) {
352 | i++;
353 | fractionalSecs += onePixelInSecs;
354 | int integerSecsNew = (int) fractionalSecs;
355 | if (integerSecsNew != integerSecs) {
356 | integerSecs = integerSecsNew;
357 | if (!onlyEveryFiveSecs || 0 == (integerSecs % 5)) {
358 | canvas.drawLine(i, 0, i, measuredHeight, mGridPaint);
359 | }
360 | }
361 | }
362 |
363 | // Draw waveform
364 | for (i = 0; i < width; i++) {
365 | Paint paint;
366 | if (i + start >= mSelectionStart &&
367 | i + start < mSelectionEnd) {
368 | paint = mSelectedLinePaint;
369 | } else {
370 | drawWaveformLine(canvas, i, 0, measuredHeight,
371 | mUnselectedBkgndLinePaint);
372 | paint = mUnselectedLinePaint;
373 | }
374 | drawWaveformLine(
375 | canvas, i,
376 | ctr - mHeightsAtThisZoomLevel[start + i],
377 | ctr + 1 + mHeightsAtThisZoomLevel[start + i],
378 | paint);
379 |
380 | if (i + start == mPlaybackPos) {
381 | canvas.drawLine(i, 0, i, measuredHeight, mPlaybackLinePaint);
382 | }
383 | }
384 |
385 | // If we can see the right edge of the waveform, draw the
386 | // non-waveform area to the right as unselected
387 | for (i = width; i < measuredWidth; i++) {
388 | drawWaveformLine(canvas, i, 0, measuredHeight,
389 | mUnselectedBkgndLinePaint);
390 | }
391 |
392 | // Draw borders
393 | canvas.drawLine(
394 | mSelectionStart - mOffset + 0.5f, 30,
395 | mSelectionStart - mOffset + 0.5f, measuredHeight,
396 | mBorderLinePaint);
397 | canvas.drawLine(
398 | mSelectionEnd - mOffset + 0.5f, 0,
399 | mSelectionEnd - mOffset + 0.5f, measuredHeight - 30,
400 | mBorderLinePaint);
401 |
402 | // Draw timecode
403 | double timecodeIntervalSecs = 1.0;
404 | if (timecodeIntervalSecs / onePixelInSecs < 50) {
405 | timecodeIntervalSecs = 5.0;
406 | }
407 | if (timecodeIntervalSecs / onePixelInSecs < 50) {
408 | timecodeIntervalSecs = 15.0;
409 | }
410 |
411 | // Draw grid
412 | fractionalSecs = mOffset * onePixelInSecs;
413 | int integerTimecode = (int) (fractionalSecs / timecodeIntervalSecs);
414 | i = 0;
415 | while (i < width) {
416 | i++;
417 | fractionalSecs += onePixelInSecs;
418 | integerSecs = (int) fractionalSecs;
419 | int integerTimecodeNew = (int) (fractionalSecs /
420 | timecodeIntervalSecs);
421 | if (integerTimecodeNew != integerTimecode) {
422 | integerTimecode = integerTimecodeNew;
423 |
424 | // Turn, e.g. 67 seconds into "1:07"
425 | String timecodeMinutes = "" + (integerSecs / 60);
426 | String timecodeSeconds = "" + (integerSecs % 60);
427 | if ((integerSecs % 60) < 10) {
428 | timecodeSeconds = "0" + timecodeSeconds;
429 | }
430 | String timecodeStr = timecodeMinutes + ":" + timecodeSeconds;
431 | float offset = (float) (
432 | 0.5 * mTimecodePaint.measureText(timecodeStr));
433 | canvas.drawText(timecodeStr,
434 | i - offset,
435 | (int)(12 * mDensity),
436 | mTimecodePaint);
437 | }
438 | }
439 |
440 | if (mListener != null) {
441 | mListener.waveformDraw();
442 | }
443 | }
444 |
445 | /**
446 | * Called once when a new sound file is added
447 | */
448 | private void computeDoublesForAllZoomLevels() {
449 | int numFrames = mSoundFile.getNumFrames();
450 | int[] frameGains = mSoundFile.getFrameGains();
451 | double[] smoothedGains = new double[numFrames];
452 | if (numFrames == 1) {
453 | smoothedGains[0] = frameGains[0];
454 | } else if (numFrames == 2) {
455 | smoothedGains[0] = frameGains[0];
456 | smoothedGains[1] = frameGains[1];
457 | } else if (numFrames > 2) {
458 | smoothedGains[0] = (double)(
459 | (frameGains[0] / 2.0) +
460 | (frameGains[1] / 2.0));
461 | for (int i = 1; i < numFrames - 1; i++) {
462 | smoothedGains[i] = (double)(
463 | (frameGains[i - 1] / 3.0) +
464 | (frameGains[i ] / 3.0) +
465 | (frameGains[i + 1] / 3.0));
466 | }
467 | smoothedGains[numFrames - 1] = (double)(
468 | (frameGains[numFrames - 2] / 2.0) +
469 | (frameGains[numFrames - 1] / 2.0));
470 | }
471 |
472 | // Make sure the range is no more than 0 - 255
473 | double maxGain = 1.0;
474 | for (int i = 0; i < numFrames; i++) {
475 | if (smoothedGains[i] > maxGain) {
476 | maxGain = smoothedGains[i];
477 | }
478 | }
479 | double scaleFactor = 1.0;
480 | if (maxGain > 255.0) {
481 | scaleFactor = 255 / maxGain;
482 | }
483 |
484 | // Build histogram of 256 bins and figure out the new scaled max
485 | maxGain = 0;
486 | int gainHist[] = new int[256];
487 | for (int i = 0; i < numFrames; i++) {
488 | int smoothedGain = (int)(smoothedGains[i] * scaleFactor);
489 | if (smoothedGain < 0)
490 | smoothedGain = 0;
491 | if (smoothedGain > 255)
492 | smoothedGain = 255;
493 |
494 | if (smoothedGain > maxGain)
495 | maxGain = smoothedGain;
496 |
497 | gainHist[smoothedGain]++;
498 | }
499 |
500 | // Re-calibrate the min to be 5%
501 | double minGain = 0;
502 | int sum = 0;
503 | while (minGain < 255 && sum < numFrames / 20) {
504 | sum += gainHist[(int)minGain];
505 | minGain++;
506 | }
507 |
508 | // Re-calibrate the max to be 99%
509 | sum = 0;
510 | while (maxGain > 2 && sum < numFrames / 100) {
511 | sum += gainHist[(int)maxGain];
512 | maxGain--;
513 | }
514 |
515 | // Compute the heights
516 | double[] heights = new double[numFrames];
517 | double range = maxGain - minGain;
518 | for (int i = 0; i < numFrames; i++) {
519 | double value = (smoothedGains[i] * scaleFactor - minGain) / range;
520 | if (value < 0.0)
521 | value = 0.0;
522 | if (value > 1.0)
523 | value = 1.0;
524 | heights[i] = value * value;
525 | }
526 |
527 | mNumZoomLevels = 5;
528 | mLenByZoomLevel = new int[5];
529 | mZoomFactorByZoomLevel = new double[5];
530 | mValuesByZoomLevel = new double[5][];
531 |
532 | // Level 0 is doubled, with interpolated values
533 | mLenByZoomLevel[0] = numFrames * 2;
534 | mZoomFactorByZoomLevel[0] = 2.0;
535 | mValuesByZoomLevel[0] = new double[mLenByZoomLevel[0]];
536 | if (numFrames > 0) {
537 | mValuesByZoomLevel[0][0] = 0.5 * heights[0];
538 | mValuesByZoomLevel[0][1] = heights[0];
539 | }
540 | for (int i = 1; i < numFrames; i++) {
541 | mValuesByZoomLevel[0][2 * i] = 0.5 * (heights[i - 1] + heights[i]);
542 | mValuesByZoomLevel[0][2 * i + 1] = heights[i];
543 | }
544 |
545 | // Level 1 is normal
546 | mLenByZoomLevel[1] = numFrames;
547 | mValuesByZoomLevel[1] = new double[mLenByZoomLevel[1]];
548 | mZoomFactorByZoomLevel[1] = 1.0;
549 | for (int i = 0; i < mLenByZoomLevel[1]; i++) {
550 | mValuesByZoomLevel[1][i] = heights[i];
551 | }
552 |
553 | // 3 more levels are each halved
554 | for (int j = 2; j < 5; j++) {
555 | mLenByZoomLevel[j] = mLenByZoomLevel[j - 1] / 2;
556 | mValuesByZoomLevel[j] = new double[mLenByZoomLevel[j]];
557 | mZoomFactorByZoomLevel[j] = mZoomFactorByZoomLevel[j - 1] / 2.0;
558 | for (int i = 0; i < mLenByZoomLevel[j]; i++) {
559 | mValuesByZoomLevel[j][i] =
560 | 0.5 * (mValuesByZoomLevel[j - 1][2 * i] +
561 | mValuesByZoomLevel[j - 1][2 * i + 1]);
562 | }
563 | }
564 |
565 | if (numFrames > 5000) {
566 | mZoomLevel = 3;
567 | } else if (numFrames > 1000) {
568 | mZoomLevel = 2;
569 | } else if (numFrames > 300) {
570 | mZoomLevel = 1;
571 | } else {
572 | mZoomLevel = 0;
573 | }
574 |
575 | mInitialized = true;
576 | }
577 |
578 | /**
579 | * Called the first time we need to draw when the zoom level has changed
580 | * or the screen is resized
581 | */
582 | private void computeIntsForThisZoomLevel() {
583 | int halfHeight = (getMeasuredHeight() / 2) - 1;
584 | mHeightsAtThisZoomLevel = new int[mLenByZoomLevel[mZoomLevel]];
585 | for (int i = 0; i < mLenByZoomLevel[mZoomLevel]; i++) {
586 | mHeightsAtThisZoomLevel[i] =
587 | (int)(mValuesByZoomLevel[mZoomLevel][i] * halfHeight);
588 | }
589 | }
590 | }
591 |
--------------------------------------------------------------------------------