summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--NEWS1
-rw-r--r--android/AndroidManifest.xml8
-rw-r--r--android/res/layout/log_item.xml5
-rw-r--r--android/res/layout/settings.xml37
-rw-r--r--android/res/values/strings.xml4
-rw-r--r--android/src/Receiver.java41
-rw-r--r--android/src/Settings.java189
7 files changed, 244 insertions, 41 deletions
diff --git a/NEWS b/NEWS
index 5eb591817..69adaf45e 100644
--- a/NEWS
+++ b/NEWS
@@ -4,6 +4,7 @@ ver 0.20.22 (not yet released)
* Android
- now runs as a service
- add button to start/stop MPD
+ - add option to auto-start on boot
ver 0.20.21 (2018/08/17)
* database
diff --git a/android/AndroidManifest.xml b/android/AndroidManifest.xml
index 3a43a5e7d..5dddf034e 100644
--- a/android/AndroidManifest.xml
+++ b/android/AndroidManifest.xml
@@ -10,6 +10,7 @@
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WAKE_LOCK"/>
<uses-permission android:name="android.permission.INTERNET"/>
+ <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<application android:allowBackup="true"
android:icon="@drawable/icon"
@@ -21,7 +22,12 @@
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
- <service android:name=".Main" />
+ <receiver android:name=".Receiver">
+ <intent-filter>
+ <action android:name="android.intent.action.BOOT_COMPLETED" />
+ </intent-filter>
+ </receiver>
+ <service android:name=".Main" android:process=":main"/>
</application>
</manifest>
diff --git a/android/res/layout/log_item.xml b/android/res/layout/log_item.xml
new file mode 100644
index 000000000..e6e74c913
--- /dev/null
+++ b/android/res/layout/log_item.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<TextView xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:typeface="monospace" />
diff --git a/android/res/layout/settings.xml b/android/res/layout/settings.xml
new file mode 100644
index 000000000..46e471b05
--- /dev/null
+++ b/android/res/layout/settings.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical" >
+
+ <ToggleButton
+ android:id="@+id/run"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:textOn="@string/toggle_button_run_on"
+ android:textOff="@string/toggle_button_run_off" />
+
+ <CheckBox
+ android:id="@+id/run_on_boot"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:text="@string/checkbox_run_on_boot" />
+
+ <CheckBox
+ android:id="@+id/wakelock"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:text="@string/checkbox_wakelock" />
+
+ <TextView
+ android:id="@+id/status"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content" />
+
+ <ListView
+ android:id="@+id/log_list"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingTop="10dip" />
+
+</LinearLayout>
diff --git a/android/res/values/strings.xml b/android/res/values/strings.xml
index bcc1ae0c5..fc5a15bda 100644
--- a/android/res/values/strings.xml
+++ b/android/res/values/strings.xml
@@ -4,4 +4,8 @@
<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>
+ <string name="toggle_button_run_on">MPD is running</string>
+ <string name="toggle_button_run_off">MPD is not running</string>
+ <string name="checkbox_run_on_boot">Run MPD automatically on boot</string>
+ <string name="checkbox_wakelock">Prevent suspend when MPD is running (Wakelock)</string>
</resources>
diff --git a/android/src/Receiver.java b/android/src/Receiver.java
new file mode 100644
index 000000000..e24a29fbc
--- /dev/null
+++ b/android/src/Receiver.java
@@ -0,0 +1,41 @@
+
+/*
+ * Copyright (C) 2003-2014 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.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.util.Log;
+
+public class Receiver extends BroadcastReceiver {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ Log.d("Receiver", "onReceive: " + intent);
+ if (intent.getAction() == "android.intent.action.BOOT_COMPLETED") {
+ if (Settings.Preferences.getBoolean(context,
+ Settings.Preferences.KEY_RUN_ON_BOOT, false)) {
+ final boolean wakelock = Settings.Preferences.getBoolean(context,
+ Settings.Preferences.KEY_WAKELOCK, false);
+ Main.start(context, wakelock);
+ }
+ }
+ }
+}
diff --git a/android/src/Settings.java b/android/src/Settings.java
index 89f96447d..69b5305e2 100644
--- a/android/src/Settings.java
+++ b/android/src/Settings.java
@@ -19,120 +19,229 @@
package org.musicpd;
+import java.util.LinkedList;
+
import android.app.Activity;
-import android.os.Build;
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.content.SharedPreferences.Editor;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
+import android.widget.ArrayAdapter;
+import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.CompoundButton.OnCheckedChangeListener;
-import android.widget.LinearLayout;
+import android.widget.ListView;
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 TextView mTextStatus;
+ private ToggleButton mRunButton;
+ private boolean mFirstRun;
+ private LinkedList<String> mLogListArray = new LinkedList<String>();
+ private ListView mLogListView;
+ private ArrayAdapter<String> mLogListAdapter;
+
+ private static final int MAX_LOGS = 500;
private static final int MSG_ERROR = 0;
private static final int MSG_STOPPED = 1;
private static final int MSG_STARTED = 2;
+ private static final int MSG_LOG = 3;
- private Handler mHandler = new Handler(new Handler.Callback() {
+ public static class Preferences {
+ public static final String KEY_RUN_ON_BOOT ="run_on_boot";
+ public static final String KEY_WAKELOCK ="wakelock";
+
+ public static SharedPreferences get(Context context) {
+ return context.getSharedPreferences(TAG, MODE_PRIVATE);
+ }
+
+ public static void putBoolean(Context context, String key, boolean value) {
+ final SharedPreferences prefs = get(context);
+ if (prefs == null)
+ return;
+ final Editor editor = prefs.edit();
+ editor.putBoolean(key, value);
+ editor.apply();
+ }
+
+ public static boolean getBoolean(Context context, String key, boolean defValue) {
+ final SharedPreferences prefs = get(context);
+
+ return prefs != null ? prefs.getBoolean(key, defValue) : defValue;
+ }
+ }
+
+ 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);
+
+ mClient.release();
+ connectClient();
+
+ mRunButton.setEnabled(false);
+ mRunButton.setChecked(false);
+
+ mTextStatus.setText((String)msg.obj);
+ mFirstRun = true;
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);
+ mRunButton.setEnabled(true);
+ if (!mFirstRun && Preferences.getBoolean(Settings.this, Preferences.KEY_RUN_ON_BOOT, false))
+ mRunButton.setChecked(true);
+ else
+ mRunButton.setChecked(false);
+ mFirstRun = true;
break;
case MSG_STARTED:
Log.d(TAG, "onStarted");
- mTextView.setText("Music Player Daemon is running"
- + "\nCAUTION: this version is EXPERIMENTAL!");
- mButton.setChecked(true);
+ mRunButton.setChecked(true);
+ mFirstRun = true;
+ mTextStatus.setText("CAUTION: this version is EXPERIMENTAL!"); // XXX
+ break;
+ case MSG_LOG:
+ if (mLogListArray.size() > MAX_LOGS)
+ mLogListArray.remove(0);
+ String priority;
+ switch (msg.arg1) {
+ case Log.DEBUG:
+ priority = "D";
+ break;
+ case Log.ERROR:
+ priority = "E";
+ break;
+ case Log.INFO:
+ priority = "I";
+ break;
+ case Log.VERBOSE:
+ priority = "V";
+ break;
+ case Log.WARN:
+ priority = "W";
+ break;
+ default:
+ priority = "";
+ }
+ mLogListArray.add(priority + "/ " + (String)msg.obj);
+ mLogListAdapter.notifyDataSetChanged();
+
break;
}
return true;
}
});
- private OnCheckedChangeListener mOnCheckedChangeListener = new OnCheckedChangeListener() {
-
+ private final OnCheckedChangeListener mOnRunChangeListener = new OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if (mClient != null) {
- if (isChecked)
+ if (isChecked) {
mClient.start();
- else
+ if (Preferences.getBoolean(Settings.this,
+ Preferences.KEY_WAKELOCK, false))
+ mClient.setWakelockEnabled(true);
+ } else {
mClient.stop();
+ }
}
}
};
+ private final OnCheckedChangeListener mOnRunOnBootChangeListener = new OnCheckedChangeListener() {
+ @Override
+ public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
+ Preferences.putBoolean(Settings.this, Preferences.KEY_RUN_ON_BOOT, isChecked);
+ if (isChecked && mClient != null && !mRunButton.isChecked())
+ mRunButton.setChecked(true);
+ }
+ };
+
+ private final OnCheckedChangeListener mOnWakelockChangeListener = new OnCheckedChangeListener() {
+ @Override
+ public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
+ Preferences.putBoolean(Settings.this, Preferences.KEY_WAKELOCK, isChecked);
+ if (mClient != null && mClient.isRunning())
+ mClient.setWakelockEnabled(isChecked);
+ }
+ };
+
@Override
protected void onCreate(Bundle savedInstanceState) {
- mTextView = new TextView(this);
- mTextView.setText("");
+ setContentView(R.layout.settings);
+ mRunButton = (ToggleButton) findViewById(R.id.run);
+ mRunButton.setOnCheckedChangeListener(mOnRunChangeListener);
+
+ mTextStatus = (TextView) findViewById(R.id.status);
- mButton = new ToggleButton(this);
- mButton.setOnCheckedChangeListener(mOnCheckedChangeListener);
+ mLogListAdapter = new ArrayAdapter<String>(this, R.layout.log_item, mLogListArray);
- mLayout = new LinearLayout(this);
- mLayout.setOrientation(LinearLayout.VERTICAL);
- mLayout.addView(mButton);
- mLayout.addView(mTextView);
+ mLogListView = (ListView) findViewById(R.id.log_list);
+ mLogListView.setAdapter(mLogListAdapter);
+ mLogListView.setTranscriptMode(ListView.TRANSCRIPT_MODE_NORMAL);
- setContentView(mLayout);
+ CheckBox checkbox = (CheckBox) findViewById(R.id.run_on_boot);
+ checkbox.setOnCheckedChangeListener(mOnRunOnBootChangeListener);
+ if (Preferences.getBoolean(this, Preferences.KEY_RUN_ON_BOOT, false))
+ checkbox.setChecked(true);
+
+ checkbox = (CheckBox) findViewById(R.id.wakelock);
+ checkbox.setOnCheckedChangeListener(mOnWakelockChangeListener);
+ if (Preferences.getBoolean(this, Preferences.KEY_WAKELOCK, false))
+ checkbox.setChecked(true);
super.onCreate(savedInstanceState);
}
- @Override
- protected void onStart() {
+ private void connectClient() {
mClient = new Main.Client(this, new Main.Client.Callback() {
+
+ private void removeMessages() {
+ /* don't remove log messages */
+ mHandler.removeMessages(MSG_STOPPED);
+ mHandler.removeMessages(MSG_STARTED);
+ mHandler.removeMessages(MSG_ERROR);
+ }
+
@Override
public void onStopped() {
- mHandler.removeCallbacksAndMessages(null);
+ removeMessages();
mHandler.sendEmptyMessage(MSG_STOPPED);
}
@Override
public void onStarted() {
- mHandler.removeCallbacksAndMessages(null);
+ removeMessages();
mHandler.sendEmptyMessage(MSG_STARTED);
}
@Override
public void onError(String error) {
- mHandler.removeCallbacksAndMessages(null);
+ removeMessages();
mHandler.sendMessage(Message.obtain(mHandler, MSG_ERROR, error));
}
@Override
public void onLog(int priority, String msg) {
+ mHandler.sendMessage(Message.obtain(mHandler, MSG_LOG, priority, 0, msg));
}
});
+ }
+
+ @Override
+ protected void onStart() {
+ mFirstRun = false;
+ connectClient();
super.onStart();
}