Skip to content

Commit

Permalink
Play custom URI (#4)
Browse files Browse the repository at this point in the history
  • Loading branch information
devgianlu committed Apr 29, 2021
1 parent 4e31577 commit a487489
Show file tree
Hide file tree
Showing 5 changed files with 125 additions and 31 deletions.
18 changes: 4 additions & 14 deletions app/src/main/java/xyz/gianlu/librespot/android/LoginActivity.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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() {
Expand All @@ -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();
});
}
Expand Down Expand Up @@ -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);

Expand Down
72 changes: 55 additions & 17 deletions app/src/main/java/xyz/gianlu/librespot/android/MainActivity.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
Expand All @@ -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() {
Expand All @@ -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));
Expand All @@ -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
Expand All @@ -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());
}
Expand All @@ -115,15 +134,15 @@ 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 |
GeneralSecurityException |
Session.SpotifyAuthenticationException |
MercuryClient.MercuryException ex) {
Log.e(TAG, "Session creation failed!", ex);
handler.post(() -> callback.failedStartingPlayback(ex));
handler.post(() -> callback.failedGettingReady(ex));
return;
}
} else {
Expand Down Expand Up @@ -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);
}
Expand Down
28 changes: 28 additions & 0 deletions app/src/main/java/xyz/gianlu/librespot/android/Utils.java
Original file line number Diff line number Diff line change
@@ -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");
}
}
34 changes: 34 additions & 0 deletions app/src/main/res/layout/activity_main.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,44 @@
android:orientation="vertical"
android:padding="24dp">

<TextView
android:id="@+id/username"
android:layout_width="match_parent"
android:layout_height="wrap_content" />

<Button
android:id="@+id/logout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/logout" />

<LinearLayout
android:id="@+id/playControls"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="24dp"
android:orientation="vertical"
android:visibility="gone">

<com.google.android.material.textfield.TextInputLayout
android:id="@+id/playUri"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="4dp"
android:hint="@string/playUri">

<com.google.android.material.textfield.TextInputEditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="spotify:track:4cOdK2wGLETKBW3PvgPWqT"
android:inputType="textVisiblePassword"
android:lines="1" />
</com.google.android.material.textfield.TextInputLayout>

<Button
android:id="@+id/play"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/play" />
</LinearLayout>
</LinearLayout>
4 changes: 4 additions & 0 deletions app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,8 @@
<string name="playbackStarted">Playback started!</string>
<string name="failedStartingPlayback">Failed starting playback!</string>
<string name="logout">Logout</string>
<string name="playerReady">Player is ready!</string>
<string name="somethingWentWrong">Something went wrong!</string>
<string name="playUri">Spotify URI to play</string>
<string name="play">Play</string>
</resources>

0 comments on commit a487489

Please sign in to comment.