Full Code of egslava/edittext-mask for AI

master 0228a1c3791b cached
38 files
56.5 KB
15.8k tokens
80 symbols
1 requests
Download .txt
Repository: egslava/edittext-mask
Branch: master
Commit: 0228a1c3791b
Files: 38
Total size: 56.5 KB

Directory structure:
gitextract_1lvie_ry/

├── .gitignore
├── .travis.yml
├── LICENSE
├── MaskedEditText/
│   ├── build.gradle
│   └── src/
│       ├── androidTest/
│       │   ├── AndroidManifest.xml
│       │   ├── java/
│       │   │   └── ru/
│       │   │       └── egslava/
│       │   │           └── lib_phone/
│       │   │               ├── MainActivityTest.java
│       │   │               ├── TestActivity.java
│       │   │               └── actions/
│       │   │                   ├── HintViewAction.java
│       │   │                   ├── KeepHintViewAction.java
│       │   │                   └── SetTextViewAction.java
│       │   └── res/
│       │       ├── layout/
│       │       │   └── activity_main.xml
│       │       └── values/
│       │           └── styles.xml
│       └── main/
│           ├── AndroidManifest.xml
│           ├── java/
│           │   └── br/
│           │       └── com/
│           │           └── sapereaude/
│           │               └── maskedEditText/
│           │                   ├── MaskedEditText.java
│           │                   ├── Range.java
│           │                   └── RawText.java
│           └── res/
│               └── values/
│                   └── attrs.xml
├── README.md
├── app/
│   ├── .gitignore
│   ├── build.gradle
│   ├── proguard-rules.pro
│   └── src/
│       ├── androidTest/
│       │   └── java/
│       │       └── ru/
│       │           └── egslava/
│       │               └── edittextphonenumber/
│       │                   └── ApplicationTest.java
│       └── main/
│           ├── AndroidManifest.xml
│           ├── java/
│           │   └── ru/
│           │       └── egslava/
│           │           └── edittextphonenumber/
│           │               └── MainActivity.java
│           └── res/
│               ├── layout/
│               │   └── activity_main.xml
│               ├── menu/
│               │   └── main.xml
│               ├── values/
│               │   ├── dimens.xml
│               │   ├── strings.xml
│               │   └── styles.xml
│               ├── values-ru/
│               │   └── strings.xml
│               └── values-w820dp/
│                   └── dimens.xml
├── build.gradle
├── gradle/
│   └── wrapper/
│       ├── gradle-wrapper.jar
│       └── gradle-wrapper.properties
├── gradle.properties
├── gradlew
├── gradlew.bat
└── settings.gradle

================================================
FILE CONTENTS
================================================

================================================
FILE: .gitignore
================================================
##### Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm #####
##### (thanks to https://github.com/github/gitignore/blob/master/Global/JetBrains.gitignore) #####

/*.iml
*.iml
*/build

## Directory-based project format:
.idea/
# if you remove the above rule, at least ignore the following:

# User-specific stuff:
# .idea/workspace.xml
# .idea/tasks.xml
# .idea/dictionaries

# Sensitive or high-churn files:
# .idea/dataSources.ids
# .idea/dataSources.xml
# .idea/sqlDataSources.xml
# .idea/dynamic.xml
# .idea/uiDesigner.xml

# Gradle:
# .idea/gradle.xml
# .idea/libraries

# Mongo Explorer plugin:
# .idea/mongoSettings.xml

## File-based project format:
*.ipr
*.iws

## Plugin-specific files:

# IntelliJ
out/

# mpeltonen/sbt-idea plugin
.idea_modules/

# JIRA plugin
atlassian-ide-plugin.xml

# Crashlytics plugin (for Android Studio and IntelliJ)
com_crashlytics_export_strings.xml


###### Android Studio generated #####
.gradle
/local.properties
/.idea/workspace.xml
.DS_Store
/build

# Built application files
*.apk
*.ap_

# Files for the Dalvik VM
*.dex

# Java class files
*.class

# Generated files
bin/
gen/

####### And standard github .gitignore for Android #####

# Proguard folder generated by Eclipse
proguard/

# Log Files
*.log


================================================
FILE: .travis.yml
================================================
language: android
jdk: oraclejdk8
sudo: false

android:
  components:
      - platform-tools
      - tools
      - build-tools-24.0.2
      - build-tools-25.0.2
      - android-22
      - android-24
      - android-25
      - sys-img-armeabi-v7a-android-22
      - sys-img-armeabi-v7a-android-25
      - extra-android-m2repository

#    # Uncomment the lines below if you want to
#    # use the latest revision of Android SDK Tools
#    - platform-tools
#    - tools
#
#    # The BuildTools version used by your project
#    - build-tools-25.0.2
#
#    # The SDK version used to compile your project
#    - android-25
#
#    # Additional components
#    - extra-google-google_play_services
#    - extra-google-m2repository
#    - extra-android-m2repository
#    - addon-google_apis-google-25
#
#    # Specify at least one system image,
#    # if you need to run emulator(s) during your tests
#    - sys-img-armeabi-v7a-android-22
#    - sys-img-armeabi-v7a-android-16

before_script:
  # Create and start emulator
  - echo no | android create avd --force -n test -t android-22 --abi armeabi-v7a
  - emulator -avd test -no-skin -no-audio -no-window &
  - android-wait-for-emulator
  - adb shell input keyevent 82 &

script: ./gradlew  -PbintrayUser=blah -PbintrayApikey=blah connectedAndroidTest


================================================
FILE: LICENSE
================================================
The MIT License (MIT)

Copyright (c) 2014 Slava Egorenkov

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.



================================================
FILE: MaskedEditText/build.gradle
================================================
plugins {
    id "com.jfrog.bintray" version "1.7.3"
}

apply plugin: 'com.android.library'
apply plugin: 'com.github.dcendents.android-maven'

String projectVersion = "1.0.5"
String projectGroup = "ru.egslava"

version = projectVersion
group = projectGroup

android {
    compileSdkVersion 25
    buildToolsVersion '25.0.2'


    defaultConfig {
        minSdkVersion 9
        targetSdkVersion 25
        versionCode 1
        versionName projectVersion
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
    }
}

dependencies {
    androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
        exclude group: 'com.android.support', module: 'support-annotations'
    })

    compile fileTree(dir: 'libs', include: ['*.jar'])
    compile 'com.android.support:appcompat-v7:25.2.0'

    testCompile 'junit:junit:4.12'
}


// bintray deploy ....
String projectName = "edittext-mask"
String projectDescription = GFileUtils.readFile(new File("README.md"))
String webUrl = "https://github.com/egslava/edittext-mask"
String gitUrl = "https://github.com/egslava/edittext-mask.git"


install {
    repositories.mavenInstaller {
        pom {
            project {
                packaging 'aar'
                
                name projectName
                description projectDescription
                url webUrl

                inceptionYear '2017' // HARDCODED

                licenses {
                    license {
                        name 'MIT'
                        url 'http://www.apache.org/licenses/LICENSE-2.0.txt'
                        distribution 'repo'
                    }
                }

                scm {
                    connection gitUrl
                    developerConnection gitUrl
                    url webUrl
                }
                developers {
                    developer {
                        id 'egslava'
                        name 'Slava Egorenkov'
                        email 'egslava@gmail.com'
                    }
                }
            }
        }
    }
}

