| /* |
| * Copyright (C) 2013 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; |
| |
| import android.content.Context; |
| import android.os.Bundle; |
| import android.telephony.PhoneNumberUtils; |
| import android.util.ArrayMap; |
| import android.util.AttributeSet; |
| import android.view.ContextThemeWrapper; |
| import android.view.KeyEvent; |
| import android.view.LayoutInflater; |
| import android.view.View; |
| import android.view.View.OnClickListener; |
| import android.view.View.OnKeyListener; |
| import android.view.ViewGroup; |
| import android.widget.EditText; |
| import android.widget.LinearLayout; |
| import android.widget.TextView; |
| import com.android.dialer.common.LogUtil; |
| import com.android.dialer.dialpadview.DialpadKeyButton; |
| import com.android.dialer.dialpadview.DialpadKeyButton.OnPressedListener; |
| import com.android.dialer.dialpadview.DialpadView; |
| import com.android.dialer.logging.DialerImpression; |
| import com.android.dialer.logging.Logger; |
| import com.android.incallui.DialpadPresenter.DialpadUi; |
| import com.android.incallui.baseui.BaseFragment; |
| import java.util.Map; |
| |
| /** Fragment for call control buttons */ |
| public class DialpadFragment extends BaseFragment<DialpadPresenter, DialpadUi> |
| implements DialpadUi, OnKeyListener, OnClickListener, OnPressedListener { |
| |
| /** Hash Map to map a view id to a character */ |
| private static final Map<Integer, Character> displayMap = new ArrayMap<>(); |
| |
| /** Set up the static maps */ |
| static { |
| // Map the buttons to the display characters |
| displayMap.put(R.id.one, '1'); |
| displayMap.put(R.id.two, '2'); |
| displayMap.put(R.id.three, '3'); |
| displayMap.put(R.id.four, '4'); |
| displayMap.put(R.id.five, '5'); |
| displayMap.put(R.id.six, '6'); |
| displayMap.put(R.id.seven, '7'); |
| displayMap.put(R.id.eight, '8'); |
| displayMap.put(R.id.nine, '9'); |
| displayMap.put(R.id.zero, '0'); |
| displayMap.put(R.id.pound, '#'); |
| displayMap.put(R.id.star, '*'); |
| } |
| |
| private final int[] buttonIds = |
| new int[] { |
| R.id.zero, |
| R.id.one, |
| R.id.two, |
| R.id.three, |
| R.id.four, |
| R.id.five, |
| R.id.six, |
| R.id.seven, |
| R.id.eight, |
| R.id.nine, |
| R.id.star, |
| R.id.pound |
| }; |
| private EditText dtmfDialerField; |
| // KeyListener used with the "dialpad digits" EditText widget. |
| private DtmfKeyListener dtmfKeyListener; |
| private DialpadView dialpadView; |
| private View endCallSpace; |
| private boolean shouldShowEndCallSpace = true; |
| |
| @Override |
| public void onClick(View v) { |
| if (v.getId() == R.id.dialpad_back) { |
| Logger.get(getContext()) |
| .logImpression(DialerImpression.Type.IN_CALL_DIALPAD_CLOSE_BUTTON_PRESSED); |
| getActivity().onBackPressed(); |
| } |
| } |
| |
| @Override |
| public boolean onKey(View v, int keyCode, KeyEvent event) { |
| Log.d(this, "onKey: keyCode " + keyCode + ", view " + v); |
| |
| if (keyCode == KeyEvent.KEYCODE_DPAD_CENTER || keyCode == KeyEvent.KEYCODE_ENTER) { |
| int viewId = v.getId(); |
| if (displayMap.containsKey(viewId)) { |
| switch (event.getAction()) { |
| case KeyEvent.ACTION_DOWN: |
| if (event.getRepeatCount() == 0) { |
| getPresenter().processDtmf(displayMap.get(viewId)); |
| } |
| break; |
| case KeyEvent.ACTION_UP: |
| getPresenter().stopDtmf(); |
| break; |
| default: // fall out |
| } |
| // do not return true [handled] here, since we want the |
| // press / click animation to be handled by the framework. |
| } |
| } |
| return false; |
| } |
| |
| @Override |
| public DialpadPresenter createPresenter() { |
| return new DialpadPresenter(); |
| } |
| |
| @Override |
| public DialpadPresenter.DialpadUi getUi() { |
| return this; |
| } |
| |
| // TODO(klp) Adds hardware keyboard listener |
| |
| @Override |
| public View onCreateView( |
| LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { |
| Context contextThemeWrapper = new ContextThemeWrapper(getActivity(), R.style.Dialer_ThemeBase); |
| LayoutInflater layoutInflater = inflater.cloneInContext(contextThemeWrapper); |
| final View parent = layoutInflater.inflate(R.layout.incall_dialpad_fragment, container, false); |
| dialpadView = (DialpadView) parent.findViewById(R.id.dialpad_view); |
| dialpadView.setCanDigitsBeEdited(false); |
| dtmfDialerField = (EditText) parent.findViewById(R.id.digits); |
| if (dtmfDialerField != null) { |
| LogUtil.i("DialpadFragment.onCreateView", "creating dtmfKeyListener"); |
| dtmfKeyListener = new DtmfKeyListener(getPresenter()); |
| dtmfDialerField.setKeyListener(dtmfKeyListener); |
| // remove the long-press context menus that support |
| // the edit (copy / paste / select) functions. |
| dtmfDialerField.setLongClickable(false); |
| dtmfDialerField.setElegantTextHeight(false); |
| configureKeypadListeners(); |
| } |
| View backButton = dialpadView.findViewById(R.id.dialpad_back); |
| backButton.setVisibility(View.VISIBLE); |
| backButton.setOnClickListener(this); |
| endCallSpace = dialpadView.findViewById(R.id.end_call_space); |
| |
| return parent; |
| } |
| |
| @Override |
| public void onResume() { |
| super.onResume(); |
| endCallSpace.setVisibility(shouldShowEndCallSpace ? View.VISIBLE : View.GONE); |
| } |
| |
| @Override |
| public void onDestroyView() { |
| dtmfKeyListener = null; |
| super.onDestroyView(); |
| } |
| |
| /** |
| * Getter for Dialpad text. |
| * |
| * @return String containing current Dialpad EditText text. |
| */ |
| public String getDtmfText() { |
| return dtmfDialerField.getText().toString(); |
| } |
| |
| /** |
| * Sets the Dialpad text field with some text. |
| * |
| * @param text Text to set Dialpad EditText to. |
| */ |
| public void setDtmfText(String text) { |
| dtmfDialerField.setText(PhoneNumberUtils.createTtsSpannable(text)); |
| } |
| |
| /** Starts the slide up animation for the Dialpad keys when the Dialpad is revealed. */ |
| public void animateShowDialpad() { |
| final DialpadView dialpadView = (DialpadView) getView().findViewById(R.id.dialpad_view); |
| dialpadView.animateShow(); |
| } |
| |
| @Override |
| public void appendDigitsToField(char digit) { |
| if (dtmfDialerField != null) { |
| // TODO: maybe *don't* manually append this digit if |
| // mDialpadDigits is focused and this key came from the HW |
| // keyboard, since in that case the EditText field will |
| // get the key event directly and automatically appends |
| // whetever the user types. |
| // (Or, a cleaner fix would be to just make mDialpadDigits |
| // *not* handle HW key presses. That seems to be more |
| // complicated than just setting focusable="false" on it, |
| // though.) |
| dtmfDialerField.getText().append(digit); |
| } |
| } |
| |
| /** Called externally (from InCallScreen) to play a DTMF Tone. */ |
| /* package */ boolean onDialerKeyDown(KeyEvent event) { |
| Log.d(this, "Notifying dtmf key down."); |
| if (dtmfKeyListener != null) { |
| return dtmfKeyListener.onKeyDown(event); |
| } else { |
| return false; |
| } |
| } |
| |
| /** Called externally (from InCallScreen) to cancel the last DTMF Tone played. */ |
| public boolean onDialerKeyUp(KeyEvent event) { |
| Log.d(this, "Notifying dtmf key up."); |
| if (dtmfKeyListener != null) { |
| return dtmfKeyListener.onKeyUp(event); |
| } else { |
| return false; |
| } |
| } |
| |
| private void configureKeypadListeners() { |
| DialpadKeyButton dialpadKey; |
| for (int i = 0; i < buttonIds.length; i++) { |
| dialpadKey = (DialpadKeyButton) dialpadView.findViewById(buttonIds[i]); |
| dialpadKey.setOnKeyListener(this); |
| dialpadKey.setOnClickListener(this); |
| dialpadKey.setOnPressedListener(this); |
| } |
| } |
| |
| @Override |
| public void onPressed(View view, boolean pressed) { |
| if (pressed && displayMap.containsKey(view.getId())) { |
| Logger.get(getContext()) |
| .logImpression(DialerImpression.Type.IN_CALL_DIALPAD_NUMBER_BUTTON_PRESSED); |
| Log.d(this, "onPressed: " + pressed + " " + displayMap.get(view.getId())); |
| getPresenter().processDtmf(displayMap.get(view.getId())); |
| } |
| if (!pressed) { |
| Log.d(this, "onPressed: " + pressed); |
| getPresenter().stopDtmf(); |
| } |
| } |
| |
| public void setShouldShowEndCallSpace(boolean show) { |
| shouldShowEndCallSpace = show; |
| } |
| |
| /** |
| * LinearLayout with getter and setter methods for the translationY property using floats, for |
| * animation purposes. |
| */ |
| public static class DialpadSlidingLinearLayout extends LinearLayout { |
| |
| public DialpadSlidingLinearLayout(Context context) { |
| super(context); |
| } |
| |
| public DialpadSlidingLinearLayout(Context context, AttributeSet attrs) { |
| super(context, attrs); |
| } |
| |
| public DialpadSlidingLinearLayout(Context context, AttributeSet attrs, int defStyle) { |
| super(context, attrs, defStyle); |
| } |
| |
| public float getYFraction() { |
| final int height = getHeight(); |
| if (height == 0) { |
| return 0; |
| } |
| return getTranslationY() / height; |
| } |
| |
| public void setYFraction(float yFraction) { |
| setTranslationY(yFraction * getHeight()); |
| } |
| } |
| } |