Showing 85 changed files with 1552 additions and 0 deletions
+1
app/.gitignore
... ...
@@ -0,0 +1 @@
1
+/build
+38
app/build.gradle
... ...
@@ -0,0 +1,38 @@
1
+apply plugin: 'com.android.application'
2
+
3
+android {
4
+    compileSdkVersion 22
5
+    buildToolsVersion '25.0.0'
6
+
7
+    defaultConfig {
8
+        applicationId "com.yc.rss.radio"
9
+        minSdkVersion 19
10
+        targetSdkVersion 20
11
+        versionCode 20170617
12
+        versionName "1.0.17"
13
+    }
14
+    buildTypes {
15
+        release {
16
+            applicationIdSuffix ".release"
17
+            minifyEnabled true
18
+            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
19
+        }
20
+        debug {
21
+            applicationIdSuffix ".debug"
22
+            minifyEnabled false
23
+            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
24
+        }
25
+    }
26
+    dexOptions {
27
+        incremental true
28
+    }
29
+    compileOptions {
30
+        sourceCompatibility JavaVersion.VERSION_1_7
31
+        targetCompatibility JavaVersion.VERSION_1_7
32
+    }
33
+}
34
+
35
+dependencies {
36
+    compile fileTree(include: ['*.jar'], dir: 'libs')
37
+    compile 'com.android.support:appcompat-v7:22.2.1'
38
+}
+17
app/proguard-rules.pro
... ...
@@ -0,0 +1,17 @@
1
+# Add project specific ProGuard rules here.
2
+# By default, the flags in this file are appended to flags specified
3
+# in /home/cawidrone/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
+#}
+13
app/src/androidTest/java/com/yc/rss/radio/ApplicationTest.java
... ...
@@ -0,0 +1,13 @@
1
+package com.yc.rss.marianne;
2
+
3
+import android.app.Application;
4
+import android.test.ApplicationTestCase;
5
+
6
+/**
7
+ * <a href="http://d.android.com/tools/testing/testing_android.html">Testing Fundamentals</a>
8
+ */
9
+public class ApplicationTest extends ApplicationTestCase<Application> {
10
+    public ApplicationTest() {
11
+        super(Application.class);
12
+    }
13
+}
+26
app/src/main/AndroidManifest.xml
... ...
@@ -0,0 +1,26 @@
1
+<?xml version="1.0" encoding="utf-8"?>
2
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
3
+    package="com.yc.rss.radio">
4
+    <uses-permission android:name="android.permission.INTERNET" />
5
+    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
6
+    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
7
+
8
+    <application
9
+        android:allowBackup="true"
10
+        android:icon="@mipmap/ic_launcher"
11
+        android:logo="@drawable/ic_launcher"
12
+        android:label="@string/app_name"
13
+        android:theme="@style/AppTheme"
14
+        android:hardwareAccelerated="true"
15
+        android:screenOrientation="portrait" >
16
+        <activity
17
+            android:name=".MainActivity"
18
+            android:label="@string/app_name" >
19
+
20
+            <intent-filter>
21
+                <action android:name="android.intent.action.MAIN" />
22
+                <category android:name="android.intent.category.LAUNCHER" />
23
+            </intent-filter>
24
+        </activity>
25
+    </application>
26
+</manifest>
BIN
app/src/main/assets/bassdrive.png
BIN
app/src/main/assets/bbcws.png
BIN
app/src/main/assets/caribbean.png
BIN
app/src/main/assets/classic21.png
BIN
app/src/main/assets/covers.png
BIN
app/src/main/assets/europe1.png
BIN
app/src/main/assets/fculture.png
BIN
app/src/main/assets/finfo.png
BIN
app/src/main/assets/finter.png
BIN
app/src/main/assets/fipradio.png
BIN
app/src/main/assets/flemme.png
BIN
app/src/main/assets/fmusique.png
BIN
app/src/main/assets/groovesalad.png
BIN
app/src/main/assets/lemouv.png
BIN
app/src/main/assets/lgrmetal.png
BIN
app/src/main/assets/lgrreggae.png
BIN
app/src/main/assets/lgrrock.png
BIN
app/src/main/assets/loading.gif
+161
app/src/main/assets/radio-local.xml
... ...
@@ -0,0 +1,161 @@
1
+<?xml version='1.0' encoding='UTF-8'?>
2
+<channel_list>
3
+    <channel>
4
+        <item>
5
+            <title>France Info</title>
6
+            <mp3>https://files.kawi.fr:8000/finfo</mp3>
7
+            <shortname>finfo</shortname>
8
+            <icy>0</icy>
9
+        </item>
10
+        <item>
11
+            <title>France Inter</title>
12
+            <mp3>https://files.kawi.fr:8000/finter</mp3>
13
+            <shortname>finter</shortname>
14
+            <icy>0</icy>
15
+        </item>
16
+        <item>
17
+            <title>France Culture</title>
18
+            <mp3>https://files.kawi.fr:8000/fculture</mp3>
19
+            <shortname>fculture</shortname>
20
+            <icy>0</icy>
21
+        </item>
22
+        <item>
23
+            <title>France Musique</title>
24
+            <mp3>https://files.kawi.fr:8000/fmusique128</mp3>
25
+            <shortname>fmusique</shortname>
26
+            <icy>0</icy>
27
+        </item>
28
+        <item>
29
+            <title>Le Mouv</title>
30
+            <mp3>https://files.kawi.fr:8000/lemouv128</mp3>
31
+            <shortname>lemouv</shortname>
32
+            <icy>0</icy>
33
+        </item>
34
+        <item>
35
+            <title>RFI Monde</title>
36
+            <mp3>https://files.kawi.fr:8000/rfi</mp3>
37
+            <shortname>rfi</shortname>
38
+            <icy>0</icy>
39
+        </item>
40
+        <item>
41
+            <title>Europe 1</title>
42
+            <mp3>https://files.kawi.fr:8000/europe1</mp3>
43
+            <shortname>europe1</shortname>
44
+            <icy>1</icy>
45
+        </item>
46
+        <item>
47
+            <title>Radio Classique</title>
48
+            <mp3>https://files.kawi.fr:8000/radioclassique</mp3>
49
+            <shortname>radio_classique</shortname>
50
+            <icy>1</icy>
51
+        </item>
52
+        <item>
53
+            <title>FIP</title>
54
+            <mp3>https://files.kawi.fr:8000/fip128</mp3>
55
+            <shortname>fipradio</shortname>
56
+            <icy>0</icy>
57
+        </item>
58
+        <item>
59
+            <title>Classic 21</title>
60
+            <mp3>https://files.kawi.fr:8000/classic21</mp3>
61
+            <shortname>classic21</shortname>
62
+            <icy>0</icy>
63
+        </item>
64
+        <item>
65
+            <title>Radio Nova</title>
66
+            <mp3>https://files.kawi.fr:8000/nova128</mp3>
67
+            <shortname>radio_nova</shortname>
68
+            <icy>0</icy>
69
+        </item>
70
+        <item>
71
+            <title>Suburbs of Goa (SomaFM)</title>
72
+            <mp3>https://files.kawi.fr:8000/suburbsofgoa</mp3>
73
+            <shortname>suburbsofgoa</shortname>
74
+            <icy>1</icy>
75
+        </item>
76
+        <item>
77
+            <title>Groove Salad (SomaFM)</title>
78
+            <mp3>https://files.kawi.fr:8000/groovesalad</mp3>
79
+            <shortname>groovesalad</shortname>
80
+            <icy>1</icy>
81
+        </item>
82
+        <item>
83
+            <title>Covers (SomaFM)</title>
84
+            <mp3>https://files.kawi.fr:8000/covers</mp3>
85
+            <shortname>covers</shortname>
86
+            <icy>1</icy>
87
+        </item>
88
+        <item>
89
+            <title>La Grosse Radio Rock</title>
90
+            <mp3>https://files.kawi.fr:8000/lgrrock</mp3>
91
+            <shortname>lgrrock</shortname>
92
+            <icy>1</icy>
93
+        </item>
94
+        <item>
95
+            <title>La Grosse Radio Metal</title>
96
+            <mp3>https://files.kawi.fr:8000/lgrmetal</mp3>
97
+            <shortname>lgrmetal</shortname>
98
+            <icy>1</icy>
99
+        </item>
100
+        <item>
101
+            <title>La Grosse Radio Reggae</title>
102
+            <mp3>https://files.kawi.fr:8000/lgrreggae</mp3>
103
+            <shortname>lgrreggae</shortname>
104
+            <icy>1</icy>
105
+        </item>
106
+        <item>
107
+            <title>Caribbean Reggae</title>
108
+            <mp3>https://files.kawi.fr:8000/caribbean</mp3>
109
+            <shortname>caribbean</shortname>
110
+            <icy>1</icy>
111
+        </item>
112
+        <item>
113
+            <title>Bassdrive</title>
114
+            <mp3>https://files.kawi.fr:8000/bassdrive</mp3>
115
+            <shortname>bassdrive</shortname>
116
+            <icy>1</icy>
117
+        </item>
118
+        <item>
119
+            <title>Stellar Attraction</title>
120
+            <mp3>https://files.kawi.fr:8000/stellar</mp3>
121
+            <shortname>stellar</shortname>
122
+            <icy>1</icy>
123
+        </item>
124
+        <item>
125
+            <title>BBC WS</title>
126
+            <mp3>https://files.kawi.fr:8000/bbcws</mp3>
127
+            <shortname>bbcws</shortname>
128
+            <icy>1</icy>
129
+        </item>
130
+        <item>
131
+            <title>Renegade Radio UK</title>
132
+            <mp3>https://files.kawi.fr:8000/rruk</mp3>
133
+            <shortname>rruk</shortname>
134
+            <icy>1</icy>
135
+        </item>
136
+        <item>
137
+            <title>Radio Flemme</title>
138
+            <mp3>https://files.kawi.fr:8000/flemme</mp3>
139
+            <shortname>flemme</shortname>
140
+            <icy>0</icy>
141
+        </item>
142
+        <item>
143
+            <title>Reggae World Crew</title>
144
+            <mp3>https://files.kawi.fr:8000/reggaewc</mp3>
145
+            <shortname>reggaewc</shortname>
146
+            <icy>1</icy>
147
+        </item>
148
+        <item>
149
+            <title>Trap.fm</title>
150
+            <mp3>https://files.kawi.fr:8000/trapfm</mp3>
151
+            <shortname>trapfm</shortname>
152
+            <icy>1</icy>
153
+        </item>
154
+        <item>
155
+            <title>Reggae World Music</title>
156
+            <mp3>https://files.kawi.fr:8000/reggaeworldmusic</mp3>
157
+            <shortname>reggaeworldmusic</shortname>
158
+            <icy>1</icy>
159
+        </item>
160
+    </channel>
161
+</channel_list>
BIN
app/src/main/assets/radio.ico
Binary file not shown.
+161
app/src/main/assets/radio.xml
... ...
@@ -0,0 +1,161 @@
1
+<?xml version='1.0' encoding='UTF-8'?>
2
+<channel_list>
3
+    <channel>
4
+        <item>
5
+            <title>France Info</title>
6
+            <mp3>http://direct.franceinfo.fr:80/live/franceinfo-lofi.mp3</mp3>
7
+            <shortname>finfo</shortname>
8
+            <icy>0</icy>
9
+        </item>
10
+        <item>
11
+            <title>France Inter</title>
12
+            <mp3>http://direct.franceinter.fr:80/live/franceinter-lofi.mp3</mp3>
13
+            <shortname>finter</shortname>
14
+            <icy>0</icy>
15
+        </item>
16
+        <item>
17
+            <title>France Culture</title>
18
+            <mp3>http://direct.franceculture.fr:80/live/franceculture-lofi.mp3</mp3>
19
+            <shortname>fculture</shortname>
20
+            <icy>0</icy>
21
+        </item>
22
+        <item>
23
+            <title>France Musique</title>
24
+            <mp3>http://direct.francemusique.fr:80/live/francemusique-midfi.mp3</mp3>
25
+            <shortname>fmusique</shortname>
26
+            <icy>0</icy>
27
+        </item>
28
+        <item>
29
+            <title>Le Mouv</title>
30
+            <mp3>http://direct.mouv.fr:80/live/mouv-midfi.mp3</mp3>
31
+            <shortname>lemouv</shortname>
32
+            <icy>0</icy>
33
+        </item>
34
+        <item>
35
+            <title>RFI Monde</title>
36
+            <mp3>http://live02.rfi.fr:80/rfimonde-64.mp3</mp3>
37
+            <shortname>rfi</shortname>
38
+            <icy>0</icy>
39
+        </item>
40
+        <item>
41
+            <title>Europe 1</title>
42
+            <mp3>http://e1-live-mp3-64.scdn.arkena.com:64/europe1.mp3</mp3>
43
+            <shortname>europe1</shortname>
44
+            <icy>1</icy>
45
+        </item>
46
+        <item>
47
+            <title>Radio Classique</title>
48
+            <mp3>http://radioclassique.ice.infomaniak.ch:80/radioclassique-high.mp3</mp3>
49
+            <shortname>radio_classique</shortname>
50
+            <icy>1</icy>
51
+        </item>
52
+        <item>
53
+            <title>FIP</title>
54
+            <mp3>http://direct.fipradio.fr:80/live/fip-midfi.mp3</mp3>
55
+            <shortname>fipradio</shortname>
56
+            <icy>0</icy>
57
+        </item>
58
+        <item>
59
+            <title>Classic 21</title>
60
+            <mp3>http://classic21.ice.rtbf.be:80/classic21-128.mp3</mp3>
61
+            <shortname>classic21</shortname>
62
+            <icy>0</icy>
63
+        </item>
64
+        <item>
65
+            <title>Radio Nova</title>
66
+            <mp3>http://novazz.ice.infomaniak.ch:80/novazz-128.mp3</mp3>
67
+            <shortname>radio_nova</shortname>
68
+            <icy>0</icy>
69
+        </item>
70
+        <item>
71
+            <title>Suburbs of Goa (SomaFM)</title>
72
+            <mp3>http://ice1.somafm.com:80/suburbsofgoa-128-mp3</mp3>
73
+            <shortname>suburbsofgoa</shortname>
74
+            <icy>1</icy>
75
+        </item>
76
+        <item>
77
+            <title>Groove Salad (SomaFM)</title>
78
+            <mp3>http://ice1.somafm.com:80/groovesalad-128-mp3</mp3>
79
+            <shortname>groovesalad</shortname>
80
+            <icy>1</icy>
81
+        </item>
82
+        <item>
83
+            <title>Covers (SomaFM)</title>
84
+            <mp3>http://ice1.somafm.com:80/covers-128-mp3</mp3>
85
+            <shortname>covers</shortname>
86
+            <icy>1</icy>
87
+        </item>
88
+        <item>
89
+            <title>La Grosse Radio Rock</title>
90
+            <mp3>http://hd.lagrosseradio.info:80/lagrosseradio-rock-064.mp3</mp3>
91
+            <shortname>lgrrock</shortname>
92
+            <icy>1</icy>
93
+        </item>
94
+        <item>
95
+            <title>La Grosse Radio Metal</title>
96
+            <mp3>http://hd.lagrosseradio.info:80/lagrosseradio-metal-064.mp3</mp3>
97
+            <shortname>lgrmetal</shortname>
98
+            <icy>1</icy>
99
+        </item>
100
+        <item>
101
+            <title>La Grosse Radio Reggae</title>
102
+            <mp3>http://hd.lagrosseradio.info:80/lagrosseradio-reggae-064.mp3</mp3>
103
+            <shortname>lgrreggae</shortname>
104
+            <icy>1</icy>
105
+        </item>
106
+        <item>
107
+            <title>Caribbean Reggae</title>
108
+            <mp3>http://strm112.1.fm:80/reggae_mobile_mp3</mp3>
109
+            <shortname>caribbean</shortname>
110
+            <icy>1</icy>
111
+        </item>
112
+        <item>
113
+            <title>Bassdrive</title>
114
+            <mp3>http://amsterdam2.shouthost.com.streams.bassdrive.com:8000/;stream.mp3</mp3>
115
+            <shortname>bassdrive</shortname>
116
+            <icy>1</icy>
117
+        </item>
118
+        <item>
119
+            <title>Stellar Attraction</title>
120
+            <mp3>http://77.68.36.137:8000/stream</mp3>
121
+            <shortname>stellar</shortname>
122
+            <icy>1</icy>
123
+        </item>
124
+        <item>
125
+            <title>BBC WS</title>
126
+            <mp3>http://bbcwssc.ic.llnwd.net:80/stream/bbcwssc_mp1_ws-eieuk</mp3>
127
+            <shortname>bbcws</shortname>
128
+            <icy>1</icy>
129
+        </item>
130
+        <item>
131
+            <title>Renegade Radio UK</title>
132
+            <mp3>http://69.30.213.131:80/stream</mp3>
133
+            <shortname>rruk</shortname>
134
+            <icy>1</icy>
135
+        </item>
136
+        <item>
137
+            <title>Radio Flemme</title>
138
+            <mp3>http://str45.streamakaci.com:8014/;895614762790501stream.nsv</mp3>
139
+            <shortname>flemme</shortname>
140
+            <icy>0</icy>
141
+        </item>
142
+        <item>
143
+            <title>Reggae World Crew</title>
144
+            <mp3>http://67.212.189.122:8042/;stream.nsv&amp;type=mp3</mp3>
145
+            <shortname>reggaewc</shortname>
146
+            <icy>1</icy>
147
+        </item>
148
+        <item>
149
+            <title>Trap.fm</title>
150
+            <mp3>http://stream.trap.fm:6004/;stream.mp3</mp3>
151
+            <shortname>trapfm</shortname>
152
+            <icy>1</icy>
153
+        </item>
154
+        <item>
155
+            <title>Reggae World Music</title>
156
+            <mp3>http://s10.whooshclouds.net:8072/live?type=.mp3</mp3>
157
+            <shortname>reggaeworldmusic</shortname>
158
+            <icy>1</icy>
159
+        </item>
160
+    </channel>
161
+</channel_list>
BIN
app/src/main/assets/radio_classique.png
BIN
app/src/main/assets/radio_nova.png
BIN
app/src/main/assets/reggaewc.png
BIN
app/src/main/assets/reggaeworldmusic.png
BIN
app/src/main/assets/rfi.png
BIN
app/src/main/assets/rruk.png
BIN
app/src/main/assets/stellar.png
BIN
app/src/main/assets/suburbsofgoa.png
BIN
app/src/main/assets/trapfm.png
BIN
app/src/main/assets/unknown.png
+120
app/src/main/java/com/yc/rss/radio/Entry.java
... ...
@@ -0,0 +1,120 @@
1
+package com.yc.rss.radio;
2
+
3
+import org.xmlpull.v1.XmlPullParser;
4
+import org.xmlpull.v1.XmlPullParserException;
5
+
6
+import java.io.IOException;
7
+
8
+/**
9
+ * Created by yc on 8/13/15.
10
+ * https://developer.android.com/training/basics/network-ops/xml.html
11
+ */
12
+/*
13
+<channel>
14
+	<title>France Info</title>
15
+	<mp3>https://files.kawi.fr:8000/finfo64</mp3>
16
+	<shortname>finfo</shortname>
17
+	<icy>0</icy>
18
+</channel>
19
+ */
20
+public class Entry {
21
+    public final String title;
22
+    public final String mp3;
23
+    public final String shortname;
24
+    public final String icy;
25
+    public static final String ns = null;
26
+
27
+    public Entry(String title, String mp3, String shortname, String icy) {
28
+        this.title = title;
29
+        this.mp3 = mp3;
30
+        this.shortname = shortname;
31
+        this.icy = icy;
32
+    }
33
+
34
+    // Parses the contents of an entry. If it encounters a title, summary, or link tag, hands them off
35
+    // to their respective "read" methods for processing. Otherwise, skips the tag.
36
+    public static Entry readItem(XmlPullParser parser) throws XmlPullParserException, IOException {
37
+        parser.require(XmlPullParser.START_TAG, ns, "item");
38
+        String title = null;
39
+        String mp3 = null;
40
+        String shortname = null;
41
+        String icy = null;
42
+        while (parser.next() != XmlPullParser.END_TAG) {
43
+            if (parser.getEventType() != XmlPullParser.START_TAG) {
44
+                continue;
45
+            }
46
+            String name = parser.getName();
47
+            if (name.equals("title")) {
48
+                title = readTitle(parser);
49
+            } else if (name.equals("mp3")) {
50
+                mp3 = readMp3(parser);
51
+            } else if (name.equals("shortname")) {
52
+                shortname = readShortname(parser);
53
+            } else if (name.equals("icy")) {
54
+                icy = readIcy(parser);
55
+            } else {
56
+                skip(parser);
57
+            }
58
+        }
59
+        return new Entry(title, mp3, shortname, icy);
60
+    }
61
+
62
+    // Processes title tags in the feed.
63
+    public static String readTitle(XmlPullParser parser) throws IOException, XmlPullParserException {
64
+        parser.require(XmlPullParser.START_TAG, ns, "title");
65
+        String title = readText(parser);
66
+        parser.require(XmlPullParser.END_TAG, ns, "title");
67
+        return title;
68
+    }
69
+
70
+    // Processes category tags in the feed.
71
+    public static String readMp3(XmlPullParser parser) throws IOException, XmlPullParserException {
72
+        parser.require(XmlPullParser.START_TAG, ns, "mp3");
73
+        String mp3 = readText(parser);
74
+        parser.require(XmlPullParser.END_TAG, ns, "mp3");
75
+        return mp3;
76
+    }
77
+
78
+    // Processes link tags in the feed.
79
+    public static String readShortname(XmlPullParser parser) throws IOException, XmlPullParserException {
80
+        parser.require(XmlPullParser.START_TAG, ns, "shortname");
81
+        String shortname = readText(parser);
82
+        parser.require(XmlPullParser.END_TAG, ns, "shortname");
83
+        return shortname;
84
+    }
85
+
86
+    // Processes summary tags in the feed.
87
+    public static String readIcy(XmlPullParser parser) throws IOException, XmlPullParserException {
88
+        parser.require(XmlPullParser.START_TAG, ns, "icy");
89
+        String icy = readText(parser);
90
+        parser.require(XmlPullParser.END_TAG, ns, "icy");
91
+        return icy;
92
+    }
93
+
94
+    // For the tags title and summary, extracts their text values.
95
+    public static String readText(XmlPullParser parser) throws IOException, XmlPullParserException {
96
+        String result = "";
97
+        if (parser.next() == XmlPullParser.TEXT) {
98
+            result = parser.getText();
99
+            parser.nextTag();
100
+        }
101
+        return result;
102
+    }
103
+
104
+    public static void skip(XmlPullParser parser) throws XmlPullParserException, IOException {
105
+        if (parser.getEventType() != XmlPullParser.START_TAG) {
106
+            throw new IllegalStateException();
107
+        }
108
+        int depth = 1;
109
+        while (depth != 0) {
110
+            switch (parser.next()) {
111
+                case XmlPullParser.END_TAG:
112
+                    depth--;
113
+                    break;
114
+                case XmlPullParser.START_TAG:
115
+                    depth++;
116
+                    break;
117
+            }
118
+        }
119
+    }
120
+}
+128
app/src/main/java/com/yc/rss/radio/EntryTag.java
... ...
@@ -0,0 +1,128 @@
1
+package com.yc.rss.radio;
2
+
3
+import android.util.Log;
4
+
5
+import org.xmlpull.v1.XmlPullParser;
6
+import org.xmlpull.v1.XmlPullParserException;
7
+
8
+import java.io.IOException;
9
+
10
+/**
11
+ * Created by yc on 8/13/15.
12
+ * https://developer.android.com/training/basics/network-ops/xml.html
13
+ */
14
+/*
15
+<channel>
16
+	<title>France Info</title>
17
+	<mp3>https://files.kawi.fr:8000/finfo64</mp3>
18
+	<shortname>finfo</shortname>
19
+	<icy>0</icy>
20
+</channel>
21
+ */
22
+public class EntryTag {
23
+    public String title;
24
+    public String shortname;
25
+    public String track_title;
26
+    public String track_artist;
27
+    public String track_url;
28
+    public String cover = null;
29
+    public static final String ns = null;
30
+
31
+    public EntryTag(String title, String shortname, String track_title, String track_artist, String track_url, String cover) {
32
+        this.title = title;
33
+        this.shortname = shortname;
34
+        this.track_title = track_title;
35
+        this.track_artist = track_artist;
36
+        this.track_url = track_url;
37
+        this.cover = cover;
38
+    }
39
+
40
+    public static EntryTag readItem(XmlPullParser parser) throws XmlPullParserException, IOException {
41
+        parser.require(XmlPullParser.START_TAG, ns, "channel");
42
+        String title = null;
43
+        String shortname = null;
44
+        String track_title = null;
45
+        String track_artist = null;
46
+        String track_url = null;
47
+        String cover = null;
48
+        while (parser.next() != XmlPullParser.END_TAG) {
49
+            if (parser.getEventType() != XmlPullParser.START_TAG) {
50
+                continue;
51
+            }
52
+            String name = parser.getName();
53
+            if (name.equals("title")) {
54
+                title = readTitle(parser);
55
+            } else if (name.equals("shortname")) {
56
+                shortname = readShortname(parser);
57
+            } else if (name.equals("track_title")) {
58
+                track_title = readTrackTitle(parser);
59
+            } else if (name.equals("track_artist")) {
60
+                track_artist = readTrackArtist(parser);
61
+            } else if (name.equals("track_url")) {
62
+                track_url = readTrackURL(parser);
63
+            } else {
64
+                skip(parser);
65
+            }
66
+        }
67
+        return new EntryTag(title, shortname, track_title, track_artist, track_url, cover);
68
+    }
69
+
70
+    public static String readTitle(XmlPullParser parser) throws IOException, XmlPullParserException {
71
+        parser.require(XmlPullParser.START_TAG, ns, "title");
72
+        String title = readText(parser);
73
+        parser.require(XmlPullParser.END_TAG, ns, "title");
74
+        return title;
75
+    }
76
+
77
+    public static String readShortname(XmlPullParser parser) throws IOException, XmlPullParserException {
78
+        parser.require(XmlPullParser.START_TAG, ns, "shortname");
79
+        String shortname = readText(parser);
80
+        parser.require(XmlPullParser.END_TAG, ns, "shortname");
81
+        return shortname;
82
+    }
83
+
84
+    public static String readTrackTitle(XmlPullParser parser) throws IOException, XmlPullParserException {
85
+        parser.require(XmlPullParser.START_TAG, ns, "track_title");
86
+        String icy = readText(parser);
87
+        parser.require(XmlPullParser.END_TAG, ns, "track_title");
88
+        return icy;
89
+    }
90
+    public static String readTrackArtist(XmlPullParser parser) throws IOException, XmlPullParserException {
91
+        parser.require(XmlPullParser.START_TAG, ns, "track_artist");
92
+        String icy = readText(parser);
93
+        parser.require(XmlPullParser.END_TAG, ns, "track_artist");
94
+        return icy;
95
+    }
96
+    public static String readTrackURL(XmlPullParser parser) throws IOException, XmlPullParserException {
97
+        parser.require(XmlPullParser.START_TAG, ns, "track_url");
98
+        String icy = readText(parser);
99
+        parser.require(XmlPullParser.END_TAG, ns, "track_url");
100
+        return icy;
101
+    }
102
+
103
+    public static String readText(XmlPullParser parser) throws IOException, XmlPullParserException {
104
+        String result = "";
105
+        if (parser.next() == XmlPullParser.TEXT) {
106
+            result = parser.getText();
107
+            parser.nextTag();
108
+        }
109
+        return result;
110
+    }
111
+
112
+    public static void skip(XmlPullParser parser) throws XmlPullParserException, IOException {
113
+        if (parser.getEventType() != XmlPullParser.START_TAG) {
114
+            throw new IllegalStateException();
115
+        }
116
+        int depth = 1;
117
+        while (depth != 0) {
118
+            switch (parser.next()) {
119
+                case XmlPullParser.END_TAG:
120
+                    depth--;
121
+                    break;
122
+                case XmlPullParser.START_TAG:
123
+                    depth++;
124
+                    break;
125
+            }
126
+        }
127
+    }
128
+}
+598
app/src/main/java/com/yc/rss/radio/MainActivity.java
... ...
@@ -0,0 +1,598 @@
1
+package com.yc.rss.radio;
2
+
3
+import android.app.Activity;
4
+import android.app.IntentService;
5
+import android.app.Notification;
6
+import android.app.NotificationManager;
7
+import android.app.PendingIntent;
8
+import android.app.ProgressDialog;
9
+import android.content.Intent;
10
+import android.content.res.AssetManager;
11
+import android.graphics.Bitmap;
12
+import android.graphics.BitmapFactory;
13
+import android.graphics.Canvas;
14
+import android.graphics.Point;
15
+import android.graphics.drawable.BitmapDrawable;
16
+import android.media.AudioManager;
17
+import android.media.MediaPlayer;
18
+import android.os.AsyncTask;
19
+import android.os.Build;
20
+import android.os.Bundle;
21
+import android.os.Environment;
22
+import android.os.Handler;
23
+import android.os.Message;
24
+import android.support.v7.app.AppCompatActivity;
25
+import android.support.v7.app.NotificationCompat;
26
+import android.util.Log;
27
+import android.view.Display;
28
+import android.view.Menu;
29
+import android.view.MenuItem;
30
+import android.view.View;
31
+import android.webkit.WebSettings;
32
+import android.webkit.WebView;
33
+import android.widget.ImageView;
34
+import android.widget.ArrayAdapter;
35
+import android.widget.ScrollView;
36
+import android.widget.TextView;
37
+import android.widget.Spinner;
38
+import android.graphics.drawable.Drawable;
39
+import android.widget.Toast;
40
+
41
+import org.xmlpull.v1.XmlPullParserException;
42
+
43
+import java.io.BufferedInputStream;
44
+import java.io.ByteArrayInputStream;
45
+import java.io.File;
46
+import java.io.FileOutputStream;
47
+import java.io.IOException;
48
+import java.io.InputStream;
49
+import java.io.OutputStream;
50
+import java.net.HttpURLConnection;
51
+import java.net.URL;
52
+import java.net.URLConnection;
53
+import java.nio.charset.StandardCharsets;
54
+import java.util.ArrayList;
55
+import java.util.HashSet;
56
+import java.util.List;
57
+
58
+public class MainActivity extends AppCompatActivity {
59
+    private ImageView mImageView;
60
+    private ImageView mCoverView;
61
+    private TextView mTextView;
62
+    private TextView mTextViewArtist;
63
+    private TextView mTextViewTitle;
64
+    public static String articles;
65
+    private Spinner spinArticle;
66
+    private List<Entry> entries = null;
67
+    public List<EntryTag> entries_tag = null;
68
+    private int entries_sz = -1;
69
+    public int entries_tag_sz = -1;
70
+    private ProgressDialog pDialog;
71
+    private DownloadFileFromURL mDownloadTags = null;
72
+    private DownloadCoverFromURL mDownloadCover = null;
73
+    private MediaPlayer mediaPlayer = null;
74
+    private int current_pos = -1;
75
+    private boolean initialState = true;
76
+    private boolean initialNoTag = true;
77
+    private static final int RADIO_NOTIFICATION=9999;
78
+    public static final String ACTION_1 = "action_1";
79
+    public static final String ACTION_2 = "action_2";
80
+    public static final String ACTION_3 = "action_3";
81
+    public static final String ACTION_4 = "action_4";
82
+
83
+    private String old_title="";
84
+    private String old_artist="";
85
+    final Intent intentClick = null;
86
+
87
+    public List<EntryTag> getTags() {
88
+        return entries_tag;
89
+    }
90
+
91
+    private Handler iSender = new Handler() {
92
+        @Override
93
+        public void handleMessage(final Message msg) {
94
+            System.out.println("iSender");
95
+            mDownloadTags = (DownloadFileFromURL) new DownloadFileFromURL().execute(getString(R.string.tags_url));
96
+            iSender.sendEmptyMessageDelayed(0, 30*1000);
97
+        }
98
+    };
99
+
100
+    class DownloadFileFromURL extends AsyncTask<String, String, String> {
101
+        private String page_content;
102
+
103
+        @Override
104
+        protected void onPreExecute() {
105
+            super.onPreExecute();
106
+            System.out.println("Starting download");
107
+            /*
108
+            pDialog = new ProgressDialog(MainActivity.this);
109
+            pDialog.setMessage("Loading... Please wait...");
110
+            pDialog.setIndeterminate(false);
111
+            pDialog.setCancelable(false);
112
+            pDialog.show();
113
+            */
114
+        }
115
+
116
+        @Override
117
+        protected String doInBackground(String... f_url) {
118
+            int count;
119
+            try {
120
+                URL url = new URL(f_url[0]);
121
+                HttpURLConnection conn = (HttpURLConnection) url.openConnection();
122
+                conn.setReadTimeout(10000 /* milliseconds */);
123
+                conn.setConnectTimeout(15000 /* milliseconds */);
124
+                conn.setRequestMethod("GET");
125
+                conn.setDoInput(true);
126
+                conn.connect();
127
+                InputStream stream = conn.getInputStream();
128
+                StringBuilder page_content_builder = new StringBuilder();
129
+                byte data[] = new byte[65536];
130
+                while ((count = stream.read(data)) != -1) {
131
+                    String str = new String(data, "UTF-8");
132
+                    page_content_builder.append(str);
133
+                }
134
+                page_content = page_content_builder.toString();
135
+            } catch (Exception e) {
136
+                Log.e("Error: ", e.getMessage());
137
+            }
138
+            return null;
139
+        }
140
+
141
+        @Override
142
+        protected void onPostExecute(String file_url) {
143
+            System.out.println("Downloaded");
144
+            //pDialog.dismiss();
145
+            try {
146
+                TagsXmlParser tagsXmlParser = new TagsXmlParser();
147
+                InputStream stream = new ByteArrayInputStream(page_content.getBytes(StandardCharsets.UTF_8));
148
+                entries_tag = tagsXmlParser.parse(stream);
149
+                entries_tag_sz = entries_tag.size();
150
+            } catch (IOException ignored) {
151
+                entries_tag = null;
152
+                entries_tag_sz = -1;
153
+            } catch (XmlPullParserException ignored) {
154
+                entries_tag = null;
155
+                entries_tag_sz = -1;
156
+            }
157
+            if(true == initialNoTag ) {
158
+                initialNoTag = false;
159
+                ToastThis(getString(R.string.tags_downloaded));
160
+            }
161
+            ExtUpdate();
162
+        }
163
+    }
164
+
165
+    class DownloadCoverFromURL extends AsyncTask<String, String, String> {
166
+        private String page_content;
167
+        private int pos;
168
+
169
+        @Override
170
+        protected void onPreExecute() {
171
+            super.onPreExecute();
172
+            System.out.println("Starting Cover download");
173
+        }
174
+
175
+        @Override
176
+        protected String doInBackground(String... f_url) {
177
+            int count;
178
+            try {
179
+                pos = Integer.parseInt(f_url[0]);
180
+                URL url = new URL(f_url[1]);
181
+                HttpURLConnection conn = (HttpURLConnection) url.openConnection();
182
+                conn.setReadTimeout(10000 /* milliseconds */);
183
+                conn.setConnectTimeout(15000 /* milliseconds */);
184
+                conn.setRequestMethod("GET");
185
+                conn.setDoInput(true);
186
+                conn.connect();
187
+                InputStream stream = conn.getInputStream();
188
+                StringBuilder page_content_builder = new StringBuilder();
189
+                byte data[] = new byte[65536];
190
+                while ((count = stream.read(data)) != -1) {
191
+                    String str = new String(data, "UTF-8");
192
+                    page_content_builder.append(str);
193
+                }
194
+                page_content = page_content_builder.toString();
195
+            } catch (Exception e) {
196
+                Log.e("Error: ", e.getMessage());
197
+            }
198
+            return null;
199
+        }
200
+
201
+        @Override
202
+        protected void onPostExecute(String file_url) {
203
+            System.out.println("Cover Downloaded");
204
+            List<EntryTag> entries_tag = getTags();
205
+            EntryTag entry_tag = entries_tag.get(pos);
206
+            entry_tag.cover = page_content;
207
+            //ExtUpdate();
208
+            InputStream stream = new ByteArrayInputStream(page_content.getBytes(StandardCharsets.UTF_8));
209
+            //Bitmap bitmap = BitmapFactory.decodeStream(stream);
210
+            //mCoverView.setImageBitmap(bitmap);
211
+            Drawable d = Drawable.createFromStream(stream, null);
212
+            mImageView.setImageDrawable(d);
213
+
214
+        }
215
+    }
216
+
217
+    class Player extends AsyncTask<String, Void, Boolean> {
218
+        private ProgressDialog progress;
219
+
220
+        @Override
221
+        protected Boolean doInBackground(String... params) {
222
+            // TODO Auto-generated method stub
223
+            Boolean prepared;
224
+            try {
225
+
226
+                mediaPlayer.setDataSource(params[0]);
227
+
228
+                mediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
229
+
230
+                    @Override
231
+                    public void onCompletion(MediaPlayer mp) {
232
+                        // TODO Auto-generated method stub
233
+//                        playPause=false;
234
+//                        btn.setBackgroundResource(R.drawable.button_play);
235
+                        mediaPlayer.stop();
236
+                        mediaPlayer.reset();
237
+                    }
238
+                });
239
+                mediaPlayer.prepare();
240
+                prepared = true;
241
+            } catch (IllegalArgumentException e) {
242
+                // TODO Auto-generated catch block
243
+                Log.d("IllegarArgument", e.getMessage());
244
+                prepared = false;
245
+                e.printStackTrace();
246
+            } catch (SecurityException e) {
247
+                // TODO Auto-generated catch block
248
+                prepared = false;
249
+                e.printStackTrace();
250
+            } catch (IllegalStateException e) {
251
+                // TODO Auto-generated catch block
252
+                prepared = false;
253
+                e.printStackTrace();
254
+            } catch (IOException e) {
255
+                // TODO Auto-generated catch block
256
+                prepared = false;
257
+                e.printStackTrace();
258
+            }
259
+            return prepared;
260
+        }
261
+
262
+        @Override
263
+        protected void onPostExecute(Boolean result) {
264
+            // TODO Auto-generated method stub
265
+            super.onPostExecute(result);
266
+            if (progress.isShowing()) {
267
+                progress.cancel();
268
+            }
269
+            Log.d("Prepared", "//" + result);
270
+            mediaPlayer.start();
271
+        }
272
+
273
+        public Player() {
274
+            progress = new ProgressDialog(MainActivity.this);
275
+        }
276
+
277
+        @Override
278
+        protected void onPreExecute() {
279
+            // TODO Auto-generated method stub
280
+            super.onPreExecute();
281
+            this.progress.setMessage("Buffering...");
282
+            this.progress.show();
283
+
284
+        }
285
+    }
286
+
287
+    public void ToastThis(String message) {
288
+        Toast.makeText(this,
289
+                message,
290
+                Toast.LENGTH_SHORT).show();
291
+    }
292
+
293
+    public static Bitmap drawableToBitmap (Drawable drawable) {
294
+        Bitmap bitmap = null;
295
+
296
+        if (drawable instanceof BitmapDrawable) {
297
+            BitmapDrawable bitmapDrawable = (BitmapDrawable) drawable;
298
+            if(bitmapDrawable.getBitmap() != null) {
299
+                return bitmapDrawable.getBitmap();
300
+            }
301
+        }
302
+
303
+        if(drawable.getIntrinsicWidth() <= 0 || drawable.getIntrinsicHeight() <= 0) {
304
+            bitmap = Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888); // Single color bitmap will be created of 1x1 pixel
305
+        } else {
306
+            bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(), Bitmap.Config.ARGB_8888);
307
+        }
308
+
309
+        Canvas canvas = new Canvas(bitmap);
310
+        drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
311
+        drawable.draw(canvas);
312
+        return bitmap;
313
+    }
314
+
315
+    public void Notify(String shortname, String notificationTitle, String notificationMessage){
316
+        /*AssetManager am = getAssets();
317
+        try {
318
+            InputStream ims = am.open(shortname + ".jpg");
319
+            Drawable d = Drawable.createFromStream(ims, null);
320
+            mNotifBuilder.setLargeIcon(drawableToBitmap(d));
321
+        } catch (IOException e) {
322
+            mNotifBuilder.setSmallIcon(R.drawable.ic_notification);
323
+        }
324
+        */
325
+
326
+        //mNotifBuilder.setSmallIcon(this.getResources().getIdentifier(shortname, "drawable", this.getPackageName()));
327
+
328
+        /*
329
+        Notification.Builder mBuilder =
330
+                new Notification.Builder(this)
331
+                        .setSmallIcon(this.getResources().getIdentifier(shortname, "drawable", this.getPackageName()))
332
+                        .setContentTitle("CoderoMusicPlayer")
333
+                        .setContentText("PLayer0!");
334
+        */
335
+        Notification.Builder mBuilder = new Notification.Builder(this);
336
+        mBuilder.setSmallIcon(this.getResources().getIdentifier(shortname, "drawable", this.getPackageName()));
337
+        if (android.os.Build.VERSION.SDK_INT <= Build.VERSION_CODES.LOLLIPOP) {
338
+            mBuilder.setContentTitle(notificationTitle);
339
+            mBuilder.setContentText(notificationMessage);
340
+        } else {
341
+            mBuilder.setContentTitle(notificationTitle);
342
+            mBuilder.setContentText(notificationMessage + "\n" + notificationTitle);
343
+            mBuilder.setColor(this.getResources().getColor(android.R.color.white));
344
+        }
345
+
346
+        mBuilder.setOngoing(true);
347
+
348
+        Intent resultIntent = new Intent(this, MainActivity.class);
349
+        resultIntent.setAction(Intent.ACTION_MAIN);
350
+        resultIntent.addCategory(Intent.CATEGORY_LAUNCHER);
351
+
352
+        PendingIntent pendingIntent = PendingIntent.getActivity(this, 0,
353
+                resultIntent, 0);
354
+
355
+        mBuilder.setContentIntent(pendingIntent);
356
+        NotificationManager mNotificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
357
+        mNotificationManager.notify(9999, mBuilder.build());
358
+    }
359
+
360
+    public void NotifyClear(){
361
+        NotificationManager notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
362
+        notificationManager.cancel(RADIO_NOTIFICATION);
363
+    }
364
+
365
+    @Override
366
+    protected void onCreate(Bundle savedInstanceState) {
367
+        super.onCreate(savedInstanceState);
368
+
369
+        iSender.sendEmptyMessage(0);
370
+        mediaPlayer = new MediaPlayer();
371
+        mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
372
+
373
+        new Thread(new Runnable() {
374
+            @Override
375
+            public void run() {
376
+                try {
377
+                    Thread.sleep(5000);
378
+                } catch (InterruptedException e) {
379
+                    e.printStackTrace();
380
+                }
381
+                runOnUiThread(new Runnable() {
382
+                    @Override
383
+                    public void run() {
384
+
385
+                    }
386
+                });
387
+            }
388
+        }).start();
389
+
390
+        setContentView(R.layout.activity_main);
391
+        mImageView = (ImageView)findViewById(R.id.imageView);
392
+        mCoverView = (ImageView)findViewById(R.id.imageViewTrack);
393
+        mTextView = (TextView) findViewById(R.id.textView);
394
+        mTextViewArtist = (TextView) findViewById(R.id.textViewArtist);
395
+        mTextViewTitle = (TextView) findViewById(R.id.textViewTitle);
396
+        spinArticle = (Spinner) findViewById(R.id.spinner_article);
397
+        addListenerOnSpinnerItemSelection();
398
+    }
399
+
400
+    public void ExtUpdate() {
401
+        int pos = spinArticle.getSelectedItemPosition();
402
+        if( current_pos != pos ) {
403
+            NotifyClear();
404
+            if (mediaPlayer.isPlaying()) {
405
+                mediaPlayer.stop();
406
+            }
407
+        }
408
+
409
+        try {
410
+            if( -1 == entries_sz ) {
411
+                FeedParser();
412
+            }
413
+            AssetManager am = getAssets();
414
+            String resourcefilename=entries.get(pos).shortname;
415
+            //InputStream ims = am.open(resourcefilename+".jpg");
416
+            InputStream ims = am.open(resourcefilename+".png");
417
+            Drawable d = Drawable.createFromStream(ims, null);
418
+            mImageView.setImageDrawable(d);
419
+            if(null== entries_tag) {
420
+                mTextView.setText(entries.get(pos).title);
421
+                mCoverView.setImageDrawable(d);
422
+            } else {
423
+                mTextView.setText(entries_tag.get(pos).title);
424
+                //mTextViewTitle.setText(entries_tag.get(pos).track_title);
425
+                if(! entries_tag.get(pos).track_title.equals("An Error Occured")) {
426
+                    mTextViewTitle.setText(entries_tag.get(pos).track_title);
427
+                } else {
428
+                    mTextViewTitle.setText("");
429
+                }
430
+                //mTextViewArtist.setText(entries_tag.get(pos).track_artist);
431
+                if(! entries_tag.get(pos).track_artist.equals("An Error Occured")) {
432
+                    mTextViewArtist.setText(entries_tag.get(pos).track_artist);
433
+                } else {
434
+                    mTextViewArtist.setText("");
435
+                }
436
+                if( (!old_artist.equals(mTextViewArtist.getText().toString())) ||
437
+                        (!old_title.equals(mTextViewTitle.getText().toString())) ) {
438
+                    Notify(entries.get(pos).shortname,
439
+                            mTextViewArtist.getText().toString(),
440
+                            mTextViewTitle.getText().toString());
441
+                    old_artist = mTextViewArtist.getText().toString();
442
+                    old_title = mTextViewTitle.getText().toString();
443
+                }
444
+                /*
445
+                if(! entries_tag.get(pos).track_url.equals("")) {
446
+                    System.out.println(entries_tag.get(pos).track_url);
447
+                    if (null != entries_tag.get(pos).cover) {
448
+                        InputStream stream = new ByteArrayInputStream(entries_tag.get(pos).cover.getBytes(StandardCharsets.UTF_8));
449
+                        d = Drawable.createFromStream(stream, null);
450
+                        mCoverView.setImageDrawable(d);
451
+                    } else {
452
+                        mDownloadCover = (DownloadCoverFromURL) new DownloadCoverFromURL().execute(Integer.toString(pos),entries_tag.get(pos).track_url);
453
+                    }
454
+                } else {
455
+                    mCoverView.setImageDrawable(d);
456
+                }*/
457
+                mCoverView.setImageDrawable(d);
458
+            }
459
+        } catch (IOException e) {
460
+            e.printStackTrace();
461
+        }
462
+
463
+        Log.d("ExtUpdate DEBUG:", "Start Playing");
464
+        if( current_pos != pos ) {
465
+            current_pos = pos;
466
+            mediaPlayer = new MediaPlayer();
467
+            new Player().execute(entries.get(pos).mp3);
468
+            if( entries_tag != null ) {
469
+                if (entries_tag.get(pos) != null) {
470
+                    if ((null != entries_tag.get(pos).track_artist) &&
471
+                            (null != entries_tag.get(pos).track_artist)) {
472
+                        Notify(entries.get(pos).shortname, entries_tag.get(pos).track_artist, entries_tag.get(pos).track_title);
473
+                    } else {
474
+                        Notify(entries.get(pos).shortname, entries.get(pos).title, getString(R.string.tags_not_found));
475
+                    }
476
+                } else {
477
+                    Notify(entries.get(pos).shortname, entries.get(pos).title, getString(R.string.tags_not_found));
478
+                }
479
+            } else {
480
+                Notify(entries.get(pos).shortname, entries.get(pos).title, getString(R.string.tags_not_dl));
481
+            }
482
+        }
483
+    }
484
+
485
+    public void addListenerOnSpinnerItemSelection(){
486
+        spinArticle.setOnItemSelectedListener(new SpinnerActivity());
487
+    }
488
+
489
+    @Override
490
+    public boolean onSupportNavigateUp(){
491
+        finish();
492
+        return true;
493
+    }
494
+
495
+    public boolean updateListView() {
496
+        boolean ret = false;
497
+        String [] items1 = null;
498
+        ArrayList al = new ArrayList<String>();
499
+        try {
500
+            items1 = doDropDown();
501
+        } catch( Exception e ) {
502
+            return ret;
503
+        }
504
+
505
+        ArrayAdapter<String> adapter1 = new ArrayAdapter<String>(this,
506
+                android.R.layout.simple_spinner_item, items1);
507
+        adapter1.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
508
+        spinArticle.setAdapter(adapter1);
509
+        adapter1.notifyDataSetChanged();
510
+        return true;
511
+    }
512
+
513
+    @Override
514
+    public boolean onCreateOptionsMenu(Menu menu) {
515
+        // Inflate the menu; this adds items to the action bar if it is present.
516
+        getMenuInflater().inflate(R.menu.menu_main, menu);
517
+        MenuItem menuItemDateRefresh = menu.findItem(R.id.last_refresh_date);
518
+        menuItemDateRefresh.setTitle(getString(R.string.version));
519
+        return true;
520
+    }
521
+
522
+
523
+    @Override
524
+    public boolean onOptionsItemSelected(MenuItem item) {
525
+        // Handle action bar item clicks here. The action bar will
526
+        // automatically handle clicks on the Home/Up button, so long
527
+        // as you specify a parent activity in AndroidManifest.xml.
528
+        int id = item.getItemId();
529
+        if (id == R.id.action_exit) {
530
+            NotifyClear();
531
+            if (mediaPlayer.isPlaying()) {
532
+                mediaPlayer.stop();
533
+            }
534
+            finish();
535
+            System.exit(0);
536
+            return true;
537
+        }
538
+
539
+        return super.onOptionsItemSelected(item);
540
+    }
541
+
542
+    private void FeedParser() {
543
+        RadioXmlParser radioXmlParser = new RadioXmlParser();
544
+        InputStream stream = null;
545
+        AssetManager am = getAssets();
546
+        try {
547
+            stream = am.open("radio.xml");
548
+            try {
549
+                entries = radioXmlParser.parse(stream);
550
+                entries_sz = entries.size();
551
+                updateListView();
552
+                invalidateOptionsMenu();
553
+                if( initialState == true ) {
554
+                    initialState = false;
555
+                    spinArticle.setSelection(0, true);
556
+                }
557
+            } catch (IOException ignored) {
558
+                entries = null;
559
+                entries_sz = -1;
560
+            } catch (XmlPullParserException ignored) {
561
+                entries = null;
562
+                entries_sz = -1;
563
+            }
564
+            if (null != stream) {
565
+                try {
566
+                    stream.close();
567
+                } catch (IOException e) {
568
+                }
569
+            }
570
+
571
+        } catch (IOException e) {
572
+            e.printStackTrace();
573
+            entries = null;
574
+            entries_sz = -1;
575
+        }
576
+    }
577
+
578
+    /** Feed 2 Article list for Spinner */
579
+    private String[] doDropDown() throws IOException {
580
+        String[] strings;
581
+        if( -1 == entries_sz ) {
582
+            FeedParser();
583
+        }
584
+
585
+        HashSet<String> hs = new HashSet<String>();
586
+        List<String> mStrings = new ArrayList<String>();
587
+        int i = 0;
588
+        for( i = 0; i < entries_sz; i ++ )
589
+        {
590
+            Entry temp = entries.get(i);
591
+            mStrings.add(i,temp.title);
592
+        }
593
+        mStrings.addAll(hs);
594
+        strings = new String[mStrings.size()];
595
+        strings = mStrings.toArray(strings);
596
+        return strings;
597
+    }
598
+}
+70
app/src/main/java/com/yc/rss/radio/RadioXmlParser.java
... ...
@@ -0,0 +1,70 @@
1
+package com.yc.rss.radio;
2
+
3
+import android.util.Xml;
4
+
5
+import org.xmlpull.v1.XmlPullParser;
6
+import org.xmlpull.v1.XmlPullParserException;
7
+
8
+import java.io.IOException;
9
+import java.io.InputStream;
10
+import java.util.ArrayList;
11
+import java.util.List;
12
+
13
+public class RadioXmlParser {
14
+    // We don't use namespaces
15
+    private static final String ns = null;
16
+
17
+    public List parse(InputStream in) throws XmlPullParserException, IOException {
18
+        try {
19
+            XmlPullParser parser = Xml.newPullParser();
20
+            parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, false);
21
+            parser.setInput(in, null);
22
+            parser.nextTag();
23
+            return readFeed(parser);
24
+        } finally {
25
+            in.close();
26
+        }
27
+    }
28
+
29
+    private List readFeed(XmlPullParser parser) throws XmlPullParserException, IOException {
30
+        List entries = new ArrayList();
31
+        Entry entry = new Entry("a","b","c","d");
32
+
33
+        parser.require(XmlPullParser.START_TAG, ns, "channel_list");
34
+        while (parser.next() != XmlPullParser.END_TAG) {
35
+            if (parser.getEventType() != XmlPullParser.START_TAG) {
36
+                continue;
37
+            }
38
+            String name = parser.getName();
39
+            // Starts by looking for the item tag
40
+            if (name.equals("channel")) {
41
+
42
+                //entries.add(entry.readEntry(parser));
43
+                entries = readFeedChannel(parser);
44
+            } else {
45
+                entry.skip(parser);
46
+            }
47
+        }
48
+        return entries;
49
+    }
50
+    private List readFeedChannel(XmlPullParser parser) throws XmlPullParserException, IOException {
51
+        List entries = new ArrayList();
52
+        Entry entry = new Entry("a","b","c","d");
53
+
54
+        parser.require(XmlPullParser.START_TAG, ns, "channel");
55
+        while (parser.next() != XmlPullParser.END_TAG) {
56
+            if (parser.getEventType() != XmlPullParser.START_TAG) {
57
+                continue;
58
+            }
59
+            String name = parser.getName();
60
+            // Starts by looking for the item tag
61
+            if (name.equals("item")) {
62
+
63
+                entries.add(entry.readItem(parser));
64
+            } else {
65
+                entry.skip(parser);
66
+            }
67
+        }
68
+        return entries;
69
+    }
70
+}
+21
app/src/main/java/com/yc/rss/radio/SpinnerActivity.java
... ...
@@ -0,0 +1,21 @@
1
+package com.yc.rss.radio;
2
+
3
+import android.app.Activity;
4
+import android.view.View;
5
+import android.widget.AdapterView;
6
+
7
+
8
+/**
9
+ * Created by cawidrone on 8/17/15.
10
+ */
11
+public class SpinnerActivity extends Activity implements AdapterView.OnItemSelectedListener {
12
+    public void onItemSelected(AdapterView<?> parent, View view,
13
+                               int pos, long id) {
14
+        MainActivity mainActivity = (MainActivity)parent.getContext();
15
+        mainActivity.ExtUpdate();
16
+    }
17
+
18
+    public void onNothingSelected(AdapterView<?> parent) {
19
+        // Another interface callback
20
+    }
21
+}
+47
app/src/main/java/com/yc/rss/radio/TagsXmlParser.java
... ...
@@ -0,0 +1,47 @@
1
+package com.yc.rss.radio;
2
+
3
+import android.util.Xml;
4
+
5
+import org.xmlpull.v1.XmlPullParser;
6
+import org.xmlpull.v1.XmlPullParserException;
7
+
8
+import java.io.IOException;
9
+import java.io.InputStream;
10
+import java.util.ArrayList;
11
+import java.util.List;
12
+
13
+public class TagsXmlParser {
14
+    // We don't use namespaces
15
+    private static final String ns = null;
16
+
17
+    public List parse(InputStream in) throws XmlPullParserException, IOException {
18
+        try {
19
+            XmlPullParser parser = Xml.newPullParser();
20
+            parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, false);
21
+            parser.setInput(in, null);
22
+            parser.nextTag();
23
+            return readFeed(parser);
24
+        } finally {
25
+            in.close();
26
+        }
27
+    }
28
+
29
+    private List readFeed(XmlPullParser parser) throws XmlPullParserException, IOException {
30
+        List entries = new ArrayList();
31
+        EntryTag entry = new EntryTag("a","b","c","d","e","f");
32
+
33
+        parser.require(XmlPullParser.START_TAG, ns, "channel_list");
34
+        while (parser.next() != XmlPullParser.END_TAG) {
35
+            if (parser.getEventType() != XmlPullParser.START_TAG) {
36
+                continue;
37
+            }
38
+            String name = parser.getName();
39
+            if (name.equals("channel")) {
40
+                entries.add(entry.readItem(parser));
41
+            } else {
42
+                entry.skip(parser);
43
+            }
44
+        }
45
+        return entries;
46
+    }
47
+}
+19
app/src/main/res/dologo
... ...
@@ -0,0 +1,19 @@
1
+#!/bin/bash
2
+
3
+FILENAME=$1
4
+
5
+if [ -z $1 ]
6
+then
7
+	echo "$(basename $0) filename.png"
8
+	exit 1
9
+fi
10
+
11
+cp $FILENAME drawable/ic_launcher.png
12
+cp $FILENAME mipmap-mdpi/ic_launcher.png
13
+cp $FILENAME mipmap-hdpi/ic_launcher.png
14
+cp $FILENAME mipmap-xhdpi/ic_launcher.png;
15
+cp $FILENAME mipmap-xxhdpi/ic_launcher.png
16
+mogrify -resize 72x72 mipmap-mdpi/ic_launcher.png
17
+mogrify -resize 72x72 mipmap-hdpi/ic_launcher.png
18
+mogrify -resize 96x96 mipmap-xhdpi/ic_launcher.png
19
+mogrify -resize 144x144 mipmap-xxhdpi/ic_launcher.png
BIN
app/src/main/res/drawable/bassdrive.png
BIN
app/src/main/res/drawable/bbcws.png
BIN
app/src/main/res/drawable/caribbean.png
BIN
app/src/main/res/drawable/classic21.png
BIN
app/src/main/res/drawable/covers.png
BIN
app/src/main/res/drawable/europe1.png
BIN
app/src/main/res/drawable/fculture.png
BIN
app/src/main/res/drawable/finfo.png
BIN
app/src/main/res/drawable/finter.png
BIN
app/src/main/res/drawable/fipradio.png
BIN
app/src/main/res/drawable/flemme.png
BIN
app/src/main/res/drawable/fmusique.png
BIN
app/src/main/res/drawable/groovesalad.png
BIN
app/src/main/res/drawable/ic_launcher.png
BIN
app/src/main/res/drawable/ic_launcher_big.png
BIN
app/src/main/res/drawable/ic_notification.png
BIN
app/src/main/res/drawable/lemouv.png
BIN
app/src/main/res/drawable/lgrmetal.png
BIN
app/src/main/res/drawable/lgrreggae.png
BIN
app/src/main/res/drawable/lgrrock.png
BIN
app/src/main/res/drawable/radio_classique.png
BIN
app/src/main/res/drawable/radio_nova.png
BIN
app/src/main/res/drawable/reggaewc.png
BIN
app/src/main/res/drawable/reggaeworldmusic.png
BIN
app/src/main/res/drawable/rfi.png
BIN
app/src/main/res/drawable/rruk.png
BIN
app/src/main/res/drawable/stellar.png
BIN
app/src/main/res/drawable/suburbsofgoa.png
BIN
app/src/main/res/drawable/trapfm.png
+65
app/src/main/res/layout/activity_main.xml
... ...
@@ -0,0 +1,65 @@
1
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
2
+    android:orientation="vertical"
3
+    android:layout_width="match_parent"
4
+    android:layout_height="match_parent">
5
+    <Spinner
6
+        android:id="@+id/spinner_article"
7
+        android:layout_width="match_parent"
8
+        android:layout_height="50dp"
9
+        android:entries="@array/article_arrays"
10
+        android:prompt="@string/article_prompt"
11
+        android:background="#cdcdcd" />
12
+
13
+	 <TextView
14
+		android:layout_width="fill_parent"
15
+		android:layout_height="50dp"
16
+		android:id="@+id/textView"
17
+		android:layout_centerHorizontal="true"
18
+		android:layout_gravity="center"
19
+		android:textAlignment="center"
20
+		android:textColor="#000000"
21
+		android:textStyle="italic"
22
+		android:textSize="38dp" />
23
+
24
+	<TextView
25
+		android:layout_width="fill_parent"
26
+		android:layout_height="75dp"
27
+		android:id="@+id/textViewArtist"
28
+		android:layout_centerHorizontal="true"
29
+		android:layout_gravity="center"
30
+		android:textAlignment="center"
31
+		android:textColor="#000000"
32
+		android:textStyle="normal|bold"
33
+		android:textSize="32dp" />
34
+		
35
+	<TextView
36
+		android:layout_width="fill_parent"
37
+		android:layout_height="120dp"
38
+		android:id="@+id/textViewTitle"
39
+		android:layout_centerHorizontal="true"
40
+		android:layout_gravity="center"
41
+		android:capitalize="words"
42
+		android:enabled="false"
43
+		android:textAlignment="center"
44
+		android:textColor="#000000"
45
+		android:textSize="24dp"
46
+		android:textStyle="normal" />
47
+		
48
+	<ImageView
49
+		android:layout_width="144dp"
50
+		android:layout_height="144dp"
51
+		android:id="@+id/imageViewTrack"
52
+		android:layout_centerHorizontal="true"
53
+		android:layout_centerVertical="true"
54
+		android:background="@drawable/ic_launcher_big"
55
+		android:layout_gravity="center" />
56
+		
57
+	<ImageView
58
+		android:layout_width="96dp"
59
+		android:layout_height="96dp"
60
+		android:id="@+id/imageView"
61
+		android:layout_alignParentBottom="true"
62
+		android:background="@drawable/ic_launcher"
63
+		android:layout_gravity="top"
64
+		android:visibility="invisible" />
65
+</LinearLayout>
+12
app/src/main/res/menu/menu_main.xml
... ...
@@ -0,0 +1,12 @@
1
+<menu xmlns:android="http://schemas.android.com/apk/res/android"
2
+    xmlns:app="http://schemas.android.com/apk/res-auto"
3
+    xmlns:tools="http://schemas.android.com/tools" tools:context=".MainActivity">
4
+
5
+    <item android:id="@+id/last_refresh_date"
6
+        android:title="@string/action_last_refresh_date"
7
+        android:orderInCategory="100" app:showAsAction="always|withText" />
8
+
9
+    <item android:id="@+id/action_exit"
10
+        android:title="@string/action_exit"
11
+        android:orderInCategory="100" app:showAsAction="never" />
12
+</menu>
BIN
app/src/main/res/mipmap-hdpi/ic_launcher.png
BIN
app/src/main/res/mipmap-mdpi/ic_launcher.png
BIN
app/src/main/res/mipmap-xhdpi/ic_launcher.png
BIN
app/src/main/res/mipmap-xxhdpi/ic_launcher.png
+6
app/src/main/res/values-w820dp/dimens.xml
... ...
@@ -0,0 +1,6 @@
1
+<resources>
2
+    <!-- Example customization of dimensions originally defined in res/values/dimens.xml
3
+         (such as screen margins) for screens with more than 820dp of available width. This
4
+         would include 7" and 10" devices in landscape (~960dp and ~1280dp respectively). -->
5
+    <dimen name="activity_horizontal_margin">0dp</dimen>
6
+</resources>
+7
app/src/main/res/values/dimens.xml
... ...
@@ -0,0 +1,7 @@
1
+<resources>
2
+    <!-- Default screen margins, per the Android Design guidelines. -->
3
+    <!-- <dimen name="activity_horizontal_margin">16dp</dimen>
4
+    <dimen name="activity_vertical_margin">16dp</dimen> -->
5
+    <dimen name="activity_horizontal_margin">0dp</dimen>
6
+    <dimen name="activity_vertical_margin">0dp</dimen>
7
+</resources>
+16
app/src/main/res/values/strings.xml
... ...
@@ -0,0 +1,16 @@
1
+<resources>
2
+    <string name="app_name">Radio</string>
3
+    <string name="version">2017-06-13</string>
4
+    <string name="hello_world">Radio Player</string>
5
+    <string name="action_exit">Exit</string>
6
+    <string name="action_last_refresh_date"></string>
7
+    <!-- <string name="tags_url">https://files.kawi.fr/radio/tags.xml</string> -->
8
+    <string name="tags_url">https://kawi.fr/radio/tags.xml</string>
9
+    <string name="article_prompt">Choose an article</string>
10
+    <string-array name="article_arrays">
11
+        <item><string name="spinner_default_message">No previous data found</string></item>
12
+    </string-array>
13
+    <string name="tags_downloaded">Tags Downloaded</string>
14
+    <string name="tags_not_found">No Tag Found</string>
15
+    <string name="tags_not_dl">Tags Not Downloaded yet...</string>
16
+</resources>
+6
app/src/main/res/values/styles.xml
... ...
@@ -0,0 +1,6 @@
1
+<resources>
2
+    <!-- Base application theme. -->
3
+    <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
4
+        <!-- Customize your theme here. -->
5
+    </style>
6
+</resources>
+19
build.gradle
... ...
@@ -0,0 +1,19 @@
1
+// Top-level build file where you can add configuration options common to all sub-projects/modules.
2
+
3
+buildscript {
4
+    repositories {
5
+        jcenter()
6
+    }
7
+    dependencies {
8
+        classpath 'com.android.tools.build:gradle:2.3.3'
9
+
10
+        // NOTE: Do not place your application dependencies here; they belong
11
+        // in the individual module build.gradle files
12
+    }
13
+}
14
+
15
+allprojects {
16
+    repositories {
17
+        jcenter()
18
+    }
19
+}
BIN
favicon.ico
Binary file not shown.
+1
settings.gradle
... ...
@@ -0,0 +1 @@
1
+include ':app'