CallButtonFragment.java revision 39fed851cc58faa469b98943dd93df0c1ee7bcea
1/*
2 * Copyright (C) 2013 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
17package com.android.incallui;
18
19import android.content.Context;
20import android.graphics.drawable.LayerDrawable;
21import android.os.Bundle;
22import android.telecomm.AudioState;
23import android.view.ContextThemeWrapper;
24import android.view.LayoutInflater;
25import android.view.Menu;
26import android.view.MenuItem;
27import android.view.View;
28import android.view.ViewGroup;
29import android.view.accessibility.AccessibilityEvent;
30import android.view.accessibility.AccessibilityManager;
31import android.widget.CompoundButton;
32import android.widget.ImageButton;
33import android.widget.PopupMenu;
34import android.widget.PopupMenu.OnDismissListener;
35import android.widget.PopupMenu.OnMenuItemClickListener;
36
37/**
38 * Fragment for call control buttons
39 */
40public class CallButtonFragment
41        extends BaseFragment<CallButtonPresenter, CallButtonPresenter.CallButtonUi>
42        implements CallButtonPresenter.CallButtonUi, OnMenuItemClickListener, OnDismissListener,
43        View.OnClickListener, CompoundButton.OnCheckedChangeListener {
44
45    private ImageButton mAudioButton;
46    private ImageButton mChangeToVoiceButton;
47    private ImageButton mMuteButton;
48    private ImageButton mShowDialpadButton;
49    private ImageButton mHoldButton;
50    private ImageButton mSwapButton;
51    private ImageButton mChangeToVideoButton;
52    private ImageButton mSwitchCameraButton;
53    private ImageButton mAddCallButton;
54    private ImageButton mMergeButton;
55    private ImageButton mPauseVideoButton;
56    private ImageButton mOverflowButton;
57
58    private PopupMenu mAudioModePopup;
59    private boolean mAudioModePopupVisible;
60    private PopupMenu mOverflowPopup;
61
62    private int mPrevAudioMode = 0;
63
64    // Constants for Drawable.setAlpha()
65    private static final int HIDDEN = 0;
66    private static final int VISIBLE = 255;
67
68    private boolean mIsEnabled;
69
70    @Override
71    CallButtonPresenter createPresenter() {
72        // TODO: find a cleaner way to include audio mode provider than having a singleton instance.
73        return new CallButtonPresenter();
74    }
75
76    @Override
77    CallButtonPresenter.CallButtonUi getUi() {
78        return this;
79    }
80
81    @Override
82    public void onCreate(Bundle savedInstanceState) {
83        super.onCreate(savedInstanceState);
84    }
85
86    @Override
87    public View onCreateView(LayoutInflater inflater, ViewGroup container,
88            Bundle savedInstanceState) {
89        final View parent = inflater.inflate(R.layout.call_button_fragment, container, false);
90
91        mAudioButton = (ImageButton) parent.findViewById(R.id.audioButton);
92        mAudioButton.setOnClickListener(this);
93        mChangeToVoiceButton = (ImageButton) parent.findViewById(R.id.changeToVoiceButton);
94        mChangeToVoiceButton. setOnClickListener(this);
95        mMuteButton = (ImageButton) parent.findViewById(R.id.muteButton);
96        mMuteButton.setOnClickListener(this);
97        mShowDialpadButton = (ImageButton) parent.findViewById(R.id.dialpadButton);
98        mShowDialpadButton.setOnClickListener(this);
99        mHoldButton = (ImageButton) parent.findViewById(R.id.holdButton);
100        mHoldButton.setOnClickListener(this);
101        mSwapButton = (ImageButton) parent.findViewById(R.id.swapButton);
102        mSwapButton.setOnClickListener(this);
103        mChangeToVideoButton = (ImageButton) parent.findViewById(R.id.changeToVideoButton);
104        mChangeToVideoButton.setOnClickListener(this);
105        mSwitchCameraButton = (ImageButton) parent.findViewById(R.id.switchCameraButton);
106        mSwitchCameraButton.setOnClickListener(this);
107        mAddCallButton = (ImageButton) parent.findViewById(R.id.addButton);
108        mAddCallButton.setOnClickListener(this);
109        mMergeButton = (ImageButton) parent.findViewById(R.id.mergeButton);
110        mMergeButton.setOnClickListener(this);
111        mPauseVideoButton = (ImageButton) parent.findViewById(R.id.pauseVideoButton);
112        mPauseVideoButton.setOnClickListener(this);
113        mOverflowButton = (ImageButton) parent.findViewById(R.id.overflowButton);
114        mOverflowButton.setOnClickListener(this);
115
116        return parent;
117    }
118
119    @Override
120    public void onActivityCreated(Bundle savedInstanceState) {
121        super.onActivityCreated(savedInstanceState);
122
123        // set the buttons
124        updateAudioButtons(getPresenter().getSupportedAudio());
125    }
126
127    @Override
128    public void onResume() {
129        if (getPresenter() != null) {
130            getPresenter().refreshMuteState();
131        }
132        super.onResume();
133    }
134
135    @Override
136    public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
137    }
138
139    @Override
140    public void onClick(View view) {
141        int id = view.getId();
142        Log.d(this, "onClick(View " + view + ", id " + id + ")...");
143
144        switch(id) {
145            case R.id.audioButton:
146                onAudioButtonClicked();
147                break;
148            case R.id.addButton:
149                getPresenter().addCallClicked();
150                break;
151            case R.id.changeToVoiceButton:
152                getPresenter().changeToVoiceClicked();
153                break;
154            case R.id.muteButton: {
155                final ImageButton button = (ImageButton) view;
156                getPresenter().muteClicked(!button.isSelected());
157                break;
158            }
159            case R.id.mergeButton:
160                getPresenter().mergeClicked();
161                break;
162            case R.id.holdButton: {
163                final ImageButton button = (ImageButton) view;
164                getPresenter().holdClicked(!button.isSelected());
165                break;
166            }
167            case R.id.swapButton:
168                getPresenter().holdClicked(true /* checked */);
169                break;
170            case R.id.dialpadButton:
171                getPresenter().showDialpadClicked(!mShowDialpadButton.isSelected());
172                break;
173            case R.id.changeToVideoButton:
174                getPresenter().changeToVideoClicked();
175                break;
176            case R.id.switchCameraButton:
177                getPresenter().switchCameraClicked(
178                        mSwitchCameraButton.isSelected() /* useFrontFacingCamera */);
179                break;
180            case R.id.pauseVideoButton:
181                getPresenter().pauseVideoClicked(
182                        !mPauseVideoButton.isSelected() /* pause */);
183                break;
184            case R.id.overflowButton:
185                mOverflowPopup.show();
186                break;
187            default:
188                Log.wtf(this, "onClick: unexpected");
189                break;
190        }
191    }
192
193    @Override
194    public void setEnabled(boolean isEnabled) {
195        mIsEnabled = isEnabled;
196        View view = getView();
197        if (view.getVisibility() != View.VISIBLE) {
198            view.setVisibility(View.VISIBLE);
199        }
200
201        mAudioButton.setEnabled(isEnabled);
202        mChangeToVoiceButton.setEnabled(isEnabled);
203        mMuteButton.setEnabled(isEnabled);
204        mShowDialpadButton.setEnabled(isEnabled);
205        mHoldButton.setEnabled(isEnabled);
206        mSwapButton.setEnabled(isEnabled);
207        mChangeToVideoButton.setEnabled(isEnabled);
208        mSwitchCameraButton.setEnabled(isEnabled);
209        mAddCallButton.setEnabled(isEnabled);
210        mMergeButton.setEnabled(isEnabled);
211        mPauseVideoButton.setEnabled(isEnabled);
212        mOverflowButton.setEnabled(isEnabled);
213    }
214
215    @Override
216    public void setMute(boolean value) {
217        if (mMuteButton.isSelected() != value) {
218            mMuteButton.setSelected(value);
219            maybeSendAccessibilityEvent(mMuteButton, value ? R.string.accessibility_call_muted
220                    : R.string.accessibility_call_unmuted);
221        }
222    }
223
224    @Override
225    public void showAudioButton(boolean show) {
226        mAudioButton.setVisibility(show ? View.VISIBLE : View.GONE);
227    }
228
229    @Override
230    public void showChangeToVoiceButton(boolean show) {
231        mChangeToVoiceButton.setVisibility(show ? View.VISIBLE : View.GONE);
232    }
233
234    @Override
235    public void enableMute(boolean enabled) {
236        mMuteButton.setEnabled(enabled);
237    }
238
239    @Override
240    public void showDialpadButton(boolean show) {
241        mShowDialpadButton.setVisibility(show ? View.VISIBLE : View.GONE);
242    }
243
244    @Override
245    public void setHold(boolean value) {
246        if (mHoldButton.isSelected() != value) {
247            mHoldButton.setSelected(value);
248            maybeSendAccessibilityEvent(mHoldButton,
249                    value ? R.string.accessibility_call_put_on_hold :
250                            R.string.accessibility_call_removed_from_hold);
251        }
252    }
253
254    @Override
255    public void showHoldButton(boolean show) {
256        mHoldButton.setVisibility(show ? View.VISIBLE : View.GONE);
257    }
258
259    @Override
260    public void enableHold(boolean enabled) {
261        mHoldButton.setEnabled(enabled);
262    }
263
264    @Override
265    public void showSwapButton(boolean show) {
266        mSwapButton.setVisibility(show ? View.VISIBLE : View.GONE);
267    }
268
269    @Override
270    public void showChangeToVideoButton(boolean show) {
271        mChangeToVideoButton.setVisibility(show ? View.VISIBLE : View.GONE);
272    }
273
274    @Override
275    public void showSwitchCameraButton(boolean show) {
276        mSwitchCameraButton.setVisibility(show ? View.VISIBLE : View.GONE);
277    }
278
279    @Override
280    public void setSwitchCameraButton(boolean isBackFacingCamera) {
281        mSwitchCameraButton.setSelected(isBackFacingCamera);
282    }
283
284    @Override
285    public void showAddCallButton(boolean show) {
286        Log.d(this, "show Add call button: " + show);
287        mAddCallButton.setVisibility(show ? View.VISIBLE : View.GONE);
288    }
289
290    @Override
291    public void enableAddCall(boolean enabled) {
292        mAddCallButton.setEnabled(enabled);
293    }
294
295    @Override
296    public void showMergeButton(boolean show) {
297        mMergeButton.setVisibility(show ? View.VISIBLE : View.GONE);
298    }
299
300    @Override
301    public void showPauseVideoButton(boolean show) {
302        mPauseVideoButton.setVisibility(show ? View.VISIBLE : View.GONE);
303    }
304
305    @Override
306    public void setPauseVideoButton(boolean isPaused) {
307        mPauseVideoButton.setSelected(isPaused);
308    }
309
310    @Override
311    public void showOverflowButton(boolean show) {
312        mOverflowButton.setVisibility(show ? View.VISIBLE : View.GONE);
313    }
314
315    @Override
316    public void configureOverflowMenu(boolean showMergeMenuOption, boolean showAddMenuOption,
317            boolean showHoldMenuOption, boolean showSwapMenuOption) {
318        if (mOverflowPopup == null) {
319            final ContextThemeWrapper contextWrapper = new ContextThemeWrapper(getActivity(),
320                    R.style.InCallPopupMenuStyle);
321            mOverflowPopup = new PopupMenu(contextWrapper, mOverflowButton);
322            mOverflowPopup.getMenuInflater().inflate(R.menu.incall_overflow_menu,
323                    mOverflowPopup.getMenu());
324            mOverflowPopup.setOnMenuItemClickListener(new OnMenuItemClickListener() {
325                @Override
326                public boolean onMenuItemClick(MenuItem item) {
327                    switch (item.getItemId()) {
328                        case R.id.overflow_merge_menu_item:
329                            getPresenter().mergeClicked();
330                            break;
331                        case R.id.overflow_add_menu_item:
332                            getPresenter().addCallClicked();
333                            break;
334                        case R.id.overflow_hold_menu_item:
335                            getPresenter().holdClicked(true /* checked */);
336                            break;
337                        case R.id.overflow_resume_menu_item:
338                            getPresenter().holdClicked(false /* checked */);
339                            break;
340                        case R.id.overflow_swap_menu_item:
341                            getPresenter().addCallClicked();
342                            break;
343                        default:
344                            Log.wtf(this, "onMenuItemClick: unexpected overflow menu click");
345                            break;
346                    }
347                    return true;
348                }
349            });
350            mOverflowPopup.setOnDismissListener(new OnDismissListener() {
351                @Override
352                public void onDismiss(PopupMenu popupMenu) {
353                    popupMenu.dismiss();
354                }
355            });
356        }
357
358        final Menu menu = mOverflowPopup.getMenu();
359        menu.findItem(R.id.overflow_merge_menu_item).setVisible(showMergeMenuOption);
360        menu.findItem(R.id.overflow_add_menu_item).setVisible(showAddMenuOption);
361        menu.findItem(R.id.overflow_hold_menu_item).setVisible(
362                showHoldMenuOption && !mHoldButton.isSelected());
363        menu.findItem(R.id.overflow_resume_menu_item).setVisible(
364                showHoldMenuOption && mHoldButton.isSelected());
365        menu.findItem(R.id.overflow_swap_menu_item).setVisible(showSwapMenuOption);
366
367        mOverflowButton.setEnabled(menu.hasVisibleItems());
368    }
369
370    @Override
371    public void setAudio(int mode) {
372        updateAudioButtons(getPresenter().getSupportedAudio());
373        refreshAudioModePopup();
374
375        if (mPrevAudioMode != mode) {
376            if (mPrevAudioMode != 0) {
377                int stringId = 0;
378                switch (mode) {
379                    case AudioState.ROUTE_EARPIECE:
380                        stringId = R.string.accessibility_earpiece_selected;
381                        break;
382                    case AudioState.ROUTE_BLUETOOTH:
383                        stringId = R.string.accessibility_bluetooth_headset_selected;
384                        break;
385                    case AudioState.ROUTE_WIRED_HEADSET:
386                        stringId = R.string.accessibility_wired_headset_selected;
387                        break;
388                    case AudioState.ROUTE_SPEAKER:
389                        stringId = R.string.accessibility_speakerphone_selected;
390                        break;
391                }
392                if (stringId != 0) {
393                    maybeSendAccessibilityEvent(mAudioButton, stringId);
394                }
395            }
396            mPrevAudioMode = mode;
397        }
398    }
399
400    @Override
401    public void setSupportedAudio(int modeMask) {
402        updateAudioButtons(modeMask);
403        refreshAudioModePopup();
404    }
405
406    @Override
407    public boolean onMenuItemClick(MenuItem item) {
408        Log.d(this, "- onMenuItemClick: " + item);
409        Log.d(this, "  id: " + item.getItemId());
410        Log.d(this, "  title: '" + item.getTitle() + "'");
411
412        int mode = AudioState.ROUTE_WIRED_OR_EARPIECE;
413
414        switch (item.getItemId()) {
415            case R.id.audio_mode_speaker:
416                mode = AudioState.ROUTE_SPEAKER;
417                break;
418            case R.id.audio_mode_earpiece:
419            case R.id.audio_mode_wired_headset:
420                // InCallAudioState.ROUTE_EARPIECE means either the handset earpiece,
421                // or the wired headset (if connected.)
422                mode = AudioState.ROUTE_WIRED_OR_EARPIECE;
423                break;
424            case R.id.audio_mode_bluetooth:
425                mode = AudioState.ROUTE_BLUETOOTH;
426                break;
427            default:
428                Log.e(this, "onMenuItemClick:  unexpected View ID " + item.getItemId()
429                        + " (MenuItem = '" + item + "')");
430                break;
431        }
432
433        getPresenter().setAudioMode(mode);
434
435        return true;
436    }
437
438    // PopupMenu.OnDismissListener implementation; see showAudioModePopup().
439    // This gets called when the PopupMenu gets dismissed for *any* reason, like
440    // the user tapping outside its bounds, or pressing Back, or selecting one
441    // of the menu items.
442    @Override
443    public void onDismiss(PopupMenu menu) {
444        Log.d(this, "- onDismiss: " + menu);
445        mAudioModePopupVisible = false;
446    }
447
448    /**
449     * Checks for supporting modes.  If bluetooth is supported, it uses the audio
450     * pop up menu.  Otherwise, it toggles the speakerphone.
451     */
452    private void onAudioButtonClicked() {
453        Log.d(this, "onAudioButtonClicked: " +
454                AudioState.audioRouteToString(getPresenter().getSupportedAudio()));
455
456        if (isSupported(AudioState.ROUTE_BLUETOOTH)) {
457            showAudioModePopup();
458        } else {
459            getPresenter().toggleSpeakerphone();
460        }
461    }
462
463    /**
464     * Refreshes the "Audio mode" popup if it's visible.  This is useful
465     * (for example) when a wired headset is plugged or unplugged,
466     * since we need to switch back and forth between the "earpiece"
467     * and "wired headset" items.
468     *
469     * This is safe to call even if the popup is already dismissed, or even if
470     * you never called showAudioModePopup() in the first place.
471     */
472    public void refreshAudioModePopup() {
473        if (mAudioModePopup != null && mAudioModePopupVisible) {
474            // Dismiss the previous one
475            mAudioModePopup.dismiss();  // safe even if already dismissed
476            // And bring up a fresh PopupMenu
477            showAudioModePopup();
478        }
479    }
480
481    /**
482     * Updates the audio button so that the appriopriate visual layers
483     * are visible based on the supported audio formats.
484     */
485    private void updateAudioButtons(int supportedModes) {
486        final boolean bluetoothSupported = isSupported(AudioState.ROUTE_BLUETOOTH);
487        final boolean speakerSupported = isSupported(AudioState.ROUTE_SPEAKER);
488
489        boolean audioButtonEnabled = false;
490        boolean audioButtonChecked = false;
491        boolean showMoreIndicator = false;
492
493        boolean showBluetoothIcon = false;
494        boolean showSpeakerphoneIcon = false;
495        boolean showHandsetIcon = false;
496
497        boolean showToggleIndicator = false;
498
499        if (bluetoothSupported) {
500            Log.d(this, "updateAudioButtons - popup menu mode");
501
502            audioButtonEnabled = true;
503            showMoreIndicator = true;
504            // The audio button is NOT a toggle in this state.  (And its
505            // setChecked() state is irrelevant since we completely hide the
506            // btn_compound_background layer anyway.)
507
508            // Update desired layers:
509            if (isAudio(AudioState.ROUTE_BLUETOOTH)) {
510                showBluetoothIcon = true;
511            } else if (isAudio(AudioState.ROUTE_SPEAKER)) {
512                showSpeakerphoneIcon = true;
513            } else {
514                showHandsetIcon = true;
515                // TODO: if a wired headset is plugged in, that takes precedence
516                // over the handset earpiece.  If so, maybe we should show some
517                // sort of "wired headset" icon here instead of the "handset
518                // earpiece" icon.  (Still need an asset for that, though.)
519            }
520        } else if (speakerSupported) {
521            Log.d(this, "updateAudioButtons - speaker toggle mode");
522
523            audioButtonEnabled = true;
524
525            // The audio button *is* a toggle in this state, and indicated the
526            // current state of the speakerphone.
527            audioButtonChecked = isAudio(AudioState.ROUTE_SPEAKER);
528
529            // update desired layers:
530            showToggleIndicator = true;
531            showSpeakerphoneIcon = true;
532        } else {
533            Log.d(this, "updateAudioButtons - disabled...");
534
535            // The audio button is a toggle in this state, but that's mostly
536            // irrelevant since it's always disabled and unchecked.
537            audioButtonEnabled = false;
538            audioButtonChecked = false;
539
540            // update desired layers:
541            showToggleIndicator = true;
542            showSpeakerphoneIcon = true;
543        }
544
545        // Finally, update it all!
546
547        Log.v(this, "audioButtonEnabled: " + audioButtonEnabled);
548        Log.v(this, "audioButtonChecked: " + audioButtonChecked);
549        Log.v(this, "showMoreIndicator: " + showMoreIndicator);
550        Log.v(this, "showBluetoothIcon: " + showBluetoothIcon);
551        Log.v(this, "showSpeakerphoneIcon: " + showSpeakerphoneIcon);
552        Log.v(this, "showHandsetIcon: " + showHandsetIcon);
553
554        // Only enable the audio button if the fragment is enabled.
555        mAudioButton.setEnabled(audioButtonEnabled && mIsEnabled);
556        mAudioButton.setSelected(audioButtonChecked);
557
558        final LayerDrawable layers = (LayerDrawable) mAudioButton.getBackground();
559        Log.d(this, "'layers' drawable: " + layers);
560
561        layers.findDrawableByLayerId(R.id.compoundBackgroundItem)
562                .setAlpha(showToggleIndicator ? VISIBLE : HIDDEN);
563
564        layers.findDrawableByLayerId(R.id.moreIndicatorItem)
565                .setAlpha(showMoreIndicator ? VISIBLE : HIDDEN);
566
567        layers.findDrawableByLayerId(R.id.bluetoothItem)
568                .setAlpha(showBluetoothIcon ? VISIBLE : HIDDEN);
569
570        layers.findDrawableByLayerId(R.id.handsetItem)
571                .setAlpha(showHandsetIcon ? VISIBLE : HIDDEN);
572
573        layers.findDrawableByLayerId(R.id.speakerphoneItem)
574                .setAlpha(showSpeakerphoneIcon ? VISIBLE : HIDDEN);
575
576    }
577
578    private void showAudioModePopup() {
579        Log.d(this, "showAudioPopup()...");
580
581        final ContextThemeWrapper contextWrapper = new ContextThemeWrapper(getActivity(),
582                R.style.InCallPopupMenuStyle);
583        mAudioModePopup = new PopupMenu(contextWrapper, mAudioButton /* anchorView */);
584        mAudioModePopup.getMenuInflater().inflate(R.menu.incall_audio_mode_menu,
585                mAudioModePopup.getMenu());
586        mAudioModePopup.setOnMenuItemClickListener(this);
587        mAudioModePopup.setOnDismissListener(this);
588
589        final Menu menu = mAudioModePopup.getMenu();
590
591        // TODO: Still need to have the "currently active" audio mode come
592        // up pre-selected (or focused?) with a blue highlight.  Still
593        // need exact visual design, and possibly framework support for this.
594        // See comments below for the exact logic.
595
596        final MenuItem speakerItem = menu.findItem(R.id.audio_mode_speaker);
597        speakerItem.setEnabled(isSupported(AudioState.ROUTE_SPEAKER));
598        // TODO: Show speakerItem as initially "selected" if
599        // speaker is on.
600
601        // We display *either* "earpiece" or "wired headset", never both,
602        // depending on whether a wired headset is physically plugged in.
603        final MenuItem earpieceItem = menu.findItem(R.id.audio_mode_earpiece);
604        final MenuItem wiredHeadsetItem = menu.findItem(R.id.audio_mode_wired_headset);
605
606        final boolean usingHeadset = isSupported(AudioState.ROUTE_WIRED_HEADSET);
607        earpieceItem.setVisible(!usingHeadset);
608        earpieceItem.setEnabled(!usingHeadset);
609        wiredHeadsetItem.setVisible(usingHeadset);
610        wiredHeadsetItem.setEnabled(usingHeadset);
611        // TODO: Show the above item (either earpieceItem or wiredHeadsetItem)
612        // as initially "selected" if speakerOn and
613        // bluetoothIndicatorOn are both false.
614
615        final MenuItem bluetoothItem = menu.findItem(R.id.audio_mode_bluetooth);
616        bluetoothItem.setEnabled(isSupported(AudioState.ROUTE_BLUETOOTH));
617        // TODO: Show bluetoothItem as initially "selected" if
618        // bluetoothIndicatorOn is true.
619
620        mAudioModePopup.show();
621
622        // Unfortunately we need to manually keep track of the popup menu's
623        // visiblity, since PopupMenu doesn't have an isShowing() method like
624        // Dialogs do.
625        mAudioModePopupVisible = true;
626    }
627
628    private boolean isSupported(int mode) {
629        return (mode == (getPresenter().getSupportedAudio() & mode));
630    }
631
632    private boolean isAudio(int mode) {
633        return (mode == getPresenter().getAudioMode());
634    }
635
636    @Override
637    public void displayDialpad(boolean value, boolean animate) {
638        mShowDialpadButton.setSelected(value);
639        if (getActivity() != null && getActivity() instanceof InCallActivity) {
640            ((InCallActivity) getActivity()).displayDialpad(value, animate);
641        }
642    }
643
644    @Override
645    public boolean isDialpadVisible() {
646        if (getActivity() != null && getActivity() instanceof InCallActivity) {
647            return ((InCallActivity) getActivity()).isDialpadVisible();
648        }
649        return false;
650    }
651
652    @Override
653    public Context getContext() {
654        return getActivity();
655    }
656
657    private void maybeSendAccessibilityEvent(View view, int stringId) {
658        final Context context = getActivity();
659        AccessibilityManager manager =
660                (AccessibilityManager) context.getSystemService(Context.ACCESSIBILITY_SERVICE);
661        if (manager != null && manager.isEnabled()) {
662            AccessibilityEvent e = AccessibilityEvent.obtain();
663            e.setSource(view);
664            e.setEventType(AccessibilityEvent.TYPE_ANNOUNCEMENT);
665            e.setClassName(getClass().getName());
666            e.setPackageName(context.getPackageName());
667            e.getText().add(context.getResources().getString(stringId));
668            manager.sendAccessibilityEvent(e);
669        }
670    }
671}
672