Snap for 4829593 from 317f803138b6f9757a3961771b7a07ce54f803f6 to pi-release

Change-Id: I90c762d3b8355b14b086ac73caa3f7f7077b3bb6
diff --git a/src/com/android/car/radio/CarRadioActivity.java b/src/com/android/car/radio/CarRadioActivity.java
index 557b1c6..642e995 100644
--- a/src/com/android/car/radio/CarRadioActivity.java
+++ b/src/com/android/car/radio/CarRadioActivity.java
@@ -255,7 +255,7 @@
         public void onItemClick(int position) {
             getDrawerController().closeDrawer();
             if (position < SUPPORTED_RADIO_BANDS.size()) {
-                mRadioController.openRadioBand(SUPPORTED_RADIO_BANDS.get(position).first);
+                mRadioController.switchBand(SUPPORTED_RADIO_BANDS.get(position).first);
             } else if (position == SUPPORTED_RADIO_BANDS.size()) {
                 startManualTuner();
             } else {
diff --git a/src/com/android/car/radio/RadioController.java b/src/com/android/car/radio/RadioController.java
index 3200295..713f64b 100644
--- a/src/com/android/car/radio/RadioController.java
+++ b/src/com/android/car/radio/RadioController.java
@@ -44,6 +44,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.ProgramSelectorUtils;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -106,11 +107,6 @@
 
     private final RadioStorage mRadioStorage;
 
-    /**
-     * The current radio band. This value is one of the BAND_* values from {@link RadioManager}.
-     * For example, {@link RadioManager#BAND_FM}.
-     */
-    private int mCurrentRadioBand = RadioStorage.INVALID_RADIO_BAND;
     private final String mAmBandString;
     private final String mFmBandString;
 
@@ -285,9 +281,11 @@
 
     /**
      * Returns the band this radio is currently tuned to.
+     *
+     * TODO(b/73950974): don't be AM/FM exclusive
      */
     public int getCurrentRadioBand() {
-        return mCurrentRadioBand;
+        return ProgramSelectorUtils.getRadioBand(mCurrentProgram.getSelector());
     }
 
     /**
@@ -303,71 +301,23 @@
     }
 
     /**
-     * Opens the given current radio band. Currently, this only supports FM and AM bands.
+     * Switch radio band. Currently, this only supports FM and AM bands.
      *
-     * @param radioBand One of {@link RadioManager#BAND_FM}, {@link RadioManager#BAND_AM},
-     *                  {@link RadioManager#BAND_FM_HD} or {@link RadioManager#BAND_AM_HD}.
+     * @param radioBand One of {@link RadioManager#BAND_FM}, {@link RadioManager#BAND_AM}.
      */
-    public void openRadioBand(int radioBand) {
-        if (mRadioManager == null || radioBand == mCurrentRadioBand) {
-            return;
-        }
-
-        setCurrentRadioBand(radioBand);
-        mRadioStorage.storeRadioBand(mCurrentRadioBand);
-
+    public void switchBand(int radioBand) {
         try {
-            mRadioManager.openRadioBand(radioBand);
-
-            updateAmFmDisplayState();
-
-            // Sets the initial mute state. This will resolve the mute state should be if an
-            // {@link AudioManager#AUDIOFOCUS_LOSS_TRANSIENT} event is received followed by an
-            // {@link AudioManager#AUDIOFOCUS_GAIN} event. In this case, the radio will un-mute itself
-            // if the user has not muted beforehand.
-            if (mUserHasMuted) {
-                mRadioManager.mute();
-            }
-
-            // Ensure the play button properly reflects the current mute state.
-            mRadioDisplayController.setPlayPauseButtonState(mRadioManager.isMuted());
-
-            maybeTuneToStoredRadioChannel();
+            mRadioManager.switchBand(radioBand);
         } catch (RemoteException e) {
-            Log.e(TAG, "openRadioBand(); remote exception: " + e.getMessage());
+            Log.e(TAG, "Couldn't switch band", e);
         }
     }
 
     /**
-     * Attempts to tune to the last played radio channel for a particular band. For example, if
-     * the user switches to the AM band from FM, this method will attempt to tune to the last
-     * AM band that the user was on.
-     *
-     * <p>If a stored radio station cannot be found, then this method will initiate a seek so that
-     * the radio is always on a valid radio station.
+     * Delegates to the {@link RadioDisplayController} to highlight the radio band.
      */
-    private void maybeTuneToStoredRadioChannel() {
-        int storedChannel = mRadioStorage.getStoredRadioChannel(mCurrentRadioBand);
-
-        if (storedChannel != RadioStorage.INVALID_RADIO_CHANNEL) {
-            Log.i(TAG, "Restoring stored program: " + storedChannel);
-            tune(ProgramSelectorExt.createAmFmSelector(storedChannel));
-        } else {
-            Log.i(TAG, "No stored program, seeking forward to not play static");
-            try {
-                mRadioManager.seekForward();
-            } catch (RemoteException e) {
-                Log.e(TAG, "Couldn't seek forward", e);
-            }
-        }
-    }
-
-    /**
-     * Delegates to the {@link RadioDisplayController} to highlight the radio band that matches
-     * up to {@link #mCurrentRadioBand}.
-     */
-    private void updateAmFmDisplayState() {
-        switch (mCurrentRadioBand) {
+    private void updateAmFmDisplayState(int band) {
+        switch (band) {
             case RadioManager.BAND_FM:
                 mRadioDisplayController.setChannelBand(mFmBandString);
                 break;
@@ -395,8 +345,7 @@
             mCurrentlyDisplayedChannel = 0;
             mRadioDisplayController.setChannelNumber("");
 
-            mCurrentRadioBand = RadioStorage.INVALID_RADIO_BAND;
-            updateAmFmDisplayState();
+            updateAmFmDisplayState(RadioStorage.INVALID_RADIO_BAND);
             return;
         }
 
@@ -407,8 +356,7 @@
         boolean isAm = ProgramSelectorExt.isAmFrequency(freq);
         int band = isAm ? RadioManager.BAND_AM : RadioManager.BAND_FM;
 
-        mCurrentRadioBand = band;
-        updateAmFmDisplayState();
+        updateAmFmDisplayState(band);
 
         if (isAm && wasAm || !isAm && wasFm) {
             mAnimator.setIntValues((int)mCurrentlyDisplayedChannel, (int)freq);
@@ -494,13 +442,6 @@
     }
 
     /**
-     * Sets the internal {@link #mCurrentRadioBand} to be the given radio band.
-     */
-    private void setCurrentRadioBand(int radioBand) {
-        mCurrentRadioBand = radioBand;
-    }
-
-    /**
      * Closes any active {@link RadioTuner}s and releases audio focus.
      */
     private void close() {
@@ -573,8 +514,6 @@
 
             mRadioDisplayController.setChannelIsPreset(mRadioStorage.isPreset(sel));
 
-            mRadioStorage.storeRadioChannel(mCurrentRadioBand, info.getChannel());
-
             // Notify that the current radio station has changed.
             if (mProgramInfoChangeListeners != null) {
                 for (ProgramInfoChangeListener listener : mProgramInfoChangeListeners) {
@@ -584,16 +523,6 @@
         }
 
         @Override
-        public void onRadioBandChanged(int radioBand) {
-            if (Log.isLoggable(TAG, Log.DEBUG)) {
-                Log.d(TAG, "onRadioBandChanged: " + radioBand);
-            }
-
-            setCurrentRadioBand(radioBand);
-            updateAmFmDisplayState();
-        }
-
-        @Override
         public void onRadioMuteChanged(boolean isMuted) {
             mRadioDisplayController.setPlayPauseButtonState(isMuted);
         }
@@ -718,12 +647,6 @@
 
                 mRadioManager.addRadioTunerCallback(mCallback);
 
-                int radioBand = mRadioStorage.getStoredRadioBand();
-
-                // Upon successful connection, open the radio.
-                openRadioBand(radioBand);
-                maybeTuneToStoredRadioChannel();
-
                 // Notify listeners
                 for (RadioServiceConnectionListener listener : mRadioServiceConnectionListeners) {
                     listener.onRadioServiceConnected();
diff --git a/src/com/android/car/radio/RadioService.java b/src/com/android/car/radio/RadioService.java
index 3683970..fc5a9ad 100644
--- a/src/com/android/car/radio/RadioService.java
+++ b/src/com/android/car/radio/RadioService.java
@@ -34,6 +34,7 @@
 
 import com.android.car.broadcastradio.support.Program;
 import com.android.car.broadcastradio.support.media.BrowseTree;
+import com.android.car.broadcastradio.support.platform.ProgramSelectorExt;
 import com.android.car.radio.audio.AudioStreamController;
 import com.android.car.radio.audio.IPlaybackStateListener;
 import com.android.car.radio.media.TunerSession;
@@ -80,7 +81,6 @@
     private boolean mRadioSuccessfullyInitialized;
 
     private ProgramInfo mCurrentProgram;
-    private int mCurrentRadioBand = RadioManager.BAND_FM;
 
     private RadioManagerExt mRadioManager;
     private ImageMemoryCache mImageCache;
@@ -139,7 +139,7 @@
 
         mAudioStreamController.addPlaybackStateListener(this);
 
-        openRadioBandInternal(mCurrentRadioBand);
+        openRadioBandInternal(mRadioStorage.getStoredRadioBand());
 
         mRadioSuccessfullyInitialized = true;
     }
@@ -176,7 +176,6 @@
     private int openRadioBandInternal(int radioBand) {
         if (!mAudioStreamController.requestMuted(false)) return RadioManager.STATUS_ERROR;
 
-        mCurrentRadioBand = radioBand;
         if (mRadioTuner == null) {
             mRadioTuner = mRadioManager.openSession(mInternalRadioTunerCallback, null);
             mProgramList = mRadioTuner.getDynamicProgramList(null);
@@ -191,9 +190,31 @@
         // opened.
         mReOpenRadioTunerCount = 0;
 
+        tuneToDefault(radioBand);
+
         return RadioManager.STATUS_OK;
     }
 
+    private void tuneToDefault(int band) {
+        if (!mAudioStreamController.preparePlayback(Optional.empty())) return;
+
+        long storedChannel = mRadioStorage.getStoredRadioChannel(band);
+        if (storedChannel != RadioStorage.INVALID_RADIO_CHANNEL) {
+            Log.i(TAG, "Restoring stored program: " + storedChannel);
+            mRadioTuner.tune(ProgramSelectorExt.createAmFmSelector(storedChannel));
+        } else {
+            Log.i(TAG, "No stored program, seeking forward to not play static");
+
+            // TODO(b/80500464): don't hardcode, pull from tuner config
+            long lastChannel;
+            if (band == RadioManager.BAND_AM) lastChannel = 1620;
+            else lastChannel = 108000;
+            mRadioTuner.tune(ProgramSelectorExt.createAmFmSelector(lastChannel));
+
+            mRadioTuner.scan(RadioTuner.DIRECTION_UP, true);
+        }
+    }
+
     /* TODO(b/73950974): remove onRadioMuteChanged from IRadioCallback,
      * use IPlaybackStateListener directly.
      */
@@ -256,7 +277,7 @@
             if (!mAudioStreamController.preparePlayback(Optional.of(true))) return;
 
             if (mRadioTuner == null) {
-                int radioStatus = openRadioBandInternal(mCurrentRadioBand);
+                int radioStatus = openRadioBandInternal(mRadioStorage.getStoredRadioBand());
                 if (radioStatus == RadioManager.STATUS_ERROR) {
                     return;
                 }
@@ -274,7 +295,7 @@
             if (!mAudioStreamController.preparePlayback(Optional.of(false))) return;
 
             if (mRadioTuner == null) {
-                int radioStatus = openRadioBandInternal(mCurrentRadioBand);
+                int radioStatus = openRadioBandInternal(mRadioStorage.getStoredRadioBand());
                 if (radioStatus == RadioManager.STATUS_ERROR) {
                     return;
                 }
@@ -321,25 +342,9 @@
             mRadioStorage.removePreset(sel);
         }
 
-        /**
-         * Opens the radio for the given band.
-         *
-         * @param radioBand One of {@link RadioManager#BAND_FM}, {@link RadioManager#BAND_AM},
-         *                  {@link RadioManager#BAND_FM_HD} or {@link RadioManager#BAND_AM_HD}.
-         * @return {@link RadioManager#STATUS_OK} if successful; otherwise,
-         * {@link RadioManager#STATUS_ERROR}.
-         */
         @Override
-        public int openRadioBand(int radioBand) {
-            if (Log.isLoggable(TAG, Log.DEBUG)) {
-                Log.d(TAG, "openRadioBand() for band: " + radioBand);
-            }
-
-            if (mRadioManager == null) {
-                return RadioManager.STATUS_ERROR;
-            }
-
-            return openRadioBandInternal(radioBand);
+        public void switchBand(int radioBand) {
+            tuneToDefault(radioBand);
         }
 
         /**
@@ -407,6 +412,7 @@
             mCurrentProgram = Objects.requireNonNull(info);
             mMediaSession.notifyProgramInfoChanged(info);
             mAudioStreamController.notifyProgramInfoChanged();
+            mRadioStorage.storeRadioChannel(info.getSelector());
 
             for (IRadioCallback callback : mRadioTunerCallbacks) {
                 try {
@@ -418,31 +424,6 @@
         }
 
         @Override
-        public void onConfigurationChanged(RadioManager.BandConfig config) {
-            if (Log.isLoggable(TAG, Log.DEBUG)) {
-                Log.d(TAG, "onConfigurationChanged(): config: " + config);
-            }
-
-            if (config != null) {
-                mCurrentRadioBand = config.getType();
-
-                if (Log.isLoggable(TAG, Log.DEBUG)) {
-                    Log.d(TAG, "onConfigurationChanged(): config type: " + mCurrentRadioBand);
-                }
-
-            }
-
-            try {
-                for (IRadioCallback callback : mRadioTunerCallbacks) {
-                    callback.onRadioBandChanged(mCurrentRadioBand);
-                }
-            } catch (RemoteException e) {
-                Log.e(TAG, "onConfigurationChanged(); "
-                        + "Failed to notify IRadioCallbacks: " + e.getMessage());
-            }
-        }
-
-        @Override
         public void onError(int status) {
             Log.e(TAG, "onError(); status: " + status);
 
@@ -480,12 +461,13 @@
             }
 
             if (mRadioTuner == null) {
-                openRadioBandInternal(mCurrentRadioBand);
+                openRadioBandInternal(mRadioStorage.getStoredRadioBand());
             }
         }
     }
 
-    private final Runnable mOpenRadioTunerRunnable = () -> openRadioBandInternal(mCurrentRadioBand);
+    private final Runnable mOpenRadioTunerRunnable =
+            () -> openRadioBandInternal(mRadioStorage.getStoredRadioBand());
 
     @Override
     public BrowserRoot onGetRoot(String clientPackageName, int clientUid, Bundle rootHints) {
diff --git a/src/com/android/car/radio/service/IRadioCallback.aidl b/src/com/android/car/radio/service/IRadioCallback.aidl
index 0e79747..d1ecf93 100644
--- a/src/com/android/car/radio/service/IRadioCallback.aidl
+++ b/src/com/android/car/radio/service/IRadioCallback.aidl
@@ -31,13 +31,6 @@
     void onCurrentProgramInfoChanged(in RadioManager.ProgramInfo info);
 
     /**
-     * Called when the current radio band has changed.
-     *
-     * @param radioBand A radio band value from {@link RadioManager}.
-     */
-    void onRadioBandChanged(int radioBand);
-
-    /**
      * Called when the mute state of the radio has changed.
      *
      * @param isMuted {@code true} if the radio is muted.
diff --git a/src/com/android/car/radio/service/IRadioManager.aidl b/src/com/android/car/radio/service/IRadioManager.aidl
index d976e52..ba005ba 100644
--- a/src/com/android/car/radio/service/IRadioManager.aidl
+++ b/src/com/android/car/radio/service/IRadioManager.aidl
@@ -74,14 +74,13 @@
     void removeFavorite(in ProgramSelector sel);
 
     /**
-     * Opens the radio for the given band.
+     * Switches radio band.
      *
-     * @param radioBand One of {@link RadioManager#BAND_FM}, {@link RadioManager#BAND_AM},
-     *                  {@link RadioManager#BAND_FM_HD} or {@link RadioManager#BAND_AM_HD}.
-     * @return {@link RadioManager#STATUS_OK} if successful; otherwise,
-     * {@link RadioManager#STATUS_ERROR}.
+     * Usually, this means tuning to the recently listened program on a given band.
+     *
+     * @param radioBand One of {@link RadioManager#BAND_FM}, {@link RadioManager#BAND_AM}.
      */
-    int openRadioBand(int radioBand);
+    void switchBand(int radioBand);
 
     /**
      * Adds the given {@link IRadioCallback} to be notified of any radio metadata changes.
diff --git a/src/com/android/car/radio/storage/RadioStorage.java b/src/com/android/car/radio/storage/RadioStorage.java
index 732ef7f..b77a64c 100644
--- a/src/com/android/car/radio/storage/RadioStorage.java
+++ b/src/com/android/car/radio/storage/RadioStorage.java
@@ -27,6 +27,7 @@
 import android.util.Log;
 
 import com.android.car.broadcastradio.support.Program;
+import com.android.car.radio.utils.ProgramSelectorUtils;
 
 import java.util.ArrayList;
 import java.util.HashMap;
@@ -164,31 +165,16 @@
     }
 
     /**
-     * Returns the stored radio band that was set in {@link #storeRadioBand(int)}. If a radio band
+     * Returns the stored radio band that was set in {@link #storeRadioChannel}. If a radio band
      * has not previously been stored, then {@link RadioManager#BAND_FM} is returned.
      *
-     * @return One of {@link RadioManager#BAND_FM}, {@link RadioManager#BAND_AM},
-     * {@link RadioManager#BAND_FM_HD} or {@link RadioManager#BAND_AM_HD}.
+     * @return One of {@link RadioManager#BAND_FM} or {@link RadioManager#BAND_AM}.
      */
     public int getStoredRadioBand() {
-        // No need to verify that the returned value is one of AM_BAND or FM_BAND because this is
-        // done in storeRadioBand(int).
         return sSharedPref.getInt(PREF_KEY_RADIO_BAND, RadioManager.BAND_FM);
     }
 
     /**
-     * Stores a radio band for later retrieval via {@link #getStoredRadioBand()}.
-     */
-    public void storeRadioBand(int radioBand) {
-        // Ensure that an incorrect radio band is not stored. Currently only FM and AM supported.
-        if (radioBand != RadioManager.BAND_FM && radioBand != RadioManager.BAND_AM) {
-            return;
-        }
-
-        sSharedPref.edit().putInt(PREF_KEY_RADIO_BAND, radioBand).apply();
-    }
-
-    /**
      * Returns the stored radio channel that was set in {@link #storeRadioChannel(int, int)}. If a
      * radio channel for the given band has not been previously stored, then
      * {@link #INVALID_RADIO_CHANNEL} is returned.
@@ -196,13 +182,13 @@
      * @param band One of the BAND_* values from {@link RadioManager}. For example,
      *             {@link RadioManager#BAND_AM}.
      */
-    public int getStoredRadioChannel(int band) {
+    public long getStoredRadioChannel(int band) {
         switch (band) {
             case RadioManager.BAND_AM:
-                return sSharedPref.getInt(PREF_KEY_RADIO_CHANNEL_AM, INVALID_RADIO_CHANNEL);
+                return sSharedPref.getLong(PREF_KEY_RADIO_CHANNEL_AM, INVALID_RADIO_CHANNEL);
 
             case RadioManager.BAND_FM:
-                return sSharedPref.getInt(PREF_KEY_RADIO_CHANNEL_FM, INVALID_RADIO_CHANNEL);
+                return sSharedPref.getLong(PREF_KEY_RADIO_CHANNEL_FM, INVALID_RADIO_CHANNEL);
 
             default:
                 return INVALID_RADIO_CHANNEL;
@@ -213,28 +199,28 @@
      * Stores a radio channel (i.e. the radio frequency) for a particular band so it can be later
      * retrieved via {@link #getStoredRadioChannel(int band)}.
      */
-    public void storeRadioChannel(int band, int channel) {
+    public void storeRadioChannel(@NonNull ProgramSelector sel) {
         if (Log.isLoggable(TAG, Log.DEBUG)) {
-            Log.d(TAG, String.format("storeRadioChannel(); band: %s, channel %s", band, channel));
-        }
-
-        if (channel <= 0) {
-            return;
+            Log.d(TAG, "storeRadioChannel(" + sel + ")");
         }
 
         // TODO(b/73950974): don't store if it's already the same
-        switch (band) {
-            case RadioManager.BAND_AM:
-                sSharedPref.edit().putInt(PREF_KEY_RADIO_CHANNEL_AM, channel).apply();
-                break;
 
-            case RadioManager.BAND_FM:
-                sSharedPref.edit().putInt(PREF_KEY_RADIO_CHANNEL_FM, channel).apply();
-                break;
+        int band = ProgramSelectorUtils.getRadioBand(sel);
+        if (band != RadioManager.BAND_AM && band != RadioManager.BAND_FM) return;
 
-            default:
-                Log.w(TAG, "Attempting to store channel for invalid band: " + band);
+        SharedPreferences.Editor editor = sSharedPref.edit();
+        editor.putInt(PREF_KEY_RADIO_BAND, band);
+
+        long freq = sel.getFirstId(ProgramSelector.IDENTIFIER_TYPE_AMFM_FREQUENCY);
+        if (band == RadioManager.BAND_AM) {
+            editor.putLong(PREF_KEY_RADIO_CHANNEL_AM, freq);
         }
+        if (band == RadioManager.BAND_FM) {
+            editor.putLong(PREF_KEY_RADIO_CHANNEL_FM, freq);
+        }
+
+        editor.apply();
     }
 
     /**
diff --git a/src/com/android/car/radio/utils/ProgramSelectorUtils.java b/src/com/android/car/radio/utils/ProgramSelectorUtils.java
new file mode 100644
index 0000000..c1d10f4
--- /dev/null
+++ b/src/com/android/car/radio/utils/ProgramSelectorUtils.java
@@ -0,0 +1,52 @@
+/**
+ * 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.annotation.NonNull;
+import android.hardware.radio.ProgramSelector;
+import android.hardware.radio.RadioManager;
+
+import com.android.car.broadcastradio.support.platform.ProgramSelectorExt;
+import com.android.car.radio.storage.RadioStorage;
+
+/**
+ * Helper methods for android.hardware.radio.ProgramSelector.
+ *
+ * Most probably, this code will end up refactored out, less likely pushed to the platform.
+ */
+public class ProgramSelectorUtils {
+    /**
+     * Returns AM/FM band for a given ProgramSelector.
+     *
+     * @param sel ProgramSelector to check.
+     * @return {@link RadioManager#BAND_FM} if sel is FM program,
+     *         {@link RadioManager#BAND_AM} if sel is AM program,
+     *         {@link RadioStorage#INVALID_RADIO_BAND} otherwise.
+     */
+    public static int getRadioBand(@NonNull ProgramSelector sel) {
+        if (!ProgramSelectorExt.isAmFmProgram(sel)) return RadioStorage.INVALID_RADIO_BAND;
+        if (!ProgramSelectorExt.hasId(sel, ProgramSelector.IDENTIFIER_TYPE_AMFM_FREQUENCY)) {
+            return RadioStorage.INVALID_RADIO_BAND;
+        }
+
+        long freq = sel.getFirstId(ProgramSelector.IDENTIFIER_TYPE_AMFM_FREQUENCY);
+        if (ProgramSelectorExt.isAmFrequency(freq)) return RadioManager.BAND_AM;
+        if (ProgramSelectorExt.isFmFrequency(freq)) return RadioManager.BAND_FM;
+
+        return RadioStorage.INVALID_RADIO_BAND;
+    }
+}