/*
* 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.contacts;




import com.android.internal.telephony.ITelephony;
import com.android.phone.CallLogAsync;
import com.android.phone.HapticFeedback;


import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.ActivityNotFoundException;
import android.content.Context;
import android.content.Intent;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Color;
import android.graphics.drawable.Drawable;
import android.media.AudioManager;
import android.media.ToneGenerator;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.SystemClock;
import android.provider.ContactsContract;
import android.provider.Settings;
import android.provider.CallLog.Calls;
import android.provider.Contacts.Phones;
import android.provider.Contacts.People;
import android.provider.Contacts.PhonesColumns;
import android.provider.Contacts.Intents.Insert;
import android.telephony.PhoneNumberFormattingTextWatcher;
import android.telephony.PhoneNumberUtils;
import android.telephony.PhoneStateListener;
import android.telephony.TelephonyManager;
import android.text.Editable;
import android.text.Spannable;
import android.text.SpannableStringBuilder;
import android.text.TextUtils;
import android.text.TextWatcher;
import android.text.method.DialerKeyListener;
import android.text.style.ForegroundColorSpan;
import android.util.Log;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewConfiguration;
import android.view.ViewGroup;
import android.view.Window;
import android.view.View.OnClickListener;
import android.view.View.OnTouchListener;
import android.view.inputmethod.InputMethodManager;
import android.widget.AbsListView;
import android.widget.AdapterView;
import android.widget.BaseAdapter;
import android.widget.CursorAdapter;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.SectionIndexer;
import android.widget.TextView;
import android.widget.ImageButton;
import android.widget.SlidingDrawer;


import java.io.InputStream;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import android.app.ListActivity;
import android.app.AlertDialog.Builder;
import android.content.AsyncQueryHandler;
import android.content.ContentResolver;
import android.content.ContentUris;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabaseCorruptException;
import android.database.sqlite.SQLiteDiskIOException;
import android.database.sqlite.SQLiteException;
import android.database.sqlite.SQLiteFullException;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.os.Bundle;
import android.provider.ContactsContract;
import android.provider.ContactsContract.Contacts;
import android.provider.ContactsContract.PhoneLookup;
import android.provider.ContactsContract.CommonDataKinds.Photo;
import android.text.TextUtils;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.AbsListView.OnScrollListener;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.AdapterView.OnItemSelectedListener;
/**
* Dialer activity that displays the typical twelve key interface.
*/
@SuppressWarnings("deprecation")
public class TwelveKeyDialer extends ListActivity implements View.OnClickListener,
View.OnLongClickListener, View.OnKeyListener,
AdapterView.OnItemClickListener, TextWatcher {
private static final String EMPTY_NUMBER = "";
private static final String TAG = "TwelveKeyDialer";

/** The length of DTMF tones in milliseconds */
private static final int TONE_LENGTH_MS = 150;


/** The DTMF tone volume relative to other sounds in the stream */
private static final int TONE_RELATIVE_VOLUME = 80;



/**
* Stream type used to play the DTMF tones off call, and mapped to the
* volume control keys
*/
private static final int DIAL_TONE_STREAM_TYPE = AudioManager.STREAM_MUSIC;
//mao
private final int NUMBER_EMTPY=1;
private final int NUMBER_NOT_EMERGENCY=2;


private EditText mDigits;
private View mDelete;
private MenuItem mAddToContactMenuItem;
private ToneGenerator mToneGenerator;
private Object mToneGeneratorLock = new Object();
private Drawable mDigitsBackground;
private Drawable mDigitsEmptyBackground;
private View mDialpad;



//private View mVoicemailDialAndDeleteRow;
private View mVoicemailButton;
// gsm1button
private View mDialButton;
// mao add gsm2 button
private View mGSM2DialButton;
private View mEmptyDialButton; //setVisibility(View.GONE);
private boolean isCardEmpty=false;
private Handler myHandler = new Handler();


// mao add SlidingDrawer
private MySlidingDrawer mDrawer;
private View mContent;// the handle control content
private ImageButton imbg;
private Boolean flag = false;
private static String mNumber;//mao
private QueryHandler mQueryHandler;//mao
private ContactItemListAdapter mAdapter;//mao
private boolean mScrollToTop;//mao
private String numberCharge="";//mao

//add mao
Context mContext = null;
/** get the phone table clonm **/
private static final String[] PHONES_PROJECTION = new String[] {
ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME,
ContactsContract.CommonDataKinds.Phone.NUMBER,
Photo.PHOTO_ID,
ContactsContract.CommonDataKinds.Phone.CONTACT_ID,
ContactsContract.CommonDataKinds.Phone.LABEL
};
private static String PHONES_SELECTION=null;

/**the contact name **/
private static final int PHONES_DISPLAY_NAME_INDEX = 0;

/**the phone number **/
private static final int PHONES_NUMBER_INDEX = 1;

/**the phone ID**/
private static final int PHONES_PHOTO_ID_INDEX = 2;

/** the contact ID**/
private static final int PHONES_CONTACT_ID_INDEX = 3;

private static final int PHONES_LABEL_INDEX=4;


/**the contact name**/
private ArrayList<String> mContactsName = new ArrayList<String>();
/**the contact label**/
private ArrayList<String> mContactsLabel = new ArrayList<String>();
/**the contact number**/
private ArrayList<String> mContactsNumber = new ArrayList<String>();
/**the contact photo**/
private ArrayList<Bitmap> mContactsPhonto = new ArrayList<Bitmap>();

private ArrayList<String> mContactNameTemp = new ArrayList<String>();
/**the contact label**/
private ArrayList<String> mContactLabelTemp = new ArrayList<String>();
/**the contact number**/
private ArrayList<String> mContactNumberTemp = new ArrayList<String>();
/**the contact photo**/
private ArrayList<Bitmap> mContactPhontoTemp = new ArrayList<Bitmap>();


private ListView mListView = null;
private MyListAdapter myAdapter = null;//mao
private static final int QUERY_TOKEN = 42;//mao




private ListView mDialpadChooser;
private DialpadChooserAdapter mDialpadChooserAdapter;
// Member variables for dialpad options
private MenuItem m2SecPauseMenuItem;
private MenuItem mWaitMenuItem;
private static final int MENU_ADD_CONTACTS = 1;
private static final int MENU_2S_PAUSE = 2;
private static final int MENU_WAIT = 3;


// Last number dialed, retrieved asynchronously from the call DB
// in onCreate. This number is displayed when the user hits the
// send key and cleared in onPause.
CallLogAsync mCallLog = new CallLogAsync();
private String mLastNumberDialed = EMPTY_NUMBER;


// determines if we want to playback local DTMF tones.
private boolean mDTMFToneEnabled;


// Vibration (haptic feedback) for dialer key presses.
private HapticFeedback mHaptic = new HapticFeedback();


/** Identifier for the "Add Call" intent extra. */
static final String ADD_CALL_MODE_KEY = "add_call_mode";


/**
* Identifier for intent extra for sending an empty Flash message for CDMA
* networks. This message is used by the network to simulate a press/depress
* of the "hookswitch" of a landline phone. Aka "empty flash".
*
* TODO: Using an intent extra to tell the phone to send this flash is a
* temporary measure. To be replaced with an ITelephony call in the future.
* TODO: Keep in sync with the string defined in
* OutgoingCallBroadcaster.java in Phone app until this is replaced with the
* ITelephony API.
*/
static final String EXTRA_SEND_EMPTY_FLASH = "com.android.phone.extra.SEND_EMPTY_FLASH";


/**
* Indicates if we are opening this dialer to add a call from the
* InCallScreen.
*/
private boolean mIsAddCallMode;

//mao
public static final class ContactsDialListItemViews {
TextView line1View;
TextView labelView;
TextView numberView;
ImageView contactIcon;
}

//mao
// add MyListAdapter
private final class MyListAdapter extends BaseAdapter {
public MyListAdapter(Context context) {
mContext = context;
}

public int getCount() {
//设置绘制数量
return mContactNumberTemp.size();
}

@Override
public boolean areAllItemsEnabled() {
return false;
}

public Object getItem(int position) {
return position;
}

public long getItemId(int position) {
return position;
}


public View getView(int position, View convertView, ViewGroup parent) {

if(convertView==null){
LayoutInflater inflater = (LayoutInflater) mContext .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView= inflater.inflate(R.layout.dial_list_contact_layout,parent, false);
}
/*if (convertView == null) {
convertView = LayoutInflater.from(mContext).inflate(
R.layout.dial_list_contact_layout, null);
}*/

findAndCacheViews(convertView);
final ContactsDialListItemViews views = (ContactsDialListItemViews) convertView.getTag();
views.line1View = (TextView) convertView.findViewById(R.id.line1);
views.labelView = (TextView) convertView.findViewById(R.id.label);
views.numberView = (TextView) convertView.findViewById(R.id.number);
views.contactIcon = (ImageView) convertView.findViewById(R.id.contact_icon);

/*String contactsName=mContactsName.get(position);
String contactsNumber=mContactsNumber.get(position);
String contactsLabel=mContactsLabel.get(position);
Bitmap contactsPhoto=mContactsPhonto.get(position);*/
Log.w("se:0",String.valueOf(mContactNumberTemp.size()));
Log.w("position:",String.valueOf(position));


String contactsNumber=mContactNumberTemp.get(position);
String contactsName=mContactNameTemp.get(position);
String contactsLabel=mContactLabelTemp.get(position);
Bitmap contactsPhoto=mContactPhontoTemp.get(position);
Log.w("numberCharge----",numberCharge);

if (contactsName!= null&&contactsName!= "") {
views.line1View.setText(contactsName);
}
views.contactIcon.setImageBitmap(contactsPhoto);
views.numberView.setVisibility(View.VISIBLE);
if (contactsLabel != null && !contactsLabel.equals("")) {
views.labelView.setText(contactsLabel);// set the label
views.labelView.setVisibility(View.VISIBLE);
} else {
views.labelView.setVisibility(View.GONE);
}
if (!TextUtils.isEmpty(contactsName) && contactsName != "") {
views.line1View.setText(contactsName);


} else if (TextUtils.isEmpty(contactsName)) {
views.line1View.setText(contactsNumber);


}
//numberView
if(numberCharge.length()==0){
views.numberView.setText(contactsNumber);// set the phone number
}else if (numberCharge!=null&&numberCharge.length()>0){
if (contactsNumber.contains(numberCharge)) {// mao
int startIndex = contactsNumber.indexOf(numberCharge);
Log.w("startIndex", String.valueOf(startIndex));
SpannableStringBuilder style = new SpannableStringBuilder(
contactsNumber);
style.setSpan(new ForegroundColorSpan(Color.RED),
startIndex, startIndex + numberCharge.length(),
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
views.numberView.setText(style);// set the phone number
}else{
views.numberView.setText(contactsNumber);// set the phone number
}
}

return convertView;
}

}


private void startQueryContacts(){
mContactNameTemp.clear();
mContactNumberTemp.clear();
mContactPhontoTemp.clear();
mContactLabelTemp.clear();
if (numberCharge != null && numberCharge.length() > 0) {
for (int i = 0; i < mContactsNumber.size(); i++) {
String contactsNumber = mContactsNumber.get(i);
String contactsName=mContactsName.get(i);
Bitmap contactsPhoto=mContactsPhonto.get(i);
String contactsLabel=mContactsLabel.get(i);
if (contactsNumber.contains(numberCharge)) {
mContactNumberTemp.add(contactsNumber);
mContactNameTemp.add(contactsName);
mContactPhontoTemp.add(contactsPhoto);
mContactLabelTemp.add(contactsLabel);
}
}
Log.w("mContactLabelTemp",String.valueOf(mContactLabelTemp.size()));


} else {
for (int i = 0; i < mContactsNumber.size(); i++) {
String contactsNumber = mContactsNumber.get(i);
String contactsName=mContactsName.get(i);
Bitmap contactsPhoto=mContactsPhonto.get(i);
String contactsLabel=mContactsLabel.get(i);
mContactNumberTemp.add(contactsNumber);
mContactNameTemp.add(contactsName);
mContactPhontoTemp.add(contactsPhoto);
mContactLabelTemp.add(contactsLabel);
}
}

}

/** get the contacts **/
private void getPhoneContacts() {
/*clear the last query result data*/
mContactsName.clear();
mContactsNumber.clear();
mContactsPhonto.clear();
mContactsLabel.clear();
mContactNameTemp.clear();
mContactNumberTemp.clear();
mContactPhontoTemp.clear();
mContactLabelTemp.clear();
ContentResolver resolver = mContext.getContentResolver();
// get the contacts
Cursor phoneCursor = resolver.query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI,
PHONES_PROJECTION, null, null, null);
if (phoneCursor != null) {
while (phoneCursor.moveToNext()) {
// get the phone number
String phoneNumber = phoneCursor.getString(PHONES_NUMBER_INDEX);
// if the phoneNumber is null or empty ,then take out from ti
if (TextUtils.isEmpty(phoneNumber))
continue;
// get the contact name
String contactName = phoneCursor.getString(PHONES_DISPLAY_NAME_INDEX);
Log.w("contactName",contactName);
// get the contact id
Long contactid = phoneCursor.getLong(PHONES_CONTACT_ID_INDEX);
// get the contact photo id
Long photoid = phoneCursor.getLong(PHONES_PHOTO_ID_INDEX);
// get the contact label
String contactLabel=phoneCursor.getString(PHONES_LABEL_INDEX);

Uri uri = ContentUris.withAppendedId(
ContactsContract.Contacts.CONTENT_URI, contactid);
/*Cursor phCursor =resolver.query(Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI,
Uri.encode(phoneNumber)),
PHONES_PROJECTION, null, null, null);*/
// get the contact Bitamp
Bitmap contactPhoto = null;
// if photoid > 0 then the photo is existed , if the photo is not existed then set a default one.
if (photoid > 0) {

InputStream input = ContactsContract.Contacts.openContactPhotoInputStream(resolver, uri);
contactPhoto = BitmapFactory.decodeStream(input);
} else {
contactPhoto = BitmapFactory.decodeResource(getResources(),R.drawable.ic_dial_action_call_gms_call);
}

mContactsName.add(contactName);
mContactsNumber.add(phoneNumber);
mContactsPhonto.add(contactPhoto);
mContactsLabel.add(contactLabel);
/*
mContactNameTemp=mContactsName;
mContactNumberTemp=mContactsNumber;
mContactPhontoTemp=mContactsPhonto;
mContactLabelTemp=mContactsLabel;*/

mContactNameTemp.add(contactName);
mContactNumberTemp.add(phoneNumber);
mContactPhontoTemp.add(contactPhoto);
mContactLabelTemp.add(contactLabel);


}


phoneCursor.close();
}
}



private final class ContactItemListAdapter extends CursorAdapter implements
SectionIndexer, OnScrollListener,
PinnedHeaderListView.PinnedHeaderAdapter {


public ContactItemListAdapter(Context context) {
super(context, null, false);
}


private SectionIndexer mIndexer;
private boolean mLoading = true;
private CharSequence mUnknownNameText;


void setLoading(boolean loading) {
mLoading = loading;
}


@Override
public void bindView(View view, Context context, Cursor cursor) {
final ContactsDialListItemViews views = (ContactsDialListItemViews) view
.getTag();
ContentResolver resolver = mContext.getContentResolver();
Log.e("resolver:",resolver.toString());
String phoneNumber = cursor.getString(PHONES_NUMBER_INDEX);
Log.w("phoneNumber:", phoneNumber);
Log.w(TAG, "phoneNumber = " + phoneNumber);
String contactName = cursor.getString(PHONES_DISPLAY_NAME_INDEX);
Log.w("contactName:", contactName);
Long contactId = cursor.getLong(PHONES_CONTACT_ID_INDEX);
Long photoId = cursor.getLong(PHONES_PHOTO_ID_INDEX);
Log.w("photoId:", String.valueOf(photoId));
String label = cursor.getString(PHONES_LABEL_INDEX);
Bitmap contactPhoto = null;
if (photoId > 0) {
Uri uri = ContentUris.withAppendedId(
ContactsContract.Contacts.CONTENT_URI, contactId);
InputStream input = ContactsContract.Contacts
.openContactPhotoInputStream(resolver, uri);
contactPhoto = BitmapFactory.decodeStream(input);
} else {
contactPhoto = BitmapFactory.decodeResource(getResources(),
R.drawable.contact_photo);
}
views.contactIcon.setImageBitmap(contactPhoto);


Log.w("label", label);
views.numberView.setVisibility(View.VISIBLE);
views.labelView.setText(label);// set the label


views.numberView.setText(phoneNumber);// set the phone number


if (!TextUtils.isEmpty(contactName)) {
views.line1View.setText(contactName);
views.line1View.setVisibility(View.VISIBLE);
views.labelView.setVisibility(View.VISIBLE);


} else if (TextUtils.isEmpty(contactName)) {
views.line1View.setText(phoneNumber);
views.labelView.setVisibility(View.VISIBLE);


}



}


@Override
public View newView(Context context, Cursor cursor, ViewGroup parent) {


LayoutInflater inflater = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View view = inflater.inflate(R.layout.dial_list_contact_layout,
parent, false);
Log.w("view", view.toString());
findAndCacheViews(view);
return view;
}


@Override
public int getPositionForSection(int section) {
// TODO Auto-generated method stub
return 0;
}


@Override
public int getSectionForPosition(int position) {
// TODO Auto-generated method stub
return 0;
}


@Override
public Object[] getSections() {
// TODO Auto-generated method stub
return null;
}


@Override
public void onScroll(AbsListView view, int firstVisibleItem,
int visibleItemCount, int totalItemCount) {
// TODO Auto-generated method stub


}


@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
// TODO Auto-generated method stub


}


@Override
public void configurePinnedHeader(View header, int position, int alpha) {
// TODO Auto-generated method stub


}


@Override
public int getPinnedHeaderState(int position) {
// TODO Auto-generated method stub
return 0;
}


}


