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