Implement proper stream selection in UI and stopStreaming

Modify sample UI to be able to select an active stream
Implement functionality for stopStreaming

Test: testapps
Change-Id: I4b88b36ba4f8313848b1a956aea611ce040574d7
diff --git a/testapps/EmbmsServiceTestApp/src/com/android/phone/testapps/embmsmw/AppActiveStreams.java b/testapps/EmbmsServiceTestApp/src/com/android/phone/testapps/embmsmw/AppActiveStreams.java
index f37a340..35d18e9 100644
--- a/testapps/EmbmsServiceTestApp/src/com/android/phone/testapps/embmsmw/AppActiveStreams.java
+++ b/testapps/EmbmsServiceTestApp/src/com/android/phone/testapps/embmsmw/AppActiveStreams.java
@@ -77,8 +77,10 @@
 
         if (entry != null) {
             try {
-                entry.setState(StreamingService.STATE_STOPPED);
-                entry.getCallback().streamStateChanged(StreamingService.STATE_STOPPED);
+                if (entry.getState() != StreamingService.STATE_STOPPED) {
+                    entry.setState(StreamingService.STATE_STOPPED);
+                    entry.getCallback().streamStateChanged(StreamingService.STATE_STOPPED);
+                }
             } catch (RemoteException e) {
                 dispose(serviceId);
             }
diff --git a/testapps/EmbmsServiceTestApp/src/com/android/phone/testapps/embmsmw/EmbmsTestStreamingService.java b/testapps/EmbmsServiceTestApp/src/com/android/phone/testapps/embmsmw/EmbmsTestStreamingService.java
index 0693292..9758d49 100644
--- a/testapps/EmbmsServiceTestApp/src/com/android/phone/testapps/embmsmw/EmbmsTestStreamingService.java
+++ b/testapps/EmbmsServiceTestApp/src/com/android/phone/testapps/embmsmw/EmbmsTestStreamingService.java
@@ -156,6 +156,16 @@
         }
 
         @Override