// mao add QueryHandler


private static final class QueryHandler extends AsyncQueryHandler {
private final WeakReference<TwelveKeyDialer> mActivity;


/**
* Simple handler that wraps background calls to catch
* {@link SQLiteException}, such as when the disk is full.
*/


protected class CatchingWorkerHandler extends
AsyncQueryHandler.WorkerHandler {
public CatchingWorkerHandler(Looper looper) {
super(looper);
}


@Override
public void handleMessage(Message msg) {
try {
// Perform same query while catching any exceptions
super.handleMessage(msg);
} catch (SQLiteDiskIOException e) {
Log.w(TAG, "Exception on background worker thread", e);
} catch (SQLiteFullException e) {
Log.w(TAG, "Exception on background worker thread", e);
} catch (SQLiteDatabaseCorruptException e) {
Log.w(TAG, "Exception on background worker thread", e);
}
}
}


@Override
protected Handler createHandler(Looper looper) {
// Provide our special handler that catches exceptions
return new CatchingWorkerHandler(looper);
}


public QueryHandler(Context context) {
super(context.getContentResolver());
mActivity = new WeakReference<TwelveKeyDialer>(
(TwelveKeyDialer) context);
}


@Override
protected void onQueryComplete(int token, Object cookie, Cursor cursor) {
final TwelveKeyDialer activity = mActivity.get();


if (activity != null && !activity.isFinishing()) {
final TwelveKeyDialer.ContactItemListAdapter contactsAdapter = activity.mAdapter;
contactsAdapter.setLoading(false);


if (activity.mScrollToTop) {
if (activity.mList.getFirstVisiblePosition() > 5) {
activity.mList.setSelection(5);
}
activity.mList.smoothScrollToPosition(0);
activity.mScrollToTop = false;
}
} else {
cursor.close();
}
}
}




