Skip to content
This repository has been archived by the owner on Aug 27, 2024. It is now read-only.

Commit

Permalink
Merge remote-tracking branch 'origin/master'
Browse files Browse the repository at this point in the history
  • Loading branch information
weblate committed Aug 12, 2017
2 parents 960b0f8 + 17502fb commit c8e9d9f
Show file tree
Hide file tree
Showing 6 changed files with 80 additions and 73 deletions.
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ Transistor - Radio App for Android

**Version 2.3.x ("Kooks")**

Transistor is a bare bones app for listening to radio programs over the internet. The app stores stations as files on your device's external storage. It currently understands streams encoded in MP3, AAC and Ogg/Opus.
Transistor is a bare bones app for listening to radio programs over the internet. The app stores stations as files on your device's external storage. It currently understands streams encoded in MP3, AAC and Ogg/Opus(*).

Important note: This is an app of type BYOS ("bring your own station"). It does not feature any kind of built-in search option. You will have to manually add radio stations.

Expand Down Expand Up @@ -66,3 +66,5 @@ Tapping and holding a radio station will toggle a tiny vibration.

### Permission "WAKE_LOCK"
During Playback Transistor acquires a so called partial wake lock. That prevents the Android system to stop playback for power saving reasons.

(*) Opus playback is only supported on devices running Android 5.0+
34 changes: 13 additions & 21 deletions app/src/main/java/org/y20k/transistor/ListFragment.java
Original file line number Diff line number Diff line change
Expand Up @@ -265,17 +265,24 @@ public boolean onOptionsItemSelected(MenuItem item) {

// CASE REFRESH LIST
case R.id.menu_refresh:
// stop player service using intent
Intent intent = new Intent(mActivity, PlayerService.class);
intent.setAction(ACTION_DISMISS);
mActivity.startService(intent);

// manually refresh list of stations (force reload) - useful when editing playlist files manually outside of Transistor
mCollectionViewModel.getStationList().setValue(StationListHelper.loadStationListFromStorage(mActivity));
ArrayList<Station> newStationList = StationListHelper.loadStationListFromStorage(mActivity);
mCollectionViewModel.getStationList().setValue(newStationList);

// update player fragment in tablet mode
if (mTwoPane && newStationList.size() > 0) {
mCollectionAdapter.showPlayerFragment(newStationList.get(0), false);
}

// check list if is empty and show action call if so
((MainActivity) mActivity).togglePlayerContainerVisibility();
toggleActionCall();

// stop player service using intent
Intent intent = new Intent(mActivity, PlayerService.class);
intent.setAction(ACTION_DISMISS);
mActivity.startService(intent);

// notify user
Toast.makeText(mActivity, mActivity.getString(R.string.toastmessage_list_refreshed), Toast.LENGTH_LONG).show();
Expand All @@ -294,18 +301,6 @@ public void onRequestPermissionsResult(int requestCode, @NonNull String[] permis
super.onRequestPermissionsResult(requestCode, permissions, grantResults);

switch (requestCode) {
case PERMISSION_REQUEST_IMAGE_PICKER_READ_EXTERNAL_STORAGE: {
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// permission granted - get system picker for images
Intent pickImageIntent = new Intent(Intent.ACTION_PICK, android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
mActivity.startActivityForResult(pickImageIntent, REQUEST_LOAD_IMAGE);
} else {
// permission denied
Toast.makeText(mActivity, mActivity.getString(R.string.toastalert_permission_denied) + " READ_EXTERNAL_STORAGE", Toast.LENGTH_LONG).show();
}
break;
}

case PERMISSION_REQUEST_STATION_FETCHER_READ_EXTERNAL_STORAGE: {
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// permission granted - fetch station from given Uri
Expand All @@ -323,9 +318,6 @@ public void onRequestPermissionsResult(int requestCode, @NonNull String[] permis
/* Updates list state after delete */
public void updateListAfterDelete(Station newStation, int stationId) {
mCollectionAdapter.setStationUriSelected(newStation.getStreamUri());
if (mTwoPane && mCollectionAdapter.getItemCount() > stationId) {
mCollectionAdapter.notifyItemChanged(stationId);
}
}


Expand Down Expand Up @@ -362,7 +354,7 @@ private void handleStreamingLink(Intent intent) {
}
// unsuccessful - log failure
else {
LogHelper.v(LOG_TAG, "Received an empty intent");
LogHelper.i(LOG_TAG, "Received an empty intent");
}
}

Expand Down
23 changes: 17 additions & 6 deletions app/src/main/java/org/y20k/transistor/MainActivity.java
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,15 @@ public void onRequestPermissionsResult(int requestCode, @NonNull String[] permis
// permission denied
Toast.makeText(this, getString(R.string.toastalert_permission_denied) + " READ_EXTERNAL_STORAGE", Toast.LENGTH_LONG).show();
}
break;
}
case PERMISSION_REQUEST_STATION_FETCHER_READ_EXTERNAL_STORAGE: {
// let list fragment handle the request
Fragment listFragment = getSupportFragmentManager().findFragmentByTag(LIST_FRAGMENT_TAG);
if (listFragment != null) {
listFragment.onRequestPermissionsResult(requestCode, permissions, grantResults);
}
break;
}
}
}
Expand Down Expand Up @@ -334,7 +343,7 @@ public int handleStationDelete(Station station) {
// delete m3u playlist file
File stationPlaylistFile = station.getStationPlaylistFile();
if (stationPlaylistFile != null && stationPlaylistFile.exists() && stationPlaylistFile.delete()) {
success = true;;
success = true;
}

// remove station and notify user
Expand All @@ -349,20 +358,22 @@ public int handleStationDelete(Station station) {
// remove station from new station list
newStationList.remove(stationId);
// determine ID of next station
if (newStationList.size() >= stationId) {
if (newStationList.size() >= stationId && stationId > 0) {
stationId--;
} else {
stationId = 0;
}

// show next station in list
Fragment listFragment = getSupportFragmentManager().findFragmentByTag(LIST_FRAGMENT_TAG);
if (mTwoPane && listFragment!= null && listFragment.isAdded() && stationId > 0) {
((ListFragment)listFragment).updateListAfterDelete(mStationList.get(stationId), stationId);
if (mTwoPane && listFragment!= null && listFragment.isAdded() && newStationList.size() > 0) {
((ListFragment)listFragment).updateListAfterDelete(newStationList.get(stationId), stationId);
}

// show next station in player view
Fragment playerFragment = getSupportFragmentManager().findFragmentByTag(PLAYER_FRAGMENT_TAG);
if (mTwoPane && playerFragment!= null && playerFragment.isAdded() && stationId > 0) {
((PlayerFragment)playerFragment).updatePlayerAfterDelete(mStationList.get(stationId));
if (mTwoPane && playerFragment!= null && playerFragment.isAdded() && newStationList.size() > 0) {
((PlayerFragment)playerFragment).updatePlayerAfterDelete(newStationList.get(stationId));
}

// update live data list of stations - used in CollectionAdapter
Expand Down
47 changes: 20 additions & 27 deletions app/src/main/java/org/y20k/transistor/PlayerService.java
Original file line number Diff line number Diff line change
Expand Up @@ -190,11 +190,6 @@ else if (intent.getAction().equals(ACTION_DISMISS)) {
if (mStation != null && mStation.getPlaybackState() != PLAYBACK_STATE_STOPPED) {
mController.getTransportControls().stop();
}

// dismiss notification
NotificationHelper.stop();
// set media session in-active
mSession.setActive(false);
}

// listen for media button
Expand Down Expand Up @@ -321,7 +316,7 @@ public void onLoadingChanged(boolean isLoading) {
state = "Media source is currently NOT being loaded.";
// // update controller - stop playback
// if (mPlayback) {
// mController.getTransportControls().stop();
// mController.getTransportControls().pause();
// }
}
LogHelper.v(LOG_TAG, "State of loading has changed: " + state);
Expand Down Expand Up @@ -402,14 +397,14 @@ public void onAudioFocusChange(int focusChange) {
// loss of audio focus of unknown duration
case AudioManager.AUDIOFOCUS_LOSS:
if (mStation.getPlaybackState() != PLAYBACK_STATE_STOPPED && mExoPlayer.getPlayWhenReady()) {
mController.getTransportControls().stop();
mController.getTransportControls().pause();
}
break;
// transient loss of audio focus - e.g. phone call
case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT:
if (mStation.getPlaybackState() != PLAYBACK_STATE_STOPPED && mExoPlayer != null && mExoPlayer.getPlayWhenReady()) {
mAudioFocusLossTransient = true;
mController.getTransportControls().stop();
mController.getTransportControls().pause();;
}
else if (mStation.getPlaybackState() == PLAYBACK_STATE_STOPPED && mExoPlayer != null && mExoPlayer.getPlayWhenReady()) {
mAudioFocusLossTransient = true;
Expand Down Expand Up @@ -524,7 +519,7 @@ private void startPlayback() {


/* Stops playback */
private void stopPlayback() {
private void stopPlayback(boolean dismissNotification) {
// check for null - can happen after a crash during playback
if (mStation == null || !mExoPlayer.getPlayWhenReady() || mSession== null) {
LogHelper.e(LOG_TAG, "Stopping playback. Station is null.");
Expand Down Expand Up @@ -565,11 +560,17 @@ private void stopPlayback() {
// update playback state
mSession.setPlaybackState(getSessionPlaybackState());

// update notification
NotificationHelper.update(mStation, mSession);

// keep media session active
mSession.setActive(true);
if (dismissNotification) {
// dismiss notification
NotificationHelper.stop();
// don't keep media session active
mSession.setActive(false);
} else {
// update notification
NotificationHelper.update(mStation, mSession);
// keep media session active
mSession.setActive(true);
}

// send local broadcast: playback stopped
Intent intent = new Intent();
Expand Down Expand Up @@ -760,7 +761,7 @@ public void onReceive(Context context, Intent intent) {
if (mStation.getPlaybackState() != PLAYBACK_STATE_STOPPED && AudioManager.ACTION_AUDIO_BECOMING_NOISY.equals(intent.getAction())) {
LogHelper.v(LOG_TAG, "Headphones unplugged. Stopping playback.");
// stop playback
mController.getTransportControls().stop();
mController.getTransportControls().pause();
// notify user
Toast.makeText(context, context.getString(R.string.toastalert_headphones_unplugged), Toast.LENGTH_LONG).show();
}
Expand All @@ -786,13 +787,13 @@ public void onPlay() {
@Override
public void onPause() {
// stop playback
stopPlayback();
stopPlayback(false);
}

@Override
public void onStop() {
// stop playback
stopPlayback();
stopPlayback(true);
}

}
Expand All @@ -809,10 +810,9 @@ private class InitializeExoPlayerHelper extends AsyncTask<Void, Void, Integer> {
@Override
protected Integer doInBackground(Void... voids) {
String contentType = "";
URLConnection connection = null;

try {
connection = new URL(mStation.getStreamUri().toString()).openConnection();
URLConnection connection = new URL(mStation.getStreamUri().toString()).openConnection();
connection.connect();
contentType = connection.getContentType();
if (contentType == null) {
Expand Down Expand Up @@ -846,7 +846,7 @@ protected Integer doInBackground(Void... voids) {
protected void onPostExecute(Integer connectionType) {
if (connectionType == CONNECTION_TYPE_ERROR) {
Toast.makeText(PlayerService.this, getString(R.string.toastalert_unable_to_connect), Toast.LENGTH_LONG).show();
stopPlayback();
stopPlayback(false);
} else {
// prepare player
prepareExoPLayer(connectionType);
Expand Down Expand Up @@ -909,13 +909,6 @@ public void playerMetadata(String key, String value) {
LocalBroadcastManager.getInstance(getApplicationContext()).sendBroadcast(i);
LogHelper.v(LOG_TAG, "LocalBroadcast: ACTION_METADATA_CHANGED -> EXTRA_STATION");

// // save metadata to shared preferences
// SharedPreferences settings = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
// SharedPreferences.Editor editor = settings.edit();
// editor.putBoolean()
// editor.putString(PREF_STATION_METADATA, mStationMetadata);
// editor.apply();

// update media session metadata
mSession.setMetadata(getSessionMetadata(getApplicationContext(), mStation));

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,9 +89,6 @@ public CollectionAdapter(Activity activity, File folder, boolean twoPane, Uri st
// create empty station list
mStationList = new ArrayList<Station>();

// // load state
// loadAppState(mActivity);

// initialize BroadcastReceiver that listens for playback changes
initializeBroadcastReceivers();

Expand All @@ -100,7 +97,6 @@ public CollectionAdapter(Activity activity, File folder, boolean twoPane, Uri st
mCollectionViewModel.getTwoPane().observe((LifecycleOwner)mActivity, createTwoPaneObserver());
mCollectionViewModel.getStationList().observe((LifecycleOwner) mActivity, createStationListObserver());


}


Expand Down Expand Up @@ -227,6 +223,12 @@ public int getItemCount() {
/* Setter for mStationUriSelected */
public void setStationUriSelected(Uri stationUriSelected) {
mStationUriSelected = stationUriSelected;
if (mTwoPane) {
int stationID = StationListHelper.findStationId(mStationList, stationUriSelected);
if (stationID >= 0 && stationID < mStationList.size()) {
notifyItemChanged(stationID);
}
}
saveAppState(mActivity);
}

Expand Down Expand Up @@ -487,25 +489,22 @@ public void onChanged(@Nullable ArrayList<Station> newStationList) {
// inform this adapter about the changes
diffResult.dispatchUpdatesTo(CollectionAdapter.this);

// FIRST RUN:
if (mTwoPane && mStationUriSelected == null && newStationList.size() != 0) {
// FIRST RUN: retrieve mStationUriSelected
if (mStationUriSelected == null && newStationList.size() != 0) {
// load state - get mStationUrlSelected
loadAppState(mActivity);
// if mStationUrlSelected still null
if (mStationUriSelected == null) {
// check if mStationUrlSelected still is null or if station is not in list
if (mStationUriSelected == null || StationListHelper.findStationId(newStationList, mStationUriSelected) == -1) {
// set first station as selected
mStationUriSelected = newStationList.get(0).getStreamUri();
showPlayerFragment(newStationList.get(0), false);
} else if (StationListHelper.findStationId(newStationList, mStationUriSelected) != -1) {
}
// tablet mode
if (mTwoPane && mStationUriSelected != null) {
// show player fragment with station corresponding to mStationUriSelected
showPlayerFragment(StationListHelper.findStation(newStationList, mStationUriSelected), false);
}
}

// check if mStationUriSelected still corresponds with a station in list
int StationIdSelected = StationListHelper.findStationId(newStationList, mStationUriSelected);
if (mTwoPane && StationIdSelected == -1) {
mStationUriSelected = newStationList.get(0).getStreamUri();
}

}
};
}
Expand Down
14 changes: 12 additions & 2 deletions app/src/main/java/org/y20k/transistor/core/Station.java
Original file line number Diff line number Diff line change
Expand Up @@ -536,6 +536,10 @@ public Bitmap fetchImageFile(URL stationURL) {

LogHelper.v(LOG_TAG, "fetching favicon: " + mStationImageFile.toString());

//
Bitmap stationImage = null;


// Get favicon address
String host = stationURL.getHost();
if (!host.startsWith("www")) {
Expand Down Expand Up @@ -566,12 +570,18 @@ public Bitmap fetchImageFile(URL stationURL) {

// get image daata and decode stream
InputStream inputStream = connection.getInputStream();
return BitmapFactory.decodeStream(inputStream);
stationImage = BitmapFactory.decodeStream(inputStream);

// close stream and disconnect connection
inputStream.close();
connection.disconnect();

return stationImage;

} catch (IOException e) {
LogHelper.e(LOG_TAG, "Unable to load favicon from URL: " + faviconUrlString);
e.printStackTrace();
return null;
return stationImage;
}
}

Expand Down

0 comments on commit c8e9d9f

Please sign in to comment.