diff options
Diffstat (limited to 'src/com/android/incallui/CallButtonFragment.java')
-rw-r--r-- | src/com/android/incallui/CallButtonFragment.java | 254 |
1 files changed, 187 insertions, 67 deletions
diff --git a/src/com/android/incallui/CallButtonFragment.java b/src/com/android/incallui/CallButtonFragment.java index a8d6ef5c..2c7fbe6f 100644 --- a/src/com/android/incallui/CallButtonFragment.java +++ b/src/com/android/incallui/CallButtonFragment.java @@ -19,20 +19,24 @@ package com.android.incallui; import android.app.AlertDialog; import android.content.Context; import android.content.DialogInterface; +import android.content.res.ColorStateList; import android.content.res.Resources; +import android.graphics.drawable.Drawable; import android.graphics.drawable.LayerDrawable; +import android.graphics.drawable.GradientDrawable; +import android.graphics.drawable.RippleDrawable; +import android.graphics.drawable.StateListDrawable; import android.os.Bundle; import android.telecom.AudioState; import android.telecom.TelecomManager; import android.telecom.VideoProfile; import android.view.ContextThemeWrapper; +import android.view.HapticFeedbackConstants; import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; -import android.view.accessibility.AccessibilityEvent; -import android.view.accessibility.AccessibilityManager; import android.widget.CompoundButton; import android.widget.ImageButton; import android.widget.PopupMenu; @@ -42,26 +46,29 @@ import android.widget.PopupMenu.OnMenuItemClickListener; import java.util.ArrayList; +import com.android.contacts.common.util.MaterialColorMapUtils; +import com.android.contacts.common.util.MaterialColorMapUtils.MaterialPalette; + /** * Fragment for call control buttons */ public class CallButtonFragment extends BaseFragment<CallButtonPresenter, CallButtonPresenter.CallButtonUi> implements CallButtonPresenter.CallButtonUi, OnMenuItemClickListener, OnDismissListener, - View.OnClickListener, CompoundButton.OnCheckedChangeListener { + View.OnClickListener { private static final int INVALID_INDEX = -1; - private ImageButton mAudioButton; + private CompoundButton mAudioButton; private ImageButton mChangeToVoiceButton; - private ImageButton mMuteButton; - private ImageButton mShowDialpadButton; - private ImageButton mHoldButton; + private CompoundButton mMuteButton; + private CompoundButton mShowDialpadButton; + private CompoundButton mHoldButton; private ImageButton mSwapButton; private ImageButton mChangeToVideoButton; - private ImageButton mSwitchCameraButton; + private CompoundButton mSwitchCameraButton; private ImageButton mAddCallButton; private ImageButton mMergeButton; - private ImageButton mPauseVideoButton; + private CompoundButton mPauseVideoButton; private ImageButton mOverflowButton; private ImageButton mAddParticipantButton; private ImageButton mManageVideoCallConferenceButton; @@ -78,6 +85,7 @@ public class CallButtonFragment private static final int VISIBLE = 255; private boolean mIsEnabled; + private MaterialPalette mCurrentThemeColors; @Override CallButtonPresenter createPresenter() { @@ -100,27 +108,27 @@ public class CallButtonFragment Bundle savedInstanceState) { final View parent = inflater.inflate(R.layout.call_button_fragment, container, false); - mAudioButton = (ImageButton) parent.findViewById(R.id.audioButton); + mAudioButton = (CompoundButton) parent.findViewById(R.id.audioButton); mAudioButton.setOnClickListener(this); mChangeToVoiceButton = (ImageButton) parent.findViewById(R.id.changeToVoiceButton); mChangeToVoiceButton. setOnClickListener(this); - mMuteButton = (ImageButton) parent.findViewById(R.id.muteButton); + mMuteButton = (CompoundButton) parent.findViewById(R.id.muteButton); mMuteButton.setOnClickListener(this); - mShowDialpadButton = (ImageButton) parent.findViewById(R.id.dialpadButton); + mShowDialpadButton = (CompoundButton) parent.findViewById(R.id.dialpadButton); mShowDialpadButton.setOnClickListener(this); - mHoldButton = (ImageButton) parent.findViewById(R.id.holdButton); + mHoldButton = (CompoundButton) parent.findViewById(R.id.holdButton); mHoldButton.setOnClickListener(this); mSwapButton = (ImageButton) parent.findViewById(R.id.swapButton); mSwapButton.setOnClickListener(this); mChangeToVideoButton = (ImageButton) parent.findViewById(R.id.changeToVideoButton); mChangeToVideoButton.setOnClickListener(this); - mSwitchCameraButton = (ImageButton) parent.findViewById(R.id.switchCameraButton); + mSwitchCameraButton = (CompoundButton) parent.findViewById(R.id.switchCameraButton); mSwitchCameraButton.setOnClickListener(this); mAddCallButton = (ImageButton) parent.findViewById(R.id.addButton); mAddCallButton.setOnClickListener(this); mMergeButton = (ImageButton) parent.findViewById(R.id.mergeButton); mMergeButton.setOnClickListener(this); - mPauseVideoButton = (ImageButton) parent.findViewById(R.id.pauseVideoButton); + mPauseVideoButton = (CompoundButton) parent.findViewById(R.id.pauseVideoButton); mPauseVideoButton.setOnClickListener(this); mAddParticipantButton = (ImageButton) parent.findViewById(R.id.addParticipant); mAddParticipantButton.setOnClickListener(this); @@ -147,10 +155,8 @@ public class CallButtonFragment getPresenter().refreshMuteState(); } super.onResume(); - } - @Override - public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { + updateColors(); } @Override @@ -158,6 +164,7 @@ public class CallButtonFragment int id = view.getId(); Log.d(this, "onClick(View " + view + ", id " + id + ")..."); + boolean isClickHandled = true; switch(id) { case R.id.audioButton: onAudioButtonClicked(); @@ -169,8 +176,7 @@ public class CallButtonFragment getPresenter().displayModifyCallOptions(); break; case R.id.muteButton: { - final ImageButton button = (ImageButton) view; - getPresenter().muteClicked(!button.isSelected()); + getPresenter().muteClicked(!mMuteButton.isSelected()); break; } case R.id.mergeButton: @@ -178,8 +184,7 @@ public class CallButtonFragment mMergeButton.setEnabled(false); break; case R.id.holdButton: { - final ImageButton button = (ImageButton) view; - getPresenter().holdClicked(!button.isSelected()); + getPresenter().holdClicked(!mHoldButton.isSelected()); break; } case R.id.swapButton: @@ -209,9 +214,122 @@ public class CallButtonFragment onManageVideoCallConferenceClicked(); break; default: + isClickHandled = false; Log.wtf(this, "onClick: unexpected"); break; } + + if (isClickHandled) { + view.performHapticFeedback( + HapticFeedbackConstants.VIRTUAL_KEY, + HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING); + } + } + + public void updateColors() { + MaterialPalette themeColors = InCallPresenter.getInstance().getThemeColors(); + + if (mCurrentThemeColors != null && mCurrentThemeColors.equals(themeColors)) { + return; + } + + Resources res = getActivity().getResources(); + View[] compoundButtons = { + mAudioButton, + mMuteButton, + mShowDialpadButton, + mHoldButton, + mSwitchCameraButton, + mPauseVideoButton + }; + + for (View button : compoundButtons) { + final LayerDrawable layers = (LayerDrawable) button.getBackground(); + final RippleDrawable btnCompoundDrawable = compoundBackgroundDrawable(themeColors); + layers.setDrawableByLayerId(R.id.compoundBackgroundItem, btnCompoundDrawable); + } + + ImageButton[] normalButtons = { + mChangeToVoiceButton, + mSwapButton, + mChangeToVideoButton, + mAddCallButton, + mMergeButton, + mOverflowButton + }; + + for (ImageButton button : normalButtons) { + final LayerDrawable layers = (LayerDrawable) button.getBackground(); + final RippleDrawable btnDrawable = backgroundDrawable(themeColors); + layers.setDrawableByLayerId(R.id.backgroundItem, btnDrawable); + } + + mCurrentThemeColors = themeColors; + } + + /** + * Generate a RippleDrawable which will be the background for a compound button, i.e. + * a button with pressed and unpressed states. The unpressed state will be the same color + * as the rest of the call card, the pressed state will be the dark version of that color. + */ + private RippleDrawable compoundBackgroundDrawable(MaterialPalette palette) { + Resources res = getResources(); + ColorStateList rippleColor = + ColorStateList.valueOf(res.getColor(R.color.incall_accent_color)); + + StateListDrawable stateListDrawable = new StateListDrawable(); + addSelectedAndFocused(res, stateListDrawable); + addFocused(res, stateListDrawable); + addSelected(res, stateListDrawable, palette); + addUnselected(res, stateListDrawable, palette); + + return new RippleDrawable(rippleColor, stateListDrawable, null); + } + + /** + * Generate a RippleDrawable which will be the background of a button to ensure it + * is the same color as the rest of the call card. + */ + private RippleDrawable backgroundDrawable(MaterialPalette palette) { + Resources res = getResources(); + ColorStateList rippleColor = + ColorStateList.valueOf(res.getColor(R.color.incall_accent_color)); + + StateListDrawable stateListDrawable = new StateListDrawable(); + addFocused(res, stateListDrawable); + addUnselected(res, stateListDrawable, palette); + + return new RippleDrawable(rippleColor, stateListDrawable, null); + } + + // state_selected and state_focused + private void addSelectedAndFocused(Resources res, StateListDrawable drawable) { + int[] selectedAndFocused = {android.R.attr.state_selected, android.R.attr.state_focused}; + Drawable selectedAndFocusedDrawable = res.getDrawable(R.drawable.btn_selected_focused); + drawable.addState(selectedAndFocused, selectedAndFocusedDrawable); + } + + // state_focused + private void addFocused(Resources res, StateListDrawable drawable) { + int[] focused = {android.R.attr.state_focused}; + Drawable focusedDrawable = res.getDrawable(R.drawable.btn_unselected_focused); + drawable.addState(focused, focusedDrawable); + } + + // state_selected + private void addSelected(Resources res, StateListDrawable drawable, MaterialPalette palette) { + int[] selected = {android.R.attr.state_selected}; + LayerDrawable selectedDrawable = (LayerDrawable) res.getDrawable(R.drawable.btn_selected); + ((GradientDrawable) selectedDrawable.getDrawable(0)).setColor(palette.mSecondaryColor); + drawable.addState(selected, selectedDrawable); + } + + // default + private void addUnselected(Resources res, StateListDrawable drawable, MaterialPalette palette) { + LayerDrawable unselectedDrawable = + (LayerDrawable) res.getDrawable(R.drawable.btn_unselected); + ((GradientDrawable) unselectedDrawable.getDrawable(0)).setColor(palette.mPrimaryColor); + drawable.addState(new int[0], unselectedDrawable); } @Override @@ -242,8 +360,6 @@ public class CallButtonFragment public void setMute(boolean value) { if (mMuteButton.isSelected() != value) { mMuteButton.setSelected(value); - maybeSendAccessibilityEvent(mMuteButton, value ? R.string.accessibility_call_muted - : R.string.accessibility_call_unmuted); } } @@ -271,9 +387,6 @@ public class CallButtonFragment public void setHold(boolean value) { if (mHoldButton.isSelected() != value) { mHoldButton.setSelected(value); - maybeSendAccessibilityEvent(mHoldButton, - value ? R.string.accessibility_call_put_on_hold : - R.string.accessibility_call_removed_from_hold); } } @@ -298,6 +411,11 @@ public class CallButtonFragment } @Override + public void enableChangeToVideoButton(boolean enable) { + mChangeToVideoButton.setEnabled(enable); + } + + @Override public void showSwitchCameraButton(boolean show) { mSwitchCameraButton.setVisibility(show ? View.VISIBLE : View.GONE); } @@ -499,26 +617,7 @@ public class CallButtonFragment refreshAudioModePopup(); if (mPrevAudioMode != mode) { - if (mPrevAudioMode != 0) { - int stringId = 0; - switch (mode) { - case AudioState.ROUTE_EARPIECE: - stringId = R.string.accessibility_earpiece_selected; - break; - case AudioState.ROUTE_BLUETOOTH: - stringId = R.string.accessibility_bluetooth_headset_selected; - break; - case AudioState.ROUTE_WIRED_HEADSET: - stringId = R.string.accessibility_wired_headset_selected; - break; - case AudioState.ROUTE_SPEAKER: - stringId = R.string.accessibility_speakerphone_selected; - break; - } - if (stringId != 0) { - maybeSendAccessibilityEvent(mAudioButton, stringId); - } - } + updateAudioButtonContentDescription(mode); mPrevAudioMode = mode; } } @@ -572,6 +671,7 @@ public class CallButtonFragment public void onDismiss(PopupMenu menu) { Log.d(this, "- onDismiss: " + menu); mAudioModePopupVisible = false; + updateAudioButtons(getPresenter().getSupportedAudio()); } /** @@ -593,7 +693,7 @@ public class CallButtonFragment Log.d(this, "onManageVideoCallConferenceClicked"); final InCallActivity activity = (InCallActivity) getActivity(); if (activity != null) { - activity.showConferenceCallManager(); + activity.showConferenceCallManager(true); } } @@ -637,10 +737,8 @@ public class CallButtonFragment Log.d(this, "updateAudioButtons - popup menu mode"); audioButtonEnabled = true; + audioButtonChecked = true; showMoreIndicator = true; - // The audio button is NOT a toggle in this state. (And its - // setChecked() state is irrelevant since we completely hide the - // btn_compound_background layer anyway.) // Update desired layers: if (isAudio(AudioState.ROUTE_BLUETOOTH)) { @@ -654,6 +752,9 @@ public class CallButtonFragment // sort of "wired headset" icon here instead of the "handset // earpiece" icon. (Still need an asset for that, though.) } + + // The audio button is NOT a toggle in this state, so set selected to false. + mAudioButton.setSelected(false); } else if (speakerSupported) { Log.d(this, "updateAudioButtons - speaker toggle mode"); @@ -662,6 +763,7 @@ public class CallButtonFragment // The audio button *is* a toggle in this state, and indicated the // current state of the speakerphone. audioButtonChecked = isAudio(AudioState.ROUTE_SPEAKER); + mAudioButton.setSelected(audioButtonChecked); // update desired layers: showToggleIndicator = true; @@ -673,6 +775,7 @@ public class CallButtonFragment // irrelevant since it's always disabled and unchecked. audioButtonEnabled = false; audioButtonChecked = false; + mAudioButton.setSelected(false); // update desired layers: showToggleIndicator = true; @@ -690,7 +793,7 @@ public class CallButtonFragment // Only enable the audio button if the fragment is enabled. mAudioButton.setEnabled(audioButtonEnabled && mIsEnabled); - mAudioButton.setSelected(audioButtonChecked); + mAudioButton.setChecked(audioButtonChecked); final LayerDrawable layers = (LayerDrawable) mAudioButton.getBackground(); Log.d(this, "'layers' drawable: " + layers); @@ -712,6 +815,38 @@ public class CallButtonFragment } + /** + * Update the content description of the audio button. + */ + private void updateAudioButtonContentDescription(int mode) { + int stringId = 0; + + // If bluetooth is not supported, the audio buttion will toggle, so use the label "speaker". + // Otherwise, use the label of the currently selected audio mode. + if (!isSupported(AudioState.ROUTE_BLUETOOTH)) { + stringId = R.string.audio_mode_speaker; + } else { + switch (mode) { + case AudioState.ROUTE_EARPIECE: + stringId = R.string.audio_mode_earpiece; + break; + case AudioState.ROUTE_BLUETOOTH: + stringId = R.string.audio_mode_bluetooth; + break; + case AudioState.ROUTE_WIRED_HEADSET: + stringId = R.string.audio_mode_wired_headset; + break; + case AudioState.ROUTE_SPEAKER: + stringId = R.string.audio_mode_speaker; + break; + } + } + + if (stringId != 0) { + mAudioButton.setContentDescription(getResources().getString(stringId)); + } + } + private void showAudioModePopup() { Log.d(this, "showAudioPopup()..."); @@ -791,21 +926,6 @@ public class CallButtonFragment return getActivity(); } - private void maybeSendAccessibilityEvent(View view, int stringId) { - final Context context = getActivity(); - AccessibilityManager manager = - (AccessibilityManager) context.getSystemService(Context.ACCESSIBILITY_SERVICE); - if (manager != null && manager.isEnabled()) { - AccessibilityEvent e = AccessibilityEvent.obtain(); - e.setSource(view); - e.setEventType(AccessibilityEvent.TYPE_ANNOUNCEMENT); - e.setClassName(getClass().getName()); - e.setPackageName(context.getPackageName()); - e.getText().add(context.getResources().getString(stringId)); - manager.sendAccessibilityEvent(e); - } - } - private boolean isTtyModeEnabled() { return (android.provider.Settings.Secure.getInt( getContext().getContentResolver(), |