How to reset data of NumberPicker - android

I am using two NumberPickers to display province(mProvincePicker) and city(mCityPicker) data in my app. When user changes province data, city data should be changed accordingly. I reset the mCityPicker data in NumberPicker.onValueChange(NumberPicker picker, int oldVal, int newVal). But it does not work well and an java.lang.ArrayIndexOutOfBoundsException crash the app.
Here is my code:
public class AreaPickerDialog extends Dialog implements OnValueChangeListener, OnClickListener {
static final String TAG = "AreaPickerDialog";
private NumberPicker mProvincePicker;
private NumberPicker mCityPicker;
private Button mCancelBtn;
private Button mOKBtn;
private AreaUtil mAreaUtil;
private List<Area> mProvinces;
private int mAreaId;
private int mProvinceId;
private Handler mHandler;
public AreaPickerDialog(Context context, Handler handler, int areaId) {
super(context);
mAreaUtil = AreaUtil.getInstance();
mProvinces = mAreaUtil.getProvinceList();
mAreaId = areaId;
mProvinceId = mAreaUtil.getProvinceIdByAreaId(areaId);
mHandler = handler;
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.dialog_area_picker);
mProvincePicker = (NumberPicker) findViewById(R.id.np_province);
mCityPicker = (NumberPicker) findViewById(R.id.np_city);
mCancelBtn = (Button) findViewById(R.id.btn_cancel);
mOKBtn = (Button) findViewById(R.id.btn_ok);
initProvinceData();
mProvincePicker.setOnValueChangedListener(this);
mCityPicker.setOnValueChangedListener(this);
mCancelBtn.setOnClickListener(this);
mOKBtn.setOnClickListener(this);
}
private void initProvinceData() {
if (mProvinces != null && mProvinces.size() > 0) {
String[] provinceNames = new String[mProvinces.size()];
for (int i = 0; i < provinceNames.length; i++) {
provinceNames[i] = mProvinces.get(i).getProvincename();
}
mProvincePicker.setDisplayedValues(provinceNames );
mProvincePicker.setMinValue(1);
mProvincePicker.setMaxValue(mProvinces.size());
}
mProvincePicker.setValue(mProvinceId);
initCityData(mProvincePicker.getValue());
}
private void initCityData(int provinceId) {
List<Arealist> cities = mAreaUtil.getCityListOfProvince(provinceId);
if (cities != null && cities.size() > 0) {
try {
int min = Integer.parseInt(cities.get(0).getAreaid());
int max = Integer.parseInt(cities.get(cities.size() -1).getAreaid());
String[] cityNames = new String[cities.size()];
for (int i = 0; i < cityNames.length; i++) {
cityNames[i] = cities.get(i).getName();
}
mCityPicker.setValue(0);
mCityPicker.setDisplayedValues(cityNames);
mCityPicker.setMinValue(min);
mCityPicker.setMaxValue(max);
} catch (NumberFormatException e) {
ILog.e(TAG, e.getMessage(), e);
}
}
}
#Override
public void onValueChange(NumberPicker picker, int oldVal, int newVal) {
if (mProvincePicker.equals(picker)) {
initCityData(mProvincePicker.getValue());
} else if (mCityPicker.equals(picker)) {
mAreaId = mCityPicker.getValue();
}
}
#Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.btn_cancel:
dismiss();
break;
case R.id.btn_ok:
Message msg = mHandler.obtainMessage(MineActivity.MSG_UPDATE_AREA);
msg.arg1 = mAreaId;
msg.sendToTarget();
dismiss();
break;
default:
break;
}
}
}
And logcat error trace:
12-30 23:09:26.560: E/InputEventReceiver(5620): Exception dispatching input event.
12-30 23:09:26.560: W/dalvikvm(5620): threadid=1: thread exiting with uncaught exception (group=0x41ddf438)
12-30 23:09:26.580: E/AndroidRuntime(5620): FATAL EXCEPTION: main
12-30 23:09:26.580: E/AndroidRuntime(5620): java.lang.ArrayIndexOutOfBoundsException: length=14; index=15
12-30 23:09:26.580: E/AndroidRuntime(5620): at net.simonvt.numberpicker.NumberPicker.updateInputTextView(NumberPicker.java:1840)
12-30 23:09:26.580: E/AndroidRuntime(5620): at net.simonvt.numberpicker.NumberPicker.setDisplayedValues(NumberPicker.java:1423)
12-30 23:09:26.580: E/AndroidRuntime(5620): at com.meishai.app.dialog.AreaPickerDialog.initCityData(AreaPickerDialog.java:88)
12-30 23:09:26.580: E/AndroidRuntime(5620): at com.meishai.app.dialog.AreaPickerDialog.onValueChange(AreaPickerDialog.java:100)
12-30 23:09:26.580: E/AndroidRuntime(5620): at net.simonvt.numberpicker.NumberPicker.notifyChange(NumberPicker.java:1855)
12-30 23:09:26.580: E/AndroidRuntime(5620): at net.simonvt.numberpicker.NumberPicker.setValueInternal(NumberPicker.java:1641)
12-30 23:09:26.580: E/AndroidRuntime(5620): at net.simonvt.numberpicker.NumberPicker.scrollBy(NumberPicker.java:1106)
12-30 23:09:26.580: E/AndroidRuntime(5620): at net.simonvt.numberpicker.NumberPicker.onTouchEvent(NumberPicker.java:886)
12-30 23:09:26.580: E/AndroidRuntime(5620): at android.view.View.dispatchTouchEvent(View.java:7127)
12-30 23:09:26.580: E/AndroidRuntime(5620): at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2170)
12-30 23:09:26.580: E/AndroidRuntime(5620): at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1905)
12-30 23:09:26.580: E/AndroidRuntime(5620): at net.simonvt.numberpicker.NumberPicker.dispatchTouchEvent(NumberPicker.java:944)
....
I am reseting the minValue,maxValue and DisplayedValues to reset the NumberPicker data and not working, so what is the right way?

check for Call setDisplayedValues(null) before setMaxValue in onClick.
Reference: https://stackoverflow.com/a/24322319/2624806

I have the same problem and I fixed it without modifing NumberPicker.java. Here is the code for your reference.
private void initCityData(int provinceId) {
List<Arealist> cities = mAreaUtil.getCityListOfProvince(provinceId);
if (cities != null && cities.size() > 0) {
try {
int min = Integer.parseInt(cities.get(0).getAreaid());
int max = Integer.parseInt(cities.get(cities.size() -1).getAreaid());
String[] cityNames = new String[cities.size()];
for (int i = 0; i < cityNames.length; i++) {
cityNames[i] = cities.get(i).getName();
}
int maxV = mCityPicker.getMaxValue();
if (max> maxV){
mCityPicker.setMinValue(min);
mCityPicker.setValue(0);
mCityPicker.setDisplayedValues(cityNames);
mCityPicker.setMaxValue(max);
}else{
mCityPicker.setMinValue(min);
mCityPicker.setValue(0);
mCityPicker.setMaxValue(max);
mCityPicker.setDisplayedValues(cityNames);
}
} catch (NumberFormatException e) {
ILog.e(TAG, e.getMessage(), e);
}
}
}