PhoneStateListener mPhoneStateListener = new PhoneStateListener() {
/**
* Listen for phone state changes so that we can take down the
* "dialpad chooser" if the phone becomes idle while the chooser UI is
* visible.
*/
@Override
public void onCallStateChanged(int state, String incomingNumber) {
// Log.i(TAG, "PhoneStateListener.onCallStateChanged: "
// + state + ", '" + incomingNumber + "'");
if ((state == TelephonyManager.CALL_STATE_IDLE)
&& dialpadChooserVisible()) {
// Log.i(TAG,
// "Call ended with dialpad chooser visible! Taking it down..."
// );
// Note there's a race condition in the UI here: the
// dialpad chooser could conceivably disappear (on its
// own) at the exact moment the user was trying to select
// one of the choices, which would be confusing. (But at
// least that's better than leaving the dialpad chooser
// onscreen, but useless...)
showDialpadChooser(false);
}
}
};


public void beforeTextChanged(CharSequence s, int start, int count,
int after) {
// Do nothing
}


public void onTextChanged(CharSequence input, int start, int before,
int changeCount) {
// Do nothing
// DTMF Tones do not need to be played here any longer -
// the DTMF dialer handles that functionality now.
}


public void afterTextChanged(Editable input) {
if (SpecialCharSequenceMgr.handleChars(this, input.toString(), mDigits)) {
// A special sequence was entered, clear the digits
mDigits.getText().clear();
}


if (!isDigitsEmpty()) {
//mDigits.setBackgroundDrawable(mDigitsBackground);//mao
} else {
mDigits.setCursorVisible(false);
//mDigits.setBackgroundDrawable(mDigitsEmptyBackground);//mao
}

updateDialAndDeleteButtonEnabledState();
}
//mao
void startQuery() {



mAdapter.setLoading(true);
// mQueryHandler = new QueryHandler(mContext);
// Cancel any pending queries
mQueryHandler.cancelOperation(QUERY_TOKEN);
String[] projection = PHONES_PROJECTION;
Uri uri =ContactsContract.CommonDataKinds.Phone.CONTENT_URI;
String selection=ContactsContract.CommonDataKinds.Phone.NUMBER+" is not null";
mQueryHandler.startQuery(QUERY_TOKEN, null, uri,
projection,null, null,
null);
}




private void findAndCacheViews(View view) {


// Get the views to bind to
ContactsDialListItemViews views = new ContactsDialListItemViews();
views.line1View = (TextView) view.findViewById(R.id.line1);
views.labelView = (TextView) view.findViewById(R.id.label);
views.numberView = (TextView) view.findViewById(R.id.number);
views.contactIcon = (ImageView) view.findViewById(R.id.contact_icon);
view.setTag(views);
}


//mao add
/*
* query the dialing number is existing in the favorites
*/
public void getPeople() {

String[] projection = { ContactsContract.PhoneLookup.DISPLAY_NAME,
ContactsContract.CommonDataKinds.Phone.NUMBER};

Log.d(TAG, "getPeople ---------");

// add the input number into the msPeers 中
Cursor cursor = this.getContentResolver().query(
ContactsContract.CommonDataKinds.Phone.CONTENT_URI,
projection, // Which columns to return.
ContactsContract.CommonDataKinds.Phone.NUMBER + " like '" + mNumber + "%'", // WHERE clause.
null, // WHERE clause value substitution
null); // Sort order.

if( cursor == null ) {
Log.d(TAG, "getPeople null");
return;
}
Log.d(TAG, "getPeople cursor.getCount() = " + cursor.getCount());
for( int i = 0; i < cursor.getCount(); i++ )
{
cursor.moveToPosition(i);

// 取得联系人名字
int nameFieldColumnIndex = cursor.getColumnIndex(ContactsContract.PhoneLookup.DISPLAY_NAME);
String name = cursor.getString(nameFieldColumnIndex);
Log.i("Contacts", "" + name + " .... " + nameFieldColumnIndex); // 这里提示 force close

}
}





@Override
protected void onCreate(Bundle icicle) {
Log.w("onCreate()============>", "mao");
super.onCreate(icicle);


Resources r = getResources();
// Do not show title in the case the device is in carmode.
if ((r.getConfiguration().uiMode & Configuration.UI_MODE_TYPE_MASK) ==
Configuration.UI_MODE_TYPE_CAR) {
requestWindowFeature(Window.FEATURE_NO_TITLE);
}
Log.w("START","START");
// Set the content view
setContentView(getContentViewResource());
numberCharge="";//

//mao move the background
// Load up the resources for the text field.
// mDigitsBackground = r.getDrawable(R.drawable.btn_dial_textfield_active);
//mDigitsEmptyBackground = r.getDrawable(R.drawable.btn_dial_textfield);


mDigits = (EditText) findViewById(R.id.digits);

Log.w("START",mDigits.toString());
mDigits.setKeyListener(DialerKeyListener.getInstance());
mDigits.setOnClickListener(this);
//mDigits.setOnKeyListener(this);
mNumber = mDigits.getText().toString();
//mao
mContext = this;
mListView = this.getListView();
/**get the contacts information**/
getPhoneContacts();
Log.w("mNumber1:",mNumber);
mDigits.setOnKeyListener(new EditText.OnKeyListener() {
public boolean onKey(View arg0, int arg1, KeyEvent arg2)
{

mNumber = mDigits.getText().toString();
Log.w(TAG, "mNumbering = " + mNumber);
return false;
}
});

mDigits.setOnFocusChangeListener(new View.OnFocusChangeListener() {
public void onFocusChange(View v, boolean hasFocus) {
// TODO Auto-generated method stub
mNumber = ((EditText)v).getText().toString();
Log.w(TAG, "mNumber2 = " + mNumber);
// startQuery();

}

});


//mAdapter=new ContactItemListAdapter(this);
myAdapter = new MyListAdapter(this);//listView

setListAdapter(myAdapter);
//mListView.setOnKeyListener(this);


// We manually save/restore the listview state
//mListView.setSaveEnabled(false);
//mQueryHandler = new QueryHandler(this);
listViewListener();// after the click ,then set the mDigits value
maybeAddNumberFormatting();// the mDigits value
/*
mListView.setOnItemClickListener(new OnItemClickListener() {

@Override
public void onItemClick(AdapterView<?> adapterView, View view,
int position, long id) {

if(mDigits.toString()!=null){
mDigits.setText(mContactsNumber.get(position));
mDigits.setSelection(mContactsNumber.get(position).length());
mDrawer.open();
}

// Intent dialIntent = new Intent(Intent.ACTION_CALL, Uri
// .parse("tel:" + mContactsNumber.get(position)));
// startActivity(dialIntent);
}
}); */


Log.w("START","wo");
// Check for the presence of the keypad
View view = findViewById(R.id.one);
if (view != null) {
setupKeypad();
}
Log.w("START","men");
//mVoicemailDialAndDeleteRow = findViewById(R.id.voicemailAndDialAndDelete);


// initVoicemailButton();


// Check whether we should show the onscreen "Dial" button.
//mDialButton = mVoicemailDialAndDeleteRow.findViewById(R.id.dialButton);
/*
if (r.getBoolean(R.bool.config_show_onscreen_dial_button)) {
mDialButton.setOnClickListener(this);
} else {
mDialButton.setVisibility(View.GONE); // It's VISIBLE by default
mDialButton = null;
}
*/
//mao
// view = mVoicemailDialAndDeleteRow.findViewById(R.id.deleteButton);
//Log.w("deletevalaue",String.valueOf(R.id.delete_Button));
//View v=findViewById(getContentViewResource());
view=findViewById(R.id.deleteButton);//mao

view.setOnClickListener(this);
view.setOnLongClickListener(this);
mDelete = view;

mDialpad = findViewById(R.id.slidingdrawer); // This is null in landscape mode.
Log.w("START",mDialpad.toString());
// mao
// initVoicemailButton();


// Check whether we should show the onscreen "Dial" button.
mDialButton = mDialpad.findViewById(R.id.dialButton1);
mGSM2DialButton=mDialpad.findViewById(R.id.dialButton2);
mEmptyDialButton=mDialpad.findViewById(R.id.emptyButton);
//mao
if(isCardEmpty){
mEmptyDialButton.setVisibility(View.VISIBLE); // It's VISIBLE by default
mEmptyDialButton.setOnClickListener(this);
mDialButton.setVisibility(View.GONE); // It's VISIBLE by default
//mVoicemailButton.setVisibility(View.GONE);
}else{
if (r.getBoolean(R.bool.config_show_onscreen_dial_button)) {
mDialButton.setOnClickListener(this);
mGSM2DialButton.setOnClickListener(this);
mEmptyDialButton.setVisibility(View.GONE);
mDialButton.setVisibility(View.VISIBLE); // It's VISIBLE by default
mGSM2DialButton.setVisibility(View.VISIBLE); // It's VISIBLE by default
//mVoicemailButton.setVisibility(View.GONE);
} else {
mDialButton.setVisibility(View.GONE); // It's VISIBLE by default
mDialButton = null;
mGSM2DialButton.setVisibility(View.GONE); // It's VISIBLE by default
mGSM2DialButton = null;
}

}



//mao add slidingDrawer
mDrawer=(MySlidingDrawer)mDialpad.findViewById(R.id.slidingdrawer);
mDrawer.setVisibility(View.VISIBLE);//make the MySlidingDrawer visible
imbg=(ImageButton)findViewById(R.id.handle_button);// the handle button
//set id of the slidingDrawer handle
mDrawer.setHandleId(R.id.handle_button); //R.id.other_handles
mDrawer.setTouchableIds(new int[] { R.id.handle_layout2,R.id.handle_layout3,R.id.handle_layout4 });// the other hanle area which is not in MySlidingDrawer
findViewById(R.id.handle_layout2).setOnClickListener(this);
findViewById(R.id.handle_layout3).setOnClickListener(this);
findViewById(R.id.handle_layout4).setOnClickListener(this);
mContent=findViewById(R.id.content);
mDrawer.open();
//mContent.setVisibility(View.VISIBLE);
//mao
addDrawerlistener();


// In landscape we put the keyboard in phone mode.
// In portrait we prevent the soft keyboard to show since the
// dialpad acts as one already.
if (null == mDialpad) {
mDigits.setInputType(android.text.InputType.TYPE_CLASS_PHONE);
} else {
mDigits.setInputType(android.text.InputType.TYPE_NULL);
}


// Set up the "dialpad chooser" UI; see showDialpadChooser().
mDialpadChooser = (ListView) findViewById(R.id.dialpadChooser);
mDialpadChooser.setOnItemClickListener(this);


if (!resolveIntent() && icicle != null) {
super.onRestoreInstanceState(icicle);
}


try {
mHaptic.init(this, r.getBoolean(R.bool.config_enable_dialer_key_vibration));
} catch (Resources.NotFoundException nfe) {
Log.e(TAG, "Vibrate control bool missing.", nfe);
}


}



