1 /**
2  * Copyright (c) 2011, Google Inc.
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 
17 package com.android.mail.utils;
18 
19 import android.content.res.Resources;
20 import android.text.TextUtils;
21 
22 import com.android.mail.R;
23 import com.android.mail.providers.Account;
24 import com.android.mail.providers.AccountObserver;
25 import com.android.mail.ui.AccountController;
26 
27 import java.util.regex.Pattern;
28 
29 /**
30  * A veiled email address is where we don't want to display the email address, because the address
31  * might be throw-away, or temporary. For these veiled addresses, we want to display some alternate
32  * information. To find if an email address is veiled, call the method
33  * {@link #isVeiledAddress(String)}
34  */
35 public final class VeiledAddressMatcher{
36     /**
37      * Resource for the regex pattern that specifies a veiled addresses.
38      */
39     private static final int VEILED_RESOURCE = R.string.veiled_address;
40 
41     /**
42      * Resource that specifies whether veiled address matching is enabled.
43      */
44     private static final int VEILED_MATCHING_ENABLED = R.bool.veiled_address_enabled;
45 
46     /**
47      * Similar to {@link #VEILED_ALTERNATE_TEXT} except this is for addresses where we don't have
48      * the name corresponding to the veiled address. Since we don't show the address, we should
49      * indicate that the recipient is unknown to us.
50      */
51     public static final int VEILED_ALTERNATE_TEXT_UNKNOWN_PERSON =
52             R.string.veiled_alternate_text_unknown_person;
53 
54     /**
55      * When we show a veiled address, we should show an alternate string rather than the email
56      * address. This is the resource that specifies the alternate string.
57      */
58     public static final int VEILED_ALTERNATE_TEXT = R.string.veiled_alternate_text;
59 
60     /**
61      * A summary string (short-string) for an unknown veiled recipient.
62      */
63     public static final int VEILED_SUMMARY_UNKNOWN = R.string.veiled_summary_unknown_person;
64 
65     /**
66      * Private object that does the actual matching.
67      */
68     private Pattern mMatcher = null;
69 
70     /**
71      * True if veiled address matching is enabled, false otherwise.
72      */
73     protected boolean mVeiledMatchingEnabled = false;
74 
75     /**
76      * The hash code of the last profile pattern retrieved . This allows us to avoid recompiling the
77      * patterns when nothing has changed.
78      */
79     private int mProfilePatternLastHash = -1;
80 
81     private final AccountObserver mObserver = new AccountObserver() {
82         @Override
83         public void onChanged(Account newAccount) {
84             loadPattern(newAccount.settings.veiledAddressPattern);
85         }
86     };
87 
88     /**
89      * Make instantiation impossible.
90      */
VeiledAddressMatcher()91     private VeiledAddressMatcher() {
92         // Do nothing.
93     }
94 
95     /**
96      * Loads the regular expression that corresponds to veiled addresses. It is safe to call this
97      * method repeatedly with the same pattern. If the pattern has not changed, little extra work
98      * is done.
99      * @param pattern
100      */
loadPattern(String pattern)101     private final void loadPattern(String pattern) {
102         if (!TextUtils.isEmpty(pattern)) {
103             final int hashCode = pattern.hashCode();
104             if (hashCode != mProfilePatternLastHash) {
105                 mProfilePatternLastHash = hashCode;
106                 mMatcher = Pattern.compile(pattern);
107                 // Since we have a non-empty pattern now, enable pattern matching.
108                 mVeiledMatchingEnabled = true;
109             }
110         }
111     }
112 
113     /**
114      * Default constructor
115      * @return
116      */
newInstance(Resources resources)117     public static final VeiledAddressMatcher newInstance(Resources resources) {
118         final VeiledAddressMatcher instance = new VeiledAddressMatcher();
119         instance.mVeiledMatchingEnabled = resources.getBoolean(VEILED_MATCHING_ENABLED);
120         if (instance.mVeiledMatchingEnabled) {
121             instance.loadPattern(resources.getString(VEILED_RESOURCE));
122         }
123         return instance;
124     }
125 
126     /**
127      * Initialize the object to listen for account changes. Without this, we cannot obtain updated
128      * values of the veiled address pattern and the value is read once from resources.
129      * @param controller
130      */
initialize(AccountController controller)131     public final void initialize(AccountController controller) {
132         mObserver.initialize(controller);
133     }
134 
135     /**
136      * Returns true if the given email address is a throw-away (or veiled) address. Such addresses
137      * are created using special server-side logic for the purpose of keeping the real address of
138      * the user hidden.
139      * @param address
140      * @return true if the address is veiled, false otherwise.
141      */
isVeiledAddress(String address)142     public final boolean isVeiledAddress (String address) {
143         if (!mVeiledMatchingEnabled || mMatcher == null) {
144             // Veiled address matching is explicitly disabled: Match nothing.
145             return false;
146         }
147         return mMatcher.matcher(address).matches();
148     }
149 }
150