Just set displayedValues to null before resetting number picker like below:
pickerWard.displayedValues = null
pickerWard.maxValue = values.size - 1
pickerWard.displayedValues = values

Well, I look into the source code of NumberPicker.java, find that it will recompute the data and refresh UI in setMinValue(int minValue) and setMaxValue(int minValue). When set the new minValue, it will compute using new minValue and old maxValue, then error occured.
So, I modify a little of the NumberPicker: set value only in setMinValue(int minValue) and setMaxValue(int maxValue), and update UI in setDisplayedValues(String[] displayedValues). When data of NumberPicker changed, just reset the minValue、maxVaule and displayedValues. Note that setDisplayedValues(String[] displayedValues) MUST be called at last.
Here is what I modified:
NumberPicker.java:
public void setMinValue(int minValue) {
if (mMinValue == minValue) {
return;
}
if (minValue < 0) {
throw new IllegalArgumentException("minValue must be >= 0");
}
mMinValue = minValue;
if (mMinValue > mValue) {
mValue = mMinValue;
}
//boolean wrapSelectorWheel = mMaxValue - mMinValue > mSelectorIndices.length;
//setWrapSelectorWheel(wrapSelectorWheel);
//initializeSelectorWheelIndices();
//updateInputTextView();
//tryComputeMaxWidth();
invalidate();
}
public void setMaxValue(int maxValue) {
if (mMaxValue == maxValue) {
return;
}
if (maxValue < 0) {
throw new IllegalArgumentException("maxValue must be >= 0");
}
mMaxValue = maxValue;
if (mMaxValue < mValue) {
mValue = mMaxValue;
}
//boolean wrapSelectorWheel = mMaxValue - mMinValue > mSelectorIndices.length;
//setWrapSelectorWheel(wrapSelectorWheel);
//initializeSelectorWheelIndices();
//updateInputTextView();
//tryComputeMaxWidth();
invalidate();
}
public void setDisplayedValues(String[] displayedValues) {
if (mDisplayedValues == displayedValues) {
return;
}
mDisplayedValues = displayedValues;
if (mDisplayedValues != null) {
// Allow text entry rather than strictly numeric entry.
mInputText.setRawInputType(InputType.TYPE_CLASS_TEXT
| InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS);
} else {
mInputText.setRawInputType(InputType.TYPE_CLASS_NUMBER);
}
boolean wrapSelectorWheel = mMaxValue - mMinValue > mSelectorIndices.length;
setWrapSelectorWheel(wrapSelectorWheel);
updateInputTextView();
initializeSelectorWheelIndices();
tryComputeMaxWidth();
}
AreaPickerDialog.java:
private void initCityData(int provinceId) {
List<Arealist> cities = mAreaUtil.getCityListOfProvince(provinceId);
if (cities != null && cities.size() > 0) {
try {
int min = Integer.parseInt(cities.get(0).getAreaid());
int max = Integer.parseInt(cities.get(cities.size() -1).getAreaid());
String[] cityNames = new String[cities.size()];
for (int i = 0; i < cityNames.length; i++) {
cityNames[i] = cities.get(i).getName();
}
mCityPicker.setMinValue(min);
mCityPicker.setMaxValue(max);
mCityPicker.setDisplayedValues(cityNames);
} catch (NumberFormatException e) {
ILog.e(TAG, e.getMessage(), e);
}
}
}
This is an ugly but working solution.