+        public void stopStreaming(String appName, int subscriptionId, String serviceId) {
+            StreamingAppIdentifier appKey =
+                    new StreamingAppIdentifier(Binder.getCallingUid(), appName, subscriptionId);
+            checkInitialized(appKey);
+            checkServiceExists(serviceId);
+
+            mHandler.post(() -> StreamStateTracker.stopStreaming(appKey, serviceId));
+        }
+
+        @Override
         public void disposeStream(String appName, int subscriptionId, String serviceId) {
             StreamingAppIdentifier appKey =
                     new StreamingAppIdentifier(Binder.getCallingUid(), appName, subscriptionId);
diff --git a/testapps/EmbmsServiceTestApp/src/com/android/phone/testapps/embmsmw/StreamStateTracker.java b/testapps/EmbmsServiceTestApp/src/com/android/phone/testapps/embmsmw/StreamStateTracker.java
index c5496e8..e340b11 100644
--- a/testapps/EmbmsServiceTestApp/src/com/android/phone/testapps/embmsmw/StreamStateTracker.java
+++ b/testapps/EmbmsServiceTestApp/src/com/android/phone/testapps/embmsmw/StreamStateTracker.java
@@ -18,12 +18,15 @@
 
 import android.telephony.mbms.IStreamingServiceCallback;
 import android.telephony.mbms.StreamingService;
+import android.util.Log;
 
 import java.util.HashMap;
 import java.util.Map;
 
 // Singleton that keeps track of streaming states for all apps using the middleware.
 public class StreamStateTracker {
+    private static final String LOG_TAG = "MbmsStreamStateTracker";
+
     private static final Map<StreamingAppIdentifier, AppActiveStreams>
             sPerAppStreamStates = new HashMap<>();
 
@@ -47,6 +50,7 @@
     }
 
     public static void stopStreaming(StreamingAppIdentifier appIdentifier, String serviceId) {
+        Log.i(LOG_TAG, "Stopping stream " + serviceId);
         AppActiveStreams appStreams = sPerAppStreamStates.get(appIdentifier);
         if (appStreams == null) {
             // It was never started, so don't bother stopping.
diff --git a/testapps/EmbmsTestStreamingApp/res/layout/activity_main.xml b/testapps/EmbmsTestStreamingApp/res/layout/activity_main.xml
index 47e9807..c1cc539 100644
--- a/testapps/EmbmsTestStreamingApp/res/layout/activity_main.xml
+++ b/testapps/EmbmsTestStreamingApp/res/layout/activity_main.xml
@@ -29,40 +29,81 @@
         android:id="@+id/curr_streaming_uri"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"/>
+    <TextView
+        android:id="@+id/tracked_streams_label"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:text="@string/tracked_streams_label"/>
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:orientation="horizontal">
+        <Spinner
+            android:id="@+id/curr_streams"
+            android:layout_width="0dp"
+            android:layout_weight="1"
+            android:layout_height="match_parent"/>
+        <TextView
+            android:id="@+id/stream_state"
+            android:layout_width="wrap_content"
+            android:layout_height="match_parent"/>
+    </LinearLayout>
+    <TextView
+        android:id="@+id/available_services_label"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:text="@string/available_streaming_services_label"/>
     <Spinner
         android:id="@+id/available_streaming_services"
         android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:label="@string/available_streaming_services_label"/>
+        android:layout_height="wrap_content"/>
     <GridLayout
         xmlns:android="http://schemas.android.com/apk/res/android"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
+        android:columnCount="2"
         android:orientation="vertical" >
         <Button
             android:id="@+id/bind_button"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
+            android:layout_row="0"
+            android:layout_column="0"
             android:text="@string/bind_button" />
         <Button
             android:id="@+id/get_streaming_services_button"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
+            android:layout_row="0"
+            android:layout_column="1"
             android:text="@string/get_streaming_services_button" />
         <Button
             android:id="@+id/start_streaming_button"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
+            android:layout_row="1"
+            android:layout_column="0"
             android:text="@string/start_streaming_button" />
         <Button
+            android:id="@+id/stop_streaming_button"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_row="1"
+            android:layout_column="1"
+            android:text="@string/stop_streaming_button" />
+        <Button
             android:id="@+id/dispose_stream_button"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
+            android:layout_row="2"
+            android:layout_column="0"
             android:text="@string/dispose_stream_button" />
         <Button
             android:id="@+id/dispose_manager_button"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
+            android:layout_row="2"
+            android:layout_column="1"
             android:text="@string/dispose_manager_button" />
     </GridLayout>
 </LinearLayout>
diff --git a/testapps/EmbmsTestStreamingApp/res/values/donottranslate_strings.xml b/testapps/EmbmsTestStreamingApp/res/values/donottranslate_strings.xml
index 58518cd..606fa25 100644
--- a/testapps/EmbmsTestStreamingApp/res/values/donottranslate_strings.xml
+++ b/testapps/EmbmsTestStreamingApp/res/values/donottranslate_strings.xml
@@ -17,10 +17,12 @@
 
 <resources>
     <string name="bind_button">Bind to service</string>
-    <string name="streaming_uri_label">Current Streaming URI</string>
+    <string name="streaming_uri_label">Current Streaming URIs</string>
     <string name="get_streaming_services_button">Get streaming services</string>
     <string name="start_streaming_button">Start Streaming</string>
+    <string name="stop_streaming_button">Stop Streaming</string>
     <string name="available_streaming_services_label">Available Streaming Services</string>
     <string name="dispose_stream_button">Dispose latest stream</string>
     <string name="dispose_manager_button">Dispose streaming manager</string>
+    <string name="tracked_streams_label">Tracked Streams</string>
 </resources>
\ No newline at end of file
diff --git a/testapps/EmbmsTestStreamingApp/src/com/android/phone/testapps/embmsfrontend/EmbmsTestStreamingApp.java b/testapps/EmbmsTestStreamingApp/src/com/android/phone/testapps/embmsfrontend/EmbmsTestStreamingApp.java
index df6396e..c310064 100644
--- a/testapps/EmbmsTestStreamingApp/src/com/android/phone/testapps/embmsfrontend/EmbmsTestStreamingApp.java
+++ b/testapps/EmbmsTestStreamingApp/src/com/android/phone/testapps/embmsfrontend/EmbmsTestStreamingApp.java
@@ -25,6 +25,7 @@
 import android.telephony.MbmsStreamingManager;
 import android.telephony.mbms.MbmsException;
 import android.telephony.mbms.MbmsStreamingManagerCallback;
+import android.telephony.mbms.StreamingService;
 import android.telephony.mbms.StreamingServiceInfo;
 import android.view.View;
 import android.view.ViewGroup;
@@ -39,6 +40,7 @@
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.Objects;
 
 public class EmbmsTestStreamingApp extends Activity {
     private static final String APP_NAME = "StreamingApp1";
@@ -87,12 +89,38 @@
         }
     }
 
+    private final class TrackedStreamAdapter extends ArrayAdapter<String> {
+        public TrackedStreamAdapter(Context context) {
+            super(context, android.R.layout.simple_spinner_item);
+            setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
+        }
+
+        @Override
+        public View getView(int position, View convertView, ViewGroup parent) {
+            String serviceId = getItem(position);
+            StreamingServiceTracker tracker = mStreamingServiceTrackerById.get(serviceId);
+            TextView result = new TextView(EmbmsTestStreamingApp.this);
+            result.setText(tracker == null ? "" : tracker.toString());
+            return result;
+        }
+
+        @Override
+        public View getDropDownView(int position, View convertView, ViewGroup parent) {
+            String serviceId = getItem(position);
+            StreamingServiceTracker tracker = mStreamingServiceTrackerById.get(serviceId);
+            TextView result = new TextView(EmbmsTestStreamingApp.this);
+            result.setText(tracker.toString());
+            return result;
+        }
+    }
+
     private MbmsStreamingManager mStreamingManager = null;
 
     private Handler mHandler;
     private HandlerThread mHandlerThread;
-    private StreamingServiceTracker mLatestStream = null;
 
+    private TrackedStreamAdapter mTrackedStreamingServiceAdapter;
+    private Spinner mStreamSelector;
     private StreamingServiceInfoAdapter mStreamingServicesDisplayAdapter;
     private final Map<String, StreamingServiceTracker> mStreamingServiceTrackerById =
             new HashMap<>();
@@ -107,6 +135,7 @@
         mHandler = new Handler(mHandlerThread.getLooper());
         mStreamingServicesDisplayAdapter =
                 new StreamingServiceInfoAdapter(this, android.R.layout.simple_spinner_item);
+        mTrackedStreamingServiceAdapter = new TrackedStreamAdapter(this);
 
         Button bindButton = (Button) findViewById(R.id.bind_button);
         bindButton.setOnClickListener((view) ->
@@ -147,17 +176,24 @@
         mStreamingServicesDisplayAdapter.setDropDownViewResource(
                 android.R.layout.simple_spinner_dropdown_item);
         serviceSelector.setAdapter(mStreamingServicesDisplayAdapter);
-        serviceSelector.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
+
+        mStreamSelector = (Spinner) findViewById(R.id.curr_streams);
+        mTrackedStreamingServiceAdapter.setDropDownViewResource(
+                android.R.layout.simple_spinner_dropdown_item);
+        mStreamSelector.setAdapter(mTrackedStreamingServiceAdapter);
+        mStreamSelector.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
             @Override
             public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
-                StreamingServiceInfo info =
-                        (StreamingServiceInfo) serviceSelector.getItemAtPosition(position);
-                String toastText = "Service selected: " + info.getNames().get(info.getLocale());
-                Toast.makeText(EmbmsTestStreamingApp.this, toastText, Toast.LENGTH_SHORT).show();
+                String serviceId = (String) mStreamSelector.getItemAtPosition(position);
+                StreamingServiceTracker tracker = mStreamingServiceTrackerById.get(serviceId);
+
+                setStreamStateDisplay(String.valueOf(tracker.getState()));
+                setUriDisplay(tracker.getUri());
             }
 
             @Override
             public void onNothingSelected(AdapterView<?> parent) {
+                clearStateAndUriDisplay();
             }
         });
 
