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