• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2007 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.phone;
18 
19 import static android.view.Window.PROGRESS_VISIBILITY_OFF;
20 import static android.view.Window.PROGRESS_VISIBILITY_ON;
21 
22 import android.app.ListActivity;
23 import android.content.AsyncQueryHandler;
24 import android.content.ContentResolver;
25 import android.content.Intent;
26 import android.database.Cursor;
27 import android.net.Uri;
28 import android.os.Bundle;
29 import android.text.BidiFormatter;
30 import android.text.TextDirectionHeuristics;
31 import android.util.Log;
32 import android.view.View;
33 import android.view.Window;
34 import android.widget.CursorAdapter;
35 import android.widget.SimpleCursorAdapter;
36 import android.widget.TextView;
37 
38 /**
39  * Abbreviated Dial Numbers (ADN) list activity for the Phone app. By default, this class will show
40  * you all Service Dialing Numbers (SDN) that are supported by a service provider.  SDNs are a form
41  * of speed dial for accessing service provider contacts like "#MIN" for getting user minutes.
42  * To see this class in use, trigger the radio info screen by dialing *#*#INFO#*#* and open the
43  * menu.
44  * This class can also be used as a base class for simple contact lists that can be represented with
45  * only labels and numbers.
46  */
47 public class ADNList extends ListActivity {
48     protected static final String TAG = "ADNList";
49     protected static final boolean DBG = false;
50 
51     private static final String[] COLUMN_NAMES = new String[] {
52         "name",
53         "number",
54         "emails"
55     };
56 
57     protected static final int NAME_COLUMN = 0;
58     protected static final int NUMBER_COLUMN = 1;
59     protected static final int EMAILS_COLUMN = 2;
60 
61     private static final int[] VIEW_NAMES = new int[] {
62         android.R.id.text1,
63         android.R.id.text2
64     };
65 
66     protected static final int QUERY_TOKEN = 0;
67     protected static final int INSERT_TOKEN = 1;
68     protected static final int UPDATE_TOKEN = 2;
69     protected static final int DELETE_TOKEN = 3;
70 
71 
72     protected QueryHandler mQueryHandler;
73     protected CursorAdapter mCursorAdapter;
74     protected Cursor mCursor = null;
75 
76     private TextView mEmptyText;
77 
78     protected int mInitialSelection = -1;
79 
80     @Override
onCreate(Bundle icicle)81     protected void onCreate(Bundle icicle) {
82         super.onCreate(icicle);
83         getWindow().requestFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
84         getWindow().addSystemFlags(
85                 android.view.WindowManager.LayoutParams
86                         .SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS);
87         setContentView(R.layout.adn_list);
88         mEmptyText = (TextView) findViewById(android.R.id.empty);
89         mQueryHandler = new QueryHandler(getContentResolver());
90     }
91 
92     @Override
onResume()93     protected void onResume() {
94         super.onResume();
95         query();
96     }
97 
98     @Override
onStop()99     protected void onStop() {
100         super.onStop();
101         if (mCursor != null) {
102             mCursor.deactivate();
103         }
104     }
105 
resolveIntent()106     protected Uri resolveIntent() {
107         Intent intent = getIntent();
108         if (intent.getData() == null) {
109             intent.setData(Uri.parse("content://icc/adn"));
110         }
111 
112         return intent.getData();
113     }
114 
query()115     private void query() {
116         Uri uri = resolveIntent();
117         if (DBG) log("query: starting an async query");
118         mQueryHandler.startQuery(QUERY_TOKEN, null, uri, COLUMN_NAMES,
119                 null, null, null);
120         displayProgress(true);
121     }
122 
reQuery()123     private void reQuery() {
124         query();
125     }
126 
setAdapter()127     private void setAdapter() {
128         // NOTE:
129         // As it it written, the positioning code below is NOT working.
130         // However, this current non-working state is in compliance with
131         // the UI paradigm, so we can't really do much to change it.
132 
133         // In the future, if we wish to get this "positioning" correct,
134         // we'll need to do the following:
135         //   1. Change the layout to in the cursor adapter to:
136         //     android.R.layout.simple_list_item_checked
137         //   2. replace the selection / focus code with:
138         //     getListView().setChoiceMode(ListView.CHOICE_MODE_SINGLE);
139         //     getListView().setItemChecked(mInitialSelection, true);
140 
141         // Since the positioning is really only useful for the dialer's
142         // SpecialCharSequence case (dialing '2#' to get to the 2nd
143         // contact for instance), it doesn't make sense to mess with
144         // the usability of the activity just for this case.
145 
146         // These artifacts include:
147         //  1. UI artifacts (checkbox and highlight at the same time)
148         //  2. Allowing the user to edit / create new SIM contacts when
149         //    the user is simply trying to retrieve a number into the d
150         //    dialer.
151 
152         if (mCursorAdapter == null) {
153             mCursorAdapter = newAdapter();
154 
155             setListAdapter(mCursorAdapter);
156         } else {
157             mCursorAdapter.changeCursor(mCursor);
158         }
159 
160         if (mInitialSelection >=0 && mInitialSelection < mCursorAdapter.getCount()) {
161             setSelection(mInitialSelection);
162             getListView().setFocusableInTouchMode(true);
163             boolean gotfocus = getListView().requestFocus();
164         }
165     }
166 
newAdapter()167     protected CursorAdapter newAdapter() {
168         SimpleCursorAdapter sca = new SimpleCursorAdapter(this,
169                 android.R.layout.simple_list_item_2,
170                 mCursor, COLUMN_NAMES, VIEW_NAMES);
171 
172         // This code block is for displaying a phone number including "+ country code" correctly
173         // in bidirectional language (b/35180168).
174         // Without this code, e.g. "+0123456789" is wrongly displayed as "0123456789+".
175         sca.setViewBinder(new SimpleCursorAdapter.ViewBinder() {
176             public boolean setViewValue(View view, Cursor cursor, int columnIndex) {
177                 view.setTextAlignment(View.TEXT_ALIGNMENT_VIEW_START);
178                 if (columnIndex == NUMBER_COLUMN) {
179                     String num = cursor.getString(NUMBER_COLUMN);
180                     if (num != null) {
181                         BidiFormatter bf = BidiFormatter.getInstance();
182                         num = bf.unicodeWrap(num, TextDirectionHeuristics.LTR, true);
183                     }
184                     if (view instanceof TextView) {
185                         ((TextView) view).setText(num);
186                     }
187                     return true;
188                 }
189                 return false;
190             }
191         });
192         return sca;
193     }
194 
displayProgress(boolean loading)195     private void displayProgress(boolean loading) {
196         if (DBG) log("displayProgress: " + loading);
197 
198         mEmptyText.setText(loading ? R.string.simContacts_emptyLoading:
199                 R.string.simContacts_empty);
200         getWindow().setFeatureInt(
201                 Window.FEATURE_INDETERMINATE_PROGRESS,
202                 loading ? PROGRESS_VISIBILITY_ON : PROGRESS_VISIBILITY_OFF);
203     }
204 
205     private class QueryHandler extends AsyncQueryHandler {
QueryHandler(ContentResolver cr)206         public QueryHandler(ContentResolver cr) {
207             super(cr);
208         }
209 
210         @Override
onQueryComplete(int token, Object cookie, Cursor c)211         protected void onQueryComplete(int token, Object cookie, Cursor c) {
212             if (DBG) log("onQueryComplete: cursor.count=" + c.getCount());
213             mCursor = c;
214             setAdapter();
215             displayProgress(false);
216 
217             // Cursor is refreshed and inherited classes may have menu items depending on it.
218             invalidateOptionsMenu();
219         }
220 
221         @Override
onInsertComplete(int token, Object cookie, Uri uri)222         protected void onInsertComplete(int token, Object cookie, Uri uri) {
223             if (DBG) log("onInsertComplete: requery");
224             reQuery();
225         }
226 
227         @Override
onUpdateComplete(int token, Object cookie, int result)228         protected void onUpdateComplete(int token, Object cookie, int result) {
229             if (DBG) log("onUpdateComplete: requery");
230             reQuery();
231         }
232 
233         @Override
onDeleteComplete(int token, Object cookie, int result)234         protected void onDeleteComplete(int token, Object cookie, int result) {
235             if (DBG) log("onDeleteComplete: requery");
236             reQuery();
237         }
238     }
239 
log(String msg)240     protected void log(String msg) {
241         Log.d(TAG, "[ADNList] " + msg);
242     }
243 }
244