// The end of the gradle file is for JCenter publication.
// The original code was written with look at Alexander Matveychuk's code
// and
// https://www.virag.si/2015/01/publishing-gradle-android-library-to-jcenter/

task sourcesJar(type: Jar) {
    from android.sourceSets.main.java.srcDirs
    classifier = 'sources'
}

task javadoc(type: Javadoc) {
    source = android.sourceSets.main.java.srcDirs
    classpath += project.files(android.getBootClasspath().join(File.pathSeparator))
}

task javadocJar(type: Jar, dependsOn: javadoc) {
    classifier = 'javadoc'
    from javadoc.destinationDir
}
artifacts {
    archives javadocJar
    archives sourcesJar
}

bintray {
    user = bintrayUser
    key = bintrayApikey

    configurations = ['archives']
    pkg {
        repo = "maven"
        name = projectName
        userOrg = user
//        projectUrl = webUrl
        vcsUrl = gitUrl
        licenses = ["MIT"]
        group = projectGroup
        publish = true

        version {
            name = projectVersion
//            desc = projectDescription
            vcsTag = projectVersion
        }
    }
}

================================================
FILE: MaskedEditText/src/androidTest/AndroidManifest.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="br.com.sapereaude.maskedEditText"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="10"
        android:targetSdkVersion="10" />

    <application >
        <activity android:name="ru.egslava.lib_phone.TestActivity"
            android:theme="@style/AppTheme"/>
    </application>

</manifest>

================================================
FILE: MaskedEditText/src/androidTest/java/ru/egslava/lib_phone/MainActivityTest.java
================================================
package ru.egslava.lib_phone;


import android.content.pm.ActivityInfo;
import android.support.test.espresso.action.ViewActions;
import android.support.test.filters.Suppress;
import android.support.test.rule.ActivityTestRule;
import android.support.test.runner.AndroidJUnit4;
import android.test.suitebuilder.annotation.LargeTest;

import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;

import java.security.InvalidParameterException;

import ru.egslava.lib_phone.actions.HintViewAction;

import static android.support.test.espresso.Espresso.onView;
import static android.support.test.espresso.action.ViewActions.clearText;
import static android.support.test.espresso.action.ViewActions.click;
import static android.support.test.espresso.action.ViewActions.closeSoftKeyboard;
import static android.support.test.espresso.action.ViewActions.typeText;
import static android.support.test.espresso.assertion.ViewAssertions.matches;
import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed;
import static android.support.test.espresso.matcher.ViewMatchers.withId;
import static android.support.test.espresso.matcher.ViewMatchers.withText;
import static org.hamcrest.Matchers.allOf;
import static ru.egslava.lib_phone.actions.KeepHintViewAction.dontKeepHints;
import static ru.egslava.lib_phone.actions.KeepHintViewAction.keepHints;

@LargeTest
@RunWith(AndroidJUnit4.class)
public class MainActivityTest {

    public static final int phone_input = br.com.sapereaude.maskedEditText.test.R.id.vControl;

    @Rule
    public ActivityTestRule<TestActivity> mActivityTestRule = new ActivityTestRule<>(TestActivity.class);

    @Test
    public void textTypingTest() {
        onView(
            allOf(
                withId(phone_input),
                isDisplayed())
        ).perform(click());

        // just in case, check again that it's the same view after the click
        onView(
            allOf(
                withId(phone_input),
                isDisplayed())
        ).perform(typeText("9997055671"));

        onView(
            allOf(
                withId(phone_input),
                withText("+7(999)705-56-71"),
                isDisplayed())
        ).perform(closeSoftKeyboard());

        onView( allOf(
            withId(phone_input),
            isDisplayed())
        ).check(matches(withText("+7(999)705-56-71")));
    }

    @Test
    public void saveInstanceStateTest() {
        onView(
            allOf(
                withId(phone_input),
                isDisplayed())
        ).perform(click());

        // just in case, check again that it's the same view after the click
        onView(
            allOf(
                withId(phone_input),
                isDisplayed())
        ).perform(typeText("9997055671"));

        onView(
            allOf(
                withId(phone_input),
                withText("+7(999)705-56-71"),
                isDisplayed())
        ).perform(closeSoftKeyboard());

        mActivityTestRule.getActivity().setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
        mActivityTestRule.getActivity().setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);

        onView( allOf(
            withId(phone_input),
            isDisplayed())
        ).check(matches(withText("+7(999)705-56-71")));
    }


    /**
     * After merging with Alexander Matveychuk, the demo app started to crash
     * if there's no any text and you rotate the phone
     */
    @Test
    public void saveInstanceStateTest2() {
        mActivityTestRule.getActivity().setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
        mActivityTestRule.getActivity().setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
    }

    /**
     * After setKeepHint(true) a hint should appeared.
     * After setKeepHint(false) a hint should disappear.
     */
    @Test
    public void setKeepHintTest() {
        onView(withId(phone_input))
                .perform(new HintViewAction("9997055671"))
                .perform(dontKeepHints)     // just to be sure

                // the first check. After setKeepHint(true) the hint should appear immediate
                .perform(ViewActions.typeText("999"))
                .perform(keepHints)
                .check(matches(withText("+7(999)705-56-71")))

                // the second check. After setKeepHint(false) the hint should disappear immediate
                .perform(dontKeepHints)
                .check(matches(withText("+7(999)")));
    }


    /**
     * If the text is empty changing of keepHint can lead to a crash.
     * It's the regression test
     */
    @Test
    public void setEmptyTextTest() {

        // given
        onView(withId(phone_input))
                .perform(new HintViewAction("9997055671"))

        // tests
                .perform(dontKeepHints)
                .check(matches(withText("+7(999)705-56-71")))
                .perform(keepHints)
                .check(matches(withText("+7(999)705-56-71")))
                .perform(dontKeepHints)

                // YES! Because the text is empty, user need to see a hint
                .check(matches(withText("+7(999)705-56-71")));
    }
    /**
     * It should keep state of keepHint after activity recreation :-/
     * It's the regression test
     */
    @Test
    @Suppress   // TODO
    public void keepHintAfterRotationTest() throws InterruptedException {

        // ======================================
        // if initial state was keepHint(false)

        // given
        onView(withId(phone_input))
                .perform(new HintViewAction("9997055671"))
                .perform(keepHints)
                .perform(typeText("999"))
                .check(matches(withText("+7(999)705-56-71")))
                .perform(dontKeepHints);

        // rotating screen
        final TestActivity a1 = mActivityTestRule.getActivity();
        a1.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);

        Thread.sleep(2500);
        final TestActivity a2 = mActivityTestRule.getActivity();
        a2.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
        Thread.sleep(2500);


        if (a1 != a2) {
            throw new InvalidParameterException("a1 != a2");
        }
        // tests
        onView(withId(phone_input))
                .check(matches(withText("+7(999)")));

        // ======================================
        // and if initial state was keepHint(true)

        onView(withId(phone_input))
                .perform(clearText())   // after previous test
                .perform(new HintViewAction("1234567890"))
                .perform(keepHints)
                .perform(typeText("999"))
                .check(matches(withText("+7(999)456-78-90")))
                ;

        // rotating screen
        mActivityTestRule.getActivity().setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
        Thread.sleep(5000);
        mActivityTestRule.getActivity().setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
        Thread.sleep(2500);


        // tests
        onView(withId(phone_input))
                .check(matches(withText("+7(999)456-78-90")));
    }
}