private void listViewListener() {


mListView.setOnItemClickListener(new OnItemClickListener() {

@Override
public void onItemClick(AdapterView<?> adapterView, View view,
int position, long id) {

Log.w("nameSize:",String.valueOf(mContactNameTemp.size()));
Log.w("numberSize:",String.valueOf(mContactNumberTemp.size()));
Log.w("photoSize:",String.valueOf(mContactPhontoTemp.size()));
Log.w("position1:",mContactNumberTemp.get(position));
Log.w("position:",String.valueOf(position));
String number=mContactNumberTemp.get(position);
mDigits.setText(number);
mDigits.setSelection(number.length());//make the edit text selection base on the String length
mDrawer.open();


// Intent dialIntent = new Intent(Intent.ACTION_CALL, Uri
// .parse("tel:" + mContactsNumber.get(position)));
// startActivity(dialIntent);
}

});
mListView.setOnFocusChangeListener(new View.OnFocusChangeListener() {
public void onFocusChange(View v, boolean hasFocus) {
if (hasFocus) {
myHandler.postAtFrontOfQueue(new Runnable() {
public void run() {

}
});
}
}
});

}

private void addDrawerlistener() {
//mao
final ImageButton viewOne = (ImageButton) findViewById(R.id.one);
final ImageButton viewTwo= (ImageButton) findViewById(R.id.two);
final ImageButton viewThree = (ImageButton) findViewById(R.id.three);
mDrawer.setOnDrawerOpenListener(new MySlidingDrawer.OnDrawerOpenListener(){
@Override
public void onDrawerOpened() {

flag=true;
imbg.setImageResource(R.drawable.handle_down);

viewOne.setImageResource(R.drawable.dial_num_1_no_vm);
viewOne.setEnabled(true);

viewTwo.setImageResource(R.drawable.dial_num_2);
viewTwo.setEnabled(true);

viewThree.setImageResource(R.drawable.dial_num_3);
viewThree.setEnabled(true);

}
});

mDrawer.setOnDrawerCloseListener(new MySlidingDrawer.OnDrawerCloseListener(){


@Override
public void onDrawerClosed() {

flag=false;
imbg.setImageResource(R.drawable.handle_up);


viewOne.setImageResource(R.drawable.num1);
viewOne.setEnabled(false);

viewTwo.setImageResource(R.drawable.num2);
viewTwo.setEnabled(false);

viewThree.setImageResource(R.drawable.num3);
viewThree.setEnabled(false);

//listViewListener();
//mListView.postInvalidate();
//setListAdapter(myAdapter);
//mDrawer.setFocusable(false);
mListView.setFocusable(true);
mListView.setFocusableInTouchMode(true);
mListView.requestFocus();
mListView.requestFocusFromTouch();
//listView2.requestFocusFromTouch();
//ListView1.clearFocus();

}
});

mDrawer.setOnDrawerScrollListener(new MySlidingDrawer.OnDrawerScrollListener(){
@Override
public void onScrollEnded() {

}


@Override
public void onScrollStarted() {

}

});
// the real drawer the buttom area, Click for closing the Drawer when 在打开状态点击时关闭抽屉
/*
mcontent.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
if (mDrawer.isOpened()) {
mDrawer.animateClose();
}
}
}); */
}

@Override
protected void onRestoreInstanceState(Bundle icicle) {
// Do nothing, state is restored in onCreate() if needed
}


protected void maybeAddNumberFormatting() {
mDigits.addTextChangedListener(new PhoneNumberFormattingTextWatcher(){

@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
// Does nothing
Log.w("numbers:",s.toString());//mao
numberCharge=s.toString();
if(s!=null&&s.length()>0){
//PHONES_SELECTION=ContactsContract.CommonDataKinds.Phone.NUMBER + " like '%" +PhoneNumberUtils.formatNumber(s.toString())+ "%'";
}else{
PHONES_SELECTION=null;
}
//Log.w("PHONES_SELECTION",PHONES_SELECTION);
//getPhoneContacts();
startQueryContacts();
myAdapter.notifyDataSetChanged();//mainly used , when one row data change
setListAdapter(myAdapter);

// SpannableStringBuilder style=new SpannableStringBuilder(s);
// style.setSpan(new ForegroundColorSpan(Color.RED),3,8,Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
//3代表从第几个字符开始变颜色,注意第一个字符序号是0.
//8代表变色到第几个字符.
// textview.setText(style);  changer*/


}

});
}


/**
* Overridden by subclasses to control the resource used by the content
* view.
*/
protected int getContentViewResource() {
return R.layout.twelve_key_dialer;
}


