From a4874897f750263772399c54c409610a9d6c676c Mon Sep 17 00:00:00 2001 From: Gianlu Date: Thu, 29 Apr 2021 15:10:04 +0200 Subject: [PATCH] Play custom URI (#4) --- .../librespot/android/LoginActivity.java | 18 ++--- .../librespot/android/MainActivity.java | 72 ++++++++++++++----- .../xyz/gianlu/librespot/android/Utils.java | 28 ++++++++ app/src/main/res/layout/activity_main.xml | 34 +++++++++ app/src/main/res/values/strings.xml | 4 ++ 5 files changed, 125 insertions(+), 31 deletions(-) create mode 100644 app/src/main/java/xyz/gianlu/librespot/android/Utils.java diff --git a/app/src/main/java/xyz/gianlu/librespot/android/LoginActivity.java b/app/src/main/java/xyz/gianlu/librespot/android/LoginActivity.java index 8f1d137..87c609b 100644 --- a/app/src/main/java/xyz/gianlu/librespot/android/LoginActivity.java +++ b/app/src/main/java/xyz/gianlu/librespot/android/LoginActivity.java @@ -5,13 +5,11 @@ import android.os.Handler; import android.os.Looper; import android.util.Log; -import android.widget.EditText; import android.widget.Toast; import androidx.annotation.UiThread; import androidx.appcompat.app.AppCompatActivity; -import com.google.android.material.textfield.TextInputLayout; import com.spotify.connectstate.Connect; import org.jetbrains.annotations.NotNull; @@ -28,21 +26,12 @@ public final class LoginActivity extends AppCompatActivity { private static final String TAG = LoginActivity.class.getSimpleName(); - @NotNull - private static String getText(@NotNull TextInputLayout layout) { - EditText editText = layout.getEditText(); - if (editText == null) throw new IllegalStateException(); - return editText.getText().toString(); - } - @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); ActivityLoginBinding binding = ActivityLoginBinding.inflate(getLayoutInflater()); setContentView(binding.getRoot()); - File credentialsFile = new File(getDataDir(), "credentials.json"); - LoginCallback callback = new LoginCallback() { @Override public void loggedIn() { @@ -58,11 +47,12 @@ public void failedLoggingIn(@NotNull Exception ex) { }; binding.login.setOnClickListener(v -> { - String username = getText(binding.username); - String password = getText(binding.password); + String username = Utils.getText(binding.username); + String password = Utils.getText(binding.password); if (username.isEmpty() || password.isEmpty()) return; + File credentialsFile = Utils.getCredentialsFile(this); new LoginThread(username, password, credentialsFile, callback).start(); }); } @@ -104,7 +94,7 @@ public void run() { .setDeviceId(null).setDeviceName("librespot-android"); Session session = builder.userPass(username, password).create(); - Log.i(TAG, "Logged in as: " + session.apWelcome().getCanonicalUsername()); + Log.i(TAG, "Logged in as: " + session.username()); LibrespotHolder.set(session); diff --git a/app/src/main/java/xyz/gianlu/librespot/android/MainActivity.java b/app/src/main/java/xyz/gianlu/librespot/android/MainActivity.java index 810c263..2857265 100644 --- a/app/src/main/java/xyz/gianlu/librespot/android/MainActivity.java +++ b/app/src/main/java/xyz/gianlu/librespot/android/MainActivity.java @@ -5,9 +5,11 @@ import android.os.Handler; import android.os.Looper; import android.util.Log; +import android.view.View; import android.widget.Toast; import androidx.annotation.Nullable; +import androidx.annotation.UiThread; import androidx.appcompat.app.AppCompatActivity; import com.spotify.connectstate.Connect; @@ -18,6 +20,8 @@ import java.io.IOException; import java.security.GeneralSecurityException; import java.util.Locale; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; import xyz.gianlu.librespot.android.databinding.ActivityMainBinding; import xyz.gianlu.librespot.android.sink.AndroidSinkOutput; @@ -28,6 +32,7 @@ public final class MainActivity extends AppCompatActivity { private static final String TAG = MainActivity.class.getSimpleName(); + private final ExecutorService executorService = Executors.newSingleThreadExecutor(); @Override protected void onDestroy() { @@ -41,7 +46,7 @@ protected void onCreate(@Nullable Bundle savedInstanceState) { ActivityMainBinding binding = ActivityMainBinding.inflate(getLayoutInflater()); setContentView(binding.getRoot()); - File credentialsFile = new File(getDataDir(), "credentials.json"); + File credentialsFile = Utils.getCredentialsFile(this); if (!credentialsFile.exists() || !credentialsFile.canRead()) { startActivity(new Intent(this, LoginActivity.class) .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK)); @@ -55,10 +60,20 @@ protected void onCreate(@Nullable Bundle savedInstanceState) { .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK)); }); - new PlayerThread(credentialsFile, "spotify:track:1ozGeip1vdU0wY1dIw1scz", new PlayerCallback() { + binding.play.setOnClickListener((v) -> { + String playUri = Utils.getText(binding.playUri); + if (playUri.isEmpty()) + return; + + executorService.execute(new PlayRunnable(playUri, () -> Toast.makeText(MainActivity.this, R.string.playbackStarted, Toast.LENGTH_SHORT).show())); + }); + + executorService.submit(new SetupRunnable(credentialsFile, new SetupCallback() { @Override - public void startedPlayback() { - Toast.makeText(MainActivity.this, R.string.playbackStarted, Toast.LENGTH_SHORT).show(); + public void playerReady(@NotNull String username) { + Toast.makeText(MainActivity.this, R.string.playerReady, Toast.LENGTH_SHORT).show(); + binding.username.setText(username); + binding.playControls.setVisibility(View.VISIBLE); } @Override @@ -68,29 +83,33 @@ public void notLoggedIn() { } @Override - public void failedStartingPlayback(@NotNull Exception ex) { - Toast.makeText(MainActivity.this, R.string.failedStartingPlayback, Toast.LENGTH_SHORT).show(); + public void failedGettingReady(@NotNull Exception ex) { + Toast.makeText(MainActivity.this, R.string.somethingWentWrong, Toast.LENGTH_SHORT).show(); + binding.playControls.setVisibility(View.GONE); } - }).start(); + })); } - private interface PlayerCallback { - void startedPlayback(); + @UiThread + private interface SetupCallback { + void playerReady(@NotNull String username); void notLoggedIn(); - void failedStartingPlayback(@NotNull Exception ex); + void failedGettingReady(@NotNull Exception ex); } - private static class PlayerThread extends Thread { + private interface PlayCallback { + void startedPlayback(); + } + + private static class SetupRunnable implements Runnable { private final File credentialsFile; - private final String playUri; - private final PlayerCallback callback; + private final SetupCallback callback; private final Handler handler; - PlayerThread(@NotNull File credentialsFile, @NotNull String playUri, @NotNull PlayerCallback callback) { + SetupRunnable(@NotNull File credentialsFile, @NotNull SetupCallback callback) { this.credentialsFile = credentialsFile; - this.playUri = playUri; this.callback = callback; this.handler = new Handler(Looper.getMainLooper()); } @@ -115,7 +134,7 @@ public void run() { .setDeviceId(null).setDeviceName("librespot-android"); session = builder.stored(credentialsFile).create(); - Log.i(TAG, "Logged in as: " + session.apWelcome().getCanonicalUsername()); + Log.i(TAG, "Logged in as: " + session.username()); LibrespotHolder.set(session); } catch (IOException | @@ -123,7 +142,7 @@ public void run() { Session.SpotifyAuthenticationException | MercuryClient.MercuryException ex) { Log.e(TAG, "Session creation failed!", ex); - handler.post(() -> callback.failedStartingPlayback(ex)); + handler.post(() -> callback.failedGettingReady(ex)); return; } } else { @@ -152,6 +171,25 @@ public void run() { return; } + handler.post(() -> callback.playerReady(session.username())); + } + } + + private static class PlayRunnable implements Runnable { + private final String playUri; + private final PlayCallback callback; + private final Handler handler = new Handler(Looper.getMainLooper()); + + PlayRunnable(@NotNull String playUri, @NotNull PlayCallback callback) { + this.playUri = playUri; + this.callback = callback; + } + + @Override + public void run() { + Player player = LibrespotHolder.getPlayer(); + if (player == null) return; + player.load(playUri, true, false); handler.post(callback::startedPlayback); } diff --git a/app/src/main/java/xyz/gianlu/librespot/android/Utils.java b/app/src/main/java/xyz/gianlu/librespot/android/Utils.java new file mode 100644 index 0000000..51c259b --- /dev/null +++ b/app/src/main/java/xyz/gianlu/librespot/android/Utils.java @@ -0,0 +1,28 @@ +package xyz.gianlu.librespot.android; + +import android.content.Context; +import android.widget.EditText; + +import com.google.android.material.textfield.TextInputLayout; + +import org.jetbrains.annotations.NotNull; + +import java.io.File; + +public final class Utils { + + private Utils() { + } + + @NotNull + public static String getText(@NotNull TextInputLayout layout) { + EditText editText = layout.getEditText(); + if (editText == null) throw new IllegalStateException(); + return editText.getText().toString(); + } + + @NotNull + public static File getCredentialsFile(@NotNull Context context) { + return new File(context.getDataDir(), "credentials.json"); + } +} diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index 961647c..6f0c6a0 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -5,10 +5,44 @@ android:orientation="vertical" android:padding="24dp"> + +