================================================
FILE: MaskedEditText/src/androidTest/java/ru/egslava/lib_phone/TestActivity.java
================================================
package ru.egslava.lib_phone;

import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;

/**
 * Created by egslava on 04/03/2017.
 */

public class TestActivity extends AppCompatActivity {
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(br.com.sapereaude.maskedEditText.test.R.layout.activity_main);
    }
}


================================================
FILE: MaskedEditText/src/androidTest/java/ru/egslava/lib_phone/actions/HintViewAction.java
================================================
package ru.egslava.lib_phone.actions;

import android.support.test.espresso.UiController;
import android.support.test.espresso.ViewAction;
import android.view.View;
import android.widget.TextView;

import org.hamcrest.Matcher;
import org.hamcrest.Matchers;

public class HintViewAction implements ViewAction {


    String hint;

    public HintViewAction(String hint) {
        this.hint = hint;
    }

    @Override
    public Matcher<View> getConstraints() {
        return Matchers.instanceOf(TextView.class);
    }

    @Override
    public String getDescription() {
        return "Set hints on view";
    }

    @Override
    public void perform(UiController uiController, View view) {
        ((TextView)view).setHint(hint);
    }
}

================================================
FILE: MaskedEditText/src/androidTest/java/ru/egslava/lib_phone/actions/KeepHintViewAction.java
================================================
package ru.egslava.lib_phone.actions;

import android.support.test.espresso.UiController;
import android.support.test.espresso.ViewAction;
import android.view.View;

import org.hamcrest.Matcher;
import org.hamcrest.Matchers;

import br.com.sapereaude.maskedEditText.MaskedEditText;

public enum KeepHintViewAction implements ViewAction {
    keepHints(true), dontKeepHints(false);


    boolean keepHint;

    KeepHintViewAction(boolean keepHint) {
        this.keepHint = keepHint;
    }

    @Override
    public Matcher<View> getConstraints() {
        return Matchers.instanceOf(MaskedEditText.class);
    }

    @Override
    public String getDescription() {
        return "Set keepHint on/off";
    }

    @Override
    public void perform(UiController uiController, View view) {
        ((MaskedEditText)view).setKeepHint(keepHint);
    }
}

================================================
FILE: MaskedEditText/src/androidTest/java/ru/egslava/lib_phone/actions/SetTextViewAction.java
================================================
package ru.egslava.lib_phone.actions;

import android.support.test.espresso.UiController;
import android.support.test.espresso.ViewAction;
import android.view.View;

import org.hamcrest.Matcher;

import br.com.sapereaude.maskedEditText.MaskedEditText;

import static org.hamcrest.Matchers.allOf;
import static org.hamcrest.Matchers.instanceOf;

public class SetTextViewAction implements ViewAction {

    private String value;

    public SetTextViewAction(String value) {
        this.value = value;
    }

    @SuppressWarnings("unchecked")
    @Override
    public Matcher<View> getConstraints() {
        return allOf(instanceOf(MaskedEditText.class));
    }

    @Override
    public void perform(UiController uiController, View view) {
        MaskedEditText maskedEditText = (MaskedEditText) view;
        maskedEditText.setText(maskedEditText.getRawText());
    }

    @Override
    public String getDescription() {
        return "replace text";
    }
};

================================================
FILE: MaskedEditText/src/androidTest/res/layout/activity_main.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:mask="http://schemas.android.com/apk/res-auto"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://schemas.android.com/apk/res/android">

    <br.com.sapereaude.maskedEditText.MaskedEditText
        android:id="@+id/vControl"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:inputType="phone"
        android:typeface="monospace"
        mask:allowed_chars="1234567890"
        mask:mask="+7(###)###-##-##"
        />

</LinearLayout>

================================================
FILE: MaskedEditText/src/androidTest/res/values/styles.xml
================================================
<resources>

    <!-- Base application theme. -->
    <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
        <!-- Customize your theme here. -->
    </style>

</resources>


================================================
FILE: MaskedEditText/src/main/AndroidManifest.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="br.com.sapereaude.maskedEditText" >

</manifest>

================================================
FILE: MaskedEditText/src/main/java/br/com/sapereaude/maskedEditText/MaskedEditText.java
================================================
package br.com.sapereaude.maskedEditText;

import android.content.Context;
import android.content.res.TypedArray;
import android.os.Bundle;
import android.os.Parcelable;
import android.support.v4.text.TextUtilsCompat;
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 static android.content.ContentValues.TAG;

public class MaskedEditText extends AppCompatEditText implements TextWatcher {

    public static final String SPACE = " ";
	private final OnEditorActionListener onEditorActionListener = 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;
			}
		}
	};
	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;
    private boolean shouldKeepText;

    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);
        boolean enableImeAction = attributes.getBoolean(R.styleable.MaskedEditText_enable_ime_action, false);

		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 if needed
		if (!enableImeAction) {
			setOnEditorActionListener(onEditorActionListener);
		} else {
			setOnEditorActionListener(null);
		}
		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;
		if(mask == null || mask.isEmpty()){
                    return;
                }
		generatePositionArrays();
                if (!shouldKeepText || rawText == null) {
                    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 setShouldKeepText(boolean shouldKeepText) {
            this.shouldKeepText = shouldKeepText;
        }

        public boolean isKeepingText() {
            return shouldKeepText;
        }

	public void setMask(String mask) {
		this.mask = mask;
		cleanUp();
	}

	public String getMask() {
		return this.mask;
	}

	public void setImeActionEnabled(boolean isEnabled) {
		if (isEnabled)
			setOnEditorActionListener(onEditorActionListener);
		else
			setOnEditorActionListener(null);
	}

	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];
		System.arraycopy(aux, 0, rawToMask, 0, charIndex);
	}

	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;
	}
}


================================================
FILE: MaskedEditText/src/main/java/br/com/sapereaude/maskedEditText/Range.java
================================================
package br.com.sapereaude.maskedEditText;

public class Range {
	private int start;
	private int end;

	Range() {
		start = -1;
		end = -1;
	}
	
	public int getStart() {
		return start;
	}
	
	public void setStart(int start) {
		this.start = start;
	}
	
	public int getEnd() {
		return end;
	}
	
	public void setEnd(int end) {
		this.end = end;
	}


}


================================================
FILE: MaskedEditText/src/main/java/br/com/sapereaude/maskedEditText/RawText.java
================================================
package br.com.sapereaude.maskedEditText;

/**
 * Raw text, another words TextWithout mask characters
 */
public class RawText {
	private String text;
	
	public RawText() {
		text = "";
	}

    /**
     * text = 012345678, range = 123 =&gt; text = 0456789
     * @param range given range
     */
	public void subtractFromString(Range range) {
		String firstPart = "";
		String lastPart = "";
		
		if(range.getStart() > 0 && range.getStart() <= text.length()) {
			firstPart = text.substring(0, range.getStart());
		}
		if(range.getEnd() >= 0 && range.getEnd() < text.length()) {
			lastPart = text.substring(range.getEnd(), text.length());
		}
		text = firstPart.concat(lastPart);
	}

	/**
	 * 
	 * @param newString New String to be added
	 * @param start Position to insert newString
	 * @param maxLength Maximum raw text length
	 * @return Number of added characters
	 */
	public int addToString(String newString, int start, int maxLength) {
		String firstPart = "";
		String lastPart = "";
		
		if(newString == null || newString.equals("")) {
			return 0;
		}
		else if(start < 0) {
			throw new IllegalArgumentException("Start position must be non-negative");
		}
		else if(start > text.length()) {
			throw new IllegalArgumentException("Start position must be less than the actual text length");
		}
		
		int count = newString.length();
		
		if(start > 0) {
			firstPart = text.substring(0, start);
		}
		if(start >= 0 && start < text.length()) {
			lastPart = text.substring(start, text.length());
		}
		if(text.length() + newString.length() > maxLength) {
			count = maxLength - text.length();
			newString = newString.substring(0, count);
		}
		text = firstPart.concat(newString).concat(lastPart);		
		return count;
	}

	public String getText() {
		return text;
	}

	public int length() {
		return text.length();
	}

	public char charAt(int position) {
		return text.charAt(position);
	}
}


================================================
FILE: MaskedEditText/src/main/res/values/attrs.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<resources>
	<declare-styleable name="MaskedEditText">
		<attr name="mask" format="string" />
        <attr name="allowed_chars" format="string" />
        <attr name="enable_ime_action" format="boolean" />
        <attr name="denied_chars" format="string" />
		<attr name="char_representation" format="string" />
		<attr name="keep_hint" format="boolean" />
	</declare-styleable>
</resources>


================================================
FILE: README.md
================================================
**Announcement**: [let's travel the world](https://github.com/egslava/edittext-mask/issues/65)! or let's just be guests :)