private boolean resolveIntent() {
boolean ignoreState = false;


// Find the proper intent
final Intent intent;
if (isChild()) {
intent = getParent().getIntent();
ignoreState = intent.getBooleanExtra(
DialtactsActivity.EXTRA_IGNORE_STATE, false);
} else {
intent = getIntent();
}
// Log.i(TAG, "==> resolveIntent(): intent: " + intent);


// by default we are not adding a call.
mIsAddCallMode = false;


// By default we don't show the "dialpad chooser" UI.
boolean needToShowDialpadChooser = false;


// Resolve the intent
final String action = intent.getAction();
if (Intent.ACTION_DIAL.equals(action)
|| Intent.ACTION_VIEW.equals(action)) {
// see if we are "adding a call" from the InCallScreen; false by
// default.
mIsAddCallMode = intent.getBooleanExtra(ADD_CALL_MODE_KEY, false);


Uri uri = intent.getData();
if (uri != null) {
if ("tel".equals(uri.getScheme())) {
// Put the requested number into the input area
String data = uri.getSchemeSpecificPart();
setFormattedDigits(data);
} else {
String type = intent.getType();
if (People.CONTENT_ITEM_TYPE.equals(type)
|| Phones.CONTENT_ITEM_TYPE.equals(type)) {
// Query the phone number
Cursor c = getContentResolver().query(intent.getData(),
new String[] { PhonesColumns.NUMBER }, null,
null, null);
if (c != null) {
if (c.moveToFirst()) {
// Put the number into the input area
setFormattedDigits(c.getString(0));
}
c.close();
}
}
}
} else {
// ACTION_DIAL or ACTION_VIEW with no data.
// This behaves basically like ACTION_MAIN: If there's
// already an active call, bring up an intermediate UI to
// make the user confirm what they really want to do.
// Be sure *not* to show the dialpad chooser if this is an
// explicit "Add call" action, though.
if (!mIsAddCallMode && phoneIsInUse()) {
needToShowDialpadChooser = true;
}
}
} else if (Intent.ACTION_MAIN.equals(action)) {
// The MAIN action means we're bringing up a blank dialer
// (e.g. by selecting the Home shortcut, or tabbing over from
// Contacts or Call log.)
//
// At this point, IF there's already an active call, there's a
// good chance that the user got here accidentally (but really
// wanted the in-call dialpad instead). So we bring up an
// intermediate UI to make the user confirm what they really
// want to do.
if (phoneIsInUse()) {
// Log.i(TAG,
// "resolveIntent(): phone is in use; showing dialpad chooser!"
// );
needToShowDialpadChooser = true;
}
}


// Bring up the "dialpad chooser" IFF we need to make the user
// confirm which dialpad they really want.
showDialpadChooser(needToShowDialpadChooser);


return ignoreState;
}


protected void setFormattedDigits(String data) {
// strip the non-dialable numbers out of the data string.
String dialString = PhoneNumberUtils.extractNetworkPortion(data);
dialString = PhoneNumberUtils.formatNumber(dialString);
if (!TextUtils.isEmpty(dialString)) {
Editable digits = mDigits.getText();
digits.replace(0, digits.length(), dialString);
// for some reason this isn't getting called in the digits.replace
// call above..
// but in any case, this will make sure the background drawable
// looks right
afterTextChanged(digits);
}
}


@Override
protected void onNewIntent(Intent newIntent) {
setIntent(newIntent);
resolveIntent();
}


@Override
protected void onPostCreate(Bundle savedInstanceState) {
super.onPostCreate(savedInstanceState);


// This can't be done in onCreate(), since the auto-restoring of the
// digits
// will play DTMF tones for all the old digits if it is when
// onRestoreSavedInstanceState()
// is called. This method will be called every time the activity is
// created, and
// will always happen after onRestoreSavedInstanceState().
mDigits.addTextChangedListener(this);
}


private void setupKeypad() {
// Setup the listeners for the buttons
View view = findViewById(R.id.one);
view.setOnClickListener(this);
/*view.setOnTouchListener(new OnTouchListener(){


@Override
public boolean onTouch(View v, MotionEvent event) {
// TODO Auto-generated method stub

switch (event.getAction()) {


case MotionEvent.ACTION_DOWN:
final int xSpan = (int) event.getX();
final int ySpan = (int) event.getY();
findViewById(R.id.two).setOnTouchListener(null);
break;
case MotionEvent.ACTION_MOVE:
findViewById(R.id.two).setOnTouchListener(null);
break;
case MotionEvent.ACTION_UP:
findViewById(R.id.two).setOnTouchListener(null);
break;
case MotionEvent.ACTION_CANCEL:


break;


}
return false;
}


});*/



view.setOnLongClickListener(this);
findViewById(R.id.two).setOnClickListener(this);
findViewById(R.id.three).setOnClickListener(this);

findViewById(R.id.four).setOnClickListener(this);
findViewById(R.id.five).setOnClickListener(this);
findViewById(R.id.six).setOnClickListener(this);
findViewById(R.id.seven).setOnClickListener(this);
findViewById(R.id.eight).setOnClickListener(this);
findViewById(R.id.nine).setOnClickListener(this);
findViewById(R.id.star).setOnClickListener(this);


view = findViewById(R.id.zero);
view.setOnClickListener(this);
view.setOnLongClickListener(this);


findViewById(R.id.pound).setOnClickListener(this);
}




@Override
protected void onStart() {
mScrollToTop = true;
super.onStart();
}


@Override
protected void onRestart() {
mScrollToTop = true;
//startQuery();
getPhoneContacts();//mao
super.onRestart();
}



@Override
protected void onResume() {
super.onResume();


// Query the last dialed number. Do it first because hitting
// the DB is 'slow'. This call is asynchronous.
queryLastOutgoingCall();

if (mAdapter != null) {
// mAdapter.clearCache();
}
//mao query the contacts list
//startQuery();
// getPhoneContacts();


// retrieve the DTMF tone play back setting.
mDTMFToneEnabled = Settings.System.getInt(getContentResolver(),
Settings.System.DTMF_TONE_WHEN_DIALING, 1) == 1;


// Retrieve the haptic feedback setting.
mHaptic.checkSystemSetting();


// if the mToneGenerator creation fails, just continue without it. It is
// a local audio signal, and is not as important as the dtmf tone
// itself.
synchronized (mToneGeneratorLock) {
if (mToneGenerator == null) {
try {
// we want the user to be able to control the volume of the
// dial tones
// outside of a call, so we use the stream type that is also
// mapped to the
// volume control keys for this activity
mToneGenerator = new ToneGenerator(DIAL_TONE_STREAM_TYPE,
TONE_RELATIVE_VOLUME);
setVolumeControlStream(DIAL_TONE_STREAM_TYPE);
} catch (RuntimeException e) {
Log.w(TAG,
"Exception caught while creating local tone generator: "
+ e);
mToneGenerator = null;
}
}
}


Activity parent = getParent();
// See if we were invoked with a DIAL intent. If we were, fill in the
// appropriate
// digits in the dialer field.
if (parent != null && parent instanceof DialtactsActivity) {
Uri dialUri = ((DialtactsActivity) parent).getAndClearDialUri();
if (dialUri != null) {
resolveIntent();
}
}


// While we're in the foreground, listen for phone state changes,
// purely so that we can take down the "dialpad chooser" if the
// phone becomes idle while the chooser UI is visible.
TelephonyManager telephonyManager = (TelephonyManager) getSystemService(TELEPHONY_SERVICE);
telephonyManager.listen(mPhoneStateListener,
PhoneStateListener.LISTEN_CALL_STATE);


// Potentially show hint text in the mDigits field when the user
// hasn't typed any digits yet. (If there's already an active call,
// this hint text will remind the user that he's about to add a new
// call.)
//
// TODO: consider adding better UI for the case where *both* lines
// are currently in use. (Right now we let the user try to add
// another call, but that call is guaranteed to fail. Perhaps the
// entire dialer UI should be disabled instead.)
if (phoneIsInUse()) {
mDigits.setHint(R.string.dialerDialpadHintText);
} else {
// Common case; no hint necessary.
mDigits.setHint(null);


// Also, a sanity-check: the "dialpad chooser" UI should NEVER
// be visible if the phone is idle!
showDialpadChooser(false);
}
//mao
updateDialAndDeleteButtonEnabledState();

}


@Override
public void onWindowFocusChanged(boolean hasFocus) {
if (hasFocus) {
// Hide soft keyboard, if visible (it's fugly over button dialer).
// The only known case where this will be true is when launching the
// dialer with
// ACTION_DIAL via a soft keyboard. we dismiss it here because we
// don't
// have a window token yet in onCreate / onNewIntent
InputMethodManager inputMethodManager = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
inputMethodManager.hideSoftInputFromWindow(
mDigits.getWindowToken(), 0);
}
}


@Override
protected void onPause() {
super.onPause();


// Stop listening for phone state changes.
TelephonyManager telephonyManager = (TelephonyManager) getSystemService(TELEPHONY_SERVICE);
telephonyManager.listen(mPhoneStateListener,
PhoneStateListener.LISTEN_NONE);


synchronized (mToneGeneratorLock) {
if (mToneGenerator != null) {
mToneGenerator.release();
mToneGenerator = null;
}
}
// TODO: I wonder if we should not check if the AsyncTask that
// lookup the last dialed number has completed.
mLastNumberDialed = EMPTY_NUMBER; // Since we are going to query again,
// free stale number.
}


@Override
public boolean onCreateOptionsMenu(Menu menu) {
mAddToContactMenuItem = menu.add(0, MENU_ADD_CONTACTS, 0,
R.string.recentCalls_addToContact).setIcon(
android.R.drawable.ic_menu_add);
m2SecPauseMenuItem = menu.add(0, MENU_2S_PAUSE, 0,
R.string.add_2sec_pause).setIcon(R.drawable.ic_menu_2sec_pause);
mWaitMenuItem = menu.add(0, MENU_WAIT, 0, R.string.add_wait).setIcon(
R.drawable.ic_menu_wait);
return true;
}


