Commit 54a5491b authored by Thomas Guillem's avatar Thomas Guillem Committed by Max Kellermann

android: Main is now a service

- add Settings: Activity to start / stop MPD Service (Main). - Main is a service that run in foreground with a notification. See Service.startForeground documentation for more details. - Main.Client is used to control the service: start or stop it and also receive callbacks when service encounters an error, is killed, is started or is stopped. - Main.start to start the service without any fallback.
parent aff070bc
......@@ -301,6 +301,7 @@ ANDROID_BUILD_TOOLS_DIR = $(ANDROID_SDK)/build-tools/$(ANDROID_SDK_BUILD_TOOLS_V
ANDROID_SDK_PLATFORM_DIR = $(ANDROID_SDK)/platforms/$(ANDROID_SDK_PLATFORM)
JAVAC = javac
AIDL = $(ANDROID_BUILD_TOOLS_DIR)/aidl
AAPT = $(ANDROID_BUILD_TOOLS_DIR)/aapt
DX = $(ANDROID_BUILD_TOOLS_DIR)/dx
ZIPALIGN = $(ANDROID_BUILD_TOOLS_DIR)/zipalign
......@@ -308,11 +309,21 @@ ZIPALIGN = $(ANDROID_BUILD_TOOLS_DIR)/zipalign
ANDROID_XML_RES := $(wildcard $(srcdir)/android/res/*/*.xml)
ANDROID_XML_RES_COPIES := $(patsubst $(srcdir)/android/%,android/build/%,$(ANDROID_XML_RES))
JAVA_SOURCE_NAMES = Bridge.java Loader.java Main.java
JAVA_SOURCE_NAMES = Bridge.java Loader.java Main.java Settings.java
JAVA_SOURCE_PATHS = $(addprefix $(srcdir)/android/src/,$(JAVA_SOURCE_NAMES))
JAVA_CLASSFILES_DIR = android/build/classes
AIDL_FILES = $(wildcard $(srcdir)/android/src/*.aidl)
AIDL_JAVA_FILES = $(patsubst $(srcdir)/android/src/%.aidl,android/build/src/org/musicpd/%.java,$(AIDL_FILES))
android/build/src/org/musicpd/IMain.java: android/build/src/org/musicpd/IMainCallback.java
$(AIDL_JAVA_FILES): android/build/src/org/musicpd/%.java: $(srcdir)/android/src/%.aidl
@$(MKDIR_P) $(@D)
@cp $< $(@D)/
$(AIDL) -Iandroid/build/src -oandroid/build/src $(patsubst %.java,%.aidl,$@)
$(ANDROID_XML_RES_COPIES): $(ANDROID_XML_RES)
@$(MKDIR_P) $(dir $@)
cp $(patsubst android/build/%,$(srcdir)/android/%,$@) $@
......@@ -330,7 +341,7 @@ android/build/resources.apk: $(ANDROID_XML_RES_COPIES) android/build/res/drawabl
# R.java is generated by aapt, when resources.apk is generated
android/build/gen/org/musicpd/R.java: android/build/resources.apk
android/build/classes.dex: $(JAVA_SOURCE_PATHS) android/build/gen/org/musicpd/R.java
android/build/classes.dex: $(JAVA_SOURCE_PATHS) $(AIDL_JAVA_FILES) android/build/gen/org/musicpd/R.java
@$(MKDIR_P) $(JAVA_CLASSFILES_DIR)
$(JAVAC) -source 1.6 -target 1.6 -Xlint:-options \
-cp $(ANDROID_SDK_PLATFORM_DIR)/android.jar:$(JAVA_CLASSFILES_DIR) \
......
ver 0.20.22 (not yet released)
* storage
- curl: URL-encode paths
* Android
- now runs as a service
- add button to start/stop MPD
ver 0.20.21 (2018/08/17)
* database
......
......@@ -8,14 +8,14 @@
<uses-sdk android:minSdkVersion="21" android:targetSdkVersion="26"/>
<application android:icon="@drawable/icon" android:label="@string/app_name">
<activity android:name=".Main"
android:label="@string/app_name"
android:launchMode="singleInstance">
<activity android:name=".Settings"
android:label="@string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service android:name=".Main" />
</application>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
......
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/layout"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:padding="10dp" >
<ImageView android:id="@+id/image"
android:layout_width="wrap_content"
android:layout_height="fill_parent"
android:layout_alignParentLeft="true"
android:layout_marginRight="10dp" />
<TextView android:id="@+id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toRightOf="@id/image"
style="Custom Notification Title" />
<TextView android:id="@+id/text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toRightOf="@id/image"
android:layout_below="@id/title"
style="Custom Notification Text" />
</RelativeLayout>
......@@ -2,4 +2,6 @@
<resources>
<string name="app_name">MPD</string>
<string name="notification_title_mpd_running">Music Player Daemon is running</string>
<string name="notification_text_mpd_running">Touch for MPD options.</string>
</resources>
package org.musicpd;
import org.musicpd.IMainCallback;
interface IMain
{
void start();
void stop();
void setWakelockEnabled(boolean enabled);
boolean isRunning();
void registerCallback(IMainCallback cb);
void unregisterCallback(IMainCallback cb);
}
package org.musicpd;
interface IMainCallback
{
void onStarted();
void onStopped();
void onError(String error);
void onLog(int priority, String msg);
}
/*
* Copyright 2003-2018 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
package org.musicpd;
import android.app.Activity;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.widget.CompoundButton;
import android.widget.CompoundButton.OnCheckedChangeListener;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.ToggleButton;
public class Settings extends Activity {
private static final String TAG = "Settings";
private Main.Client mClient;
private TextView mTextView;
private ToggleButton mButton;
private LinearLayout mLayout;
private static final int MSG_ERROR = 0;
private static final int MSG_STOPPED = 1;
private static final int MSG_STARTED = 2;
private Handler mHandler = new Handler(new Handler.Callback() {
@Override
public boolean handleMessage(Message msg) {
switch (msg.what) {
case MSG_ERROR:
Log.d(TAG, "onError");
final String error = (String) msg.obj;
mTextView.setText("Failed to load the native MPD libary.\n" +
"Report this problem to us, and include the following information:\n" +
"SUPPORTED_ABIS=" + String.join(", ", Build.SUPPORTED_ABIS) + "\n" +
"PRODUCT=" + Build.PRODUCT + "\n" +
"FINGERPRINT=" + Build.FINGERPRINT + "\n" +
"error=" + error);
mButton.setChecked(false);
mButton.setEnabled(false);
break;
case MSG_STOPPED:
Log.d(TAG, "onStopped");
if (mButton.isEnabled()) // don't overwrite previous error message
mTextView.setText("Music Player Daemon is not running");
mButton.setEnabled(true);
mButton.setChecked(false);
break;
case MSG_STARTED:
Log.d(TAG, "onStarted");
mTextView.setText("Music Player Daemon is running"
+ "\nCAUTION: this version is EXPERIMENTAL!");
mButton.setChecked(true);
break;
}
return true;
}
});
private OnCheckedChangeListener mOnCheckedChangeListener = new OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if (mClient != null) {
if (isChecked)
mClient.start();
else
mClient.stop();
}
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
mTextView = new TextView(this);
mTextView.setText("");
mButton = new ToggleButton(this);
mButton.setOnCheckedChangeListener(mOnCheckedChangeListener);
mLayout = new LinearLayout(this);
mLayout.setOrientation(LinearLayout.VERTICAL);
mLayout.addView(mButton);
mLayout.addView(mTextView);
setContentView(mLayout);
super.onCreate(savedInstanceState);
}
@Override
protected void onStart() {
mClient = new Main.Client(this, new Main.Client.Callback() {
@Override
public void onStopped() {
mHandler.removeCallbacksAndMessages(null);
mHandler.sendEmptyMessage(MSG_STOPPED);
}
@Override
public void onStarted() {
mHandler.removeCallbacksAndMessages(null);
mHandler.sendEmptyMessage(MSG_STARTED);
}
@Override
public void onError(String error) {
mHandler.removeCallbacksAndMessages(null);
mHandler.sendMessage(Message.obtain(mHandler, MSG_ERROR, error));
}
@Override
public void onLog(int priority, String msg) {
}
});
super.onStart();
}
@Override
protected void onStop() {
mClient.release();
mClient = null;
super.onStop();
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment