1/*
2 * Copyright (C) 2017 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License
15 */
16
17package com.android.phone.testapps.embmsfrontend;
18
19import android.app.Activity;
20import android.content.Context;
21import android.net.Uri;
22import android.os.Bundle;
23import android.os.Handler;
24import android.os.HandlerThread;
25import android.telephony.MbmsStreamingSession;
26import android.telephony.mbms.MbmsStreamingSessionCallback;
27import android.telephony.mbms.StreamingService;
28import android.telephony.mbms.StreamingServiceInfo;
29import android.view.View;
30import android.view.ViewGroup;
31import android.widget.AdapterView;
32import android.widget.ArrayAdapter;
33import android.widget.Button;
34import android.widget.Spinner;
35import android.widget.TextView;
36import android.widget.Toast;
37
38import java.util.Collections;
39import java.util.HashMap;
40import java.util.List;
41import java.util.Locale;
42import java.util.Map;
43import java.util.NoSuchElementException;
44
45public class EmbmsTestStreamingApp extends Activity {
46    private MbmsStreamingSessionCallback mStreamingListener = new MbmsStreamingSessionCallback() {
47        @Override
48        public void onStreamingServicesUpdated(List<StreamingServiceInfo> services) {
49            EmbmsTestStreamingApp.this.runOnUiThread(() ->
50                    Toast.makeText(EmbmsTestStreamingApp.this,
51                            "Got services length " + services.size(),
52                            Toast.LENGTH_SHORT).show());
53            updateStreamingServicesList(services);
54        }
55
56        @Override
57        public void onMiddlewareReady() {
58            runOnUiThread(() -> Toast.makeText(EmbmsTestStreamingApp.this, "Successfully bound",
59                    Toast.LENGTH_SHORT).show());
60        }
61    };
62
63    private final class StreamingServiceInfoAdapter
64            extends ArrayAdapter<StreamingServiceInfo> {
65        public StreamingServiceInfoAdapter(Context context, int resource) {
66            super(context, resource);
67        }
68
69        private String getName(StreamingServiceInfo info) {
70            Locale locale = Locale.getDefault();
71            try {
72                return info.getNameForLocale(locale).toString();
73            } catch (NoSuchElementException e) {
74                locale = info.getLocales().iterator().next();
75                return info.getNameForLocale(locale).toString();
76            }
77        }
78
79        @Override
80        public View getView(int position, View convertView, ViewGroup parent) {
81            StreamingServiceInfo info = getItem(position);
82            TextView result = new TextView(EmbmsTestStreamingApp.this);
83            result.setText(getName(info));
84            return result;
85        }
86
87        @Override
88        public View getDropDownView(int position, View convertView, ViewGroup parent) {
89            StreamingServiceInfo info = getItem(position);
90            TextView result = new TextView(EmbmsTestStreamingApp.this);
91            String text = "name="
92                    + getName(info)
93                    + ", "
94                    + "serviceId="
95                    + info.getServiceId();
96            result.setText(text);
97            return result;
98        }
99
100        public void update(List<StreamingServiceInfo> services) {
101            clear();
102            addAll(services);
103        }
104    }
105
106    private final class TrackedStreamAdapter extends ArrayAdapter<String> {
107        public TrackedStreamAdapter(Context context) {
108            super(context, android.R.layout.simple_spinner_item);
109            setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
110        }
111
112        @Override
113        public View getView(int position, View convertView, ViewGroup parent) {
114            String serviceId = getItem(position);
115            StreamingServiceTracker tracker = mStreamingServiceTrackerById.get(serviceId);
116            TextView result = new TextView(EmbmsTestStreamingApp.this);
117            result.setText(tracker == null ? "" : tracker.toString());
118            return result;
119        }
120
121        @Override
122        public View getDropDownView(int position, View convertView, ViewGroup parent) {
123            String serviceId = getItem(position);
124            StreamingServiceTracker tracker = mStreamingServiceTrackerById.get(serviceId);
125            TextView result = new TextView(EmbmsTestStreamingApp.this);
126            result.setText(tracker.toString());
127            return result;
128        }
129    }
130
131    private MbmsStreamingSession mStreamingManager = null;
132
133    private Handler mHandler;
134    private HandlerThread mHandlerThread;
135
136    private TrackedStreamAdapter mTrackedStreamingServiceAdapter;
137    private Spinner mStreamSelector;
138    private StreamingServiceInfoAdapter mStreamingServicesDisplayAdapter;
139    private final Map<String, StreamingServiceTracker> mStreamingServiceTrackerById =
140            new HashMap<>();
141
142    @Override
143    protected void onCreate(Bundle savedInstanceState) {
144        super.onCreate(savedInstanceState);
145        setContentView(R.layout.activity_main);
146
147        mHandlerThread = new HandlerThread("EmbmsSampleFrontendWorker");
148        mHandlerThread.start();
149        mHandler = new Handler(mHandlerThread.getLooper());
150        mStreamingServicesDisplayAdapter =
151                new StreamingServiceInfoAdapter(this, android.R.layout.simple_spinner_item);
152        mTrackedStreamingServiceAdapter = new TrackedStreamAdapter(this);
153
154        Button bindButton = (Button) findViewById(R.id.bind_button);
155        bindButton.setOnClickListener((view) -> {
156            mStreamingManager = MbmsStreamingSession.create(
157                    EmbmsTestStreamingApp.this, mStreamingListener, mHandler);
158        });
159
160        Button getStreamingServicesButton = (Button)
161                findViewById(R.id.get_streaming_services_button);
162        getStreamingServicesButton.setOnClickListener((view) -> {
163            if (mStreamingManager == null) {
164                Toast.makeText(EmbmsTestStreamingApp.this,
165                        "No streaming service bound", Toast.LENGTH_SHORT).show();
166                return;
167            }
168            mStreamingManager.requestUpdateStreamingServices(Collections.singletonList("Class1"));
169        });
170
171        final Spinner serviceSelector = (Spinner) findViewById(R.id.available_streaming_services);
172        mStreamingServicesDisplayAdapter.setDropDownViewResource(
173                android.R.layout.simple_spinner_dropdown_item);
174        serviceSelector.setAdapter(mStreamingServicesDisplayAdapter);
175
176        mStreamSelector = (Spinner) findViewById(R.id.curr_streams);
177        mTrackedStreamingServiceAdapter.setDropDownViewResource(
178                android.R.layout.simple_spinner_dropdown_item);
179        mStreamSelector.setAdapter(mTrackedStreamingServiceAdapter);
180        mStreamSelector.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
181            @Override
182            public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
183                String serviceId = (String) mStreamSelector.getItemAtPosition(position);
184                StreamingServiceTracker tracker = mStreamingServiceTrackerById.get(serviceId);
185
186                setStreamStateDisplay(String.valueOf(tracker.getState()));
187                setUriDisplay(tracker.getUri());
188            }
189
190            @Override
191            public void onNothingSelected(AdapterView<?> parent) {
192                clearStateAndUriDisplay();
193            }
194        });
195
196        Button startStreamingButton = (Button) findViewById(R.id.start_streaming_button);
197        startStreamingButton.setOnClickListener((view) -> {
198            if (mStreamingManager == null) {
199                Toast.makeText(EmbmsTestStreamingApp.this,
200                        "No streaming service bound", Toast.LENGTH_SHORT).show();
201                return;
202            }
203            StreamingServiceInfo serviceInfo =
204                    (StreamingServiceInfo) serviceSelector.getSelectedItem();
205            if (serviceInfo == null) {
206                Toast.makeText(EmbmsTestStreamingApp.this,
207                        "No streaming service selected", Toast.LENGTH_SHORT).show();
208                return;
209            }
210
211            StreamingServiceTracker tracker = new StreamingServiceTracker(this, serviceInfo);
212            if (tracker.startStreaming(mStreamingManager)) {
213                mStreamingServiceTrackerById.put(serviceInfo.getServiceId(), tracker);
214                mTrackedStreamingServiceAdapter.add(serviceInfo.getServiceId());
215            }
216        });
217
218        Button stopStreamingButton = (Button) findViewById(R.id.stop_streaming_button);
219        stopStreamingButton.setOnClickListener((view) -> {
220            if (getSelectedTrackedStream() == null) {
221                Toast.makeText(EmbmsTestStreamingApp.this,
222                        "No streams selected", Toast.LENGTH_SHORT).show();
223                return;
224            }
225            StreamingServiceTracker stream = getSelectedTrackedStream();
226            stream.stopStreaming();
227        });
228
229        Button disposeManagerButton = (Button) findViewById(R.id.dispose_manager_button);
230        disposeManagerButton.setOnClickListener((view) -> {
231            clearStateAndUriDisplay();
232            mTrackedStreamingServiceAdapter.clear();
233            mStreamingServicesDisplayAdapter.update(Collections.emptyList());
234            mStreamingServiceTrackerById.clear();
235            mStreamingManager.close();
236        });
237    }
238
239    @Override
240    protected void onDestroy() {
241        super.onDestroy();
242        mHandlerThread.quit();
243    }
244
245    private void updateStreamingServicesList(List<StreamingServiceInfo> services) {
246        runOnUiThread(() -> mStreamingServicesDisplayAdapter.update(services));
247    }
248
249    private StreamingServiceTracker getSelectedTrackedStream() {
250        String serviceId = (String) mStreamSelector.getSelectedItem();
251        return mStreamingServiceTrackerById.get(serviceId);
252    }
253
254    private void setUriDisplay(Uri uri) {
255        runOnUiThread(() -> {
256            TextView uriField = (TextView) findViewById(R.id.curr_streaming_uri);
257            uriField.setText(uri.toSafeString());
258        });
259    }
260
261    private void setStreamStateDisplay(String stateString) {
262        runOnUiThread(() -> {
263            TextView uriField = (TextView) findViewById(R.id.stream_state);
264            uriField.setText(stateString);
265        });
266    }
267
268    private void setStreamMethodDisplay(int method) {
269        runOnUiThread(() -> {
270            String methodString = "UNKNOWN METHOD";
271            switch (method) {
272                case StreamingService.BROADCAST_METHOD: {
273                    methodString = "BROADCAST";
274                    break;
275                }
276                case StreamingService.UNICAST_METHOD: {
277                    methodString = "UNICAST";
278                    break;
279                }
280            }
281            TextView methodField = (TextView) findViewById(R.id.curr_streaming_method);
282            methodField.setText(methodString);
283        });
284    }
285
286    private void clearStateAndUriDisplay() {
287        setUriDisplay(Uri.EMPTY);
288        setStreamStateDisplay("");
289        setStreamMethodDisplay(StreamingService.UNICAST_METHOD);
290    }
291
292    public void updateUri() {
293        Uri uri = getSelectedTrackedStream() == null ?
294            Uri.EMPTY : getSelectedTrackedStream().getUri();
295        setUriDisplay(uri);
296    }
297
298    public void updateStreamingState() {
299        String stateString = getSelectedTrackedStream() == null ?
300            "" : String.valueOf(getSelectedTrackedStream().getState());
301        setStreamStateDisplay(stateString);
302    }
303
304    /** implementation of updateMethod callback */
305    public void updateMethod() {
306        StreamingServiceTracker serviceTracker = getSelectedTrackedStream();
307        if (serviceTracker == null) {
308            setStreamMethodDisplay(StreamingService.UNICAST_METHOD);
309        } else {
310            setStreamMethodDisplay(serviceTracker.getMethod());
311        }
312    }
313}
314