@Override
public boolean onPrepareOptionsMenu(Menu menu) {
// We never show a menu if the "choose dialpad" UI is up.
if (dialpadChooserVisible()) {
return false;
}


if (isDigitsEmpty()) {
mAddToContactMenuItem.setVisible(false);
m2SecPauseMenuItem.setVisible(false);
mWaitMenuItem.setVisible(false);
} else {
CharSequence digits = mDigits.getText();


// Put the current digits string into an intent
Intent intent = new Intent(Intent.ACTION_INSERT_OR_EDIT);
intent.putExtra(Insert.PHONE, digits);
intent.setType(People.CONTENT_ITEM_TYPE);
mAddToContactMenuItem.setIntent(intent);
mAddToContactMenuItem.setVisible(true);


// Check out whether to show Pause & Wait option menu items
int selectionStart;
int selectionEnd;
String strDigits = digits.toString();


selectionStart = mDigits.getSelectionStart();
selectionEnd = mDigits.getSelectionEnd();


if (selectionStart != -1) {
if (selectionStart > selectionEnd) {
// swap it as we want start to be less then end
int tmp = selectionStart;
selectionStart = selectionEnd;
selectionEnd = tmp;
}


if (selectionStart != 0) {
// Pause can be visible if cursor is not in the begining
m2SecPauseMenuItem.setVisible(true);


// For Wait to be visible set of condition to meet
mWaitMenuItem.setVisible(showWait(selectionStart,
selectionEnd, strDigits));
} else {
// cursor in the beginning both pause and wait to be
// invisible
m2SecPauseMenuItem.setVisible(false);
mWaitMenuItem.setVisible(false);
}
} else {
// cursor is not selected so assume new digit is added to the
// end
int strLength = strDigits.length();
mWaitMenuItem.setVisible(showWait(strLength, strLength,
strDigits));
}
}
return true;
}


@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
switch (keyCode) {
case KeyEvent.KEYCODE_CALL: {
long callPressDiff = SystemClock.uptimeMillis()
- event.getDownTime();
if (callPressDiff >= ViewConfiguration.getLongPressTimeout()) {
// Launch voice dialer
Intent intent = new Intent(Intent.ACTION_VOICE_COMMAND);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
try {
startActivity(intent);
} catch (ActivityNotFoundException e) {
}
}
return true;
}
case KeyEvent.KEYCODE_1: {
long timeDiff = SystemClock.uptimeMillis() - event.getDownTime();
if (timeDiff >= ViewConfiguration.getLongPressTimeout()) {
// Long press detected, call voice mail
callVoicemail();
}
return true;
}
}
return super.onKeyDown(keyCode, event);
}


@Override
public boolean onKeyUp(int keyCode, KeyEvent event) {
switch (keyCode) {
case KeyEvent.KEYCODE_CALL: {
// TODO: In dialButtonPressed we do some of these
// tests again. We should try to consolidate them in
// one place.
if (!phoneIsCdma() && mIsAddCallMode && isDigitsEmpty()) {
// For CDMA phones, we always call
// dialButtonPressed() because we may need to send
// an empty flash command to the network.
// Otherwise, if we are adding a call from the
// InCallScreen and the phone number entered is
// empty, we just close the dialer to expose the
// InCallScreen under it.
finish();
}


// If we're CDMA, regardless of where we are adding a call from
// (either
// InCallScreen or Dialtacts), the user may need to send an empty
// flash command to the network. So let's call dialButtonPressed()
// regardless
// and dialButtonPressed will handle this functionality for us.
// otherwise, we place the call.
dialButtonPressed();
return true;
}
}
return super.onKeyUp(keyCode, event);
}


private void keyPressed(int keyCode) {
mHaptic.vibrate();
KeyEvent event = new KeyEvent(KeyEvent.ACTION_DOWN, keyCode);
mDigits.onKeyDown(keyCode, event);
}


public boolean onKey(View view, int keyCode, KeyEvent event) {
switch (view.getId()) {
case R.id.digits:
if (keyCode == KeyEvent.KEYCODE_ENTER) {
dialButtonPressed();
return true;
}
break;
}
return false;
}


public void onClick(View view) {
switch (view.getId()) {
case R.id.one: {
playTone(ToneGenerator.TONE_DTMF_1);
keyPressed(KeyEvent.KEYCODE_1);
return;
}
case R.id.two: {
playTone(ToneGenerator.TONE_DTMF_2);
keyPressed(KeyEvent.KEYCODE_2);
return;
}
case R.id.three: {
playTone(ToneGenerator.TONE_DTMF_3);
keyPressed(KeyEvent.KEYCODE_3);
return;
}
case R.id.four: {
playTone(ToneGenerator.TONE_DTMF_4);
keyPressed(KeyEvent.KEYCODE_4);
return;
}
case R.id.five: {
playTone(ToneGenerator.TONE_DTMF_5);
keyPressed(KeyEvent.KEYCODE_5);
return;
}
case R.id.six: {
playTone(ToneGenerator.TONE_DTMF_6);
keyPressed(KeyEvent.KEYCODE_6);
return;
}
case R.id.seven: {
playTone(ToneGenerator.TONE_DTMF_7);
keyPressed(KeyEvent.KEYCODE_7);
return;
}
case R.id.eight: {
playTone(ToneGenerator.TONE_DTMF_8);
keyPressed(KeyEvent.KEYCODE_8);
return;
}
case R.id.nine: {
playTone(ToneGenerator.TONE_DTMF_9);
keyPressed(KeyEvent.KEYCODE_9);
return;
}
case R.id.zero: {
playTone(ToneGenerator.TONE_DTMF_0);
keyPressed(KeyEvent.KEYCODE_0);
return;
}
case R.id.pound: {
playTone(ToneGenerator.TONE_DTMF_P);
keyPressed(KeyEvent.KEYCODE_POUND);
return;
}
case R.id.star: {
playTone(ToneGenerator.TONE_DTMF_S);
keyPressed(KeyEvent.KEYCODE_STAR);
return;
}//mao
case R.id.deleteButton: {
keyPressed(KeyEvent.KEYCODE_DEL);
return;
}
case R.id.dialButton1: {
mHaptic.vibrate(); // Vibrate here too, just like we do for the
// regular keys
dialButtonPressed();
return;
}
case R.id.dialButton2: {
mHaptic.vibrate(); // Vibrate here too, just like we do for the
// regular keys
GSM2dialButtonPressed();
return;
}
case R.id.emptyButton: {
mHaptic.vibrate(); // Vibrate here too, just like we do for the
// regular keys
emptyButtonPressed();
return;
}
case R.id.voicemailButton: {
callVoicemail();
mHaptic.vibrate();
return;
}
case R.id.digits: {
if (!isDigitsEmpty()) {
mDigits.setCursorVisible(true);
}
return;
}
}
}


public boolean onLongClick(View view) {
final Editable digits = mDigits.getText();
int id = view.getId();
switch (id) {
case R.id.deleteButton: {
digits.clear();
//TODO: The framework forgets to clear the pressed
// status of disabled button. Until this is fixed,
// clear manually the pressed status. b/2133127
mDelete.setPressed(false);
return true;
}
case R.id.one: {
if (isDigitsEmpty()) {
//callVoicemail();
return true;
}
return false;
}
case R.id.zero: {
keyPressed(KeyEvent.KEYCODE_PLUS);
return true;
}
}
return false;
}


void callVoicemail() {
StickyTabs.saveTab(this, getIntent());
Intent intent = new Intent(Intent.ACTION_CALL_PRIVILEGED, Uri
.fromParts("voicemail", EMPTY_NUMBER, null));
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
mDigits.getText().clear();
finish();
}

//mao add emptyButtonPressed()
void emptyButtonPressed(){

final String number = mDigits.getText().toString();
if (PhoneNumberUtils.isEmergencyNumber(number)) {


// place the call if it is a valid number
if(number == null||number.length()==0 ){
showDialog(NUMBER_EMTPY);
}
if (!TextUtils.isGraphic(number)) {
// There is no number entered.
playTone(ToneGenerator.TONE_PROP_NACK);
return;
}
Intent intent = new Intent(Intent.ACTION_CALL_EMERGENCY);
intent.setData(Uri.fromParts("tel", number, null));
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
finish();
} else {


// erase the number and throw up an alert dialog.
mDigits.getText().delete(0, mDigits.getText().length());
showDialog(NUMBER_NOT_EMERGENCY);
}

}