# MaskedEditText
[![Download](https://api.bintray.com/packages/egorenkov/maven/edittext-mask/images/download.svg) ](https://bintray.com/egorenkov/maven/edittext-mask/_latestVersion) [![Build Status](https://travis-ci.org/egslava/edittext-mask.svg?branch=master)](https://travis-ci.org/egslava/edittext-mask)

![MaskedEditText - the library for masked input of phone numbers, social security numbers and so on for Android](publish/README.gif)

**Announcement**: [let's travel the world](https://github.com/egslava/edittext-mask/issues/65)! or let's just be guests :)

This project derives from [toshikurauchi/MaskedEditText](https://github.com/toshikurauchi/MaskedEditText), but it's been adapted for gradle build system and has additional features:

1. filter allowed chars
2. filter denied chars
3. user can use chars from mask in his input (in original version of this library user couldn't use digit '7' in the '+7(XXX)XXX-XX-XX' pattern).
4. You can keep hints even when user started typing.

So it allows you to use masks for phones, urls, etc.

Enjoy!

<a href='https://play.google.com/store/apps/details?id=ru.egslava.edittextmaskdemo&utm_source=github&pcampaignid=MKT-Other-global-all-co-prtnr-py-PartBadge-Mar2515-1'><img width=200 alt='Get it on Google Play' src='https://play.google.com/intl/en_us/badges/images/generic/en_badge_web_generic.png'/></a>

*********************************
## en_US
MaskedEditText is a simple Android EditText with customizable input mask support.

For instance, you need user specified his phone in format +7(XXX)XXX-XX-XX. You also know user should have the only possibility to write digits but minuses, brackets and "+7" should appear automatically.

### Usage

Add this to your `build.gradle` :
```groovy
compile 'ru.egslava:MaskedEditText:1.0.5'
```
Or download project and plug it in as a library.

**Announcement**: [let's travel the world](https://github.com/egslava/edittext-mask/issues/65)! or let's just be guests :)

Add _xmlns:mask="http://schemas.android.com/apk/res-auto"_ to your layout xml root:

      <br.com.sapereaude.maskedEditText.MaskedEditText
        android:id="@+id/phone_input"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:inputType="phone"
        android:typeface="monospace"
        mask:allowed_chars="1234567890"
        mask:mask="+7(###)###-##-##"
        android:hint="1234567890"
        app:keep_hint="true"
        />    
Where _mask_ is the input mask you want and '#' is an editable position (will be replaced by a whitespace on screen).

You can optionally set the representation character (in case you don't want to use '#'):

    <br.com.sapereaude.maskedEditText.MaskedEditText
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        mask:mask="ccc.ccc.ccc-cc"
        mask:char_representation="c"
    />

**Announcement**: [let's travel the world](https://github.com/egslava/edittext-mask/issues/65)! or let's just be guests :)

You can also change the mask and the representation character programatically:

	MaskedEditText editText = (MaskedEditText) findViewById(R.id.my_edit_text)
	// Setting the representation character to '$'
	editText.setCharRepresentation('$');
	// Logging the representation character
	Log.i("Representation character", editText.getCharRepresentation());
	// Setting the mask
	editText.setMask("##/##/####");
	// Logging the mask
	Log.i("Mask", editText.getMask());
	
To enable Enter softkey action (IME action):

	<br.com.sapereaude.maskedEditText.MaskedEditText
	    ...
	    mask:enable_ime_action="true"
	    ...
	/>
    
**Announcement**: [let's travel the world](https://github.com/egslava/edittext-mask/issues/65)! or let's just be guests :)

Or programmatically:

	MaskedEditText editText = (MaskedEditText) findViewById(R.id.my_edit_text)
	editText.setImeActionEnabled(true);
	
*************************************************************************************************
## ru_RU

MaskedEditText - это всего лишь EditText, но с возможностью задавать произвольную маску.

Например, нужно ввести телефон в формате +7(XXX)XXX-XX-XX. Причём можно ввести только цифры, а скобочки, дефисы и "+7" должны подставляться самостоятельно.

### Использование

Вписать в `build.gradle`:
```groovy
compile 'ru.egslava:MaskedEditText:1.0.5'
```
или скачать проект и подключить как библиотеку.

Добавить _xmlns:mask="http://schemas.android.com/apk/res-auto"_ в корневой элемент файла разметки:

      <br.com.sapereaude.maskedEditText.MaskedEditText
        android:id="@+id/phone_input"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:inputType="phone"
        android:typeface="monospace"
        mask:allowed_chars="1234567890"
        mask:mask="+7(###)###-##-##"
        android:hint="1234567890"
        app:keep_hint="true"
        />

_mask_ задаёт требуемую маску, символ '#' задаёт редактируемую позицию (и будет заменён на пробел на экране).

Если использовать '#' нельзя, то можно попробовать использовать другой символ:

    <br.com.sapereaude.maskedEditText.MaskedEditText
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        mask:mask="ccc.ccc.ccc-cc"
        mask:char_representation="c"
    />

Кроме того, всё тоже самое можно сделать и программно:

	MaskedEditText editText = (MaskedEditText) findViewById(R.id.my_edit_text)
	// Setting the representation character to '$'
	editText.setCharRepresentation('$');
	// Logging the representation character
	Log.i("Representation character", editText.getCharRepresentation());
	// Setting the mask
	editText.setMask("##/##/####");
	// Logging the mask
	Log.i("Mask", editText.getMask());
	
Чтобы включить обработку нажатия Enter (IME action):

	<br.com.sapereaude.maskedEditText.MaskedEditText
	    ...
	    mask:enable_ime_action="true"
	    ...
	/>
    
Или программно:

	MaskedEditText editText = (MaskedEditText) findViewById(R.id.my_edit_text)
	editText.setImeActionEnabled(true);


================================================
FILE: app/.gitignore
================================================
/build


================================================
FILE: app/build.gradle
================================================
apply plugin: 'com.android.application'

android {
    compileSdkVersion 25
    buildToolsVersion '25.0.2'

    defaultConfig {
        applicationId "ru.egslava.edittextphonenumber"
        minSdkVersion 9
        targetSdkVersion 25
        versionCode 1
        versionName "1.0.0"
        testInstrumentationRunner 'android.support.test.runner.AndroidJUnitRunner'
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
}

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    compile 'com.android.support:appcompat-v7:25.2.0'
    compile project(':MaskedEditText')
    androidTestCompile 'com.android.support.test.espresso:espresso-core:2.2.2', {
        exclude group: 'com.android.support', module: 'support-annotations'
    }
}


================================================
FILE: app/proguard-rules.pro
================================================
# Add project specific ProGuard rules here.
# By default, the flags in this file are appended to flags specified
# in /Users/egslava/apps/sdk/tools/proguard/proguard-android.txt
# You can edit the include path and order by changing the proguardFiles
# directive in build.gradle.
#
# For more details, see
#   http://developer.android.com/guide/developing/tools/proguard.html

# Add any project specific keep options here:

# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
#   public *;
#}


================================================
FILE: app/src/androidTest/java/ru/egslava/edittextphonenumber/ApplicationTest.java
================================================
package ru.egslava.edittextphonenumber;

import android.app.Application;
import android.test.ApplicationTestCase;

/**
 * <a href="http://d.android.com/tools/testing/testing_android.html">Testing Fundamentals</a>
 */
public class ApplicationTest extends ApplicationTestCase<Application> {
    public ApplicationTest() {
        super(Application.class);
    }
}

================================================
FILE: app/src/main/AndroidManifest.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="ru.egslava.edittextphonenumber" >

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name=".MainActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>


================================================
FILE: app/src/main/java/ru/egslava/edittextphonenumber/MainActivity.java
================================================
package ru.egslava.edittextphonenumber;

import android.support.v7.app.ActionBarActivity;
import android.os.Bundle;
import android.text.InputFilter;
import android.text.Spanned;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.EditText;


import br.com.sapereaude.maskedEditText.MaskedEditText;

public class MainActivity extends ActionBarActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        MaskedEditText phone = (MaskedEditText)findViewById(R.id.phone_input);
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        int id = item.getItemId();
        if (id == R.id.action_settings) {
            return true;
        }
        return super.onOptionsItemSelected(item);
    }
}


================================================
FILE: app/src/main/res/layout/activity_main.xml
================================================
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    xmlns:mask="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    android:paddingBottom="@dimen/activity_vertical_margin"
    tools:context=".MainActivity"
    android:orientation="vertical">

    <TextView
        android:id="@+id/phone"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="@string/please_provide_phone_number"
        />

    <br.com.sapereaude.maskedEditText.MaskedEditText
        android:id="@+id/phone_input"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:inputType="phone"
        android:typeface="monospace"
        mask:allowed_chars="1234567890"
        android:hint="9081234567"
        android:textColorHint="@android:color/darker_gray"
        mask:mask="+7(###)###-##-##"
        mask:keep_hint="false" />

</LinearLayout>


================================================
FILE: app/src/main/res/menu/main.xml
================================================
<menu xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    tools:context=".MainActivity" >
    <item android:id="@+id/action_settings"
        android:title="@string/action_settings"
        android:orderInCategory="100"
        app:showAsAction="never" />
</menu>


================================================
FILE: app/src/main/res/values/dimens.xml
================================================
<resources>
    <!-- Default screen margins, per the Android Design guidelines. -->
    <dimen name="activity_horizontal_margin">16dp</dimen>
    <dimen name="activity_vertical_margin">16dp</dimen>
</resources>


================================================
FILE: app/src/main/res/values/strings.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<resources>

    <string name="app_name">EditTextPhoneNumber</string>
    <string name="hello_world">Hello world!</string>
    <string name="action_settings">Settings</string>
    <string name="please_provide_phone_number">Please, provide your phone number</string>

</resources>


================================================
FILE: app/src/main/res/values/styles.xml
================================================
<resources>

    <!-- Base application theme. -->
    <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
        <!-- Customize your theme here. -->
    </style>

</resources>


================================================
FILE: app/src/main/res/values-ru/strings.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<resources>

    <string name="app_name">EditTextPhoneNumber</string>
    <string name="hello_world">Hello world!</string>
    <string name="action_settings">Settings</string>
    <string name="please_provide_phone_number">Пожалуйста, укажите свой номер телефона</string>
</resources>


================================================
FILE: app/src/main/res/values-w820dp/dimens.xml
================================================
<resources>
    <!-- Example customization of dimensions originally defined in res/values/dimens.xml
         (such as screen margins) for screens with more than 820dp of available width. This
         would include 7" and 10" devices in landscape (~960dp and ~1280dp respectively). -->
    <dimen name="activity_horizontal_margin">64dp</dimen>
</resources>


================================================
FILE: build.gradle
================================================
// Top-level build file where you can add configuration options common to all sub-projects/modules.

buildscript {
    repositories {
        jcenter()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:2.2.3'
//        classpath 'com.github.dcendents:android-maven-plugin:1.2'
        // https://mvnrepository.com/artifact/com.github.dcendents/android-maven-gradle-plugin
        classpath group: 'com.github.dcendents', name: 'android-maven-gradle-plugin', version: '1.5'
//        classpath 'com.jfrog.bintray.gradle:gradle-bintray-plugin:1.0'
        // NOTE: Do not place your application dependencies here; they belong
        // in the individual module build.gradle files
    }
}
allprojects {
    repositories {
        jcenter()
    }
}

================================================
FILE: gradle/wrapper/gradle-wrapper.properties
================================================
#Wed Apr 10 15:27:10 PDT 2013
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-3.3-all.zip

================================================
FILE: gradle.properties
================================================
# Project-wide Gradle settings.

# IDE (e.g. Android Studio) users:
# Settings specified in this file will override any Gradle settings
# configured through the IDE.

# For more details on how to configure your build environment visit
# http://www.gradle.org/docs/current/userguide/build_environment.html

# Specifies the JVM arguments used for the daemon process.
# The setting is particularly useful for tweaking memory settings.
# Default value: -Xmx10248m -XX:MaxPermSize=256m
 org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8

# When configured, Gradle will run in incubating parallel mode.
# This option should only be used with decoupled projects. More details, visit
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
org.gradle.parallel=true
org.gradle.daemon=true

================================================
FILE: gradlew
================================================
#!/usr/bin/env bash

##############################################################################
##
##  Gradle start up script for UN*X
##
##############################################################################

# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS=""

APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"`

# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"

warn ( ) {
    echo "$*"
}

die ( ) {
    echo
    echo "$*"
    echo
    exit 1
}

# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
case "`uname`" in
  CYGWIN* )
    cygwin=true
    ;;
  Darwin* )
    darwin=true
    ;;
  MINGW* )
    msys=true
    ;;