looking the code of NumberPicker you're using:
private boolean updateInputTextView() {
/*
* 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.
*/
String text = (mDisplayedValues == null) ? formatNumber(mValue)
: mDisplayedValues[mValue - mMinValue];
you can see that's using mMinValue before you call setMinValue.
Try setting minValue and maxValue, before set the displayed values.

Related

How to allow mm/yyyy format in edittext for entering credit/debit card details

I have an activity where credit/debit card details is added. Currently my code allows to add date and month in MM/YY format. But i need year in 4 digits format MM/YYYY. Adding the '/' divider is set after 2nd digit. So if i increase my total digits count, i get the divider after every 2nd digit. How to fix this?
Carddetails.java:
public class CardDetailsActivity extends AppCompatActivity implements TextWatcher {
private static final int CARD_NUMBER_TOTAL_SYMBOLS = 19; // size of pattern 0000-0000-0000-0000
private static final int CARD_NUMBER_TOTAL_DIGITS = 16; // max numbers of digits in pattern: 0000 x walknew2
private static final int CARD_NUMBER_DIVIDER_MODULO = 5; // means divider position is every 5th symbol beginning with walknew4
private static final int CARD_NUMBER_DIVIDER_POSITION = CARD_NUMBER_DIVIDER_MODULO - 1; // means divider position is every 4th symbol beginning with 0
private static final char CARD_NUMBER_DIVIDER = '-';
#BindView(R.id.cardno)
EditText cardno;
#BindView(R.id.cardDateEditText)
EditText cardDateEditText;
#BindView(R.id.cardCVCEditText)
EditText cardCVCEditText;
SharedPreferences pref;
SharedPreferences.Editor editor;
private static final int CARD_DATE_TOTAL_SYMBOLS = 7; // size of pattern MM/YY
private static final int CARD_DATE_TOTAL_DIGITS = 6; // max numbers of digits in pattern: MM + YY
private static final int CARD_DATE_DIVIDER_MODULO = 3; // means divider position is every 3rd symbol beginning with walknew4
private static final int CARD_DATE_DIVIDER_POSITION = CARD_DATE_DIVIDER_MODULO - 1; // means divider position is every 2nd symbol beginning with 0
private static final char CARD_DATE_DIVIDER = '/';
private static final int CARD_CVC_TOTAL_SYMBOLS = 3;
String card_date, card_year, card_month, card_cvv, card_num, user_id, card_type = "debitcard";
#BindView(R.id.btn_add_card)
Button btn_add_card;
#BindView(R.id.btn_back)
Button btn_back;
Context context;
ProgressDialog progressDialog;
ApiService apiService;
String driverid, id, usertype, c_id, booking_id;
EditText card_numm, card_yearm, card_cvvm;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_card_details);
ButterKnife.bind(this);
context = CardDetailsActivity.this;
Log.e("TAG", "Inside Card Details Activity:");
apiService = RetrofitSingleton.getApiService();
usertype = PrefConnect.readString(CardDetailsActivity.this, PrefConnect.USERTYPE, "");
pref = getApplicationContext().getSharedPreferences("MyPref", 0);
editor = pref.edit();
id = pref.getString("driver_id", "");
Log.e("driver_id", id);
try {
if (getIntent() != null) {
driverid = getIntent().getStringExtra("Driverid");
booking_id = getIntent().getStringExtra("bookingid");
}
} catch (Exception e) {
e.printStackTrace();
Log.e("paymentact", e.getMessage());
}
cardno.getText().toString().trim();
getWindow().setSoftInputMode(
WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN);
cardno.addTextChangedListener(this);
cardDateEditText.addTextChangedListener(this);
card_numm = (EditText) findViewById(R.id.cardno);
card_yearm = (EditText) findViewById(R.id.cardDateEditText);
card_cvvm = (EditText) findViewById(R.id.cardCVCEditText);
}
#OnClick({R.id.btn_add_card, R.id.btn_back})
public void OnClick(View view) {
switch (view.getId()) {
case R.id.btn_back:
finish();
break;
case R.id.btn_add_card:
View view1 = getCurrentFocus();
Log.e("TAG", "Inside Card Details Activity Button Add Card ");
Validation();
break;
}
}
private boolean isInputCorrect(Editable s, int size, int dividerPosition, char divider) {
boolean isCorrect = s.length() <= size;
for (int i = 0; i < s.length(); i++) {
if (i > 0 && (i + 1) % dividerPosition == 0) {
isCorrect &= divider == s.charAt(i);
} else {
isCorrect &= Character.isDigit(s.charAt(i));
}
}
return isCorrect;
}
private String concatString(char[] digits, int dividerPosition, char divider) {
final StringBuilder formatted = new StringBuilder();
for (int i = 0; i < digits.length; i++) {
if (digits[i] != 0) {
formatted.append(digits[i]);
if ((i > 0) && (i < (digits.length - 1)) && (((i + 1) % dividerPosition) == 0)) {
formatted.append(divider);
}
}
}
return formatted.toString();
}
private char[] getDigitArray(final Editable s, final int size) {
char[] digits = new char[size];
int index = 0;
for (int i = 0; i < s.length() && index < size; i++) {
char current = s.charAt(i);
if (Character.isDigit(current)) {
digits[index] = current;
index++;
}
}
return digits;
}
#Override
public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {
}
#Override
public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
}
#Override
public void afterTextChanged(Editable s) {
card_num = String.valueOf(s);
Log.i("TAG", "Card Date:" + s);
Log.i("TAG", "Card Date :" + cardDateEditText.getEditableText());
if (s == cardno.getEditableText()) {
if (!isInputCorrect(s, CARD_NUMBER_TOTAL_SYMBOLS, CARD_NUMBER_DIVIDER_MODULO, CARD_NUMBER_DIVIDER)) {
s.replace(0, s.length(), concatString(getDigitArray(s, CARD_NUMBER_TOTAL_DIGITS), CARD_NUMBER_DIVIDER_POSITION, CARD_NUMBER_DIVIDER));
}
// DO STH
} else if (s == cardDateEditText.getEditableText()) {
if (!isInputCorrect(s, CARD_DATE_TOTAL_SYMBOLS, CARD_DATE_DIVIDER_MODULO, CARD_DATE_DIVIDER)) {
s.replace(0, s.length(), concatString(getDigitArray(s, CARD_DATE_TOTAL_DIGITS), CARD_DATE_DIVIDER_POSITION, CARD_DATE_DIVIDER));
} else if (s == cardCVCEditText.getEditableText()) {
if (s.length() > CARD_CVC_TOTAL_SYMBOLS) {
s.delete(CARD_CVC_TOTAL_SYMBOLS, s.length());
}
}
}
}
}
As by my understanding, your date divider must always be at position 2
private static final int CARD_DATE_DIVIDER_POSITION = CARD_DATE_DIVIDER_MODULO - 1; // means divider position is every 2nd symbol beginning with 0
with the above declaration, before appending the date divider, I should test this way ( you can change your isInputCorrect method this way):
private boolean isInputCorrect(Editable s, int size, int dividerPosition, char divider) {
boolean isCorrect = s.length() <= size;
for (int i = 0; i < s.length(); i++) {
if (i > 0 && (i + 1) % dividerPosition == 0) {
if (divider=='/') {
if (i==2) {
isCorrect &= divider == s.charAt(i);
}
}
} else {
isCorrect &= Character.isDigit(s.charAt(i));
}
}
return isCorrect;
}
And then after the text has changed can be modified a bit to become:
#Override
public void afterTextChanged(Editable s) {
card_num = String.valueOf(s);
String ss=cardDateEditText.getText().toString();
Log.i("TAG", "Card Date:" + s);
Log.i("TAG", "Card Date :" + ss);
if (s == cardno.getEditableText()) {
if (!isInputCorrect(s, CARD_NUMBER_TOTAL_SYMBOLS, CARD_NUMBER_DIVIDER_MODULO, CARD_NUMBER_DIVIDER)) {
s.replace(0, s.length(), concatString(getDigitArray(s, CARD_NUMBER_TOTAL_DIGITS), CARD_NUMBER_DIVIDER_POSITION, CARD_NUMBER_DIVIDER));
}
} else if (s == cardDateEditText.getEditableText()) {
if (s.length()<=CARD_DATE_TOTAL_SYMBOLS)
{
if (!isInputCorrect(s, CARD_DATE_TOTAL_SYMBOLS, CARD_DATE_DIVIDER_MODULO, CARD_DATE_DIVIDER)) {
Log.e("TAG",s+"");
s.replace(0, s.length(), concatString(getDigitArray(s, CARD_DATE_TOTAL_DIGITS), CARD_DATE_DIVIDER_POSITION, CARD_DATE_DIVIDER));
}
}else
{
s.delete(CARD_DATE_TOTAL_SYMBOLS,s.length());
}
} else if (s == cardCVCEditText.getEditableText()) {
if (s.length() > CARD_CVC_TOTAL_SYMBOLS) {
s.delete(CARD_CVC_TOTAL_SYMBOLS, s.length());
}
}
}
So you test also the length of the editable text.
The date divider must be included only once and just after the month represented by two first characters. That means the last digit must be at 2nd position index 1, at that instant i==1. So no other divider will be appended. I should have to test if the divider set is for date, to know I'm dealing with the date and then test if the index is not greater or equals to 2.
That's how I could handle that. I hope this will help.

Masked EditText with format (XXX) XXX-XXXX ext.XXXXXX in android?

