1 /*
2  * Copyright (C) 2011 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 
17 package com.android.contacts.common.util;
18 
19 import android.content.Context;
20 import android.os.AsyncTask;
21 import android.telephony.PhoneNumberFormattingTextWatcher;
22 import android.widget.TextView;
23 
24 import com.android.contacts.common.GeoUtil;
25 import com.android.contacts.common.compat.PhoneNumberFormattingTextWatcherCompat;
26 
27 public final class PhoneNumberFormatter {
PhoneNumberFormatter()28     private PhoneNumberFormatter() {}
29 
30     /**
31      * Load {@link TextWatcherLoadAsyncTask} in a worker thread and set it to a {@link TextView}.
32      */
33     private static class TextWatcherLoadAsyncTask extends
34             AsyncTask<Void, Void, PhoneNumberFormattingTextWatcher> {
35         private final String mCountryCode;
36         private final TextView mTextView;
37         private final boolean mFormatAfterWatcherSet;
38 
TextWatcherLoadAsyncTask( String countryCode, TextView textView, boolean formatAfterWatcherSet)39         public TextWatcherLoadAsyncTask(
40                 String countryCode, TextView textView, boolean formatAfterWatcherSet) {
41             mCountryCode = countryCode;
42             mTextView = textView;
43             mFormatAfterWatcherSet = formatAfterWatcherSet;
44         }
45 
46         @Override
doInBackground(Void... params)47         protected PhoneNumberFormattingTextWatcher doInBackground(Void... params) {
48             return PhoneNumberFormattingTextWatcherCompat.newInstance(mCountryCode);
49         }
50 
51         @Override
onPostExecute(PhoneNumberFormattingTextWatcher watcher)52         protected void onPostExecute(PhoneNumberFormattingTextWatcher watcher) {
53             if (watcher == null || isCancelled()) {
54                 return; // May happen if we cancel the task.
55             }
56 
57             // Setting a text changed listener is safe even after the view is detached.
58             mTextView.addTextChangedListener(watcher);
59 
60             // Forcing formatting the existing phone number
61             if (mFormatAfterWatcherSet) {
62                 watcher.afterTextChanged(mTextView.getEditableText());
63             }
64         }
65     }
66 
67     /**
68      * Delay-set {@link PhoneNumberFormattingTextWatcher} to a {@link TextView}.
69      */
setPhoneNumberFormattingTextWatcher(Context context, TextView textView)70     public static final void setPhoneNumberFormattingTextWatcher(Context context,
71             TextView textView) {
72         setPhoneNumberFormattingTextWatcher(context, textView,
73                 /* formatAfterWatcherSet =*/ false);
74     }
75 
76     /**
77      * Delay-sets {@link PhoneNumberFormattingTextWatcher} to a {@link TextView}
78      * and formats the number immediately if formatAfterWaterSet is true.
79      * In some cases, formatting before user editing might cause unwanted results
80      * (e.g. the editor thinks the user changed the content, and would save
81      * when closed even when the user didn't make other changes.)
82      */
setPhoneNumberFormattingTextWatcher( Context context, TextView textView, boolean formatAfterWatcherSet)83     public static final void setPhoneNumberFormattingTextWatcher(
84             Context context, TextView textView, boolean formatAfterWatcherSet) {
85         new TextWatcherLoadAsyncTask(GeoUtil.getCurrentCountryIso(context),
86                 textView, formatAfterWatcherSet)
87                 .executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, (Void[]) null);
88     }
89 }
90