• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2016 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.android.incallui.incall.impl;
18 
19 import android.support.annotation.CallSuper;
20 import android.support.annotation.DrawableRes;
21 import android.support.annotation.NonNull;
22 import android.support.annotation.StringRes;
23 import android.telecom.CallAudioState;
24 import android.text.TextUtils;
25 import android.view.View;
26 import android.view.View.OnClickListener;
27 import com.android.dialer.common.Assert;
28 import com.android.incallui.incall.impl.CheckableLabeledButton.OnCheckedChangeListener;
29 import com.android.incallui.incall.protocol.InCallButtonIds;
30 import com.android.incallui.incall.protocol.InCallButtonUiDelegate;
31 import com.android.incallui.incall.protocol.InCallScreenDelegate;
32 
33 /** Manages a single button. */
34 interface ButtonController {
35 
isEnabled()36   boolean isEnabled();
37 
setEnabled(boolean isEnabled)38   void setEnabled(boolean isEnabled);
39 
isAllowed()40   boolean isAllowed();
41 
setAllowed(boolean isAllowed)42   void setAllowed(boolean isAllowed);
43 
setChecked(boolean isChecked)44   void setChecked(boolean isChecked);
45 
46   @InCallButtonIds
getInCallButtonId()47   int getInCallButtonId();
48 
setButton(CheckableLabeledButton button)49   void setButton(CheckableLabeledButton button);
50 
51   final class Controllers {
52 
resetButton(CheckableLabeledButton button)53     private static void resetButton(CheckableLabeledButton button) {
54       if (button != null) {
55         button.setOnCheckedChangeListener(null);
56         button.setOnClickListener(null);
57       }
58     }
59   }
60 
61   abstract class CheckableButtonController implements ButtonController, OnCheckedChangeListener {
62 
63     @NonNull protected final InCallButtonUiDelegate delegate;
64     @InCallButtonIds protected final int buttonId;
65     @StringRes protected final int checkedDescription;
66     @StringRes protected final int uncheckedDescription;
67     protected boolean isEnabled;
68     protected boolean isAllowed;
69     protected boolean isChecked;
70     protected CheckableLabeledButton button;
71 
CheckableButtonController( @onNull InCallButtonUiDelegate delegate, @InCallButtonIds int buttonId, @StringRes int checkedContentDescription, @StringRes int uncheckedContentDescription)72     protected CheckableButtonController(
73         @NonNull InCallButtonUiDelegate delegate,
74         @InCallButtonIds int buttonId,
75         @StringRes int checkedContentDescription,
76         @StringRes int uncheckedContentDescription) {
77       Assert.isNotNull(delegate);
78       this.delegate = delegate;
79       this.buttonId = buttonId;
80       this.checkedDescription = checkedContentDescription;
81       this.uncheckedDescription = uncheckedContentDescription;
82     }
83 
84     @Override
isEnabled()85     public boolean isEnabled() {
86       return isEnabled;
87     }
88 
89     @Override
setEnabled(boolean isEnabled)90     public void setEnabled(boolean isEnabled) {
91       this.isEnabled = isEnabled;
92       if (button != null) {
93         button.setEnabled(isEnabled);
94       }
95     }
96 
97     @Override
isAllowed()98     public boolean isAllowed() {
99       return isAllowed;
100     }
101 
102     @Override
setAllowed(boolean isAllowed)103     public void setAllowed(boolean isAllowed) {
104       this.isAllowed = isAllowed;
105       if (button != null) {
106         button.setVisibility(isAllowed ? View.VISIBLE : View.INVISIBLE);
107       }
108     }
109 
110     @Override
setChecked(boolean isChecked)111     public void setChecked(boolean isChecked) {
112       this.isChecked = isChecked;
113       if (button != null) {
114         button.setChecked(isChecked);
115       }
116     }
117 
118     @Override
119     @InCallButtonIds
getInCallButtonId()120     public int getInCallButtonId() {
121       return buttonId;
122     }
123 
124     @Override
125     @CallSuper
setButton(CheckableLabeledButton button)126     public void setButton(CheckableLabeledButton button) {
127       Controllers.resetButton(this.button);
128 
129       this.button = button;
130       if (button != null) {
131         button.setEnabled(isEnabled);
132         button.setVisibility(isAllowed ? View.VISIBLE : View.INVISIBLE);
133         button.setChecked(isChecked);
134         button.setOnClickListener(null);
135         button.setOnCheckedChangeListener(this);
136         button.setContentDescription(
137             button.getContext().getText(isChecked ? checkedDescription : uncheckedDescription));
138         button.setShouldShowMoreIndicator(false);
139       }
140     }
141 
142     @Override
onCheckedChanged(CheckableLabeledButton checkableLabeledButton, boolean isChecked)143     public void onCheckedChanged(CheckableLabeledButton checkableLabeledButton, boolean isChecked) {
144       button.setContentDescription(
145           button.getContext().getText(isChecked ? checkedDescription : uncheckedDescription));
146       doCheckedChanged(isChecked);
147     }
148 
doCheckedChanged(boolean isChecked)149     protected abstract void doCheckedChanged(boolean isChecked);
150   }
151 
152   abstract class SimpleCheckableButtonController extends CheckableButtonController {
153 
154     @StringRes private final int label;
155     @DrawableRes private final int icon;
156 
SimpleCheckableButtonController( @onNull InCallButtonUiDelegate delegate, @InCallButtonIds int buttonId, @StringRes int checkedContentDescription, @StringRes int uncheckedContentDescription, @StringRes int label, @DrawableRes int icon)157     protected SimpleCheckableButtonController(
158         @NonNull InCallButtonUiDelegate delegate,
159         @InCallButtonIds int buttonId,
160         @StringRes int checkedContentDescription,
161         @StringRes int uncheckedContentDescription,
162         @StringRes int label,
163         @DrawableRes int icon) {
164       super(
165           delegate,
166           buttonId,
167           checkedContentDescription == 0 ? label : checkedContentDescription,
168           uncheckedContentDescription == 0 ? label : uncheckedContentDescription);
169       this.label = label;
170       this.icon = icon;
171     }
172 
173     @Override
174     @CallSuper
setButton(CheckableLabeledButton button)175     public void setButton(CheckableLabeledButton button) {
176       super.setButton(button);
177       if (button != null) {
178         button.setLabelText(label);
179         button.setIconDrawable(icon);
180       }
181     }
182   }
183 
184   abstract class NonCheckableButtonController implements ButtonController, OnClickListener {
185 
186     protected final InCallButtonUiDelegate delegate;
187     @InCallButtonIds protected final int buttonId;
188     @StringRes protected final int contentDescription;
189     protected boolean isEnabled;
190     protected boolean isAllowed;
191     protected CheckableLabeledButton button;
192 
NonCheckableButtonController( InCallButtonUiDelegate delegate, @InCallButtonIds int buttonId, @StringRes int contentDescription)193     protected NonCheckableButtonController(
194         InCallButtonUiDelegate delegate,
195         @InCallButtonIds int buttonId,
196         @StringRes int contentDescription) {
197       this.delegate = delegate;
198       this.buttonId = buttonId;
199       this.contentDescription = contentDescription;
200     }
201 
202     @Override
isEnabled()203     public boolean isEnabled() {
204       return isEnabled;
205     }
206 
207     @Override
setEnabled(boolean isEnabled)208     public void setEnabled(boolean isEnabled) {
209       this.isEnabled = isEnabled;
210       if (button != null) {
211         button.setEnabled(isEnabled);
212       }
213     }
214 
215     @Override
isAllowed()216     public boolean isAllowed() {
217       return isAllowed;
218     }
219 
220     @Override
setAllowed(boolean isAllowed)221     public void setAllowed(boolean isAllowed) {
222       this.isAllowed = isAllowed;
223       if (button != null) {
224         button.setVisibility(isAllowed ? View.VISIBLE : View.INVISIBLE);
225       }
226     }
227 
228     @Override
setChecked(boolean isChecked)229     public void setChecked(boolean isChecked) {
230       Assert.fail();
231     }
232 
233     @Override
234     @InCallButtonIds
getInCallButtonId()235     public int getInCallButtonId() {
236       return buttonId;
237     }
238 
239     @Override
240     @CallSuper
setButton(CheckableLabeledButton button)241     public void setButton(CheckableLabeledButton button) {
242       Controllers.resetButton(this.button);
243 
244       this.button = button;
245       if (button != null) {
246         button.setEnabled(isEnabled);
247         button.setVisibility(isAllowed ? View.VISIBLE : View.INVISIBLE);
248         button.setChecked(false);
249         button.setOnCheckedChangeListener(null);
250         button.setOnClickListener(this);
251         button.setContentDescription(button.getContext().getText(contentDescription));
252         button.setShouldShowMoreIndicator(false);
253       }
254     }
255   }
256 
257   abstract class SimpleNonCheckableButtonController extends NonCheckableButtonController {
258 
259     @StringRes private final int label;
260     @DrawableRes private final int icon;
261 
SimpleNonCheckableButtonController( InCallButtonUiDelegate delegate, @InCallButtonIds int buttonId, @StringRes int contentDescription, @StringRes int label, @DrawableRes int icon)262     protected SimpleNonCheckableButtonController(
263         InCallButtonUiDelegate delegate,
264         @InCallButtonIds int buttonId,
265         @StringRes int contentDescription,
266         @StringRes int label,
267         @DrawableRes int icon) {
268       super(delegate, buttonId, contentDescription == 0 ? label : contentDescription);
269       this.label = label;
270       this.icon = icon;
271     }
272 
273     @Override
274     @CallSuper
setButton(CheckableLabeledButton button)275     public void setButton(CheckableLabeledButton button) {
276       super.setButton(button);
277       if (button != null) {
278         button.setLabelText(label);
279         button.setIconDrawable(icon);
280       }
281     }
282   }
283 
284   class MuteButtonController extends SimpleCheckableButtonController {
285 
MuteButtonController(InCallButtonUiDelegate delegate)286     public MuteButtonController(InCallButtonUiDelegate delegate) {
287       super(
288           delegate,
289           InCallButtonIds.BUTTON_MUTE,
290           R.string.incall_content_description_muted,
291           R.string.incall_content_description_unmuted,
292           R.string.incall_label_mute,
293           R.drawable.quantum_ic_mic_off_white_36);
294     }
295 
296     @Override
doCheckedChanged(boolean isChecked)297     public void doCheckedChanged(boolean isChecked) {
298       delegate.muteClicked(isChecked, true /* clickedByUser */);
299     }
300   }
301 
302   class SpeakerButtonController
303       implements ButtonController, OnCheckedChangeListener, OnClickListener {
304 
305     @NonNull private final InCallButtonUiDelegate delegate;
306     private boolean isEnabled;
307     private boolean isAllowed;
308     private boolean isChecked;
309     private CheckableLabeledButton button;
310 
311     @StringRes private int label = R.string.incall_label_speaker;
312     @DrawableRes private int icon = R.drawable.quantum_ic_volume_up_white_36;
313     private boolean checkable;
314     private CharSequence contentDescription;
315     private CharSequence checkedContentDescription;
316     private CharSequence uncheckedContentDescription;
317 
SpeakerButtonController(@onNull InCallButtonUiDelegate delegate)318     public SpeakerButtonController(@NonNull InCallButtonUiDelegate delegate) {
319       this.delegate = delegate;
320     }
321 
322     @Override
isEnabled()323     public boolean isEnabled() {
324       return isEnabled;
325     }
326 
327     @Override
setEnabled(boolean isEnabled)328     public void setEnabled(boolean isEnabled) {
329       this.isEnabled = isEnabled;
330       if (button != null) {
331         button.setEnabled(isEnabled && isAllowed);
332       }
333     }
334 
335     @Override
isAllowed()336     public boolean isAllowed() {
337       return isAllowed;
338     }
339 
340     @Override
setAllowed(boolean isAllowed)341     public void setAllowed(boolean isAllowed) {
342       this.isAllowed = isAllowed;
343       if (button != null) {
344         button.setEnabled(isEnabled && isAllowed);
345       }
346     }
347 
348     @Override
setChecked(boolean isChecked)349     public void setChecked(boolean isChecked) {
350       this.isChecked = isChecked;
351       if (button != null) {
352         button.setChecked(isChecked);
353       }
354     }
355 
356     @Override
getInCallButtonId()357     public int getInCallButtonId() {
358       return InCallButtonIds.BUTTON_AUDIO;
359     }
360 
361     @Override
setButton(CheckableLabeledButton button)362     public void setButton(CheckableLabeledButton button) {
363       this.button = button;
364       if (button != null) {
365         button.setEnabled(isEnabled && isAllowed);
366         button.setVisibility(View.VISIBLE);
367         button.setChecked(isChecked);
368         button.setOnClickListener(checkable ? null : this);
369         button.setOnCheckedChangeListener(checkable ? this : null);
370         button.setLabelText(label);
371         button.setIconDrawable(icon);
372         button.setContentDescription(
373             isChecked ? checkedContentDescription : uncheckedContentDescription);
374         button.setShouldShowMoreIndicator(!checkable);
375       }
376     }
377 
setAudioState(CallAudioState audioState)378     public void setAudioState(CallAudioState audioState) {
379       @StringRes int contentDescriptionResId;
380       if ((audioState.getSupportedRouteMask() & CallAudioState.ROUTE_BLUETOOTH)
381           == CallAudioState.ROUTE_BLUETOOTH) {
382         checkable = false;
383         isChecked = false;
384         label = R.string.incall_label_audio;
385 
386         if ((audioState.getRoute() & CallAudioState.ROUTE_BLUETOOTH)
387             == CallAudioState.ROUTE_BLUETOOTH) {
388           icon = R.drawable.quantum_ic_bluetooth_audio_white_36;
389           contentDescriptionResId = R.string.incall_content_description_bluetooth;
390         } else if ((audioState.getRoute() & CallAudioState.ROUTE_SPEAKER)
391             == CallAudioState.ROUTE_SPEAKER) {
392           icon = R.drawable.quantum_ic_volume_up_white_36;
393           contentDescriptionResId = R.string.incall_content_description_speaker;
394         } else if ((audioState.getRoute() & CallAudioState.ROUTE_WIRED_HEADSET)
395             == CallAudioState.ROUTE_WIRED_HEADSET) {
396           icon = R.drawable.quantum_ic_headset_white_36;
397           contentDescriptionResId = R.string.incall_content_description_headset;
398         } else {
399           icon = R.drawable.ic_phone_audio_white_36dp;
400           contentDescriptionResId = R.string.incall_content_description_earpiece;
401         }
402       } else {
403         checkable = true;
404         isChecked = audioState.getRoute() == CallAudioState.ROUTE_SPEAKER;
405         label = R.string.incall_label_speaker;
406         icon = R.drawable.quantum_ic_volume_up_white_36;
407         contentDescriptionResId = R.string.incall_content_description_speaker;
408       }
409 
410       contentDescription = delegate.getContext().getText(contentDescriptionResId);
411       checkedContentDescription =
412           TextUtils.concat(
413               contentDescription,
414               delegate.getContext().getText(R.string.incall_talkback_speaker_on));
415       uncheckedContentDescription =
416           TextUtils.concat(
417               contentDescription,
418               delegate.getContext().getText(R.string.incall_talkback_speaker_off));
419       setButton(button);
420     }
421 
422     @Override
onClick(View v)423     public void onClick(View v) {
424       delegate.showAudioRouteSelector();
425     }
426 
427     @Override
onCheckedChanged(CheckableLabeledButton checkableLabeledButton, boolean isChecked)428     public void onCheckedChanged(CheckableLabeledButton checkableLabeledButton, boolean isChecked) {
429       checkableLabeledButton.setContentDescription(
430           isChecked ? checkedContentDescription : uncheckedContentDescription);
431       delegate.toggleSpeakerphone();
432     }
433   }
434 
435   class DialpadButtonController extends SimpleCheckableButtonController {
436 
DialpadButtonController(@onNull InCallButtonUiDelegate delegate)437     public DialpadButtonController(@NonNull InCallButtonUiDelegate delegate) {
438       super(
439           delegate,
440           InCallButtonIds.BUTTON_DIALPAD,
441           0,
442           0,
443           R.string.incall_label_dialpad,
444           R.drawable.quantum_ic_dialpad_white_36);
445     }
446 
447     @Override
doCheckedChanged(boolean isChecked)448     public void doCheckedChanged(boolean isChecked) {
449       delegate.showDialpadClicked(isChecked);
450     }
451   }
452 
453   class HoldButtonController extends SimpleCheckableButtonController {
454 
HoldButtonController(@onNull InCallButtonUiDelegate delegate)455     public HoldButtonController(@NonNull InCallButtonUiDelegate delegate) {
456       super(
457           delegate,
458           InCallButtonIds.BUTTON_HOLD,
459           R.string.incall_content_description_unhold,
460           R.string.incall_content_description_hold,
461           R.string.incall_label_hold,
462           R.drawable.quantum_ic_pause_white_36);
463     }
464 
465     @Override
doCheckedChanged(boolean isChecked)466     public void doCheckedChanged(boolean isChecked) {
467       delegate.holdClicked(isChecked);
468     }
469   }
470 
471   class AddCallButtonController extends SimpleNonCheckableButtonController {
472 
AddCallButtonController(@onNull InCallButtonUiDelegate delegate)473     public AddCallButtonController(@NonNull InCallButtonUiDelegate delegate) {
474       super(
475           delegate,
476           InCallButtonIds.BUTTON_ADD_CALL,
477           0,
478           R.string.incall_label_add_call,
479           R.drawable.ic_addcall_white);
480       Assert.isNotNull(delegate);
481     }
482 
483     @Override
onClick(View view)484     public void onClick(View view) {
485       delegate.addCallClicked();
486     }
487   }
488 
489   class SwapButtonController extends SimpleNonCheckableButtonController {
490 
SwapButtonController(@onNull InCallButtonUiDelegate delegate)491     public SwapButtonController(@NonNull InCallButtonUiDelegate delegate) {
492       super(
493           delegate,
494           InCallButtonIds.BUTTON_SWAP,
495           R.string.incall_content_description_swap_calls,
496           R.string.incall_label_swap,
497           R.drawable.quantum_ic_swap_calls_white_36);
498       Assert.isNotNull(delegate);
499     }
500 
501     @Override
onClick(View view)502     public void onClick(View view) {
503       delegate.swapClicked();
504     }
505   }
506 
507   class MergeButtonController extends SimpleNonCheckableButtonController {
508 
MergeButtonController(@onNull InCallButtonUiDelegate delegate)509     public MergeButtonController(@NonNull InCallButtonUiDelegate delegate) {
510       super(
511           delegate,
512           InCallButtonIds.BUTTON_MERGE,
513           R.string.incall_content_description_merge_calls,
514           R.string.incall_label_merge,
515           R.drawable.quantum_ic_call_merge_white_36);
516       Assert.isNotNull(delegate);
517     }
518 
519     @Override
onClick(View view)520     public void onClick(View view) {
521       delegate.mergeClicked();
522     }
523   }
524 
525   class UpgradeToVideoButtonController extends SimpleNonCheckableButtonController {
526 
UpgradeToVideoButtonController(@onNull InCallButtonUiDelegate delegate)527     public UpgradeToVideoButtonController(@NonNull InCallButtonUiDelegate delegate) {
528       super(
529           delegate,
530           InCallButtonIds.BUTTON_UPGRADE_TO_VIDEO,
531           0,
532           R.string.incall_label_videocall,
533           R.drawable.quantum_ic_videocam_white_36);
534       Assert.isNotNull(delegate);
535     }
536 
537     @Override
onClick(View view)538     public void onClick(View view) {
539       delegate.changeToVideoClicked();
540     }
541   }
542 
543   class ManageConferenceButtonController extends SimpleNonCheckableButtonController {
544 
545     private final InCallScreenDelegate inCallScreenDelegate;
546 
ManageConferenceButtonController(@onNull InCallScreenDelegate inCallScreenDelegate)547     public ManageConferenceButtonController(@NonNull InCallScreenDelegate inCallScreenDelegate) {
548       super(
549           null,
550           InCallButtonIds.BUTTON_MANAGE_VOICE_CONFERENCE,
551           R.string.a11y_description_incall_label_manage_content,
552           R.string.incall_label_manage,
553           R.drawable.quantum_ic_group_white_36);
554       Assert.isNotNull(inCallScreenDelegate);
555       this.inCallScreenDelegate = inCallScreenDelegate;
556     }
557 
558     @Override
onClick(View view)559     public void onClick(View view) {
560       inCallScreenDelegate.onManageConferenceClicked();
561     }
562   }
563 
564   class SwitchToSecondaryButtonController extends SimpleNonCheckableButtonController {
565 
566     private final InCallScreenDelegate inCallScreenDelegate;
567 
SwitchToSecondaryButtonController(InCallScreenDelegate inCallScreenDelegate)568     public SwitchToSecondaryButtonController(InCallScreenDelegate inCallScreenDelegate) {
569       super(
570           null,
571           InCallButtonIds.BUTTON_SWITCH_TO_SECONDARY,
572           R.string.incall_content_description_swap_calls,
573           R.string.incall_label_swap,
574           R.drawable.quantum_ic_swap_calls_white_36);
575       Assert.isNotNull(inCallScreenDelegate);
576       this.inCallScreenDelegate = inCallScreenDelegate;
577     }
578 
579     @Override
onClick(View view)580     public void onClick(View view) {
581       inCallScreenDelegate.onSecondaryInfoClicked();
582     }
583   }
584 }
585