@@ -177,30 +213,43 @@
             }
 
             StreamingServiceTracker tracker = new StreamingServiceTracker(this, serviceInfo);
-            tracker.startStreaming(mStreamingManager);
-            mStreamingServiceTrackerById.put(serviceInfo.getServiceId(), tracker);
-            mLatestStream = tracker;
+            if (tracker.startStreaming(mStreamingManager)) {
+                mStreamingServiceTrackerById.put(serviceInfo.getServiceId(), tracker);
+                mTrackedStreamingServiceAdapter.add(serviceInfo.getServiceId());
+            }
+        });
+
+        Button stopStreamingButton = (Button) findViewById(R.id.stop_streaming_button);
+        stopStreamingButton.setOnClickListener((view) -> {
+            if (getSelectedTrackedStream() == null) {
+                Toast.makeText(EmbmsTestStreamingApp.this,
+                        "No streams selected", Toast.LENGTH_SHORT).show();
+                return;
+            }
+            StreamingServiceTracker stream = getSelectedTrackedStream();
+            stream.stopStreaming();
         });
 
         Button disposeStreamButton = (Button) findViewById(R.id.dispose_stream_button);
         disposeStreamButton.setOnClickListener((view) -> {
-            if (mLatestStream == null) {
+            if (getSelectedTrackedStream() == null) {
                 Toast.makeText(EmbmsTestStreamingApp.this,
-                        "No streams active", Toast.LENGTH_SHORT).show();
+                        "No streams selected", Toast.LENGTH_SHORT).show();
                 return;
             }
-            mLatestStream.dispose();
-            mStreamingServiceTrackerById.remove(mLatestStream.getServiceId());
-            TextView uriField = (TextView) findViewById(R.id.curr_streaming_uri);
-            uriField.setText("");
-            mLatestStream = null;
+            clearStateAndUriDisplay();
+            StreamingServiceTracker stream = getSelectedTrackedStream();
+            mTrackedStreamingServiceAdapter.remove(stream.getServiceId());
+            mStreamingServiceTrackerById.remove(stream.getServiceId());
+            stream.dispose();
         });
 
         Button disposeManagerButton = (Button) findViewById(R.id.dispose_manager_button);
         disposeManagerButton.setOnClickListener((view) -> {
-            TextView uriField = (TextView) findViewById(R.id.curr_streaming_uri);
-            uriField.setText("");
+            clearStateAndUriDisplay();
+            mTrackedStreamingServiceAdapter.clear();
             mStreamingServicesDisplayAdapter.update(Collections.emptyList());
+            mStreamingServiceTrackerById.clear();
             mStreamingManager.dispose();
         });
     }
