blob: 18b48fad5f076237fb061ca068b23f4d6700cd1f [file] [log] [blame]
/*
* Copyright (C) 2007 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.phone;
import static android.view.Window.PROGRESS_VISIBILITY_OFF;
import static android.view.Window.PROGRESS_VISIBILITY_ON;
import android.app.ListActivity;
import android.content.AsyncQueryHandler;
import android.content.ContentResolver;
import android.content.Intent;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.text.BidiFormatter;
import android.text.TextDirectionHeuristics;
import android.util.Log;
import android.view.View;
import android.view.Window;
import android.widget.CursorAdapter;
import android.widget.SimpleCursorAdapter;
import android.widget.TextView;
/**
* Abbreviated Dial Numbers (ADN) list activity for the Phone app. By default, this class will show
* you all Service Dialing Numbers (SDN) that are supported by a service provider. SDNs are a form
* of speed dial for accessing service provider contacts like "#MIN" for getting user minutes.
* To see this class in use, trigger the radio info screen by dialing *#*#INFO#*#* and open the
* menu.
* This class can also be used as a base class for simple contact lists that can be represented with
* only labels and numbers.
*/
public class ADNList extends ListActivity {
protected static final String TAG = "ADNList";
protected static final boolean DBG = false;
private static final String[] COLUMN_NAMES = new String[] {
"name",
"number",
"emails"
};
protected static final int NAME_COLUMN = 0;
protected static final int NUMBER_COLUMN = 1;
protected static final int EMAILS_COLUMN = 2;
private static final int[] VIEW_NAMES = new int[] {
android.R.id.text1,
android.R.id.text2
};
protected static final int QUERY_TOKEN = 0;
protected static final int INSERT_TOKEN = 1;
protected static final int UPDATE_TOKEN = 2;
protected static final int DELETE_TOKEN = 3;
protected QueryHandler mQueryHandler;
protected CursorAdapter mCursorAdapter;
protected Cursor mCursor = null;
private TextView mEmptyText;
protected int mInitialSelection = -1;
@Override
protected void onCreate(Bundle icicle) {
super.onCreate(icicle);
getWindow().requestFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
setContentView(R.layout.adn_list);
mEmptyText = (TextView) findViewById(android.R.id.empty);
mQueryHandler = new QueryHandler(getContentResolver());
}
@Override
protected void onResume() {
super.onResume();
query();
}
@Override
protected void onStop() {
super.onStop();
if (mCursor != null) {
mCursor.deactivate();
}
}
protected Uri resolveIntent() {
Intent intent = getIntent();
if (intent.getData() == null) {
intent.setData(Uri.parse("content://icc/adn"));
}
return intent.getData();
}
private void query() {
Uri uri = resolveIntent();
if (DBG) log("query: starting an async query");
mQueryHandler.startQuery(QUERY_TOKEN, null, uri, COLUMN_NAMES,
null, null, null);
displayProgress(true);
}
private void reQuery() {
query();
}
private void setAdapter() {
// NOTE:
// As it it written, the positioning code below is NOT working.
// However, this current non-working state is in compliance with
// the UI paradigm, so we can't really do much to change it.
// In the future, if we wish to get this "positioning" correct,
// we'll need to do the following:
// 1. Change the layout to in the cursor adapter to:
// android.R.layout.simple_list_item_checked
// 2. replace the selection / focus code with:
// getListView().setChoiceMode(ListView.CHOICE_MODE_SINGLE);
// getListView().setItemChecked(mInitialSelection, true);
// Since the positioning is really only useful for the dialer's
// SpecialCharSequence case (dialing '2#' to get to the 2nd
// contact for instance), it doesn't make sense to mess with
// the usability of the activity just for this case.
// These artifacts include:
// 1. UI artifacts (checkbox and highlight at the same time)
// 2. Allowing the user to edit / create new SIM contacts when
// the user is simply trying to retrieve a number into the d
// dialer.
if (mCursorAdapter == null) {
mCursorAdapter = newAdapter();
setListAdapter(mCursorAdapter);
} else {
mCursorAdapter.changeCursor(mCursor);
}
if (mInitialSelection >=0 && mInitialSelection < mCursorAdapter.getCount()) {
setSelection(mInitialSelection);
getListView().setFocusableInTouchMode(true);
boolean gotfocus = getListView().requestFocus();
}
}
protected CursorAdapter newAdapter() {
SimpleCursorAdapter sca = new SimpleCursorAdapter(this,
android.R.layout.simple_list_item_2,
mCursor, COLUMN_NAMES, VIEW_NAMES);
// This code block is for displaying a phone number including "+ country code" correctly
// in bidirectional language (b/35180168).
// Without this code, e.g. "+0123456789" is wrongly displayed as "0123456789+".
sca.setViewBinder(new SimpleCursorAdapter.ViewBinder() {
public boolean setViewValue(View view, Cursor cursor, int columnIndex) {
view.setTextAlignment(View.TEXT_ALIGNMENT_VIEW_START);
if (columnIndex == NUMBER_COLUMN) {
String num = cursor.getString(NUMBER_COLUMN);
if (num != null) {
BidiFormatter bf = BidiFormatter.getInstance();
num = bf.unicodeWrap(num, TextDirectionHeuristics.LTR, true);
}
if (view instanceof TextView) {
((TextView) view).setText(num);
}
return true;
}
return false;
}
});
return sca;
}
private void displayProgress(boolean loading) {
if (DBG) log("displayProgress: " + loading);
mEmptyText.setText(loading ? R.string.simContacts_emptyLoading:
R.string.simContacts_empty);
getWindow().setFeatureInt(
Window.FEATURE_INDETERMINATE_PROGRESS,
loading ? PROGRESS_VISIBILITY_ON : PROGRESS_VISIBILITY_OFF);
}
private class QueryHandler extends AsyncQueryHandler {
public QueryHandler(ContentResolver cr) {
super(cr);
}
@Override
protected void onQueryComplete(int token, Object cookie, Cursor c) {
if (DBG) log("onQueryComplete: cursor.count=" + c.getCount());
mCursor = c;
setAdapter();
displayProgress(false);
// Cursor is refreshed and inherited classes may have menu items depending on it.
invalidateOptionsMenu();
}
@Override
protected void onInsertComplete(int token, Object cookie, Uri uri) {
if (DBG) log("onInsertComplete: requery");
reQuery();
}
@Override
protected void onUpdateComplete(int token, Object cookie, int result) {
if (DBG) log("onUpdateComplete: requery");
reQuery();
}
@Override
protected void onDeleteComplete(int token, Object cookie, int result) {
if (DBG) log("onDeleteComplete: requery");
reQuery();
}
}
protected void log(String msg) {
Log.d(TAG, "[ADNList] " + msg);
}
}