├── app
├── .gitignore
├── src
│ ├── main
│ │ ├── res
│ │ │ ├── mipmap-hdpi
│ │ │ │ └── ic_launcher.png
│ │ │ ├── mipmap-mdpi
│ │ │ │ └── ic_launcher.png
│ │ │ ├── mipmap-xhdpi
│ │ │ │ └── ic_launcher.png
│ │ │ ├── mipmap-xxhdpi
│ │ │ │ └── ic_launcher.png
│ │ │ ├── mipmap-xxxhdpi
│ │ │ │ └── ic_launcher.png
│ │ │ ├── drawable-hdpi
│ │ │ │ ├── ic_info_black_24dp.png
│ │ │ │ ├── ic_sync_black_24dp.png
│ │ │ │ ├── ic_settings_white_24dp.png
│ │ │ │ └── ic_equalizer_white_24dp.png
│ │ │ ├── drawable-mdpi
│ │ │ │ ├── ic_info_black_24dp.png
│ │ │ │ ├── ic_sync_black_24dp.png
│ │ │ │ ├── ic_settings_white_24dp.png
│ │ │ │ └── ic_equalizer_white_24dp.png
│ │ │ ├── drawable-xhdpi
│ │ │ │ ├── ic_info_black_24dp.png
│ │ │ │ ├── ic_sync_black_24dp.png
│ │ │ │ ├── ic_equalizer_white_24dp.png
│ │ │ │ └── ic_settings_white_24dp.png
│ │ │ ├── drawable-xxhdpi
│ │ │ │ ├── ic_info_black_24dp.png
│ │ │ │ ├── ic_sync_black_24dp.png
│ │ │ │ ├── ic_settings_white_24dp.png
│ │ │ │ └── ic_equalizer_white_24dp.png
│ │ │ ├── drawable-xxxhdpi
│ │ │ │ ├── ic_info_black_24dp.png
│ │ │ │ ├── ic_sync_black_24dp.png
│ │ │ │ ├── ic_equalizer_white_24dp.png
│ │ │ │ └── ic_settings_white_24dp.png
│ │ │ ├── layout
│ │ │ │ ├── spinner_item.xml
│ │ │ │ ├── spinner_dropdown_item.xml
│ │ │ │ ├── equalizer_channel.xml
│ │ │ │ ├── activity_equalizer.xml
│ │ │ │ ├── content_main.xml
│ │ │ │ ├── activity_main.xml
│ │ │ │ ├── control_channel.xml
│ │ │ │ ├── equalizer_row.xml
│ │ │ │ └── control_row.xml
│ │ │ ├── xml
│ │ │ │ ├── pref_about.xml
│ │ │ │ ├── pref_headers.xml
│ │ │ │ └── pref_connection.xml
│ │ │ ├── values-w820dp
│ │ │ │ └── dimens.xml
│ │ │ ├── values
│ │ │ │ ├── colors.xml
│ │ │ │ ├── dimens.xml
│ │ │ │ ├── styles.xml
│ │ │ │ └── strings.xml
│ │ │ ├── drawable-v21
│ │ │ │ ├── ic_equalizer_white_24dp.xml
│ │ │ │ ├── ic_info_black_24dp.xml
│ │ │ │ ├── ic_sync_black_24dp.xml
│ │ │ │ └── ic_settings_white_24dp.xml
│ │ │ ├── values-v21
│ │ │ │ └── styles.xml
│ │ │ ├── menu
│ │ │ │ ├── menu_equalizer.xml
│ │ │ │ └── menu_main.xml
│ │ │ ├── layout-land
│ │ │ │ ├── equalizer_channel.xml
│ │ │ │ ├── activity_equalizer.xml
│ │ │ │ └── equalizer_row.xml
│ │ │ ├── values-cs
│ │ │ │ └── strings.xml
│ │ │ └── values-nl
│ │ │ │ └── strings.xml
│ │ ├── java
│ │ │ └── cz
│ │ │ │ └── jiriskorpil
│ │ │ │ └── amixerwebui
│ │ │ │ ├── control
│ │ │ │ ├── IBooleanControl.java
│ │ │ │ ├── InterfaceType.java
│ │ │ │ ├── IEnumeratedControl.java
│ │ │ │ ├── ControlType.java
│ │ │ │ ├── IControl.java
│ │ │ │ ├── IChannel.java
│ │ │ │ ├── IIntegerControl.java
│ │ │ │ ├── mixer
│ │ │ │ │ ├── MixerControl.java
│ │ │ │ │ ├── BooleanControl.java
│ │ │ │ │ ├── Channel.java
│ │ │ │ │ ├── MixerControlFactory.java
│ │ │ │ │ ├── EnumeratedControl.java
│ │ │ │ │ └── IntegerControl.java
│ │ │ │ ├── ControlContainerType.java
│ │ │ │ ├── ControlFactory.java
│ │ │ │ ├── Control.java
│ │ │ │ ├── Equalizer.java
│ │ │ │ ├── ControlParser.java
│ │ │ │ ├── ControlContainer.java
│ │ │ │ ├── EqualizerAdapter.java
│ │ │ │ └── ControlContainerAdapter.java
│ │ │ │ ├── task
│ │ │ │ ├── RetrieveCardHttpRequestTask.java
│ │ │ │ ├── ChangeSourceHttpRequestTask.java
│ │ │ │ ├── RetrieveHostnameHttpRequestTask.java
│ │ │ │ ├── ToggleControlHttpRequestTask.java
│ │ │ │ ├── RetrieveEqualizerHttpRequestTask.java
│ │ │ │ ├── RetrieveCardsHttpRequestTask.java
│ │ │ │ ├── ChangeVolumeHttpRequestTask.java
│ │ │ │ ├── RetrieveControlsHttpRequestTask.java
│ │ │ │ ├── ChangeCardHttpRequestTask.java
│ │ │ │ ├── ChangeEqualizerHttpRequestTask.java
│ │ │ │ └── AsyncHttpRequestTask.java
│ │ │ │ └── activity
│ │ │ │ ├── AppCompatPreferenceActivity.java
│ │ │ │ ├── EqualizerActivity.java
│ │ │ │ ├── MainActivity.java
│ │ │ │ ├── SettingsActivity.java
│ │ │ │ └── DataHandler.java
│ │ └── AndroidManifest.xml
│ ├── test
│ │ └── java
│ │ │ └── cz
│ │ │ └── jiriskorpil
│ │ │ └── amixerwebui
│ │ │ └── ExampleUnitTest.java
│ └── androidTest
│ │ └── java
│ │ └── cz
│ │ └── jiriskorpil
│ │ └── amixerwebui
│ │ └── ApplicationTest.java
├── proguard-rules.pro
└── build.gradle
├── settings.gradle
├── screenshot.png
├── .gitignore
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradle.properties
├── LICENSE
├── README.md
├── gradlew.bat
└── gradlew
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app'
2 |
--------------------------------------------------------------------------------
/screenshot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JiriSko/amixer-webui-android/HEAD/screenshot.png
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | *.iml
2 | .gradle
3 | /local.properties
4 | /.idea
5 | .DS_Store
6 | /build
7 | /captures
8 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JiriSko/amixer-webui-android/HEAD/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JiriSko/amixer-webui-android/HEAD/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JiriSko/amixer-webui-android/HEAD/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JiriSko/amixer-webui-android/HEAD/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JiriSko/amixer-webui-android/HEAD/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JiriSko/amixer-webui-android/HEAD/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/ic_info_black_24dp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JiriSko/amixer-webui-android/HEAD/app/src/main/res/drawable-hdpi/ic_info_black_24dp.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/ic_sync_black_24dp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JiriSko/amixer-webui-android/HEAD/app/src/main/res/drawable-hdpi/ic_sync_black_24dp.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-mdpi/ic_info_black_24dp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JiriSko/amixer-webui-android/HEAD/app/src/main/res/drawable-mdpi/ic_info_black_24dp.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-mdpi/ic_sync_black_24dp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JiriSko/amixer-webui-android/HEAD/app/src/main/res/drawable-mdpi/ic_sync_black_24dp.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/ic_info_black_24dp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JiriSko/amixer-webui-android/HEAD/app/src/main/res/drawable-xhdpi/ic_info_black_24dp.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/ic_sync_black_24dp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JiriSko/amixer-webui-android/HEAD/app/src/main/res/drawable-xhdpi/ic_sync_black_24dp.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/ic_settings_white_24dp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JiriSko/amixer-webui-android/HEAD/app/src/main/res/drawable-hdpi/ic_settings_white_24dp.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-mdpi/ic_settings_white_24dp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JiriSko/amixer-webui-android/HEAD/app/src/main/res/drawable-mdpi/ic_settings_white_24dp.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/ic_info_black_24dp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JiriSko/amixer-webui-android/HEAD/app/src/main/res/drawable-xxhdpi/ic_info_black_24dp.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/ic_sync_black_24dp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JiriSko/amixer-webui-android/HEAD/app/src/main/res/drawable-xxhdpi/ic_sync_black_24dp.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxxhdpi/ic_info_black_24dp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JiriSko/amixer-webui-android/HEAD/app/src/main/res/drawable-xxxhdpi/ic_info_black_24dp.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxxhdpi/ic_sync_black_24dp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JiriSko/amixer-webui-android/HEAD/app/src/main/res/drawable-xxxhdpi/ic_sync_black_24dp.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/ic_equalizer_white_24dp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JiriSko/amixer-webui-android/HEAD/app/src/main/res/drawable-hdpi/ic_equalizer_white_24dp.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-mdpi/ic_equalizer_white_24dp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JiriSko/amixer-webui-android/HEAD/app/src/main/res/drawable-mdpi/ic_equalizer_white_24dp.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/ic_equalizer_white_24dp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JiriSko/amixer-webui-android/HEAD/app/src/main/res/drawable-xhdpi/ic_equalizer_white_24dp.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/ic_settings_white_24dp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JiriSko/amixer-webui-android/HEAD/app/src/main/res/drawable-xhdpi/ic_settings_white_24dp.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/ic_settings_white_24dp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JiriSko/amixer-webui-android/HEAD/app/src/main/res/drawable-xxhdpi/ic_settings_white_24dp.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/ic_equalizer_white_24dp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JiriSko/amixer-webui-android/HEAD/app/src/main/res/drawable-xxhdpi/ic_equalizer_white_24dp.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxxhdpi/ic_equalizer_white_24dp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JiriSko/amixer-webui-android/HEAD/app/src/main/res/drawable-xxxhdpi/ic_equalizer_white_24dp.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxxhdpi/ic_settings_white_24dp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JiriSko/amixer-webui-android/HEAD/app/src/main/res/drawable-xxxhdpi/ic_settings_white_24dp.png
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Fri May 04 17:37:41 CEST 2018
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip
7 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/spinner_item.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/xml/pref_about.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
7 |
8 |
11 |
12 |
--------------------------------------------------------------------------------
/app/src/main/res/values-w820dp/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 64dp
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #009688
4 | #00796A
5 | #80CBC4
6 | #009688
7 | #006064
8 | #F5F5F5
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable-v21/ic_equalizer_white_24dp.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/values-v21/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable-v21/ic_info_black_24dp.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/test/java/cz/jiriskorpil/amixerwebui/ExampleUnitTest.java:
--------------------------------------------------------------------------------
1 | package cz.jiriskorpil.amixerwebui;
2 |
3 | import org.junit.Test;
4 |
5 | import static org.junit.Assert.assertEquals;
6 |
7 | /**
8 | * To work on unit tests, switch the Test Artifact in the Build Variants view.
9 | */
10 | public class ExampleUnitTest {
11 | @Test
12 | public void additionIsCorrect() throws Exception {
13 | assertEquals(4, 2 + 2);
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/app/src/androidTest/java/cz/jiriskorpil/amixerwebui/ApplicationTest.java:
--------------------------------------------------------------------------------
1 | package cz.jiriskorpil.amixerwebui;
2 |
3 | import android.app.Application;
4 | import android.test.ApplicationTestCase;
5 |
6 | /**
7 | * Testing Fundamentals
8 | */
9 | public class ApplicationTest extends ApplicationTestCase {
10 | public ApplicationTest() {
11 | super(Application.class);
12 | }
13 | }
--------------------------------------------------------------------------------
/app/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 16dp
4 | 16dp
5 | 16dp
6 |
7 | 4dp
8 | 8dp
9 | 8dp
10 | 4dp
11 |
12 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/menu_equalizer.xml:
--------------------------------------------------------------------------------
1 |
2 |
14 |
--------------------------------------------------------------------------------
/app/src/main/java/cz/jiriskorpil/amixerwebui/control/IBooleanControl.java:
--------------------------------------------------------------------------------
1 | package cz.jiriskorpil.amixerwebui.control;
2 |
3 | /**
4 | * Interface for representing boolean control (on/off)
5 | */
6 | public interface IBooleanControl extends IControl
7 | {
8 | /**
9 | * Checks whether control is active.
10 | *
11 | * @return true if control is active
12 | */
13 | boolean isChecked();
14 |
15 | /**
16 | * Sets control value.
17 | *
18 | * @param value true if control should be active
19 | */
20 | void setChecked(boolean value);
21 | }
22 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/spinner_dropdown_item.xml:
--------------------------------------------------------------------------------
1 |
2 |
12 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable-v21/ic_sync_black_24dp.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/equalizer_channel.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
13 |
14 |
--------------------------------------------------------------------------------
/app/src/main/java/cz/jiriskorpil/amixerwebui/control/InterfaceType.java:
--------------------------------------------------------------------------------
1 | package cz.jiriskorpil.amixerwebui.control;
2 |
3 | /**
4 | * Interface types.
5 | */
6 | public enum InterfaceType
7 | {
8 | MIXER,
9 | PCM,
10 | UNKNOWN;
11 |
12 | /**
13 | * Converts string to interface type.
14 | *
15 | * @param iface interface type as string
16 | * @return interface type
17 | */
18 | public static InterfaceType fromString(String iface)
19 | {
20 | switch (iface)
21 | {
22 | case "MIXER":
23 | return MIXER;
24 | case "PCM":
25 | return PCM;
26 | default:
27 | return UNKNOWN;
28 | }
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/app/src/main/res/xml/pref_headers.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
9 |
10 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/app/src/main/java/cz/jiriskorpil/amixerwebui/control/IEnumeratedControl.java:
--------------------------------------------------------------------------------
1 | package cz.jiriskorpil.amixerwebui.control;
2 |
3 | /**
4 | * Interface for representing enumerated control (select one from many).
5 | */
6 | public interface IEnumeratedControl extends IControl
7 | {
8 | /**
9 | * Returns array of items names.
10 | *
11 | * @return array of names
12 | */
13 | String[] getItems();
14 |
15 | /**
16 | * Returns index of currently active item.
17 | *
18 | * @return active item index
19 | */
20 | int getValue();
21 |
22 | /**
23 | * Sets index of active item.
24 | *
25 | * @param index active item index
26 | */
27 | void setValue(int index);
28 | }
29 |
--------------------------------------------------------------------------------
/app/src/main/java/cz/jiriskorpil/amixerwebui/control/ControlType.java:
--------------------------------------------------------------------------------
1 | package cz.jiriskorpil.amixerwebui.control;
2 |
3 | /**
4 | * Control types.
5 | */
6 | public enum ControlType
7 | {
8 | ENUMERATED,
9 | BOOLEAN,
10 | INTEGER,
11 | UNKNOWN;
12 |
13 | /**
14 | * Converts string to control type.
15 | *
16 | * @param type control type as string
17 | * @return control type
18 | */
19 | public static ControlType fromString(String type)
20 | {
21 | switch (type)
22 | {
23 | case "ENUMERATED":
24 | return ENUMERATED;
25 | case "BOOLEAN":
26 | return BOOLEAN;
27 | case "INTEGER":
28 | return INTEGER;
29 | default:
30 | return UNKNOWN;
31 | }
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/app/src/main/java/cz/jiriskorpil/amixerwebui/control/IControl.java:
--------------------------------------------------------------------------------
1 | package cz.jiriskorpil.amixerwebui.control;
2 |
3 | /**
4 | * Interface for representing base control.
5 | */
6 | public interface IControl
7 | {
8 | /**
9 | * Returns control identifier.
10 | *
11 | * @return identifier
12 | */
13 | int getId();
14 |
15 | /**
16 | * Returns interface type.
17 | *
18 | * @return type of interface
19 | */
20 | InterfaceType getIface();
21 |
22 | /**
23 | * Returns access string for control.
24 | *
25 | * @return access string
26 | */
27 | String getAccess();
28 |
29 | /**
30 | * Returns control name.
31 | *
32 | * @return name
33 | */
34 | String getName();
35 | }
36 |
--------------------------------------------------------------------------------
/app/src/main/java/cz/jiriskorpil/amixerwebui/control/IChannel.java:
--------------------------------------------------------------------------------
1 | package cz.jiriskorpil.amixerwebui.control;
2 |
3 | /**
4 | * Interface for representing one channel in integer control.
5 | */
6 | public interface IChannel
7 | {
8 | /**
9 | * Returns parent integer control.
10 | *
11 | * @return parent control
12 | */
13 | IIntegerControl getControl();
14 |
15 | /**
16 | * Returns channel name.
17 | *
18 | * @return name
19 | */
20 | String getName();
21 |
22 | /**
23 | * Returns channel value.
24 | *
25 | * @return value
26 | */
27 | int getValue();
28 |
29 | /**
30 | * Sets channel value.
31 | *
32 | * @param value channel value
33 | */
34 | void setValue(int value);
35 | }
36 |
--------------------------------------------------------------------------------
/app/src/main/java/cz/jiriskorpil/amixerwebui/task/RetrieveCardHttpRequestTask.java:
--------------------------------------------------------------------------------
1 | package cz.jiriskorpil.amixerwebui.task;
2 |
3 | import android.content.Context;
4 |
5 | /**
6 | * Asynchronous task for retrieving active sound card from server.
7 | */
8 | public class RetrieveCardHttpRequestTask extends AsyncHttpRequestTask
9 | {
10 | public RetrieveCardHttpRequestTask(Context context, String url, OnFinishListener listener)
11 | {
12 | super(context, url);
13 | this.mOnFinishListener = listener;
14 | }
15 |
16 | /**
17 | * {@inheritDoc}
18 | * Retrieves active sound card from server.
19 | */
20 | @Override
21 | protected String doInBackground(String... params)
22 | {
23 | return downloadFromURL("/card/");
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # By default, the flags in this file are appended to flags specified
3 | # in C:\Users\jiris\AppData\Local\Android\sdk/tools/proguard/proguard-android.txt
4 | # You can edit the include path and order by changing the proguardFiles
5 | # directive in build.gradle.
6 | #
7 | # For more details, see
8 | # http://developer.android.com/guide/developing/tools/proguard.html
9 |
10 | # Add any project specific keep options here:
11 |
12 | # If your project uses WebView with JS, uncomment the following
13 | # and specify the fully qualified class name to the JavaScript interface
14 | # class:
15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
16 | # public *;
17 | #}
18 |
--------------------------------------------------------------------------------
/app/src/main/java/cz/jiriskorpil/amixerwebui/control/IIntegerControl.java:
--------------------------------------------------------------------------------
1 | package cz.jiriskorpil.amixerwebui.control;
2 |
3 | /**
4 | * Interface for representing integer control (common volume slider).
5 | */
6 | public interface IIntegerControl extends IControl
7 | {
8 | /**
9 | * Returns array of volume channels.
10 | *
11 | * @return array of volume channels
12 | */
13 | IChannel[] getChannels();
14 |
15 | /**
16 | * Returns volume slider maximum.
17 | *
18 | * @return slider minimum
19 | */
20 | int getMin();
21 |
22 | /**
23 | * Returns volume slider maximum value.
24 | *
25 | * @return slider maximum
26 | */
27 | int getMax();
28 |
29 | /**
30 | * Returns volume slider step.
31 | *
32 | * @return slider step
33 | */
34 | int getStep();
35 | }
36 |
--------------------------------------------------------------------------------
/app/src/main/java/cz/jiriskorpil/amixerwebui/task/ChangeSourceHttpRequestTask.java:
--------------------------------------------------------------------------------
1 | package cz.jiriskorpil.amixerwebui.task;
2 |
3 | import android.content.Context;
4 |
5 | /**
6 | * Asynchronous task for sending request to change source of specific control.
7 | */
8 | public class ChangeSourceHttpRequestTask extends AsyncHttpRequestTask
9 | {
10 | public ChangeSourceHttpRequestTask(Context context, String url)
11 | {
12 | super(context, url);
13 | }
14 |
15 | /**
16 | * {@inheritDoc}
17 | * Sends request to change source.
18 | *
19 | * @param params first parameter is control id,
20 | * second parameter is new source
21 | */
22 | @Override
23 | protected String doInBackground(String... params)
24 | {
25 | return downloadFromURL("/source/" + params[0] + "/" + params[1] + "/", "PUT");
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/app/src/main/java/cz/jiriskorpil/amixerwebui/task/RetrieveHostnameHttpRequestTask.java:
--------------------------------------------------------------------------------
1 | package cz.jiriskorpil.amixerwebui.task;
2 |
3 | import android.content.Context;
4 |
5 | /**
6 | * Asynchronous task for retrieving server's hostname.
7 | */
8 | public class RetrieveHostnameHttpRequestTask extends AsyncHttpRequestTask
9 | {
10 | public RetrieveHostnameHttpRequestTask(Context context, String url)
11 | {
12 | super(context, url);
13 | }
14 |
15 | public RetrieveHostnameHttpRequestTask(Context context, String url, OnFinishListener listener)
16 | {
17 | this(context, url);
18 | this.mOnFinishListener = listener;
19 | }
20 |
21 | /**
22 | * {@inheritDoc}
23 | * Retrieves server's hostname.
24 | */
25 | @Override
26 | protected String doInBackground(String... params)
27 | {
28 | return downloadFromURL("/hostname/");
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
11 |
15 |
16 |
17 |
18 |
19 |
20 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/app/src/main/java/cz/jiriskorpil/amixerwebui/task/ToggleControlHttpRequestTask.java:
--------------------------------------------------------------------------------
1 | package cz.jiriskorpil.amixerwebui.task;
2 |
3 | import android.content.Context;
4 |
5 | /**
6 | * Asynchronous task for sending request to turn on/off specific control.
7 | */
8 | public class ToggleControlHttpRequestTask extends AsyncHttpRequestTask
9 | {
10 | public ToggleControlHttpRequestTask(Context context, String url)
11 | {
12 | super(context, url);
13 | }
14 |
15 | /**
16 | * {@inheritDoc}
17 | * Sends request to turn on/off.
18 | *
19 | * @param params first parameter is control id,
20 | * second parameter is value (0 to turn off, 1 to turn on)
21 | */
22 | @Override
23 | protected String doInBackground(String... params)
24 | {
25 | return downloadFromURL("/control/" + params[0] + "/" + params[1] + "/", "PUT");
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/app/src/main/res/xml/pref_connection.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
13 |
14 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/app/src/main/java/cz/jiriskorpil/amixerwebui/task/RetrieveEqualizerHttpRequestTask.java:
--------------------------------------------------------------------------------
1 | package cz.jiriskorpil.amixerwebui.task;
2 |
3 | import android.content.Context;
4 |
5 | /**
6 | * Asynchronous task for retrieving equalizer from server.
7 | */
8 | public class RetrieveEqualizerHttpRequestTask extends AsyncHttpRequestTask
9 | {
10 | public RetrieveEqualizerHttpRequestTask(Context context, String url)
11 | {
12 | super(context, url);
13 | }
14 |
15 | public RetrieveEqualizerHttpRequestTask(Context context, String url, OnFinishListener listener)
16 | {
17 | this(context, url);
18 | this.mOnFinishListener = listener;
19 | }
20 |
21 | /**
22 | * {@inheritDoc}
23 | * Retrieves controls from server.
24 | */
25 | @Override
26 | protected String doInBackground(String... params)
27 | {
28 | return downloadFromURL("/equalizer/");
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/app/src/main/java/cz/jiriskorpil/amixerwebui/task/RetrieveCardsHttpRequestTask.java:
--------------------------------------------------------------------------------
1 | package cz.jiriskorpil.amixerwebui.task;
2 |
3 | import android.content.Context;
4 |
5 | /**
6 | * Asynchronous task for retrieving available sound cards from server.
7 | */
8 | public class RetrieveCardsHttpRequestTask extends AsyncHttpRequestTask
9 | {
10 | public RetrieveCardsHttpRequestTask(Context context, String url)
11 | {
12 | super(context, url);
13 | }
14 |
15 | public RetrieveCardsHttpRequestTask(Context context, String url, OnFinishListener listener)
16 | {
17 | this(context, url);
18 | this.mOnFinishListener = listener;
19 | }
20 |
21 | /**
22 | * {@inheritDoc}
23 | * Retrieves available sound cards from server.
24 | */
25 | @Override
26 | protected String doInBackground(String... params)
27 | {
28 | return downloadFromURL("/cards/");
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/app/src/main/java/cz/jiriskorpil/amixerwebui/task/ChangeVolumeHttpRequestTask.java:
--------------------------------------------------------------------------------
1 | package cz.jiriskorpil.amixerwebui.task;
2 |
3 | import android.content.Context;
4 |
5 | /**
6 | * Asynchronous task for sending request to change volumes of specific control.
7 | */
8 | public class ChangeVolumeHttpRequestTask extends AsyncHttpRequestTask
9 | {
10 | public ChangeVolumeHttpRequestTask(Context context, String url)
11 | {
12 | super(context, url);
13 | }
14 |
15 | /**
16 | * {@inheritDoc}
17 | * Sends request to change volumes.
18 | *
19 | * @param params first parameters is control id,
20 | * second parameter is new set of volumes [in form: (/)*, e.g. 50/40/60 ]
21 | */
22 | @Override
23 | protected String doInBackground(String... params)
24 | {
25 | return downloadFromURL("/volume/" + params[0] + "/" + params[1] + "/", "PUT");
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/app/src/main/java/cz/jiriskorpil/amixerwebui/task/RetrieveControlsHttpRequestTask.java:
--------------------------------------------------------------------------------
1 | package cz.jiriskorpil.amixerwebui.task;
2 |
3 | import android.content.Context;
4 |
5 | /**
6 | * Asynchronous task for retrieving controls from server while user is waiting on progress dialog.
7 | */
8 | public class RetrieveControlsHttpRequestTask extends AsyncHttpRequestTask
9 | {
10 | public RetrieveControlsHttpRequestTask(Context context, String url)
11 | {
12 | super(context, url);
13 | }
14 |
15 | public RetrieveControlsHttpRequestTask(Context context, String url, OnFinishListener listener)
16 | {
17 | this(context, url);
18 | this.mOnFinishListener = listener;
19 | }
20 |
21 | /**
22 | * {@inheritDoc}
23 | * Retrieves controls from server.
24 | */
25 | @Override
26 | protected String doInBackground(String... params)
27 | {
28 | return downloadFromURL("/controls/");
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/app/src/main/java/cz/jiriskorpil/amixerwebui/task/ChangeCardHttpRequestTask.java:
--------------------------------------------------------------------------------
1 | package cz.jiriskorpil.amixerwebui.task;
2 |
3 | import android.content.Context;
4 |
5 | /**
6 | * Asynchronous task for sending request to change sound card.
7 | */
8 | public class ChangeCardHttpRequestTask extends AsyncHttpRequestTask
9 | {
10 | public ChangeCardHttpRequestTask(Context context, String url)
11 | {
12 | super(context, url);
13 | }
14 |
15 | public ChangeCardHttpRequestTask(Context context, String url, OnFinishListener listener)
16 | {
17 | this(context, url);
18 | this.mOnFinishListener = listener;
19 | }
20 |
21 | /**
22 | * {@inheritDoc}
23 | * Sends request to change card.
24 | *
25 | * @param params first parameter is card id
26 | */
27 | @Override
28 | protected String doInBackground(String... params)
29 | {
30 | return downloadFromURL("/card/" + params[0] + "/", "PUT");
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/app/src/main/java/cz/jiriskorpil/amixerwebui/task/ChangeEqualizerHttpRequestTask.java:
--------------------------------------------------------------------------------
1 | package cz.jiriskorpil.amixerwebui.task;
2 |
3 | import android.content.Context;
4 |
5 | /**
6 | * Asynchronous task for sending request to change equalizer values of specific control.
7 | */
8 | public class ChangeEqualizerHttpRequestTask extends AsyncHttpRequestTask
9 | {
10 | public ChangeEqualizerHttpRequestTask(Context context, String url)
11 | {
12 | super(context, url);
13 | }
14 |
15 | /**
16 | * {@inheritDoc}
17 | * Sends request to change equalizer values.
18 | *
19 | * @param params first parameters is control id,
20 | * second parameter is new set of volumes [in form: (/)*, e.g. 50/40/60 ]
21 | */
22 | @Override
23 | protected String doInBackground(String... params)
24 | {
25 | return downloadFromURL("/equalizer/" + params[0] + "/" + params[1] + "/", "PUT");
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 |
3 | # IDE (e.g. Android Studio) users:
4 | # Gradle settings configured through the IDE *will override*
5 | # any settings specified in this file.
6 |
7 | # For more details on how to configure your build environment visit
8 | # http://www.gradle.org/docs/current/userguide/build_environment.html
9 |
10 | # Specifies the JVM arguments used for the daemon process.
11 | # The setting is particularly useful for tweaking memory settings.
12 | # Default value: -Xmx10248m -XX:MaxPermSize=256m
13 | # org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
14 |
15 | # When configured, Gradle will run in incubating parallel mode.
16 | # This option should only be used with decoupled projects. More details, visit
17 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
18 | # org.gradle.parallel=true
--------------------------------------------------------------------------------
/app/src/main/res/layout-land/equalizer_channel.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
12 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_equalizer.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
20 |
21 |
--------------------------------------------------------------------------------
/app/src/main/res/layout-land/activity_equalizer.xml:
--------------------------------------------------------------------------------
1 |
2 |
10 |
11 |
21 |
22 |
--------------------------------------------------------------------------------
/app/src/main/java/cz/jiriskorpil/amixerwebui/control/mixer/MixerControl.java:
--------------------------------------------------------------------------------
1 | package cz.jiriskorpil.amixerwebui.control.mixer;
2 |
3 | import org.json.JSONException;
4 | import org.json.JSONObject;
5 |
6 | import cz.jiriskorpil.amixerwebui.control.Control;
7 | import cz.jiriskorpil.amixerwebui.control.ControlType;
8 |
9 | /**
10 | * Represents mixer control.
11 | */
12 | public class MixerControl extends Control
13 | {
14 | private ControlType type;
15 |
16 | /**
17 | * Creates new instance of mixer control.
18 | *
19 | * @param jsonObject JSON object representing integer control retrieved from server
20 | * @throws JSONException
21 | */
22 | public MixerControl(JSONObject jsonObject) throws JSONException
23 | {
24 | super(jsonObject);
25 |
26 | type = ControlType.fromString(jsonObject.getString("type"));
27 | }
28 |
29 | /**
30 | * Returns mixer control type.
31 | *
32 | * @return type of mixer control
33 | */
34 | public ControlType getType()
35 | {
36 | return type;
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/menu_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
31 |
--------------------------------------------------------------------------------
/app/src/main/java/cz/jiriskorpil/amixerwebui/control/ControlContainerType.java:
--------------------------------------------------------------------------------
1 | package cz.jiriskorpil.amixerwebui.control;
2 |
3 | /**
4 | * Control container types.
5 | */
6 | public enum ControlContainerType
7 | {
8 | SOURCE,
9 | SWITCH,
10 | VOLUME,
11 | UNKNOWN;
12 |
13 | /**
14 | * Converts control name to control container type.
15 | *
16 | * @param name control as string
17 | * @return control container type
18 | */
19 | public static ControlContainerType fromName(String name)
20 | {
21 | if (name.matches("^(.*) Source$")) {
22 | return SOURCE;
23 | } else if (name.matches("^(.*) Switch")) {
24 | return SWITCH;
25 | } else if (name.matches("^(.*) Volume$")) {
26 | return VOLUME;
27 | }
28 | return UNKNOWN;
29 | }
30 |
31 | /**
32 | * Returns container name based on control name.
33 | *
34 | * @param name control name
35 | * @return container name
36 | */
37 | public static String getContainerName(String name)
38 | {
39 | return name.replaceAll("^(.*) (Source|Switch|Volume)$", "$1");
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/app/src/main/res/layout-land/equalizer_row.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
18 |
19 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/app/src/main/java/cz/jiriskorpil/amixerwebui/control/mixer/BooleanControl.java:
--------------------------------------------------------------------------------
1 | package cz.jiriskorpil.amixerwebui.control.mixer;
2 |
3 | import org.json.JSONException;
4 | import org.json.JSONObject;
5 |
6 | import cz.jiriskorpil.amixerwebui.control.IBooleanControl;
7 |
8 | /**
9 | * Represents boolean control (on/off).
10 | */
11 | public class BooleanControl extends MixerControl implements IBooleanControl
12 | {
13 | private boolean value;
14 |
15 | /**
16 | * Creates new instance of boolean control.
17 | *
18 | * @param jsonObject JSON object representing boolean control retrieved from server
19 | * @throws JSONException
20 | */
21 | public BooleanControl(JSONObject jsonObject) throws JSONException
22 | {
23 | super(jsonObject);
24 | value = (boolean) jsonObject.getJSONArray("values").get(0);
25 | }
26 |
27 | /**
28 | * {@inheritDoc}
29 | */
30 | public boolean isChecked()
31 | {
32 | return value;
33 | }
34 |
35 | /**
36 | * {@inheritDoc}
37 | */
38 | public void setChecked(boolean value)
39 | {
40 | this.value = value;
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/content_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
12 |
13 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
14 |
15 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/app/src/main/java/cz/jiriskorpil/amixerwebui/control/ControlFactory.java:
--------------------------------------------------------------------------------
1 | package cz.jiriskorpil.amixerwebui.control;
2 |
3 | import android.util.Log;
4 |
5 | import org.json.JSONException;
6 | import org.json.JSONObject;
7 |
8 | import cz.jiriskorpil.amixerwebui.control.mixer.MixerControlFactory;
9 |
10 | /**
11 | * Factory for create new control from JSON object
12 | */
13 | @SuppressWarnings("PMD.ClassNamingConventions")
14 | public final class ControlFactory
15 | {
16 | private ControlFactory() {}
17 |
18 | /**
19 | * Creates control instance.
20 | *
21 | * @param jsonObject JSON object representing control retrieved from server
22 | * @return new control instance
23 | */
24 | public static Control createControl(JSONObject jsonObject)
25 | {
26 | try
27 | {
28 | switch (InterfaceType.fromString(jsonObject.getString("iface")))
29 | {
30 | case MIXER:
31 | return MixerControlFactory.createMixerControl(jsonObject);
32 | default:
33 | return new Control(jsonObject);
34 | }
35 | } catch (JSONException e) {
36 | Log.e("JSONException", "Error: " + e.toString());
37 | }
38 | return null;
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/control_channel.xml:
--------------------------------------------------------------------------------
1 |
2 |
11 |
12 |
17 |
18 |
24 |
25 |
31 |
32 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2016 Jiří Škorpil
4 |
5 | Permission is hereby granted, free of charge, to any person
6 | obtaining a copy of this software and associated documentation
7 | files (the "Software"), to deal in the Software without
8 | restriction, including without limitation the rights to use,
9 | copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | copies of the Software, and to permit persons to whom the
11 | Software is furnished to do so, subject to the following
12 | conditions:
13 |
14 | The above copyright notice and this permission notice shall be
15 | included in all copies or substantial portions of the Software.
16 |
17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
19 | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
21 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
22 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
23 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
24 | OTHER DEALINGS IN THE SOFTWARE.
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 |
3 | android {
4 | compileSdkVersion 27
5 | buildToolsVersion "27.0.3"
6 | defaultConfig {
7 | applicationId "cz.jiriskorpil.amixerwebui"
8 | minSdkVersion 15
9 | targetSdkVersion 27
10 | versionCode 8
11 | versionName "0.3.2"
12 | }
13 | buildTypes {
14 | release {
15 | minifyEnabled false
16 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
17 | }
18 | }
19 | }
20 |
21 | ext.supportLibraryVersion = '27.1.1'
22 | dependencies {
23 | implementation fileTree(include: ['*.jar'], dir: 'libs')
24 | testImplementation 'junit:junit:4.12'
25 | implementation "com.android.support:appcompat-v7:$supportLibraryVersion"
26 | implementation "com.android.support:design:$supportLibraryVersion"
27 | implementation "com.android.support:support-v4:$supportLibraryVersion"
28 | implementation "com.android.support:cardview-v7:$supportLibraryVersion"
29 | implementation "com.android.support:recyclerview-v7:$supportLibraryVersion"
30 | implementation 'com.h6ah4i.android.widget.verticalseekbar:verticalseekbar:0.7.0'
31 | }
32 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable-v21/ic_settings_white_24dp.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/equalizer_row.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
16 |
17 |
28 |
29 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # ALSA Mixer WebUI for Android
2 |
3 | [](LICENSE) [](https://lonamiwebs.github.io/stringlate/translate?git=https%3A%2F%2Fgithub.com%2FJiriSko%2Famixer-webui-android) [](https://app.codeac.io/github/JiriSko/amixer-webui-android)
4 |
5 | Android client for control ALSA volume on remote server using [ALSA Mixer WebUI](https://github.com/JiriSko/amixer-webui/).
6 |
7 |
8 |
9 |
10 | [](screenshot.png)
11 |
12 | ## Supported version
13 |
14 | - Android 4.0.3 and newer
15 |
16 | ## Usage
17 |
18 | - Install from [latest APK](https://github.com/JiriSko/amixer-webui-android/releases/download/v0.3.2/amixer-webui-v0.3.2.apk), or
19 | - Get it on [F-Droid](https://f-droid.org/packages/cz.jiriskorpil.amixerwebui/)
20 | - Build from source code
21 |
22 | ## License
23 |
24 | The application is released under [The MIT License](LICENSE).
25 |
--------------------------------------------------------------------------------
/app/src/main/java/cz/jiriskorpil/amixerwebui/control/mixer/Channel.java:
--------------------------------------------------------------------------------
1 | package cz.jiriskorpil.amixerwebui.control.mixer;
2 |
3 | import cz.jiriskorpil.amixerwebui.control.IChannel;
4 | import cz.jiriskorpil.amixerwebui.control.IIntegerControl;
5 |
6 | /**
7 | * Represents one channel in integer control.
8 | */
9 | public class Channel implements IChannel
10 | {
11 | private IIntegerControl control;
12 | private String name;
13 | private int value;
14 |
15 | /**
16 | * Creates new channel instance.
17 | *
18 | * @param control parent control
19 | * @param name channel name
20 | * @param value channel value
21 | */
22 | public Channel(IIntegerControl control, String name, int value)
23 | {
24 | this.control = control;
25 | this.name = name;
26 | this.value = value;
27 | }
28 |
29 | /**
30 | * {@inheritDoc}
31 | */
32 | public IIntegerControl getControl()
33 | {
34 | return control;
35 | }
36 |
37 | /**
38 | * {@inheritDoc}
39 | */
40 | public String getName()
41 | {
42 | return name;
43 | }
44 |
45 | /**
46 | * {@inheritDoc}
47 | */
48 | public int getValue()
49 | {
50 | return value;
51 | }
52 |
53 | /**
54 | * {@inheritDoc}
55 | */
56 | public void setValue(int value)
57 | {
58 | this.value = value;
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/app/src/main/java/cz/jiriskorpil/amixerwebui/control/mixer/MixerControlFactory.java:
--------------------------------------------------------------------------------
1 | package cz.jiriskorpil.amixerwebui.control.mixer;
2 |
3 | import android.util.Log;
4 |
5 | import org.json.JSONException;
6 | import org.json.JSONObject;
7 |
8 | import cz.jiriskorpil.amixerwebui.control.ControlType;
9 |
10 | /**
11 | * Factory for create new mixer control from JSON object
12 | */
13 | @SuppressWarnings("PMD.ClassNamingConventions")
14 | public final class MixerControlFactory
15 | {
16 | private MixerControlFactory() {}
17 |
18 | /**
19 | * Creates mixer control instance.
20 | *
21 | * @param jsonObject JSON object representing mixer control retrieved from server
22 | * @return new mixer control instance
23 | */
24 | @SuppressWarnings("PMD.SwitchStmtsShouldHaveDefault")
25 | public static MixerControl createMixerControl(JSONObject jsonObject)
26 | {
27 | try {
28 | switch (ControlType.fromString(jsonObject.getString("type")))
29 | {
30 | case ENUMERATED:
31 | return new EnumeratedControl(jsonObject);
32 | case BOOLEAN:
33 | return new BooleanControl(jsonObject);
34 | case INTEGER:
35 | return new IntegerControl(jsonObject);
36 | }
37 | } catch (JSONException e) {
38 | Log.e("JSONException", "Error: " + e.toString());
39 | }
40 | return null;
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/app/src/main/java/cz/jiriskorpil/amixerwebui/control/Control.java:
--------------------------------------------------------------------------------
1 | package cz.jiriskorpil.amixerwebui.control;
2 |
3 | import org.json.JSONException;
4 | import org.json.JSONObject;
5 |
6 | /**
7 | * Represents one control.
8 | */
9 | public class Control implements IControl
10 | {
11 | private int id;
12 | private InterfaceType iface;
13 | private String access;
14 | private String name;
15 |
16 | /**
17 | * Creates new instance of control.
18 | *
19 | * @param jsonObject JSON object representing control retrieved from server
20 | * @throws JSONException
21 | */
22 | public Control(JSONObject jsonObject) throws JSONException
23 | {
24 | super();
25 | id = jsonObject.getInt("id");
26 | iface = InterfaceType.fromString(jsonObject.getString("iface"));
27 | access = jsonObject.getString("access");
28 | name = jsonObject.getString("name");
29 | }
30 |
31 | /**
32 | * {@inheritDoc}
33 | */
34 | public int getId()
35 | {
36 | return id;
37 | }
38 |
39 | /**
40 | * {@inheritDoc}
41 | */
42 | public InterfaceType getIface()
43 | {
44 | return iface;
45 | }
46 |
47 | /**
48 | * {@inheritDoc}
49 | */
50 | public String getAccess()
51 | {
52 | return access;
53 | }
54 |
55 | /**
56 | * {@inheritDoc}
57 | */
58 | public String getName()
59 | {
60 | return name;
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/app/src/main/java/cz/jiriskorpil/amixerwebui/control/mixer/EnumeratedControl.java:
--------------------------------------------------------------------------------
1 | package cz.jiriskorpil.amixerwebui.control.mixer;
2 |
3 | import org.json.JSONException;
4 | import org.json.JSONObject;
5 |
6 | import cz.jiriskorpil.amixerwebui.control.IEnumeratedControl;
7 |
8 | /**
9 | * Represents enumerated control (select one from many).
10 | */
11 | public class EnumeratedControl extends MixerControl implements IEnumeratedControl
12 | {
13 | private String[] items;
14 | private int value;
15 |
16 | /**
17 | * Creates new instance of enumerated control.
18 | *
19 | * @param jsonObject JSON object representing enumerated control retrieved from server
20 | * @throws JSONException
21 | */
22 | public EnumeratedControl(JSONObject jsonObject) throws JSONException
23 | {
24 | super(jsonObject);
25 |
26 | value = (int) jsonObject.getJSONArray("values").get(0);
27 |
28 | items = new String[jsonObject.getJSONObject("items").length()];
29 | for (int i = 0; i < items.length; i++) {
30 | items[i] = jsonObject.getJSONObject("items").getString(String.valueOf(i));
31 | }
32 | }
33 |
34 | /**
35 | * {@inheritDoc}
36 | */
37 | public String[] getItems()
38 | {
39 | return items;
40 | }
41 |
42 | /**
43 | * {@inheritDoc}
44 | */
45 | public int getValue()
46 | {
47 | return value;
48 | }
49 |
50 | /**
51 | * {@inheritDoc}
52 | */
53 | public void setValue(int value)
54 | {
55 | this.value = value;
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/app/src/main/res/values-cs/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | ALSA Mixer WebUI
3 | Nastavení
4 | Nastavení
5 | Jiří Škorpil
6 |
7 | Stahování přerušeno
8 | Spojení selhalo!
9 | Opakovat
10 |
11 | Uzamknout posuvníky
12 | Kanály jsou uzamčeny.
13 | Kanály jsou odemčeny.
14 | %1$d %%
15 |
16 | Zvuková karta
17 | Ekvalizér
18 |
19 |
20 |
21 |
22 |
23 | Připojení
24 |
25 | IP adresa
26 | 192.168.1.5
27 |
28 | Port
29 | 8080
30 |
31 |
32 |
33 | O aplikaci
34 |
35 | Autor
36 | Verze
37 |
38 |
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | ALSA Mixer WebUI
3 | Settings
4 | Settings
5 | Jiří Škorpil
6 |
7 | Downloading canceled
8 | Connection failed!
9 | RETRY
10 |
11 | Lock sliders
12 | Channel sliders are locked together.
13 | Channel sliders are unlocked.
14 | %1$d %%
15 |
16 | Sound card
17 | Equalizer
18 |
19 |
20 |
21 |
22 |
23 | Connection
24 |
25 | IP address
26 | 192.168.1.5
27 |
28 | Port
29 | 8080
30 |
31 |
32 |
33 | About
34 |
35 | Author
36 | Version
37 |
38 |
--------------------------------------------------------------------------------
/app/src/main/res/values-nl/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | ALSA Mixer WebUI
3 | Instellingen
4 | Instellingen
5 | Jiří Škorpil
6 |
7 | Downloaden geannuleerd
8 | Verbinding mislukt!
9 | Opnieuw proberen
10 |
11 | Vergrendel schuifregelaars
12 | Kanaal schuifregelaars zijn samen vergrendeld
13 | Kanaal schuifregelaars zijn ontgrendeld
14 | %1$d %%
15 |
16 | Geluidskaart
17 | Niveauregelaar
18 |
19 |
20 |
21 |
22 |
23 | Connectie
24 |
25 | IP adres
26 | 192.168.1.5
27 |
28 | Poort
29 | 8080
30 |
31 |
32 |
33 | Over
34 |
35 | Auteur
36 | Versie
37 |
38 |
--------------------------------------------------------------------------------
/app/src/main/java/cz/jiriskorpil/amixerwebui/control/Equalizer.java:
--------------------------------------------------------------------------------
1 | package cz.jiriskorpil.amixerwebui.control;
2 |
3 | import android.os.Parcel;
4 | import android.os.Parcelable;
5 | import android.util.Log;
6 |
7 | import org.json.JSONArray;
8 | import org.json.JSONException;
9 |
10 | import java.util.ArrayList;
11 | import java.util.List;
12 |
13 | public class Equalizer implements Parcelable
14 | {
15 | private List controls;
16 | private String rawData;
17 |
18 | public Equalizer(String rawData)
19 | {
20 | controls = new ArrayList<>();
21 | this.rawData = rawData;
22 | }
23 |
24 | public List getControls()
25 | {
26 | if (controls.isEmpty())
27 | {
28 | try {
29 | controls = ControlParser.parse(new JSONArray(rawData));
30 | } catch (JSONException e) {
31 | Log.e("JSONException", "Error: " + e.toString());
32 | }
33 | }
34 | return controls;
35 | }
36 |
37 |
38 | public Equalizer(Parcel in)
39 | {
40 | controls = new ArrayList<>();
41 | rawData = in.readString();
42 | }
43 |
44 | @Override
45 | public int describeContents()
46 | {
47 | return 0;
48 | }
49 |
50 | @Override
51 | public void writeToParcel(Parcel parcel, int i)
52 | {
53 | parcel.writeString(rawData);
54 | }
55 |
56 | public static final Parcelable.Creator CREATOR= new Parcelable.Creator()
57 | {
58 | @Override
59 | public Equalizer createFromParcel(Parcel parcel)
60 | {
61 | return new Equalizer(parcel);
62 | }
63 |
64 | @Override
65 | public Equalizer[] newArray(int i)
66 | {
67 | return new Equalizer[i];
68 | }
69 | };
70 | }
71 |
--------------------------------------------------------------------------------
/app/src/main/java/cz/jiriskorpil/amixerwebui/control/mixer/IntegerControl.java:
--------------------------------------------------------------------------------
1 | package cz.jiriskorpil.amixerwebui.control.mixer;
2 |
3 | import org.json.JSONException;
4 | import org.json.JSONObject;
5 |
6 | import cz.jiriskorpil.amixerwebui.control.IChannel;
7 | import cz.jiriskorpil.amixerwebui.control.IIntegerControl;
8 |
9 | /**
10 | * Represents integer control (common volume slider).
11 | */
12 | public class IntegerControl extends MixerControl implements IIntegerControl
13 | {
14 | private IChannel[] channels;
15 |
16 | private int min;
17 | private int max;
18 | private int step;
19 |
20 | /**
21 | * Creates new instance of integer control.
22 | *
23 | * @param jsonObject JSON object representing integer control retrieved from server
24 | * @throws JSONException
25 | */
26 | public IntegerControl(JSONObject jsonObject) throws JSONException
27 | {
28 | super(jsonObject);
29 |
30 | min = jsonObject.getInt("min");
31 | max = jsonObject.getInt("max");
32 | step = jsonObject.getInt("step");
33 |
34 | channels = new Channel[jsonObject.getJSONArray("channels").length()];
35 | for (int i = 0; i < channels.length; i++) {
36 | channels[i] = new Channel(this,
37 | jsonObject.getJSONArray("channels").get(i).toString(),
38 | Integer.parseInt(jsonObject.getJSONArray("values").get(i).toString()));
39 | }
40 | }
41 |
42 | /**
43 | * {@inheritDoc}
44 | */
45 | public IChannel[] getChannels()
46 | {
47 | return channels;
48 | }
49 |
50 | /**
51 | * {@inheritDoc}
52 | */
53 | public int getMin()
54 | {
55 | return min;
56 | }
57 |
58 | /**
59 | * {@inheritDoc}
60 | */
61 | public int getMax()
62 | {
63 | return max;
64 | }
65 |
66 | /**
67 | * {@inheritDoc}
68 | */
69 | public int getStep()
70 | {
71 | return step;
72 | }
73 | }
74 |
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
13 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
28 |
29 |
32 |
33 |
37 |
38 |
41 |
42 |
43 |
44 |
45 |
--------------------------------------------------------------------------------
/app/src/main/java/cz/jiriskorpil/amixerwebui/control/ControlParser.java:
--------------------------------------------------------------------------------
1 | package cz.jiriskorpil.amixerwebui.control;
2 |
3 | import android.util.Log;
4 |
5 | import org.json.JSONArray;
6 | import org.json.JSONException;
7 |
8 | import java.util.ArrayList;
9 | import java.util.List;
10 |
11 | import cz.jiriskorpil.amixerwebui.control.mixer.MixerControl;
12 |
13 | public final class ControlParser
14 | {
15 | private static List controls;
16 |
17 | private ControlParser() {}
18 |
19 | /**
20 | * Parses controls out of JSON array.
21 | *
22 | * @param jsonArray JSON array representing controls retrieved from server
23 | * @return list of control containers
24 | */
25 | public static List parse(JSONArray jsonArray)
26 | {
27 | Control control;
28 | controls = new ArrayList<>();
29 |
30 | try {
31 | for (int i = 0; i < jsonArray.length(); i++)
32 | {
33 | control = ControlFactory.createControl(jsonArray.getJSONObject(i));
34 | if (control instanceof MixerControl) {
35 | getControlContainer(control.getName()).addControl(control);
36 | }/* else {
37 | // not supported (yet?)
38 | }*/
39 | }
40 | } catch (JSONException e) {
41 | Log.e("JSONException", "Error: " + e.toString());
42 | }
43 | return controls;
44 | }
45 |
46 | private static ControlContainer getControlContainer(String controlName)
47 | {
48 | int index = findControlContainer(controlName);
49 |
50 | if (index == -1) // if doesn't exists then create new container
51 | {
52 | controls.add(new ControlContainer(controlName));
53 | index = controls.size() - 1;
54 | }
55 |
56 | return controls.get(index);
57 | }
58 |
59 | private static int findControlContainer(String controlName)
60 | {
61 | for (int i = 0; i < controls.size(); i++) {
62 | if (controls.get(i).getName().equals(ControlContainerType.getContainerName(controlName))) {
63 | return i;
64 | }
65 | }
66 | return -1;
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/control_row.xml:
--------------------------------------------------------------------------------
1 |
2 |
10 |
11 |
15 |
16 |
21 |
22 |
29 |
30 |
41 |
42 |
53 |
54 |
55 |
64 |
65 |
71 |
72 |
73 |
74 |
75 |
--------------------------------------------------------------------------------
/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/java/cz/jiriskorpil/amixerwebui/control/ControlContainer.java:
--------------------------------------------------------------------------------
1 | package cz.jiriskorpil.amixerwebui.control;
2 |
3 | /**
4 | * Container for related controls (connects boolean, enumerated and integer control into logical container).
5 | */
6 | public class ControlContainer
7 | {
8 | private IEnumeratedControl cSource;
9 | private IBooleanControl cSwitch;
10 | private IIntegerControl cVolume;
11 |
12 | private String name;
13 |
14 | /**
15 | * Creates new blank control container.
16 | *
17 | * @param name container or control name (container name is automatically extracted from control name)
18 | */
19 | public ControlContainer(String name)
20 | {
21 | super();
22 | this.name = ControlContainerType.getContainerName(name);
23 | }
24 |
25 | /**
26 | * Returns container name.
27 | *
28 | * @return container name
29 | */
30 | public String getName()
31 | {
32 | return name;
33 | }
34 |
35 | /**
36 | * Adds control into container. Control type is automatically detected based on its name.
37 | *
38 | * @param control control which should be added into container
39 | */
40 | @SuppressWarnings("PMD.SwitchStmtsShouldHaveDefault")
41 | public void addControl(Control control)
42 | {
43 | switch (ControlContainerType.fromName(control.getName()))
44 | {
45 | case SOURCE:
46 | cSource = (IEnumeratedControl) control;
47 | break;
48 | case SWITCH:
49 | cSwitch = (IBooleanControl) control;
50 | break;
51 | case VOLUME:
52 | cVolume = (IIntegerControl) control;
53 | break;
54 | }
55 | }
56 |
57 | /**
58 | * Checks whether container contains enumerated control.
59 | *
60 | * @return true if container contains enumerated control
61 | */
62 | public boolean hasSourceControl()
63 | {
64 | return cSource != null;
65 | }
66 |
67 | /**
68 | * Returns enumerated control.
69 | *
70 | * @return enumerated control
71 | */
72 | public IEnumeratedControl getSource()
73 | {
74 | return cSource;
75 | }
76 |
77 | /**
78 | * Checks whether container contains boolean control.
79 | *
80 | * @return true if container contains boolean control
81 | */
82 | public boolean hasSwitchControl()
83 | {
84 | return cSwitch != null;
85 | }
86 |
87 | /**
88 | * Returns boolean control.
89 | *
90 | * @return boolean control
91 | */
92 | public IBooleanControl getSwitch()
93 | {
94 | return cSwitch;
95 | }
96 |
97 | /**
98 | * Checks whether container contains integer control.
99 | *
100 | * @return true if container contains boolean control
101 | */
102 | public boolean hasVolumeControl()
103 | {
104 | return cVolume != null;
105 | }
106 |
107 | /**
108 | * Returns integer control.
109 | *
110 | * @return integer control
111 | */
112 | public IIntegerControl getVolume()
113 | {
114 | return cVolume;
115 | }
116 | }
117 |
--------------------------------------------------------------------------------
/app/src/main/java/cz/jiriskorpil/amixerwebui/activity/AppCompatPreferenceActivity.java:
--------------------------------------------------------------------------------
1 | package cz.jiriskorpil.amixerwebui.activity;
2 |
3 | import android.content.res.Configuration;
4 | import android.os.Bundle;
5 | import android.preference.PreferenceActivity;
6 | import android.support.annotation.LayoutRes;
7 | import android.support.annotation.NonNull;
8 | import android.support.annotation.Nullable;
9 | import android.support.v7.app.ActionBar;
10 | import android.support.v7.app.AppCompatDelegate;
11 | import android.support.v7.widget.Toolbar;
12 | import android.view.MenuInflater;
13 | import android.view.View;
14 | import android.view.ViewGroup;
15 |
16 | /**
17 | * A {@link android.preference.PreferenceActivity} which implements and proxies the necessary calls
18 | * to be used with AppCompat.
19 | */
20 | public abstract class AppCompatPreferenceActivity extends PreferenceActivity
21 | {
22 | private AppCompatDelegate mDelegate;
23 |
24 | @Override
25 | protected void onCreate(Bundle savedInstanceState)
26 | {
27 | getDelegate().installViewFactory();
28 | getDelegate().onCreate(savedInstanceState);
29 | super.onCreate(savedInstanceState);
30 | }
31 |
32 | @Override
33 | protected void onPostCreate(Bundle savedInstanceState)
34 | {
35 | super.onPostCreate(savedInstanceState);
36 | getDelegate().onPostCreate(savedInstanceState);
37 | }
38 |
39 | public ActionBar getSupportActionBar()
40 | {
41 | return getDelegate().getSupportActionBar();
42 | }
43 |
44 | public void setSupportActionBar(@Nullable Toolbar toolbar)
45 | {
46 | getDelegate().setSupportActionBar(toolbar);
47 | }
48 |
49 | @NonNull
50 | @Override
51 | public MenuInflater getMenuInflater()
52 | {
53 | return getDelegate().getMenuInflater();
54 | }
55 |
56 | @Override
57 | public void setContentView(@LayoutRes int layoutResID)
58 | {
59 | getDelegate().setContentView(layoutResID);
60 | }
61 |
62 | @Override
63 | public void setContentView(View view)
64 | {
65 | getDelegate().setContentView(view);
66 | }
67 |
68 | @Override
69 | public void setContentView(View view, ViewGroup.LayoutParams params)
70 | {
71 | getDelegate().setContentView(view, params);
72 | }
73 |
74 | @Override
75 | public void addContentView(View view, ViewGroup.LayoutParams params)
76 | {
77 | getDelegate().addContentView(view, params);
78 | }
79 |
80 | @Override
81 | protected void onPostResume()
82 | {
83 | super.onPostResume();
84 | getDelegate().onPostResume();
85 | }
86 |
87 | @Override
88 | protected void onTitleChanged(CharSequence title, int color)
89 | {
90 | super.onTitleChanged(title, color);
91 | getDelegate().setTitle(title);
92 | }
93 |
94 | @Override
95 | public void onConfigurationChanged(Configuration newConfig)
96 | {
97 | super.onConfigurationChanged(newConfig);
98 | getDelegate().onConfigurationChanged(newConfig);
99 | }
100 |
101 | @Override
102 | protected void onStop()
103 | {
104 | super.onStop();
105 | getDelegate().onStop();
106 | }
107 |
108 | @Override
109 | protected void onDestroy()
110 | {
111 | super.onDestroy();
112 | getDelegate().onDestroy();
113 | }
114 |
115 | public void invalidateOptionsMenu()
116 | {
117 | getDelegate().invalidateOptionsMenu();
118 | }
119 |
120 | private AppCompatDelegate getDelegate()
121 | {
122 | if (mDelegate == null) {
123 | mDelegate = AppCompatDelegate.create(this, null);
124 | }
125 | return mDelegate;
126 | }
127 | }
128 |
--------------------------------------------------------------------------------
/app/src/main/java/cz/jiriskorpil/amixerwebui/task/AsyncHttpRequestTask.java:
--------------------------------------------------------------------------------
1 | package cz.jiriskorpil.amixerwebui.task;
2 |
3 | import android.content.Context;
4 |
5 | import java.io.BufferedInputStream;
6 | import java.io.InputStream;
7 | import java.net.HttpURLConnection;
8 | import java.net.URL;
9 |
10 | /**
11 | * Abstract class for asynchronous HTTP request to the server
12 | */
13 | abstract public class AsyncHttpRequestTask extends android.os.AsyncTask
14 | {
15 | protected Context context;
16 | protected OnFinishListener mOnFinishListener;
17 | protected String url;
18 |
19 | /**
20 | * Creates new instance of asynchronous task
21 | *
22 | * @param context The context to use. Usually {@link android.app.Activity} object.
23 | * @param url base url directing to server
24 | */
25 | public AsyncHttpRequestTask(Context context, String url)
26 | {
27 | super();
28 | this.context = context;
29 | this.url = url;
30 | }
31 |
32 | /**
33 | * Creates new instance of asynchronous task with callback after HTTP response arrives
34 | *
35 | * @param context The context to use. Usually {@link android.app.Activity} object.
36 | * @param url base url directing to server
37 | * @param listener listener which is called after HTTP response arrives
38 | */
39 | public AsyncHttpRequestTask(Context context, String url, OnFinishListener listener)
40 | {
41 | this(context, url);
42 | this.mOnFinishListener = listener;
43 | }
44 |
45 | /**
46 | * {@inheritDoc}
47 | */
48 | @Override
49 | abstract protected String doInBackground(String... params);
50 |
51 | /**
52 | * {@inheritDoc}
53 | *
54 | * @param result
55 | */
56 | @Override
57 | protected void onPostExecute(String result)
58 | {
59 | if (mOnFinishListener != null) {
60 | mOnFinishListener.onFinish(result);
61 | }
62 | }
63 |
64 | /**
65 | * Creates HTTP request to specific URL path with GET method and returns downloaded data.
66 | *
67 | * @param urlString path
68 | * @return downloaded data
69 | */
70 | protected String downloadFromURL(String urlString)
71 | {
72 | return downloadFromURL(urlString, "GET");
73 | }
74 |
75 | /**
76 | * Creates HTTP request to specific URL path and returns downloaded data.
77 | *
78 | * @param urlString path
79 | * @param method used method
80 | * @return downloaded data
81 | */
82 | @SuppressWarnings({"PMD.EmptyCatchBlock", "PMD.CloseResource"})
83 | protected String downloadFromURL(String urlString, String method)
84 | {
85 | //System.out.println("[" + method + "] Accessing " + this.url + urlString);
86 |
87 | String result = "";
88 | HttpURLConnection urlConnection = null;
89 | try
90 | {
91 | URL url = new URL(this.url + urlString);
92 | urlConnection = (HttpURLConnection) url.openConnection();
93 | urlConnection.setRequestMethod(method);
94 |
95 | InputStream in = new BufferedInputStream(urlConnection.getInputStream());
96 |
97 | int data = in.read();
98 | while (data != -1)
99 | {
100 | result += (char) data;
101 | data = in.read();
102 | }
103 | in.close();
104 | } catch (Exception e) {
105 | //e.printStackTrace();
106 | } finally {
107 | if (urlConnection != null) {
108 | urlConnection.disconnect();
109 | }
110 | }
111 | return result;
112 | }
113 |
114 |
115 | public interface OnFinishListener
116 | {
117 | /**
118 | * Called when downloading finished.
119 | *
120 | * @param result downloaded data
121 | */
122 | void onFinish(String result);
123 | }
124 | }
125 |
--------------------------------------------------------------------------------
/app/src/main/java/cz/jiriskorpil/amixerwebui/activity/EqualizerActivity.java:
--------------------------------------------------------------------------------
1 | package cz.jiriskorpil.amixerwebui.activity;
2 |
3 | import android.content.res.ColorStateList;
4 | import android.content.res.Configuration;
5 | import android.graphics.Color;
6 | import android.os.Bundle;
7 | import android.support.v7.app.AppCompatActivity;
8 | import android.support.v7.widget.AppCompatCheckBox;
9 | import android.support.v7.widget.LinearLayoutManager;
10 | import android.support.v7.widget.RecyclerView;
11 | import android.view.Menu;
12 | import android.view.MenuItem;
13 | import android.widget.CompoundButton;
14 |
15 | import cz.jiriskorpil.amixerwebui.R;
16 | import cz.jiriskorpil.amixerwebui.control.Equalizer;
17 | import cz.jiriskorpil.amixerwebui.control.EqualizerAdapter;
18 |
19 | /**
20 | * Equalizer activity.
21 | */
22 | public class EqualizerActivity extends AppCompatActivity {
23 |
24 | private LinearLayoutManager manager;
25 |
26 | private boolean lockedSliders;
27 |
28 | /**
29 | * {@inheritDoc}
30 | */
31 | @Override
32 | protected void onCreate(Bundle savedInstanceState) {
33 | super.onCreate(savedInstanceState);
34 | setContentView(R.layout.activity_equalizer);
35 |
36 | if (getSupportActionBar() != null) {
37 | getSupportActionBar().setDisplayHomeAsUpEnabled(true);
38 | }
39 |
40 | Equalizer equalizer = getIntent().getParcelableExtra("equalizer");
41 |
42 | manager = new LinearLayoutManager(this, getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE ? LinearLayoutManager.HORIZONTAL : LinearLayoutManager.VERTICAL, false);
43 |
44 | RecyclerView equalizerList = (RecyclerView) findViewById(R.id.equalizer_list);
45 | equalizerList.setLayoutManager(manager);
46 | equalizerList.setAdapter(new EqualizerAdapter(this, equalizer.getControls()));
47 | }
48 |
49 | /**
50 | * {@inheritDoc}
51 | */
52 | @Override
53 | public void onConfigurationChanged(Configuration newConfig)
54 | {
55 | super.onConfigurationChanged(newConfig);
56 |
57 | manager.setOrientation(newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE ? LinearLayoutManager.HORIZONTAL : LinearLayoutManager.VERTICAL);
58 | }
59 |
60 | /**
61 | * {@inheritDoc}
62 | */
63 | @Override
64 | public boolean onCreateOptionsMenu(Menu menu)
65 | {
66 | getMenuInflater().inflate(R.menu.menu_equalizer, menu);
67 |
68 | setupCheckbox(menu);
69 |
70 | return true;
71 | }
72 |
73 | /**
74 | * Setups checkbox in menu.
75 | * @param menu menu
76 | */
77 | private void setupCheckbox(Menu menu)
78 | {
79 | AppCompatCheckBox checkBox = (AppCompatCheckBox) menu.findItem(R.id.equalizer_lock).getActionView();
80 | ColorStateList colorStateList = new ColorStateList(new int[][]{
81 | new int[]{-android.R.attr.state_enabled}, // disabled
82 | new int[]{android.R.attr.state_enabled}, // enabled
83 | },
84 | new int[]{
85 | Color.WHITE, // disabled
86 | Color.WHITE // enabled
87 | });
88 | checkBox.setSupportButtonTintList(colorStateList);
89 | checkBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
90 | @Override
91 | public void onCheckedChanged(CompoundButton compoundButton, boolean b)
92 | {
93 | lockedSliders = b;
94 | }
95 | });
96 | checkBox.setText(getString(R.string.lock_sliders));
97 | checkBox.setChecked(true);
98 | checkBox.setPadding(0,0,Math.round(getResources().getDimension(R.dimen.activity_horizontal_margin)),0);
99 | }
100 |
101 | /**
102 | * {@inheritDoc}
103 | */
104 | @Override
105 | public boolean onOptionsItemSelected(MenuItem item)
106 | {
107 | switch (item.getItemId()) {
108 | // Respond to the action bar's Up/Home button
109 | case android.R.id.home:
110 | finish();
111 | return true;
112 |
113 | default:
114 | return super.onOptionsItemSelected(item);
115 | }
116 | }
117 |
118 | public boolean isLockedSliders()
119 | {
120 | return lockedSliders;
121 | }
122 | }
123 |
--------------------------------------------------------------------------------
/app/src/main/java/cz/jiriskorpil/amixerwebui/activity/MainActivity.java:
--------------------------------------------------------------------------------
1 | package cz.jiriskorpil.amixerwebui.activity;
2 |
3 | import android.content.Intent;
4 | import android.content.res.Configuration;
5 | import android.os.Bundle;
6 | import android.support.design.widget.Snackbar;
7 | import android.support.v4.content.ContextCompat;
8 | import android.support.v4.widget.SwipeRefreshLayout;
9 | import android.support.v7.app.AppCompatActivity;
10 | import android.support.v7.widget.GridLayoutManager;
11 | import android.support.v7.widget.RecyclerView;
12 | import android.support.v7.widget.Toolbar;
13 | import android.view.Menu;
14 | import android.view.MenuItem;
15 | import android.view.View;
16 |
17 | import cz.jiriskorpil.amixerwebui.R;
18 |
19 | /**
20 | * Main application activity.
21 | */
22 | public class MainActivity extends AppCompatActivity
23 | {
24 | public static final int EQUALIZER_REQUEST = 1;
25 |
26 | private DataHandler dataHandler;
27 | private String lastUrl;
28 | protected Menu menu;
29 |
30 | @Override
31 | protected void onCreate(Bundle savedInstanceState)
32 | {
33 | super.onCreate(savedInstanceState);
34 | setContentView(R.layout.activity_main);
35 |
36 | setSupportActionBar((Toolbar) findViewById(R.id.toolbar));
37 |
38 | dataHandler = new DataHandler(this,
39 | (RecyclerView) findViewById(R.id.controls_list),
40 | (SwipeRefreshLayout) findViewById(R.id.swipe_container))
41 | .setOnFailListener(new DataHandler.OnFailListener()
42 | {
43 | @Override
44 | public void onFail()
45 | {
46 | Snackbar
47 | .make(findViewById(android.R.id.content),
48 | getResources().getString(R.string.msg_connection_error),
49 | Snackbar.LENGTH_LONG)
50 | .setAction(getResources().getString(R.string.retry_btn_title), new View.OnClickListener()
51 | {
52 | @Override
53 | public void onClick(View v)
54 | {
55 | dataHandler.download();
56 | }
57 | }).setActionTextColor(ContextCompat.getColor(getBaseContext(), R.color.colorPrimaryLight))
58 | .show();
59 | }
60 | });
61 | lastUrl = DataHandler.getBaseUrl(this);
62 | }
63 |
64 | /**
65 | * {@inheritDoc}
66 | */
67 | @Override
68 | public void onConfigurationChanged(Configuration newConfig)
69 | {
70 | super.onConfigurationChanged(newConfig);
71 |
72 | GridLayoutManager manager = (GridLayoutManager) ((RecyclerView) findViewById(R.id.controls_list)).getLayoutManager();
73 | manager.setSpanCount(newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE ? 2 : 1);
74 | }
75 |
76 | /**
77 | * {@inheritDoc}
78 | */
79 | @Override
80 | public void onResume()
81 | {
82 | super.onResume();
83 |
84 | if (!lastUrl.equals(DataHandler.getBaseUrl(this)))
85 | {
86 | dataHandler.download();
87 | lastUrl = DataHandler.getBaseUrl(this);
88 | }
89 | }
90 |
91 | /**
92 | * {@inheritDoc}
93 | */
94 | @Override
95 | public boolean onCreateOptionsMenu(Menu menu)
96 | {
97 | this.menu = menu;
98 | getMenuInflater().inflate(R.menu.menu_main, menu);
99 |
100 | dataHandler.download();
101 |
102 | return true;
103 | }
104 |
105 | /**
106 | * {@inheritDoc}
107 | */
108 | @Override
109 | public boolean onOptionsItemSelected(MenuItem item)
110 | {
111 | int id = item.getItemId();
112 |
113 | switch (id)
114 | {
115 | case R.id.action_settings:
116 | startActivity(new Intent(this, SettingsActivity.class));
117 | return true;
118 |
119 | case R.id.action_equalizer:
120 | Intent intent = new Intent(this, EqualizerActivity.class);
121 | intent.putExtra("equalizer", dataHandler.getEqualizer());
122 | startActivityForResult(intent, EQUALIZER_REQUEST);
123 | return true;
124 |
125 | default:
126 | return super.onOptionsItemSelected(item);
127 | }
128 | }
129 |
130 | @SuppressWarnings("PMD.MissingBreakInSwitch")
131 | @Override
132 | protected void onActivityResult(int requestCode, int resultCode, Intent data)
133 | {
134 | switch (requestCode)
135 | {
136 | case EQUALIZER_REQUEST:
137 | dataHandler.setupEqualizer();
138 | break;
139 |
140 | default:
141 | super.onActivityResult(requestCode, resultCode, data);
142 | }
143 | }
144 | }
145 |
--------------------------------------------------------------------------------
/app/src/main/java/cz/jiriskorpil/amixerwebui/control/EqualizerAdapter.java:
--------------------------------------------------------------------------------
1 | package cz.jiriskorpil.amixerwebui.control;
2 |
3 | import android.app.Activity;
4 | import android.content.Context;
5 | import android.support.v7.widget.RecyclerView;
6 | import android.view.LayoutInflater;
7 | import android.view.View;
8 | import android.view.ViewGroup;
9 | import android.widget.LinearLayout;
10 | import android.widget.SeekBar;
11 | import android.widget.TextView;
12 |
13 | import java.util.List;
14 | import java.util.regex.Matcher;
15 | import java.util.regex.Pattern;
16 |
17 | import cz.jiriskorpil.amixerwebui.R;
18 | import cz.jiriskorpil.amixerwebui.activity.DataHandler;
19 | import cz.jiriskorpil.amixerwebui.activity.EqualizerActivity;
20 | import cz.jiriskorpil.amixerwebui.task.ChangeEqualizerHttpRequestTask;
21 |
22 | /**
23 | * List adapter for equalizer control container.
24 | */
25 | public class EqualizerAdapter extends RecyclerView.Adapter
26 | {
27 | private Context context;
28 | private List data = null;
29 |
30 | /**
31 | * @param context The context to use. Usually {@link android.app.Activity} object.
32 | * @param data list of controls
33 | */
34 | public EqualizerAdapter(Context context, List data)
35 | {
36 | this.context = context;
37 | this.data = data;
38 | }
39 |
40 | /**
41 | * {@inheritDoc}
42 | */
43 | @Override
44 | public int getItemCount()
45 | {
46 | return data.size();
47 | }
48 |
49 | /**
50 | * {@inheritDoc}
51 | */
52 | @Override
53 | public void onBindViewHolder(EqualizerAdapter.ViewHolder holder, int position)
54 | {
55 | setupEqualizerRow(data.get(position), holder);
56 | }
57 |
58 | /**
59 | * {@inheritDoc}
60 | */
61 | @Override
62 | public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType)
63 | {
64 | View itemView = LayoutInflater.from(parent.getContext()).inflate(R.layout.equalizer_row, parent, false);
65 |
66 | return new ViewHolder(itemView);
67 | }
68 |
69 | /**
70 | * Setups equalizer row.
71 | *
72 | * @param controlContainer control container
73 | * @param holder control container holder
74 | */
75 | private void setupEqualizerRow(ControlContainer controlContainer, final ViewHolder holder)
76 | {
77 | if (!controlContainer.hasVolumeControl()) {
78 | return;
79 | }
80 |
81 | holder.channelsList.removeAllViews();
82 |
83 | final EqualizerActivity equalizerActivity = (EqualizerActivity) context;
84 |
85 | final IIntegerControl volume = controlContainer.getVolume();
86 |
87 | String name = controlContainer.getName();
88 | Pattern p = Pattern.compile("[0-9]+\\. ([0-9]+ k?Hz) .*");
89 | Matcher m = p.matcher(name);
90 | holder.channelName.setText(m.find() ? m.group(1) : name);
91 |
92 | for (final IChannel channel: volume.getChannels())
93 | {
94 | View channelView = ((Activity) context).getLayoutInflater().inflate(R.layout.equalizer_channel, holder.channelsList, false);
95 |
96 | SeekBar channelVolumeSeekBar = (SeekBar) channelView.findViewById(R.id.channel_volume_seek_bar);
97 | channelVolumeSeekBar.setMax(volume.getMax());
98 | channelVolumeSeekBar.setProgress(channel.getValue());
99 | channelVolumeSeekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
100 | @Override
101 | public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser)
102 | {
103 | if (fromUser && equalizerActivity.isLockedSliders())
104 | {
105 | for (int i = 0; i < volume.getChannels().length; i++)
106 | {
107 | if (!holder.channelsList.getChildAt(i).equals(seekBar))
108 | {
109 | volume.getChannels()[i].setValue(progress);
110 | View channelView = holder.channelsList.getChildAt(i);
111 | ((SeekBar) channelView.findViewById(R.id.channel_volume_seek_bar))
112 | .setProgress(progress);
113 | }
114 | }
115 | }
116 | if (fromUser)
117 | {
118 | channel.setValue(progress);
119 | }
120 | }
121 |
122 | @SuppressWarnings("PMD.UncommentedEmptyMethodBody")
123 | @Override
124 | public void onStartTrackingTouch(SeekBar seekBar)
125 | {
126 | }
127 |
128 | @Override
129 | public void onStopTrackingTouch(SeekBar seekBar)
130 | {
131 | String volumes = "";
132 | for (int i = 0; i < volume.getChannels().length; i++)
133 | {
134 | if (!"".equals(volumes)) {
135 | volumes += "/";
136 | }
137 | volumes += String.valueOf(volume.getChannels()[i].getValue());
138 | }
139 |
140 | new ChangeEqualizerHttpRequestTask(holder.v.getContext(), DataHandler.getBaseUrl(holder.v.getContext()))
141 | .execute(String.valueOf(volume.getId()), volumes);
142 | }
143 | });
144 |
145 | holder.channelsList.addView(channelView);
146 | }
147 | }
148 |
149 |
150 | /**
151 | * Holds GUI controls.
152 | */
153 | static class ViewHolder extends RecyclerView.ViewHolder
154 | {
155 | View v;
156 |
157 | LinearLayout channelsList;
158 | TextView channelName;
159 |
160 | ViewHolder(View v)
161 | {
162 | super(v);
163 | this.v = v;
164 | channelsList = (LinearLayout) v.findViewById(R.id.channels_list);
165 | channelName = (TextView) v.findViewById(R.id.channel_name);
166 | }
167 | }
168 | }
169 |
--------------------------------------------------------------------------------
/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/java/cz/jiriskorpil/amixerwebui/activity/SettingsActivity.java:
--------------------------------------------------------------------------------
1 | package cz.jiriskorpil.amixerwebui.activity;
2 |
3 | import android.annotation.TargetApi;
4 | import android.content.Context;
5 | import android.content.pm.PackageInfo;
6 | import android.content.pm.PackageManager;
7 | import android.content.res.Configuration;
8 | import android.os.Build;
9 | import android.os.Bundle;
10 | import android.preference.ListPreference;
11 | import android.preference.Preference;
12 | import android.preference.PreferenceActivity;
13 | import android.support.v7.app.ActionBar;
14 | import android.preference.PreferenceFragment;
15 | import android.preference.PreferenceManager;
16 | import android.view.MenuItem;
17 |
18 | import java.util.List;
19 |
20 | import cz.jiriskorpil.amixerwebui.R;
21 |
22 | /**
23 | * A {@link PreferenceActivity} that presents a set of application settings. On
24 | * handset devices, settings are presented as a single list. On tablets,
25 | * settings are split by category, with category headers shown to the left of
26 | * the list of settings.
27 | *
28 | * See
29 | * Android Design: Settings for design guidelines and the Settings
31 | * API Guide for more information on developing a Settings UI.
32 | */
33 | public class SettingsActivity extends AppCompatPreferenceActivity
34 | {
35 | /**
36 | * A preference value change listener that updates the preference's summary
37 | * to reflect its new value.
38 | */
39 | private static Preference.OnPreferenceChangeListener sBindPreferenceSummaryToValueListener = new Preference.OnPreferenceChangeListener()
40 | {
41 | @Override
42 | public boolean onPreferenceChange(Preference preference, Object value)
43 | {
44 | String stringValue = value.toString();
45 |
46 | if (preference instanceof ListPreference)
47 | {
48 | // For list preferences, look up the correct display value in
49 | // the preference's 'entries' list.
50 | ListPreference listPreference = (ListPreference) preference;
51 | int index = listPreference.findIndexOfValue(stringValue);
52 |
53 | // Set the summary to reflect the new value.
54 | preference.setSummary(
55 | index >= 0
56 | ? listPreference.getEntries()[index]
57 | : null);
58 |
59 | } else {
60 | // For all other preferences, set the summary to the value's
61 | // simple string representation.
62 | preference.setSummary(stringValue);
63 | }
64 | return true;
65 | }
66 | };
67 |
68 | /**
69 | * Helper method to determine if the device has an extra-large screen. For
70 | * example, 10" tablets are extra-large.
71 | */
72 | private static boolean isXLargeTablet(Context context)
73 | {
74 | return (context.getResources().getConfiguration().screenLayout
75 | & Configuration.SCREENLAYOUT_SIZE_MASK) >= Configuration.SCREENLAYOUT_SIZE_XLARGE;
76 | }
77 |
78 | /**
79 | * Binds a preference's summary to its value. More specifically, when the
80 | * preference's value is changed, its summary (line of text below the
81 | * preference title) is updated to reflect the value. The summary is also
82 | * immediately updated upon calling this method. The exact display format is
83 | * dependent on the type of preference.
84 | *
85 | * @see #sBindPreferenceSummaryToValueListener
86 | */
87 | private static void bindPreferenceSummaryToValue(Preference preference)
88 | {
89 | // Set the listener to watch for value changes.
90 | preference.setOnPreferenceChangeListener(sBindPreferenceSummaryToValueListener);
91 |
92 | // Trigger the listener immediately with the preference's
93 | // current value.
94 | sBindPreferenceSummaryToValueListener.onPreferenceChange(preference,
95 | PreferenceManager
96 | .getDefaultSharedPreferences(preference.getContext())
97 | .getString(preference.getKey(), ""));
98 | }
99 |
100 | @Override
101 | protected void onCreate(Bundle savedInstanceState)
102 | {
103 | super.onCreate(savedInstanceState);
104 | setupActionBar();
105 | }
106 |
107 | /**
108 | * Set up the {@link android.app.ActionBar}, if the API is available.
109 | */
110 | private void setupActionBar()
111 | {
112 | ActionBar actionBar = getSupportActionBar();
113 | if (actionBar != null) {
114 | // Show the Up button in the action bar.
115 | actionBar.setDisplayHomeAsUpEnabled(true);
116 | }
117 | }
118 |
119 | /**
120 | * {@inheritDoc}
121 | */
122 | @Override
123 | public boolean onIsMultiPane()
124 | {
125 | return isXLargeTablet(this);
126 | }
127 |
128 | /**
129 | * {@inheritDoc}
130 | */
131 | @Override
132 | @TargetApi(Build.VERSION_CODES.HONEYCOMB)
133 | public void onBuildHeaders(List target)
134 | {
135 | loadHeadersFromResource(R.xml.pref_headers, target);
136 | }
137 |
138 | /**
139 | * This method stops fragment injection in malicious applications.
140 | * Make sure to deny any unknown fragments here.
141 | */
142 | protected boolean isValidFragment(String fragmentName)
143 | {
144 | return PreferenceFragment.class.getName().equals(fragmentName)
145 | || ConnectionPreferenceFragment.class.getName().equals(fragmentName)
146 | || AboutFragment.class.getName().equals(fragmentName);
147 | }
148 |
149 | /**
150 | * This fragment shows connection preferences only. It is used when the
151 | * activity is showing a two-pane settings UI.
152 | */
153 | @TargetApi(Build.VERSION_CODES.HONEYCOMB)
154 | public static class ConnectionPreferenceFragment extends PreferenceFragment
155 | {
156 | @Override
157 | public void onCreate(Bundle savedInstanceState)
158 | {
159 | super.onCreate(savedInstanceState);
160 | addPreferencesFromResource(R.xml.pref_connection);
161 | setHasOptionsMenu(true);
162 |
163 | bindPreferenceSummaryToValue(findPreference("ip_address"));
164 | bindPreferenceSummaryToValue(findPreference("port"));
165 | }
166 | }
167 |
168 | /**
169 | * This fragment shows data and sync preferences only. It is used when the
170 | * activity is showing a two-pane settings UI.
171 | */
172 | @TargetApi(Build.VERSION_CODES.HONEYCOMB)
173 | public static class AboutFragment extends PreferenceFragment
174 | {
175 | @SuppressWarnings("PMD.EmptyCatchBlock")
176 | @Override
177 | public void onCreate(Bundle savedInstanceState)
178 | {
179 | super.onCreate(savedInstanceState);
180 | addPreferencesFromResource(R.xml.pref_about);
181 | setHasOptionsMenu(true);
182 |
183 | findPreference("author").setSummary(getResources().getString(R.string.author));
184 |
185 | PackageManager pManager = getActivity().getPackageManager();
186 |
187 | try
188 | {
189 | PackageInfo pInfo = pManager.getPackageInfo(getActivity().getPackageName(), 0);
190 | findPreference("version").setSummary(pInfo.versionName);
191 | } catch (PackageManager.NameNotFoundException e) { }
192 | }
193 | }
194 |
195 | @Override
196 | public boolean onOptionsItemSelected(MenuItem item)
197 | {
198 | int id = item.getItemId();
199 | if (id == android.R.id.home)
200 | {
201 | onBackPressed();
202 | return true;
203 | }
204 | return super.onOptionsItemSelected(item);
205 | }
206 | }
207 |
--------------------------------------------------------------------------------
/app/src/main/java/cz/jiriskorpil/amixerwebui/activity/DataHandler.java:
--------------------------------------------------------------------------------
1 | package cz.jiriskorpil.amixerwebui.activity;
2 |
3 | import android.content.Context;
4 | import android.content.SharedPreferences;
5 | import android.content.res.Configuration;
6 | import android.preference.PreferenceManager;
7 | import android.support.v4.widget.SwipeRefreshLayout;
8 | import android.support.v7.widget.GridLayoutManager;
9 | import android.support.v7.widget.RecyclerView;
10 | import android.util.Log;
11 | import android.view.MenuItem;
12 | import android.view.View;
13 | import android.widget.AdapterView;
14 | import android.widget.ArrayAdapter;
15 | import android.widget.Spinner;
16 |
17 | import org.json.JSONArray;
18 | import org.json.JSONException;
19 | import org.json.JSONObject;
20 |
21 | import java.util.ArrayList;
22 | import java.util.Iterator;
23 | import java.util.List;
24 |
25 | import cz.jiriskorpil.amixerwebui.R;
26 | import cz.jiriskorpil.amixerwebui.control.ControlContainer;
27 | import cz.jiriskorpil.amixerwebui.control.ControlContainerAdapter;
28 | import cz.jiriskorpil.amixerwebui.control.ControlParser;
29 | import cz.jiriskorpil.amixerwebui.control.Equalizer;
30 | import cz.jiriskorpil.amixerwebui.task.AsyncHttpRequestTask;
31 | import cz.jiriskorpil.amixerwebui.task.ChangeCardHttpRequestTask;
32 | import cz.jiriskorpil.amixerwebui.task.RetrieveCardHttpRequestTask;
33 | import cz.jiriskorpil.amixerwebui.task.RetrieveCardsHttpRequestTask;
34 | import cz.jiriskorpil.amixerwebui.task.RetrieveControlsHttpRequestTask;
35 | import cz.jiriskorpil.amixerwebui.task.RetrieveEqualizerHttpRequestTask;
36 | import cz.jiriskorpil.amixerwebui.task.RetrieveHostnameHttpRequestTask;
37 |
38 | /**
39 | * Class which supplies (main) activity with data.
40 | */
41 | public class DataHandler
42 | {
43 | private Context context;
44 | private OnFailListener mOnFailListener;
45 |
46 | /* GUI components */
47 | private RecyclerView listView;
48 | private SwipeRefreshLayout swipeRefreshLayout;
49 |
50 | private boolean downloadEnabled = true;
51 | private String lastUrl = "";
52 | private String cardId = "";
53 |
54 | private Equalizer equalizer;
55 |
56 | /**
57 | * @param context The context to use. Usually {@link android.app.Activity} object.
58 | * @param resultListView ListView for results
59 | * @param swipeRefreshLayout layout for results
60 | */
61 | DataHandler(Context context, RecyclerView resultListView, SwipeRefreshLayout swipeRefreshLayout)
62 | {
63 | this.context = context;
64 |
65 | this.listView = resultListView;
66 | this.listView.setHasFixedSize(true);
67 | this.listView.setLayoutManager(new GridLayoutManager(context, context.getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE ? 2 : 1, GridLayoutManager.VERTICAL, false));
68 |
69 | this.swipeRefreshLayout = swipeRefreshLayout;
70 | this.swipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener()
71 | {
72 | @Override
73 | public void onRefresh()
74 | {
75 | download();
76 | }
77 | });
78 | }
79 |
80 | /**
81 | * Creates request to download data
82 | * @return self
83 | */
84 | DataHandler download()
85 | {
86 | if (!downloadEnabled) {
87 | return this;
88 | }
89 | downloadEnabled = false;
90 |
91 | swipeRefreshLayout.post(new Runnable()
92 | {
93 | @Override
94 | public void run()
95 | {
96 | swipeRefreshLayout.setRefreshing(true);
97 | new RetrieveControlsHttpRequestTask(context, getBaseUrl(context), new AsyncHttpRequestTask.OnFinishListener()
98 | {
99 | @Override
100 | public void onFinish(String result)
101 | {
102 | try
103 | {
104 | downloadEnabled = true;
105 | lastUrl = getBaseUrl(context);
106 | displayData("".equals(result) ? null : new JSONArray(result));
107 | } catch (JSONException e) {
108 | Log.e("JSONException", "Error: " + e.toString());
109 | }
110 | }
111 | }).execute();
112 |
113 | if (!lastUrl.equals(getBaseUrl(context)))
114 | {
115 | cardId = "";
116 | setupHostname();
117 | setupSoundCards();
118 | }
119 | setupEqualizer();
120 | }
121 | });
122 | return this;
123 | }
124 |
125 | private void setupHostname()
126 | {
127 | final MainActivity activity = (MainActivity) context;
128 | if (activity.getSupportActionBar() != null) {
129 | activity.getSupportActionBar().setSubtitle("");
130 | }
131 |
132 | new RetrieveHostnameHttpRequestTask(context, getBaseUrl(context), new AsyncHttpRequestTask.OnFinishListener() {
133 | @Override
134 | public void onFinish(String result) {
135 | activity.getSupportActionBar().setSubtitle(result);
136 | }
137 | }).execute();
138 | }
139 |
140 | private void setupSoundCards()
141 | {
142 | final MenuItem soundCard = ((MainActivity) context).menu.findItem(R.id.action_card);
143 | soundCard.setVisible(false);
144 | new RetrieveCardsHttpRequestTask(context, getBaseUrl(context), new AsyncHttpRequestTask.OnFinishListener() {
145 | @Override
146 | public void onFinish(String result) {
147 | try
148 | {
149 | JSONObject cards = "[]".equals(result) ? new JSONObject() : (JSONObject) (new JSONArray("[" + result + "]")).get(0);
150 |
151 | if (cards.length() > 1) {
152 | soundCard.setVisible(true);
153 |
154 | final List cardIds = new ArrayList<>();
155 | List cardNames = new ArrayList<>();
156 |
157 | Iterator iter = cards.keys();
158 | while (iter.hasNext()) {
159 | String id = iter.next();
160 | cardNames.add((String) cards.get(id));
161 | cardIds.add(id);
162 | }
163 |
164 | final Spinner spinner = (Spinner) soundCard.getActionView();
165 | ArrayAdapter adapter = new ArrayAdapter<>(context, R.layout.spinner_item, cardNames);
166 | adapter.setDropDownViewResource(R.layout.spinner_dropdown_item);
167 | spinner.setAdapter(adapter);
168 |
169 | spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
170 | @Override
171 | public void onItemSelected(AdapterView> adapterView, View view, final int i, long l) {
172 | if (cardId.equals(cardIds.get(i)) || "".equals(cardId)) {
173 | return;
174 | }
175 |
176 | (new ChangeCardHttpRequestTask(context, getBaseUrl(context), new AsyncHttpRequestTask.OnFinishListener() {
177 | @Override
178 | public void onFinish(String result) {
179 | download();
180 | }
181 | })).execute(cardIds.get(i));
182 | cardId = cardIds.get(i);
183 | }
184 |
185 | @SuppressWarnings("PMD.UncommentedEmptyMethodBody")
186 | @Override
187 | public void onNothingSelected(AdapterView> adapterView) {
188 | }
189 | });
190 |
191 | new RetrieveCardHttpRequestTask(context, getBaseUrl(context), new AsyncHttpRequestTask.OnFinishListener() {
192 | @Override
193 | public void onFinish(String result) {
194 | cardId = result;
195 | spinner.setSelection(cardIds.indexOf(result), false);
196 | }
197 | }).execute();
198 | }
199 | } catch (JSONException e) {
200 | Log.e("JSONException", "Error: " + e.toString());
201 | }
202 | }
203 | }).execute();
204 | }
205 |
206 | void setupEqualizer()
207 | {
208 | final MainActivity activity = (MainActivity) context;
209 |
210 | new RetrieveEqualizerHttpRequestTask(context, getBaseUrl(context), new AsyncHttpRequestTask.OnFinishListener() {
211 | @Override
212 | public void onFinish(String result) {
213 | try
214 | {
215 | JSONArray data = new JSONArray(result);
216 | if (data.length() > 0) {
217 | activity.menu.findItem(R.id.action_equalizer).setVisible(true);
218 | equalizer = new Equalizer(result);
219 | }
220 | } catch (JSONException e) {
221 | Log.e("JSONException", "Error: " + e.toString());
222 | }
223 | }
224 | }).execute();
225 | }
226 |
227 | DataHandler setOnFailListener(OnFailListener listener)
228 | {
229 | mOnFailListener = listener;
230 | return this;
231 | }
232 |
233 | /**
234 | * Displays downloaded data.
235 | *
236 | * @param jsonArray JSON array representing controls retrieved from server
237 | */
238 | private void displayData(JSONArray jsonArray)
239 | {
240 | List controls = new ArrayList<>();
241 |
242 | if (jsonArray == null) {
243 | if (mOnFailListener != null) {
244 | mOnFailListener.onFail();
245 | lastUrl = "";
246 | cardId = "";
247 | }
248 | } else {
249 | controls = ControlParser.parse(jsonArray);
250 | }
251 |
252 | listView.setAdapter(new ControlContainerAdapter(context, controls));
253 | swipeRefreshLayout.setRefreshing(false);
254 | }
255 |
256 | /**
257 | * Returns base url to server (http://:)
258 | *
259 | * @return server url
260 | */
261 | public static String getBaseUrl(Context context)
262 | {
263 | SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context);
264 | String ipAddress = preferences.getString("ip_address", context.getResources().getString(R.string.pref_default_ip_address));
265 | String port = preferences.getString("port", context.getResources().getString(R.string.pref_default_port));
266 | return "http://" + ipAddress + ":" + port;
267 | }
268 |
269 | public Equalizer getEqualizer() {
270 | return equalizer;
271 | }
272 |
273 | interface OnFailListener
274 | {
275 | /**
276 | * Called when downloading failed.
277 | */
278 | void onFail();
279 | }
280 | }
281 |
--------------------------------------------------------------------------------
/app/src/main/java/cz/jiriskorpil/amixerwebui/control/ControlContainerAdapter.java:
--------------------------------------------------------------------------------
1 | package cz.jiriskorpil.amixerwebui.control;
2 |
3 | import android.app.Activity;
4 | import android.content.Context;
5 | import android.support.v7.widget.RecyclerView;
6 | import android.support.v7.widget.SwitchCompat;
7 | import android.view.LayoutInflater;
8 | import android.view.View;
9 | import android.view.ViewGroup;
10 | import android.widget.CheckBox;
11 | import android.widget.LinearLayout;
12 | import android.widget.RadioButton;
13 | import android.widget.RadioGroup;
14 | import android.widget.SeekBar;
15 | import android.widget.TextView;
16 | import android.widget.Toast;
17 |
18 | import java.util.List;
19 |
20 | import cz.jiriskorpil.amixerwebui.R;
21 | import cz.jiriskorpil.amixerwebui.activity.DataHandler;
22 | import cz.jiriskorpil.amixerwebui.task.ChangeSourceHttpRequestTask;
23 | import cz.jiriskorpil.amixerwebui.task.ChangeVolumeHttpRequestTask;
24 | import cz.jiriskorpil.amixerwebui.task.ToggleControlHttpRequestTask;
25 |
26 | /**
27 | * List adapter for control container.
28 | */
29 | public class ControlContainerAdapter extends RecyclerView.Adapter
30 | {
31 | private Context context;
32 | private List data = null;
33 |
34 | private static final float FULL_VISIBILITY = 1;
35 | private static final float LOW_VISIBILITY = (float) 0.4;
36 |
37 | /**
38 | * @param context The context to use. Usually {@link android.app.Activity} object.
39 | * @param data list of controls
40 | */
41 | public ControlContainerAdapter(Context context, List data)
42 | {
43 | this.context = context;
44 | this.data = data;
45 | }
46 |
47 | @Override
48 | public int getItemCount()
49 | {
50 | return data.size();
51 | }
52 |
53 | @Override
54 | public void onBindViewHolder(ControlContainerHolder holder, int i)
55 | {
56 | ControlContainer container = data.get(i);
57 |
58 | setupCard(container, holder);
59 | }
60 |
61 | @Override
62 | public ControlContainerHolder onCreateViewHolder(ViewGroup viewGroup, int i)
63 | {
64 | View itemView = LayoutInflater
65 | .from(viewGroup.getContext())
66 | .inflate(R.layout.control_row, viewGroup, false);
67 |
68 | return new ControlContainerHolder(itemView);
69 | }
70 |
71 | /**
72 | * Setups control card.
73 | *
74 | * @param container control container
75 | * @param holder control container holder
76 | */
77 | private void setupCard(ControlContainer container, ControlContainerHolder holder)
78 | {
79 | setupCardHeader(container, holder);
80 |
81 | setupCardBodySource(container, holder);
82 | setupCardBodyChannels(container, holder);
83 |
84 | setCardBodyAlpha(container, holder);
85 | }
86 |
87 | /**
88 | * Sets card body alpha color part based on boolean control value.
89 | *
90 | * @param container control container
91 | * @param holder control container holder
92 | */
93 | private void setCardBodyAlpha(ControlContainer container, ControlContainerHolder holder)
94 | {
95 | if (container.hasSwitchControl()) {
96 | if (container.getSwitch().isChecked())
97 | {
98 | holder.source_list.setAlpha(FULL_VISIBILITY);
99 | holder.channels_list.setAlpha(FULL_VISIBILITY);
100 | } else
101 | {
102 | holder.source_list.setAlpha(LOW_VISIBILITY);
103 | holder.channels_list.setAlpha(LOW_VISIBILITY);
104 | }
105 | }
106 | }
107 |
108 | /**
109 | * Changes boolean control value including initialize of request to server.
110 | *
111 | * @param container control container
112 | * @param holder control container holder
113 | * @param isChecked true if boolean control is checked else false
114 | */
115 | private void toggleControl(final ControlContainer container, final ControlContainerHolder holder, boolean isChecked)
116 | {
117 | container.getSwitch().setChecked(isChecked);
118 | setCardBodyAlpha(container, holder);
119 | new ToggleControlHttpRequestTask(holder.getView().getContext(), DataHandler.getBaseUrl(holder.getView().getContext()))
120 | .execute(String.valueOf(container.getSwitch().getId()), container.getSwitch().isChecked() ? "1" : "0");
121 | }
122 |
123 | /**
124 | * Setups card header (Switch, TextView and CheckBox values, settings and listeners).
125 | *
126 | * @param container control container
127 | * @param holder control container holder
128 | */
129 | private void setupCardHeader(final ControlContainer container, final ControlContainerHolder holder)
130 | {
131 | if (container.hasSwitchControl()) // set check value and add onClick listener
132 | {
133 | holder.enabled.setVisibility(View.VISIBLE);
134 | holder.enabled.setChecked(container.getSwitch().isChecked());
135 | holder.enabled.setOnClickListener(new View.OnClickListener()
136 | {
137 | @Override
138 | public void onClick(View v)
139 | {
140 | toggleControl(container, holder, holder.enabled.isChecked());
141 | }
142 | });
143 | holder.name.setOnClickListener(new View.OnClickListener()
144 | {
145 | @Override
146 | public void onClick(View v)
147 | {
148 | toggleControl(container, holder, !holder.enabled.isChecked());
149 | holder.enabled.setChecked(!holder.enabled.isChecked());
150 | }
151 | });
152 | } else { // or hide the switch
153 | holder.enabled.setVisibility(View.INVISIBLE);
154 | }
155 |
156 | holder.name.setText(container.getName());
157 |
158 | if (container.hasVolumeControl()) // if there is volume control then display bind checkbox and add listener
159 | {
160 | holder.bind_sliders.setVisibility(View.VISIBLE);
161 | holder.bind_sliders.setOnLongClickListener(new View.OnLongClickListener()
162 | {
163 | @Override
164 | public boolean onLongClick(View v)
165 | {
166 | Toast.makeText(holder.getView().getContext(),
167 | holder.getView().getContext().getResources().getString(holder.bind_sliders.isChecked() ? R.string.sliders_locked : R.string.sliders_unlocked),
168 | Toast.LENGTH_LONG).show();
169 | return true;
170 | }
171 | });
172 | } else {
173 | holder.bind_sliders.setVisibility(View.INVISIBLE);
174 | }
175 | }
176 |
177 | /**
178 | * Setups part of cards body - source radio buttons (values, settings and listeners).
179 | *
180 | * @param container control container
181 | * @param holder control container holder
182 | */
183 | private void setupCardBodySource(final ControlContainer container, final ControlContainerHolder holder)
184 | {
185 | holder.source_list.removeAllViews();
186 | if (container.hasSourceControl())
187 | {
188 | holder.source_list.setVisibility(View.VISIBLE);
189 | holder.source_list.check(0);
190 | for (int i = 0; i < container.getSource().getItems().length; i++)
191 | {
192 | final RadioButton button = new RadioButton(holder.getView().getContext());
193 | button.setId(i + 1);
194 | button.setText(container.getSource().getItems()[i]);
195 | button.setOnClickListener(new View.OnClickListener()
196 | {
197 | @Override
198 | public void onClick(View v)
199 | {
200 | container.getSource().setValue(holder.source_list.getCheckedRadioButtonId());
201 | new ChangeSourceHttpRequestTask(holder.getView().getContext(), DataHandler.getBaseUrl(holder.getView().getContext()))
202 | .execute(String.valueOf(container.getSource().getId()), String.valueOf(button.getId()));
203 | }
204 | });
205 | holder.source_list.addView(button);
206 | }
207 | holder.source_list.check(container.getSource().getValue() + 1);
208 | } else {
209 | holder.source_list.setVisibility(View.INVISIBLE);
210 | }
211 | }
212 |
213 | /**
214 | * Setups part of cards body - channels (values, settings nad listeners).
215 | *
216 | * @param container control container
217 | * @param holder control container holder
218 | */
219 | private void setupCardBodyChannels(final ControlContainer container, final ControlContainerHolder holder)
220 | {
221 | holder.channels_list.removeAllViews();
222 | if (container.hasVolumeControl())
223 | {
224 | for (int i = 0; i < container.getVolume().getChannels().length; i++)
225 | {
226 | LinearLayout channelLayout = (LinearLayout) holder.getView().findViewById(R.id.control_channel);
227 | View channelView = ((Activity) context).getLayoutInflater().inflate(R.layout.control_channel, channelLayout, false);
228 | holder.channels_list.addView(channelView, i);
229 |
230 | TextView channelName = (TextView) channelView.findViewById(R.id.channel_name);
231 | SeekBar channelVolumeSeekBar = (SeekBar) channelView.findViewById(R.id.channel_volume_seek_bar);
232 | final TextView channelVolume = (TextView) channelView.findViewById(R.id.channel_volume);
233 |
234 | final IChannel channel = container.getVolume().getChannels()[i];
235 |
236 | channelName.setText(channel.getName());
237 | channelVolumeSeekBar.setMax(channel.getControl().getMax());
238 | channelVolumeSeekBar.setProgress(channel.getValue());
239 | channelVolume.setText(holder.getView().getContext().getString(R.string.channel_value, Math.round(100 * (double) channel.getValue() / channel.getControl().getMax())));
240 |
241 | channelVolumeSeekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener()
242 | {
243 | @Override
244 | public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser)
245 | {
246 | String progressMsg = holder.getView().getContext().getString(R.string.channel_value, Math.round(100 * progress / seekBar.getMax()));
247 | if (fromUser && holder.bind_sliders.isChecked()) {
248 | for (int j = 0; j < container.getVolume().getChannels().length; j++) {
249 | if (!holder.channels_list.getChildAt(j).equals(seekBar))
250 | {
251 | container.getVolume().getChannels()[j].setValue(progress);
252 | View channelView = holder.channels_list.getChildAt(j);
253 | ((SeekBar) channelView.findViewById(R.id.channel_volume_seek_bar))
254 | .setProgress(progress);
255 | ((TextView) channelView.findViewById(R.id.channel_volume))
256 | .setText(progressMsg);
257 | }
258 | }
259 | }
260 | if (fromUser)
261 | {
262 | channel.setValue(progress);
263 | channelVolume.setText(progressMsg);
264 | }
265 | }
266 |
267 | @SuppressWarnings("PMD.UncommentedEmptyMethodBody")
268 | @Override
269 | public void onStartTrackingTouch(SeekBar seekBar)
270 | {
271 | }
272 |
273 | @Override
274 | public void onStopTrackingTouch(SeekBar seekBar)
275 | {
276 | String volumes = "";
277 | for (int j = 0; j < container.getVolume().getChannels().length; j++)
278 | {
279 | if (!"".equals(volumes)) {
280 | volumes += "/";
281 | }
282 | volumes += String.valueOf(container.getVolume().getChannels()[j].getValue());
283 | }
284 | new ChangeVolumeHttpRequestTask(holder.getView().getContext(), DataHandler.getBaseUrl(holder.getView().getContext()))
285 | .execute(String.valueOf(container.getVolume().getId()), volumes);
286 | }
287 | });
288 | }
289 | }
290 | }
291 |
292 | /**
293 | * Holds ControlContainer GUI controls.
294 | */
295 | static class ControlContainerHolder extends RecyclerView.ViewHolder
296 | {
297 | View v;
298 |
299 | SwitchCompat enabled;
300 | TextView name;
301 | CheckBox bind_sliders;
302 | RadioGroup source_list;
303 | LinearLayout channels_list;
304 |
305 | ControlContainerHolder(View v)
306 | {
307 | super(v);
308 | this.v = v;
309 | enabled = (SwitchCompat) v.findViewById(R.id.enabled);
310 | name = (TextView) v.findViewById(R.id.name);
311 | bind_sliders = (CheckBox) v.findViewById(R.id.bind_sliders);
312 | source_list = (RadioGroup) v.findViewById(R.id.source_list);
313 | channels_list = (LinearLayout) v.findViewById(R.id.channels_list);
314 | }
315 |
316 |
317 | public View getView()
318 | {
319 | return v;
320 | }
321 | }
322 | }
323 |
--------------------------------------------------------------------------------