@@ -215,10 +264,39 @@
         runOnUiThread(() -> mStreamingServicesDisplayAdapter.update(services));
     }
 
-    public void updateUriInUi(Uri uri) {
+    private StreamingServiceTracker getSelectedTrackedStream() {
+        String serviceId = (String) mStreamSelector.getSelectedItem();
+        return mStreamingServiceTrackerById.get(serviceId);
+    }
+
+    private void setUriDisplay(Uri uri) {
         runOnUiThread(() -> {
             TextView uriField = (TextView) findViewById(R.id.curr_streaming_uri);
             uriField.setText(uri.toSafeString());
         });
     }
+
+    private void setStreamStateDisplay(String stateString) {
+        runOnUiThread(() -> {
+            TextView uriField = (TextView) findViewById(R.id.stream_state);
+            uriField.setText(stateString);
+        });
+    }
+
+    private void clearStateAndUriDisplay() {
+        setUriDisplay(Uri.EMPTY);
+        setStreamStateDisplay("");
+    }
+
+    public void updateUri() {
+        Uri uri = getSelectedTrackedStream() == null ?
+            Uri.EMPTY : getSelectedTrackedStream().getUri();
+        setUriDisplay(uri);
+    }
+
+    public void updateStreamingState() {
+        String stateString = getSelectedTrackedStream() == null ?
+            "" : String.valueOf(getSelectedTrackedStream().getState());
+        setStreamStateDisplay(stateString);
+    }
 }
