blob: 8c113649dbc0f2adf07500be838f34f21ef496ff [file] [log] [blame]
/*
* Copyright (C) 2016 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.incallui.incall.impl;
import android.support.annotation.CallSuper;
import android.support.annotation.DrawableRes;
import android.support.annotation.NonNull;
import android.support.annotation.StringRes;
import android.telecom.CallAudioState;
import android.text.TextUtils;
import android.view.View;
import android.view.View.OnClickListener;
import com.android.dialer.common.Assert;
import com.android.incallui.incall.impl.CheckableLabeledButton.OnCheckedChangeListener;
import com.android.incallui.incall.protocol.InCallButtonIds;
import com.android.incallui.incall.protocol.InCallButtonUiDelegate;
import com.android.incallui.incall.protocol.InCallScreenDelegate;
/** Manages a single button. */
interface ButtonController {
boolean isEnabled();
void setEnabled(boolean isEnabled);
boolean isAllowed();
void setAllowed(boolean isAllowed);
void setChecked(boolean isChecked);
@InCallButtonIds
int getInCallButtonId();
void setButton(CheckableLabeledButton button);
final class Controllers {
private static void resetButton(CheckableLabeledButton button) {
if (button != null) {
button.setOnCheckedChangeListener(null);
button.setOnClickListener(null);
}
}
}
abstract class CheckableButtonController implements ButtonController, OnCheckedChangeListener {
@NonNull protected final InCallButtonUiDelegate delegate;
@InCallButtonIds protected final int buttonId;
@StringRes protected final int checkedDescription;
@StringRes protected final int uncheckedDescription;
protected boolean isEnabled;
protected boolean isAllowed;
protected boolean isChecked;
protected CheckableLabeledButton button;
protected CheckableButtonController(
@NonNull InCallButtonUiDelegate delegate,
@InCallButtonIds int buttonId,
@StringRes int checkedContentDescription,
@StringRes int uncheckedContentDescription) {
Assert.isNotNull(delegate);
this.delegate = delegate;
this.buttonId = buttonId;
this.checkedDescription = checkedContentDescription;
this.uncheckedDescription = uncheckedContentDescription;
}
@Override
public boolean isEnabled() {
return isEnabled;
}
@Override
public void setEnabled(boolean isEnabled) {
this.isEnabled = isEnabled;
if (button != null) {
button.setEnabled(isEnabled);
}
}
@Override
public boolean isAllowed() {
return isAllowed;
}
@Override
public void setAllowed(boolean isAllowed) {
this.isAllowed = isAllowed;
if (button != null) {
button.setVisibility(isAllowed ? View.VISIBLE : View.INVISIBLE);
}
}
@Override
public void setChecked(boolean isChecked) {
this.isChecked = isChecked;
if (button != null) {
button.setChecked(isChecked);
}
}
@Override
@InCallButtonIds
public int getInCallButtonId() {
return buttonId;
}
@Override
@CallSuper
public void setButton(CheckableLabeledButton button) {
Controllers.resetButton(this.button);
this.button = button;
if (button != null) {
button.setEnabled(isEnabled);
button.setVisibility(isAllowed ? View.VISIBLE : View.INVISIBLE);
button.setChecked(isChecked);
button.setOnClickListener(null);
button.setOnCheckedChangeListener(this);
button.setContentDescription(
button.getContext().getText(isChecked ? checkedDescription : uncheckedDescription));
button.setShouldShowMoreIndicator(false);
}
}
@Override
public void onCheckedChanged(CheckableLabeledButton checkableLabeledButton, boolean isChecked) {
button.setContentDescription(
button.getContext().getText(isChecked ? checkedDescription : uncheckedDescription));
doCheckedChanged(isChecked);
}
protected abstract void doCheckedChanged(boolean isChecked);
}
abstract class SimpleCheckableButtonController extends CheckableButtonController {
@StringRes private final int label;
@DrawableRes private final int icon;
protected SimpleCheckableButtonController(
@NonNull InCallButtonUiDelegate delegate,
@InCallButtonIds int buttonId,
@StringRes int checkedContentDescription,
@StringRes int uncheckedContentDescription,
@StringRes int label,
@DrawableRes int icon) {
super(
delegate,
buttonId,
checkedContentDescription == 0 ? label : checkedContentDescription,
uncheckedContentDescription == 0 ? label : uncheckedContentDescription);
this.label = label;
this.icon = icon;
}
@Override
@CallSuper
public void setButton(CheckableLabeledButton button) {
super.setButton(button);
if (button != null) {
button.setLabelText(label);
button.setIconDrawable(icon);
}
}
}
abstract class NonCheckableButtonController implements ButtonController, OnClickListener {
protected final InCallButtonUiDelegate delegate;
@InCallButtonIds protected final int buttonId;
@StringRes protected final int contentDescription;
protected boolean isEnabled;
protected boolean isAllowed;
protected CheckableLabeledButton button;
protected NonCheckableButtonController(
InCallButtonUiDelegate delegate,
@InCallButtonIds int buttonId,
@StringRes int contentDescription) {
this.delegate = delegate;
this.buttonId = buttonId;
this.contentDescription = contentDescription;
}
@Override
public boolean isEnabled() {
return isEnabled;
}
@Override
public void setEnabled(boolean isEnabled) {
this.isEnabled = isEnabled;
if (button != null) {
button.setEnabled(isEnabled);
}
}
@Override
public boolean isAllowed() {
return isAllowed;
}
@Override
public void setAllowed(boolean isAllowed) {
this.isAllowed = isAllowed;
if (button != null) {
button.setVisibility(isAllowed ? View.VISIBLE : View.INVISIBLE);
}
}
@Override
public void setChecked(boolean isChecked) {
Assert.fail();
}
@Override
@InCallButtonIds
public int getInCallButtonId() {
return buttonId;
}
@Override
@CallSuper
public void setButton(CheckableLabeledButton button) {
Controllers.resetButton(this.button);
this.button = button;
if (button != null) {
button.setEnabled(isEnabled);
button.setVisibility(isAllowed ? View.VISIBLE : View.INVISIBLE);
button.setChecked(false);
button.setOnCheckedChangeListener(null);
button.setOnClickListener(this);
button.setContentDescription(button.getContext().getText(contentDescription));
button.setShouldShowMoreIndicator(false);
}
}
}
abstract class SimpleNonCheckableButtonController extends NonCheckableButtonController {
@StringRes private final int label;
@DrawableRes private final int icon;
protected SimpleNonCheckableButtonController(
InCallButtonUiDelegate delegate,
@InCallButtonIds int buttonId,
@StringRes int contentDescription,
@StringRes int label,
@DrawableRes int icon) {
super(delegate, buttonId, contentDescription == 0 ? label : contentDescription);
this.label = label;
this.icon = icon;
}
@Override
@CallSuper
public void setButton(CheckableLabeledButton button) {
super.setButton(button);
if (button != null) {
button.setLabelText(label);
button.setIconDrawable(icon);
}
}
}
class MuteButtonController extends SimpleCheckableButtonController {
public MuteButtonController(InCallButtonUiDelegate delegate) {
super(
delegate,
InCallButtonIds.BUTTON_MUTE,
R.string.incall_content_description_muted,
R.string.incall_content_description_unmuted,
R.string.incall_label_mute,
R.drawable.quantum_ic_mic_off_white_36);
}
@Override
public void doCheckedChanged(boolean isChecked) {
delegate.muteClicked(isChecked, true /* clickedByUser */);
}
}
class SpeakerButtonController
implements ButtonController, OnCheckedChangeListener, OnClickListener {
@NonNull private final InCallButtonUiDelegate delegate;
private boolean isEnabled;
private boolean isAllowed;
private boolean isChecked;
private CheckableLabeledButton button;
@StringRes private int label = R.string.incall_label_speaker;
@DrawableRes private int icon = R.drawable.quantum_ic_volume_up_white_36;
private boolean checkable;
private CharSequence contentDescription;
private CharSequence checkedContentDescription;
private CharSequence uncheckedContentDescription;
public SpeakerButtonController(@NonNull InCallButtonUiDelegate delegate) {
this.delegate = delegate;
}
@Override
public boolean isEnabled() {
return isEnabled;
}
@Override
public void setEnabled(boolean isEnabled) {
this.isEnabled = isEnabled;
if (button != null) {
button.setEnabled(isEnabled && isAllowed);
}
}
@Override
public boolean isAllowed() {
return isAllowed;
}
@Override
public void setAllowed(boolean isAllowed) {
this.isAllowed = isAllowed;
if (button != null) {
button.setEnabled(isEnabled && isAllowed);
}
}
@Override
public void setChecked(boolean isChecked) {
this.isChecked = isChecked;
if (button != null) {
button.setChecked(isChecked);
}
}
@Override
public int getInCallButtonId() {
return InCallButtonIds.BUTTON_AUDIO;
}
@Override
public void setButton(CheckableLabeledButton button) {
this.button = button;
if (button != null) {
button.setEnabled(isEnabled && isAllowed);
button.setVisibility(View.VISIBLE);
button.setChecked(isChecked);
button.setOnClickListener(checkable ? null : this);
button.setOnCheckedChangeListener(checkable ? this : null);
button.setLabelText(label);
button.setIconDrawable(icon);
button.setContentDescription(
isChecked ? checkedContentDescription : uncheckedContentDescription);
button.setShouldShowMoreIndicator(!checkable);
}
}
public void setAudioState(CallAudioState audioState) {
@StringRes int contentDescriptionResId;
if ((audioState.getSupportedRouteMask() & CallAudioState.ROUTE_BLUETOOTH)
== CallAudioState.ROUTE_BLUETOOTH) {
checkable = false;
isChecked = false;
label = R.string.incall_label_audio;
if ((audioState.getRoute() & CallAudioState.ROUTE_BLUETOOTH)
== CallAudioState.ROUTE_BLUETOOTH) {
icon = R.drawable.quantum_ic_bluetooth_audio_white_36;
contentDescriptionResId = R.string.incall_content_description_bluetooth;
} else if ((audioState.getRoute() & CallAudioState.ROUTE_SPEAKER)
== CallAudioState.ROUTE_SPEAKER) {
icon = R.drawable.quantum_ic_volume_up_white_36;
contentDescriptionResId = R.string.incall_content_description_speaker;
} else if ((audioState.getRoute() & CallAudioState.ROUTE_WIRED_HEADSET)
== CallAudioState.ROUTE_WIRED_HEADSET) {
icon = R.drawable.quantum_ic_headset_white_36;
contentDescriptionResId = R.string.incall_content_description_headset;
} else {
icon = R.drawable.ic_phone_audio_white_36dp;
contentDescriptionResId = R.string.incall_content_description_earpiece;
}
} else {
checkable = true;
isChecked = audioState.getRoute() == CallAudioState.ROUTE_SPEAKER;
label = R.string.incall_label_speaker;
icon = R.drawable.quantum_ic_volume_up_white_36;
contentDescriptionResId = R.string.incall_content_description_speaker;
}
contentDescription = delegate.getContext().getText(contentDescriptionResId);
checkedContentDescription =
TextUtils.concat(
contentDescription,
delegate.getContext().getText(R.string.incall_talkback_speaker_on));
uncheckedContentDescription =
TextUtils.concat(
contentDescription,
delegate.getContext().getText(R.string.incall_talkback_speaker_off));
setButton(button);
}
@Override
public void onClick(View v) {
delegate.showAudioRouteSelector();
}
@Override
public void onCheckedChanged(CheckableLabeledButton checkableLabeledButton, boolean isChecked) {
checkableLabeledButton.setContentDescription(
isChecked ? checkedContentDescription : uncheckedContentDescription);
delegate.toggleSpeakerphone();
}
}
class DialpadButtonController extends SimpleCheckableButtonController {
public DialpadButtonController(@NonNull InCallButtonUiDelegate delegate) {
super(
delegate,
InCallButtonIds.BUTTON_DIALPAD,
0,
0,
R.string.incall_label_dialpad,
R.drawable.quantum_ic_dialpad_white_36);
}
@Override
public void doCheckedChanged(boolean isChecked) {
delegate.showDialpadClicked(isChecked);
}
}
class HoldButtonController extends SimpleCheckableButtonController {
public HoldButtonController(@NonNull InCallButtonUiDelegate delegate) {
super(
delegate,
InCallButtonIds.BUTTON_HOLD,
R.string.incall_content_description_unhold,
R.string.incall_content_description_hold,
R.string.incall_label_hold,
R.drawable.quantum_ic_pause_white_36);
}
@Override
public void doCheckedChanged(boolean isChecked) {
delegate.holdClicked(isChecked);
}
}
class AddCallButtonController extends SimpleNonCheckableButtonController {
public AddCallButtonController(@NonNull InCallButtonUiDelegate delegate) {
super(
delegate,
InCallButtonIds.BUTTON_ADD_CALL,
0,
R.string.incall_label_add_call,
R.drawable.ic_addcall_white);
Assert.isNotNull(delegate);
}
@Override
public void onClick(View view) {
delegate.addCallClicked();
}
}
class SwapButtonController extends SimpleNonCheckableButtonController {
public SwapButtonController(@NonNull InCallButtonUiDelegate delegate) {
super(
delegate,
InCallButtonIds.BUTTON_SWAP,
R.string.incall_content_description_swap_calls,
R.string.incall_label_swap,
R.drawable.quantum_ic_swap_calls_white_36);
Assert.isNotNull(delegate);
}
@Override
public void onClick(View view) {
delegate.swapClicked();
}
}
class MergeButtonController extends SimpleNonCheckableButtonController {
public MergeButtonController(@NonNull InCallButtonUiDelegate delegate) {
super(
delegate,
InCallButtonIds.BUTTON_MERGE,
R.string.incall_content_description_merge_calls,
R.string.incall_label_merge,
R.drawable.quantum_ic_call_merge_white_36);
Assert.isNotNull(delegate);
}
@Override
public void onClick(View view) {
delegate.mergeClicked();
}
}
class UpgradeToVideoButtonController extends SimpleNonCheckableButtonController {
public UpgradeToVideoButtonController(@NonNull InCallButtonUiDelegate delegate) {
super(
delegate,
InCallButtonIds.BUTTON_UPGRADE_TO_VIDEO,
0,
R.string.incall_label_videocall,
R.drawable.quantum_ic_videocam_white_36);
Assert.isNotNull(delegate);
}
@Override
public void onClick(View view) {
delegate.changeToVideoClicked();
}
}
class ManageConferenceButtonController extends SimpleNonCheckableButtonController {
private final InCallScreenDelegate inCallScreenDelegate;
public ManageConferenceButtonController(@NonNull InCallScreenDelegate inCallScreenDelegate) {
super(
null,
InCallButtonIds.BUTTON_MANAGE_VOICE_CONFERENCE,
R.string.a11y_description_incall_label_manage_content,
R.string.incall_label_manage,
R.drawable.quantum_ic_group_white_36);
Assert.isNotNull(inCallScreenDelegate);
this.inCallScreenDelegate = inCallScreenDelegate;
}
@Override
public void onClick(View view) {
inCallScreenDelegate.onManageConferenceClicked();
}
}
class SwitchToSecondaryButtonController extends SimpleNonCheckableButtonController {
private final InCallScreenDelegate inCallScreenDelegate;
public SwitchToSecondaryButtonController(InCallScreenDelegate inCallScreenDelegate) {
super(
null,
InCallButtonIds.BUTTON_SWITCH_TO_SECONDARY,
R.string.incall_content_description_swap_calls,
R.string.incall_label_swap,
R.drawable.quantum_ic_swap_calls_white_36);
Assert.isNotNull(inCallScreenDelegate);
this.inCallScreenDelegate = inCallScreenDelegate;
}
@Override
public void onClick(View view) {
inCallScreenDelegate.onSecondaryInfoClicked();
}
}
}