How can I mask EditText with below format in android ?
(XXX) XXX-XXXX ext.XXXXXX i.e (654) 321-5846 ext.654321
Used below Custom Edit Text class
package com.test.PhoneNumberFormatter;
import android.content.Context;
import android.content.res.TypedArray;
import android.os.Bundle;
import android.os.Parcelable;
import android.support.v7.widget.AppCompatEditText;
import android.text.Editable;
import android.text.SpannableStringBuilder;
import android.text.TextWatcher;
import android.text.style.ForegroundColorSpan;
import android.util.AttributeSet;
import android.util.Log;
import android.view.KeyEvent;
import android.view.View;
import android.widget.TextView;
import com.test.R;
import static android.content.ContentValues.TAG;
public class MaskedEditText extends AppCompatEditText implements TextWatcher {
public static final String SPACE = " ";
private String mask;
private char charRepresentation;
private boolean keepHint;
private int[] rawToMask;
private RawText rawText;
private boolean editingBefore;
private boolean editingOnChanged;
private boolean editingAfter;
private int[] maskToRaw;
private int selection;
private boolean initialized;
private boolean ignore;
protected int maxRawLength;
private int lastValidMaskPosition;
private boolean selectionChanged;
private OnFocusChangeListener focusChangeListener;
private String allowedChars;
private String deniedChars;
public MaskedEditText(Context context) {
super(context);
init();
}
public MaskedEditText(Context context, AttributeSet attrs) {
super(context, attrs);
init();
TypedArray attributes = context.obtainStyledAttributes(attrs, R.styleable.MaskedEditText);
mask = attributes.getString(R.styleable.MaskedEditText_mask);
allowedChars = attributes.getString(R.styleable.MaskedEditText_allowed_chars);
deniedChars = attributes.getString(R.styleable.MaskedEditText_denied_chars);
String representation = attributes.getString(R.styleable.MaskedEditText_char_representation);
if (representation == null) {
charRepresentation = '#';
} else {
charRepresentation = representation.charAt(0);
}
keepHint = attributes.getBoolean(R.styleable.MaskedEditText_keep_hint, false);
cleanUp();
// Ignoring enter key presses
setOnEditorActionListener(new OnEditorActionListener() {
#Override
public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
switch (actionId) {
// case EditorInfo.IME_ACTION_NEXT:
// fixing actionNext
// return false;
default:
return true;
}
}
});
attributes.recycle();
}
#Override
public Parcelable onSaveInstanceState() {
final Parcelable superParcellable = super.onSaveInstanceState();
final Bundle state = new Bundle();
state.putParcelable("super", superParcellable);
state.putString("text", getRawText());
state.putBoolean("keepHint", isKeepHint());
return state;
}
#Override
public void onRestoreInstanceState(Parcelable state) {
Bundle bundle = (Bundle) state;
keepHint = bundle.getBoolean("keepHint", false);
super.onRestoreInstanceState(((Bundle) state).getParcelable("super"));
final String text = bundle.getString("text");
setText(text);
Log.d(TAG, "onRestoreInstanceState: " + text);
}
#Override
public void setText(CharSequence text, BufferType type) {
// if (text == null || text.equals("")) return;
super.setText(text, type);
}
/**
* #param listener - its onFocusChange() method will be called before performing MaskedEditText operations,
* related to this event.
*/
#Override
public void setOnFocusChangeListener(OnFocusChangeListener listener) {
focusChangeListener = listener;
}
private void cleanUp() {
initialized = false;
generatePositionArrays();
rawText = new RawText();
selection = rawToMask[0];
editingBefore = true;
editingOnChanged = true;
editingAfter = true;
if (hasHint() && rawText.length() == 0) {
this.setText(makeMaskedTextWithHint());
} else {
this.setText(makeMaskedText());
}
editingBefore = false;
editingOnChanged = false;
editingAfter = false;
maxRawLength = maskToRaw[previousValidPosition(mask.length() - 1)] + 1;
lastValidMaskPosition = findLastValidMaskPosition();
initialized = true;
super.setOnFocusChangeListener(new OnFocusChangeListener() {
#Override
public void onFocusChange(View v, boolean hasFocus) {
if (focusChangeListener != null) {
focusChangeListener.onFocusChange(v, hasFocus);
}
if (hasFocus()) {
selectionChanged = false;
MaskedEditText.this.setSelection(lastValidPosition());
}
}
});
}
private int findLastValidMaskPosition() {
for (int i = maskToRaw.length - 1; i >= 0; i--) {
if (maskToRaw[i] != -1) return i;
}
throw new RuntimeException("Mask must contain at least one representation char");
}
private boolean hasHint() {
return getHint() != null;
}
public MaskedEditText(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init();
}
public void setMask(String mask) {
this.mask = mask;
cleanUp();
}
public String getMask() {
return this.mask;
}
public String getRawText() {
return this.rawText.getText();
}
public void setCharRepresentation(char charRepresentation) {
this.charRepresentation = charRepresentation;
cleanUp();
}
public char getCharRepresentation() {
return this.charRepresentation;
}
/**
* Generates positions for values characters. For instance:
* Input data: mask = "+7(###)###-##-##
* After method execution:
* rawToMask = [3, 4, 5, 6, 8, 9, 11, 12, 14, 15]
* maskToRaw = [-1, -1, -1, 0, 1, 2, -1, 3, 4, 5, -1, 6, 7, -1, 8, 9]
* charsInMask = "+7()- " (and space, yes)
*/
private void generatePositionArrays() {
int[] aux = new int[mask.length()];
maskToRaw = new int[mask.length()];
String charsInMaskAux = "";
int charIndex = 0;
for (int i = 0; i < mask.length(); i++) {
char currentChar = mask.charAt(i);
if (currentChar == charRepresentation) {
aux[charIndex] = i;
maskToRaw[i] = charIndex++;
} else {
String charAsString = Character.toString(currentChar);
if (!charsInMaskAux.contains(charAsString)) {
charsInMaskAux = charsInMaskAux.concat(charAsString);
}
maskToRaw[i] = -1;
}
}
if (charsInMaskAux.indexOf(' ') < 0) {
charsInMaskAux = charsInMaskAux + SPACE;
}
char[] charsInMask = charsInMaskAux.toCharArray();
rawToMask = new int[charIndex];
for (int i = 0; i < charIndex; i++) {
rawToMask[i] = aux[i];
}
}
private void init() {
addTextChangedListener(this);
}
#Override
public void beforeTextChanged(CharSequence s, int start, int count,
int after) {
if (!editingBefore) {
editingBefore = true;
if (start > lastValidMaskPosition) {
ignore = true;
}
int rangeStart = start;
if (after == 0) {
rangeStart = erasingStart(start);
}
Range range = calculateRange(rangeStart, start + count);
if (range.getStart() != -1) {
rawText.subtractFromString(range);
}
if (count > 0) {
selection = previousValidPosition(start);
}
}
}
private int erasingStart(int start) {
while (start > 0 && maskToRaw[start] == -1) {
start--;
}
return start;
}
#Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
if (!editingOnChanged && editingBefore) {
editingOnChanged = true;
if (ignore) {
return;
}
if (count > 0) {
int startingPosition = maskToRaw[nextValidPosition(start)];
String addedString = s.subSequence(start, start + count).toString();
count = rawText.addToString(clear(addedString), startingPosition, maxRawLength);
if (initialized) {
int currentPosition;
if (startingPosition + count < rawToMask.length)
currentPosition = rawToMask[startingPosition + count];
else
currentPosition = lastValidMaskPosition + 1;
selection = nextValidPosition(currentPosition);
}
}
}
}
#Override
public void afterTextChanged(Editable s) {
if (!editingAfter && editingBefore && editingOnChanged) {
editingAfter = true;
if (hasHint() && (keepHint || rawText.length() == 0)) {
setText(makeMaskedTextWithHint());
} else {
setText(makeMaskedText());
}
selectionChanged = false;
setSelection(selection);
editingBefore = false;
editingOnChanged = false;
editingAfter = false;
ignore = false;
}
}
public boolean isKeepHint() {
return keepHint;
}
public void setKeepHint(boolean keepHint) {
this.keepHint = keepHint;
setText(getRawText());
}
#Override
protected void onSelectionChanged(int selStart, int selEnd) {
// On Android 4+ this method is being called more than 1 time if there is a hint in the EditText, what moves the cursor to left
// Using the boolean var selectionChanged to limit to one execution
if (initialized) {
if (!selectionChanged) {
selStart = fixSelection(selStart);
selEnd = fixSelection(selEnd);
// exactly in this order. If getText.length() == 0 then selStart will be -1
if (selStart > getText().length()) selStart = getText().length();
if (selStart < 0) selStart = 0;
// exactly in this order. If getText.length() == 0 then selEnd will be -1
if (selEnd > getText().length()) selEnd = getText().length();
if (selEnd < 0) selEnd = 0;
setSelection(selStart, selEnd);
selectionChanged = true;
} else {
//check to see if the current selection is outside the already entered text
if (selStart > rawText.length() - 1) {
final int start = fixSelection(selStart);
final int end = fixSelection(selEnd);
if (start >= 0 && end < getText().length()) {
setSelection(start, end);
}
}
}
}
super.onSelectionChanged(selStart, selEnd);
}
private int fixSelection(int selection) {
if (selection > lastValidPosition()) {
return lastValidPosition();
} else {
return nextValidPosition(selection);
}
}
private int nextValidPosition(int currentPosition) {
while (currentPosition < lastValidMaskPosition && maskToRaw[currentPosition] == -1) {
currentPosition++;
}
if (currentPosition > lastValidMaskPosition) return lastValidMaskPosition + 1;
return currentPosition;
}
private int previousValidPosition(int currentPosition) {
while (currentPosition >= 0 && maskToRaw[currentPosition] == -1) {
currentPosition--;
if (currentPosition < 0) {
return nextValidPosition(0);
}
}
return currentPosition;
}
private int lastValidPosition() {
if (rawText.length() == maxRawLength) {
return rawToMask[rawText.length() - 1] + 1;
}
return nextValidPosition(rawToMask[rawText.length()]);
}
private String makeMaskedText() {
int maskedTextLength;
if (rawText.length() < rawToMask.length) {
maskedTextLength = rawToMask[rawText.length()];
} else {
maskedTextLength = mask.length();
}
char[] maskedText = new char[maskedTextLength]; //mask.replace(charRepresentation, ' ').toCharArray();
for (int i = 0; i < maskedText.length; i++) {
int rawIndex = maskToRaw[i];
if (rawIndex == -1) {
maskedText[i] = mask.charAt(i);
} else {
maskedText[i] = rawText.charAt(rawIndex);
}
}
return new String(maskedText);
}
private CharSequence makeMaskedTextWithHint() {
SpannableStringBuilder ssb = new SpannableStringBuilder();
int mtrv;
int maskFirstChunkEnd = rawToMask[0];
for (int i = 0; i < mask.length(); i++) {
mtrv = maskToRaw[i];
if (mtrv != -1) {
if (mtrv < rawText.length()) {
ssb.append(rawText.charAt(mtrv));
} else {
ssb.append(getHint().charAt(maskToRaw[i]));
}
} else {
ssb.append(mask.charAt(i));
}
if ((keepHint && rawText.length() < rawToMask.length && i >= rawToMask[rawText.length()])
|| (!keepHint && i >= maskFirstChunkEnd)) {
ssb.setSpan(new ForegroundColorSpan(getCurrentHintTextColor()), i, i + 1, 0);
}
}
return ssb;
}
private Range calculateRange(int start, int end) {
Range range = new Range();
for (int i = start; i <= end && i < mask.length(); i++) {
if (maskToRaw[i] != -1) {
if (range.getStart() == -1) {
range.setStart(maskToRaw[i]);
}
range.setEnd(maskToRaw[i]);
}
}
if (end == mask.length()) {
range.setEnd(rawText.length());
}
if (range.getStart() == range.getEnd() && start < end) {
int newStart = previousValidPosition(range.getStart() - 1);
if (newStart < range.getStart()) {
range.setStart(newStart);
}
}
return range;
}
private String clear(String string) {
if (deniedChars != null) {
for (char c : deniedChars.toCharArray()) {
string = string.replace(Character.toString(c), "");
}
}
if (allowedChars != null) {
StringBuilder builder = new StringBuilder(string.length());
for (char c : string.toCharArray()) {
if (allowedChars.contains(String.valueOf(c))) {
builder.append(c);
}
}
string = builder.toString();
}
return string;
}
}
In activity_main.xml
<com.test.PhoneNumberFormatter.MaskedEditText
android:id="#+id/phone_input"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#color/white"
android:hint="#string/phone_number"
android:imeOptions="actionNext"
android:inputType="textPhonetic"
android:paddingBottom="#dimen/_3sdp"
android:paddingTop="#dimen/_8sdp"
android:textColorHint="#color/grey_color"
android:textSize="#dimen/_12sdp"
mask:allowed_chars="1234567890ext."
mask:keep_hint="false"
mask:mask="(###)###-#### ext.######" />
Thanks.
For format Edit-text, below things can be helpful to you.
**Step 1** : Add following line in your build.gradle file
implementation 'com.github.pinball83:masked-edittext:1.0.4'
**Step 2 :** by xml :
<com.github.pinball83.maskededittext.MaskedEditText
android:id="#+id/masked_edit_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="number"
app:mask="8 (***) *** **-**"
app:notMaskedSymbol="*"
app:maskIcon="#drawable/abc_ic_clear_mtrl_alpha"
app:maskIconColor="#color/colorPrimary"
/>
or by java file :
MaskedEditText maskedEditText = new MaskedEditText.Builder(context)
.mask("8 (***) *** **-**")
.notMaskedSymbol("*")
.icon(R.drawable.ic_account_circle)
.iconCallback(unmaskedText -> { //Icon click callback handler })
.build();
MaskedEditText editText = new MaskedEditText.Builder(context)
.mask("8 (***) *** **-**")
.notMaskedSymbol("*")
.build();; //set mask to "8 (***) *** **-**" and not masked symbol to "*"
Text setup and formatting
MaskedEditText editText = new MaskedEditText..Builder(context)
.mask("8 (***) *** **-**")
.notMaskedSymbol("*")
.format("[1][2][3] [4][5][6]-[7][8]-[10][9]")//set format of returned data input into MaskedEditText
.build();
editText.setMaskedText("5551235567");
for more details use following url :
https://github.com/pinball83/Masked-Edittext
Enjoy :)
Step 1 : Create editText
<EditText
android:id="#+id/masked_edit_text"
android:layout_width="yourSize"
android:layout_height="yourSize"
android:inputType="textPassword"/>
Step2:
public class CustomTransformation extends PasswordTransformationMethod {
#Override
public CharSequence getTransformation(CharSequence source, View view) {
return new TransformedSequence(source);
}
private class TransformedSequence implements CharSequence {
private CharSequence sequence;
public TransformedSequence(CharSequence source) {
sequence = source; // Store char sequence
}
public char charAt(int index) {
return 'X'; // Replace with what you want.
}
public int length() {
return sequence.length(); // return the length
}
public CharSequence subSequence(int start, int end) {
return sequence.subSequence(start, end); //return sequence
}
}
Step 3: apply the transformation
EditText edittext = findViewById(R.id.masked_edit_text);
edittext.setTransformationMethod(new CustomTransformation());
https://github.com/mukeshsolanki/country-picker-android
try this library .
this will automatically mask your edittext with selected country number .

How to call text Watcher when user update any value from edit text

i have button,on button click it create editText with value, value of edit text is depending on count of total edit texts.for example edittext1 = 100, when user create two edit text then the value will be like this edittext1 = 50,edittext2 = 50 and so on.( value = 100/ total no of edittext) which i set equally to each edit text.now the problem is when user want to change/update any value from edittext, i want to update value of each edittext according to user's newly entered value.
i want to call textwatcher when value changed by only user,in my case when user click on button it will call.
thank you.
here is my code
public class StageForm extends BaseActivity implements View.OnClickListener {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.stage_form);
spinnerProjectStage = (Spinner) findViewById(R.id.spinnerAddProjectStage);
spinnerProjectList = (Spinner) findViewById(R.id.spinnerProjectList);
stageLinearLayout = (LinearLayout) findViewById(R.id.stageProjectList);
btnAddMoreStage = (Button) findViewById(R.id.btnAddMoreStage);
btnAddMoreStage.setOnClickListener(this);
getProjectStage();
}
public void onClick(View v) {
if (v.getId() == R.id.btnAddMoreStage) {
public void addMoreFields () {
try {
k++;
flag = k;
final LinearLayout.LayoutParams lparams;
lparams = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
layout[flag] = new LinearLayout(StageForm.this);
layout[flag].setLayoutParams(lparams);
layout[flag].setId(flag);
txtStageName[flag] = new EditText(StageForm.this);
txtStageName[flag].setLayoutParams(lparams);
txtStageName[flag].setHint("stage " + k + "");
txtStageName[flag].setId(flag);
txtStagePercent[flag] = new EditText(StageForm.this);
txtStagePercent[flag].setLayoutParams(lparams);
txtStagePercent[flag].setHint("percent");
txtStagePercent[flag].setId(flag);
txtStagePercent[flag].addTextChangedListener(stagePercentChangeListener);
if (flag == 0) {
txtStagePercent[flag].setText(String.valueOf(totalPercent));
} else {
countEditText = flag + 1;
calculatePercentage(countEditText, flag);
}
} catch (Exception e) {
e.printStackTrace();
}
layout[flag].addView(txtStageName[flag]);
layout[flag].addView(txtStagePercent[flag]);
stageLinearLayout.addView(layout[flag]);
}
}
}
private void calculatePercentage(int countEditText, int flag) {
k = flag;
if (flag == 0) {
// countEditText = flag;
lastTextBox = countEditText;
} else {
// countEditText = flag;
lastTextBox = countEditText - 1;
}
result = totalPercent / countEditText;
convertFloatResult = Math.round(result);
remainingPercent = totalPercent - (convertFloatResult * countEditText);
lastTextValue = convertFloatResult + remainingPercent;
try {
if (remainingPercent == 0) {
for (int j = 0; j <= lastTextBox; j++) {
txtStagePercent[j].setText(String.valueOf(convertFloatResult));
}
txtStagePercent[lastTextBox].setText(String.valueOf(lastTextValue));
} else {
for (int j = 0; j < lastTextBox; j++) {
txtStagePercent[j].setText(String.valueOf(convertFloatResult));
}
txtStagePercent[lastTextBox].setText(String.valueOf(lastTextValue));
}
} catch (Exception e) {
e.printStackTrace();
}
}
private TextWatcher stagePercentChangeListener = new TextWatcher() {
#Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
if (flag == 0) {
} else {
String getbeforValue = String.valueOf(s);
beforeTextChanged = Integer.parseInt(getbeforValue);
}
}
#Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
String getchangedValue = String.valueOf(s);
afterTextChanged = Integer.parseInt(getchangedValue);
}
#Override
public void afterTextChanged(Editable s) {
totalPercent = totalPercent - afterTextChanged;
countEditText = countEditText - 1;
calculatePercentage(countEditText, flag);
}
};
}