diff --git a/testapps/EmbmsTestStreamingApp/src/com/android/phone/testapps/embmsfrontend/StreamingServiceTracker.java b/testapps/EmbmsTestStreamingApp/src/com/android/phone/testapps/embmsfrontend/StreamingServiceTracker.java
index 512c119..c0b12cb 100644
--- a/testapps/EmbmsTestStreamingApp/src/com/android/phone/testapps/embmsfrontend/StreamingServiceTracker.java
+++ b/testapps/EmbmsTestStreamingApp/src/com/android/phone/testapps/embmsfrontend/StreamingServiceTracker.java
@@ -42,20 +42,34 @@
     private final EmbmsTestStreamingApp mActivity;
     private final StreamingServiceInfo mStreamingServiceInfo;
     private StreamingService mStreamingService;
-    private int mState;
+
+    private int mState = StreamingService.STATE_STOPPED;
+    private Uri mStreamingUri = Uri.EMPTY;
 
     public StreamingServiceTracker(EmbmsTestStreamingApp appActivity, StreamingServiceInfo info) {
         mActivity = appActivity;
         mStreamingServiceInfo = info;
     }
 
-    public void startStreaming(MbmsStreamingManager streamingManager) {
+    public boolean startStreaming(MbmsStreamingManager streamingManager) {
         try {
             mStreamingService =
                     streamingManager.startStreaming(mStreamingServiceInfo, new Callback());
+            return true;
         } catch (MbmsException e) {
             Toast.makeText(mActivity,
-                    "Error starting streaming" + e.getErrorCode(),
+                    "Error starting streaming: " + e.getErrorCode(),
+                    Toast.LENGTH_SHORT).show();
+        }
+        return false;
+    }
+
+    public void stopStreaming() {
+        try {
+            mStreamingService.stopStreaming();
+        } catch (MbmsException e) {
+            Toast.makeText(mActivity,
+                    "Error stopping streaming: " + e.getErrorCode(),
                     Toast.LENGTH_SHORT).show();
         }
     }
@@ -74,17 +88,19 @@
         return mStreamingServiceInfo.getServiceId();
     }
 
+    public int getState() {
+        return mState;
+    }
+
+    public Uri getUri() {
+        return mStreamingUri;
+    }
+
     private void onStreamStateChanged(int state) {
-        String toastMessage = "Stream "
-                + mStreamingServiceInfo.getNames().get(mStreamingServiceInfo.getLocale())
-                + " has entered state "
-                + state;
-        mActivity.runOnUiThread(() ->
-                Toast.makeText(mActivity, toastMessage, Toast.LENGTH_SHORT).show());
         if (state == StreamingService.STATE_STARTED && mState != StreamingService.STATE_STARTED) {
             try {
-                Uri streamingUri = mStreamingService.getPlaybackUri();
-                mActivity.updateUriInUi(streamingUri);
+                mStreamingUri = mStreamingService.getPlaybackUri();
+                mActivity.updateUri();
             } catch (MbmsException e) {
                 String errorToast = "Got error " + e.getErrorCode() + " while getting uri";
                 mActivity.runOnUiThread(() ->
@@ -92,5 +108,11 @@
             }
         }
         mState = state;
+        mActivity.updateStreamingState();
+    }
+
+    @Override
+    public String toString() {
+        return "Tracked service with ID " + getServiceId();
     }
 }