Cleanup Radio UI Service callback interface.
Bug: 73950974
Test: build and run radio app
Change-Id: I38da6a69d9b8d50d431831f13f8a048723f3ddf1
diff --git a/src/com/android/car/radio/PlayPauseButton.java b/src/com/android/car/radio/PlayPauseButton.java
index 0e1f82d..2f1cb75 100644
--- a/src/com/android/car/radio/PlayPauseButton.java
+++ b/src/com/android/car/radio/PlayPauseButton.java
@@ -28,8 +28,8 @@
public class PlayPauseButton extends ImageView {
private static final String TAG = "Em.PlayPauseButton";
- private final int[] STATE_PLAYING = {R.attr.state_playing};
- private final int[] STATE_PAUSED = {R.attr.state_paused};
+ private static final int[] STATE_PLAYING = {R.attr.state_playing};
+ private static final int[] STATE_PAUSED = {R.attr.state_paused};
private int mPlaybackState = -1;
@@ -40,16 +40,9 @@
/**
* Set the current play state of the button.
*
- * @param playState One of the values from {@link PlaybackState}. Only
- * {@link PlaybackState#STATE_PAUSED} and {@link PlaybackState#STATE_PLAYING}
- * are valid.
+ * @param playState One of the values from {@link PlaybackState}.
*/
public void setPlayState(int playState) {
- if (playState != PlaybackState.STATE_PAUSED && playState != PlaybackState.STATE_PLAYING) {
- throw new IllegalArgumentException("Playback state should be either "
- + "PlaybackState.STATE_PAUSED or PlaybackState.STATE_PLAYING");
- }
-
mPlaybackState = playState;
}
@@ -62,11 +55,14 @@
case PlaybackState.STATE_PLAYING:
mergeDrawableStates(drawableState, STATE_PLAYING);
break;
+ case PlaybackState.STATE_NONE:
case PlaybackState.STATE_PAUSED:
+ case PlaybackState.STATE_STOPPED:
+ case PlaybackState.STATE_CONNECTING:
mergeDrawableStates(drawableState, STATE_PAUSED);
break;
default:
- Log.e(TAG, "Unknown PlaybackState: " + mPlaybackState);
+ Log.e(TAG, "Unsupported PlaybackState: " + mPlaybackState);
}
if (getBackground() != null) {
getBackground().setState(drawableState);
diff --git a/src/com/android/car/radio/RadioController.java b/src/com/android/car/radio/RadioController.java
index 713f64b..8bec5d0 100644
--- a/src/com/android/car/radio/RadioController.java
+++ b/src/com/android/car/radio/RadioController.java
@@ -32,7 +32,6 @@
import android.hardware.radio.RadioManager.ProgramInfo;
import android.hardware.radio.RadioMetadata;
import android.hardware.radio.RadioTuner;
-import android.media.AudioManager;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;
@@ -98,20 +97,13 @@
private final RadioDisplayController mRadioDisplayController;
- /**
- * Keeps track of if the user has manually muted the radio. This value is used to determine
- * whether or not to un-mute the radio after an {@link AudioManager#AUDIOFOCUS_LOSS_TRANSIENT}
- * event has been received.
- */
- private boolean mUserHasMuted;
-
private final RadioStorage mRadioStorage;
private final String mAmBandString;
private final String mFmBandString;
- private List<ProgramInfoChangeListener> mProgramInfoChangeListeners = new ArrayList<>();
- private List<RadioServiceConnectionListener> mRadioServiceConnectionListeners =
+ private final List<ProgramInfoChangeListener> mProgramInfoChangeListeners = new ArrayList<>();
+ private final List<RadioServiceConnectionListener> mRadioServiceConnectionListeners =
new ArrayList<>();
/**
@@ -255,9 +247,6 @@
try {
mRadioDisplayController.setSingleChannelDisplay(mRadioBackground);
- // Ensure the play button properly reflects the current mute state.
- mRadioDisplayController.setPlayPauseButtonState(mRadioManager.isMuted());
-
// TODO(b/73950974): use callback only
ProgramInfo current = mRadioManager.getCurrentProgramInfo();
if (current != null) mCallback.onCurrentProgramInfoChanged(current);
@@ -442,18 +431,6 @@
}
/**
- * Closes any active {@link RadioTuner}s and releases audio focus.
- */
- private void close() {
- if (Log.isLoggable(TAG, Log.DEBUG)) {
- Log.d(TAG, "close()");
- }
-
- // Lost focus, so display that the radio is not playing anymore.
- mRadioDisplayController.setPlayPauseButtonState(true);
- }
-
- /**
* Closes all active connections in the {@link RadioController}.
*/
public void shutdown() {
@@ -471,8 +448,6 @@
Log.e(TAG, "tuneToRadioChannel(); remote exception: " + e.getMessage());
}
}
-
- close();
}
@Override
@@ -515,23 +490,10 @@
mRadioDisplayController.setChannelIsPreset(mRadioStorage.isPreset(sel));
// Notify that the current radio station has changed.
- if (mProgramInfoChangeListeners != null) {
- for (ProgramInfoChangeListener listener : mProgramInfoChangeListeners) {
- listener.onProgramInfoChanged(info);
- }
+ for (ProgramInfoChangeListener listener : mProgramInfoChangeListeners) {
+ listener.onProgramInfoChanged(info);
}
}
-
- @Override
- public void onRadioMuteChanged(boolean isMuted) {
- mRadioDisplayController.setPlayPauseButtonState(isMuted);
- }
-
- @Override
- public void onError(int status) {
- Log.e(TAG, "Radio callback error with status: " + status);
- close();
- }
};
private final View.OnClickListener mBackwardSeekClickListener = new View.OnClickListener() {
@@ -587,11 +549,6 @@
} else {
mRadioManager.mute();
}
-
- boolean isMuted = mRadioManager.isMuted();
-
- mUserHasMuted = isMuted;
- mRadioDisplayController.setPlayPauseButtonState(isMuted);
} catch (RemoteException e) {
Log.e(TAG, "playPauseClickListener(); remote exception: " + e.getMessage());
}
@@ -638,6 +595,7 @@
}
mRadioDisplayController.setEnabled(true);
+ mRadioManager.addPlaybackStateListener(mRadioDisplayController);
if (mRadioErrorDisplay != null) {
mRadioErrorDisplay.setVisibility(View.GONE);
diff --git a/src/com/android/car/radio/RadioDisplayController.java b/src/com/android/car/radio/RadioDisplayController.java
index f9b1b7e..9c1179a 100644
--- a/src/com/android/car/radio/RadioDisplayController.java
+++ b/src/com/android/car/radio/RadioDisplayController.java
@@ -17,17 +17,20 @@
package com.android.car.radio;
import android.content.Context;
-import android.media.session.PlaybackState;
+import android.support.v4.media.session.PlaybackStateCompat;
import android.text.TextUtils;
import android.view.View;
import android.view.ViewStub;
import android.widget.ImageView;
import android.widget.TextView;
+import com.android.car.radio.audio.IPlaybackStateListener;
+import com.android.car.radio.utils.LocalInterface;
+
/**
* Controller that controls the appearance state of various UI elements in the radio.
*/
-public class RadioDisplayController {
+public class RadioDisplayController implements IPlaybackStateListener, LocalInterface {
private final Context mContext;
private TextView mChannelBand;
@@ -225,21 +228,15 @@
}
}
- /**
- * Sets the current state of the play button. If the given {@code muted} value is {@code true},
- * then the button display a play icon. If {@code false}, then the button will display a
- * pause icon.
- */
- public void setPlayPauseButtonState(boolean muted) {
+ @Override
+ public void onPlaybackStateChanged(@PlaybackStateCompat.State int state) {
if (mPlayButton != null) {
- mPlayButton.setPlayState(muted
- ? PlaybackState.STATE_PAUSED : PlaybackState.STATE_PLAYING);
+ mPlayButton.setPlayState(state);
mPlayButton.refreshDrawableState();
}
if (mPresetPlayButton != null) {
- mPresetPlayButton.setPlayState(muted
- ? PlaybackState.STATE_PAUSED : PlaybackState.STATE_PLAYING);
+ mPresetPlayButton.setPlayState(state);
mPresetPlayButton.refreshDrawableState();
}
}
diff --git a/src/com/android/car/radio/RadioService.java b/src/com/android/car/radio/RadioService.java
index 5cbe278..e51a2ab 100644
--- a/src/com/android/car/radio/RadioService.java
+++ b/src/com/android/car/radio/RadioService.java
@@ -28,7 +28,6 @@
import android.os.IBinder;
import android.os.RemoteException;
import android.support.v4.media.MediaBrowserCompat.MediaItem;
-import android.support.v4.media.session.PlaybackStateCompat;
import android.util.Log;
import androidx.media.MediaBrowserServiceCompat;
@@ -44,6 +43,7 @@
import com.android.car.radio.service.IRadioCallback;
import com.android.car.radio.service.IRadioManager;
import com.android.car.radio.storage.RadioStorage;
+import com.android.car.radio.utils.LocalInterface;
import java.util.ArrayList;
import java.util.HashSet;
@@ -58,7 +58,7 @@
*
* <p>Utilize the {@link RadioBinder} to perform radio operations.
*/
-public class RadioService extends MediaBrowserServiceCompat implements IPlaybackStateListener {
+public class RadioService extends MediaBrowserServiceCompat implements LocalInterface {
private static String TAG = "BcRadioApp.uisrv";
@@ -138,8 +138,6 @@
mRadioStorage.addPresetsChangeListener(mPresetsListener);
onPresetsChanged();
- mAudioStreamController.addPlaybackStateListener(this);
-
openRadioBandInternal(mRadioStorage.getStoredRadioBand());
mRadioSuccessfullyInitialized = true;
@@ -216,23 +214,6 @@
}
}
- /* TODO(b/73950974): remove onRadioMuteChanged from IRadioCallback,
- * use IPlaybackStateListener directly.
- */
- @Override
- public void onPlaybackStateChanged(@PlaybackStateCompat.State int state) {
- boolean muted = state != PlaybackStateCompat.STATE_PLAYING;
- synchronized (mLock) {
- for (IRadioCallback callback : mRadioTunerCallbacks) {
- try {
- callback.onRadioMuteChanged(muted);
- } catch (RemoteException e) {
- Log.e(TAG, "Mute state change callback failed", e);
- }
- }
- }
- }
-
/**
* Closes any active {@link RadioTuner}s and releases audio focus.
*/
@@ -379,6 +360,16 @@
return mCurrentProgram;
}
+ @Override
+ public void addPlaybackStateListener(IPlaybackStateListener callback) {
+ mAudioStreamController.addPlaybackStateListener(callback);
+ }
+
+ @Override
+ public void removePlaybackStateListener(IPlaybackStateListener callback) {
+ mAudioStreamController.removePlaybackStateListener(callback);
+ }
+
/**
* Returns {@code true} if the radio was able to successfully initialize. A value of
* {@code false} here could mean that the {@code RadioService} was not able to connect to
@@ -442,14 +433,6 @@
mReOpenRadioTunerCount++;
}
-
- try {
- for (IRadioCallback callback : mRadioTunerCallbacks) {
- callback.onError(status);
- }
- } catch (RemoteException e) {
- Log.e(TAG, "onError(); Failed to notify IRadioCallbacks: " + e.getMessage());
- }
}
@Override
@@ -494,9 +477,4 @@
return super.onStartCommand(intent, flags, startId);
}
-
- @Override
- public IBinder asBinder() {
- throw new UnsupportedOperationException("Not a binder");
- }
}
diff --git a/src/com/android/car/radio/media/TunerSession.java b/src/com/android/car/radio/media/TunerSession.java
index 3b77057..a565046 100644
--- a/src/com/android/car/radio/media/TunerSession.java
+++ b/src/com/android/car/radio/media/TunerSession.java
@@ -23,7 +23,6 @@
import android.hardware.radio.RadioManager.ProgramInfo;
import android.net.Uri;
import android.os.Bundle;
-import android.os.IBinder;
import android.os.RemoteException;
import android.support.v4.media.MediaMetadataCompat;
import android.support.v4.media.RatingCompat;
@@ -39,6 +38,7 @@
import com.android.car.radio.R;
import com.android.car.radio.audio.IPlaybackStateListener;
import com.android.car.radio.service.IRadioManager;
+import com.android.car.radio.utils.LocalInterface;
import com.android.car.radio.utils.ThrowingRunnable;
import java.util.Objects;
@@ -46,7 +46,8 @@
/**
* Implementation of tuner's MediaSession.
*/
-public class TunerSession extends MediaSessionCompat implements IPlaybackStateListener {
+public class TunerSession extends MediaSessionCompat
+ implements IPlaybackStateListener, LocalInterface {
private static final String TAG = "BcRadioApp.msess";
private final Object mLock = new Object();
@@ -191,9 +192,4 @@
}
}
}
-
- @Override
- public IBinder asBinder() {
- throw new UnsupportedOperationException("Not a binder");
- }
}
diff --git a/src/com/android/car/radio/service/IRadioCallback.aidl b/src/com/android/car/radio/service/IRadioCallback.aidl
index d1ecf93..95bab45 100644
--- a/src/com/android/car/radio/service/IRadioCallback.aidl
+++ b/src/com/android/car/radio/service/IRadioCallback.aidl
@@ -29,19 +29,4 @@
* @param info The current program info.
*/
void onCurrentProgramInfoChanged(in RadioManager.ProgramInfo info);
-
- /**
- * Called when the mute state of the radio has changed.
- *
- * @param isMuted {@code true} if the radio is muted.
- */
- void onRadioMuteChanged(boolean isMuted);
-
- /**
- * Called when the radio has encountered an error.
- *
- * @param status One of the error states in {@link RadioManager}. For example,
- * {@link RadioManager#ERROR_HARDWARE_FAILURE}.
- */
- void onError(int status);
}
diff --git a/src/com/android/car/radio/service/IRadioManager.aidl b/src/com/android/car/radio/service/IRadioManager.aidl
index ba005ba..4902c4b 100644
--- a/src/com/android/car/radio/service/IRadioManager.aidl
+++ b/src/com/android/car/radio/service/IRadioManager.aidl
@@ -19,6 +19,7 @@
import android.hardware.radio.RadioManager;
import com.android.car.broadcastradio.support.Program;
+import com.android.car.radio.audio.IPlaybackStateListener;
import com.android.car.radio.service.IRadioCallback;
/**
@@ -96,6 +97,16 @@
RadioManager.ProgramInfo getCurrentProgramInfo();
/**
+ * Adds {@link IPlaybackStateListener} listener for play/pause notifications.
+ */
+ void addPlaybackStateListener(in IPlaybackStateListener callback);
+
+ /**
+ * Removes {@link IPlaybackStateListener} listener.
+ */
+ void removePlaybackStateListener(in IPlaybackStateListener callback);
+
+ /**
* Returns {@code true} if the radio was able to successfully initialize. A value of
* {@code false} here could mean that the {@code RadioService} was not able to connect to
* the {@link RadioManager} or there were no radio modules on the current device.
diff --git a/src/com/android/car/radio/utils/LocalInterface.java b/src/com/android/car/radio/utils/LocalInterface.java
new file mode 100644
index 0000000..ddc9fa7
--- /dev/null
+++ b/src/com/android/car/radio/utils/LocalInterface.java
@@ -0,0 +1,34 @@
+/**
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.car.radio.utils;
+
+import android.os.IBinder;
+import android.os.IInterface;
+
+/**
+ * Marks given I-Class as not-a-binder.
+ *
+ * It saves some copy-pasting for interfaces that are not meant to be used cross-process.
+ */
+public interface LocalInterface extends IInterface {
+ /**
+ * Dummy implementation of {@link IInterface#asBinder}.
+ */
+ default IBinder asBinder() {
+ throw new UnsupportedOperationException("Not a binder");
+ }
+}