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