1a8dc86faac4d1ac07901be75dc92b7a877ca46ffVikram Aggarwal/** 2a8dc86faac4d1ac07901be75dc92b7a877ca46ffVikram Aggarwal * Copyright (c) 2011, Google Inc. 3a8dc86faac4d1ac07901be75dc92b7a877ca46ffVikram Aggarwal * 4a8dc86faac4d1ac07901be75dc92b7a877ca46ffVikram Aggarwal * Licensed under the Apache License, Version 2.0 (the "License"); 5a8dc86faac4d1ac07901be75dc92b7a877ca46ffVikram Aggarwal * you may not use this file except in compliance with the License. 6a8dc86faac4d1ac07901be75dc92b7a877ca46ffVikram Aggarwal * You may obtain a copy of the License at 7a8dc86faac4d1ac07901be75dc92b7a877ca46ffVikram Aggarwal * 8a8dc86faac4d1ac07901be75dc92b7a877ca46ffVikram Aggarwal * http://www.apache.org/licenses/LICENSE-2.0 9a8dc86faac4d1ac07901be75dc92b7a877ca46ffVikram Aggarwal * 10a8dc86faac4d1ac07901be75dc92b7a877ca46ffVikram Aggarwal * Unless required by applicable law or agreed to in writing, software 11a8dc86faac4d1ac07901be75dc92b7a877ca46ffVikram Aggarwal * distributed under the License is distributed on an "AS IS" BASIS, 12a8dc86faac4d1ac07901be75dc92b7a877ca46ffVikram Aggarwal * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13a8dc86faac4d1ac07901be75dc92b7a877ca46ffVikram Aggarwal * See the License for the specific language governing permissions and 14a8dc86faac4d1ac07901be75dc92b7a877ca46ffVikram Aggarwal * limitations under the License. 15a8dc86faac4d1ac07901be75dc92b7a877ca46ffVikram Aggarwal */ 16a8dc86faac4d1ac07901be75dc92b7a877ca46ffVikram Aggarwal 17a8dc86faac4d1ac07901be75dc92b7a877ca46ffVikram Aggarwalpackage com.android.mail.utils; 18a8dc86faac4d1ac07901be75dc92b7a877ca46ffVikram Aggarwal 19a8dc86faac4d1ac07901be75dc92b7a877ca46ffVikram Aggarwalimport android.content.res.Resources; 2069a6cdff8afde77ec9bcd75a5651ee212344019eVikram Aggarwalimport android.text.TextUtils; 21a8dc86faac4d1ac07901be75dc92b7a877ca46ffVikram Aggarwal 22a8dc86faac4d1ac07901be75dc92b7a877ca46ffVikram Aggarwalimport com.android.mail.R; 2369a6cdff8afde77ec9bcd75a5651ee212344019eVikram Aggarwalimport com.android.mail.providers.Account; 2469a6cdff8afde77ec9bcd75a5651ee212344019eVikram Aggarwalimport com.android.mail.providers.AccountObserver; 2569a6cdff8afde77ec9bcd75a5651ee212344019eVikram Aggarwalimport com.android.mail.ui.AccountController; 2669a6cdff8afde77ec9bcd75a5651ee212344019eVikram Aggarwal 27a8dc86faac4d1ac07901be75dc92b7a877ca46ffVikram Aggarwalimport java.util.regex.Pattern; 28a8dc86faac4d1ac07901be75dc92b7a877ca46ffVikram Aggarwal 29a8dc86faac4d1ac07901be75dc92b7a877ca46ffVikram Aggarwal/** 30a8dc86faac4d1ac07901be75dc92b7a877ca46ffVikram Aggarwal * A veiled email address is where we don't want to display the email address, because the address 31a8dc86faac4d1ac07901be75dc92b7a877ca46ffVikram Aggarwal * might be throw-away, or temporary. For these veiled addresses, we want to display some alternate 32a8dc86faac4d1ac07901be75dc92b7a877ca46ffVikram Aggarwal * information. To find if an email address is veiled, call the method 3369a6cdff8afde77ec9bcd75a5651ee212344019eVikram Aggarwal * {@link #isVeiledAddress(String)} 34a8dc86faac4d1ac07901be75dc92b7a877ca46ffVikram Aggarwal */ 3569a6cdff8afde77ec9bcd75a5651ee212344019eVikram Aggarwalpublic final class VeiledAddressMatcher{ 36a8dc86faac4d1ac07901be75dc92b7a877ca46ffVikram Aggarwal /** 37a8dc86faac4d1ac07901be75dc92b7a877ca46ffVikram Aggarwal * Resource for the regex pattern that specifies a veiled addresses. 38a8dc86faac4d1ac07901be75dc92b7a877ca46ffVikram Aggarwal */ 39a8dc86faac4d1ac07901be75dc92b7a877ca46ffVikram Aggarwal private static final int VEILED_RESOURCE = R.string.veiled_address; 40a8dc86faac4d1ac07901be75dc92b7a877ca46ffVikram Aggarwal 41a8dc86faac4d1ac07901be75dc92b7a877ca46ffVikram Aggarwal /** 42a8dc86faac4d1ac07901be75dc92b7a877ca46ffVikram Aggarwal * Resource that specifies whether veiled address matching is enabled. 43a8dc86faac4d1ac07901be75dc92b7a877ca46ffVikram Aggarwal */ 44a8dc86faac4d1ac07901be75dc92b7a877ca46ffVikram Aggarwal private static final int VEILED_MATCHING_ENABLED = R.bool.veiled_address_enabled; 45a8dc86faac4d1ac07901be75dc92b7a877ca46ffVikram Aggarwal 46a8dc86faac4d1ac07901be75dc92b7a877ca46ffVikram Aggarwal /** 47a8dc86faac4d1ac07901be75dc92b7a877ca46ffVikram Aggarwal * Similar to {@link #VEILED_ALTERNATE_TEXT} except this is for addresses where we don't have 48a8dc86faac4d1ac07901be75dc92b7a877ca46ffVikram Aggarwal * the name corresponding to the veiled address. Since we don't show the address, we should 49a8dc86faac4d1ac07901be75dc92b7a877ca46ffVikram Aggarwal * indicate that the recipient is unknown to us. 50a8dc86faac4d1ac07901be75dc92b7a877ca46ffVikram Aggarwal */ 51a8dc86faac4d1ac07901be75dc92b7a877ca46ffVikram Aggarwal public static final int VEILED_ALTERNATE_TEXT_UNKNOWN_PERSON = 52a8dc86faac4d1ac07901be75dc92b7a877ca46ffVikram Aggarwal R.string.veiled_alternate_text_unknown_person; 53a8dc86faac4d1ac07901be75dc92b7a877ca46ffVikram Aggarwal 54a8dc86faac4d1ac07901be75dc92b7a877ca46ffVikram Aggarwal /** 55a8dc86faac4d1ac07901be75dc92b7a877ca46ffVikram Aggarwal * When we show a veiled address, we should show an alternate string rather than the email 56a8dc86faac4d1ac07901be75dc92b7a877ca46ffVikram Aggarwal * address. This is the resource that specifies the alternate string. 57a8dc86faac4d1ac07901be75dc92b7a877ca46ffVikram Aggarwal */ 58a8dc86faac4d1ac07901be75dc92b7a877ca46ffVikram Aggarwal public static final int VEILED_ALTERNATE_TEXT = R.string.veiled_alternate_text; 59a8dc86faac4d1ac07901be75dc92b7a877ca46ffVikram Aggarwal 60a8dc86faac4d1ac07901be75dc92b7a877ca46ffVikram Aggarwal /** 617faa4d0a0ee25200f4fdc6dee30bb98b8e18b24aVikram Aggarwal * A summary string (short-string) for an unknown veiled recipient. 627faa4d0a0ee25200f4fdc6dee30bb98b8e18b24aVikram Aggarwal */ 637faa4d0a0ee25200f4fdc6dee30bb98b8e18b24aVikram Aggarwal public static final int VEILED_SUMMARY_UNKNOWN = R.string.veiled_summary_unknown_person; 647faa4d0a0ee25200f4fdc6dee30bb98b8e18b24aVikram Aggarwal 657faa4d0a0ee25200f4fdc6dee30bb98b8e18b24aVikram Aggarwal /** 6669a6cdff8afde77ec9bcd75a5651ee212344019eVikram Aggarwal * Private object that does the actual matching. 6769a6cdff8afde77ec9bcd75a5651ee212344019eVikram Aggarwal */ 6869a6cdff8afde77ec9bcd75a5651ee212344019eVikram Aggarwal private Pattern mMatcher = null; 6969a6cdff8afde77ec9bcd75a5651ee212344019eVikram Aggarwal 7069a6cdff8afde77ec9bcd75a5651ee212344019eVikram Aggarwal /** 7169a6cdff8afde77ec9bcd75a5651ee212344019eVikram Aggarwal * True if veiled address matching is enabled, false otherwise. 7269a6cdff8afde77ec9bcd75a5651ee212344019eVikram Aggarwal */ 7369a6cdff8afde77ec9bcd75a5651ee212344019eVikram Aggarwal protected boolean mVeiledMatchingEnabled = false; 7469a6cdff8afde77ec9bcd75a5651ee212344019eVikram Aggarwal 7569a6cdff8afde77ec9bcd75a5651ee212344019eVikram Aggarwal /** 7669a6cdff8afde77ec9bcd75a5651ee212344019eVikram Aggarwal * The hash code of the last profile pattern retrieved . This allows us to avoid recompiling the 7769a6cdff8afde77ec9bcd75a5651ee212344019eVikram Aggarwal * patterns when nothing has changed. 7869a6cdff8afde77ec9bcd75a5651ee212344019eVikram Aggarwal */ 7969a6cdff8afde77ec9bcd75a5651ee212344019eVikram Aggarwal private int mProfilePatternLastHash = -1; 8069a6cdff8afde77ec9bcd75a5651ee212344019eVikram Aggarwal 8169a6cdff8afde77ec9bcd75a5651ee212344019eVikram Aggarwal private final AccountObserver mObserver = new AccountObserver() { 8269a6cdff8afde77ec9bcd75a5651ee212344019eVikram Aggarwal @Override 8369a6cdff8afde77ec9bcd75a5651ee212344019eVikram Aggarwal public void onChanged(Account newAccount) { 8469a6cdff8afde77ec9bcd75a5651ee212344019eVikram Aggarwal loadPattern(newAccount.settings.veiledAddressPattern); 8569a6cdff8afde77ec9bcd75a5651ee212344019eVikram Aggarwal } 8669a6cdff8afde77ec9bcd75a5651ee212344019eVikram Aggarwal }; 8769a6cdff8afde77ec9bcd75a5651ee212344019eVikram Aggarwal 8869a6cdff8afde77ec9bcd75a5651ee212344019eVikram Aggarwal /** 8969a6cdff8afde77ec9bcd75a5651ee212344019eVikram Aggarwal * Make instantiation impossible. 9069a6cdff8afde77ec9bcd75a5651ee212344019eVikram Aggarwal */ 9169a6cdff8afde77ec9bcd75a5651ee212344019eVikram Aggarwal private VeiledAddressMatcher() { 9269a6cdff8afde77ec9bcd75a5651ee212344019eVikram Aggarwal // Do nothing. 9369a6cdff8afde77ec9bcd75a5651ee212344019eVikram Aggarwal } 9469a6cdff8afde77ec9bcd75a5651ee212344019eVikram Aggarwal 9569a6cdff8afde77ec9bcd75a5651ee212344019eVikram Aggarwal /** 9669a6cdff8afde77ec9bcd75a5651ee212344019eVikram Aggarwal * Loads the regular expression that corresponds to veiled addresses. It is safe to call this 9769a6cdff8afde77ec9bcd75a5651ee212344019eVikram Aggarwal * method repeatedly with the same pattern. If the pattern has not changed, little extra work 9869a6cdff8afde77ec9bcd75a5651ee212344019eVikram Aggarwal * is done. 9969a6cdff8afde77ec9bcd75a5651ee212344019eVikram Aggarwal * @param pattern 10069a6cdff8afde77ec9bcd75a5651ee212344019eVikram Aggarwal */ 10169a6cdff8afde77ec9bcd75a5651ee212344019eVikram Aggarwal private final void loadPattern(String pattern) { 10269a6cdff8afde77ec9bcd75a5651ee212344019eVikram Aggarwal if (!TextUtils.isEmpty(pattern)) { 10369a6cdff8afde77ec9bcd75a5651ee212344019eVikram Aggarwal final int hashCode = pattern.hashCode(); 10469a6cdff8afde77ec9bcd75a5651ee212344019eVikram Aggarwal if (hashCode != mProfilePatternLastHash) { 10569a6cdff8afde77ec9bcd75a5651ee212344019eVikram Aggarwal mProfilePatternLastHash = hashCode; 10669a6cdff8afde77ec9bcd75a5651ee212344019eVikram Aggarwal mMatcher = Pattern.compile(pattern); 10769a6cdff8afde77ec9bcd75a5651ee212344019eVikram Aggarwal // Since we have a non-empty pattern now, enable pattern matching. 10869a6cdff8afde77ec9bcd75a5651ee212344019eVikram Aggarwal mVeiledMatchingEnabled = true; 10969a6cdff8afde77ec9bcd75a5651ee212344019eVikram Aggarwal } 11069a6cdff8afde77ec9bcd75a5651ee212344019eVikram Aggarwal } 11169a6cdff8afde77ec9bcd75a5651ee212344019eVikram Aggarwal } 11269a6cdff8afde77ec9bcd75a5651ee212344019eVikram Aggarwal 11369a6cdff8afde77ec9bcd75a5651ee212344019eVikram Aggarwal /** 11469a6cdff8afde77ec9bcd75a5651ee212344019eVikram Aggarwal * Default constructor 11569a6cdff8afde77ec9bcd75a5651ee212344019eVikram Aggarwal * @return 11669a6cdff8afde77ec9bcd75a5651ee212344019eVikram Aggarwal */ 11769a6cdff8afde77ec9bcd75a5651ee212344019eVikram Aggarwal public static final VeiledAddressMatcher newInstance(Resources resources) { 11869a6cdff8afde77ec9bcd75a5651ee212344019eVikram Aggarwal final VeiledAddressMatcher instance = new VeiledAddressMatcher(); 11969a6cdff8afde77ec9bcd75a5651ee212344019eVikram Aggarwal instance.mVeiledMatchingEnabled = resources.getBoolean(VEILED_MATCHING_ENABLED); 12069a6cdff8afde77ec9bcd75a5651ee212344019eVikram Aggarwal if (instance.mVeiledMatchingEnabled) { 12169a6cdff8afde77ec9bcd75a5651ee212344019eVikram Aggarwal instance.loadPattern(resources.getString(VEILED_RESOURCE)); 12269a6cdff8afde77ec9bcd75a5651ee212344019eVikram Aggarwal } 12369a6cdff8afde77ec9bcd75a5651ee212344019eVikram Aggarwal return instance; 12469a6cdff8afde77ec9bcd75a5651ee212344019eVikram Aggarwal } 12569a6cdff8afde77ec9bcd75a5651ee212344019eVikram Aggarwal 12669a6cdff8afde77ec9bcd75a5651ee212344019eVikram Aggarwal /** 12769a6cdff8afde77ec9bcd75a5651ee212344019eVikram Aggarwal * Initialize the object to listen for account changes. Without this, we cannot obtain updated 12869a6cdff8afde77ec9bcd75a5651ee212344019eVikram Aggarwal * values of the veiled address pattern and the value is read once from resources. 12969a6cdff8afde77ec9bcd75a5651ee212344019eVikram Aggarwal * @param controller 13069a6cdff8afde77ec9bcd75a5651ee212344019eVikram Aggarwal */ 13169a6cdff8afde77ec9bcd75a5651ee212344019eVikram Aggarwal public final void initialize(AccountController controller) { 13269a6cdff8afde77ec9bcd75a5651ee212344019eVikram Aggarwal mObserver.initialize(controller); 13369a6cdff8afde77ec9bcd75a5651ee212344019eVikram Aggarwal } 13469a6cdff8afde77ec9bcd75a5651ee212344019eVikram Aggarwal 13569a6cdff8afde77ec9bcd75a5651ee212344019eVikram Aggarwal /** 136a8dc86faac4d1ac07901be75dc92b7a877ca46ffVikram Aggarwal * Returns true if the given email address is a throw-away (or veiled) address. Such addresses 137a8dc86faac4d1ac07901be75dc92b7a877ca46ffVikram Aggarwal * are created using special server-side logic for the purpose of keeping the real address of 138a8dc86faac4d1ac07901be75dc92b7a877ca46ffVikram Aggarwal * the user hidden. 139a8dc86faac4d1ac07901be75dc92b7a877ca46ffVikram Aggarwal * @param address 140a8dc86faac4d1ac07901be75dc92b7a877ca46ffVikram Aggarwal * @return true if the address is veiled, false otherwise. 141a8dc86faac4d1ac07901be75dc92b7a877ca46ffVikram Aggarwal */ 14269a6cdff8afde77ec9bcd75a5651ee212344019eVikram Aggarwal public final boolean isVeiledAddress (String address) { 14369a6cdff8afde77ec9bcd75a5651ee212344019eVikram Aggarwal if (!mVeiledMatchingEnabled || mMatcher == null) { 14469a6cdff8afde77ec9bcd75a5651ee212344019eVikram Aggarwal // Veiled address matching is explicitly disabled: Match nothing. 145a8dc86faac4d1ac07901be75dc92b7a877ca46ffVikram Aggarwal return false; 146a8dc86faac4d1ac07901be75dc92b7a877ca46ffVikram Aggarwal } 147a8dc86faac4d1ac07901be75dc92b7a877ca46ffVikram Aggarwal return mMatcher.matcher(address).matches(); 148a8dc86faac4d1ac07901be75dc92b7a877ca46ffVikram Aggarwal } 149a8dc86faac4d1ac07901be75dc92b7a877ca46ffVikram Aggarwal} 150