java.lang.ClassCastException in Handler Message

Here are the error log:
E/AndroidRuntime: FATAL EXCEPTION: main
java.lang.ClassCastException: java.lang.String cannot be cast to com.example.demoapp.device.Dev
at com.example.demoapp.MainActivity$MyHandler.handleMessage(MainActivity.java:177)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:137)
at android.app.ActivityThread.main(ActivityThread.java:5140)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:525)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:737)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:553)
at dalvik.system.NativeStart.main(Native Method)
This is My Handler Code error occurred here in new DevSetNameThread
class MyHandler extends Handler {
public MyHandler() {
}
#Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
new DevSetNameThread(((Dev) msg.obj), deviceNickName).start();
}
}
And Here is the code from that send message to handler with put object
static final int CMD_TIMEOUT = 8;
static final int DISPLAY_DEVID = 9;
static final int FIND_DEVID = 3;
static final int FIND_ERROR = 4;
public static final int SCAN_CODE = 1;
static final int START_SUBMIT = 5;
static final int SUBMIT_ERROR = 2;
static final int SUBMIT_START = 0;
static final int SUBMIT_SUCCEED = 1;
public static final String TAG = "MainActivity";
static final int TIME_OUT = 6;
Handler handler;
List<Dev> listDev;
Msg msg;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
init();
}
private void init() {
info = "";
type = "";
msg = new Msg();
listDev = new ArrayList();
}
class SubmitThread extends Thread {
SubmitThread() {
}
public void run() {
if (listDev.size() > 0) {
Dev d = (Dev) listDev.get(SUBMIT_START);
listDev.remove(d);
if (d != null) {
MainActivity mainActivity;
int index;
Message message = new Message();
message.what = SUBMIT_ERROR;
Log.v("SubmitThread", "\u5f00\u59cb\u63d0\u4ea4\u6570\u636e start..");
int delay = 50;
int reSendTime = SUBMIT_SUCCEED;
Cfg.isSubmitDev = false;
String strId = d.getId();
if (StrTools.stringToInt(strId.substring(SUBMIT_START, SUBMIT_SUCCEED)) == 0) {
mainActivity = MainActivity.this;
devId = strId.substring(SUBMIT_SUCCEED);
} else {
devId = strId;
}
message.obj = devId;
mainActivity = MainActivity.this;
passwd = d.getPass();
byte[] data = new byte[16];
long val = StrTools.stringToInt(devId);
int i = SUBMIT_START;
int index2 = SUBMIT_START;
while (i < CMD_TIMEOUT) {
index = index2 + SUBMIT_SUCCEED;
data[index2] = (byte) ((int) (val % 256));
val /= 256;
i += SUBMIT_SUCCEED;
index2 = index;
}
byte[] b = new byte[CMD_TIMEOUT];
val = StrTools.stringToInt(passwd);
for (i = SUBMIT_START; i < CMD_TIMEOUT; i += SUBMIT_SUCCEED) {
b[i] = (byte) ((int) (val % 256));
val /= 256;
}
byte[] buff = StrTools.byteToSwapByte(b);
i = SUBMIT_START;
while (i < CMD_TIMEOUT) {
index = index2 + SUBMIT_SUCCEED;
data[index2] = buff[i];
i += SUBMIT_SUCCEED;
index2 = index;
}
msg.setId(Cfg.userId);
msg.setCmdType(MSGCMDTYPE.valueOf(-17));
msg.setCmd(MSGCMD.valueOf((int) TIME_OUT));
msg.setTorken(Cfg.tcpTorken);
msg.setData(data);
msg.setDataLen(data.length);
protocol.MessageEnCode(msg);
Log.i(TAG, " data:" + StrTools.bytesToHexString(data));
Log.i(TAG, "sendData:" + StrTools.bytesToHexString(msg.getSendData()));
Message handlermsg = new Message();
handlermsg.obj = devId;
handlermsg.what = SUBMIT_START;
handler.sendMessage(handlermsg);
do {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
reSendTime--;
if (reSendTime <= 0) {
reSendTime = 10;
socketService.socketSendMessage(msg);
}
if (Cfg.isSubmitDev) {
message.what = SUBMIT_SUCCEED;
message.obj = d;
succedDev = d;
handler.sendMessage(message);
return;
}
delay--;
} while (delay > 0);
message.what = SUBMIT_ERROR;
handler.sendMessage(message);
}
}
}
}
Sorry for inconvenience i can't put whole code.
I tried to casting retrieved object with standard code but it's giving me this error so, how can i retrieve Dev object through handler and use it ?