protected Dialog onCreateDialog(int id) {
switch (id) {
case NUMBER_EMTPY:
return new AlertDialog.Builder(TwelveKeyDialer.this).setIcon(
android.R.drawable.ic_dialog_info).setTitle("emergency call")
.setMessage("call failed,please dial emergency call!").setPositiveButton("confirm",
new DialogInterface.OnClickListener() {


@Override
public void onClick(DialogInterface a0, int a1) {
// TODO Auto-generated method stub
}


}).create();
case NUMBER_NOT_EMERGENCY:
return new AlertDialog.Builder(TwelveKeyDialer.this).setIcon(
android.R.drawable.ic_dialog_info).setTitle("emergency call")
.setMessage(
"call failed,because" + mDigits.getText().toString()
+ "is not a emergency number!").setPositiveButton("confirm",
new DialogInterface.OnClickListener() {


@Override
public void onClick(DialogInterface a0, int a1) {
// TODO Auto-generated method stub
}


}).create();
default:
return null;
}


}
//mao
void GSM2dialButtonPressed(){
final String number = mDigits.getText().toString();
boolean sendEmptyFlash = false;
Intent intent = new Intent(Intent.ACTION_CALL_PRIVILEGED);


if (isDigitsEmpty()) { // There is no number entered.
if (phoneIsCdma() && phoneIsOffhook()) {
// On CDMA phones, if we're already on a call, pressing
// the Dial button without entering any digits means "send
// an empty flash."
intent.setData(Uri.fromParts("tel", EMPTY_NUMBER, null));
intent.putExtra(EXTRA_SEND_EMPTY_FLASH, true);
sendEmptyFlash = true;
} else if (!TextUtils.isEmpty(mLastNumberDialed)) {
// Otherwise, pressing the Dial button without entering
// any digits means "recall the last number dialed".
mDigits.setText(mLastNumberDialed);
return;
} else {
// Rare case: there's no "last number dialed". There's
// nothing useful for the Dial button to do in this case.
playTone(ToneGenerator.TONE_PROP_NACK);
return;
}
} else { // There is a number.
intent.setData(Uri.fromParts("tel", number, null));
intent.putExtra("network", "G2");//mao
}


StickyTabs.saveTab(this, getIntent());
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
mDigits.getText().clear();
if (!sendEmptyFlash) {
finish();
}

}

//mao dialButtonOnPressed ,ACTION_CALL_PRIVILEGED
void dialButtonPressed() {
final String number = mDigits.getText().toString();
boolean sendEmptyFlash = false;
Intent intent = new Intent(Intent.ACTION_CALL_PRIVILEGED);


if (isDigitsEmpty()) { // There is no number entered.
if (phoneIsCdma() && phoneIsOffhook()) {
// On CDMA phones, if we're already on a call, pressing
// the Dial button without entering any digits means "send
// an empty flash."
intent.setData(Uri.fromParts("tel", EMPTY_NUMBER, null));
intent.putExtra(EXTRA_SEND_EMPTY_FLASH, true);
sendEmptyFlash = true;
} else if (!TextUtils.isEmpty(mLastNumberDialed)) {
// Otherwise, pressing the Dial button without entering
// any digits means "recall the last number dialed".
mDigits.setText(mLastNumberDialed);
return;
} else {
// Rare case: there's no "last number dialed". There's
// nothing useful for the Dial button to do in this case.
playTone(ToneGenerator.TONE_PROP_NACK);
return;
}
} else { // There is a number.
intent.setData(Uri.fromParts("tel", number, null));
intent.putExtra("network", "G1");//mao
}


StickyTabs.saveTab(this, getIntent());
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
mDigits.getText().clear();


// Don't finish TwelveKeyDialer yet if we're sending a blank flash for
// CDMA. CDMA
// networks use Flash messages when special processing needs to be done,
// mainly for
// 3-way or call waiting scenarios. Presumably, here we're in a special
// 3-way scenario
// where the network needs a blank flash before being able to add the
// new participant.
// (This is not the case with all 3-way calls, just certain CDMA
// infrastructures.)
if (!sendEmptyFlash) {
finish();
}
}


/**
* Plays the specified tone for TONE_LENGTH_MS milliseconds.
*
* The tone is played locally, using the audio stream for phone calls. Tones
* are played only if the "Audible touch tones" user preference is checked,
* and are NOT played if the device is in silent mode.
*
* @param tone
* a tone code from {@link ToneGenerator}
*/
void playTone(int tone) {
// if local tone playback is disabled, just return.
if (!mDTMFToneEnabled) {
return;
}


// Also do nothing if the phone is in silent mode.
// We need to re-check the ringer mode for *every* playTone()
// call, rather than keeping a local flag that's updated in
// onResume(), since it's possible to toggle silent mode without
// leaving the current activity (via the ENDCALL-longpress menu.)
AudioManager audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
int ringerMode = audioManager.getRingerMode();
if ((ringerMode == AudioManager.RINGER_MODE_SILENT)
|| (ringerMode == AudioManager.RINGER_MODE_VIBRATE)) {
return;
}


synchronized (mToneGeneratorLock) {
if (mToneGenerator == null) {
Log.w(TAG, "playTone: mToneGenerator == null, tone: " + tone);
return;
}


// Start the new tone (will stop any playing tone)
mToneGenerator.startTone(tone, TONE_LENGTH_MS);
}
}


/**
* Brings up the "dialpad chooser" UI in place of the usual Dialer elements
* (the textfield/button and the dialpad underneath).
*
* We show this UI if the user brings up the Dialer while a call is already
* in progress, since there's a good chance we got here accidentally (and
* the user really wanted the in-call dialpad instead). So in this situation
* we display an intermediate UI that lets the user explicitly choose
* between the in-call dialpad ("Use touch tone
* keypad") and the regular Dialer ("Add call"). (Or, the option "Return to
* call in progress" just goes back to the in-call UI with no dialpad at
* all.)
*
* @param enabled
* If true, show the "dialpad chooser" instead of the regular
* Dialer UI
*/
private void showDialpadChooser(boolean enabled) {
if (enabled) {
// Log.i(TAG, "Showing dialpad chooser!");
mDigits.setVisibility(View.GONE);
if (mDialpad != null)
mDialpad.setVisibility(View.GONE);
//mVoicemailDialAndDeleteRow.setVisibility(View.GONE);
mDialpadChooser.setVisibility(View.VISIBLE);


// Instantiate the DialpadChooserAdapter and hook it up to the
// ListView. We do this only once.
if (mDialpadChooserAdapter == null) {
mDialpadChooserAdapter = new DialpadChooserAdapter(this);
mDialpadChooser.setAdapter(mDialpadChooserAdapter);
}
} else {
// Log.i(TAG, "Displaying normal Dialer UI.");
mDigits.setVisibility(View.VISIBLE);
if (mDialpad != null)
mDialpad.setVisibility(View.VISIBLE);
//mVoicemailDialAndDeleteRow.setVisibility(View.VISIBLE);
mDialpadChooser.setVisibility(View.GONE);
}
}


/**
* @return true if we're currently showing the "dialpad chooser" UI.
*/
private boolean dialpadChooserVisible() {
return mDialpadChooser.getVisibility() == View.VISIBLE;
}


/**
* Simple list adapter, binding to an icon + text label for each item in the
* "dialpad chooser" list.
*/
private static class DialpadChooserAdapter extends BaseAdapter {
private LayoutInflater mInflater;


// Simple struct for a single "choice" item.
static class ChoiceItem {
String text;
Bitmap icon;
int id;


public ChoiceItem(String s, Bitmap b, int i) {
text = s;
icon = b;
id = i;
}
}


// IDs for the possible "choices":
static final int DIALPAD_CHOICE_USE_DTMF_DIALPAD = 101;
static final int DIALPAD_CHOICE_RETURN_TO_CALL = 102;
static final int DIALPAD_CHOICE_ADD_NEW_CALL = 103;


private static final int NUM_ITEMS = 3;
private ChoiceItem mChoiceItems[] = new ChoiceItem[NUM_ITEMS];


public DialpadChooserAdapter(Context context) {
// Cache the LayoutInflate to avoid asking for a new one each time.
mInflater = LayoutInflater.from(context);


// Initialize the possible choices.
// TODO: could this be specified entirely in XML?


// - "Use touch tone keypad"
mChoiceItems[0] = new ChoiceItem(context
.getString(R.string.dialer_useDtmfDialpad), BitmapFactory
.decodeResource(context.getResources(),
R.drawable.ic_dialer_fork_tt_keypad),
DIALPAD_CHOICE_USE_DTMF_DIALPAD);


// - "Return to call in progress"
mChoiceItems[1] = new ChoiceItem(context
.getString(R.string.dialer_returnToInCallScreen),
BitmapFactory.decodeResource(context.getResources(),
R.drawable.ic_dialer_fork_current_call),
DIALPAD_CHOICE_RETURN_TO_CALL);


// - "Add call"
mChoiceItems[2] = new ChoiceItem(context
.getString(R.string.dialer_addAnotherCall), BitmapFactory
.decodeResource(context.getResources(),
R.drawable.ic_dialer_fork_add_call),
DIALPAD_CHOICE_ADD_NEW_CALL);
}


public int getCount() {
return NUM_ITEMS;
}


/**
* Return the ChoiceItem for a given position.
*/
public Object getItem(int position) {
return mChoiceItems[position];
}


/**
* Return a unique ID for each possible choice.
*/
public long getItemId(int position) {
return position;
}


/**
* Make a view for each row.
*/
public View getView(int position, View convertView, ViewGroup parent) {
// When convertView is non-null, we can reuse it (there's no need
// to reinflate it.)
if (convertView == null) {
convertView = mInflater.inflate(
R.layout.dialpad_chooser_list_item, null);
}


TextView text = (TextView) convertView.findViewById(R.id.text);
text.setText(mChoiceItems[position].text);


ImageView icon = (ImageView) convertView.findViewById(R.id.icon);
icon.setImageBitmap(mChoiceItems[position].icon);


return convertView;
}
}


