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