After several successful runs, progress dialog suddenly returns null pointer exception

I'm developing an app in which the user inputs his/her voice and the app will calculate its features. so I put a progress dialog to inform the user that the app is calculating its features. At first, the application runs perfectly, then on third run, the progress dialog returns null pointer exception. I don't know how to fix. Here's the logcat:
02-22 20:35:11.776: D/AndroidRuntime(24137): Shutting down VM
02-22 20:35:11.776: W/dalvikvm(24137): threadid=1: thread exiting with uncaught exception (group=0x4186bda0)
02-22 20:35:11.786: E/AndroidRuntime(24137): FATAL EXCEPTION: main
02-22 20:35:11.786: E/AndroidRuntime(24137): Process: com.neu.val.activity, PID: 24137
02-22 20:35:11.786: E/AndroidRuntime(24137): java.lang.NullPointerException
02-22 20:35:11.786: E/AndroidRuntime(24137): at android.app.ProgressDialog.setMessage(ProgressDialog.java:325)
02-22 20:35:11.786: E/AndroidRuntime(24137): at com.neu.val.activity.CreateVoiceSample$MfccTask.onProgressUpdate(CreateVoiceSample.java:341)
02-22 20:35:11.786: E/AndroidRuntime(24137): at android.os.AsyncTask$InternalHandler.handleMessage(AsyncTask.java:648)
02-22 20:35:11.786: E/AndroidRuntime(24137): at android.os.Handler.dispatchMessage(Handler.java:102)
02-22 20:35:11.786: E/AndroidRuntime(24137): at android.os.Looper.loop(Looper.java:146)
02-22 20:35:11.786: E/AndroidRuntime(24137): at android.app.ActivityThread.main(ActivityThread.java:5653)
02-22 20:35:11.786: E/AndroidRuntime(24137): at java.lang.reflect.Method.invokeNative(Native Method)
02-22 20:35:11.786: E/AndroidRuntime(24137): at java.lang.reflect.Method.invoke(Method.java:515)
02-22 20:35:11.786: E/AndroidRuntime(24137): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1291)
02-22 20:35:11.786: E/AndroidRuntime(24137): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1107)
02-22 20:35:11.786: E/AndroidRuntime(24137): at dalvik.system.NativeStart.main(Native Method)
and here's the class:
public class CreateVoiceSample extends ActionBarActivity {
private Button btSpeak, btCance, btSave;
private WaveRecorder waveRecorder;
private ProgressBar progressBar;
private TextView timerText;
private boolean stopped;
private int MAX_DURATION = 2500, progressTime, seconds;
private Timer timer;
static final String TAG = "VAP";
public String codebookString;
private long userId;
private Uri insertFeatures;
private AppDB appDB = new AppDB(this);
/** The recording output file. */
private static File outputFile = new File(
Environment
.getExternalStoragePublicDirectory(Environment.DIRECTORY_MUSIC),
"recording.wav");
#Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.recordvoice);
userId = getIntent().getLongExtra(Extras.EXTRA_USER_ID, 1);
initializeVar();
enableButtons(true, false, true);
}
public void initializeVar() {
btSpeak = (Button) findViewById(R.id.bSpeak);
btSave = (Button) findViewById(R.id.bSave);
btCancel = (Button) findViewById(R.id.bCancel);
progressBar = (ProgressBar) findViewById(R.id.progressBar1);
timerText = (TextView) findViewById(R.id.textView1);
stopped = true;
progressBar.setMax(MAX_DURATION);
startProgress();
}
public void actionBt(View v) {
if (v.getId() == R.id.bSpeak) {
startRecord();
} else if (v.getId() == R.id.bCancel) {
finish();
} else if (v.getId() == R.id.bSave) {
insertFeature(codebookString);
}
}
private void startRecord() {
// TODO Auto-generated method stub
enableButtons(false, false, false);
seconds = 1000;
progressTime = 0;
progressBar.setProgress(0);
timerText.setText("00:00:00");
if (outputFile.exists())
outputFile.delete();
waveRecorder = new WaveRecorder(8000);
waveRecorder.setOutputFile(outputFile.getAbsolutePath());
stopped = false;
try {
waveRecorder.prepare();
waveRecorder.start();
Toast.makeText(getApplicationContext(), "Recording started ... ",
Toast.LENGTH_SHORT).show();
} catch (Exception e) {
e.printStackTrace();
}
}
public void stopRecord() {
stopped = true;
waveRecorder.stop();
waveRecorder.release();
waveRecorder.reset();
timer.cancel();
Toast.makeText(getApplicationContext(), "Recording stopped..", Toast.LENGTH_SHORT).show();
calculateMfccs();
startProgress();
}
public void startProgress() {
enableButtons(true,true,true);
final Handler handler = new Handler();
TimerTask timerTask = new TimerTask() {
#Override
public void run() {
handler.post(new Runnable() {
#Override
public void run() {
try {
progress();
} catch (Exception e) {
// TODO Auto-generated catch block
}
}
});
}
};
timer = new Timer();
timer.schedule(timerTask, 1, 1000);
}
public void enableButtons(boolean startBt, boolean stopBt, boolean saveBt,
boolean cancelBt) {
btSpeak.setEnabled(startBt);
btSave.setEnabled(saveBt);
btCancel.setEnabled(cancelBt);
}
public void progress() {
if (!stopped) // call ui only when the progress is not stopped
{
if (progressTime < MAX_DURATION) {
runOnUiThread(new Runnable() {
#Override
public void run() {
try {
int secondsText = seconds / 1000;
progressTime = progressBar.getProgress() + 1000;
progressBar.setProgress(progressTime);
timerText.setText("00:00:0" + secondsText);
seconds += 1000;
} catch (Exception e) {
}
}
});
} else {
stopRecord();
}
}
}
private void calculateMfccs() {
new MfccTask(this).execute(outputFile.getAbsolutePath());
}
private void insertFeature(String password) {
enableButtons(true,false,true);
long modeId = ((VoiceApplication)getApplication()).getModeId();
ContentValues cv = new ContentValues();
cv.put(Feature.SUBJECT_ID, userId);
cv.put(Feature.MODE_ID, modeId);
cv.put(Feature.REPRESENTATION, password);
insertFeatures = this.getContentResolver().insert(Feature.CONTENT_URI, cv);
appDB.onClose();
finish();
Intent changePassIntent = new Intent(this,MainActivity.class);
changePassIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK|IntentCompat.FLAG_ACTIVITY_CLEAR_TASK);
this.startActivity(changePassIntent);
}
class MfccTask extends AsyncTask<String, Object, String> {
private ProgressDialog progressDialog;
private final Activity parentActivity;
public MfccTask(Activity parentActivity) {
this.parentActivity = parentActivity;
}
#Override
protected String doInBackground(String... params) {
String filename = params[0];
WavReader wavReader = new WavReader(filename);
Log.i(TAG, "Starting to read from file " + filename);
double[] samples = readSamples(wavReader);
Log.i(TAG, "Starting to calculate MFCC");
double[][] mfcc = calculateMfcc(samples);
FeatureVector pl = createFeatureVector(mfcc);
KMeans kmeans = doClustering(pl);
Codebook cb = createCodebook(kmeans);
Gson gson = new Gson();
String codebookJsonString = gson.toJson(cb, Codebook.class);
Log.i(TAG, codebookJsonString);
return codebookJsonString;
}
private Codebook createCodebook(KMeans kmeans) {
int numberClusters = kmeans.getNumberClusters();
Matrix[] centers = new Matrix[numberClusters];
for (int i = 0; i < numberClusters; i++) {
centers[i] = kmeans.getCluster(i).getCenter();
}
Codebook cb = new Codebook();
cb.setLength(numberClusters);
cb.setCentroids(centers);
return cb;
}
private KMeans doClustering(FeatureVector pl) {
long start;
KMeans kmeans = new KMeans(Constants.CLUSTER_COUNT, pl,
Constants.CLUSTER_MAX_ITERATIONS);
Log.i(TAG, "Prepared k means clustering");
start = System.currentTimeMillis();
progressDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);
kmeans.run();
Log.i(TAG,
"Clustering finished, total time = "
+ (System.currentTimeMillis() - start) + "ms");
return kmeans;
}
private FeatureVector createFeatureVector(double[][] mfcc) {
int vectorSize = mfcc[0].length;
int vectorCount = mfcc.length;
Log.i(TAG, "Creating pointlist with dimension=" + vectorSize
+ ", count=" + vectorCount);
FeatureVector pl = new FeatureVector(vectorSize, vectorCount);
for (int i = 0; i < vectorCount; i++) {
pl.add(mfcc[i]);
}
Log.d(TAG, "Added all MFCC vectors to pointlist");
return pl;
}
private short createSample(byte[] buffer) {
short sample = 0;
// hardcoded two bytes here
short b1 = buffer[0];
short b2 = buffer[1];
b2 <<= 8;
sample = (short) (b1 | b2);
return sample;
}
private double[][] calculateMfcc(double[] samples) {
MFCC mfccCalculator = new MFCC(Constants.SAMPLERATE,
Constants.WINDOWSIZE, Constants.COEFFICIENTS, false,
Constants.MINFREQ + 1, Constants.MAXFREQ, Constants.FILTERS);
int hopSize = Constants.WINDOWSIZE / 2;
int mfccCount = (samples.length / hopSize) - 1;
double[][] mfcc = new double[mfccCount][Constants.COEFFICIENTS];
long start = System.currentTimeMillis();
for (int i = 0, pos = 0; pos < samples.length - hopSize; i++, pos += hopSize) {
mfcc[i] = mfccCalculator.processWindow(samples, pos);
if (i % 20 == 0) {
publishProgress("Calculating features...", i, mfccCount);
}
}
publishProgress("Calculating features...", mfccCount, mfccCount);
Log.i(TAG, "Calculated " + mfcc.length + " vectors of MFCCs in "
+ (System.currentTimeMillis() - start) + "ms");
return mfcc;
}
private double[] readSamples(WavReader wavReader) {
int sampleSize = wavReader.getFrameSize();
int sampleCount = wavReader.getPayloadLength() / sampleSize;
int windowCount = (int) Math.floor(sampleCount
/ Constants.WINDOWSIZE);
byte[] buffer = new byte[sampleSize];
double[] samples = new double[windowCount * Constants.WINDOWSIZE];
try {
for (int i = 0; i < samples.length; i++) {
wavReader.read(buffer, 0, sampleSize);
samples[i] = createSample(buffer);
if (i % 1000 == 0) {
publishProgress("Reading samples...", i, samples.length);
}
}
} catch (IOException e) {
Log.e(TAG, "Exception in reading samples", e);
}
return samples;
}
#Override
protected void onPostExecute(String result) {
codebookString = result;
progressDialog.dismiss();
}
#Override
protected void onPreExecute() {
progressDialog = new ProgressDialog(parentActivity);
progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
progressDialog.setTitle("Working...");
progressDialog.setMessage("Working...");
progressDialog.setProgress(0);
progressDialog.setMax(10000);
progressDialog.show();
progressDialog.setCancelable(false);
progressDialog.setCanceledOnTouchOutside(false);
}
#Override
protected void onProgressUpdate(Object... values) {
String msg = (String) values[0];
Integer current = (Integer) values[1];
Integer max = (Integer) values[2];
progressDialog.setMessage(msg);
progressDialog.setProgress(current);
progressDialog.setMax(max);
}
}
}
and here's the line(line 341) where the error occured:
progressDialog.setMessage(msg);
I think the problem is in actionBt where the function startRecord() get called and in the line progressBar.setProgress(0); if the progressBar didn't yet initialized then Error will raise.its not a good way to initialize a global variable several times in different lines.

Categories

Resources