/**
* Handle clicks from the dialpad chooser.
*/
public void onItemClick(AdapterView parent, View v, int position, long id) {
DialpadChooserAdapter.ChoiceItem item = (DialpadChooserAdapter.ChoiceItem) parent
.getItemAtPosition(position);
int itemId = item.id;
switch (itemId) {
case DialpadChooserAdapter.DIALPAD_CHOICE_USE_DTMF_DIALPAD:
// Log.i(TAG, "DIALPAD_CHOICE_USE_DTMF_DIALPAD");
// Fire off an intent to go back to the in-call UI
// with the dialpad visible.
returnToInCallScreen(true);
break;


case DialpadChooserAdapter.DIALPAD_CHOICE_RETURN_TO_CALL:
// Log.i(TAG, "DIALPAD_CHOICE_RETURN_TO_CALL");
// Fire off an intent to go back to the in-call UI
// (with the dialpad hidden).
returnToInCallScreen(false);
break;


case DialpadChooserAdapter.DIALPAD_CHOICE_ADD_NEW_CALL:
// Log.i(TAG, "DIALPAD_CHOICE_ADD_NEW_CALL");
// Ok, guess the user really did want to be here (in the
// regular Dialer) after all. Bring back the normal Dialer UI.
showDialpadChooser(false);
break;


default:
Log.w(TAG, "onItemClick: unexpected itemId: " + itemId);
break;
}
}


/**
* Returns to the in-call UI (where there's presumably a call in progress)
* in response to the user selecting "use touch tone keypad" or
* "return to call" from the dialpad chooser.
*/
private void returnToInCallScreen(boolean showDialpad) {
try {
ITelephony phone = ITelephony.Stub.asInterface(ServiceManager
.checkService("phone"));
if (phone != null)
phone.showCallScreenWithDialpad(showDialpad);
} catch (RemoteException e) {
Log.w(TAG, "phone.showCallScreenWithDialpad() failed", e);
}


// Finally, finish() ourselves so that we don't stay on the
// activity stack.
// Note that we do this whether or not the showCallScreenWithDialpad()
// call above had any effect or not! (That call is a no-op if the
// phone is idle, which can happen if the current call ends while
// the dialpad chooser is up. In this case we can't show the
// InCallScreen, and there's no point staying here in the Dialer,
// so we just take the user back where he came from...)
finish();
}


/**
* @return true if the phone is "in use", meaning that at least one line is
* active (ie. off hook or ringing or dialing).
*/
private boolean phoneIsInUse() {
boolean phoneInUse = false;
try {
ITelephony phone = ITelephony.Stub.asInterface(ServiceManager
.checkService("phone"));
if (phone != null)
phoneInUse = !phone.isIdle();
} catch (RemoteException e) {
Log.w(TAG, "phone.isIdle() failed", e);
}
return phoneInUse;
}


/**
* @return true if the phone is a CDMA phone type
*/
private boolean phoneIsCdma() {
boolean isCdma = false;
try {
ITelephony phone = ITelephony.Stub.asInterface(ServiceManager
.checkService("phone"));
if (phone != null) {
isCdma = (phone.getActivePhoneType() == TelephonyManager.PHONE_TYPE_CDMA);
}
} catch (RemoteException e) {
Log.w(TAG, "phone.getActivePhoneType() failed", e);
}
return isCdma;
}


/**
* @return true if the phone state is OFFHOOK
*/
private boolean phoneIsOffhook() {
boolean phoneOffhook = false;
try {
ITelephony phone = ITelephony.Stub.asInterface(ServiceManager
.checkService("phone"));
if (phone != null)
phoneOffhook = phone.isOffhook();
} catch (RemoteException e) {
Log.w(TAG, "phone.isOffhook() failed", e);
}
return phoneOffhook;
}


/**
* Returns true whenever any one of the options from the menu is selected.
* Code changes to support dialpad options
*/
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case MENU_2S_PAUSE:
updateDialString(",");
return true;
case MENU_WAIT:
updateDialString(";");
return true;
}
return false;
}


/**
* Updates the dial string (mDigits) after inserting a Pause character (,)
* or Wait character (;).
*/
private void updateDialString(String newDigits) {
int selectionStart;
int selectionEnd;


// SpannableStringBuilder editable_text = new
// SpannableStringBuilder(mDigits.getText());
int anchor = mDigits.getSelectionStart();
int point = mDigits.getSelectionEnd();


selectionStart = Math.min(anchor, point);
selectionEnd = Math.max(anchor, point);


Editable digits = mDigits.getText();
if (selectionStart != -1) {
if (selectionStart == selectionEnd) {
// then there is no selection. So insert the pause at this
// position and update the mDigits.
digits.replace(selectionStart, selectionStart, newDigits);
} else {
digits.replace(selectionStart, selectionEnd, newDigits);
// Unselect: back to a regular cursor, just pass the character
// inserted.
mDigits.setSelection(selectionStart + 1);
}
} else {
int len = mDigits.length();
digits.replace(len, len, newDigits);
}
}


/**
* Update the enabledness of the "Dial" and "Backspace" buttons if
* applicable.
*/

private void updateDialAndDeleteButtonEnabledState() {
final boolean digitsNotEmpty = !isDigitsEmpty();
//mao
if (mDialButton != null) {
// On CDMA phones, if we're already on a call, we *always*
// enable the Dial button (since you can press it without
// entering any digits to send an empty flash.)
if (phoneIsCdma() && phoneIsOffhook()) {
mDialButton.setEnabled(true);
} else {
// Common case: GSM, or CDMA but not on a call.
// Enable the Dial button if some digits have
// been entered, or if there is a last dialed number
// that could be redialed.
mDialButton.setEnabled(digitsNotEmpty
|| !TextUtils.isEmpty(mLastNumberDialed));
}
}
mDelete.setEnabled(digitsNotEmpty);
}


/**
* Check if voicemail is enabled/accessible.
*/
private void initVoicemailButton() {
boolean hasVoicemail = false;
try {
hasVoicemail = TelephonyManager.getDefault().getVoiceMailNumber() != null;
} catch (SecurityException se) {
// Possibly no READ_PHONE_STATE privilege.
}


// mVoicemailButton = mVoicemailDialAndDeleteRow
// .findViewById(R.id.voicemailButton);
//mao
mVoicemailButton = mDialpad.findViewById(R.id.voicemailButton);
if (hasVoicemail) {
mVoicemailButton.setOnClickListener(this);
} else {
mVoicemailButton.setEnabled(false);
}
}

/**
* This function return true if Wait menu item can be shown otherwise
* returns false. Assumes the passed string is non-empty and the 0th index
* check is not required.
*/
private boolean showWait(int start, int end, String digits) {
if (start == end) {
// visible false in this case
if (start > digits.length())
return false;


// preceding char is ';', so visible should be false
if (digits.charAt(start - 1) == ';')
return false;


// next char is ';', so visible should be false
if ((digits.length() > start) && (digits.charAt(start) == ';'))
return false;
} else {
// visible false in this case
if (start > digits.length() || end > digits.length())
return false;


// In this case we need to just check for ';' preceding to start
// or next to end
if (digits.charAt(start - 1) == ';')
return false;
}
return true;
}


/**
* @return true if the widget with the phone number digits is empty.
*/
private boolean isDigitsEmpty() {
return mDigits.length() == 0;
}


/**
* Starts the asyn query to get the last dialed/outgoing number. When the
* background query finishes, mLastNumberDialed is set to the last dialed
* number or an empty string if none exists yet.
*/
private void queryLastOutgoingCall() {
mLastNumberDialed = EMPTY_NUMBER;
CallLogAsync.GetLastOutgoingCallArgs lastCallArgs = new CallLogAsync.GetLastOutgoingCallArgs(
this, new CallLogAsync.OnLastOutgoingCallComplete() {
public void lastOutgoingCall(String number) {
// TODO: Filter out emergency numbers if
// the carrier does not want redial for
// these.
mLastNumberDialed = number;
//mao
updateDialAndDeleteButtonEnabledState();
}
});
mCallLog.getLastOutgoingCall(lastCallArgs);
}








@Override
public void startSearch(String initialQuery, boolean selectInitialQuery,
Bundle appSearchData, boolean globalSearch) {
if (globalSearch) {
super.startSearch(initialQuery, selectInitialQuery, appSearchData,
globalSearch);
} else {
ContactsSearchManager.startSearch(this, initialQuery);
}
}
}

更多相关文章

  1. Android中base64加密后的字符串带有“\n”导致出错的问题解决
  2. %1$s %1$d Android string (java & Android 格式化字符串)
  3. Android中字符串的拆分-split
  4. iphone/android比较学习之──图片、文件、字符串
  5. android textview 中超出屏幕宽度的字符 省略号显示
  6. Android资源文件 - 使用资源存储字符串 颜色 尺寸 整型 布尔值

随机推荐

  1. 关于Android的多种屏幕适配
  2. 在 Android(安卓)设备上搭建 Web 服务器
  3. Android(安卓)轻松实现语音朗读
  4. Android(安卓)WebView、js交互方式原理总
  5. Android在智能终端领域的关键技术专题讲
  6. Android(安卓)Studio 简单介绍和使用问题
  7. Android(安卓)事件处理
  8. Android音视频开发:录制视频 + 语音识别 +
  9. 工作不久的安卓开发者,他们是这样规划自己
  10. Android(安卓)渗透测试学习手册 第三章 A