1/*
2 * Copyright (C) 2006 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package android.text;
18
19/**
20 * Abstract class for filtering login-related text (user names and passwords)
21 *
22 */
23public abstract class LoginFilter implements InputFilter {
24    private boolean mAppendInvalid;  // whether to append or ignore invalid characters
25    /**
26     * Base constructor for LoginFilter
27     * @param appendInvalid whether or not to append invalid characters.
28     */
29    LoginFilter(boolean appendInvalid) {
30        mAppendInvalid = appendInvalid;
31    }
32
33    /**
34     * Default constructor for LoginFilter doesn't append invalid characters.
35     */
36    LoginFilter() {
37        mAppendInvalid = false;
38    }
39
40    /**
41     * This method is called when the buffer is going to replace the
42     * range <code>dstart &hellip; dend</code> of <code>dest</code>
43     * with the new text from the range <code>start &hellip; end</code>
44     * of <code>source</code>.  Returns the CharSequence that we want
45     * placed there instead, including an empty string
46     * if appropriate, or <code>null</code> to accept the original
47     * replacement.  Be careful to not to reject 0-length replacements,
48     * as this is what happens when you delete text.
49     */
50    public CharSequence filter(CharSequence source, int start, int end,
51            Spanned dest, int dstart, int dend) {
52        onStart();
53
54        // Scan through beginning characters in dest, calling onInvalidCharacter()
55        // for each invalid character.
56        for (int i = 0; i < dstart; i++) {
57            char c = dest.charAt(i);
58            if (!isAllowed(c)) onInvalidCharacter(c);
59        }
60
61        // Scan through changed characters rejecting disallowed chars
62        SpannableStringBuilder modification = null;
63        int modoff = 0;
64
65        for (int i = start; i < end; i++) {
66            char c = source.charAt(i);
67            if (isAllowed(c)) {
68                // Character allowed.
69                modoff++;
70            } else {
71                if (mAppendInvalid) {
72                    modoff++;
73                } else {
74                    if (modification == null) {
75                        modification = new SpannableStringBuilder(source, start, end);
76                        modoff = i - start;
77                    }
78
79                    modification.delete(modoff, modoff + 1);
80                }
81
82                onInvalidCharacter(c);
83            }
84        }
85
86        // Scan through remaining characters in dest, calling onInvalidCharacter()
87        // for each invalid character.
88        for (int i = dend; i < dest.length(); i++) {
89            char c = dest.charAt(i);
90            if (!isAllowed(c)) onInvalidCharacter(c);
91        }
92
93        onStop();
94
95        // Either returns null if we made no changes,
96        // or what we wanted to change it to if there were changes.
97        return modification;
98    }
99
100    /**
101     * Called when we start processing filter.
102     */
103    public void onStart() {
104
105    }
106
107    /**
108     * Called whenever we encounter an invalid character.
109     * @param c the invalid character
110     */
111    public void onInvalidCharacter(char c) {
112
113    }
114
115    /**
116     * Called when we're done processing filter
117     */
118    public void onStop() {
119
120    }
121
122    /**
123     * Returns whether or not we allow character c.
124     * Subclasses must override this method.
125     */
126    public abstract boolean isAllowed(char c);
127
128    /**
129     * This filter rejects characters in the user name that are not compatible with GMail
130     * account creation. It prevents the user from entering user names with characters other than
131     * [a-zA-Z0-9.].
132     *
133     */
134    public static class UsernameFilterGMail extends LoginFilter {
135
136        public UsernameFilterGMail() {
137            super(false);
138        }
139
140        public UsernameFilterGMail(boolean appendInvalid) {
141            super(appendInvalid);
142        }
143
144        @Override
145        public boolean isAllowed(char c) {
146            // Allow [a-zA-Z0-9@.]
147            if ('0' <= c && c <= '9')
148                return true;
149            if ('a' <= c && c <= 'z')
150                return true;
151            if ('A' <= c && c <= 'Z')
152                return true;
153            if ('.' == c)
154                return true;
155            return false;
156        }
157    }
158
159    /**
160     * This filter rejects characters in the user name that are not compatible with Google login.
161     * It is slightly less restrictive than the above filter in that it allows [a-zA-Z0-9._-+].
162     *
163     */
164    public static class UsernameFilterGeneric extends LoginFilter {
165        private static final String mAllowed = "@_-+."; // Additional characters
166
167        public UsernameFilterGeneric() {
168            super(false);
169        }
170
171        public UsernameFilterGeneric(boolean appendInvalid) {
172            super(appendInvalid);
173        }
174
175        @Override
176        public boolean isAllowed(char c) {
177            // Allow [a-zA-Z0-9@.]
178            if ('0' <= c && c <= '9')
179                return true;
180            if ('a' <= c && c <= 'z')
181                return true;
182            if ('A' <= c && c <= 'Z')
183                return true;
184            if (mAllowed.indexOf(c) != -1)
185                return true;
186            return false;
187        }
188    }
189
190    /**
191     * This filter is compatible with GMail passwords which restricts characters to
192     * the Latin-1 (ISO8859-1) char set.
193     *
194     */
195    public static class PasswordFilterGMail extends LoginFilter {
196
197        public PasswordFilterGMail() {
198            super(false);
199        }
200
201        public PasswordFilterGMail(boolean appendInvalid) {
202            super(appendInvalid);
203        }
204
205        // We should reject anything not in the Latin-1 (ISO8859-1) charset
206        @Override
207        public boolean isAllowed(char c) {
208            if (32 <= c && c <= 127)
209                return true; // standard charset
210            // if (128 <= c && c <= 159) return true;  // nonstandard (Windows(TM)(R)) charset
211            if (160 <= c && c <= 255)
212                return true; // extended charset
213            return false;
214        }
215    }
216}
217