1 /*
2  * Copyright 2022 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 
17 package com.example.androidx.mediarouting.activities;
18 
19 import static com.example.androidx.mediarouting.ui.UiUtils.setUpEnumBasedSpinner;
20 
21 import android.content.ComponentName;
22 import android.content.Context;
23 import android.content.Intent;
24 import android.content.ServiceConnection;
25 import android.os.Bundle;
26 import android.os.IBinder;
27 import android.text.Editable;
28 import android.text.TextWatcher;
29 import android.widget.Button;
30 import android.widget.EditText;
31 import android.widget.Switch;
32 
33 import androidx.appcompat.app.AppCompatActivity;
34 import androidx.core.util.Consumer;
35 
36 import com.example.androidx.mediarouting.R;
37 import com.example.androidx.mediarouting.RoutesManager;
38 import com.example.androidx.mediarouting.data.RouteItem;
39 import com.example.androidx.mediarouting.services.SampleDynamicGroupMediaRouteProviderService;
40 
41 import org.jspecify.annotations.NonNull;
42 import org.jspecify.annotations.Nullable;
43 
44 /** Allows the user to add and edit routes. */
45 public class AddEditRouteActivity extends AppCompatActivity {
46     private static final String EXTRA_ROUTE_ID_KEY = "routeId";
47 
48     private @Nullable SampleDynamicGroupMediaRouteProviderService mService;
49     private ServiceConnection mConnection;
50     private RoutesManager mRoutesManager;
51     private RouteItem mRouteItem;
52 
53     /** Launches the activity. */
launchActivity(@onNull Context context, @Nullable String routeId)54     public static void launchActivity(@NonNull Context context, @Nullable String routeId) {
55         Intent intent = new Intent(context, AddEditRouteActivity.class);
56         intent.putExtra(EXTRA_ROUTE_ID_KEY, routeId);
57         context.startActivity(intent);
58     }
59 
60     @Override
onCreate(@ullable Bundle savedInstanceState)61     protected void onCreate(@Nullable Bundle savedInstanceState) {
62         super.onCreate(savedInstanceState);
63         setContentView(R.layout.activity_add_edit_route);
64 
65         mRoutesManager = RoutesManager.getInstance(getApplicationContext());
66 
67         String routeId = getIntent().getStringExtra(EXTRA_ROUTE_ID_KEY);
68         mRouteItem = mRoutesManager.getRouteWithId(routeId);
69         mConnection = new ProviderServiceConnection();
70 
71         if (mRouteItem == null) {
72             mRouteItem = new RouteItem();
73         } else {
74             mRouteItem = RouteItem.copyOf(mRouteItem);
75         }
76 
77         setUpViews();
78     }
79 
80     @Override
onStart()81     protected void onStart() {
82         super.onStart();
83         Intent intent = new Intent(this, SampleDynamicGroupMediaRouteProviderService.class);
84         intent.setAction(SampleDynamicGroupMediaRouteProviderService.ACTION_BIND_LOCAL);
85         bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
86     }
87 
88     @Override
onStop()89     protected void onStop() {
90         super.onStop();
91         unbindService(mConnection);
92     }
93 
setUpViews()94     private void setUpViews() {
95         setUpEditText(
96                 findViewById(R.id.name_edit_text),
97                 mRouteItem.getName(),
98                 newName -> mRouteItem.setName(newName));
99 
100         setUpEditText(
101                 findViewById(R.id.description_edit_text),
102                 mRouteItem.getDescription(),
103                 newDescription -> mRouteItem.setDescription(newDescription));
104 
105         setUpEnumBasedSpinner(
106                 /* context= */ this,
107                 findViewById(R.id.control_filters_spinner),
108                 mRouteItem.getControlFilter(),
109                 newControlFilter ->
110                         mRouteItem.setControlFilter((RouteItem.ControlFilter) newControlFilter));
111 
112         setUpEnumBasedSpinner(
113                 /* context= */ this,
114                 findViewById(R.id.playback_stream_spinner),
115                 mRouteItem.getPlaybackStream(),
116                 newPlaybackStream ->
117                         mRouteItem.setPlaybackStream((RouteItem.PlaybackStream) newPlaybackStream));
118 
119         setUpEnumBasedSpinner(
120                 /* context= */ this,
121                 findViewById(R.id.playback_type_spinner),
122                 mRouteItem.getPlaybackType(),
123                 newPlaybackType ->
124                         mRouteItem.setPlaybackType((RouteItem.PlaybackType) newPlaybackType));
125 
126         setUpEnumBasedSpinner(
127                 /* context= */ this,
128                 findViewById(R.id.device_type_spinner),
129                 mRouteItem.getDeviceType(),
130                 newDeviceType -> mRouteItem.setDeviceType((RouteItem.DeviceType) newDeviceType));
131 
132         setUpEnumBasedSpinner(
133                 /* context= */ this,
134                 findViewById(R.id.volume_handling_spinner),
135                 mRouteItem.getVolumeHandling(),
136                 mewVolumeHandling ->
137                         mRouteItem.setVolumeHandling((RouteItem.VolumeHandling) mewVolumeHandling));
138 
139         setUpEditText(
140                 findViewById(R.id.volume_edit_text),
141                 String.valueOf(mRouteItem.getVolume()),
142                 mewVolume -> mRouteItem.setVolume(Integer.parseInt(mewVolume)));
143 
144         setUpEditText(
145                 findViewById(R.id.volume_max_edit_text),
146                 String.valueOf(mRouteItem.getVolumeMax()),
147                 mewVolumeMax -> mRouteItem.setVolumeMax(Integer.parseInt(mewVolumeMax)));
148 
149         setUpSwitch(
150                 findViewById(R.id.can_disconnect_switch),
151                 mRouteItem.isCanDisconnect(),
152                 newValue -> mRouteItem.setCanDisconnect(newValue));
153 
154         setUpSwitch(
155                 findViewById(R.id.is_sender_driven_switch),
156                 mRouteItem.isSenderDriven(),
157                 newValue -> mRouteItem.setSenderDriven(newValue));
158 
159         setUpSaveButton();
160     }
161 
setUpSaveButton()162     private void setUpSaveButton() {
163         Button saveButton = findViewById(R.id.save_button);
164         saveButton.setOnClickListener(
165                 view -> {
166                     mRoutesManager.addRoute(mRouteItem);
167                     if (mService != null) {
168                         mService.reloadRoutes();
169                     }
170                     finish();
171                 });
172     }
173 
setUpSwitch(Switch switchWidget, boolean currentValue, Consumer<Boolean> propertySetter)174     private static void setUpSwitch(Switch switchWidget, boolean currentValue,
175             Consumer<Boolean> propertySetter) {
176         switchWidget.setChecked(currentValue);
177         switchWidget.setOnCheckedChangeListener((compoundButton, b) -> propertySetter.accept(b));
178     }
179 
setUpEditText( EditText editText, String currentValue, Consumer<String> propertySetter)180     private static void setUpEditText(
181             EditText editText, String currentValue, Consumer<String> propertySetter) {
182         editText.setText(currentValue);
183         editText.addTextChangedListener(
184                 new TextWatcher() {
185                     @Override
186                     public void beforeTextChanged(
187                             CharSequence charSequence, int i, int i1, int i2) {}
188 
189                     @Override
190                     public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
191                         propertySetter.accept(charSequence.toString());
192                     }
193 
194                     @Override
195                     public void afterTextChanged(Editable editable) {}
196                 });
197     }
198 
199     private class ProviderServiceConnection implements ServiceConnection {
200 
201         @Override
onServiceConnected(ComponentName className, IBinder service)202         public void onServiceConnected(ComponentName className, IBinder service) {
203             SampleDynamicGroupMediaRouteProviderService.LocalBinder binder =
204                     (SampleDynamicGroupMediaRouteProviderService.LocalBinder) service;
205             mService = binder.getService();
206         }
207 
208         @Override
onServiceDisconnected(ComponentName unusedComponentName)209         public void onServiceDisconnected(ComponentName unusedComponentName) {
210             mService = null;
211         }
212     }
213 }
214