esac

# For Cygwin, ensure paths are in UNIX format before anything is touched.
if $cygwin ; then
    [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
fi

# Attempt to set APP_HOME
# Resolve links: $0 may be a link
PRG="$0"
# Need this for relative symlinks.
while [ -h "$PRG" ] ; do
    ls=`ls -ld "$PRG"`
    link=`expr "$ls" : '.*-> \(.*\)$'`
    if expr "$link" : '/.*' > /dev/null; then
        PRG="$link"
    else
        PRG=`dirname "$PRG"`"/$link"
    fi
done
SAVED="`pwd`"
cd "`dirname \"$PRG\"`/" >&-
APP_HOME="`pwd -P`"
cd "$SAVED" >&-

CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar

# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
    if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
        # IBM's JDK on AIX uses strange locations for the executables
        JAVACMD="$JAVA_HOME/jre/sh/java"
    else
        JAVACMD="$JAVA_HOME/bin/java"
    fi
    if [ ! -x "$JAVACMD" ] ; then
        die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME

Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
    fi
else
    JAVACMD="java"
    which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.

Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi

# Increase the maximum file descriptors if we can.
if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
    MAX_FD_LIMIT=`ulimit -H -n`
    if [ $? -eq 0 ] ; then
        if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
            MAX_FD="$MAX_FD_LIMIT"
        fi
        ulimit -n $MAX_FD
        if [ $? -ne 0 ] ; then
            warn "Could not set maximum file descriptor limit: $MAX_FD"
        fi
    else
        warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
    fi
fi

# For Darwin, add options to specify how the application appears in the dock
if $darwin; then
    GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
fi

# For Cygwin, switch paths to Windows format before running java
if $cygwin ; then
    APP_HOME=`cygpath --path --mixed "$APP_HOME"`
    CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`

    # We build the pattern for arguments to be converted via cygpath
    ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
    SEP=""
    for dir in $ROOTDIRSRAW ; do
        ROOTDIRS="$ROOTDIRS$SEP$dir"
        SEP="|"
    done
    OURCYGPATTERN="(^($ROOTDIRS))"
    # Add a user-defined pattern to the cygpath arguments
    if [ "$GRADLE_CYGPATTERN" != "" ] ; then
        OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
    fi
    # Now convert the arguments - kludge to limit ourselves to /bin/sh
    i=0
    for arg in "$@" ; do
        CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
        CHECK2=`echo "$arg"|egrep -c "^-"`                                 ### Determine if an option

        if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then                    ### Added a condition
            eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
        else
            eval `echo args$i`="\"$arg\""
        fi
        i=$((i+1))
    done
    case $i in
        (0) set -- ;;
        (1) set -- "$args0" ;;
        (2) set -- "$args0" "$args1" ;;
        (3) set -- "$args0" "$args1" "$args2" ;;
        (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
        (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
        (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
        (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
        (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
        (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
    esac
fi

# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
function splitJvmOpts() {
    JVM_OPTS=("$@")
}
eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"

exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"


================================================
FILE: gradlew.bat
================================================
@if "%DEBUG%" == "" @echo off
@rem ##########################################################################
@rem
@rem  Gradle startup script for Windows
@rem
@rem ##########################################################################

@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal

@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS=

set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%

@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome

set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto init

echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.

goto fail

:findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe

if exist "%JAVA_EXE%" goto init

echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.

goto fail

:init
@rem Get command-line arguments, handling Windowz variants

if not "%OS%" == "Windows_NT" goto win9xME_args
if "%@eval[2+2]" == "4" goto 4NT_args

:win9xME_args
@rem Slurp the command line arguments.
set CMD_LINE_ARGS=
set _SKIP=2

:win9xME_args_slurp
if "x%~1" == "x" goto execute

set CMD_LINE_ARGS=%*
goto execute

:4NT_args
@rem Get arguments from the 4NT Shell from JP Software
set CMD_LINE_ARGS=%$

:execute
@rem Setup the command line

set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar

@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%

:end
@rem End local scope for the variables with windows NT shell
if "%ERRORLEVEL%"=="0" goto mainEnd

:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
if  not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
exit /b 1

:mainEnd
if "%OS%"=="Windows_NT" endlocal

:omega


================================================
FILE: settings.gradle
================================================
include ':app', ':MaskedEditText'
Download .txt
gitextract_1lvie_ry/

├── .gitignore
├── .travis.yml
├── LICENSE
├── MaskedEditText/
│   ├── build.gradle
│   └── src/
│       ├── androidTest/
│       │   ├── AndroidManifest.xml
│       │   ├── java/
│       │   │   └── ru/
│       │   │       └── egslava/
│       │   │           └── lib_phone/
│       │   │               ├── MainActivityTest.java
│       │   │               ├── TestActivity.java
│       │   │               └── actions/
│       │   │                   ├── HintViewAction.java
│       │   │                   ├── KeepHintViewAction.java
│       │   │                   └── SetTextViewAction.java
│       │   └── res/
│       │       ├── layout/
│       │       │   └── activity_main.xml
│       │       └── values/
│       │           └── styles.xml
│       └── main/
│           ├── AndroidManifest.xml
│           ├── java/
│           │   └── br/
│           │       └── com/
│           │           └── sapereaude/
│           │               └── maskedEditText/
│           │                   ├── MaskedEditText.java
│           │                   ├── Range.java
│           │                   └── RawText.java
│           └── res/
│               └── values/
│                   └── attrs.xml
├── README.md
├── app/
│   ├── .gitignore
│   ├── build.gradle
│   ├── proguard-rules.pro
│   └── src/
│       ├── androidTest/
│       │   └── java/
│       │       └── ru/
│       │           └── egslava/
│       │               └── edittextphonenumber/
│       │                   └── ApplicationTest.java
│       └── main/
│           ├── AndroidManifest.xml
│           ├── java/
│           │   └── ru/
│           │       └── egslava/
│           │           └── edittextphonenumber/
│           │               └── MainActivity.java
│           └── res/
│               ├── layout/
│               │   └── activity_main.xml
│               ├── menu/
│               │   └── main.xml
│               ├── values/
│               │   ├── dimens.xml
│               │   ├── strings.xml
│               │   └── styles.xml
│               ├── values-ru/
│               │   └── strings.xml
│               └── values-w820dp/
│                   └── dimens.xml
├── build.gradle
├── gradle/
│   └── wrapper/
│       ├── gradle-wrapper.jar
│       └── gradle-wrapper.properties
├── gradle.properties
├── gradlew
├── gradlew.bat
└── settings.gradle
Download .txt
SYMBOL INDEX (80 symbols across 10 files)

FILE: MaskedEditText/src/androidTest/java/ru/egslava/lib_phone/MainActivityTest.java
  class MainActivityTest (line 32) | @LargeTest
    method textTypingTest (line 41) | @Test
    method saveInstanceStateTest (line 69) | @Test
    method saveInstanceStateTest2 (line 105) | @Test
    method setKeepHintTest (line 115) | @Test
    method setEmptyTextTest (line 136) | @Test
    method keepHintAfterRotationTest (line 157) | @Test

FILE: MaskedEditText/src/androidTest/java/ru/egslava/lib_phone/TestActivity.java
  class TestActivity (line 10) | public class TestActivity extends AppCompatActivity {
    method onCreate (line 11) | @Override

FILE: MaskedEditText/src/androidTest/java/ru/egslava/lib_phone/actions/HintViewAction.java
  class HintViewAction (line 11) | public class HintViewAction implements ViewAction {
    method HintViewAction (line 16) | public HintViewAction(String hint) {
    method getConstraints (line 20) | @Override
    method getDescription (line 25) | @Override
    method perform (line 30) | @Override

FILE: MaskedEditText/src/androidTest/java/ru/egslava/lib_phone/actions/KeepHintViewAction.java
  type KeepHintViewAction (line 12) | public enum KeepHintViewAction implements ViewAction {
    method KeepHintViewAction (line 18) | KeepHintViewAction(boolean keepHint) {
    method getConstraints (line 22) | @Override
    method getDescription (line 27) | @Override
    method perform (line 32) | @Override

FILE: MaskedEditText/src/androidTest/java/ru/egslava/lib_phone/actions/SetTextViewAction.java
  class SetTextViewAction (line 14) | public class SetTextViewAction implements ViewAction {
    method SetTextViewAction (line 18) | public SetTextViewAction(String value) {
    method getConstraints (line 22) | @SuppressWarnings("unchecked")
    method perform (line 28) | @Override
    method getDescription (line 34) | @Override

FILE: MaskedEditText/src/main/java/br/com/sapereaude/maskedEditText/MaskedEditText.java
  class MaskedEditText (line 21) | public class MaskedEditText extends AppCompatEditText implements TextWat...
    method onEditorAction (line 25) | @Override
    method MaskedEditText (line 56) | public MaskedEditText(Context context) {
    method MaskedEditText (line 61) | public MaskedEditText(Context context, AttributeSet attrs) {
    method onSaveInstanceState (line 93) | @Override
    method onRestoreInstanceState (line 103) | @Override
    method setText (line 114) | @Override
    method setOnFocusChangeListener (line 122) | @Override
    method cleanUp (line 127) | private void cleanUp() {
    method findLastValidMaskPosition (line 168) | private int findLastValidMaskPosition() {
    method hasHint (line 175) | private boolean hasHint() {
    method MaskedEditText (line 179) | public MaskedEditText(Context context, AttributeSet attrs, int defStyl...
    method setShouldKeepText (line 184) | public void setShouldKeepText(boolean shouldKeepText) {
    method isKeepingText (line 188) | public boolean isKeepingText() {
    method setMask (line 192) | public void setMask(String mask) {
    method getMask (line 197) | public String getMask() {
    method setImeActionEnabled (line 201) | public void setImeActionEnabled(boolean isEnabled) {
    method getRawText (line 208) | public String getRawText() {
    method setCharRepresentation (line 212) | public void setCharRepresentation(char charRepresentation) {
    method getCharRepresentation (line 217) | public char getCharRepresentation() {
    method generatePositionArrays (line 229) | private void generatePositionArrays() {
    method init (line 259) | private void init() {
    method beforeTextChanged (line 263) | @Override
    method erasingStart (line 285) | private int erasingStart(int start) {
    method onTextChanged (line 292) | @Override
    method afterTextChanged (line 315) | @Override
    method isKeepHint (line 335) | public boolean isKeepHint() {
    method setKeepHint (line 339) | public void setKeepHint(boolean keepHint) {
    method onSelectionChanged (line 344) | @Override
    method fixSelection (line 378) | private int fixSelection(int selection) {
    method nextValidPosition (line 386) | private int nextValidPosition(int currentPosition) {
    method previousValidPosition (line 394) | private int previousValidPosition(int currentPosition) {
    method lastValidPosition (line 404) | private int lastValidPosition() {
    method makeMaskedText (line 412) | private String makeMaskedText() {
    method makeMaskedTextWithHint (line 431) | private CharSequence makeMaskedTextWithHint() {
    method calculateRange (line 454) | private Range calculateRange(int start, int end) {
    method clear (line 476) | private String clear(String string) {

FILE: MaskedEditText/src/main/java/br/com/sapereaude/maskedEditText/Range.java
  class Range (line 3) | public class Range {
    method Range (line 7) | Range() {
    method getStart (line 12) | public int getStart() {
    method setStart (line 16) | public void setStart(int start) {
    method getEnd (line 20) | public int getEnd() {
    method setEnd (line 24) | public void setEnd(int end) {

FILE: MaskedEditText/src/main/java/br/com/sapereaude/maskedEditText/RawText.java
  class RawText (line 6) | public class RawText {
    method RawText (line 9) | public RawText() {
    method subtractFromString (line 17) | public void subtractFromString(Range range) {
    method addToString (line 37) | public int addToString(String newString, int start, int maxLength) {
    method getText (line 67) | public String getText() {
    method length (line 71) | public int length() {
    method charAt (line 75) | public char charAt(int position) {

FILE: app/src/androidTest/java/ru/egslava/edittextphonenumber/ApplicationTest.java
  class ApplicationTest (line 9) | public class ApplicationTest extends ApplicationTestCase<Application> {
    method ApplicationTest (line 10) | public ApplicationTest() {

FILE: app/src/main/java/ru/egslava/edittextphonenumber/MainActivity.java
  class MainActivity (line 15) | public class MainActivity extends ActionBarActivity {
    method onCreate (line 17) | @Override
    method onCreateOptionsMenu (line 24) | @Override
    method onOptionsItemSelected (line 30) | @Override
Condensed preview — 38 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (65K chars).
[
  {
    "path": ".gitignore",
    "chars": 1268,
    "preview": "##### Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm #####\n##### (thanks to https://github.com/gi"
  },
  {
    "path": ".travis.yml",
    "chars": 1295,
    "preview": "language: android\njdk: oraclejdk8\nsudo: false\n\nandroid:\n  components:\n      - platform-tools\n      - tools\n      - build"
  },
  {
    "path": "LICENSE",
    "chars": 1083,
    "preview": "The MIT License (MIT)\n\nCopyright (c) 2014 Slava Egorenkov\n\nPermission is hereby granted, free of charge, to any person o"
  },
  {
    "path": "MaskedEditText/build.gradle",
    "chars": 3215,
    "preview": "plugins {\n    id \"com.jfrog.bintray\" version \"1.7.3\"\n}\n\napply plugin: 'com.android.library'\napply plugin: 'com.github.dc"
  },
  {
    "path": "MaskedEditText/src/androidTest/AndroidManifest.xml",
    "chars": 470,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    package="
  },
  {
    "path": "MaskedEditText/src/androidTest/java/ru/egslava/lib_phone/MainActivityTest.java",
    "chars": 7280,
    "preview": "package ru.egslava.lib_phone;\n\n\nimport android.content.pm.ActivityInfo;\nimport android.support.test.espresso.action.View"
  },
  {
    "path": "MaskedEditText/src/androidTest/java/ru/egslava/lib_phone/TestActivity.java",
    "chars": 413,
    "preview": "package ru.egslava.lib_phone;\n\nimport android.os.Bundle;\nimport android.support.v7.app.AppCompatActivity;\n\n/**\n * Create"
  },
  {
    "path": "MaskedEditText/src/androidTest/java/ru/egslava/lib_phone/actions/HintViewAction.java",
    "chars": 740,
    "preview": "package ru.egslava.lib_phone.actions;\n\nimport android.support.test.espresso.UiController;\nimport android.support.test.es"
  },
  {
    "path": "MaskedEditText/src/androidTest/java/ru/egslava/lib_phone/actions/KeepHintViewAction.java",
    "chars": 848,
    "preview": "package ru.egslava.lib_phone.actions;\n\nimport android.support.test.espresso.UiController;\nimport android.support.test.es"
  },
  {
    "path": "MaskedEditText/src/androidTest/java/ru/egslava/lib_phone/actions/SetTextViewAction.java",
    "chars": 963,
    "preview": "package ru.egslava.lib_phone.actions;\n\nimport android.support.test.espresso.UiController;\nimport android.support.test.es"
  },
  {
    "path": "MaskedEditText/src/androidTest/res/layout/activity_main.xml",
    "chars": 765,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmln"
  },
  {
    "path": "MaskedEditText/src/androidTest/res/values/styles.xml",
    "chars": 194,
    "preview": "<resources>\n\n    <!-- Base application theme. -->\n    <style name=\"AppTheme\" parent=\"Theme.AppCompat.Light.DarkActionBar"
  },
  {
    "path": "MaskedEditText/src/main/AndroidManifest.xml",
    "chars": 169,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    package="
  },
  {
    "path": "MaskedEditText/src/main/java/br/com/sapereaude/maskedEditText/MaskedEditText.java",
    "chars": 14251,
    "preview": "package br.com.sapereaude.maskedEditText;\n\nimport android.content.Context;\nimport android.content.res.TypedArray;\nimport"
  },
  {
    "path": "MaskedEditText/src/main/java/br/com/sapereaude/maskedEditText/Range.java",
    "chars": 351,
    "preview": "package br.com.sapereaude.maskedEditText;\n\npublic class Range {\n\tprivate int start;\n\tprivate int end;\n\n\tRange() {\n\t\tstar"
  },
  {
    "path": "MaskedEditText/src/main/java/br/com/sapereaude/maskedEditText/RawText.java",
    "chars": 1898,
    "preview": "package br.com.sapereaude.maskedEditText;\n\n/**\n * Raw text, another words TextWithout mask characters\n */\npublic class R"
  },
  {
    "path": "MaskedEditText/src/main/res/values/attrs.xml",
    "chars": 433,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n\t<declare-styleable name=\"MaskedEditText\">\n\t\t<attr name=\"mask\" format"
  },
  {
    "path": "README.md",
    "chars": 6186,
    "preview": "**Announcement**: [let's travel the world](https://github.com/egslava/edittext-mask/issues/65)! or let's just be guests "
  },
  {
    "path": "app/.gitignore",
    "chars": 7,
    "preview": "/build\n"
  },
  {
    "path": "app/build.gradle",
    "chars": 883,
    "preview": "apply plugin: 'com.android.application'\n\nandroid {\n    compileSdkVersion 25\n    buildToolsVersion '25.0.2'\n\n    defaultC"
  },
  {
    "path": "app/proguard-rules.pro",
    "chars": 654,
    "preview": "# Add project specific ProGuard rules here.\n# By default, the flags in this file are appended to flags specified\n# in /U"
  },
  {
    "path": "app/src/androidTest/java/ru/egslava/edittextphonenumber/ApplicationTest.java",
    "chars": 361,
    "preview": "package ru.egslava.edittextphonenumber;\n\nimport android.app.Application;\nimport android.test.ApplicationTestCase;\n\n/**\n "
  },
  {
    "path": "app/src/main/AndroidManifest.xml",
    "chars": 697,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    package="
  },
  {
    "path": "app/src/main/java/ru/egslava/edittextphonenumber/MainActivity.java",
    "chars": 1045,
    "preview": "package ru.egslava.edittextphonenumber;\n\nimport android.support.v7.app.ActionBarActivity;\nimport android.os.Bundle;\nimpo"
  },
  {
    "path": "app/src/main/res/layout/activity_main.xml",
    "chars": 1249,
    "preview": "<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/too"
  },
  {
    "path": "app/src/main/res/menu/main.xml",
    "chars": 382,
    "preview": "<menu xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\""
  },
  {
    "path": "app/src/main/res/values/dimens.xml",
    "chars": 211,
    "preview": "<resources>\n    <!-- Default screen margins, per the Android Design guidelines. -->\n    <dimen name=\"activity_horizontal"
  },
  {
    "path": "app/src/main/res/values/strings.xml",
    "chars": 319,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n\n    <string name=\"app_name\">EditTextPhoneNumber</string>\n    <string"
  },
  {
    "path": "app/src/main/res/values/styles.xml",
    "chars": 194,
    "preview": "<resources>\n\n    <!-- Base application theme. -->\n    <style name=\"AppTheme\" parent=\"Theme.AppCompat.Light.DarkActionBar"
  },
  {
    "path": "app/src/main/res/values-ru/strings.xml",
    "chars": 324,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n\n    <string name=\"app_name\">EditTextPhoneNumber</string>\n    <string"
  },
  {
    "path": "app/src/main/res/values-w820dp/dimens.xml",
    "chars": 358,
    "preview": "<resources>\n    <!-- Example customization of dimensions originally defined in res/values/dimens.xml\n         (such as s"
  },
  {
    "path": "build.gradle",
    "chars": 770,
    "preview": "// Top-level build file where you can add configuration options common to all sub-projects/modules.\n\nbuildscript {\n    r"
  },
  {
    "path": "gradle/wrapper/gradle-wrapper.properties",
    "chars": 229,
    "preview": "#Wed Apr 10 15:27:10 PDT 2013\ndistributionBase=GRADLE_USER_HOME\ndistributionPath=wrapper/dists\nzipStoreBase=GRADLE_USER_"
  },
  {
    "path": "gradle.properties",
    "chars": 873,
    "preview": "# Project-wide Gradle settings.\n\n# IDE (e.g. Android Studio) users:\n# Settings specified in this file will override any "
  },
  {
    "path": "gradlew",
    "chars": 5080,
    "preview": "#!/usr/bin/env bash\n\n##############################################################################\n##\n##  Gradle start "
  },
  {
    "path": "gradlew.bat",
    "chars": 2404,
    "preview": "@if \"%DEBUG%\" == \"\" @echo off\r\n@rem ##########################################################################\r\n@rem\r\n@r"
  },
  {
    "path": "settings.gradle",
    "chars": 33,
    "preview": "include ':app', ':MaskedEditText'"
  }
]

// ... and 1 more files (download for full content)

About this extraction

This page contains the full source code of the egslava/edittext-mask GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 38 files (56.5 KB), approximately 15.8k tokens, and a symbol index with 80 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!