blob: 86671a88a509e82b96ffb845576e29387e7ff11d [file] [log] [blame]
/*
* Copyright (C) 2008 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 android.app.Activity;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.res.TypedArray;
import android.preference.EditTextPreference;
import android.provider.ContactsContract.CommonDataKinds.Phone;
import android.telephony.PhoneNumberUtils;
import android.text.TextUtils;
import android.text.method.ArrowKeyMovementMethod;
import android.text.method.DialerKeyListener;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;
import android.widget.EditText;
import android.widget.ImageButton;
import android.widget.TextView;
public class EditPhoneNumberPreference extends EditTextPreference {
//allowed modes for this preference.
/** simple confirmation (OK / CANCEL) */
private static final int CM_CONFIRM = 0;
/** toggle [(ENABLE / CANCEL) or (DISABLE / CANCEL)], use isToggled() to see requested state.*/
private static final int CM_ACTIVATION = 1;
private int mConfirmationMode;
//String constants used in storing the value of the preference
// The preference is backed by a string that holds the encoded value, which reads:
// <VALUE_ON | VALUE_OFF><VALUE_SEPARATOR><mPhoneNumber>
// for example, an enabled preference with a number of 6502345678 would read:
// "1:6502345678"
private static final String VALUE_SEPARATOR = ":";
private static final String VALUE_OFF = "0";
private static final String VALUE_ON = "1";
//UI layout
private ImageButton mContactPickButton;
//Listeners
/** Called when focus is changed between fields */
private View.OnFocusChangeListener mDialogFocusChangeListener;
/** Called when the Dialog is closed. */
private OnDialogClosedListener mDialogOnClosedListener;
/**
* Used to indicate that we are going to request for a
* default number. for the dialog.
*/
private GetDefaultNumberListener mGetDefaultNumberListener;
//Activity values
private Activity mParentActivity;
private Intent mContactListIntent;
/** Arbitrary activity-assigned preference id value */
private int mPrefId;
//similar to toggle preference
private CharSequence mEnableText;
private CharSequence mDisableText;
private CharSequence mChangeNumberText;
private CharSequence mSummaryOn;
private CharSequence mSummaryOff;
// button that was clicked on dialog close.
private int mButtonClicked;
//relevant (parsed) value of the mText
private String mPhoneNumber;
private boolean mChecked;
/**
* Interface for the dialog closed listener, related to
* DialogPreference.onDialogClosed(), except we also pass in a buttonClicked
* value indicating which of the three possible buttons were pressed.
*/
interface OnDialogClosedListener {
void onDialogClosed(EditPhoneNumberPreference preference, int buttonClicked);
}
/**
* Interface for the default number setting listener. Handles requests for
* the default display number for the dialog.
*/
interface GetDefaultNumberListener {
/**
* Notify that we are looking for a default display value.
* @return null if there is no contribution from this interface,
* indicating that the orignal value of mPhoneNumber should be
* displayed unchanged.
*/
String onGetDefaultNumber(EditPhoneNumberPreference preference);
}
/*
* Constructors
*/
public EditPhoneNumberPreference(Context context, AttributeSet attrs) {
super(context, attrs);
setDialogLayoutResource(R.layout.pref_dialog_editphonenumber);
//create intent to bring up contact list
mContactListIntent = new Intent(Intent.ACTION_GET_CONTENT);
mContactListIntent.setType(Phone.CONTENT_ITEM_TYPE);
//get the edit phone number default settings
TypedArray a = context.obtainStyledAttributes(attrs,
R.styleable.EditPhoneNumberPreference, 0, R.style.EditPhoneNumberPreference);
mEnableText = a.getString(R.styleable.EditPhoneNumberPreference_enableButtonText);
mDisableText = a.getString(R.styleable.EditPhoneNumberPreference_disableButtonText);
mChangeNumberText = a.getString(R.styleable.EditPhoneNumberPreference_changeNumButtonText);
mConfirmationMode = a.getInt(R.styleable.EditPhoneNumberPreference_confirmMode, 0);
a.recycle();
//get the summary settings, use CheckBoxPreference as the standard.
a = context.obtainStyledAttributes(attrs, android.R.styleable.CheckBoxPreference, 0, 0);
mSummaryOn = a.getString(android.R.styleable.CheckBoxPreference_summaryOn);
mSummaryOff = a.getString(android.R.styleable.CheckBoxPreference_summaryOff);
a.recycle();
}
public EditPhoneNumberPreference(Context context) {
this(context, null);
}
/*
* Methods called on UI bindings
*/
@Override
//called when we're binding the view to the preference.
protected void onBindView(View view) {
super.onBindView(view);
// Sync the summary view
TextView summaryView = (TextView) view.findViewById(android.R.id.summary);
if (summaryView != null) {
CharSequence sum;
int vis;
//set summary depending upon mode
if (mConfirmationMode == CM_ACTIVATION) {
if (mChecked) {
sum = (mSummaryOn == null) ? getSummary() : mSummaryOn;
} else {
sum = (mSummaryOff == null) ? getSummary() : mSummaryOff;
}
} else {
sum = getSummary();
}
if (sum != null) {
summaryView.setText(sum);
vis = View.VISIBLE;
} else {
vis = View.GONE;
}
if (vis != summaryView.getVisibility()) {
summaryView.setVisibility(vis);
}
}
}
//called when we're binding the dialog to the preference's view.
@Override
protected void onBindDialogView(View view) {
// default the button clicked to be the cancel button.
mButtonClicked = DialogInterface.BUTTON_NEGATIVE;
super.onBindDialogView(view);
//get the edittext component within the number field
EditText editText = getEditText();
//get the contact pick button within the number field
mContactPickButton = (ImageButton) view.findViewById(R.id.select_contact);
//setup number entry
if (editText != null) {
// see if there is a means to get a default number,
// and set it accordingly.
if (mGetDefaultNumberListener != null) {
String defaultNumber = mGetDefaultNumberListener.onGetDefaultNumber(this);
if (defaultNumber != null) {
mPhoneNumber = defaultNumber;
}
}
editText.setText(mPhoneNumber);
editText.setMovementMethod(ArrowKeyMovementMethod.getInstance());
editText.setKeyListener(DialerKeyListener.getInstance());
editText.setOnFocusChangeListener(mDialogFocusChangeListener);
}
//set contact picker
if (mContactPickButton != null) {
mContactPickButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
if (mParentActivity != null) {
mParentActivity.startActivityForResult(mContactListIntent, mPrefId);
}
}
});
}
}
/**
* Overriding EditTextPreference's onAddEditTextToDialogView.
*
* This method attaches the EditText to the container specific to this
* preference's dialog layout.
*/
@Override
protected void onAddEditTextToDialogView(View dialogView, EditText editText) {
// look for the container object
ViewGroup container = (ViewGroup) dialogView
.findViewById(R.id.edit_container);
// add the edittext to the container.
if (container != null) {
container.addView(editText, ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT);
}
}
//control the appearance of the dialog depending upon the mode.
@Override
protected void onPrepareDialogBuilder(AlertDialog.Builder builder) {
// modified so that we just worry about the buttons being
// displayed, since there is no need to hide the edittext
// field anymore.
if (mConfirmationMode == CM_ACTIVATION) {
if (mChecked) {
builder.setPositiveButton(mChangeNumberText, this);
builder.setNeutralButton(mDisableText, this);
} else {
builder.setPositiveButton(null, null);
builder.setNeutralButton(mEnableText, this);
}
}
// set the call icon on the title.
builder.setIcon(R.mipmap.ic_launcher_phone);
}
/*
* Listeners and other state setting methods
*/
//set the on focus change listener to be assigned to the Dialog's edittext field.
public void setDialogOnFocusChangeListener(View.OnFocusChangeListener l) {
mDialogFocusChangeListener = l;
}
//set the listener to be called wht the dialog is closed.
public void setDialogOnClosedListener(OnDialogClosedListener l) {
mDialogOnClosedListener = l;
}
//set the link back to the parent activity, so that we may run the contact picker.
public void setParentActivity(Activity parent, int identifier) {
mParentActivity = parent;
mPrefId = identifier;
mGetDefaultNumberListener = null;
}
//set the link back to the parent activity, so that we may run the contact picker.
//also set the default number listener.
public void setParentActivity(Activity parent, int identifier, GetDefaultNumberListener l) {
mParentActivity = parent;
mPrefId = identifier;
mGetDefaultNumberListener = l;
}
/*
* Notification handlers
*/
//Notify the preference that the pick activity is complete.
public void onPickActivityResult(String pickedValue) {
EditText editText = getEditText();
if (editText != null) {
editText.setText(pickedValue);
}
}
//called when the dialog is clicked.
@Override
public void onClick(DialogInterface dialog, int which) {
// The neutral button (button3) is always the toggle.
if ((mConfirmationMode == CM_ACTIVATION) && (which == DialogInterface.BUTTON_NEUTRAL)) {
//flip the toggle if we are in the correct mode.
setToggled(!isToggled());
}
// record the button that was clicked.
mButtonClicked = which;
super.onClick(dialog, which);
}
@Override
//When the dialog is closed, perform the relevant actions, including setting
// phone numbers and calling the close action listener.
protected void onDialogClosed(boolean positiveResult) {
// A positive result is technically either button1 or button3.
if ((mButtonClicked == DialogInterface.BUTTON_POSITIVE) ||
(mButtonClicked == DialogInterface.BUTTON_NEUTRAL)){
setPhoneNumber(getEditText().getText().toString());
super.onDialogClosed(positiveResult);
setText(getStringValue());
} else {
super.onDialogClosed(positiveResult);
}
// send the clicked button over to the listener.
if (mDialogOnClosedListener != null) {
mDialogOnClosedListener.onDialogClosed(this, mButtonClicked);
}
}
/*
* Toggle handling code.
*/
//return the toggle value.
public boolean isToggled() {
return mChecked;
}
//set the toggle value.
// return the current preference to allow for chaining preferences.
public EditPhoneNumberPreference setToggled(boolean checked) {
mChecked = checked;
setText(getStringValue());
notifyChanged();
return this;
}
/**
* Phone number handling code
*/
public String getPhoneNumber() {
// return the phone number, after it has been stripped of all
// irrelevant text.
return PhoneNumberUtils.stripSeparators(mPhoneNumber);
}
/** The phone number including any formatting characters */
protected String getRawPhoneNumber() {
return mPhoneNumber;
}
//set the phone number value.
// return the current preference to allow for chaining preferences.
public EditPhoneNumberPreference setPhoneNumber(String number) {
mPhoneNumber = number;
setText(getStringValue());
notifyChanged();
return this;
}
/*
* Other code relevant to preference framework
*/
//when setting default / initial values, make sure we're setting things correctly.
@Override
protected void onSetInitialValue(boolean restoreValue, Object defaultValue) {
setValueFromString(restoreValue ? getPersistedString(getStringValue())
: (String) defaultValue);
}
/**
* Decides how to disable dependents.
*/
@Override
public boolean shouldDisableDependents() {
// There is really only one case we care about, but for consistency
// we fill out the dependency tree for all of the cases. If this
// is in activation mode (CF), we look for the encoded toggle value
// in the string. If this in confirm mode (VM), then we just
// examine the number field.
// Note: The toggle value is stored in the string in an encoded
// manner (refer to setValueFromString and getStringValue below).
boolean shouldDisable = false;
if ((mConfirmationMode == CM_ACTIVATION) && (mEncodedText != null)) {
String[] inValues = mEncodedText.split(":", 2);
shouldDisable = inValues[0].equals(VALUE_ON);
} else {
shouldDisable = (TextUtils.isEmpty(mPhoneNumber) && (mConfirmationMode == CM_CONFIRM));
}
return shouldDisable;
}
/**
* Override persistString so that we can get a hold of the EditTextPreference's
* text field.
*/
private String mEncodedText = null;
@Override
protected boolean persistString(String value) {
mEncodedText = value;
return super.persistString(value);
}
/*
* Summary On handling code
*/
//set the Summary for the on state (relevant only in CM_ACTIVATION mode)
public EditPhoneNumberPreference setSummaryOn(CharSequence summary) {
mSummaryOn = summary;
if (isToggled()) {
notifyChanged();
}
return this;
}
//set the Summary for the on state, given a string resource id
// (relevant only in CM_ACTIVATION mode)
public EditPhoneNumberPreference setSummaryOn(int summaryResId) {
return setSummaryOn(getContext().getString(summaryResId));
}
//get the summary string for the on state
public CharSequence getSummaryOn() {
return mSummaryOn;
}
/*
* Summary Off handling code
*/
//set the Summary for the off state (relevant only in CM_ACTIVATION mode)
public EditPhoneNumberPreference setSummaryOff(CharSequence summary) {
mSummaryOff = summary;
if (!isToggled()) {
notifyChanged();
}
return this;
}
//set the Summary for the off state, given a string resource id
// (relevant only in CM_ACTIVATION mode)
public EditPhoneNumberPreference setSummaryOff(int summaryResId) {
return setSummaryOff(getContext().getString(summaryResId));
}
//get the summary string for the off state
public CharSequence getSummaryOff() {
return mSummaryOff;
}
/*
* Methods to get and set from encoded strings.
*/
//set the values given an encoded string.
protected void setValueFromString(String value) {
String[] inValues = value.split(":", 2);
setToggled(inValues[0].equals(VALUE_ON));
setPhoneNumber(inValues[1]);
}
//retrieve the state of this preference in the form of an encoded string
protected String getStringValue() {
return ((isToggled() ? VALUE_ON : VALUE_OFF) + VALUE_SEPARATOR + getPhoneNumber());
}
/**
* Externally visible method to bring up the dialog.
*
* Generally used when we are navigating the user to this preference.
*/
public void showPhoneNumberDialog() {
showDialog(null);
}
}