Android Open Source - Matrix-Mate Number Picker






From Project

Back to project page Matrix-Mate.

License

The source code is released under:

MIT License

If you think the Android project Matrix-Mate listed in this page is inappropriate, such as containing malicious code/tools or violating the copyright, please email info at java2s dot com, thanks.

Java Source Code

/*
 * Copyright 2008 The Android Open Source Project
 * Copyright 2011-2012 Michael Novak <michael.novakjr@gmail.com>.
 */*ww w .  j  a v  a  2  s.  co  m*/
 * 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.RSen.MatrixMate;

import android.content.Context;
import android.content.res.TypedArray;
import android.os.Handler;
import android.text.InputFilter;
import android.text.InputType;
import android.text.Spanned;
import android.text.method.NumberKeyListener;
import android.util.AttributeSet;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.View.OnFocusChangeListener;
import android.view.View.OnLongClickListener;
import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.TextView.OnEditorActionListener;

/**
 * This class has been pulled from the Android platform source code, its an
 * internal widget that hasn't been made public so its included in the project
 * in this fashion for use with the preferences screen; I have made a few slight
 * modifications to the code here, I simply put a MAX and MIN default in the
 * code but these values can still be set publicly by calling code.
 * 
 * @author Google
 */
public class NumberPicker extends LinearLayout implements OnClickListener,
    OnEditorActionListener, OnFocusChangeListener, OnLongClickListener {

  private static final int DEFAULT_MAX = 20;
  private static final int DEFAULT_MIN = 1;
  private static final int DEFAULT_VALUE = 1;
  private static final boolean DEFAULT_WRAP = true;

  public interface OnChangedListener {
    void onChanged(NumberPicker picker, int oldVal, int newVal);
  }

  public interface Formatter {
    String toString(int value);
  }

  /*
   * Use a custom NumberPicker formatting callback to use two-digit minutes
   * strings like "01". Keeping a static formatter etc. is the most efficient
   * way to do this; it avoids creating temporary objects on every call to
   * format().
   */
  public static final NumberPicker.Formatter TWO_DIGIT_FORMATTER = new NumberPicker.Formatter() {
    final StringBuilder mBuilder = new StringBuilder();
    final java.util.Formatter mFmt = new java.util.Formatter(mBuilder);
    final Object[] mArgs = new Object[1];

    public String toString(int value) {
      mArgs[0] = value;
      mBuilder.delete(0, mBuilder.length());
      mFmt.format("%02d", mArgs);
      return mFmt.toString();
    }
  };

  private final Handler mHandler;
  private final Runnable mRunnable = new Runnable() {
    public void run() {
      if (mIncrement) {
        changeCurrent(mCurrent + 1);
        mHandler.postDelayed(this, mSpeed);
      } else if (mDecrement) {
        changeCurrent(mCurrent - 1);
        mHandler.postDelayed(this, mSpeed);
      }
    }
  };

  private final EditText mText;
  private final InputFilter mNumberInputFilter;

  private String[] mDisplayedValues;
  protected int mStart;
  protected int mEnd;
  protected int mCurrent;
  protected int mPrevious;
  protected OnChangedListener mListener;
  protected Formatter mFormatter;
  protected boolean mWrap;
  protected long mSpeed = 300;

  private boolean mIncrement;
  private boolean mDecrement;

  public NumberPicker(Context context) {
    this(context, null);
  }

  public NumberPicker(Context context, AttributeSet attrs) {
    this(context, attrs, 0);
  }

  public NumberPicker(Context context, AttributeSet attrs, int defStyle) {
    super(context, attrs);
    setOrientation(VERTICAL);
    LayoutInflater inflater = (LayoutInflater) context
        .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    inflater.inflate(R.layout.number_picker, this, true);
    mHandler = new Handler();
    InputFilter inputFilter = new NumberPickerInputFilter();
    mNumberInputFilter = new NumberRangeKeyListener();
    mIncrementButton = (NumberPickerButton) findViewById(R.id.increment);
    mIncrementButton.setOnClickListener(this);
    mIncrementButton.setOnLongClickListener(this);
    mIncrementButton.setNumberPicker(this);
    mDecrementButton = (NumberPickerButton) findViewById(R.id.decrement);
    mDecrementButton.setOnClickListener(this);
    mDecrementButton.setOnLongClickListener(this);
    mDecrementButton.setNumberPicker(this);

    mText = (EditText) findViewById(R.id.timepicker_input);
    mText.setOnFocusChangeListener(this);
    mText.setOnEditorActionListener(this);
    mText.setFilters(new InputFilter[] { inputFilter });
    mText.setRawInputType(InputType.TYPE_CLASS_NUMBER);

    if (!isEnabled()) {
      setEnabled(false);
    }

    TypedArray a = context.obtainStyledAttributes(attrs,
        R.styleable.numberpicker);
    mStart = a.getInt(R.styleable.numberpicker_startRange, DEFAULT_MIN);
    mEnd = a.getInt(R.styleable.numberpicker_endRange, DEFAULT_MAX);
    mWrap = a.getBoolean(R.styleable.numberpicker_wrap, DEFAULT_WRAP);
    mCurrent = a.getInt(R.styleable.numberpicker_defaultValue,
        DEFAULT_VALUE);
    mCurrent = Math.max(mStart, Math.min(mCurrent, mEnd));
    mText.setText("" + mCurrent);
  }

  @Override
  public void setEnabled(boolean enabled) {
    super.setEnabled(enabled);
    mIncrementButton.setEnabled(enabled);
    mDecrementButton.setEnabled(enabled);
    mText.setEnabled(enabled);
  }

  public void setOnChangeListener(OnChangedListener listener) {
    mListener = listener;
  }

  public void setFormatter(Formatter formatter) {
    mFormatter = formatter;
  }

  /**
   * Set the range of numbers allowed for the number picker. The current value
   * will be automatically set to the start.
   * 
   * @param start
   *            the start of the range (inclusive)
   * @param end
   *            the end of the range (inclusive)
   */
  public void setRange(int start, int end) {
    mStart = start;
    mEnd = end;
    mCurrent = start;
    updateView();
  }

  /**
   * Specify if numbers should wrap after the edge has been reached.
   * 
   * @param wrap
   *            values
   */
  public void setWrap(boolean wrap) {
    mWrap = wrap;
  }

  /**
   * Set the range of numbers allowed for the number picker. The current value
   * will be automatically set to the start. Also provide a mapping for values
   * used to display to the user.
   * 
   * @param start
   *            the start of the range (inclusive)
   * @param end
   *            the end of the range (inclusive)
   * @param displayedValues
   *            the values displayed to the user.
   */
  public void setRange(int start, int end, String[] displayedValues) {
    mDisplayedValues = displayedValues;
    mStart = start;
    mEnd = end;
    mCurrent = start;
    updateView();
  }

  public void setCurrent(int current) {
    if (mEnd < current)
      throw new IllegalArgumentException(
          "Current value cannot be greater than the range end.");

    mCurrent = current;
    updateView();
  }

  public void setCurrentAndNotify(int current) {
    mCurrent = current;
    notifyChange();
    updateView();
  }

  /**
   * The speed (in milliseconds) at which the numbers will scroll when the the
   * +/- buttons are longpressed. Default is 300ms.
   */
  public void setSpeed(long speed) {
    mSpeed = speed;
  }

  public void onClick(View v) {
    validateInput(mText);
    if (!mText.hasFocus())
      mText.requestFocus();

    // now perform the increment/decrement
    if (R.id.increment == v.getId()) {
      changeCurrent(mCurrent + 1);
    } else if (R.id.decrement == v.getId()) {
      changeCurrent(mCurrent - 1);
    }
  }

  protected String formatNumber(int value) {
    return (mFormatter != null) ? mFormatter.toString(value) : String
        .valueOf(value);
  }

  protected void changeCurrent(int current) {
    // Wrap around the values if we go past the start or end
    if (current > mEnd) {
      current = mWrap ? mStart : mEnd;
    } else if (current < mStart) {
      current = mWrap ? mEnd : mStart;
    }
    mPrevious = mCurrent;
    mCurrent = current;

    notifyChange();
    updateView();
  }

  protected void notifyChange() {
    if (mListener != null) {
      mListener.onChanged(this, mPrevious, mCurrent);
    }
  }

  protected void updateView() {

    /*
     * If we don't have displayed values then use the current number else
     * find the correct value in the displayed values for the current
     * number.
     */
    if (mDisplayedValues == null) {
      mText.setText(formatNumber(mCurrent));
    } else {
      mText.setText(mDisplayedValues[mCurrent - mStart]);
    }
    mText.setSelection(mText.getText().length());
  }

  private void validateCurrentView(CharSequence str) {
    int val = getSelectedPos(str.toString());
    if ((val >= mStart) && (val <= mEnd)) {
      if (mCurrent != val) {
        mPrevious = mCurrent;
        mCurrent = val;
        notifyChange();
      }
    }
    updateView();
  }

  public void onFocusChange(View v, boolean hasFocus) {

    /*
     * When focus is lost check that the text field has valid values.
     */
    if (!hasFocus) {
      validateInput(v);
    }
  }

  @Override
  public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
    if (v == mText) {
      validateInput(v);
      // Don't return true, let Android handle the soft keyboard
    }
    return false;
  }

  private void validateInput(View v) {
    String str = String.valueOf(((TextView) v).getText());
    if ("".equals(str)) {

      // Restore to the old value as we don't allow empty values
      updateView();
    } else {

      // Check the new value and ensure it's in range
      validateCurrentView(str);
    }
  }

  /**
   * We start the long click here but rely on the {@link NumberPickerButton}
   * to inform us when the long click has ended.
   */
  public boolean onLongClick(View v) {

    /*
     * The text view may still have focus so clear it's focus which will
     * trigger the on focus changed and any typed values to be pulled.
     */
    mText.clearFocus();
    mText.requestFocus();
    if (R.id.increment == v.getId()) {
      mIncrement = true;
      mHandler.post(mRunnable);
    } else if (R.id.decrement == v.getId()) {
      mDecrement = true;
      mHandler.post(mRunnable);
    }

    return true;
  }

  public void cancelIncrement() {
    mIncrement = false;
  }

  public void cancelDecrement() {
    mDecrement = false;
  }

  private static final char[] DIGIT_CHARACTERS = new char[] { '0', '1', '2',
      '3', '4', '5', '6', '7', '8', '9' };

  private NumberPickerButton mIncrementButton;
  private NumberPickerButton mDecrementButton;

  private class NumberPickerInputFilter implements InputFilter {
    public CharSequence filter(CharSequence source, int start, int end,
        Spanned dest, int dstart, int dend) {
      if (mDisplayedValues == null) {
        return mNumberInputFilter.filter(source, start, end, dest,
            dstart, dend);
      }
      CharSequence filtered = String.valueOf(source.subSequence(start,
          end));
      String result = String.valueOf(dest.subSequence(0, dstart))
          + filtered + dest.subSequence(dend, dest.length());
      String str = String.valueOf(result).toLowerCase();
      for (String val : mDisplayedValues) {
        val = val.toLowerCase();
        if (val.startsWith(str)) {
          return filtered;
        }
      }
      return "";
    }
  }

  private class NumberRangeKeyListener extends NumberKeyListener {

    // XXX This doesn't allow for range limits when controlled by a
    // soft input method!
    public int getInputType() {
      return InputType.TYPE_CLASS_NUMBER;
    }

    @Override
    protected char[] getAcceptedChars() {
      return DIGIT_CHARACTERS;
    }

    @Override
    public CharSequence filter(CharSequence source, int start, int end,
        Spanned dest, int dstart, int dend) {

      CharSequence filtered = super.filter(source, start, end, dest,
          dstart, dend);
      if (filtered == null) {
        filtered = source.subSequence(start, end);
      }

      String result = String.valueOf(dest.subSequence(0, dstart))
          + filtered + dest.subSequence(dend, dest.length());

      if ("".equals(result)) {
        return result;
      }
      int val = getSelectedPos(result);

      /*
       * Ensure the user can't type in a value greater than the max
       * allowed. We have to allow less than min as the user might want to
       * delete some numbers and then type a new number.
       */
      if (val > mEnd) {
        return "";
      } else {
        return filtered;
      }
    }
  }

  private int getSelectedPos(String str) {
    if (mDisplayedValues == null) {
      return Integer.parseInt(str);
    } else {
      for (int i = 0; i < mDisplayedValues.length; i++) {

        /* Don't force the user to type in jan when ja will do */
        str = str.toLowerCase();
        if (mDisplayedValues[i].toLowerCase().startsWith(str)) {
          return mStart + i;
        }
      }

      /*
       * The user might have typed in a number into the month field i.e.
       * 10 instead of OCT so support that too.
       */
      try {
        return Integer.parseInt(str);
      } catch (NumberFormatException e) {

        /* Ignore as if it's not a number we don't care */
      }
    }
    return mStart;
  }

  /**
   * @return the current value.
   */
  public int getCurrent() {
    return mCurrent;
  }
}




Java Source Code List

com.RSen.MatrixMate.GmailSender.java
com.RSen.MatrixMate.JSSEProvider.java
com.RSen.MatrixMate.MainSearchLayout.java
com.RSen.MatrixMate.ManipulateActivity.java
com.RSen.MatrixMate.MatrixMateActivity.java
com.RSen.MatrixMate.NumberPickerButton.java
com.RSen.MatrixMate.NumberPickerDialog.java
com.RSen.MatrixMate.NumberPickerPreference.java
com.RSen.MatrixMate.NumberPicker.java
com.RSen.MatrixMate.ReportDialog.java
com.RSen.MatrixMate.SimpleEula.java