Home | History | Annotate | Download | only in phone
      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
     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
     89     protected void onResume() {
     90         super.onResume();
     91         query();
     92     }
     93 
     94     @Override
     95     protected void onStop() {
     96         super.onStop();
     97         if (mCursor != null) {
     98             mCursor.deactivate();
     99         }
    100     }
    101 
    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 
    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 
    119     private void reQuery() {
    120         query();
    121     }
    122 
    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 
    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 
    169     private void displayProgress(boolean loading) {
    170         if (DBG) log("displayProgress: " + loading);
    171 
    172         mEmptyText.setText(loading ? R.string.simContacts_emptyLoading:
    173             (isAirplaneModeOn(this) ? R.string.simContacts_airplaneMode :
    174                 R.string.simContacts_empty));
    175         getWindow().setFeatureInt(
    176                 Window.FEATURE_INDETERMINATE_PROGRESS,
    177                 loading ? PROGRESS_VISIBILITY_ON : PROGRESS_VISIBILITY_OFF);
    178     }
    179 
    180     private static boolean isAirplaneModeOn(Context context) {
    181         return Settings.System.getInt(context.getContentResolver(),
    182                 Settings.System.AIRPLANE_MODE_ON, 0) != 0;
    183     }
    184 
    185     private class QueryHandler extends AsyncQueryHandler {
    186         public QueryHandler(ContentResolver cr) {
    187             super(cr);
    188         }
    189 
    190         @Override
    191         protected void onQueryComplete(int token, Object cookie, Cursor c) {
    192             if (DBG) log("onQueryComplete: cursor.count=" + c.getCount());
    193             mCursor = c;
    194             setAdapter();
    195             displayProgress(false);
    196 
    197             // Cursor is refreshed and inherited classes may have menu items depending on it.
    198             invalidateOptionsMenu();
    199         }
    200 
    201         @Override
    202         protected void onInsertComplete(int token, Object cookie, Uri uri) {
    203             if (DBG) log("onInsertComplete: requery");
    204             reQuery();
    205         }
    206 
    207         @Override
    208         protected void onUpdateComplete(int token, Object cookie, int result) {
    209             if (DBG) log("onUpdateComplete: requery");
    210             reQuery();
    211         }
    212 
    213         @Override
    214         protected void onDeleteComplete(int token, Object cookie, int result) {
    215             if (DBG) log("onDeleteComplete: requery");
    216             reQuery();
    217         }
    218     }
    219 
    220     protected void log(String msg) {
    221         Log.d(TAG, "[ADNList] " + msg);
    222     }
    223 }
    224