/*
* Copyright (c) 2014-2015 Amberfog.
*
* 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.amberfog.countryflagsdemo;
import android.app.Fragment;
import android.content.Context;
import android.os.AsyncTask;
import android.text.InputFilter;
import android.text.Spanned;
import android.text.TextUtils;
import android.util.SparseArray;
import android.view.KeyEvent;
import android.view.View;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputMethodManager;
import android.widget.AdapterView;
import android.widget.EditText;
import android.widget.Spinner;
import android.widget.TextView;
import com.google.i18n.phonenumbers.NumberParseException;
import com.google.i18n.phonenumbers.PhoneNumberUtil;
import com.google.i18n.phonenumbers.Phonenumber;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.TreeSet;
public abstract class BaseFlagFragment extends Fragment {
protected static final TreeSet<String> CANADA_CODES = new TreeSet<String>();
protected static final TreeSet<String> US_CODES = new TreeSet<String>();
protected static final TreeSet<String> DO_CODES = new TreeSet<String>();
protected static final TreeSet<String> PR_CODES = new TreeSet<String>();
static {
//USA
US_CODES.add("201");
US_CODES.add("202");
US_CODES.add("203");
US_CODES.add("205");
US_CODES.add("206");
US_CODES.add("207");
US_CODES.add("208");
US_CODES.add("209");
US_CODES.add("210");
US_CODES.add("212");
US_CODES.add("213");
US_CODES.add("214");
US_CODES.add("215");
US_CODES.add("216");
US_CODES.add("217");
US_CODES.add("218");
US_CODES.add("219");
US_CODES.add("224");
US_CODES.add("225");
US_CODES.add("228");
US_CODES.add("229");
US_CODES.add("231");
US_CODES.add("234");
US_CODES.add("239");
US_CODES.add("240");
US_CODES.add("248");
US_CODES.add("251");
US_CODES.add("252");
US_CODES.add("253");
US_CODES.add("254");
US_CODES.add("256");
US_CODES.add("260");
US_CODES.add("262");
US_CODES.add("267");
US_CODES.add("269");
US_CODES.add("270");
US_CODES.add("276");
US_CODES.add("281");
US_CODES.add("301");
US_CODES.add("302");
US_CODES.add("303");
US_CODES.add("304");
US_CODES.add("305");
US_CODES.add("307");
US_CODES.add("308");
US_CODES.add("309");
US_CODES.add("310");
US_CODES.add("312");
US_CODES.add("313");
US_CODES.add("314");
US_CODES.add("315");
US_CODES.add("316");
US_CODES.add("317");
US_CODES.add("318");
US_CODES.add("319");
US_CODES.add("320");
US_CODES.add("321");
US_CODES.add("323");
US_CODES.add("325");
US_CODES.add("330");
US_CODES.add("334");
US_CODES.add("336");
US_CODES.add("337");
US_CODES.add("339");
US_CODES.add("347");
US_CODES.add("351");
US_CODES.add("352");
US_CODES.add("360");
US_CODES.add("361");
US_CODES.add("386");
US_CODES.add("401");
US_CODES.add("402");
US_CODES.add("404");
US_CODES.add("405");
US_CODES.add("406");
US_CODES.add("407");
US_CODES.add("408");
US_CODES.add("409");
US_CODES.add("410");
US_CODES.add("412");
US_CODES.add("413");
US_CODES.add("414");
US_CODES.add("415");
US_CODES.add("417");
US_CODES.add("419");
US_CODES.add("423");
US_CODES.add("425");
US_CODES.add("430");
US_CODES.add("432");
US_CODES.add("434");
US_CODES.add("435");
US_CODES.add("440");
US_CODES.add("443");
US_CODES.add("469");
US_CODES.add("478");
US_CODES.add("479");
US_CODES.add("480");
US_CODES.add("484");
US_CODES.add("501");
US_CODES.add("502");
US_CODES.add("503");
US_CODES.add("504");
US_CODES.add("505");
US_CODES.add("507");
US_CODES.add("508");
US_CODES.add("509");
US_CODES.add("510");
US_CODES.add("512");
US_CODES.add("513");
US_CODES.add("515");
US_CODES.add("516");
US_CODES.add("517");
US_CODES.add("518");
US_CODES.add("520");
US_CODES.add("530");
US_CODES.add("540");
US_CODES.add("541");
US_CODES.add("551");
US_CODES.add("559");
US_CODES.add("561");
US_CODES.add("562");
US_CODES.add("563");
US_CODES.add("567");
US_CODES.add("570");
US_CODES.add("571");
US_CODES.add("573");
US_CODES.add("574");
US_CODES.add("575");
US_CODES.add("580");
US_CODES.add("585");
US_CODES.add("586");
US_CODES.add("601");
US_CODES.add("602");
US_CODES.add("603");
US_CODES.add("605");
US_CODES.add("606");
US_CODES.add("607");
US_CODES.add("608");
US_CODES.add("609");
US_CODES.add("610");
US_CODES.add("612");
US_CODES.add("614");
US_CODES.add("615");
US_CODES.add("616");
US_CODES.add("617");
US_CODES.add("618");
US_CODES.add("619");
US_CODES.add("620");
US_CODES.add("623");
US_CODES.add("626");
US_CODES.add("630");
US_CODES.add("631");
US_CODES.add("636");
US_CODES.add("641");
US_CODES.add("646");
US_CODES.add("650");
US_CODES.add("651");
US_CODES.add("660");
US_CODES.add("661");
US_CODES.add("662");
US_CODES.add("678");
US_CODES.add("682");
US_CODES.add("701");
US_CODES.add("702");
US_CODES.add("703");
US_CODES.add("704");
US_CODES.add("706");
US_CODES.add("707");
US_CODES.add("708");
US_CODES.add("712");
US_CODES.add("713");
US_CODES.add("714");
US_CODES.add("715");
US_CODES.add("716");
US_CODES.add("717");
US_CODES.add("718");
US_CODES.add("719");
US_CODES.add("720");
US_CODES.add("724");
US_CODES.add("727");
US_CODES.add("731");
US_CODES.add("732");
US_CODES.add("734");
US_CODES.add("740");
US_CODES.add("754");
US_CODES.add("757");
US_CODES.add("760");
US_CODES.add("763");
US_CODES.add("765");
US_CODES.add("770");
US_CODES.add("772");
US_CODES.add("773");
US_CODES.add("774");
US_CODES.add("775");
US_CODES.add("781");
US_CODES.add("785");
US_CODES.add("786");
US_CODES.add("801");
US_CODES.add("802");
US_CODES.add("803");
US_CODES.add("804");
US_CODES.add("805");
US_CODES.add("806");
US_CODES.add("808");
US_CODES.add("810");
US_CODES.add("812");
US_CODES.add("813");
US_CODES.add("814");
US_CODES.add("815");
US_CODES.add("816");
US_CODES.add("817");
US_CODES.add("818");
US_CODES.add("828");
US_CODES.add("830");
US_CODES.add("831");
US_CODES.add("832");
US_CODES.add("843");
US_CODES.add("845");
US_CODES.add("847");
US_CODES.add("848");
US_CODES.add("850");
US_CODES.add("856");
US_CODES.add("857");
US_CODES.add("858");
US_CODES.add("859");
US_CODES.add("860");
US_CODES.add("862");
US_CODES.add("863");
US_CODES.add("864");
US_CODES.add("865");
US_CODES.add("866");
US_CODES.add("870");
US_CODES.add("901");
US_CODES.add("903");
US_CODES.add("904");
US_CODES.add("906");
US_CODES.add("907");
US_CODES.add("908");
US_CODES.add("909");
US_CODES.add("910");
US_CODES.add("912");
US_CODES.add("913");
US_CODES.add("914");
US_CODES.add("915");
US_CODES.add("916");
US_CODES.add("917");
US_CODES.add("918");
US_CODES.add("919");
US_CODES.add("920");
US_CODES.add("925");
US_CODES.add("928");
US_CODES.add("931");
US_CODES.add("936");
US_CODES.add("937");
US_CODES.add("940");
US_CODES.add("941");
US_CODES.add("947");
US_CODES.add("949");
US_CODES.add("951");
US_CODES.add("952");
US_CODES.add("954");
US_CODES.add("956");
US_CODES.add("970");
US_CODES.add("971");
US_CODES.add("972");
US_CODES.add("973");
US_CODES.add("978");
US_CODES.add("979");
US_CODES.add("980");
US_CODES.add("985");
US_CODES.add("989");
//Dominican Republic
DO_CODES.add("809");
DO_CODES.add("829");
DO_CODES.add("849");
//Puerto Rico
PR_CODES.add("787");
PR_CODES.add("939");
//Canada
CANADA_CODES.add("204");
CANADA_CODES.add("226");
CANADA_CODES.add("236");
CANADA_CODES.add("249");
CANADA_CODES.add("250");
CANADA_CODES.add("289");
CANADA_CODES.add("306");
CANADA_CODES.add("343");
CANADA_CODES.add("365");
CANADA_CODES.add("387");
CANADA_CODES.add("403");
CANADA_CODES.add("416");
CANADA_CODES.add("418");
CANADA_CODES.add("431");
CANADA_CODES.add("437");
CANADA_CODES.add("438");
CANADA_CODES.add("450");
CANADA_CODES.add("506");
CANADA_CODES.add("514");
CANADA_CODES.add("519");
CANADA_CODES.add("548");
CANADA_CODES.add("579");
CANADA_CODES.add("581");
CANADA_CODES.add("587");
CANADA_CODES.add("604");
CANADA_CODES.add("613");
CANADA_CODES.add("639");
CANADA_CODES.add("647");
CANADA_CODES.add("672");
CANADA_CODES.add("705");
CANADA_CODES.add("709");
CANADA_CODES.add("742");
CANADA_CODES.add("778");
CANADA_CODES.add("780");
CANADA_CODES.add("782");
CANADA_CODES.add("807");
CANADA_CODES.add("819");
CANADA_CODES.add("825");
CANADA_CODES.add("867");
CANADA_CODES.add("873");
CANADA_CODES.add("902");
CANADA_CODES.add("905");
}
protected SparseArray<ArrayList<Country>> mCountriesMap = new SparseArray<ArrayList<Country>>();
protected PhoneNumberUtil mPhoneNumberUtil = PhoneNumberUtil.getInstance();
protected Spinner mSpinner;
protected String mLastEnteredPhone;
protected EditText mPhoneEdit;
protected CountryAdapter mAdapter;
protected TextView mBtnLink;
protected AdapterView.OnItemSelectedListener mOnItemSelectedListener = new AdapterView.OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
Country c = (Country) mSpinner.getItemAtPosition(position);
if (mLastEnteredPhone != null && mLastEnteredPhone.startsWith(c.getCountryCodeStr())) {
return;
}
mPhoneEdit.getText().clear();
mPhoneEdit.getText().insert(mPhoneEdit.getText().length() > 0 ? 1 : 0, String.valueOf(c.getCountryCode()));
mPhoneEdit.setSelection(mPhoneEdit.length());
mLastEnteredPhone = null;
}
@Override
public void onNothingSelected(AdapterView<?> parent) {
}
};
protected OnPhoneChangedListener mOnPhoneChangedListener = new OnPhoneChangedListener() {
@Override
public void onPhoneChanged(String phone) {
try {
mLastEnteredPhone = phone;
Phonenumber.PhoneNumber p = mPhoneNumberUtil.parse(phone, null);
ArrayList<Country> list = mCountriesMap.get(p.getCountryCode());
Country country = null;
if (list != null) {
if (p.getCountryCode() == 1) {
String num = String.valueOf(p.getNationalNumber());
if (num.length() >= 3) {
String code = num.substring(0, 3);
if (CANADA_CODES.contains(code)) {
for (Country c : list) {
// Canada has priority 1, US has priority 0
if (c.getPriority() == 1) {
country = c;
break;
}
}
}
else if (DO_CODES.contains(code)) {
for (Country c : list) {
// Dominican Republic has priority 2
if (c.getPriority() == 2) {
country = c;
break;
}
}
}
else if (PR_CODES.contains(code)) {
for (Country c : list) {
// Puerto Rico has priority 3
if (c.getPriority() == 3) {
country = c;
break;
}
}
}
}
}
if (country == null) {
for (Country c : list) {
if (c.getPriority() == 0) {
country = c;
break;
}
}
}
}
if (country != null) {
final int position = country.getNum();
mSpinner.post(new Runnable() {
@Override
public void run() {
mSpinner.setSelection(position);
}
});
}
} catch (NumberParseException ignore) {
}
}
};
protected void initUI(View rootView) {
mSpinner = (Spinner) rootView.findViewById(R.id.spinner);
mSpinner.setOnItemSelectedListener(mOnItemSelectedListener);
mAdapter = new CountryAdapter(getActivity());
mSpinner.setAdapter(mAdapter);
mPhoneEdit = (EditText) rootView.findViewById(R.id.phone);
mPhoneEdit.addTextChangedListener(new CustomPhoneNumberFormattingTextWatcher(mOnPhoneChangedListener));
InputFilter filter = new InputFilter() {
public CharSequence filter(CharSequence source, int start, int end,
Spanned dest, int dstart, int dend) {
for (int i = start; i < end; i++) {
char c = source.charAt(i);
if (dstart > 0 && !Character.isDigit(c)) {
return "";
}
}
return null;
}
};
mPhoneEdit.setFilters(new InputFilter[]{filter});
mBtnLink = (TextView) rootView.findViewById(R.id.btn_send);
mBtnLink.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
send();
}
});
mPhoneEdit.setImeOptions(EditorInfo.IME_ACTION_SEND);
mPhoneEdit.setImeActionLabel(getString(R.string.label_send), EditorInfo.IME_ACTION_SEND);
mPhoneEdit.setOnEditorActionListener(new TextView.OnEditorActionListener() {
@Override
public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
if (actionId == EditorInfo.IME_ACTION_SEND) {
send();
return true;
}
return false;
}
});
}
protected void initCodes(Context context) {
new AsyncPhoneInitTask(context).execute();
}
protected class AsyncPhoneInitTask extends AsyncTask<Void, Void, ArrayList<Country>> {
private int mSpinnerPosition = -1;
private Context mContext;
public AsyncPhoneInitTask(Context context) {
mContext = context;
}
@Override
protected ArrayList<Country> doInBackground(Void... params) {
ArrayList<Country> data = new ArrayList<Country>(233);
BufferedReader reader = null;
try {
reader = new BufferedReader(new InputStreamReader(mContext.getApplicationContext().getAssets().open("countries.dat"), "UTF-8"));
// do reading, usually loop until end of file reading
String line;
int i = 0;
while ((line = reader.readLine()) != null) {
//process line
Country c = new Country(mContext, line, i);
data.add(c);
ArrayList<Country> list = mCountriesMap.get(c.getCountryCode());
if (list == null) {
list = new ArrayList<Country>();
mCountriesMap.put(c.getCountryCode(), list);
}
list.add(c);
i++;
}
} catch (IOException e) {
//log the exception
} finally {
if (reader != null) {
try {
reader.close();
} catch (IOException e) {
//log the exception
}
}
}
if (!TextUtils.isEmpty(mPhoneEdit.getText())) {
return data;
}
String countryRegion = PhoneUtils.getCountryRegionFromPhone(mContext);
int code = mPhoneNumberUtil.getCountryCodeForRegion(countryRegion);
ArrayList<Country> list = mCountriesMap.get(code);
if (list != null) {
for (Country c : list) {
if (c.getPriority() == 0) {
mSpinnerPosition = c.getNum();
break;
}
}
}
return data;
}
@Override
protected void onPostExecute(ArrayList<Country> data) {
mAdapter.addAll(data);
if (mSpinnerPosition > 0) {
mSpinner.setSelection(mSpinnerPosition);
}
}
}
protected abstract void send();
protected String validate() {
String region = null;
String phone = null;
if (mLastEnteredPhone != null) {
try {
Phonenumber.PhoneNumber p = mPhoneNumberUtil.parse(mLastEnteredPhone, null);
StringBuilder sb = new StringBuilder(16);
sb.append('+').append(p.getCountryCode()).append(p.getNationalNumber());
phone = sb.toString();
region = mPhoneNumberUtil.getRegionCodeForNumber(p);
} catch (NumberParseException ignore) {
}
}
if (region != null) {
return phone;
} else {
return null;
}
}
protected void hideKeyboard(View v) {
InputMethodManager imm = (InputMethodManager) v.getContext().getApplicationContext().getSystemService(Context.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(v.getWindowToken(), 0);
}
protected void showKeyboard(View v) {
InputMethodManager imm = (InputMethodManager) v.getContext().getApplicationContext().getSystemService(Context.INPUT_METHOD_SERVICE);
imm.toggleSoftInput(InputMethodManager.SHOW_FORCED, 0);
}
}